Ant: Как выполнить команду для каждого файла в каталоге?
Я хочу выполнить команду из файла сборки Ant для каждого файла в каталоге.
Я ищу платформо-независимое решение.
Как это сделать?
Конечно, я мог бы написать script на некоторых скриптовых языках,
но это добавит дополнительные зависимости к проекту.
Ответы
Ответ 1
Краткий ответ
Используйте <foreach>
с вложенным <FileSet>
Foreach требует ant-contrib.
Обновлен пример недавнего 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>
Это будет antcall целевой "bar" с ${theFile}, в результате получившим текущий файл.
Ответ 2
Используйте <apply> Задача.
Он выполняет команду один раз для каждого файла. Укажите файлы с помощью наборов файлов или любого другого ресурса. < & применять GT; встроен; никакой дополнительной зависимости не требуется; не требуется выполнение специальных задач.
Также можно запустить команду только один раз, добавив все файлы в качестве аргументов за один раз. Используйте параллельный атрибут для переключения поведения.
Извините, что опоздал на год.
Ответ 3
Подход без ant -contrib предлагается Tassilo Horn (исходная цель здесь)
В основном, поскольку нет расширения <java> (пока?) таким же образом
что <apply> расширяет <exec> , он предлагает использовать <apply> (который, конечно же, может также запускать Java-программу в командной строке)
Вот несколько примеров:
<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>
Ответ 4
Вот как это сделать, используя javascript и задачу ant scriptdef, вам не нужен ant -contrib для работы этого кода, поскольку scriptdef является основной задачей 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>
Ответ 5
ant -contrib - зло; напишите пользовательскую задачу ant.
ant -contrib is evil, потому что он пытается преобразовать ant из декларативного стиля в императивный стиль. Но xml делает язык программирования дерьма.
В отличие от пользовательской задачи ant вы можете писать на реальном языке (Java) с реальной IDE, где вы можете писать модульные тесты, чтобы убедиться, что у вас есть поведение, которое вы хотите, и затем сделать чистое объявление в вашей сборке script о поведении, которое вы хотите.
Это разглагольствование имеет значение только в том случае, если вы заботитесь о написании поддерживаемых сценариев ant. Если вы не заботитесь о ремонтопригодности, все делаете.:)
JTF
Ответ 6
Я знаю, что этот пост очень старый, но теперь, когда прошло некоторое время и версии ant, есть способ сделать это с помощью основных функций ant, и я подумал, что должен поделиться им.
Выполняется с помощью рекурсивного макродефа, который вызывает вложенные задачи (даже другие макросы могут быть вызваны). Единственное соглашение - использовать фиксированное имя переменной (элемент здесь).
<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>
Основные функции, необходимые для:
Мне не удалось создать разделитель variabel, но это не может быть серьезным недостатком.
Ответ 7
Вы можете использовать задачу ant -contrib "для" итерации в списке файлов, разделенных любым делителем, по умолчанию - ",".
Ниже приведен пример файла, который показывает это:
<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>
Ответ 8
Сделайте то, что предложил blak3r, и определите целевые классы объектов таким образом
<taskdef resource="net/sf/antcontrib/antlib.xml">
<classpath>
<fileset dir="lib">
<include name="**/*.jar"/>
</fileset>
</classpath>
</taskdef>
где lib - это место, где вы храните свою банку