2011年2月27日日曜日

[ant][dtd][macrodef] antstructureタスクを例としたantをforkするマクロ

Antのantstructureタスクは、ビルドファイルで使える要素と属性を定義する
DTDを生成してくれます。
ですが、ヒトクセあるこのタスクは、実行時に外部のjarが必要で、Ant実行時に
クラスパスに追加してやる必要があるのです。そこで、こんな試み。
  1. 必要なjarをダウンロードする。
  2. 配布元にはMavenのリポジトリを使う。
  3. ダウンロードしたjarをクラスパスに追加して、別のvmでAntを走らせる。
  4. そこでantstructureタスクを使う。
javaタスクのforkをantタスクでやる感じです。antでforkする感じ。antfork?みたいな?


---
<?xml version="1.0" encoding="UTF-8"?>
<project basedir="." default="default" 
  xmlns:tomorrowscode="http://tomorrowscode.blogspot.com/">


  <target name="default" depends="init">
    <!--
    AntのDTDを生成します。
    antstructureタスクに必要なライブラリをMavenリポジトリからダウンロードします。
    ダウンロードしたライブラリを別のVMのクラスパスを加えて処理します。
    -->
    <tomorrowscode:antfork target="invoke-antstructure"
      classpath="${lib.dir}/commons-net-2.2-ftp.jar"/>
  </target>


  <macrodef name="antfork" uri="http://tomorrowscode.blogspot.com/">
    <!--
    このマクロは、ビルドファイルを別のVM上で実行するタスクを定義します。


    JavaからAntを起動する方法は、ここが参考になります。
    http://ant.apache.org/manual/running.html#viajava
    Antの組み込みプロパティの説明は、ここが参考になります。
    http://ant.apache.org/manual/properties.html
    -->
    <attribute name="basedir" default="${basedir}" description="Optional"/>
    <attribute name="target" default="NOT SET" description="Required"/>
    <attribute name="antfile" default="${ant.file}" description="Optional"/>
    <attribute name="classpath" description="Optional"/>
    <sequential>
      <java  classname="org.apache.tools.ant.launch.Launcher"
        fork="true" failonerror="true"
        classpath="${ant.core.lib}/../ant-launcher.jar;@{classpath}">
        <arg value="-f"/>
        <arg file="@{antfile}"/>
        <arg value="-Dbasedir=@{basedir}"/>
        <arg value="@{target}"/>
      </java>
    </sequential>
  </macrodef>


  <target name="init">
    <!--
    Mavenリポジトリから必要なjarファイルをダウンロードします。
    jarの場所は、http://mvnrepository.com/ から検索できます。
    -->
    <property name="lib.dir" location="lib"/>
    <mkdir dir="${lib.dir}"/>
    <get
      src="http://repo1.maven.org/maven2/commons-net/commons-net/2.2/commons-net-2.2-ftp.jar"
      dest="${lib.dir}" usetimestamp="true"/>
  </target>


  <target name="invoke-antstructure">
    <!--
    AntのDTDを生成します。クラスパスにcommons-netが必要です。
    -->
    <antstructure output="ant.dtd"/>
  </target>
</project>
---


リポジトリにもコミります。リポジトリからブラウズした方が読みやすいです。
ではでは。

---
追加 2011-3-25
依存するライブラリcommons-net を取得するのに、上ではgetタスクを使いましたけど、
Maven Ant Tasks を使えばもっとステキにできそうです。
http://maven.apache.org/ant-tasks/index.html

3 件のコメント:

  1. お疲れさまです、師匠。

    * さっそくありがたく使わせていただきます!
    * lib.dir プロパティの宣言 (?) は、グローバルスコープでなくてもいいんですね (そもそも Ant のビルドスクリプトにスコープの概念があるのかわかりませんが……)。
    * Maven リポジトリ検索用の Ant タスクとかないんでしょうか? commons-net-ftp.jar の URL を返してくれるといいなぁ、と。

    返信削除
  2. お疲れ様です。

    プロパティはプロジェクトインスタンス単位でグローバルになります。
    なのでantcallとかforkとかでは同名でも別プロパティです。

    リポジトリ検索のロジックはMavenに実装されているはずなので、
    そのAPIを呼び出せば実現できそうですね。フリですか。フリですね。

    返信削除
  3. > Maven リポジトリ検索用の Ant タスクとかないんでしょうか?

    Maven Ant Tasks を使えばいいみたい。
    http://maven.apache.org/ant-tasks/index.html

    返信削除