Modify global variable Ant - 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.

Related

How can I generate Ant targets?

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>

get property from different ant project

Is it possible to read properties from another ant project ?
I could do it with:
<ant antfile="child/build.xml" target="echoproperties">
<property name="echoproperties.file" value="${tmp}/child.properties" />
</ant>
<property prefix="child" file="${tmp}/child.properties" />
<delete file="${tmp}/child.properties" />
While in child/build.xml:
<target name="echoproperties">
<echoproperties destfile="${echoproperties.file}" />
</target>
But I would like to avoid creating temporary files.
I've found that Ant-Contrib has antfetch task although it's functionality is not that great (no prefix, no propertysets).

Change values of list in ANT

I need to change the values of an ANT-script list in real time.
This is the situation;
I have these properties:
x.y.6.1=something1
x.y.6.2=something2
x.y.6.3=something3
list=6.1,6.2
I want the list to become list=something1;something2
This is the gist of the code;
<target name="target1">
<foreach list="${list}" target="target2" param="var" delimiter="," />
</target>
<target name="target2">
<propertycopy name="var" from="x.y.${var}" silent="true"/>
</target>
Now, the propertycopy part works, however, it will not keep the new value.
I tried many variations, none which worked.
I am using ant-contrib.
Help would be much appreciated!
Adam
The target attribute of your foreach should be the name of the target called.
I guess here it should be <foreach list="${list}" target="agent_version_to_path" param="var" delimiter="," />
If I'm wrong, post your target2 and explain what you're trying to do.
Edit:
Ok for your edit, did you already try override="yes"?
And cannot you change your name of property (var) it is quite confusing!
I'm not a fan of the ant-contrib tasks. Have you considered embedding a scripting language instead?
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy" classpathref="build.path"/>
<groovy>
properties["list"].split(",").each {
println properties["x.y.${it}"]
}
</groovy>
Update
Here's a more complete example that loops and calls another target:
$ ant
Buildfile: build.xml
process:
doSomething:
[echo] something1
doSomething:
[echo] something2
BUILD SUCCESSFUL
Total time: 0 seconds
build.xml
<project name="demo" default="process">
<property file="build.properties"/>
<path id="build.path">
<pathelement location="lib/groovy-all-2.1.5.jar"/>
</path>
<target name="process" description="Process values in a list">
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy" classpathref="build.path"/>
<groovy>
properties["list"].split(",").each {
properties.var = properties["x.y.${it}"]
ant.ant(target:"doSomething")
}
</groovy>
</target>
<target name="doSomething">
<echo>${var}</echo>
</target>
</project>
I have solved the problem, in an icky way, but it works great!
<project name="Test" default="main">
<property file="agent.properties" />
<property file="temp_updates.txt" />
<taskdef name="propertycopy" classname="net.sf.antcontrib.property.PropertyCopy" />
<taskdef name="foreach" classname="net.sf.antcontrib.logic.ForEach" />
<target name="main">
<property name="Agent Updates" value="6.1,6.2" />
<antcall target="create_temp_files" />
<antcall target="agent_updates_target" />
<propertycopy name="custom.agent.release.group" from="updates" silent="true" override="true" />
</target>
<target name="agent_updates_target">
<foreach list="${Agent Updates}" target="agent_version_to_path" param="var" delimiter="," />
</target>
<target name="agent_version_to_path">
<propertycopy name="var" from="agent.installer.${var}" silent="true" override="true"/>
<echo message="${var};" file="temp_updates.txt" append="true" />
</target>
<target name="create_temp_files">
<echo message="updates=" file="temp_updates.txt" />
</target>
</project>
on another file, "agent.properties" I had that;
agent.installer.6.3=something3
agent.installer.6.2=something2
agent.installer.6.1=something1
agent.installer.6.0=...
agent.installer.5.6=...
agent.installer.5.0.12=...
agent.installer.5.0.11=...
agent.installer.5.0.9.5=...
agent.installer.3.8=...
agent.installer.3.7=...
As a result, a new file "temp_updates.txt" was created, having
updates=something1;something2;
Which I then loaded into the actual program.
May not be pretty, but it works quite well.
Thank you Skoll and Mark O'Connor for all your help, I used those ideas to come up with this one. I would rate you, but I can't :( Sorry!

how to check if a particular file is present in a directory or not

I have a jar file in /programs/src i want my program to print a message that it is present in the directory:
<if>
<available file="**/*.jar" />
<then>
<echo message="Available" />
</then>
<else>
<echo message="Not Available" />
</else>
but it is not working
There's nothing in the documentation for <available> that says it can handle wildcards. You need to use an actual file path.
You may use the builtin ${toString:yourfilesetid} mechanism from ant combined with Ant Addon Flaka like that :
<project name="demo" xmlns:fl="antlib:it.haefelinger.flaka">
<fileset dir="/home/rosebud/temp" includes="**/*.jar" id="foobar"/>
<fl:choose>
<fl:when test=" '${toString:foobar}' ne '' ">
<echo message="Available" />
<!-- .. other stuff -->
</fl:when>
<fl:otherwise>
<echo message="Not Available" />
<!-- .. other stuff -->
</fl:otherwise>
</fl:choose>
</project>

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}.

Resources