How to call an immutable ant target twice - ant

I have to run a pre-existing immutable target twice with different property values and have written a macrodef for it. I'm able to set the property value and run the macrodef twice but I do not know how to execute the target from within the macrodef. I've gone through many related posts and it seems that using antcall is my only option. Is there another way?
Pre-existing, immutable target: unit-tests
Main target called: release
<macrodef name="unit-tests-macrodef">
<attribute name="is-special-host"/>
<sequential>
<echo message="Running target with #{is-special-host}" />
<property name="jvmargs" value="${baseJvmArgs} -Dis.special.host=#{is-special-host}" />
</sequential>
</macrodef>
<target name="run-unit-tests">
<unit-tests-macrodef is-special-host="false"/>
<unit-tests-macrodef is-special-host="true"/>
</target>
<target name="release" depends="run-unit-tests" />
How do I ensure that unit-tests-macrodef runs unit-tests every time it is invoked?

Related

How to pass Ant property values set in one target to another which does not depend on the first

Below is the example Ant task.
<target name="evalTask">
<condition property="conditionValue" >
<mycustomTask:evaluateCondition/>
</condition>
</target>
<target name="checkAndUpdateFlag" unless="conditionValue">
<property name="isEnabled" value="true"/>
</target>
<target name="targetA" depends="checkAndUpdateFlag" unless="conditionValue">
<echo message="Do something if the conditionValue is set" />
</target>
<target name="targetB">
<echo message=" Value of isEnabled : ${isEnabled} />
</target>
In the above example target "evalTask" will set the property "conditionValue" is the my custom task "evalauateCondition returns true.
The target "targetA" will get executed only if the property "conditionValue" is set. Which I am working fine. But the property "isEnabled" in "checkAndUpdateFlag" is not getting set or it never gets inside "checkAndUpdateFlag" target and I still get the "isEnabled" property value inside "targetB" as ${isEnabled}. Basically the "isEnabled" is never set.
Below is the ant command I used to run this targets.
ant targetA targetB
Any suggestion on why I am not getting the value of isEnabled in targetB ?
In your example, the evalTask target never runs so the conditionValue property is never set.
Since the conditionValue property isn't set, the checkAndUpdateFlag target won't run:
<target name="checkAndUpdateFlag" unless="conditionValue">
The unless="conditionValue" tells Ant to skip the <target name="checkAndUpdateFlag"> if the conditionValue property isn't set.
Possible solution #1:
Add a depends to checkAndUpdateFlag:
<target name="checkAndUpdateFlag" unless="conditionValue" depends="evalTask">
<!-- ... -->
Possible solution #2:
Call the evalTask target first on the command line:
ant evalTask targetA targetB

antcontrib foreach executed in parallel does not raise errors

I have the following ant script that I can't seem to find a way to make fail when parallel is set to true for antcontrib's foreach task. Any ideas?
<project name="asdf" >
<taskdef resource="net/sf/antcontrib/antcontrib.properties">
<classpath>
<pathelement location="../lib/ant/ant-contrib-1.0b3.jar" />
</classpath>
</taskdef>
<target name="build">
<foreach target="exex-subant" param="foreach.dir" parallel="true" maxthreads="4" inheritall="true" list="1,2,3">
<param name="target" value="build" />
</foreach>
</target>
<target name="exex-subant">
<fail>test</fail>
</target>
</project>
This occurs because when executed in parallel, <foreach> uses the <parallel> task, but does not set the "failonany" property, or give any way to say that the task should fail if any iteration failed.
Fortunately, there is a relatively easy workaround, which is to use <for> instead of <foreach>. In your example, that would look like this:
<target name="build">
<for param="foreach.dir" parallel="true" list="1,2,3">
<sequential>
<antcall target="exex-subant" inheritall="true">
<param name="target" value="build" />
<param name="foreach.dir" value="#{foreach.dir}" />
</antcall>
</sequential>
</for>
</target>
Note that you have to explicitly pass in the foreach.dir property, which will then be accessible in the exex-subant target as ${foreach.dir}.
This will execute all iterations in parallel, but the script will fail if any one of them fails (it will not execute anything beyond the for task).
Note that in order to use the for task, you'll need ant 1.6 or higher, and will need to change your taskdef to:
<taskdef resource="net/sf/antcontrib/antlib.xml">
<classpath>
<pathelement location="../lib/ant/ant-contrib-1.0b3.jar" />
</classpath>
</taskdef>
If for some reason you need to support older versions of ant, then you would have to change the exex-subant target slightly, so that it changed something when it failed. For example, you could wrap the current logic in exex-subant within a try/catch, and in the catch block it could create a file. Then after the foreach terminates you can check to see if that file exists, and fail the build if it does. That way, if any execution of the foreach fails, the ant script will fail after the foreach finishes.
Note that you can't just set a property in exex-subant on failure, since the property won't propagate back to the foreach loop (which is why I suggested creating a file). But I'd strongly recommend just using the for task and requiring ant 1.6 or higher.

"global var" in ant

I'm calling one target (e.g target) from other targets (e.g. first, second). Is there a way to define a property (or whatever) in target in such a way that it could be used in first and second. Please don't advise me to pass a variable as a parameter into first and second
Every "variable" (property) ever set in ant is always "global"
<project name="foo" default="first">
<target name="first" depends="target">
<echo message="${foo}"/>
</target>
<target name="second" depends="target">
<echo message="${foo}"/>
</target>
<target name="target">
<property name="foo" value="bar"/>
</target>
</project>
In latest versions of ant you can use the "local" task to declare a variable as local.
Otherwise properties are always global.

Ant antcall a target that defines a property

In Ant I want to define a target (called A) that define a property and antcall it from another target (called B). I want that the target B, after antcalling the target A, can access the property defined in the target A.
For example:
<target name="B">
<antcall target="A" inheritAll="true" inheritRefs="true" />
<echo>${myprop}</echo>
</target>
<target name="A">
<property name="myprop" value="myvalue" />
</target>
However it doesn't work and <echo>${myprop}</echo> doesn't print myvalue (I think because the property myprop isn't defined in B).
Is there any way to do that?
According to the Apache Ant FAQ:
<target name="cond" depends="cond-if"/>
<target name="cond-if" if="prop1">
<antcall target="cond-if-2"/>
</target>
<target name="cond-if-2" if="prop2">
<antcall target="cond-if-3"/>
</target>
<target name="cond-if-3" unless="prop3">
<echo message="yes"/>
</target>
Note: <antcall> tasks do not pass property changes back up to the environment they were called from, so you wouldn't be able to, for example, set a result property in the cond-if-3 target, then do <echo message="result is ${result}"/> in the cond target.
In this respect, it is impossible to do what you want using antcall.
========== edit ===========
Try antcallback: AntCallBack is identical to the standard 'antcall' task, except that it allows properties set in the called target to be available in the calling target.
http://antelope.tigris.org/nonav/docs/manual/bk03ch20.html
Sample code pasted from the above page:
<target name="testCallback" description="Test CallBack">
<taskdef name="antcallback" classname="ise.antelope.tasks.AntCallBack" classpath="${antelope.home}/build" />
<antcallback target="-testcb" return="a, b"/>
<echo>a = ${a}</echo>
<echo>b = ${b}</echo>
</target>
<target name="-testcb">
<property name="a" value="A"/>
<property name="b" value="B"/>
</target>
Another approach is to refactor your targets into macros. You are trying to use targets like functions and they are just not intended to be used that way. I typically write the bulk of my logic as macros, so that I can compose it more easily into more complicated macros. Then I write simple wrapper targets for the command-line entry points that I need.
Rather than using <antcall>, why not just have target B depend on target A?
<target name="B" depends="A">
<echo>${myprop}</echo>
</target>
<target name="A">
<property name="myprop" value="myvalue" />
</target>
I think you want to use a param.
<project default="B">
<target name="B">
<antcall target="A">
<param name="myprop" value="myvalue"/>
</antcall>
</target>
<target name="A">
<echo>${myprop}</echo>
</target>
</project>
I surrounded this with a project tag and moved the echo statement into "A". My output says
B:
A:
[echo] myvalue
BUILD SUCCESSFUL
#alem0lars, since you said you would like to subdivide a target, let me offer a different solution (that unfortunately doesn't answer your original question).
<project default="mytarg">
<target name="mytarg">
<property name="tgt" value="build"/>
<antcall target="deps"/>
</target>
<target name="deps" depends="aTgt,bTgt"/>
<target name="aTgt">
<echo>"In aTgt doing a ${tgt}"</echo>
</target>
<target name="bTgt">
<echo>"In bTgt doing a ${tgt}"</echo>
</target>
</project>
This subdivides the build into aTgt and bTgt.
Output will be
aTgt:
[echo] "In aTgt doing a build"
bTgt:
[echo] "In bTgt doing a build"
deps:
BUILD SUCCESSFUL

How to invoke a macrodef from within another file

I wrote a small macrodef in separate file:
macrodefs.xml
<macrodef name="do-cool-stuff">
<attribute name="message"/>
<sequential>
<echo message="#{message}" />
</sequential>
</macrodef>
I got a second file, my main build file:
build.xml
<target name="build">
<!-- do this and that -->
<!-- cheking out macrodefs.xml via CVS -->
<ant antfile="macrodefs.xml" target="do-cool-stuff" >
<property name="message" value="Hello, World!" />
</ant>
</target>
As you might guess this dosen't work. The error message is something like:
Target 'do-cool-stuff' does not exist in this project.
The only possible solution I found is to provide a extra target in the macrodefs.xml to forward the ant calls.
Is there a possibility to invoke the macrodef from within another file?
Thanks in advance.
You can import the file and use the macro like this:
<import file="macrodefs.xml" />
<do-cool-stuff message="Hello, World!" />
Note that in the macro definition you should use #{curlybrackets} when referencing macro attributes:
<sequential>
<echo message="#{message}" />
</sequential>
There are some examples at the end of the Ant macrodef task docs.
More
What you're trying to do isn't well supported by Ant. The ant and antcall tasks don't allow the 'callee' to affect the caller directly. You can write files in the called task, then load those in the caller. But as you have observed, the pre-process tasks import and include cannot be called from within a target. The ant/antcall tasks only allow you to run targets in subsidiary builds, not macros.
One workaround method (this might be similar to the one you mention, but allows you to put all the real work in the top-level build) would be to have an inner buildfile that includes the top-level import of the macrodefs.xml.
Something like the following. The macrodefs.xml file is as before. (But note that the imported files - including the macro definitions - need to be complete Ant project files, so they must include a project element.)
build.xml:
<target name="build">
<!-- cvs actions -->
<ant antfile="inner-build.xml" target="target-runner">
<property name="target" value="top-target" />
</ant>
</target>
<!-- this target will fail unless invoked from the inner build -->
<target name="top-target">
<do-cool-stuff message="Hello, World!" />
</target>
inner-build.xml:
<project>
<import file="macrodefs.xml" />
<target name="target-runner">
<ant antfile="build.xml" target="${target}" />
</target>
</project>
Effectively you would be doing
build.xml --> inner-build.xml --> build.xml (again)
(cvs) (import macros) (use macros)
The inner buildfile could potentially be generated on-the-fly by the main build - say if you wanted to import multiple macro definition files - but that's getting perhaps too unwieldy.

Resources