Ant: Dizindeki her dosya için bir komut nasıl çalıştırılır?


97

Bir dizindeki her dosya için Ant yapı dosyasından bir komut yürütmek istiyorum.
Platformdan bağımsız bir çözüm arıyorum.

Bunu nasıl yaparım?

Elbette, bazı komut dosyası dillerinde bir komut dosyası yazabilirim, ancak bu projeye daha fazla bağımlılık katacaktır.

Yanıtlar:


61

Kısa cevap

Kullanım <foreach>yuvalanmış olan<FileSet>

Foreach, karınca katkısı gerektirir .

En son karınca katkısı için güncellenmiş Örnek:

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

Bu, $ {theFile} ile sonuçlanan hedef "çubuğunu" geçersiz kılar ve mevcut dosya ile sonuçlanır.


Yani, bir şey eklemem gerekiyor? Yoksa harici karınca kütüphanesine ihtiyacım var mı? "Sorun: görev oluşturulamadı veya foreach yazılamadı" mesajı alıyorum . Doğru anladıysam , bu, foreach'in bilinmeyen bir anahtar kelime olduğu anlamına gelir .
ivan_ivanovich_ivanoff

4
Ohhh topal ... bu bir Ant-Contrib Görevi. Yani, bir şeyler yüklemelisin. Buraya bakın: ant-contrib.sourceforge.net
blak3r

3
Bu örnek, karınca katkısına dahil edilmeden önceki bir foreach'tan. Ant.1045680.n5.nabble.com/Using-foreach-td1354624.html adresinde iyi bir örnek var, bu örneği çalışacak şekilde güncelleyeceğim.
Sean

2
Yuvalanmış dosya kümesi öğesi kullanımdan kaldırıldı, bunun yerine iç içe bir yol kullanın
dostum

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

88

<apply> görevini kullanın .

Her dosya için bir komut yürütür. Dosyaları dosya kümeleri veya başka herhangi bir kaynak aracılığıyla belirtin. <apply> yerleşiktir; ek bağımlılık gerekmez; özel görev uygulaması gerekmez.

Komutu yalnızca bir kez çalıştırarak tüm dosyaları tek seferde bağımsız değişken olarak eklemek de mümkündür. Davranışı değiştirmek için paralel niteliği kullanın.

Bir yıl geciktiğim için üzgünüm.


4
Bunu 2011'de faydalı buldum, bunun için yine de teşekkürler!
Michael Della Bitta

7
<apply> ile ilgili sorun, yalnızca harici sistem komutlarını yürütmesidir. Doğrudan hiçbir şey yapmaz. Asıl sorunun bununla ilgili olup olmadığı net değil. Temel olarak iki farklı durum için <apply> veya <foreach> kullanmanız gerekir ... ki bu tamamen aptalca.
Archie

27

Tassilo Horn tarafından karınca katkısı olmayan bir yaklaşım önerilmektedir ( asıl hedef buradadır )

Temel olarak, hiçbir uzantısı olmadığı için <java> (henüz?) Aynı şekilde o <uygulamak> uzanır <exec> , o kullanımına da anlaşılacağı <uygulamak> (aynı zamanda bir komut satırında bir java programm çalıştırmak Tabii hangi teneke)

İşte bazı örnekler:

  <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
Bu, orijinal soruda açıkça gerekli olmasına rağmen, platformdan çok bağımsız değil ...
Chucky,

18

İşte javascript ve ant scriptdef görevini kullanarak bunu yapmanın bir yolu, scriptdef temel bir karınca görevi olduğundan bu kodun çalışması için ant-katkısına ihtiyacınız yoktur.

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

projectYukarıdaki örnekte bir değişkene atıfta bulunulmuştur, ancak önceden bir tanım yapılmamıştır. Bunun temsil edilmesi veya açıklığa kavuşturulması iyi olur. DÜZENLEME: n / m, projectmevcut projeye erişmek için önceden tanımlanmış bir değişken olduğu bulundu . Bundan şüphelenmiştim ama emin değildim.
Jon L.

2
Bunu JDK8 veya sonraki sürümlerde deneyenler için, "importClass" ın JRE tarafından yüklenen ScriptEngine gergedan (çoğu JDK 6 ve 7 için geçerliydi) gergedan ise, Nashorn'da (8'den itibaren) çalıştığını unutmayın. geriye dönük uyumlu "File = java.io.File" veya daha yenisi ancak geriye dönük uyumlu Java.type değil. Bugün yaşadığım gibi Ant, scriptdef'i çalıştırırken sorun yaşarken sessizce başarısız görünüyor.
Matteo Steccolini

16

karınca katkısı kötüdür; özel bir karınca görevi yazın.

karınca katkısı kötüdür çünkü karıncayı bildirimsel bir tarzdan emredici bir tarza dönüştürmeye çalışır. Ama xml saçma bir programlama dili yapar.

Buna karşılık, özel bir karınca görevi, gerçek bir IDE ile gerçek bir dilde (Java) yazmanıza olanak tanır; burada istediğiniz davranışa sahip olduğunuzdan emin olmak için birim testleri yazabilir ve ardından oluşturma komut dosyanızda bunun hakkında temiz bir bildirimde bulunabilirsiniz. istediğiniz davranış.

Bu rant sadece, sürdürülebilir karınca senaryoları yazmayı önemsiyorsanız önemlidir. Sürdürülebilirliği kesinlikle önemsemiyorsanız, işe yarayan her şeyi yapın. :)

Jtf


2
Haklısın, sadece Java'da özel bir karınca görevi
yazmalıyım

4
karınca katkısı gerçekten kötüdür. Şu anda, if / then / else ve antcall'ları yoğun bir şekilde kullanan ve gerçekten korkunç olan büyük bir karınca inşa projesinin ortasındayım. Her şey dönüştürülmüş bir toplu iş / kabuk betiğine benziyor ve ant'ın yaptığı tüm bağımlılık işleri, karınca katkısının yoğun kullanımıyla tamamen kapatılıyor. Kurulumunuzu temiz tutmak istiyorsanız, kendi görevinizi oluşturun. : - /
cringe

2
@cringe, katılmıyorum. Her şey gibi, karınca katkısını kullanmanın ne zaman en iyi yararınıza olduğunu bilmelisiniz. If ve var gibi şeylerden uzak durun ve tekerleği yeniden icat etmekten kaçınmak için karınca katkısı kullanın.
Neil

1
Ve başlangıç ​​için çok zorunlu ve bildirimsel olmayan bir betik dili olmalıydı. Öyleyse bu Ve kim kötü IMO
mvmn

Belki karınca katkısı bir önsel kötülüktür, ancak black3r'ün bunu kullanması mantıklı ve tabiri caizse mantıklı görünmektedir.
ssimm

7

Bu yazının gerçekten eski olduğunu biliyorum ama şimdi biraz zaman ve karınca sürümleri geçtiğine göre, bunu temel karınca özellikleriyle yapmanın bir yolu var ve paylaşmam gerektiğini düşündüm.

İç içe geçmiş görevleri çağıran özyinelemeli bir makro aracılığıyla yapılır (hatta diğer makrolar çağrılabilir). Tek kural, sabit bir değişken adı kullanmaktır (buradaki eleman).

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

Şu durumlarda ihtiyaç duyulan temel özellikler:

Sınırlayıcı değişkenini yapmayı başaramadım, ancak bu büyük bir dezavantaj olmayabilir.


Ne yazık ki bu bellek yetersiz kalıyor ve oldukça hızlı bir şekilde patlıyor.
David St Denis

Evet, işlediğiniz dosya sayısına bağlı olarak yığınızı patlatabilir. Yaklaşık 66 Dosya ile oldukça başarılı oldum (artırılmış Bellek seçenekleri olmadan). Bununla birlikte, daha fazla işlevsellik sunan ant-assistant'a erişiminiz yoksa (örneğin, paralel çalışma), yalnızca bir seçeneğe neden olur.
dag

Bu çok yardımcı oldu.
DiamondDrake

0

Herhangi bir sınırlayıcıyla ayrılmış dosyalar listesinde yineleme yapmak için "için" ant-katkıda görevini kullanabilirsiniz, varsayılan sınırlayıcı "," dir.

Bunu gösteren örnek dosya aşağıdadır:

<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'nin önerdiği şeyi yapın ve hedeflerinizi sınıf yolunu bu şekilde tanımlayın

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

lib, kavanozlarınızı nerede sakladığınız

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.