developer tip

Ant : 디렉토리의 각 파일에 대해 명령을 실행하는 방법은 무엇입니까?

optionbox 2020. 8. 28. 07:22
반응형

Ant : 디렉토리의 각 파일에 대해 명령을 실행하는 방법은 무엇입니까?


디렉토리의 각 파일에 대해 Ant 빌드 파일에서 명령을 실행하고 싶습니다.
플랫폼 독립적 인 솔루션을 찾고 있습니다.

어떻게해야합니까?

물론 일부 스크립팅 언어로 스크립트를 작성할 수 있지만 이렇게하면 프로젝트에 더 많은 종속성이 추가됩니다.


짧은 답변

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

이렇게하면 $ {theFile}로 대상 "bar"가 호출되어 현재 파일이 생성됩니다.


<apply> 작업을 사용합니다 .

각 파일에 대해 한 번씩 명령을 실행합니다. 파일 세트 또는 기타 리소스를 사용하여 파일을 지정합니다. <적용>이 내장되어 있습니다. 추가 종속성이 필요하지 않습니다. 사용자 지정 작업 구현이 필요하지 않습니다.

명령을 한 번만 실행하여 한 번에 모든 파일을 인수로 추가 할 수도 있습니다. 동작을 전환하려면 parallel 속성을 사용하십시오.

1 년 늦어서 죄송합니다.


ant-contrib 없는 접근 방식 Tassilo Horn 이 제안합니다 ( 원래 목표는 여기에 있음 ).

Basicly의 확장자가 없기 때문에 <자바> (아직?) 같은 방법으로하는 것이 <적용> 확장 <임원> , 그 사용에 제안 <적용> (또한 명령 줄에서 자바 programm에 실행 과정의 어느 캔)

다음은 몇 가지 예입니다.

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

javascript와 ant scriptdef 작업을 사용하여이 작업을 수행하는 방법은 다음과 같습니다. scriptdef가 핵심 ant 작업이므로이 코드가 작동하기 위해 ant-contrib이 필요하지 않습니다.

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

ant-contrib is evil; write a custom ant task.

ant-contrib is evil because it tries to convert ant from a declarative style to an imperative style. But xml makes a crap programming language.

By contrast a custom ant task allows you to write in a real language (Java), with a real IDE, where you can write unit tests to make sure you have the behavior you want, and then make a clean declaration in your build script about the behavior you want.

This rant only matters if you care about writing maintainable ant scripts. If you don't care about maintainability by all means do whatever works. :)

Jtf


I know this post is realy old but now that some time and ant versions passed there is a way to do this with basic ant features and i thought i should share it.

It's done via a recursive macrodef that calls nested tasks (even other macros may be called). The only convention is to use a fixed variable name (element here).

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

The key features needed where:

I didnt manage to make the delimiter variabel, but this may not be a major downside.


You can use the ant-contrib task "for" to iterate on the list of files separate by any delimeter, default delimeter is ",".

Following is the sample file which shows this:

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

Do what blak3r suggested and define your targets classpath like so

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

where lib is where you store your jar's

참고URL : https://stackoverflow.com/questions/1467991/ant-how-to-execute-a-command-for-each-file-in-directory

반응형