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