[英]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>
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-coverage
和javacoco-report
taskdefs在其名称中都使用了连字符(“ - ”),但相应的任务分别称为jacoco:coverage
和jacoco-report
...为什么冒号(“:”)用于覆盖,以及它是如何工作的(确实如此,相信我!)? Thanks in advance! 提前致谢!
Let's take this question one step at a time: 让我们一步一步地回答这个问题:
You can define a task in one of two ways: 您可以通过以下两种方式之一定义任务:
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/>
。
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.jar
或jacoco-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. 并保存几行。
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-that
和Never-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:
有两种方法可以解决这个问题:
antlib:
URI that is somewhat standardized, and uses that reverse naming for the namespace: antlib:org.jacoco.ant
. antlib:
URI,并使用命名空间的反向命名: antlib:org.jacoco.ant
。 http://www.eclemma.org/jacoco/
. 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/>
中的uri
与xmlns: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.