Is there a way to ensure that the ant dependency runs only once?

My question is similar to avoiding-re-building-prerequisites-in-ant , except that my need is not related to the objects being created, but calls, so the solutions discussed there will not work for me. At least I think so, but I'm new to ant.

My situation is that I am writing a set of ant targets, and I need the put-call-it installation target to be executed once and only once, regardless of which target is invoked. Here is a very simplified example:


    <?xml version="1.0"?>
    <project name="Ant_Test" basedir=".">
      <target name="setup">
        <echo message="In setup" />
      </target>
      <target name="do.several" depends="setup">
        <echo message="In do.several, calling do.first" />
        <antcall target="do.first" />
        <echo message="In do.several, calling do.second" />
        <antcall target="do.second" />
      </target>
      <target name="do.first" depends="setup">
        <echo message="In do.first" />
      </target>
      <target name="do.second" depends="setup">
        <echo message="In do.second" />
      </target>
    </project>

I need a setting that needs to be called exactly once, regardless of whether do.several, do.first or do.second are called. With my naive attempt above, calling do.several results in three setup calls.

( setup.has.been.invoked) , , , , setup.has.been.invoked true, .

? -, ? ?

+5
5

antcalls do.first do.second do.several:

<target name="do.several" depends="setup, do.first, do.second">
</target>

, setup :

setup:
     [echo] In setup

do.first:
     [echo] In do.first

do.second:
     [echo] In do.second

do.several:

BUILD SUCCESSFUL
Total time: 0 seconds

, set antcall:

; , , , .., , .

+9

.

<target name="setup" unless="setup.already.executed">
    <echo message="In setup" />
    <property name="setup.already.executed" value="x" />
</target>

, , . "" , , /, .

.

+6

, , , , . Antlib, , , , , , . :

import org.apache.tools.ant.Task;
import org.apache.tools.ant.TaskContainer;
import org.apache.tools.ant.BuildException;
import java.util.List;
import java.util.LinkedList;

/**
 * Task container to ensure that some set of actions is only performed
 * once per build.  On completion of the actions a property is set that
 * prevents subsequent executions.
 */
public class Once extends Task implements TaskContainer
{
    private final List<Task> tasks = new LinkedList<Task>();

    private String property;

    /**
     * The name of the property to consult in order to determine whether
     * the nested tasks should be performed.  This is a required attribute.
     */
    public void setProperty(String property)
    {
        this.property = property;
    }

    public void addTask(Task task)
    {
        tasks.add(task);
    }     

    @Override
    public void execute() throws BuildException
    {
        if (property == null || property.length() == 0)
        {
            throw new BuildException("Property name must be specified.");
        }
        // If no value is specified, the tasks are performed if the property
        // is set to any value.  If a value is specified, the tasks are only
        // performed if the property matches that value.
        if (getProject().getProperty(property) == null)
        {
            for (Task task : tasks)
            {
                task.perform();
            }
            getProject().setProperty(property, "done");
        }
    }
}
+3

include import Ant. .

, : build.xml, common.xml macrodef_project_setup.xml

build.xml

<?xml version="1.0"?>
<project name="Ant_Test" basedir="." default="init">

<import file="common.xml"/>

<!-- This target overridden by the one in common.xml -->
<target name="common.init"/>

<target name="setup" depends="init"/>

<target name="do.several" depends="common.setup">
    <echo message="In do.several, calling do.first" />
    <antcall target="do.first" />
    <echo message="In do.several, calling do.second" />
    <antcall target="do.second" />
</target>

<target name="do.first" depends="common.setup">
    <echo message="In do.first" />
</target>
<target name="do.second" depends="common.setup">
    <echo message="In do.second" />
</target>

</project>

common.xml

<?xml version="1.0"?>
<project name="common">

<target name="init">
    <project_setup option="Stack.Over.Flow"/>
</target>

<target name="setup">
</target>

<import file="macrodef_project_setup.xml"/>

</project>

macrodef

<?xml version="1.0"?>
<project name="project_setup" basedir=".">

<macrodef name="project_setup">
        <attribute name="option" default=""/>
        <sequential>

            <!-- some process -->
            <echo>THIS IS MY SETUP OPTION: @{option}</echo>

        </sequential>
</macrodef>

</project>

Output:

ant -p
Buildfile: build.xml
Main targets:

Other targets:

 common.setup
 do.first
 do.second
 do.several
 init
 setup
Default target: init

The default target is init.

ant
Buildfile: build.xml

Ant_Test.init:
     [echo] In setup initialization
     [echo] THIS IS MY SETUP OPTION: Stack.Over.Flow

But you can still use Ant setup.

ant setup
Buildfile: build.xml

Ant_Test.init:
     [echo] In setup initialization 
     [echo] THIS IS MY SETUP OPTION: Stack.Over.Flow

Run it with do.several.

ant do.several
Buildfile: build.xml

Ant_Test.init:
     [echo] In setup initialization 
     [echo] THIS IS MY SETUP OPTION: Stack.Over.Flow

Ant_Test.do.several:
     [echo] In do.several, calling do.first

Ant_Test.do.first:
     [echo] In do.first

     [echo] In do.several, calling do.second

Ant_Test.do.second:
     [echo] In do.second
+1
source

Goals can have an if element that will skip the goal if a property is set that the if points to.

0
source

All Articles