Iterate over for loop with fixed amount of iterations

Sergei Ledvanov picture Sergei Ledvanov · Nov 28, 2013 · Viewed 18.2k times · Source

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.

Answer

halfbit picture halfbit · Nov 28, 2013

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 &lt; 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 antcalls:

<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 &lt; 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>