file-io - ejemplos - programacion batch avanzada



Ant: ¿Cómo ejecutar un comando para cada archivo en el directorio? (6)

Respuesta corta

Utilice <foreach> con un <FileSet> anidado

Foreach requiere ant-contrib .

Ejemplo actualizado para ant-contrib reciente:

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

Esto anulará la "barra" de destino con el $ {theFile} resultante en el archivo actual.

https://code.i-harness.com

Quiero ejecutar un comando desde un archivo de compilación Ant, para cada archivo en un directorio.
Estoy buscando una solución independiente de la plataforma.

¿Cómo hago esto?

Claro, podría escribir un script en algún lenguaje de scripting, pero esto agregaría más dependencias al proyecto.


Aquí hay una manera de hacer esto usando javascript y la tarea ant scriptdef, no necesita ant-contrib para que este código funcione, ya que scriptdef es una tarea central.

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

Puede usar la tarea ant-contrib "para" para iterar en la lista de archivos separados por cualquier delímetro, el delímetro predeterminado es ",".

A continuación se muestra el archivo de muestra que muestra esto:

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

Sé que esta publicación es realmente antigua, pero ahora que pasaron algunas versiones de tiempo y hormiga, hay una manera de hacer esto con las características básicas de la hormiga y pensé que debería compartirlo.

Se realiza mediante un macrodef recursivo que llama a tareas anidadas (incluso se pueden llamar otras macros). La única convención es usar un nombre de variable fijo (elemento aquí).

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

Las características clave necesarias donde:

No logré hacer el delimitador variabel, pero esto puede no ser un inconveniente importante.


Use la tarea <aplicar> .

Ejecuta un comando una vez para cada archivo. Especifique los archivos por medio de conjuntos de archivos o cualquier otro recurso. <aplicar> está incorporado; no se necesita una dependencia adicional; no es necesaria la implementación de tareas personalizadas.

También es posible ejecutar el comando solo una vez, agregando todos los archivos como argumentos de una vez. Use el atributo paralelo para cambiar el comportamiento.

Perdón por llegar tarde un año.


ant-contrib es malo; escribe una tarea de hormiga personalizada.

ant-contrib es malo porque trata de convertir a la hormiga de un estilo declarativo a un estilo imperativo. Pero xml hace un lenguaje de programación de mierda.

Por el contrario, una tarea personalizada le permite escribir en un lenguaje real (Java), con un IDE real, donde puede escribir pruebas de unidad para asegurarse de que tiene el comportamiento que desea, y luego hacer una declaración limpia en su script de construcción sobre el comportamiento que quieres.

Esta diatriba solo importa si te preocupa escribir guiones de hormiga mantenibles. Si no te importa la facilidad de mantenimiento, haz lo que funcione. :)

Jtf





build-automation