How can I generate Ant targets? - ant

I want to be able to generate a number of Ant targets something like this:
<property name="grunt_tasks" value="jsp,css,js,img" />
<foreach list="${grunt_tasks}" param="task">
<target name="${task}">
<exec executable="grunt" failonerror="true">
<arg line="${task}" />
</exec>
</target>
</foreach>
allowing me to run ant jsp or ant js.
However, this code fails because a target tag cannot be placed in a foreach tag.
How can I accomplish this?

There's a number of ways you might add targets on the fly. Here's one suggestion:
<property name="mybuild" value="mybuild.xml" />
<property name="grunt_tasks" value="jsp,css,js,img" />
<echo message="<project>" file="${mybuild}" />
<for list="${grunt_tasks}" param="task">
<sequential>
<echo file="${mybuild}" append="yes"><![CDATA[
<target name="#{task}">
<exec executable="grunt" failonerror="true">
<arg line="#{task}" />
</exec>
</target>
]]></echo>
</sequential>
</for>
<echo message="</project>" file="${mybuild}" append="yes"/>
<import file="${mybuild}" />
Explanation:
Use the antcontrib <for> task in preference to <foreach>, else you have to have a separate target for the body of the loop.
Create a second buildfile, here called mybuild.xml, to contain your targets.
The buildfile content has to be within a <project> element.
Import the buildfile.
You can then invoke the on-the-fly targets in the way you wish.
You might alternatively use a <script> task to create the targets if you prefer, which would remove the need for the separate buildfile and import, something like this:
<for list="${grunt_tasks}" param="task">
<sequential>
<script language="javascript"><![CDATA[
importClass(org.apache.tools.ant.Target);
var exec = project.createTask( "exec" );
exec.setExecutable( "grunt" );
exec.setFailonerror( true );
var arg = exec.createArg( );
arg.setValue( "#{task}" );
var target = new Target();
target.addTask( exec );
target.setName( "#{task}" );
project.addOrReplaceTarget( target );
]]></script>
</sequential>
</for>

Related

ANT passing all command line properties to <java>

I have a got a ANT build system which invokes builds on different projects using following macro;
<macrodef name="buildComponent">
<attribute name="name"/>
<attribute name="dir"/>
<attribute name="antTarget"/>
<attribute name="antCommonDistDir" />
<sequential>
<available property="build.xml.exists.#{dir}" file="#{dir}/build.xml" />
<if>
<equals arg1="${build.xml.exists.#{dir}}" arg2="true" />
<then>
<java classname="org.apache.tools.ant.launch.Launcher"
fork="true"
failonerror="true"
dir="#{dir}"
timeout="4000000"
output="${common.build.dir}/log/#{name}.log"
taskname="startAnt" >
<jvmarg value="-Dant.home=${ant.home}"/>
<classpath>
<pathelement location="${ant.home}/lib/ant-launcher.jar"/>
</classpath>
<arg value="-Dbasedir=#{dir}"/>
<arg value="#{antTarget}"/>
<arg value="-Dprop1=${prop1}" />
<syspropertyset refid="project.common.properties" />
<sysproperty key="common.dist.dir.os" value="#{antCommonDistDir}" />
</java>
</then>
</if>
</sequential>
</macrodef>
I would like to override properties form command line but the problem is that these properties are not being passed by task and my subsequent build uses the default values. For example I am executing the build as follows;
ant dist -Dprop1=override.prop1 -Dprop2=override.prop2 -Dprop3=override.prop3
As you see currently the only option for me to pass these overridden values from command line for prop2 and prop3 is add <arg /> under <java /> task for each property passed like I have done for 'prop1' which works but not desirable. Is there anyway I can access all properties passed to ANT and simply pass them as is to <java /> task?
You can use the echoproperties task to save all current Ant properties to a file, and then pass that file to the java task to be loaded by the subproject.
<echoproperties destfile="my.properties"/>
Having said this, a better solution instead of executing the java command to invoke another Ant build, you can simply call the ant task which will build your subproject and automatically inherit all properties from the parent project:
<available property="build.xml.exists.#{dir}" file="#{dir}/build.xml" />
<if>
<equals arg1="${build.xml.exists.#{dir}}" arg2="true" />
<then>
<ant antfile="#{dir}/build.xml" target="#{antTarget}"/>
</then>
</if>
I couldn't find any thing which can do this directly. So I ended up writing a javascript and populated a ant property to parse command line options which was stored in env variable and passed it to <java /> task as <arg line="${command.line.properties}" />. Remember to use <arg line="" /> as it trim out all extra spaces etc before invoking a task.

Unusual ant behavior with presetdef and antcall

Consider the following excerpt from an ant build.xml:
<presetdef name="echo1def">
<echo message="prop: ${foo}" />
</presetdef>
<presetdef name="echo2def">
<sequential>
<echo message="prop: ${foo}" />
</sequential>
</presetdef>
<target name="echotarget1">
<property name="foo" value="bar" />
<echo1def/>
</target>
<target name="echotarget2">
<property name="foo" value="bar" />
<echo2def/>
</target>
<target name="echo1">
<antcall target="echotarget1" />
</target>
<target name="echo2">
<antcall target="echotarget2" />
</target>
Calling any of {echotarget1, echotarget2, echo1} produce the expected output of prop: bar. Calling echo2, however, produces prop: ${foo}.
Why can't the echo2def resolve the ${foo} property? It's defined immediately before, in the same project (i.e., not even on the other side of the antcall). The echo1 call, which does the same thing except the presetdef is not wrapped in <sequential>, has no issue.
Finally,
<target name="echo3">
<property name="foo" value="baz" />
<antcall target="echotarget2" />
</target>
reports prop: baz - so the property from the antcalling project can be seen, even though it is defined after the presetdef is.
Just get rid of <sequential> in your echo2def presetdef, means :
<presetdef name="echo2def">
<echo message="prop: ${foo}" />
</presetdef>
and all will work as expected.
It's because property scopes exist at Apache Ant's various "block" levels including sequential, that's how i.e. the local task (new in Ant 1.8.0) works.
antcall opens a new project scope, without antcall - means calling those targets echotarget1 and echotarget2 directly - it works also, resolving the property ${foo}.

Modify global variable Ant

I want to change "variable" in Ant file, in one target and see that change in another target.
<variable name="foo" value="hello" />
<target name="print-me">
<echo message="${foo}" />
<antcall target="change-me" />
<echo message="${foo}" />
</target>
<target name="change-me">
<variable name="foo" value="world" />
</target>
While I want it to print: 'hello , world' , it prints 'hello, hello'
Either use :
<target name="change-me">
<variable name="foo" unset="true"/>
<variable name="foo" value="world"/>
</target>
as Oers already mentioned in his comment to your question or use a morestraightforward approach with the let task of Ant addon Flaka :
<project xmlns:fl="antlib:it.haefelinger.flaka">
...
<!-- overwrite any existing property or userproperty
(those properties defined on the commandline via -Dfoo=bar ..) -->
<fl:let> foo ::= 'world'</fl:let>
...
</project>
This will work if you use the ant-contrib tags.

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"/>

overwriting ANT properties file

How can i overwrite some existing property with a newly created properties file?
Here is the required structure:
initially load Master.properties
generate new.properties
load new.properties and master.properties
run master.xml (ANT script)
The idea is that Master.properties generates some product version which should be replaced by new.properties. However, other properties in Master.properties should be kept the same.
Reading this does not help as i do not know how can i load the new.properties file
EDIT Here is ANT Script:
<project name="nightly_build" default="main" basedir="C:\Work\NightlyBuild">
<target name="init1">
<sequential>
<property file="C:/Work/NightlyBuild/master.properties"/>
<exec executable="C:/Work/Searchlatestversion.exe">
<arg line='"/SASE Lab Tools" "${Product_Tip}/RELEASE_"'/>
</exec>
<sleep seconds="10"/>
<property file="C:/Work/new.properties"/>
</sequential>
</target>
<target name="init" depends="init1">
<sequential>
<echo message="The product version is ${Product_Version}"/>
<exec executable="C:/Work/checksnapshot.exe">
<arg line='-NightlyBuild ${Product_Version}-AppsMerge' />
</exec>
<sleep seconds="10"/>
<property file="C:/Work/checksnapshot.properties"/>
<tstamp>
<format property="suffix" pattern="yyyy-MM-dd.HHmm"/>
</tstamp>
</sequential>
</target>
<target name="main" depends="init">
<echo message="loading properties files.." />
<echo message="Backing up folder" />
<move file="C:\NightlyBuild\NightlyBuild" tofile="C:\NightlyBuild\NightlyBuild.${suffix}" failonerror="false" />
<exec executable="C:/Work/sortfolder.exe">
<arg line="6" />
</exec>
<exec executable="C:/Work/NightlyBuild/antc.bat">
</exec>
</target>
</project>
in the above script, <exec executable="C:/Work/NightlyBuild/antc.bat"> will run Master.xml ANT script. This Master.xml will load up Master.properties:
<project name="Master ANT Build" default="main" >
<taskdef name="CFileEdit" classname="com.ANT_Tasks.CFileEdit"/>
<!-- ========================================================== -->
<!-- init: sets global properties -->
<!-- ========================================================== -->
<target name="init">
<property environment="env"/>
<!-- ========================================================== -->
<!-- Set the timestamp format -->
<!-- ========================================================== -->
<property file="Master.properties"/>
...
</project>
You should be able to resolve this by looking at the order in which you load (or otherwise specify) your property values. You probably don't need to override property values at all, which something not supported by core Ant.
Maybe you can split your Master.properties into two files - one loaded before you generate new.properties and one loaded after?
Maybe you don't need to generate new.properties at all.
Could you give some more detail on what you need to do?
Since you eventually fork a new Ant process (exec antc.bat), does that not start a fresh environment anyway? If it just loads Master.properties, those are the only properties it will have.
Not sure what your antc.bat does, but it's pretty unusual to exec Ant from Ant in this way. There are two standard tasks which might be useful - Ant and AntCall.
OK running on from your later comments...
Let's say that instead of doing this:
<exec executable="antc.bat">
you instead did something like this:
<ant file="Master.xml" inheritall="false">
<property name="Product_Version" value="${Product_Version}"/>
</ant>
I think that is getting towards what you want. You selectively pass specific values that you have obtained by loading new.properties. See the documentation for the Ant task.
If you still have the problem that you already defined Product_Version before loading new.properties, then I would say get the script you have that produces new.properties to output the version with a different name, e.g. New_Product_Version. Then invoke your master build something like this:
<ant file="Master.xml" inheritall="false">
<property name="Product_Version" value="${New_Product_Version}"/>
</ant>
May be this is a old question. Hopefully OP is reading this.
You can just use the ant task "propertyfile". reference
it can read properties from the file and write back updated values to them.

Resources