How to loop executable argument for Ant <exec>? - ant

I have a command that will receive option that can be used multiple times, for example
$./myprogram --param a --param b --param c --param d
the input param
a
b
c
d
I want to execute this program using Ant <exec> and ant-contrib's <for>.
Instead of looping the <exec>, like below
<for list="a,b,c,d" param="var">
<exec executable="myprogram">
<arg value="--param"/>
<arg path="#{var}"/>
</exec>
</for>
I tried this looping the param, like below
<exec executable="myprogram">
<for list="a,b,c,d" param="var">
<arg value="--param"/>
<arg path="#{var}"/>
</for>
</exec>
But it doesn't work. The terminal returns this message
exec doesn't support the nested "for" element.
Is there any way to do this?

I just tried this from this question, and it works although it's longer than what I thought
<property name="arg_list" value="a,b,c,d"/>
<resources id="arguments">
<mappedresources>
<string value="${arg_list}" />
<filtermapper>
<replacestring from="," to=" --param "/>
</filtermapper>
</mappedresources>
</resources>
<property name="arguments" value="--param ${toString:arguments}" />
<exec executable="myprogram">
<arg line="${arguments}"/>
</exec>

Related

No output running yui-compressor from Ant

I'm going to minify my js files by yuicomressor via ant, I wrote this:
<property name="concat-js-file-name" value="main.concat.js"/>
<property name="concat-js-file-path" value="${temp-folder}/js/${concat-js-file-name}"/>
<property name="yui-jar-path" value="lib/yuicompressor-2.4.7.jar"/>
<target name="minification" depends="concatation">
<echo>---Minification is started</echo>
<java jar="${yui-jar-path}" fork="true">
<arg value="${concat-js-file-path}"/>
<arg value="-o minified.js"/>
</java>
<echo>---Minification is finished successfully...</echo>
</target>
The problem is the output file is not generated!
Any idea?
You should set <java ... failonerror="true"/> and increase the noiselevel to see what's going on, means start your ant build with ant -f yourbuild.xml -debug
Actually, after some tries I found a solution:
I used <arg line="-o outputfile inputfile"/> instead, and it worked.
I suggest using <arg value="..."> instead of <arg line="...">. <arg value="..."> ensures that each command line argument has quotes around it, if necessary.
In the case of yui-compressor, the "-o" and "<file>" arguments should each go in their own <arg value="..."> elements:
<java jar="${yui-jar-path}" fork="true">
<arg value="-o"/>
<arg value="minified.js"/>
<arg value="${concat-js-file-path}"/>
</java>

Variable number of parameters using <macrodef> and exec

I am using exec to invoke a command line program multiple times from an ant build.xml. This command line program takes variable number of arguments for different cases.
At the moment I am calling this external program multiple time using exec and code looks cluttered. For example:
<exec dir="./deploy_abc/bin" executable="python" failonerror="true" >
<arg line="tests.py"/>
<arg line="-h aaa"/>
<arg line="-u bbb"/>
<arg line="-p ccc"/>
</exec>
<exec dir="./deploy_abc/bin" executable="python" failonerror="true" >
<arg line="tests.py"/>
<arg line="-h ddd"/>
<arg line="-u eee"/>
<arg line="-p fff"/>
<arg value="this is second test"/>
</exec>
<exec dir="./deploy_abc/bin" executable="python" failonerror="true" >
<arg line="tests.py"/>
<arg line="-u bbb"/>
<arg line="-p ccc"/>
<arg value="this is another test"/>
</exec>
So I am planning to refactor this build.xml file using macrodef.
My question is how to pass variable number of parameters to macrodef. As it is shown above I need to pass different arguments to the exec-ed program based on the scenario.
You can use a macrodef element to support this:
This is used to specify nested elements of the new task. The contents
of the nested elements of the task instance are placed in the
templated task at the tag name.
For example, you might define your macro like this:
<macrodef name="call-exec">
<attribute name="dir"/>
<attribute name="executable"/>
<attribute name="failonerror"/>
<element name="arg-elements"/>
<sequential>
<exec dir="#{dir}" executable="#{executable}"
failonerror="#{failonerrer}" >
<arg-elements />
</exec>
</sequential>
</macrodef>
And call it like this:
<call-exec dir="./deploy_abc/bin" executable="python" failonerror="true" >
<arg-elements>
<arg line="tests.py"/>
<arg line="-u bbb"/>
<arg line="-p ccc"/>
<arg value="this is another test"/>
</arg-elements>
</call-exec>

How to get a local IP address in ant 1.5.1

I was wondering, if there is a way to figure out the local IP address with ant. I cannot use the hostinfo task, since I am bound to ant 1.5.1. Now I would write little scripts for each platform and use ant conditional mechanics to execute the appropriate script for each platform. However, maybe any of you know a more elegant way? Thanks in advance.
Benjamin
This works on my mac running os x 10.8.2 :
<target name="getCurrentIP">
<exec executable="/usr/sbin/ipconfig" outputproperty="currentIP">
<arg value="getifaddr"/>
<arg value="en0"/>
</exec>
<echo>currentIP : ${currentIP}</echo>
</target>
<target name="checkos">
<condition property="isWindows" value="true">
<os family="windows" />
</condition>
<condition property="isLinux" value="true">
<os family="unix" />
</condition>
</target>
<target name="if_windows" depends="checkos" if="isWindows">
<exec executable="cmd" outputproperty="myHostName">
<arg value="/c" />
<arg value="hostname"/>
</exec>
<exec executable="cmd" outputproperty="infraServerIPTemp" >
<arg value="/c"/>
<arg value="FOR /f "tokens=1 delims=:" %d IN ('ping ${myHostName} -4 -n 1 ^| find /i "reply"') DO FOR /F "tokens=3 delims= " %g IN ("%d") DO echo infraServerIP=%g > myIP.properties"/>
</exec>
<property file="myIP.properties"/>
</target>
<target name="if_unix" depends="checkos" if="isLinux">
<exec executable="hostname" outputproperty="infraServer">
<arg line="-i"/>
</exec>
<property name="infraServerIP" value="${infraServer}"/>
</target>
<target name="checkOSType" depends="if_windows, if_unix"/>
<target name="do-something" depends="checkOSType">
</target>
with the help of Ant addon Flaka you might use :
<project xmlns:fl="antlib:it.haefelinger.flaka">
<!-- on windows -->
<exec executable="cmd" outputproperty="winip">
<arg value="/c" />
<arg value="ipconfig" />
</exec>
<!-- simple echo -->
<fl:echo>localip => #{replace('${winip}', '$2' , '\s(IP.+):\s?(\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b)')}</fl:echo>
<!-- set property -->
<fl:let>localip := replace('${winip}', '$2' , '\s(IP.+):\s?(\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b)')</fl:let>
<!-- on linux -->
<exec executable="hostname" outputproperty="linuxip">
<arg value="-i" />
</exec>
<!-- simple echo -->
<fl:echo>localip => #{replace('${linuxip}', '$1' , '(\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b)\s(.+)')}</fl:echo>
<!-- set property -->
<fl:let>localip := replace('${linuxip}', '$1' , '(\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b)\s(.+)')</fl:let>
</project>
Our solution to the problem is, that we built a little Java program, which prints the local ip to the standard output. We store this output in an ant property. (We use Java instead of a scripting language of some sort, because we would otherwise have to deploy the language runtime on many systems and Java is already deployed throughout our system landscape)

problem with ant script properties

The following is my ant script:
<project name="nightly_build" default="main" basedir="C:\Work\6.70_Extensions\NightlyBuild">
<target name="init">
<sequential>
<exec executable="C:/Work/Searchlatestversion.exe">
<arg line='"/SASE Lab Tools" "6.70_Extensions/6.70.102/ANT_SASE_RELEASE_"'/>
</exec>
<property file="C:/Work/latestbuild.properties"/>
<sleep seconds="10"/>
<echo message="The product version is ${Product_Version}"/>
<exec executable="C:/Work/checksnapshot.exe">
<arg line='"ANT_SASE_RELEASE_${Product_Version}_SASE Lab Tools-NightlyBuild" ANT_SASE_RELEASE_${Product_Version}_AnalyzerCommon-NightlyBuild ${Product_Version}-AppsMerge' />
</exec>
<property file="C:/Work/checksnapshot.properties"/>
<tstamp>
<format property="suffix" pattern="ddMMyyyyHHmm"/>
</tstamp>
</sequential>
</target>
<target name="main" depends="init">
<echo message="loading properties files.." />
<sleep seconds="10"/>
<echo message="Backing up folder" />
<move file="C:\NightlyBuild\NightlyBuild" tofile="C:\NightlyBuild\NightlyBuild.${suffix}" failonerror="false" />
<parallel>
<exec executable="C:/Work/sortfolder.exe">
<arg line="6" />
</exec>
<exec executable="C:/Work/6.70_Extensions/NightlyBuild/antc.bat">
</exec>
</parallel>
</target>
</project>
Basically the sequence goes something like this:
I will run Searchlatestversion.exe and write latestbuild.properties
Using the latestbuild.properties i will obtain ${Product_Version} and would like to allow checksnapshot.exe access to latestbuild.properties and obtain ${Product_Version}
checksnapshot.exe will then generate checksnapshot.properties which will then be used by the target in main antc.bat
am i doing something wrong over here? seems like ${Product_Version} is not being received well by checksnapshot.exe
You appear to have a hard coded wait period of 10 seconds for Searchlatestversion to write out your file. If the executable does not complete inside that time, ${Product_Version} cannot be read from file.
Have you considered using the Waitfor Ant Task? As the name implies, this will wait for a certain condition before it will allow the rest of the task to progress. You could do something like
<property name="props.file" value="C:/Work/latestbuild.properties"/>
<waitfor maxwait="10" maxwaitunit="second">
<available file="${props.file}"/>
</waitfor>
<property file="${props.file}"/>
Does Searchlatestversion.exe produce the file C:/Work/latestbuild.properties?
If so, should you not sleep/wait before you load that properties file?
You have this:
<exec .../>
<property file="C:/Work/latestbuild.properties"/>
<sleep seconds="10"/>
Should you not have this:
<exec ... />
<sleep seconds="10"/>
<property file="C:/Work/latestbuild.properties"/>

Iterating through a directory with Ant

Let's say I have a collection of PDF files with the following paths:
/some/path/pdfs/birds/duck.pdf
/some/path/pdfs/birds/goose.pdf
/some/path/pdfs/insects/fly.pdf
/some/path/pdfs/insects/mosquito.pdf
What I'd like to do is generate thumbnails for each PDF that respect the relative path structure, and output to another location, i.e.:
/another/path/thumbnails/birds/duck.png
/another/path/thumbnails/birds/goose.png
/another/path/thumbnails/insects/fly.png
/another/path/thumbnails/insects/mosquito.png
I'd like this to be done in Ant. Assume I'm going to use Ghostscript on the command line and I've already worked out the call to GS:
<exec executable="${ghostscript.executable.name}">
<arg value="-q"/>
<arg value="-r72"/>
<arg value="-sDEVICE=png16m"/>
<arg value="-sOutputFile=${thumbnail.image.path}"/>
<arg value="${input.pdf.path}"/>
</exec>
So what I need to do is work out the correct values for ${thumbnail.image.path} and ${input.pdf.path} while traversing the PDF input directory.
I have access to ant-contrib (just installed the "latest", which is 1.0b3) and I'm using Ant 1.8.0. I think I can make something work using the <for> task, <fileset>s and <mapper>s, but I am having trouble putting it all together.
I tried something like:
<for param="file">
<path>
<fileset dir="${some.dir.path}/pdfs">
<include name="**/*.pdf"/>
</fileset>
</path>
<sequential>
<echo message="#{file}"/>
</sequential>
</for>
But unfortunately the #{file} property is an absolute path, and I can't find any simple way of decomposing it into the relative components.
If I can only do this using a custom task, I guess I could write one, but I'm hoping I can just plug together existing components.
In the sequential task you could may be able to use the ant-contrib propertyregex task to map the input paths to output. For example:
<propertyregex override="yes" property="outfile" input="#{file}"
regexp="/some/path/pdfs/(.*).pdf"
replace="/another/path/\1.png" />
Which maps, for example /some/path/pdfs/birds/duck.pdf to /another/path/birds/duck.png.
For the sake of completeness, here's what I came up with for a target based on martin clayton's answer. It only works on Windows for now but that's because I haven't gotten around to installing Ghostscript in a non-proxy way yet on Mac OS X. Note that to be a cross-platform solution I had to "scrub" the file separators to be consistently forward-slash only.
<target name="make-thumbnails" depends="">
<taskdef resource="net/sf/antcontrib/antlib.xml">
<classpath>
<pathelement location="/path/to/ant-contrib-1.0b3.jar"/>
</classpath>
</taskdef>
<condition property="ghostscript.executable.name" value="/path/to/gswin32c.exe">
<os family="windows"/>
</condition>
<condition property="ghostscript.executable.name" value="">
<os family="mac"/>
</condition>
<for param="file">
<path>
<fileset dir="/path/to/pdfs">
<include name="**/*.pdf"/>
</fileset>
</path>
<sequential>
<propertyregex override="yes" property="file-scrubbed" input="#{file}"
regexp="\\"
replace="/" />
<propertyregex override="yes" property="output-path-directory-fragment" input="${file-scrubbed}"
regexp=".*/pdfs/(.*)/.+\.pdf"
replace="\1" />
<propertyregex override="yes" property="output-path-file-fragment" input="${file-scrubbed}"
regexp=".*/pdfs.*/(.+)\.pdf"
replace="\1.png" />
<mkdir dir="${thumbnails.base.dir}/${output-path-directory-fragment}"/>
<exec executable="${ghostscript.executable.name}">
<arg value="-q"/>
<arg value="-dLastPage=1"/>
<arg value="-dNOPAUSE"/>
<arg value="-dBATCH"/>
<arg value="-dSAFER"/>
<arg value="-r72"/>
<arg value="-sDEVICE=png16m"/>
<arg value="-sOutputFile=${thumbnails.base.dir}/${output-path-directory-fragment}/${output-path-file-fragment}"/>
<arg value="${file-scrubbed}"/>
</exec>
</sequential>
</for>
</target>

Resources