Chcę wykonać polecenie z pliku kompilacji Ant, dla każdego pliku w katalogu.
Szukam rozwiązania niezależnego od platformy.
Jak mam to zrobic?
Jasne, mógłbym napisać skrypt w jakimś języku skryptowym, ale dodałoby to dalsze zależności do projektu.
Chcę wykonać polecenie z pliku kompilacji Ant, dla każdego pliku w katalogu.
Szukam rozwiązania niezależnego od platformy.
Jak mam to zrobic?
Jasne, mógłbym napisać skrypt w jakimś języku skryptowym, ale dodałoby to dalsze zależności do projektu.
Odpowiedzi:
Użyj <foreach>
z zagnieżdżonym plikiem<FileSet>
Foreach wymaga ant-contrib .
Zaktualizowany przykład dla niedawnego ant-contrib:
<target name="foo">
<foreach target="bar" param="theFile">
<fileset dir="${server.src}" casesensitive="yes">
<include name="**/*.java"/>
<exclude name="**/*Test*"/>
</fileset>
</foreach>
</target>
<target name="bar">
<echo message="${theFile}"/>
</target>
Spowoduje to wywołanie docelowego "baru" z $ {theFile} skutkującym plikiem bieżącym.
Użyj zadania <apply> .
Wykonuje polecenie raz dla każdego pliku. Określ pliki za pomocą zestawów plików lub dowolnego innego zasobu. <apply> jest wbudowane; nie jest potrzebna żadna dodatkowa zależność; nie ma potrzeby wykonywania niestandardowych zadań.
Możliwe jest również uruchomienie polecenia tylko raz, dołączając wszystkie pliki jako argumenty za jednym razem. Użyj atrybutu parallel, aby zmienić zachowanie.
Przepraszam za spóźnienie o rok.
Podejście bez wkładu mrówek jest sugerowane przez Tassilo Horn ( oryginalny cel jest tutaj )
Zasadniczo, ponieważ nie ma rozszerzenia <java> (jeszcze?) W taki sam sposób, w jaki <apply> rozszerza <exec> , sugeruje użycie <apply> (które oczywiście może również uruchomić program java w wierszu poleceń)
Oto kilka przykładów:
<apply executable="java">
<arg value="-cp"/>
<arg pathref="classpath"/>
<arg value="-f"/>
<srcfile/>
<arg line="-o ${output.dir}"/>
<fileset dir="${input.dir}" includes="*.txt"/>
</apply>
Oto sposób na zrobienie tego za pomocą javascript i zadania ant scriptdef. Nie potrzebujesz ant-contrib, aby ten kod działał, ponieważ scriptdef jest podstawowym zadaniem ant.
<scriptdef name="bzip2-files" language="javascript">
<element name="fileset" type="fileset"/>
<![CDATA[
importClass(java.io.File);
filesets = elements.get("fileset");
for (i = 0; i < filesets.size(); ++i) {
fileset = filesets.get(i);
scanner = fileset.getDirectoryScanner(project);
scanner.scan();
files = scanner.getIncludedFiles();
for( j=0; j < files.length; j++) {
var basedir = fileset.getDir(project);
var filename = files[j];
var src = new File(basedir, filename);
var dest= new File(basedir, filename + ".bz2");
bzip2 = self.project.createTask("bzip2");
bzip2.setSrc( src);
bzip2.setDestfile(dest );
bzip2.execute();
}
}
]]>
</scriptdef>
<bzip2-files>
<fileset id="test" dir="upstream/classpath/jars/development">
<include name="**/*.jar" />
</fileset>
</bzip2-files>
project
w powyższym przykładzie występuje odniesienie do zmiennej , ale bez udostępnionej wcześniejszej definicji. Byłoby dobrze, gdyby to zostało przedstawione lub wyjaśnione. EDYCJA: n / m, stwierdzono, że project
jest to predefiniowana zmienna dostępu do bieżącego projektu. Podejrzewałem to, ale nie byłem pewien.
mrówka jest złem; napisz własne zadanie mrówki.
ant-contrib jest zła, ponieważ próbuje zmienić styl mrówki ze stylu deklaratywnego na imperatywny. Ale xml tworzy gówniany język programowania.
W przeciwieństwie do tego, niestandardowe zadanie mrówki umożliwia pisanie w prawdziwym języku (Java), w prawdziwym środowisku IDE, w którym można pisać testy jednostkowe, aby upewnić się, że zachowuje się pożądane, a następnie sporządzić czystą deklarację w skrypcie kompilacji o pożądane zachowanie.
Ta racja ma znaczenie tylko wtedy, gdy zależy ci na pisaniu skryptów mrówek, które można utrzymać. Jeśli nie zależy Ci na łatwości utrzymania, zrób wszystko, co działa. :)
Jtf
Wiem, że ten post jest naprawdę stary, ale teraz, gdy minęło trochę czasu i wersji Ant, jest sposób na zrobienie tego z podstawowymi funkcjami Ant i pomyślałem, że powinienem się nim podzielić.
Odbywa się to za pomocą rekurencyjnej makrodefy, która wywołuje zagnieżdżone zadania (można wywołać nawet inne makra). Jedyną konwencją jest użycie stałej nazwy zmiennej (tutaj elementu).
<project name="iteration-test" default="execute" xmlns="antlib:org.apache.tools.ant" xmlns:if="ant:if" xmlns:unless="ant:unless">
<macrodef name="iterate">
<attribute name="list" />
<element name="call" implicit="yes" />
<sequential>
<local name="element" />
<local name="tail" />
<local name="hasMoreElements" />
<!-- unless to not get a error on empty lists -->
<loadresource property="element" unless:blank="@{list}" >
<concat>@{list}</concat>
<filterchain>
<replaceregex pattern="([^;]*).*" replace="\1" />
</filterchain>
</loadresource>
<!-- call the tasks that handle the element -->
<call />
<!-- recursion -->
<condition property="hasMoreElements">
<contains string="@{list}" substring=";" />
</condition>
<loadresource property="tail" if:true="${hasMoreElements}">
<concat>@{list}</concat>
<filterchain>
<replaceregex pattern="[^;]*;(.*)" replace="\1" />
</filterchain>
</loadresource>
<iterate list="${tail}" if:true="${hasMoreElements}">
<call />
</iterate>
</sequential>
</macrodef>
<target name="execute">
<fileset id="artifacts.fs" dir="build/lib">
<include name="*.jar" />
<include name="*.war" />
</fileset>
<pathconvert refid="artifacts.fs" property="artifacts.str" />
<echo message="$${artifacts.str}: ${artifacts.str}" />
<!-- unless is required for empty lists to not call the enclosed tasks -->
<iterate list="${artifacts.str}" unless:blank="${artifacts.str}">
<echo message="I see:" />
<echo message="${element}" />
</iterate>
<!-- local variable is now empty -->
<echo message="${element}" />
</target>
</project>
Najważniejsze funkcje potrzebne, gdy:
Nie udało mi się ustawić separatora zmiennego, ale może to nie być poważny minus.
Możesz użyć zadania ant-contrib „for”, aby iterować na liście plików oddzielonych dowolnym separatorem, domyślnym separatorem jest „,”.
Poniżej znajduje się przykładowy plik, który to pokazuje:
<project name="modify-files" default="main" basedir=".">
<taskdef resource="net/sf/antcontrib/antlib.xml"/>
<target name="main">
<for list="FileA,FileB,FileC,FileD,FileE" param="file">
<sequential>
<echo>Updating file: @{file}</echo>
<!-- Do something with file here -->
</sequential>
</for>
</target>
</project>