简体   繁体   English

为什么Ant插件taskdefs的变化?

[英]Why the variations on Ant plugin taskdefs?

I'm really confused with the proper (most modern, best practices, etc.) way of defining taskdefs for Ant plugins. 我真的很困惑为Ant插件定义taskdef的正确 (最现代,最佳实践等)方式。 Below is a snippet of code that I pieced together taken from one of our in-house Java app's build.xml . 下面是我从一个内部Java应用程序的build.xml拼凑而来的代码片段。 Please note that all of the following Ant targets work perfect 100% (even though I've cut-n-pasted them together, and stripped out most of their contents for brevity's sake): 请注意,以下所有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>
  1. Why do I need to define an XML namespace for JaCoCo but not for Findbugs? 为什么我需要为JaCoCo定义XML命名空间,而不是为Findbugs定义?
  2. What is antlib? 什么是antlib? Sometimes I see it inside the XML namespace definition, and sometimes it's not there. 有时我会在XML命名空间定义中看到它,有时它不在那里。
  3. Although both jacoco-coverage and javacoco-report taskdefs use a hyphen ("-") in their name, the corresponding tasks are called jacoco:coverage and jacoco-report respectively...why the colon (":") for coverage, and how does that even work (it does, trust me!)? 虽然jacoco-coveragejavacoco-report taskdefs在其名称中都使用了连字符(“ - ”),但相应的任务分别称为jacoco:coveragejacoco-report ...为什么冒号(“:”)用于覆盖,以及它是如何工作的(确实如此,相信我!)?

Thanks in advance! 提前致谢!

Let's take this question one step at a time: 让我们一步一步地回答这个问题:

Step #1: Defining your task 第一步:定义你的任务

You can define a task in one of two ways: 您可以通过以下两种方式之一定义任务:

  1. You can point to a class file, and then give the task that classfile defines a name . 您可以指向一个类文件,然后给出classfile定义名称的任务。
  2. You can point to resource file inside the jar that has the task names and the classfile that those task names use. 您可以指向jar中具有任务名称和这些任务名称使用的类文件的资源文件。

In your case for JaCoCo, you did the first: 在你的JaCoCo案例中,你做了第一个:

<taskdef name="jacoco-coverage" 
    classname="org.jacoco.ant.CoverageTask"/>
<taskdef name="jacoco-report"
    classname="org.jacoco.ant.ReportTask"/>

However, you could do it the second way too: 但是,您也可以采用第二种方式:

<taskdef resource="org/jacoco/ant/antlib.xml"/>

If you open up the jacoco jar file and drill down in that directory, you will see a file called antlib.xml . 如果打开jacoco jar文件并在该目录中向下钻取,您将看到一个名为antlib.xml的文件。 If you look at that file, you will see this: 如果你查看该文件,你会看到:

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

So, if there is a resource file located in the jar, you can define all of your tasks with a single <taskdef> . 因此,如果jar中有资源文件,您可以使用单个<taskdef>定义所有任务。 Note that what you called jacoco-coverage is simply called coverage here and what you called jacoco-report is called report here. 请注意,你叫什么jacoco-coverage简称为coverage这里,你叫什么jacoco-report被称为report在这里。

Where you used <jacoco-coverage/> as an Ant task, I would use <coverage/> . 如果你使用<jacoco-coverage/>作为Ant任务,我会使用<coverage/>

Step #2: Where's the JAR file? 第二步:JAR文件在哪里?

In the above, I defined the task as: 在上面,我将任务定义为:

<taskdef resource="org/jacoco/ant/antlib.xml">

Somewhere, Ant has to find that path in its classpath, but where? 在某个地方,Ant必须在其类路径中找到该路径,但在哪里? If you put the JaCoCo jar into your $ANT_HOME/lib folder, it will automatically included in your classpath. 如果将JaCoCo jar放入$ANT_HOME/lib文件夹,它将自动包含在您的类路径中。 It makes defining the task very easy to do. 它使定义任务变得非常容易。 Unfortunately, it also means that if someone else wants to run your Ant script, they'll have to download that JaCoCo jar and put it in their $ANT_HOME/lib folder. 不幸的是,这也意味着如果其他人想要运行你的Ant脚本,他们必须下载JaCoCo jar并将其放在$ANT_HOME/lib文件夹中。 Not very portable. 不太便携。

Fortunately, you can specify where that JaCoCo jar is located. 幸运的是,您可以指定JaCoCo jar的位置。 Since your project is usually under version control, the best place to put it is under your project's directory just below where the build.xml is located. 由于您的项目通常受版本控制,因此放置它的最佳位置位于build.xml所在的项目目录下。 When someone checks out your project, and the build.xml , they'll get the JaCoCo.jar too. 当有人检出你的项目和build.xml ,他们也会得到JaCoCo.jar。

My preference is to create a directory called antlib and then create a subdirectory in that antlib directory for each and every set of tasks. 我的首选是创建一个名为antlib的目录,然后在该antlib目录中为每个任务集创建一个子目录。 In this case, I would have a directory called antlib/jacoco . 在这种情况下,我将有一个名为antlib/jacoco的目录。

Once my jacoco.jar file is safely ensconced. 一旦我的jacoco.jar文件安全地安置。 in that directory, I can add a <classpath> sub-entity to my <taskdef> saying where to find jacoco.jar : 在那个目录中,我可以在我的<taskdef>添加一个<classpath>子实体,说明在哪里找到jacoco.jar

Before Classpath: 在Classpath之前:

<taskdef resource="org/jacoco/ant/antlib.xml"/>

After Classpath: 在Classpath之后:

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

Note by using <fileset/> , I don't care whether my JaCoCo jar file is called jacoco.jar or jacoco-2.3.jar . 请注意,使用<fileset/> ,我不关心我的JaCoCo jar文件是否被称为jacoco.jarjacoco-2.3.jar If you know the jar's exact name, you could do this: 如果你知道jar的确切名称,你可以这样做:

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

And save a couple of lines. 并保存几行。

Step #3: XML Namespace 第3步:XML命名空间

As of this point, I don't need jacoco: prefixed to my task names. 到目前为止,我不需要jacoco:前缀为我的任务名称。

I could simply do this: 我可以这样做:

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

And, you could leave it at that. 并且,你可以把它留在那。 No problems at all. 没问题。 Simple and clean. 简单干净。

However, what if you are using two different Ant task sets, one called Foo and one called Bar , and both happen to have a <munge/> task defined in them? 但是,如果您使用两个不同的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>

Which munge task is being executed? 哪个munge任务正在执行? Is it the one in foo.jar or the one in bar.jar ? 它是foo.jar中的foo.jar还是bar.jar中的bar.jar

To get around this, Ant allows you to define an XML Namespace for each set of tasks. 为了解决这个问题,Ant允许您为每组任务定义XML命名空间 You can define such a namespace in the very top <project> entity, inside a task itself, or in a <target> name. 您可以在最顶层的<project>实体,任务本身或<target>名称中定义这样的命名空间。 99% of the time, it's done in the <project> entity. 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>

Now, I know that this is the <munge/> task from the Foo task list! 现在,我知道这是来自Foo任务列表的<munge/>任务!

The xmlns defines an XML namespace. xmlns定义XML命名空间。 The xmlns:foo defines a namespace for the Foo set of taks and the xmlns:bar defines it for the bar set of task. xmlns:foo为Foo设置的taks定义了一个名称空间,而xmlns:bar为任务栏集定义了它。 When I use a task from foo.jar , I prefix it with the foo: namespace. 当我使用来自foo.jar的任务时,我在它foo.jar加上foo: namespace。 Note that this prefix is the one right after xmlns: . 请注意,此前缀是xmlns:后面的前缀xmlns:

The uri is merely a string that matches the namespace string. uri只是一个与命名空间字符串匹配的字符串。 I used the strings I-will-have-fries-with-that and Never-on-a-first-date to show you that the strings themselves aren't important. 我使用了字符串I-will-have-fries-with-thatNever-on-a-first-date来向你展示字符串本身并不重要。 What is important is that this string matches the uri parameter of the <taskdef> task. 重要的是这个字符串匹配<taskdef>任务的uri参数。 This way, tasks being defined know what namespace they should use. 这样,定义的任务就知道应该使用哪个命名空间

Now, normally the URI string is a URI definition. 现在,通常URI字符串是URI定义。 There are two ways to go with this: 有两种方法可以解决这个问题:

  • Use an antlib: URI that is somewhat standardized, and uses that reverse naming for the namespace: antlib:org.jacoco.ant . 使用有点标准化的antlib: URI,并使用命名空间的反向命名: antlib:org.jacoco.ant
  • Use the URL that points to the project: http://www.eclemma.org/jacoco/ . 使用指向项目的URL: http://www.eclemma.org/jacoco/http://www.eclemma.org/jacoco/

I prefer the latter because it'll point to the documentation. 我更喜欢后者,因为它会指向文档。 However it looks like the first is more popular. 然而,看起来第一个更受欢迎。

So, let's look at how Jacoco will work: 那么,让我们来看看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>

Note that the uri in the JaCoCo <taskdef/> is the same as the xmlns:jacoco string. 请注意,JaCoCo <taskdef/>中的urixmlns:jacoco字符串相同。

That's all there is to task definitions. 这就是任务定义的全部内容。 I hope it explains where the jacoco: prefix comes and how you can define tasks by pointing to an actual classname that contains that class, or to a resource file that points to both the task name and the class. 我希望它能解释jacoco:前缀的来源以及如何通过指向包含该类的实际类名来定义任务,或者指向指向任务名称类的资源文件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM