How to use macrodef? - ant

Lets assume this is my code. buildJar is my macrodef.
<target name="build">
<buildJar build.dir="module1"/>
<buildJar build.dir="module2"/>
</target>
How to invoke macrodef "buildJar" based on some condition? For example, above code can be:
<target name="build">
<if module="module1" >
<buildJar build.dir="module1"/>
</if>
<if module="module2" >
<buildJar build.dir="module2"/>
</if>
</target>

Ant supports if and unless attributes. These can be combined with a directory check using the available task:
<project name="demo" default="build" xmlns:if="ant:if">
<macrodef name="greeting">
<attribute name="name"/>
<sequential>
<echo message="found #{name}"/>
</sequential>
</macrodef>
<available property="found.module1" file="module1"/>
<available property="found.module2" file="module2"/>
<target name="build">
<greeting name="module1" if:true="${found.module1}"/>
<greeting name="module2" if:true="${found.module2}"/>
</target>
</project>

Related

how to test symlinks with ant 1.9

I need to perform a command if the jar file is a file instead of a symlink. I have found a solution that works only with ant 1.10.
Does anyone know how to do it with ant 1.9 ?
Here is my build.xml.
<?xml version="1.0"?>
<project name="AsterixDecoder" default="bm" basedir=".">
<!-- set global properties for this build -->
<property name="src" location="src"/>
<property name="build" location="build"/>
<property name="dist" location="dist"/>
<property environment="env"/>
<condition property="exists.CCM_ADDR">
<isset property="env.CCM_ADDR"/>
</condition>
<target name="compile" description="compile the source " >
<mkdir dir="${build}"/>
<javac srcdir="${src}" destdir="${build}" includeantruntime="false"/>
<mkdir dir="${build}/resources"/>
<copy todir="${build}/resources">
<fileset dir="resources"/>
</copy>
</target>
<target name="checkout" if="exists.CCM_ADDR">
<ccmcheckout file="${dist}/AsterixDecoder.jar"/>
</target>
<target name="dist" depends="compile, checkout"
description="generate the distribution" >
<jar jarfile="${dist}/AsterixDecoder.jar" filesetmanifest="mergewithoutmain">
<manifest>
<attribute name="Main-Class" value="fr.eurocontrol.escape.ground.asterixdecoder.AsterixDataTree"/>
<attribute name="Class-Path" value="."/>
</manifest>
<fileset dir="${build}"/>
</jar>
</target>
<target name="check.symlink">
<fileset dir="${dist}" id="fileset" includes="AsterixDecoder.jar">
<symlink/>
</fileset>
<pathconvert refid="fileset" property="is.symlink" setonempty="false"/>
</target>
<target name="reconcile" depends="check.symlink" if="exists.CCM_ADDR" unless="is.symlink">
<exec executable="ccm">
<arg value="reconcile"/>
<arg value="-udb"/>
<arg value="${dist}/AsterixDecoder.jar"/>
</exec>
</target>
<target name="bm" description="build management" depends="dist, reconcile">
</target>
</project>
Do not hesitate to make any suggestion of improvements. I am still a beginner in writing ant files.
The most straightforward way to do this would be to use the record function of Ant's symlink task. This creates a property file that lists all of the symlinks found within a given resource collection. Here's an example target:
<target name="default">
<symlink link="testdir" resource="build" />
<symlink action="record" linkfilename="links.record">
<fileset dir="." includes="*" />
</symlink>
<property file="links.record" />
<condition property="testdir.is.symlink">
<isset property="testdir" />
</condition>
<echo message="${testdir.is.symlink}" />
</target>

Ant Script Loop through property file and replace values dynamically

I got a requirement to loop through some XML files, replace the environment specific values in it and create new set of XML files. The environment specific values are to be taken from property file. I am able to loop through a directory to read all the files and replace some specific value using xmltask as below.
<target name="updateConfig" description="update the configuration" depends="init">
<xmltask todir="${ConfigDestDirectory}" report="false" failwithoutmatch="true">
<fileset dir="${ConfigSourceDirectory}">
<include name="*.xml"/>
</fileset>
<replace path="/:application/:NVPairs/:NameValuePair[:name='Connections/HTTP/HostName']/:value/text()" withXml="localhost"/>
</xmltask>
<echo>Replaced Successfully</echo>
</target>
But I would like to read through a property file and get the path/value from it.
I tried using property selector,property,var as different options for this case and manage to get the path but not the value. Below are the snippet of property file and the target that I am using.
#DEV.properties
HostName.xpath=/:application/:NVPairs/:NameValuePair[:name='Connections/HTTP/HostName']/:value/text()
HostName.value=localhost
<project name="TestBuild" default="ReadPropertyFile" basedir=".">
<target name="init">
<property file="DEV.properties"/>
<taskdef name="xmltask" classname="com.oopsconsultancy.xmltask.ant.XmlTask" classpath="${xmltaskPath}"/>
<taskdef resource="net/sf/antcontrib/antlib.xml" classpath="${antcontribPath}"/>
<taskdef resource="net/sf/antcontrib/antcontrib.properties"/>
</target>
<target name="ReadPropertyFile" description="update the configuration" depends="init">
<property file="DEV.properties" prefix="x"/>
<propertyselector property="propertyList" delimiter="," select="\0" match="([^\.]*)\.xpath" casesensitive="true" distinct="true"/>
<for list="${propertyList}" param="sequence">
<sequential>
<propertyregex property="destproperty" input="#{sequence}" regexp="([^\.]*)\." select="\1" />
<property name="tempname" value="${destproperty}.value" />
<var name="localprop" value="${tempname}"/>
<echo> #{sequence} </echo>
<echo> ${x.#{sequence}} </echo>
<echo>destproperty --> ${destproperty}</echo>
<echo>tempname --> ${tempname}</echo>
<echo> localprop --> ${localprop}</echo>
<echo>${x.${localprop}} </echo> <!--This is not working -->
</sequential>
</for>
</target>
It would be really helpful if you guys can throw some light.
Thanks,
Venkat
Would this work better ?
I think you got yourself confused with the "x." prefix.
<project name="TestBuild" default="ReadPropertyFile" basedir=".">
<target name="init">
<property file="DEV.properties"/>
<taskdef name="xmltask" classname="com.oopsconsultancy.xmltask.ant.XmlTask" classpath="${xmltaskPath}"/>
<taskdef resource="net/sf/antcontrib/antlib.xml" classpath="${antcontribPath}"/>
<taskdef resource="net/sf/antcontrib/antcontrib.properties"/>
</target>
<target name="ReadPropertyFile" description="update the configuration" depends="init">
<property file="DEV.properties" prefix="x"/>
<local name="propertyList"/>
<propertyselector property="propertyList" delimiter="," select="\1" match="x\.([^\.]*)\.xpath" casesensitive="true" distinct="true"/>
<for list="${propertyList}" param="sequence">
<sequential>
<echo> #{sequence} </echo>
<echo> #{sequence}.xpath = ${x.#{sequence}.xpath} </echo>
<echo> #{sequence}.value = ${x.#{sequence}.value} </echo>
</sequential>
</for>
</target>
</project>

Split the value from property using ANT

I have the following code:
<dirset id="aa" dir="FOLDER" includes="example*" excludes=".*">
</dirset>
<pathconvert pathsep="," property="bb" refid="aa">
<mapper type="flatten"/>
</pathconvert>
<echo message="LIST:${bb}"/>
and the output is for example 'examle.aa,example.bb'
And I would like to call another target for each example.*.. Can you help me please?
A macrodef would work for this, you could invoke it with custom attributes or elements based on you current property:
macrodef
Try antcontrib for the loop functionality. Here's an example
<project>
<target name="test">
<taskdef resource="net/sf/antcontrib/antlib.xml" classpath="./lib/ant-contrib-1.0.jar" />
<for param="file">
<dirset dir="." />
<sequential>
<task dir="#{file}" />
</sequential>
</for>
</target>
<macrodef name="task">
<attribute name="dir" />
<sequential>
<echo>#{dir}</echo>
</sequential>
</macrodef>
</project>

How to <foreach> in a <macrodef>?

I have a xml just like below:
<data>
<foo>value1</foo>
<foo>value2</foo>
<foo>value3</foo>
</data>
I want to create macrodef which implements below function:
<?xml version="1.0"?>
<project name="OATS" default="execute" basedir=".">
<xmlproperty file="data.xml" collapseAttributes="true"/>
<target name="execute">
<foreach list="${data.foo}" target="runScript" param="script"/>
</target>
<target name="runScript">
<echo>Doing things with ${script}</echo>
</target>
</project>
Anybody knows how to ? Thanks in advance.
xmltask is the best choice in the Ant community for this purpose, and you don't have to define your own macrodef.
So for instance:
<tools:xmltask source="data.xml" report="false" >
<tools:call path="data/foo">
<param name="value" path="text()"/>
<actions>
<echo>Doing things with #{value}</echo>
</actions>
</tools:call>
</tools:xmltask>
I encourage you to read the user manual, for xmltask has lots of options. It basically supports XPath to extract and iterate any portion of your xml. It also supports calls to existing targets in addition to anonymous code blocks (as in the example).
It's just hard to beat.
The following example uses the groovy ANT task
<project name="OATS" default="execute" basedir=".">
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy">
<classpath>
<pathelement location="lib/groovy-all-2.1.0-rc-2.jar"/>
</classpath>
</taskdef>
<target name="execute">
<groovy>
def data = new XmlSlurper().parse(new File("data.xml"))
data.foo.each {
properties["script"] = it
ant.project.executeTarget("runScript")
}
</groovy>
</target>
<target name="runScript">
<echo>Doing things with ${script}</echo>
</target>
</project>
This is my macrodef.
<?xml version="1.0" encoding="UTF-8"?>
<project name="OATS" default="test" basedir=".">
<property environment = "env"/>
<path id = "antcontrib.path">
<fileset file = "${env.ANT_HOME}/../net.sf.antcontrib_1.1.0.0_1-0b2/lib/ant-contrib.jar"/>
</path>
<taskdef resource="net/sf/antcontrib/antlib.xml" classpathref="antcontrib.path"/>
<macrodef name="runOATS">
<attribute name="suite"/>
<attribute name="toDir"/>
<sequential>
<delete dir="#{toDir}"/>
<mkdir dir="#{toDir}"/>
<xmlproperty file="#{suite}" collapseAttributes="true"/>
<for list="${data.foo}" param="script">
<sequential>
<runScript script="#{script}"/>
</sequential>
</for>
</sequential>
</macrodef>
<macrodef name="runScript">
<attribute name="script"/>
<sequential>
<echo>Doing things with #{script}</echo>
</sequential>
</macrodef>
<target name="test">
<runOATS toDir="/OATS/results" suite="data.xml"/>
</target>
</project>

How do I select the first element of a filelist in ant?

How do I take only the first element of an ant <filelist> and also <echo> that filename as a string?
Here's a solution that doesn't require external tasks
<project name="demo" default="run">
<path id="files.path">
<first>
<filelist dir="dir1" files="foo.jar,file1.jar,file2.jar"/>
</first>
</path>
<target name="run">
<pathconvert property="path.output" refid="files.path"/>
<echo message="Output: ${path.output}"/>
</target>
</project>
You will need ant-contrib and the trick used in the code is the fact that properties cannot be changed once they are set.
<for param="file">
<path>
<filelist
id="docfiles"
dir="toto"
files="foo.xml
bar.xml"/>
</path>
<sequential>
<basename property="package" file="#{file}"/>
</sequential>
</for>
<echo>${package}</echo>
EDIT:
An alternative solution is using the break task from Antelope

Resources