9 Stimmen

Gibt es eine Möglichkeit zu garantieren, dass eine Ant-Abhängigkeit nur einmal ausgeführt wird?

Meine Frage ist ähnlich wie vermeidende-umbau-voraussetzungen-in-ant Ich brauche jedoch keine erstellten Objekte, sondern aufgerufene Prozesse, so dass die dort erörterten Lösungen für mich nicht funktionieren werden. Zumindest denke ich so - aber ich bin neu bei ant.

Meine Situation ist, dass ich eine Reihe von Ameisen-Ziele zu schreiben, und ich brauche die lets-call-it Einrichtung Ziel einmal und nur einmal ausgeführt werden, unabhängig davon, welches Ziel aufgerufen wird. Hier ist ein stark vereinfachtes Beispiel:

    <?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>

Ich brauche Einrichtung genau einmal aufgerufen werden, unabhängig davon, ob tun.mehrere , tun.erst , oder do.second aufgerufen werden. Bei meinem naiven Versuch oben führt der Aufruf von do.several zu drei Aufrufen von Einrichtung .

Ich habe daran gedacht, eine Eigenschaft zu setzen (nennen wir sie setup.wurde.aufgerufen ), und die Verwendung dieses Parameters zum bedingten Aufruf von Einrichtung von jedem Ziel aus, aber es scheint, dass die Eigenschaftseinstellung auf den Bereich beschränkt ist, in dem sie vorgenommen wird, wenn also in Einrichtung stelle ich setup.wurde.aufgerufen auf true gesetzt wird, existiert dieser Wert nur innerhalb Einrichtung .

Was übersehe ich? Gibt es einen Abschnitt in den Tutorials oder der Online-Dokumentation, den ich übersprungen habe? Haben Sie irgendwelche Hinweise oder Tipps?

13voto

Peter Lang Punkte 52229

Sie sollten die antcalls und hinzufügen do.first y do.second als Abhängigkeiten von do.several :

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

Damit wird sichergestellt, dass setup wird nur einmal aufgerufen:

setup:
     [echo] In setup

do.first:
     [echo] In do.first

do.second:
     [echo] In do.second

do.several:

BUILD SUCCESSFUL
Total time: 0 seconds

In der Dokumentation steht, warum eine im Setup festgelegte Eigenschaft nicht mit antcall funktioniert:

Das/die aufgerufene(n) Ziel(e) werden in einem neuen Projekt ausgeführt; beachten Sie, dass dies bedeutet, dass Eigenschaften, Referenzen usw., die von aufgerufenen Zielen gesetzt wurden, nicht in das aufrufende Projekt zurückgeführt werden.

9voto

Mensfeld Punkte 91

Ich möchte nur eine weitere Möglichkeit hinzufügen, dies zu tun.

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

Auf diese Weise führen Sie es nur einmal aus und setzen dann sofort das Kennzeichen, dass es bereits einmal ausgeführt wurde. Außerdem bricht es nicht den "depends"-Teil Ihres Codes, da es nur Ziele ausführt, wenn es möglich/notwendig ist, aber es bricht nicht die Ausführung des zielabhängigen Ziels.

Dies ist auch die geringste Änderung in Ihren Skripten.

Bearbeiten: Erläuterung des Teils "macht die Abhängigkeiten nicht kaputt" :

Wenn 'ant do.first do.second' aufgerufen wird, führt dies dazu, dass setup zweimal aufgerufen wird, auch wenn alle Ziele setup als Abhängigkeit verwenden. Das wäre ein Problem, wenn setup Dinge wie das Klonen eines Repositories oder andere zeitaufwändige Operationen durchführt. Dieser Ansatz funktioniert für beide Fälle - also 'ant do.several' oder 'ant do.first do.second'.

3voto

Dan Dyer Punkte 52915

Eine Alternative zu den Antworten, die Sie bereits erhalten haben, besteht darin, einen benutzerdefinierten Aufgabencontainer zu erstellen, der sicherstellt, dass er eine Aktion nicht wiederholt. Ich habe eine solche benutzerdefinierte Aufgabe in meine persönliche Antlib aber da ist noch eine ganze Menge anderer Kram drin, den Sie wahrscheinlich nicht wollen, also können Sie vielleicht einfach kopieren die Quelle und fügen Sie es zu Ihrem eigenen Projekt hinzu. Es sieht in etwa so aus:

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");
        }
    }
}

2voto

Ravedave Punkte 1148

Ziele können ein "unless"-Element haben, das das Ziel überspringt, wenn die durch "unless" referenzierte Eigenschaft gesetzt ist.

1voto

user16797 Punkte 361

Sehen Sie den Unterschied, zwischen einschließen. y importieren im Ant-Handbuch. Verwenden Sie auch macrodefs .

Ich habe Ihr Beispiel leicht abgewandelt, Sie benötigen mehrere Dateien: build.xml, common.xml und 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>

Makrodef

<?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>

Ausgabe:

ant -p
Buildfile: build.xml
Main targets:

Other targets:

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

Das Standardziel ist jetzt init.

ant
Buildfile: build.xml

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

Sie können aber trotzdem die Ameisenstraße benutzen.

ant setup
Buildfile: build.xml

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

Führen Sie es mit do.several aus.

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X