I am using ant-contrib library in my ant scripts, but I do not get how can I make a fixed amount of loops using foreach tag? By fixed amount of iterations I do not mean some hardcoded value, but the ant property, supplied from command line.
2 Answers
The following code creates a loop with a fixed number of 5 iterations:
<target name="example">
<foreach param="calleeparam" list="0,1,2,3,4" target="callee"/>
</target>
<target name="callee">
<echo message="${calleeparam}"/>
</target>
It prints
example:
callee:
[echo] 0
callee:
[echo] 1
callee:
[echo] 2
callee:
[echo] 3
callee:
[echo] 4
Edit
If you want a variable number of iterations then you may want to try one of the following approaches (which differ in the number of iterations they support and readability). The first approach can handle a few iterations. It uses a fixed list which gets truncated using a regular expression to get a fixed number of characters.
<target name="example1">
<property name="n" value="17"/>
<property name="maxlist" value="00,01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16,17,18,19"/>
<propertyregex property="list" input="${maxlist}" regexp="(^.{${n}}.{${n}}.{${n}})" select="\1"/>
<foreach param="calleeparam" list="${list}" target="callee"/>
</target>
The second approach can handle quite a number of iterations: It reads a textfile and replaces every character with X,
to form a list which gets truncated like in the previous approach:
<target name="example2">
<property name="n" value="170"/>
<loadfile property="chars" srcfile="${ant.file}"/><!-- some large text file -->
<propertyregex property="maxlist" input="${chars}" regexp="((?:.|[\r\n\t]))" replace="X," global="true"/>
<propertyregex property="list" input="${maxlist}" regexp="(^.{${n}}.{${n}})" select="\1"/>
<foreach param="calleeparam" list="${list}" target="callee"/>
</target>
The third approach uses JavaScript to prepare the list for foreach
:
<target name="example3">
<property name="n" value="330"/>
<property name="target" value="callee"/>
<property name="param" value="calleeparam"/>
<script language="javascript">
var list="", n=parseInt(project.getProperty("n"),10);
for (var i = 0; i < n; i++) list += i + ",";
project.setProperty("list", list);
</script>
<foreach param="calleeparam" list="${list}" target="callee"/>
</target>
The fourth approach does not use foreach
but uses JavaScript to do the desired amount of calls to the target using dynamically created antcall
s:
<target name="example4">
<property name="n" value="3300"/>
<property name="target" value="callee"/>
<property name="param" value="calleeparam"/>
<script language="javascript">
// does n antcall's with iteration number param
var n = parseInt(project.getProperty("n"),10);
for (var i = 0; i < n; i++) {
var t = project.createTask("antcall");
t.setTarget(project.getProperty("target"));
var p = t.createParam();
p.setName(project.getProperty("param"));
p.setValue(""+i);
t.perform();
}
</script>
</target>

- 3,414
- 1
- 20
- 26
-
I edited the question: the total amount of iterations is not known. – Sergei Ledvanov Nov 28 '13 at 14:35
-
For the above to work, you'll need to include the ant-contrib as Brimstedt pointed out, you can do so by having the following in your project: `
` – James Oravec Nov 22 '16 at 23:11
ANT is not a programming language and I'm not a fan of ant-contrib, which I think attempts to retrofit this feature...
My recommendation is to embed a scripting language into your build. The advantage of javascript is that it won't require additional jars, but I think you'll discover the groovy ANT task is extremely powerful.
Example
$ ant -Dtimes=3
loop:
dosomething:
[echo] hello world
dosomething:
[echo] hello world
dosomething:
[echo] hello world
build.xml
<project name="demo" default="loop">
<property name="times" value="2"/>
<target name="loop">
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy"/>
<groovy>
def count = properties.times.toInteger()
(1..count).each {
ant.ant(target: "dosomething")
}
</groovy>
</target>
<target name="dosomething">
<echo message="hello world"/>
</target>
</project>
An extra "bootstrap" target could be added to install groovy jar dependency automatically
<target name="bootstrap">
<mkdir dir="${user.home}/.ant/lib"/>
<get dest="${user.home}/.ant/lib/groovy-all.jar" src="http://search.maven.org/remotecontent?filepath=org/codehaus/groovy/groovy-all/2.2.1/groovy-all-2.2.1.jar"/>
</target>

- 76,015
- 10
- 139
- 185
-
Great post, although it doesn't quite work. Bootstrap work but the jar isn't added to the current classpath. taskdef class org.codehaus.groovy.ant.Groovy cannot be found – spy Jan 21 '15 at 12:15
-
@spy I suspect you using a version of ANT earlier than 1.6? See the ANT documentation for the installation of optional tasks: http://ant.apache.org/manual/install.html#optionalTasks – Mark O'Connor Jan 21 '15 at 18:10
-
I think the issue is I was missing the classpathref. In addition, I'm calling ant from maven, which presents additional classpath challenges. Thanks for the insight – spy Jan 22 '15 at 00:48
-
@spy Yes, using ANT within Maven would work differently. You would need the classpath reference when defining the groovy task. This can be retrieved from the Maven enviroment see the following doco: http://maven.apache.org/plugins/maven-antrun-plugin/examples/classpaths.html – Mark O'Connor Jan 22 '15 at 00:56