为什么Ant插件taskdefs的变化?

IAm*_*aja 4 java ant plugins findbugs cobertura

我真的很困惑为Ant插件定义taskdef 的正确(最现代,最佳实践等)方式.下面是我从一个内部Java应用程序中拼凑而来的代码片段build.xml.请注意,以下所有Ant目标都可以完美地完成100%(即使我将它们拼接在一起,并为了简洁起见而剥离了大部分内容):

<project name="MyApp" default="package" basedir="." xmlns:jacoco="antlib:org.jacoco.ant">
    <path id="cobertura.path">
        <!-- ... -->
    </path>

    <taskdef name="jacoco-coverage" classname="org.jacoco.ant.CoverageTask"/>
    <taskdef name="jacoco-report" classname="org.jacoco.ant.ReportTask"/>
    <taskdef classpathref="cobertura.path" resource="tasks.properties" />
    <taskdef name="findbugs" classname="edu.umd.cs.findbugs.anttask.FindBugsTask"/>

    <target name="run-coco" depends="doOtherStuff">
        <jacoco:coverage>
            <!-- ... -->
        </jacoco:covergae>

        <jacoco-report>
            <!-- ... -->
        </jacoco-report>        
    </target>

    <target name="findbugs">
        <antcall target="compile" />
        <findbugs home="${findbugs.home}" output="xml:withMessages" outputFile="findbugs.xml">
            <!-- ... -->
        </findbugs>
    </target>
</project>
Run Code Online (Sandbox Code Playgroud)
  1. 为什么我需要为JaCoCo定义XML命名空间,而不是为Findbugs定义?
  2. 什么是antlib?有时我会在XML命名空间定义中看到它,有时它不在那里.
  3. 虽然这两个jacoco-coveragejavacoco-report任务定义使用连字符(" - ")在其名称,相应的任务被称为jacoco:coveragejacoco-report分别...为什么冒号(":")的覆盖范围,以及如何做,即使是工作(是的话,相信我! )?

提前致谢!

Dav*_* W. 10

让我们一步一步地回答这个问题:

第一步:定义你的任务

您可以通过以下两种方式之一定义任务:

  1. 您可以指向一个类文件,然后给出classfile定义名称的任务.
  2. 您可以指向jar中具有任务名称和这些任务名称使用的类文件的资源文件.

在你的JaCoCo案例中,你做了第一个:

<taskdef name="jacoco-coverage" 
    classname="org.jacoco.ant.CoverageTask"/>
<taskdef name="jacoco-report"
    classname="org.jacoco.ant.ReportTask"/>
Run Code Online (Sandbox Code Playgroud)

但是,您也可以采用第二种方式:

<taskdef resource="org/jacoco/ant/antlib.xml"/>
Run Code Online (Sandbox Code Playgroud)

如果打开jacoco jar文件并在该目录中向下钻取,您将看到一个名为的文件antlib.xml.如果你查看该文件,你会看到:

<antlib>
    <taskdef name="coverage"  classname="org.jacoco.ant.CoverageTask"/>
    <taskdef name="agent"     classname="org.jacoco.ant.AgentTask"/>
    <taskdef name="report"    classname="org.jacoco.ant.ReportTask"/>
    <taskdef name="merge"     classname="org.jacoco.ant.MergeTask"/>
    <taskdef name="dump"      classname="org.jacoco.ant.DumpTask"/>
</antlib>
Run Code Online (Sandbox Code Playgroud)

因此,如果jar中有资源文件,您可以使用单个文件定义所有任务<taskdef>.请注意,您调用的jacoco-coverage内容只是coverage在这里调用,您调用的jacoco-report内容report在此处调用.

你用作<jacoco-coverage/>Ant任务的地方,我会用<coverage/>.

第二步:JAR文件在哪里?

在上面,我将任务定义为:

<taskdef resource="org/jacoco/ant/antlib.xml">
Run Code Online (Sandbox Code Playgroud)

在某个地方,Ant必须在其类路径中找到该路径,但在哪里?如果将JaCoCo jar放入您的$ANT_HOME/lib文件夹,它将自动包含在您的类路径中.它使定义任务变得非常容易.不幸的是,这也意味着如果其他人想要运行你的Ant脚本,他们将不得不下载该JaCoCo jar并将其放入他们的$ANT_HOME/lib文件夹中.不太便携.

幸运的是,您可以指定JaCoCo jar的位置.由于您的项目通常受版本控制,因此放置它的最佳位置build.xml位于项目目录下方所在的位置.当有人检查你的项目时build.xml,他们也会得到JaCoCo.jar.

我的首选是创建一个名为的目录antlib,然后在该antlib目录中为每个任务集创建一个子目录.在这种情况下,我会有一个名为的目录antlib/jacoco.

一旦我的jacoco.jar文件安全地安置.在那个目录中,我可以添加一个<classpath>子实体给我<taskdef>说在哪里找到jacoco.jar:

在Classpath之前:

<taskdef resource="org/jacoco/ant/antlib.xml"/>
Run Code Online (Sandbox Code Playgroud)

在Classpath之后:

<taskdef resource="org/jacoco/ant/antlib.xml">
   <classpath>
       <fileset dir="${basedir}/antlib/jacoco"/>
   </classpath>
</taskdef>
Run Code Online (Sandbox Code Playgroud)

通过使用注意<fileset/>,我不在乎我的JaCoCo jar文件是否被调用jacoco.jarjacoco-2.3.jar.如果你知道jar的确切名称,你可以这样做:

<taskdef resource="org/jacoco/ant/antlib.xml">
   <classpath path="${basedir}/antlib/jacoco/jacoco.jar"/>
</taskdef>
Run Code Online (Sandbox Code Playgroud)

并保存几行.

第3步:XML命名空间

到目前为止,我不需要jacoco:为我的任务名称添加前缀.

我可以这样做:

<project name="MyApp" default="package" basedir=".">

    <taskdef resource="org/jacoco/ant/antlib.xml">
        <classpath path="${basedir}/antlib/jacoco/jacoco.jar"/>
    </taskdef>

    <target name="run-coco" depends="doOtherStuff">
        <coverage>
            <!-- ... -->
        <coverage>

        <report>
            <!-- ... -->
        <report>        
    </target>
</project>
Run Code Online (Sandbox Code Playgroud)

并且,你可以把它留在那.没问题.简单干净.

但是,如果您使用两个不同的Ant任务集,一个被调用Foo,一个被调用Bar,并且两个都碰巧<munge/>在其中定义了任务,那该怎么办?

<taskdef resource="org/foo/ant/antlib.xml">
    <classpath path="${basedir}/antlib/foo.jar/>
</taskdef>

<taskdef resource="org/bar/ant/antlib.xml">
    <classpath path="${basedir}/antlib/bar.jar/>
</taskdef>

<target name="munge-this">
    <!-- Is this foo.jar's or bar.jar's munge task? -->
    <munge vorbix="fester"/>
</target>
Run Code Online (Sandbox Code Playgroud)

哪个munge任务正在执行?它是一个foo.jar还是一个bar.jar

为了解决这个问题,Ant允许您为每组任务定义XML命名空间.您可以在最顶层<project>实体,任务本身或名称中定义此类命名空间<target>.99%的情况下,它是在<project>实体中完成的.

<project name="demo" default="package" basename="."
    xmlns:foo="I-will-have-fries-with-that"
    xmlns:bar="Never-on-a-first-date">

 <taskdef uri="I-will-have-fries-with-that"
    resource="org/foo/ant/antlib.xml">
    <classpath path="${basedir}/antlib/foo.jar/>
</taskdef>

<taskdef uri="Never-on-a-first-date"
    resource="org/bar/ant/antlib.xml">
    <classpath path="${basedir}/antlib/bar.jar/>
</taskdef>

<target name="munge-this">
    <!-- Look the 'foo:' XMLNS prefix! It's foo.jar's much task! -->
    <foo:munge vorbix="fester"/>
</target>
Run Code Online (Sandbox Code Playgroud)

现在,我知道这是<munge/>Foo任务列表中的任务!

xmlns定义XML命名空间.在xmlns:foo为Foo集TAKS定义了一个命名空间和xmlns:bar定义它了吧集的任务.当我使用任务时foo.jar,我在它前面加上foo:命名空间.请注意,此前缀是紧随其后的前缀xmlns:.

uri仅仅是该命名空间的字符串相匹配的字符串.我使用了字符串I-will-have-fries-with-thatNever-on-a-first-date告诉你字符串本身并不重要.重要的是这个字符串匹配任务的uri参数<taskdef>.这样,定义的任务就知道应该使用哪个命名空间.

现在,通常URI字符串是URI定义.有两种方法可以解决这个问题:

  • 使用antlib:有点标准化的URI,并使用命名空间的反向命名:antlib:org.jacoco.ant.
  • 使用指向该项目的网址:http://www.eclemma.org/jacoco/.

我更喜欢后者,因为它会指向文档.然而,看起来第一个更受欢迎.

那么,让我们来看看Jacoco将如何运作:

<project name="MyApp" default="package" basedir="."
    xmlns:jacoco="antlib:org.jacoco.ant">

    <taskdef uri="antlib:org.jacoco.ant" 
        resource="org/jacoco/ant/antlib.xml">
        <classpath path="${basedir}/antlib/jacoco/jacoco.jar"/>
    </taskdef>

    <target name="run-coco" depends="doOtherStuff">
        <jacoco:coverage>
            <!-- ... -->
        <jacoco:coverage>

        <jacoco:report>
            <!-- ... -->
        <jacoco:report>        
    </target>
</project>
Run Code Online (Sandbox Code Playgroud)

请注意,uriJaCoCo <taskdef/>中的xmlns:jacoco字符串与字符串相同.

这就是任务定义的全部内容.我希望它能解释jacoco:前缀的来源以及如何通过指向包含该类的实际类名来定义任务,或者指向指向任务名称类的资源文件.