2011-10-07 75 views
1

我對螞蟻相當陌生,我見過叔叔鮑勃的「提取,直到你放棄」插曲。螞蟻有條件的目標和'遞歸'

因此,我嘗試定義儘可能小的螞蟻目標,以便您可以精確地看到目標的本質,而不是更多。有關更多詳細信息,您必須參考子目標。

無論好壞風格是不同的辯論(或可能是一場火焰戰爭)。

因此,我創建一個構建腳本,在僞代碼,應該是這樣的:

build = 
    compile 
    instrument if coverage 

coverage任務分割成子目標,太:

coverage: 
    create-coverage-dirs 
    call-cobertura 

編輯 - 我想表示coverage子目標不應運行。

但是...我很難在ant-ese中表達這個'乾淨'。

假設我可以使用depends屬性表示...目標間的依賴關係,我得到了這樣的事情:

<target name="build" depends="compile, coverage"/> 

<target name="compile"> .... </target> 

<target name="coverage" depends=" 
     create-coverage-dirs, 
     taskdef-cobertura" 
if="build.with.coverage"> 

    <cobertura-instrument ...> ... </cobertura-instrument> 

</target> 

<target name="create-coverage-dirs"> 
    ...  
</target> 

<target name="taskdef-cobertura"> 
    ... 
</target> 

Whow這看起來不錯!

只有它似乎是,執行時的coverage任務duefully省略,但它的子任務仍執行build.with.coveragefalse

>ant -v compile 
Build sequence for target(s) `build' is 
    [compile, create-coverage-dirs, taskdef- cobertura, coverage, build] 
Complete build sequence is 
    [compile, create-coverage-dirs, taskdef-cobertura, coverage, build, ] 

我可以把每一個覆蓋子任務的if屬性,但似乎並不乾淨的給我。

所以這裏的問題:

  1. 是我的螞蟻ESE一個可怕的方言?我是不是在做'螞蟻'?
  2. if應該以這種方式使用,還是有if-and-recurse種屬性?
+0

(我使用ant 1.8.2) – xtofl

回答

2

我不會在這種情況下,在所有使用屬性,但僅僅依靠depends(這似乎更自然給我這個任務):

後我
<target name="build" depends="compile, coverage"/> 

<target name="compile"> ... 

<target name="coverage" 
     depends="compile, instrument, 
       create-coverage-dirs, taskdef-cobertura"> ... 
+1

這也是我的感受。只有'coverage'還依賴於'compile',否? – xtofl

+0

好點,我會更新我的回答 – michael667

1

if attribute測試屬性是否存在,而不是如果它是真或假。如果您不想運行覆蓋率目標,則不要定義屬性build.with.coverage

螞蟻的1.8.0您可以使用屬性擴展resplver財產作爲布爾:

<target name="coverage" depends=" 
      create-coverage-dirs, 
      taskdef-cobertura" 
     if="${build.with.coverage}"> 
+0

感謝您的信息;即使'build.with.coverage'沒有定義,唯一被排除的目標是'主'覆蓋'目標。我想表達的是,它的子目標也不應該運行。 – xtofl

+0

您可以從相關列表中刪除子目標,並通過覆蓋率任務中的[antcall](http://ant.apache.org/manual/Tasks/antcall.html)調用它們。 – krock

+1

Antcall與depends相同:不會覆蓋現有引用,即使將inheritRefs設置爲true也是如此。由於被調用的構建文件與調用構建文件是相同的構建文件,這意味着它不會通過id屬性覆蓋任何參考集。子項目可以繼承的唯一引用是由嵌套的元素或直接由任務定義的引用定義的引用(不使用id屬性)。請參閱http://ant.apache.org/manual/Tasks/antcall.html – michael667

3

重複:螞蟻是不是一種編程語言。實際上,在黑板上寫下100次。

螞蟻不是一種編程語言,所以不要這樣想。它是一個構建依賴矩陣。

對於程序員來說,圍繞這個想法很困難。他們想要告訴Ant每一步以及何時應該完成。他們想要循環,如果語句。他們會求助於使用build.sh腳本來調用Ant中的各種目標,因爲您無法輕鬆編程Ant。

在Ant中,您指定了離散任務,以及哪些任務依賴於其他任務,並讓Ant處理執行任務的位置和時間。

我在說的是,你通常不會將任務分成子任務,然後嘗試對它們調用<ant><subant>

有離散任務,但讓每個任務都知道他們依賴的其他任務。還要記住在Ant中沒有真正的順序。當你列出depends=任務,也不能保證其順序,他們將在執行。


標準的Ant風格(這意味着我的方式做到這一點(又名正確的方式),而不是我的方式同事這樣做(aka The Wrong Way)),通常規定在屬性文件的頂部定義任務,而不是在任何目標中定義任務。下面是我如何構建一個基本的輪廓我build.xml

<project name=...> 

     <!-- Build Properties File --> 
     <property name="build.properties.file" 
      value="${basedir}/build.properties"/> 
     <property file="${build.properties.file"/> 

     <!-- Base Java Properties --> 
     <property name="..." value="..."/> 

     <taskdef/> 
     <taskdef/> 

     <!-- Javac properties --> 
     <property name="javac..." value="..."/> 

     <task/> 
     <task/> 
</project> 

這就產生了一個有趣的層次。如果您有一個名爲build.properties的文件,它將覆蓋build.xml腳本中定義的屬性。例如,您有:

<property name="copy.verbose" value="false"/> 

<copy todir="${target}" 
    verbose="${copy.verbose}"> 
    <fileset dir="${source}"/> 
</copy> 

您可以通過僅僅在build.properties文件中設置copy.verbose = true開啓冗長的副本。

$ ant -Dbuild.properties.file="my.build.properties" 

(是的,是的,我知道有一個爲ant一個-property命令行參數)

我通常:而且,你可以僅僅通過指定在命令行上指定一個不同的構建屬性文件將build.xml中的各個值設置爲假定的默認值,但任何人都可以通過創建build.properties文件來更改它們。而且,由於所有的基本屬性都在開頭,所以很容易找到。

任務也在這個非目標空間中定義。這樣,我可以很容易地找到定義,因爲它們在每個build.xml的相同位置,並且我知道我可以使用任務而不用擔心任務定義目標是否已經命中。現在

,你的問題:

定義您的任務(並沒有定義任務焦油,否則你會自己開車瘋了)。然後,定義每個這些任務的依賴關係。開發人員可以選擇他們想要擊中的目標。例如:

<project> 
    <description> 
     yadda, yadda, yadda 
    </description> 

    <taskdef name="cobertura"/> 

    <target name="compile" 
     description="Compile the code"/> 

    <!-- Do you have to compile code before you run Cobertura?--> 
    <target name="coverage" 
     description="Calculate test coverage" 
     depends="compile"> 

     <mkdir dir="${coverage.dir}"/> 
     <cobertura-instrument/> 
    </target> 
<project> 

如果你想編譯代碼,但不運行任何測試,你與compile目標執行ant。如果您想運行測試,則執行ant,並使用coverage目標。沒有必要使用depends=參數。

另請注意description=參數和<description>任務。這是因爲如果你這樣做:

$ ant -p 

螞蟻會顯示哪些內容在<description>任務,具有description參數所有目標,而且描述。這樣,開發人員就知道哪些目標用於哪些任務。

順便說一句,我還建議做正確的方式(也就是我這樣做),並在Maven lifecycle goals後命名您的目標。爲什麼?因爲這是標準化目標名稱的好方法。開發人員知道clean將刪除所有構建的工件,並且compile將運行<javac>任務,並且該test將運行junit測試。因此,您應該使用Cobertura plugincobertura中的目標。


編輯

我的問題是:我把「覆蓋」作爲與「優化」和「調試」,即構建味道。這就是我的困難所在:對於Java,覆蓋率在編譯步驟中會產生額外的中間目標。

我看Corburta頁面,並且有在<javac>任務沒有真正的改變(這是的一部分編譯目標。

相反,你對已建成.class文件運行Corburtura ,然後運行<junit>任務。最大的變化是在你的<junit>現在的任務,其中必須包括您Corburtura罐子引用,以及對你的儀表類。

我想像你可以有一個corburtura目標或要什麼都叫它。該目標運行儀器化的JUnit測試。這是您希望開發人員打的目標,並且應該包含運行儀器測試的說明。

當然,如果不先測試它們,您將無法運行測試的Junit測試。因此,您的corburtura目標將取決於另一個instrument.tests目標。這個目標是內部的。運行你的build.xml的人通常不會在沒有運行這些測試的情況下說「儀器測試」。因此,這個目標沒有描述。

當然,instrument.tests目標取決於其.class文件到儀器,所以它必須就compile目標的依賴在運行<javac>任務:

<target name="instrument.classes" 
    depends="compile"> 
    <coburtura-instrument/> 
</target> 

<target name="corburtura" 
    depends="instrument.classes" 
    description="Runs the JUnit tests instrumented with Corburtura"> 
    <junit/> 
</target> 

唯一的問題是,你指定你的<junit>目標兩次:一次當儀表,一次正常測試。這可能是一個小問題。如果您更新了JUnit測試的運行方式,則必須在兩個地方完成。

如果你想解決這個問題,你可以使用<macrodef>來定義運行宏的JUnit測試。我使用了Corbertura頁面上的內容來幫助提綱。完全沒有經過測試,可能是語法錯誤:

<target name="instrument.tests" 
    depends="compile"> 
    <corburtura-instrument/> 
</target> 

<target name="corburtura" 
    depends="instrument.tests" 
    description="Instrument and run the JUnit tests"> 

    <run.junit.test fork.flag="true"> 
     <systemproperty.addition> 
      <sysproperty key="net.sourceforge.corbertura.datafile" 
       file="${basedir}/cobertura.ser" /> 
     </systemproperty.addition> 
     <pre.classpath> 
      <classpath location="${instrumented.dir}" /> 
     </pre.classpath> 
     <post.classpath> 
      <classpath refid="cobertura_classpath" /> 
     </post.classpath> 
    </run.junit.test> 
</target> 

<target name="test" 
    description="Runs the Junit tests without any instrumentation"> 
    <run.junit.test/> 
</target> 

<macrodef name="run.junit.test"> 
    <attribute name="fork.flag" default="false"/> 
    <element name="sysproperty.addition" optional="yes"/> 
    <element name="pre.classpath" optional="yes"/> 
    <element name="post.classpath" optional="yes"/> 
    <sequential> 
     <junit fork="@{fork.flag}" dir="${basedir}" failureProperty="test.failed"> 

      <systemproperty.addtion/> 
      <pre.classpath/> 
      <classpath location="${classes.dir}" /> 
      <post.classpath/> 

      <formatter type="xml" /> 
      <test name="${testcase}" todir="${reports.xml.dir}" if="testcase" /> 
      <batchtest todir="${reports.xml.dir}" unless="testcase"> 
       <fileset dir="${src.dir}"> 
        <include name="**/*Test.java" /> 
       </fileset> 
      </batchtest> 
     </junit> 
    </sequential> 
</macrodef> 
+0

哇,謝謝你這個詳細的答案。我完全同意'depends ='i.s.o. 'antcall';我的問題是:我認爲'coverage'與'優化'和'調試'有關,即構建風格。這就是我的困難所在:對於Java,覆蓋率在編譯步驟中會導致**額外的中間目標**。 – xtofl

+0

就像例如我在發佈版本時對非優化代碼不感興趣,我不需要任何javac輸出。 – xtofl

+0

順便說一句,我稱之爲構建樣式'coverage'iso'cobertura',因爲我想指定**它做了什麼** iso **是誰做的**。這對我來說是正確的方式,因爲我也在用相同的語義進行C++構建。 – xtofl