In what order are Ant target's "if" and "depends" evaluated? - ant

That is, will calling the following target when testSetupDone evaluates to false, execute the targets in dependency chain?
<target name="-runTestsIfTestSetupDone" if="testSetupDone" depends="-runTests" />

Yes, the dependencies are executed before the conditions get evaluated.
From the Ant manual:
Important: the if and unless attributes only enable or disable the target to which they are attached. They do not control whether or not targets that a conditional target depends upon get executed. In fact, they do not even get evaluated until the target is about to be executed, and all its predecessors have already run.
Here is an example:
<project>
<target name="-runTests">
<property name="testSetupDone" value="foo"/>
</target>
<target name="runTestsIfTestSetupDone" if="testSetupDone" depends="-runTests">
<echo>Test</echo>
</target>
</project>
The property testSetupDone is set within the target in depends, and the output is:
Buildfile: build.xml
-runTests:
runTestsIfTestSetupDone:
[echo] Test
BUILD SUCCESSFUL
Total time: 0 seconds
Target -runTests is executed, even though testSetupDone is not set at this moment. runTestsIfTestSetupDone is executed afterwards, so depend is evaluated before if.

From the docs:
Ant tries to execute the targets in the depends attribute in the order they
appear (from left to right). Keep in mind that it is possible that a
target can get executed earlier when an earlier target depends on it:
<target name="A"/>
<target name="B" depends="A"/>
<target name="C" depends="B"/>
<target name="D" depends="C,B,A"/>
Suppose we want to execute target D. From its depends attribute,
you might think that first target C, then B and then A is executed.
Wrong! C depends on B, and B depends on A,
so first A is executed, then B, then C, and finally D.
Call-Graph: A --> B --> C --> D

Related

Call Ant target directly and indirectly based on condition

I have the following default target defined in my build file:
<target name="main" depends="generate.doc" unless="generated.doc.present"/>
The property is set when the doc files already exist. In that case I don't want to do anything. However, it doesn't work since the dependent target is always executed before the condition is evaluated.
I still need to be able to call the dependent target directly and execute it, no matter if the output already exists or not. Hence something like this would not work:
<target name="main" depends="generate.doc"/>
<target name="generate.doc" unless="generated.doc.present">...</target>
Is there a solution without using antcall in the main target?
In the example below, the main <target> has been changed to have two dependencies. A new <target> named -pre-conditions will run before generate.doc.
The -pre-conditions <target> sets the skip-generate.doc property only if the generated.doc.present property has already been set.
The generate.doc <target> has been changed so it will be skipped if -pre-conditions set the skip-generate.doc property.
With these changes, generate.doc will always run when it's called directly.
<target name="-pre-conditions">
<condition property="skip-generate.doc">
<isset property="generated.doc.present"/>
</condition>
</target>
<target name="main" depends="-pre-conditions, generate.doc"/>
<target name="generate.doc" unless="skip-generate.doc">
<echo>generate.doc running</echo>
</target>

how to call multiple ant targets for foreach

here is what am trying to do, I want to replace name and address from my large number of property files during build, but unfortunately I cant do this, is there a better way of doing this without having to copy paste the foreach twice. can someone help?
<target name="replace" >
<foreach target="replace.name,replace.address" param="foreach.file" inheritall="true">
<path>
<fileset dir="${build.tmp.dir}/resource">
<!-- some complicated conditions go here -->
</path>
</foreach>
</target>
<target name="replace.address">
<echo>replacing #Address# for ${foreach.file}</echo>
<replace file="${foreach.file}" token="#Address#" value="${address}" />
</target>
<target name="replace.name">
<echo>replacing #Name# for ${foreach.file}</echo>
<replace file="${foreach.file}" token="#Name#" value="${Name}" />
</target>
.properties file looks like
name=#Name#
address=#Address#
target of foreach is not designed to take more than one target name. It only iterates through the provided list, not the provided targets.
To make the implementation more DRY, you may
use a for loop instead of foreach with two antcalls;
use macrodef with for loop -- macrodef can pack several ant xml code into a task-like thing
Actually, for the two targets -- replace.address and replace.name, are you sure that you want to call them from the commandline?
If not, name them -replace.address and -replace.name or use macrodef -- exposing the iteration body of foreach is not a good practice.

ant - Running a target at the end of every build

Is there a way to always run a target at the end of every build?
I know I can do something like this...
<target name="runJob" depends="actuallyRunJob, teardown"/>
... but that's sloppy, since I'd need a wrapper for every target that needs a teardown.
Any ideas?
Thanks,
Roy
use a buildlistener, f.e. the exec-listener which provides a taskcontainer for each build result ( BUILD SUCCESSFUL | BUILD FAILED ) where you can put all your needed tasks in
see Conditional Task on exec failure in Ant for further details
or roll your own build listener, see =
http://ant.apache.org/manual/develop.html
and the api docs from your ant installation =
$ANT_HOME/docs/manual/api/org/apache/tools/ant/BuildListener.html
In the same spirit as Rebse's answer, you can write a BuildListener in Javascript as follows (if you don't mind trading an Ant extension against some code in your makefile):
<project name="test-ant" default="build">
<target name="init">
<script language="javascript"> <![CDATA[
function noop () {}
var listener = new org.apache.tools.ant.BuildListener() {
buildFinished: function(e) {
project.executeTarget("_finally");
},
buildStarted: noop,
messageLogged: noop,
targetStarted: noop,
targetFinished: noop,
taskStarted: noop,
taskFinished: noop
}
project.addBuildListener(listener)
]]></script>
</target>
<target name="build" depends="init"/>
<target name="fail" depends="init">
<fail message="expected failure"/>
</target>
<target name="_finally">
<echo message="executing _finally target..."/>
</target>
</project>
Intercepting other events should be quite easy as you can see.
I had a similar need and ended up writing a custom task, which looks like this:
<!-- a task that executes the embedded sequential element at the end of the build,
but only if the nested condition is true; in this case, we're dumping out the
properties to a file but only if the target directory exists (otherwise, the clean
target would also generate the file and we'd never really be clean!) -->
<build:whendone>
<condition>
<available file="${project_target-dir}" />
</condition>
<sequential>
<mkdir dir="${project_final-build-properties-file}/.." />
<echoproperties destfile="${project_final-build-properties-file}" />
</sequential>
</build:whendone>
In this case, I wanted a record of all of the Ant properties that contributed to a build, but doing that at the beginning of the build misses quite a few (if they're initialized as part of targets, after dumping them to the file).
Unfortunately, I can't share specific code, but this is nothing more than an Ant Task that implements SubBuildListener, specifically buildFinished(BuildEvent). The listener tests the embedded condition and then, if true, executes the embedded sequential.
I'd love to know if there's a better way.
If it's an android project you can easily override the "-post-build" target in your local "build.xml" file. This target is just for this purpose.

Ant: How to test if a target exist (and call it not if it doesn't)?

I have a set of build files, some of them calling others -- importing them first. End of line builds may have or may not have a specific target (e.g. "copyother"). I want to call it from my main build file if that target is defined within the end-of-line build script. How can I do it?
Part of the calling script:
<!-- Import project-specific libraries and classpath -->
<property name="build.dir" value="${projectDir}/build"/>
<import file="${build.dir}/build_libs.xml"/>
...
<!-- "copyother" is a foreign target, imported in build_libs.xml per project -->
<target name="pre-package" depends=" clean,
init,
compile-src,
copy-src-resources,
copy-app-resources,
copyother,
compile-tests,
run-junit-tests"/>
I do not want every project to define "copyother" target. How can I do a conditional ant call?
I'm guessing you aren't importing the "other" build scripts into your main build.xml. (Because that wouldn't work. Ant treats imports as local.)
At the same time, you are using depends and not ant/ant call so maybe you are importing them, but one at a time.
You can't do what you want in native Ant. As you noted testing for a file is easy but a target is not. Especially if that other project isn't loaded yet. You definitely have to write a custom Ant task to accomplish what you want. Two avenues:
1) Call project.getTargets() and see if your target is there. This involves refactoring your script to use ant/antcall instead of pure depends, but doesn't feel like a hack. Writing a custom Java condition isn't hard and there is an example in the Ant manual.
2) Add a target to the current project if not already there. The new target would be a no-op. [not sure if this approach works]
For the same of completeness. Another approach is to have some target for checking the target.
The approach is discussed here: http://ant.1045680.n5.nabble.com/Checking-if-a-Target-Exists-td4960861.html (vimil's post). Check is done using scriptdef. So it is not that different from other answer(Jeanne Boyarsky), but script is easy to add.
<scriptdef name="hastarget" language="javascript">
<attribute name="targetname"/>
<attribute name="property"/>
<![CDATA[
var targetname = attributes.get("property");
if(project.getTargets().containsKey(targetname)) {
project.setProperty(attributes.get("property"), "true");
}
]]>
</scriptdef>
<target name="check-and-call-exports">
<hastarget targetname="exports" property="is-export-defined"/>
<if>
<isset property="is-export-defined"/>
<then>
<antcall target="exports" if="is-export-defined"/>
</then>
</if>
</target>
<target name="target-that-may-run-exports-if-available" depends="check-and-call-exports">
You should explore use of the typefound condition, added to ANT in 1.7. You can use it, for example, with the if task from antcontrib like this, but you have to check for a macrodef and not a taskdef due to how it works:
<if>
<typefound name="some-macrodef"/>
<then>
<some-macrodef/>
</then>
</if>
With this, ant files that have a macrodef named "some-macro-or-taskdef" will get it invoked and other ant files without it will not get an error.

ANT: How to read property setted in a foreach loop

Dear, I currently face some problem to retrieve the value of a property setted in a foreach loop. Maybe one of you could help me...
The purpose is to check if one file of a folder has been modified since the corresponding jar has been generated. This way I know if I have to generate the jar again.
What I do is to go through the folder with a foreach loop and if one file match my test, set a property to true.
The problem is that my variable doesn't seems to exist after my loop... Here is a simplified code example that has the same problem:
<target name="target">
<taskdef resource="net/sf/antcontrib/antlib.xml" classpath="${lib.dir}/ant-contrib.jar"></taskdef>
<foreach target="setVar" param="var" list="a,b"/>
<echo>myreturn in target: ${env.myreturn}</echo>
<property name="env.myreturn" value="c"/>
<echo>myreturn in second: ${env.myreturn}</echo>
</target>
<target name="setVar">
<property name="env.myreturn" value="${var}"/>
<echo>myreturn in setVar: ${env.myreturn}</echo>
</target>
The result of this code is:
target:
setVar:
[echo] myreturn in setVar: a
setVar:
[echo] myreturn in setVar: b
[echo] myreturn in target: ${env.myreturn}
[echo] myreturn in second: c
BUILD SUCCESSFUL
It seems that the variable is correctly set as it could be printed in the "setVar" target but no way to retrieve value from the calling target.
I also know it's not possible to assign a value to a property twice. But the problem doesn't even occurs... When it'll be the case I could add a check on the value of the property before to assign it to be sure it is not already initialized...
Do you have a clue on the way I can solve my problem ???
Many thanks in advance for your help :)
Try <for> task from ant-contrib instead of <foreach>. The <for> task takes advantage of Ant macro facility that came later. It works faster and is more flexible than the older <foreach> task. You are in the same project context when using <for>. That means properties set in the loop will be visible outside of the loop. Of course, normal rules for properties apply... you only get to set it once... unless you use <var> task from ant-contrib to overwrite or unset previously set properties.
Ah the joys of Ant hacking.
Not sure about your foreach problem, but can you not use the uptodate task for your requirement?
Even if I don't need it anymore thanks to sudocode, I found a solution for my question. Maybe it could be useful for someone else...
A collegue talked about the "antcallback" target of ant-contrib: it allows to return a result from a called target to the calling one. With a combination of "for" target and "antcallback" it is possible to do what I wanted to do:
<target name="target">
<taskdef resource="net/sf/antcontrib/antlib.xml" classpath="${lib.dir}/ant-contrib.jar"></taskdef>
<for param="file">
<path>
<fileset dir="../myDirectory" includes="**/*" />
</path>
<sequential>
<antcallback target="setVar" return="retValue">
<param name="file" value="#{file}"/>
</antcallback>
</sequential>
</for>
<echo>result: ${retValue}</echo>
</target>
<target name="setVar">
<property name="retValue" value="${file}"/>
</target>
"file" contains the name of the file in the directory. It is given to the called target as parameter with value "#{file}" ('#' necessary due to "for" target implementation).
At the end of the main target, ${retValue} contains the first value setted by the "setVar" target. No error is thrown when trying to set it multiple times, so it's not necessary to check if variable has already been instantiated before to set it in "setVar" target.
The <foreach> task uses the same logic as <antcall> under the covers, and any proprrties set inside a target invoked by <antcall> do not have scope beyond the execution of that target.
In other words, the env.myreturn property that you define in the setVar target is lost as soon as execution of that target completes.
This sort of scripting really isn't what Ant is designed for. The Ant-contrib library tries to patch up the holes, but it's still bending it way out of shape.
If you need to write such scripts, and want to use Ant tasks to achieve them, have a look at Gradle instead. It's a rather lovely blend of Groovy (for scripting) and Ant (for the tasks).
The other approaches here (<for>, <var>, <groovy>properties.put(....)</groovy>, <property>, <antcallback>) did not work with ANT 1.9.4, so I used the file system similar to this (pseudocode):
<target name="outer">
<for> <antcall target="inner" /> </for>
<loadproperties srcfile="tmpfile.properties" />
<echo message="${outerprop}" />
</target>
<target name="inner">
<!-- did not work: -->
<!--
<property name="outerprop" value="true" />
<var name="outerprop" value="true" />
<groovy>properties.put('outerprop','true')</groovy>
<antcallback target="setouterprop" />
-->
<echo message="outerprop=true" file="tmpfile.properties" />
</target>
Maybe the other approaches did not work because of my <antcall>, but I need it here. (outerprop is initially unset)

Resources