'Use a phing ForEach loop to execute tasks

I want to execute an arbitrary selection of tasks in a Phing build.

I'm passing in a list of modules for building. Each module is of a particular type. The type is specified in the name, as {type}_{unitname}. I started with a build file that took a single module name and built it, that works fine. I now want to pass in a list of modules and have it build all of them. (What I'd really like to do is load the list of modules from an XML manifest file, but perhaps one thing at a time).

I've tried multiple ways and have found a problem with each.

I seem to need an ad-hoc task to derive my properties (task and related directory settings) from the module name. This seems to cause problems, but not at first.

At first I tried to use the loop variable as the target

<foreach list="${mylist}" param="item" target="${item"} />

but it doesn't seem to allow a variable as a target name. So I split it up into two tasks.

<foreach list="${parts}" param="dTarg" target="doIt" >
<task name="DoIt">
    <phingcall target="build">
        <property name="extension" value="${dTarg}" />
    </phingcall -->
</task>

My problem here is (I think) "extension" is a constant and thus can't be overwritten. I tried using "var", which the docs say is a thing, but my setup complains it doesn't exist. Is it a 3.0 feature? I'm running 2.17.

So I tried changing the "phingcall" to "phing" and put my main functionality in a separate file. Here I run into problems with the ad-hoc task again. If I put it in the "subordinate" file, it complains that's it's re-declared (I think, the message isn't very helpful) when the file is called a second time. If I leave it in the main file, the subordinate file can't find it, even with inheritrefs and inheritall set.

How can I execute tasks whose names are in list?



Solution 1:[1]

At first I tried to use the loop variable as the target

<foreach list="${mylist}" param="item" target="${item"} />

but it doesn't seem to allow a variable as a target name

The target attribute of the foreach task is able to use variables as a value, but at this point param="item" is not yet available but in the target it is.

So I split it up into two tasks.

<foreach list="${parts}" param="dTarg" target="doIt" >
<task name="DoIt">
    <phingcall target="build">
        <property name="extension" value="${dTarg}" />
    </phingcall>
</task>

Here you try to use a task task which is simply not a valid target.

What you want to do instead is to have targets to iterate over. The following example demonstrates the usage:

Input build.xml

<?xml version="1.0" encoding="utf-8" ?>

<project name="test" default="main">
    <property name="mylist" value="A,B,C" />

    <target name="main">
        <foreach list="${mylist}" param="item" target="DoIt"/>
    </target>

    <target name="DoIt">
        <echo>${item}</echo>
    </target>

</project>

Output

test > main:


test > DoIt:

     [echo] A

test > DoIt:

     [echo] B

test > DoIt:

     [echo] C

BUILD FINISHED

Complex Example (with property override and inheritAll)

<?xml version="1.0" encoding="utf-8" ?>

<project name="test" default="main">
    <property name="mylist" value="A,B,C" />

    <target name="main">
        <foreach list="${mylist}" param="item" target="DoIt"/>
    </target>

    <target name="DoIt">
        <phingcall target="${item}" inheritAll="true">
            <property name="extension" override="true" value="${item}-ext" />
        </phingcall>
    </target>

    <target name="A">
        <echo>Inside target ${item} with ${extension} extension</echo>
    </target>

    <target name="B">
        <echo>Inside target ${item} with ${extension} extension</echo>
    </target>

    <target name="C">
        <echo>Inside target ${item} with ${extension} extension</echo>
    </target>
</project>

Output

test > main:


test > DoIt:


test > A:

     [echo] Inside target A with A-ext extension

test > DoIt:


test > B:

     [echo] Inside target B with B-ext extension

test > DoIt:


test > C:

     [echo] Inside target C with C-ext extension

BUILD FINISHED

Example execute as one task with changed values from the list

<?xml version="1.0" encoding="utf-8" ?>

<project name="test" default="main">
    <property name="mylist" value="A,B,C" />

    <target name="main">
        <foreach list="${mylist}" param="item" target="DoIt"/>
    </target>

    <target name="DoIt">
        <phingcall target="build">
            <property name="extension" override="true" value="${item}-ext" />
        </phingcall>
    </target>

    <target name="build">
        <echo>Inside target build with ${extension}</echo>
    </target>
</project>

Output

test > main:


test > DoIt:


test > build:

     [echo] Inside target build with A-ext

test > DoIt:


test > build:

     [echo] Inside target build with B-ext

test > DoIt:


test > build:

     [echo] Inside target build with C-ext

BUILD FINISHED

Simplified and final build

<?xml version="1.0" encoding="utf-8" ?>

<project name="test" default="main">
    <property name="mylist" value="A,B,C" />

    <target name="main">
        <foreach list="${mylist}" param="item" target="build">
            <property name="extension" override="true" value="${item}-ext" />
        </foreach>
    </target>

    <target name="build">
        <echo>Inside target build with ${extension}</echo>
    </target>
</project>

Output

test > main:


test > build:

     [echo] Inside target build with A-ext

test > build:

     [echo] Inside target build with B-ext

test > build:

     [echo] Inside target build with C-ext

BUILD FINISHED

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1