Ant: จะรันคำสั่งสำหรับแต่ละไฟล์ในไดเร็กทอรีได้อย่างไร?


97

ฉันต้องการรันคำสั่งจาก Ant buildfile สำหรับแต่ละไฟล์ในไดเร็กทอรี
ฉันกำลังมองหาโซลูชันที่ไม่ขึ้นกับแพลตฟอร์ม

ฉันต้องทำอย่างไร

แน่นอนว่าฉันสามารถเขียนสคริปต์ในภาษาสคริปต์บางภาษาได้ แต่สิ่งนี้จะเพิ่มการอ้างอิงเพิ่มเติมให้กับโครงการ

คำตอบ:


61

คำตอบสั้น ๆ

ใช้<foreach>กับ<FileSet>

foreach ต้องมด 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>

การดำเนินการนี้จะเรียก "bar" เป้าหมายด้วย $ {theFile} ซึ่งส่งผลให้เกิดไฟล์ปัจจุบัน


ดังนั้นฉันต้องรวมอะไรบางอย่าง? หรือฉันต้องการ ant lib ภายนอกบ้าง? ฉันได้รับ"ปัญหา: ล้มเหลวในการสร้างงานหรือประเภท foreach" ถ้าฉันเข้าใจถูกต้องหมายความว่าforeachเป็นคำหลักที่ไม่รู้จัก
ivan_ivanovich_ivanoff

4
โอ้ยยย ... มันเป็นงาน Ant-Contrib ดังนั้นคุณต้องติดตั้งบางอย่าง ดูที่นี่: ant-contrib.sourceforge.net
blak3r

3
ตัวอย่างนั้นมาจาก foreach ก่อนที่จะรวมอยู่ใน ant-Contrib มีตัวอย่างที่ดีที่ant.1045680.n5.nabble.com/Using-foreach-td1354624.htmlฉันจะอัปเดตตัวอย่างให้ใช้งานได้
Sean

2
องค์ประกอบชุดไฟล์ที่ซ้อนกันถูกยกเลิกใช้เส้นทางที่ซ้อนกันแทน
เพื่อน

@dude ใช้ <foreach> <path> <fileset> <include name = "*. jar" /> </fileset> </path> </foreach>
Sharat

88

ใช้<ใช้> งาน

เรียกใช้คำสั่งหนึ่งครั้งสำหรับแต่ละไฟล์ ระบุไฟล์โดยใช้ชุดไฟล์หรือทรัพยากรอื่น ๆ <apply> อยู่ในตัว; ไม่จำเป็นต้องพึ่งพาเพิ่มเติม ไม่จำเป็นต้องใช้งานแบบกำหนดเอง

นอกจากนี้ยังสามารถเรียกใช้คำสั่งเพียงครั้งเดียวโดยต่อท้ายไฟล์ทั้งหมดเป็นอาร์กิวเมนต์ในครั้งเดียว ใช้แอตทริบิวต์คู่ขนานเพื่อเปลี่ยนลักษณะการทำงาน

ขออภัยที่มาช้าไปปี


4
ฉันเพิ่งพบว่าสิ่งนี้มีประโยชน์ในปี 2011 ดังนั้นขอบคุณสำหรับสิ่งนั้น!
Michael Della Bitta

7
ปัญหาของ <apply> คือมันดำเนินการเฉพาะคำสั่งระบบภายนอกเท่านั้น มันจะไม่ทำสิ่งที่เป็นอันตรายโดยตรง ไม่ชัดเจนว่านั่นคือสิ่งที่คำถามเดิมเกี่ยวกับหรือไม่ โดยทั่วไปคุณต้องใช้ <apply> หรือ <foreach> สำหรับสองสถานการณ์ที่แตกต่างกัน ... ซึ่งเป็นเรื่องโง่โดยสิ้นเชิง
Archie

27

Tassilo Hornแนะนำแนวทางที่ไม่มีAnt- Contrib ( เป้าหมายเดิมอยู่ที่นี่ )

โดยพื้นฐานแล้วเนื่องจากไม่มีส่วนขยายของ<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> 

2
นี่ไม่ใช่แพลตฟอร์มที่เป็นอิสระมากนักแม้ว่าจะจำเป็นอย่างชัดเจนในคำถามเดิมก็ตาม ...
Chucky

18

นี่คือวิธีดำเนินการโดยใช้ javascript และงาน ant scriptdef คุณไม่จำเป็นต้องมี ant-Contrib เพื่อให้โค้ดนี้ทำงานเนื่องจาก scriptdef เป็นงานหลักของมด

<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การอ้างอิงตัวแปรในตัวอย่างด้านบน แต่ไม่มีคำจำกัดความก่อนหน้านี้ จะเป็นการดีที่จะให้สิ่งนั้นเป็นตัวแทนหรือชี้แจง แก้ไข: n / m พบว่าprojectเป็นตัวแปรที่กำหนดไว้ล่วงหน้าเพื่อเข้าถึงโครงการปัจจุบัน ฉันสงสัยอย่างนั้น แต่ก็ไม่แน่ใจ
Jon L.

2
สำหรับผู้ที่ลองใช้ใน JDK8 หรือใหม่กว่าโปรดทราบว่า "importClass" ทำงานได้หาก ScriptEngine ที่โหลดโดย JRE เป็นแรด (ซึ่งเป็นจริงสำหรับ JDK 6 และ 7 ส่วนใหญ่) ในขณะที่ใน Nashorn (ตั้งแต่ 8 เป็นต้นไป) คุณสามารถใช้ "File = java.io.File" ที่เข้ากันได้แบบย้อนหลังหรือใหม่กว่า แต่ไม่รองรับ Java.type แบบย้อนกลับ Ant ดูเหมือนจะล้มเหลวอย่างเงียบ ๆ เมื่อมีปัญหาในการเรียกใช้ scriptdef อย่างที่ฉันได้สัมผัสในวันนี้
Matteo Steccolini

16

มด - มีส่วนเป็นสิ่งชั่วร้าย เขียนงานมดที่กำหนดเอง

ant-Contrib นั้นชั่วร้ายเพราะมันพยายามที่จะแปลงมดจากรูปแบบที่เปิดเผยเป็นรูปแบบที่จำเป็น แต่ xml สร้างภาษาโปรแกรมไร้สาระ

ในทางตรงกันข้ามงาน ant แบบกำหนดเองช่วยให้คุณสามารถเขียนในภาษาจริง (Java) ด้วย IDE จริงซึ่งคุณสามารถเขียนการทดสอบหน่วยเพื่อให้แน่ใจว่าคุณมีพฤติกรรมที่คุณต้องการจากนั้นทำการประกาศแบบสะอาดในสคริปต์บิลด์ของคุณเกี่ยวกับ พฤติกรรมที่คุณต้องการ

การพูดจาโผงผางนี้มีความสำคัญต่อเมื่อคุณสนใจเกี่ยวกับการเขียนสคริปต์มดที่ดูแลรักษาได้ หากคุณไม่สนใจเกี่ยวกับการบำรุงรักษาไม่ว่าจะทำอะไรก็ตาม :)

Jtf


2
คุณพูดถูกฉันควรจะเขียนงานมดที่กำหนดเองใน Java;)
ivan_ivanovich_ivanoff

4
ant-Contrib นั้นชั่วร้ายจริงๆ ตอนนี้ฉันอยู่ระหว่างโครงการสร้างมดขนาดใหญ่ที่ใช้ if / then / else และ antcalls อย่างเข้มข้นและมันก็น่ากลัวจริงๆ สิ่งทั้งหมดดูเหมือนแบทช์ / เชลล์สคริปต์ที่แปลงแล้วและสิ่งที่ขึ้นต่อกันทั้งหมดที่มดทำจะถูกปิดอย่างสมบูรณ์โดยการใช้ ant-Contrib อย่างหนัก หากคุณต้องการให้การตั้งค่าของคุณสะอาดให้สร้างงานของคุณเอง : - /
ประจบประแจง

2
@cringe ฉันไม่เห็นด้วย เช่นเดียวกับสิ่งอื่นใดคุณต้องรู้ว่าเมื่อใดที่เป็นประโยชน์สูงสุดในการใช้ Ant-Contrib อยู่ห่างจากสิ่งต่างๆเช่น if และ var และใช้ ant-Contrib เพื่อหลีกเลี่ยงการสร้างวงล้อใหม่
นีล

1
และควรเป็นภาษาสคริปต์ดังนั้นจึงมีความจำเป็นและไม่ต้องเปิดเผยเพื่อเริ่มต้นด้วย และใครคือผู้ชั่วร้าย IMO
mvmn

บางที ant-Contrib อาจเป็นความชั่วร้ายระดับต้น แต่การใช้ black3r มันดูสมเหตุสมผลและเป็น ant-ish ดังนั้นที่จะพูด
ssimm

7

ฉันรู้ว่าโพสต์นี้เก่าจริง แต่ตอนนี้เวลาและเวอร์ชันมดผ่านไปแล้วมีวิธีทำเช่นนี้ด้วยคุณสมบัติพื้นฐานของมดและฉันคิดว่าฉันควรแบ่งปัน

ทำได้โดยใช้ macrodef แบบเรียกซ้ำซึ่งเรียกใช้งานที่ซ้อนกัน (แม้แต่มาโครอื่น ๆ อาจเรียกได้) หลักการเดียวคือการใช้ชื่อตัวแปรคงที่ (องค์ประกอบที่นี่)

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

คุณสมบัติหลักที่จำเป็นสำหรับ:

ฉันไม่สามารถสร้างตัวแปรตัวคั่นได้ แต่นี่อาจไม่ใช่ข้อเสียที่สำคัญ


น่าเสียดายที่หน่วยความจำนี้หมดและระเบิดค่อนข้างเร็ว
David St Denis

ใช่มันอาจระเบิดสแต็กของคุณขึ้นอยู่กับจำนวนไฟล์ที่คุณประมวลผล ฉันทำได้ค่อนข้างประสบความสำเร็จด้วยไฟล์ประมาณ 66 ไฟล์ (โดยไม่มีตัวเลือกหน่วยความจำเพิ่มขึ้น) อย่างไรก็ตามมันเป็นเพียงตัวเลือกเดียวในกรณีที่คุณไม่มีสิทธิ์เข้าถึง ant-Contrib ซึ่งมีฟังก์ชันเพิ่มเติม (เช่นการทำงานแบบขนาน)
dag

สิ่งนี้มีประโยชน์มาก
DiamondDrake

0

คุณสามารถใช้งาน ant-Contrib "for" เพื่อวนซ้ำในรายการไฟล์ที่แยกตามตัวคั่นใด ๆ ตัวคั่นเริ่มต้นคือ ","

ต่อไปนี้เป็นไฟล์ตัวอย่างที่แสดงสิ่งนี้:

<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

ทำตามที่ blak3r แนะนำและกำหนดคลาสพา ธ เป้าหมายของคุณเช่นนั้น

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

โดยที่ lib คือที่ที่คุณเก็บขวดโหลของคุณ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.