Apache Ivy を試す - その2

ライブラリプロジェクトに対して、そのテストプロジェクトが依存するという関係を Ivy で解決する。独自のロガーライブラリを例にとる。logging が本体プロジェクト、logging-test がテストプロジェクト。

logging の build.xml

<?xml version="1.0" encoding="utf-8"?>

<project name="logger" basedir="." default="compile"
         xmlns:ivy="antlib:org.apache.ivy.ant">

    <property name="revision" value="0.1.0" />

    <property name="src.d" value="src" />
    <property name="bin.d" value="bin" />
    <property name="lib.d" value="lib" />
    <property name="dist.d" value="dist" />

    <macrodef name="m_compile">
        <attribute name="excludes" default="" />
        <attribute name="includes" default="" />

        <sequential>
            <javac srcdir="${src.d}"
                   destdir="${bin.d}"
                   excludes="@{excludes}"
                   includes="@{includes}"
                   debug="on">
                <compilerarg value="-Xlint" />
            </javac>
        </sequential>
    </macrodef>


    <target name="init" description=": initialize project">
        <mkdir dir="${bin.d}" />
        <mkdir dir="${src.d}" />
        <mkdir dir="${lib.d}" />
        <mkdir dir="${dist.d}" />
    </target>

    <target name="resolve" description=": resolve module dependencies">
        <ivy:retrieve />
    </target>

    <target name="compile" depends="init, resolve"
            description=": compile application classes">
        <m_compile />
    </target>

    <target name="clean" description=": clean the project">
        <delete includeemptydirs="true">
            <fileset dir="${basedir}">
                <exclude name="src/**" />
                <exclude name="build.xml" />
                <exclude name="ivy.xml" />
                <exclude name="ivysettings.xml" />
            </fileset>
        </delete>
    </target>

    <target name="jar" depends="compile"
            description=": create jar">
        <jar destfile="${dist.d}/logging.jar"
             basedir="${bin.d}" />
    </target>

    <target name="publish" depends="jar"
            description=": publish this module">
        <ivy:publish
            artifactspattern="${dist.d}/[artifact].[ext]"
            resolver="local"
            pubrevision="${revision}"
            overwrite="true" />
    </target>

</project>

こちらで重要なのは publish target。artifactspattern にマッチする jar ファイル (厳密には (たぶん) jar に限らない、後述) を、resolver に publish してもらうという感じ。

logging の ivy.xml

<ivy-module version="2.0">

    <info organisation="mylib" module="logging" revision="0.1.0" />

    <publications>
    	<artifact />
    </publications>

</ivy-module>

publications が重要。ここではデフォルト設定の artifact だけを定義してるけど、ここで logging プロジェクトに含まれる artifact を色々書くこともできる。artifact には type と ext という属性がある。上で「jar に限らない」と書いたのはこれが関係してて、type や ext に jar 以外を指定すると、jar 以外から成る artifact (?) とすることができる。

logging-test の build.xml

上のとほとんど同じ。ivy:cacheclean 用の target とか jar へのクラスパスを追加してるだけ。

logging-test の ivy.xml

<ivy-module version="2.0">

    <info organisation="mylib" module="logging-test" />

    <dependencies>
        <dependency org="junit" name="junit" rev="4.5" />
        <dependency org="mylib" name="logging" rev="0.1.0" />
    </dependencies>

</ivy-module>

junit-4.5 と logging-0.1.0 に依存してますよーという定義。org やら name は logging artifact のものと一致している必要がある。

初め、jar target の属性が間違っていて、クラスファイルのない jar ファイルを publish してしまっていた。その状態でテストプロジェクトで resolve してコンパイルしたら、当然だけど失敗した。
その後 jar targe を修正してからクラスファイルがある jar ファイルを publish し、テストプロジェクトで resolve しても空の jar が使われ続けていた。

これは Ivy のキャッシュが残っているせいで、一度解決した際に手に入れた jar ファイル (クラスファイルのない jar ファイル) を使い続けていたのが原因だった。一度 ivy:cleancache してやると解決した。これに気づくのに時間がかかった。

この手のツールは、設定同士のつながりが分かってきてはじめて、理解が進む感じがした。