Почему вариации на плагине Ant плагин taskdefs?

Меня действительно смущает правильный (самый современный, передовой опыт и т. Д.) Способ определения taskdef для плагинов Ant. Ниже приведен фрагмент кода, который я собрал из одного из наших собственных 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>
  1. Почему мне нужно определить пространство имен XML для JaCoCo, а не для Findbugs?
  2. Что такое Antlib? Иногда я вижу его в определении пространства имен XML, а иногда его там нет.
  3. Хотя оба jacoco-coverage а также javacoco-report Taskdefs используют дефис ("-") в своем имени, соответствующие задачи называются jacoco:coverage а также jacoco-report соответственно... почему двоеточие (":") для покрытия, и как это вообще работает (это, поверьте мне!)?

Заранее спасибо!

1 ответ

Решение

Давайте рассмотрим этот вопрос по одному шагу за раз:

Шаг № 1: Определение вашей задачи

Вы можете определить задачу одним из двух способов:

  1. Вы можете указать на файл класса, а затем дать задаче, что classfile определяет имя.
  2. Вы можете указать на файл ресурсов внутри фляги, в которой есть имена задач и файл классов, которые используют эти имена задач.

В вашем случае с JaCoCo вы сделали первое:

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

Однако вы можете сделать это и вторым способом:

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

Если вы откроете jar-файл jacoco и перейдете в этот каталог, вы увидите файл с именем 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>

Таким образом, если в банке находится файл ресурсов, вы можете определить все свои задачи с помощью одного <taskdef>, Обратите внимание, что вы назвали jacoco-coverage просто называется coverage здесь и то, что вы назвали jacoco-report называется report Вот.

Где вы использовали <jacoco-coverage/> в качестве задачи Ant я бы использовал <coverage/>,

Шаг № 2: Где находится файл JAR?

Выше я определил задачу следующим образом:

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

Где-то Ant должен найти этот путь в своем пути к классам, но где? Если вы положите банку JaCoCo в свой $ANT_HOME/lib папка, она будет автоматически включена в ваш classpath. Это делает определение задачи очень простым для выполнения. К сожалению, это также означает, что если кто-то еще захочет запустить ваш Ant-скрипт, ему придется скачать этот Jar-файл JaCoCo и поместить его в свой $ANT_HOME/lib папка. Не очень портативный.

К счастью, вы можете указать, где находится эта банка JaCoCo. Так как ваш проект обычно находится под управлением версией, лучшее место для его размещения находится в каталоге вашего проекта чуть ниже, где build.xml расположен. Когда кто-то проверяет ваш проект, и build.xmlони тоже получат JaCoCo.jar.

Я предпочитаю создавать каталог с именем antlib а затем создать подкаталог в этом antlib каталог для каждого набора задач. В этом случае у меня будет каталог с именем antlib/jacoco,

Однажды мой файл jacoco.jar благополучно запутался. в этом каталоге я могу добавить <classpath> Субъект моего <taskdef> говоря где найти jacoco.jar:

Перед Classpath:

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

После Classpath:

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

Примечание с помощью <fileset/>, Мне все равно, называется ли мой Jar-файл JaCoCo jacoco.jar или же jacoco-2.3.jar, Если вы знаете точное имя банки, вы можете сделать это:

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

И сохраните пару строк.

Шаг № 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>

И вы можете оставить это на этом. Никаких проблем. Просто и чисто.

Однако что делать, если вы используете два разных набора задач 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>

Который 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>

Теперь я знаю, что это <munge/> задача из списка задач Foo!

xmlns определяет пространство имен XML. xmlns:foo определяет пространство имен для набора Too Foo и xmlns:bar определяет его для набора задач. Когда я использую задачу из foo.jar, Я префикс это с foo: Пространство имен. Обратите внимание, что этот префикс является тот, который сразу после xmlns:,

uri это просто строка, которая соответствует строке пространства имен. Я использовал струны I-will-have-fries-with-that а также Never-on-a-first-date чтобы показать вам, что сами строки не важны. Важно то, что эта строка соответствует uri параметр <taskdef> задача. Таким образом, определяемые задачи знают, какое пространство имен они должны использовать.

Теперь обычно строка URI является определением URI. Есть два способа сделать это:

  • Используйте antlib: URI, который несколько стандартизирован и использует обратное именование для пространства имен: antlib:org.jacoco.ant,
  • Используйте URL, который указывает на проект: 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>

Обратите внимание, что uri в JaCoCo <taskdef/> такой же, как xmlns:jacoco строка.

Это все, что нужно для определения задач. Я надеюсь, что это объясняет, где jacoco: Приходит префикс и то, как вы можете определять задачи, указывая на фактическое имя класса, которое содержит этот класс, или на файл ресурсов, который указывает и на имя задачи, и на класс.

Другие вопросы по тегам