AntでScriptdefを使ってIFタスクを作る

今回も技術ネタ。お、まるで技術ブログみたいだ(w

閑話休題。ANTでIF分岐を行おうとしたら、targetを分けてif/unlessで処理をわけるのが常套手段である。しかしながら、たかだか、特定の条件でメッセージを変えたいくらいのことでtargetを分けるのはずいぶん大げさであるし、eclipseのAnt Launcherはなぜかプライベートターゲットを無視してくれない(一体、なんでなんだ……)。

ANTでIF文が用意されないのは、ある種の設計ポリシーによるものであるのはわかるが、どう考えても不便極まりない。たかだか、分岐をするだけで大幅にbuild.xmlを書き換えねばならないわけだから。

世の中には同じ事を考える人もいるようで、ant-contrib にはIFタスクがあるのだが、こちらのプロジェクトは、Version 1.0に至ることなく消滅しかけているようだ。そもそも拡張ライブラリは、可搬性を考えると、意外に面倒な点が多い。そこで考えた。Java6ではrhinoが同梱されている。IFタスクを作っちゃえばいいんじゃなかろうか。

というわけで作ってみたのが次のもの*1

    <scriptdef name="if" language="javascript">
        <attribute name="test" />
        <element name="then" type="sequential" />
        <element name="else" type="sequential" />
        <![CDATA[
            var value = project.getProperty(attributes.get('test'));
            var elems = elements.get(project.toBoolean(value) ? 'then' : 'else');
            if (elems) for (var i = 0; i < elems.size(); i++) elems.get(i).execute();
        ]]>
    </scriptdef>

使い方はこんな感じ。Condition タスクと組み合わせることでかなり自由に条件分岐の設定ができる。

<project name="iftest" default="iftest">
    <target name="iftest">
        <condition property="result">
            <os family="windows" />
        </condition>
        <if test="${result}">
            <then>
                <echo message="success!" />
            </then>
            <else>
                <echo message="fail!" />
            </else>
        </if>
    </target>
    ...
</project>

*1:どうでもいいけど、scriptdefはmacrodefに比べて機能が少なすぎる……