Обратите внимание, я работаю с муравьем 1.7.С локальной областью видимости в Ant 1.8 есть некоторые дополнительные опции, так что неизменность не такая уж сложная задача, но некоторые из этих других советов будут по-прежнему полезны.
Во-первых, в отношении вопроса о дополнительном выполнении задачи на основерезультаты обновления в макросе - это означает, что вам не нужно 2 цели.Для этого используйте тег условия.Тег заставит его выполнить второе условие только в случае сбоя первого условия.Тег позволяет использовать JavaScript для выполнения других задач муравья.Вот пример (@-теги обозначают атрибуты macrodef):
<condition property="whatever" value="false">
<or>
<uptodate>
<srcfiles dir="@{srcdir}" includes="@{srcincludes}" excludes="@{srcexcludes}"/>
<mapper><chainedmapper>
<flattenmapper/><!-- use any mappers you need to match source to target files-->
<globmapper from="*.jxw" to="@{targetdir}\*W.java"/>
</chainedmapper></mapper>
</uptodate>
<!-- w/ java 1.6 or later, you get a rhino javascript interpreter included w/ java-->
<scriptcondition language="javascript" value="true">
self.setValue(true);
echo = project.createTask("echo");
myArg1="@{myArg1}";
myArg2="@{myArg2}";
// need to create a reference from a classpath refid
myReference = new org.apache.tools.ant.types.Reference(project,"@{my.classpath.id.string}");
// get a handle to the ant java task, which we will use to execute a java program
javaTask = project.createTask("java");
javaTask.setFork(true);
javaTask.setFailonerror(true);
javaTask.setClassname("com.mycompany.mypackage.MySpecialClass");
javaTask.setClasspathRef(myReference);
javaTask.createArg().setValue(myArg1);
javaTask.createArg().setValue(myArg2);
//output the command line to standard out, for reference
echo.setMessage(javaTask.getCommandLine());
echo.perform();
javaTask.perform();
</scriptcondition>
</or>
</condition>
Теперь, если вы похожи на меня, вы можете захотеть выполнить некоторую обработку с атрибутами, которые являются вашими входными данными macrodef, и получить некоторые производные значения, которые могутбыть упомянутым в вашем скрипте macrodef.Если ваша обработка просто включает в себя конкатенацию атрибутов и строк, вы можете сделать это в блоке, где вы указали свои атрибуты, указав второй набор атрибутов со значением по умолчанию, который содержит шаги конкатенации.Однако, если вам нужно сделать что-то, что вы не можете подключить к атрибуту по умолчанию, вам нужно будет поместить его в свойство.Поскольку свойства являются неизменяемыми, вам нужно предпринять некоторые дополнительные шаги, чтобы дать вашей собственности уникальные имена.Tstamp пригодится, чтобы помочь с этим.Как правило, некоторая комбинация параметров, передаваемых вашему макросу, будет уникальной, но если эта уникальная комбинация включает в себя обратную косую черту, вы захотите получить вторичный уникальный идентификатор, используя тег tstamp, чтобы вы не столкнулись с проблемами обратной косой черты в своем JavaScript, когдаВы хотите использовать эти производные свойства.Вот как создать ваши уникальные свойства, на которые вы можете легко ссылаться в своем скрипте.
<macrodef name="public.macro.example">
<attribute name="srcpath"/>
<sequential>
<tstamp prefix="@{srcpath}"><format pattern="ddhhmmssSSS" property="time"/></tstamp>
<private.macro.example srcpath="@{srcpath}" propertyPrefix="prop${@{srcpath}.time}"/>
</sequential>
</macrodef>
<macrodef name="private.macro.example">
<attribute name="srcpath"/>
<attribute name="prefix"/>
<sequential>
<pathconvert property="@{prefix}.src"/>
<!-- now you can do special things with ${@{prefix}.src}, even in javascript -->
<script language="javascript">
self.setValue(true);
echo = project.createTask("echo");
myPrefix="@{prefix}";
mySpecialPropertyKey=myPrefix+".src";
//if your special property contains backslashes or other special js characters
// you need to use project.getProperty instead of a string literal to get the value
mySpecialPropertyVal=project.getProperty(mySpecialPropertyKey);
// do something with this derived value in javascript
echo.setMessage("my special property = "+mySpecialPropertyVal);
echo.perform();
</script>
</sequential>
</macrodef>
Прежде чем я пришел к вышеупомянутому решению, я придумал хак-стиль решения для переопределения свойства ant с помощьюновое значениеХотя это может оказаться полезным для переопределения свойства, поскольку я делаю прямой вызов класса ant, существует риск, что это может не сработать в будущих версиях ant.Поскольку это похоже на взлом, мое намерение состоит в том, чтобы использовать подход 2 macrodef, перечисленный выше, а не этот подход, когда это возможно.Обратите внимание, что этот конкретный вариант не поддерживает символы обратной косой черты, потому что на атрибуты ссылаются непосредственно в строковом литерале JavaScript.Первоначально я использовал этот простой вариант для создания своего уникального префикса, что исключало необходимость применения подхода с 2 макроопределениями для обхода неизменности свойств.Однако вы можете адаптировать этот макроопределение для использования второго макроопределения и уникального префикса, чтобы получить «@ {значение}» в javascript с помощью команды project.getProperty.
<macrodef name="public.canova.setproperty">
<attribute name="name"/>
<attribute name="value"/>
<sequential>
<script language="javascript">
project.setUserProperty("@{name}","@{value}");
</script>
<sequential>
</macrodef>
На первый взгляд, некоторые изэто может показаться немного сложным, но если вы правильно работаете с макросами и создаете макросы в стиле компонентов (т.е. не помещаете код спагетти в макрос), ваши скрипты ant должны стать короче, проще для понимания и проще в обслуживании, а такжеЖурналы будут легче следить.Совет - используйте javascript только тогда, когда это необходимо, и когда вы его используете, предпочтительно использовать его внутри макроса, чтобы он был инкапсулирован и скрыт от основной «логики» вашего скрипта ant, тем самым способствуя самодокументированию и читабельности.вашей основной "логики".Используйте комментарии, когда вещи не очевидны.