web-dev-qa-db-fra.com

Ant: Comment exécuter une commande pour chaque fichier du répertoire?

Je veux exécuter une commande à partir d'un fichier de compilation Ant, pour chaque fichier d'un répertoire.
Je recherche une solution indépendante de la plate-forme.

Comment puis-je faire cela?

Bien sûr, je pourrais écrire un script dans un langage de script, mais cela ajouterait d'autres dépendances au projet.

94

Réponse courte

Utilisez <foreach> Avec un <FileSet> Imbriqué

Foreach oblige ant-contrib .

Exemple mis à jour pour ant-contrib récent:

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

Ceci va appeler la "barre" cible avec le $ {theFile} résultant dans le fichier actuel.

59
blak3r

Utilisez la tâche <apply> .

Il exécute une commande une fois pour chaque fichier. Spécifiez les fichiers à l'aide de groupes de fichiers ou de toute autre ressource. <apply> est intégré; aucune dépendance supplémentaire nécessaire; aucune implémentation de tâche personnalisée nécessaire.

Il est également possible d'exécuter la commande une seule fois, en ajoutant tous les fichiers comme arguments en une fois. Utilisez l'attribut parallèle pour changer le comportement.

Désolé d'être en retard une année.

86
Alex

Une approche sans ant-contrib est suggérée par Tassilo Horn (le la cible d'origine est ici )

En gros, comme il n’ya pas d’extension de <Java> (encore?) De la même manière que <s'applique> s'étend <exec>, il suggère d'utiliser <apply> (qui peut bien entendu aussi exécuter un Java programme dans une commande ligne)

Voici quelques exemples:

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

Voici comment faire en utilisant javascript et la tâche ant scriptdef, vous n'avez pas besoin de ant-contrib pour que ce code fonctionne, car scriptdef est une tâche ant principale.

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

ant-contrib est diabolique; écrire une tâche de fourmi personnalisée.

ant-contrib est diabolique, car il tente de convertir un style déclaratif en un style impératif. Mais XML fait un langage de programmation merde.

En revanche, une tâche ant personnalisée vous permet d’écrire dans un langage réel (Java), avec un véritable IDE, dans lequel vous pouvez écrire des tests unitaires pour vous assurer que vous avez le comportement souhaité, puis faire une nouvelle déclaration dans votre script de construction à propos de le comportement que vous voulez.

Ce discours n’a d’importance que si vous vous souciez de l’écriture de scripts Ant maintenables. Si vous ne vous souciez pas de la maintenabilité, faites tout ce que vous voulez. :)

Jtf

15
Jeffrey Fredrick

Je sais que cet article est vraiment vieux, mais maintenant que certaines versions de fourmis ont passé, il existe un moyen de le faire avec des fonctionnalités de base pour fourmis et j’ai pensé que je devrais le partager.

Cela se fait via un macrodef récursif qui appelle des tâches imbriquées (même d'autres macros peuvent être appelées). La seule convention consiste à utiliser un nom de variable fixe (élément ici).

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

Les principales caractéristiques nécessaires où:

Je n'ai pas réussi à faire le délimiteur variabel, mais cela peut ne pas être un inconvénient majeur.

5
dag

Faites ce que blak3r a suggéré et définissez votre classpath comme

<taskdef resource="net/sf/antcontrib/antlib.xml">
    <classpath>
        <fileset dir="lib">
          <include name="**/*.jar"/>
        </fileset>
    </classpath>        
</taskdef>

où lib est l'endroit où vous stockez votre pot

0
bungee

Vous pouvez utiliser la tâche ant-contrib "for" pour parcourir la liste des fichiers séparés par un délimiteur, délimiteur par défaut: ",".

Voici le fichier exemple qui montre ceci:

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