私はant 1.7で作業していることに注意してください。Ant 1.8 のローカル スコープにはいくつかの追加オプションがあるため、不変性はそれほど大きな課題ではありませんが、これらの他のヒントのいくつかは依然として役に立ちます。
まず、マクロ内の uptodate の結果に基づいてオプションでタスクを実行する問題について - つまり、2 つのターゲットは必要ありません。これを行うには、条件タグを使用します。<or> タグを使用すると、最初の条件が失敗した場合にのみ 2 番目の条件が実行されます。<scriptcondition> タグを使用すると、JavaScript を使用して他の Ant タスクを実行できます。以下に例を示します (@ タグはマクロ定義属性を示します)。
<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>
さて、あなたが私のような人なら、マクロ定義入力である属性を処理して、マクロ定義スクリプトで参照できるいくつかの派生値を生成したいと思うかもしれません。処理に属性と文字列の連結が含まれているだけの場合は、連結ステップを含むデフォルト設定で属性の 2 番目のセットを指定する属性を指定することで、ブロックでそれを行うことができます。ただし、属性のデフォルトにプラグインできない何かを行う必要がある場合は、それをプロパティに入れる必要があります。プロパティは不変であるため、プロパティに一意の名前を付けるには、いくつかの追加手順を実行する必要があります。これには tstamp が役立ちます。通常、マクロに渡されるパラメーターの組み合わせには固有のものがありますが、この固有の組み合わせにバックスラッシュが含まれている場合は、これらの派生プロパティを使用するときに、javascript でバックスラッシュの問題が発生しないように、tstamp タグを使用してセカンダリの一意の識別子を派生させます。スクリプトで簡単に参照できる独自のプロパティを作成する方法は次のとおりです。
<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 つのマクロ定義アプローチを使用する必要がなくなりました。
<macrodef name="public.canova.setproperty">
<attribute name="name"/>
<attribute name="value"/>
<sequential>
<script language="javascript">
project.setUserProperty("@{name}","@{value}");
</script>
<sequential>
</macrodef>
一見すると、これのいくつかは少し複雑に見えるかもしれませんが、macrodef を正しく機能させ、コンポーネント スタイルのマクロを作成すると (つまり、マクロにスパゲッティ コードを入れないでください)、ant スクリプトは実際には短くなり、理解しやすくなります。維持しやすく、ログを追跡しやすくなります。ヒント - JavaScript は必要な場合にのみ使用してください。JavaScript を使用する場合は、マクロ内で使用することをお勧めします。これにより、Ant スクリプトのメインの「ロジック」からカプセル化されて隠されるため、自己文書化と可読性が向上します。あなたの主な「ロジック」の。物事が明らかでない場合は、コメントを使用してください。