Antの怪力

 

MuzzAntの達人だった。彼を見習って使えるAntタスクの幅を広げていこう。

 

Antで日本で最も有名なサイトはもしかしたらここかもしれない。

http://homepage1.nifty.com/kuprij/antdoc/about.html#navi_top

 

実際ここにはお世話になってます。困ったことがあるとすぐにこのページに行きます。大概というか殆ど解決します。

 

注)以下各タスクの説明になりますが、説明の例(緑色文字で表示)内で、${}で囲まれた文字列はプロパティ名です。このプロパティはbuild.xmlファイル内の上の方で定義されているか、外部のプロパティからインポートされているかなどを前提としています。

 

 

タスク詳細

ant       http://homepage1.nifty.com/kuprij/antdoc/tasks/ant.html

新しくAntのプロジェクトを開始する。現在のプロジェクトのサブプロジェクトとして使われることを意図している。

 

 

 

available:  http://homepage1.nifty.com/kuprij/antdoc/tasks/available.html

リソースが実行環境で使用できるか判定し、その結果プロパティに値を設定する。

リソースとは、ファイルやクラスパス中のクラス、JVMのシステムリソースのこと。

 

ü        property:        値を格納するプロパティの名前を指定

ü        value:           プロパティに設定する値が指定できる(指定しない場合、trueもしくはfalseが設定される)

 

<available file="a.properties" property=" myprop" value="a">

(結果)

a.propertiesが利用可能な場合、mypropプロパティに"a"が設定される。

 

 

copy:        http://homepage1.nifty.com/kuprij/antdoc/tasks/copy.html

ファイル及びファイルセットを新しいファイルまたはディレクトリにコピーする。

コピーする際にフィルタ処理を定義しておくと、指定した文字列を置換することができる。

1.5からはencodingパラメタが追加された。適切な円コーディングを指定することで文字化けが防止できる。

 

ü        file:            コピーするファイルのファイル名をひとつ指定する

ü        preservelastmodified:  

コピーしたファイルの最終更新日を、元のファイルと同じにする

ü        tofile:          コピー先のファイル名を指定

ü        todir:           コピー先のディレクトリ名を指定

ü        overwrite:       コピー先のファイルのほうが新しい場合でも、強制的に上書きする(yes/no)

ü        filtering:       フィルタ処理を有効にするかの指定(yes/no)

ü        flatten:         コピー元のディレクトリ構造を無視して、指定のディレクトリにフラットにコピー

ü        includeEmptyDirs:

ネストしたFileset要素に空のディレクトリが含まれている場合に、空のままディレクトリをコピーする(yes/no)

ü        encoding:        コピーするファイルのエンコーディングを指定

 

<copy todir="${build}/config" filtering="true">

<fileset dir="${src}/config"/>

<filterset refid="global_filters"/>

</copy>

(結果)

${src}/configディレクトリ配下のファイルがglobal_filtersフィルタを適用された状態で、${build}/config配下にコピーされる。

 

 

condition:  http://homepage1.nifty.com/kuprij/antdoc/tasks/condition.html

指定した条件を満たした場合に、プロパティを設定する。

条件はネストした要素で表される。

 

ü        property:        セットするプロパティ名を指定する

ü        value:           条件にマッチした場合にプロパティに設定する値を指定する

 

(包含できる要素)

       And

       Available

       Checksum

       Contains

       Equals

       Filesmatch

       Http

       Isfalse

       Isset

       Istrue

       Not

       Or

       Os

       Socket

       Uptodate

 

例)Equals要素

2つの文字列を比較してその結果を返す。完全に一致した場合はTrue,そうでない場合はFalseを返す。

ü        arg1:            比べる文字列1を指定する

ü        arg2:            比べる文字列2を指定する

ü        casesensitive:   大文字小文字を区別するかの指定

ü        trim:            比較する前に前後の余分な空白を削除するよう指定

 

       <condition property="target.env.pfx" value="NFA-">

              <equals arg1="${target.env}" arg2="uat" casesensitive="false"/>

       </condition>

 

delete:

ファイルおよびディレクトリを削除する。

 

echoproperties:  

プロパティの一覧を出力する。(ものすごく便利)

       <echoproperties destfile="${output_folder}/ant.properties" />

 

fail:       http://homepage1.nifty.com/kuprij/antdoc/tasks/fail.html

実行中のビルドを停止する。

 

ü        message:         ビルドが中止されたときに表示されるメッセージの指定

ü        if:              指定したプロパティが設定されていたら、ビルドを中止する

ü        unless:          指定したプロパティが設定されていなかったら、ビルドを中止する

 

<fail if="myprop" message="${myprop}: can be set other than true/false by task available!"/>

(結果)

mypropプロパティが設定されていたら、メッセージが出力されてビルドが中止する。

 

 

filter:     http://homepage1.nifty.com/kuprij/antdoc/tasks/filter.html

フィルタを設定する。トークンの区切り文字は@

この機能は強力である。たとえば、デプロイ先の環境が、開発環境、テスト環境、本番環境と複数あることは一般的なことであると思われる。

実際の運用としては、

1)リリースするたびに環境固有の設定を登録する

2)環境固有のconfigファイルを各環境に配置し、実行ファイルおよび実行スクリプトは環境固有の設定をこのファイルから読み取る(Java.propertiesファイルなど)

 

などがあろうが、この機能はこれを覆す。

3)保存されているソースコードのスクリプトやconfigファイル内には「@<トークン名>@」の形式で、パラメタを保存しておき、ビルド時に環境固有の設定をfilter機能を用いて、置換(具体的にはcopyタスクでファイルをコピー)する。

結果、環境にデプロイされる時点で、@<トークン名>@は具体的な値をもって配布されることになる。もちろん、この操作で.propertiesファイルをテンプレートの状態から、具体的な値を持ったものに変換してもよい。

 

1)は文句なく面倒くさい。2)はなかなかよいが、3)はさらにビルド時に条件等(例 -Dprofile=<prod|uat|dev>)を考慮して、トークンの置き換えが可能なのでより柔軟である。

 

ü        token:           トークンを指定。@は不要

ü        valuie:          トークンと入れ替える文字列を指定

ü        filtersfile:     フィルタ処理で入れ替える対象のトークンが記述されているファイルを指定。

 

<filter token = "author" value = "hoge" />

<copyfile src = "before.txt" dest = "after.txt" filtering = "on" />

(結果)

トークン@author@を文字列hogeで置き換えることを指定する。

before.txtafter.txtにコピーする際に、before.txt内の@author@トークンを文字列hogeに置き換える。

 

<filterset id="global_filters">         

              <filtersfile file="${output_folder}/ant.properties"/>                     

       </filterset>

 

<copy todir="${output_folder}" filtering="true">

<filterset refid="global_filters"/>

<fileset dir="." includes="${cfg_folder}/**/*.*"/>   

</copy>

(結果)

カレントディレクトリ内の${cfg_folder}/**/*.*に適合するファイル群が、${output_folder}ディレクトリにコピーされる際にフィルタが適用され、そのフィルタセットはglobal_filtersで指定されたものであり、この場合その内容は${output_folder}/ant.propertiesに格納された一連のプロパティ群である。

 

fixcrlf:    http://homepage1.nifty.com/kuprij/antdoc/tasks/fixcrlf.html

改行文字の変換をおこなう。Windowsで開発したテキストファイルをUNIXに転送する場合、改行文字の違いに悩まされることがしばしばある。Windows環境にて、転送前にこのタスクで改行文字を変更してから圧縮し、UNIX側にて解凍すればその問題を回避することが出来る。

       <fixcrlf srcdir="${output_folder}/${bin_folder}" eol="lf" eof="remove">

              <include name="**/*.*"/>

       </fixcrlf>

 

javac:      http://homepage1.nifty.com/kuprij/antdoc/tasks/javac.html

Antを実行中のVMでコンパイルを実行する。標準以外のコンパイラも指定可能。

最も簡単な方法はsrcdirパラメタにソースファイルを指定するやり方。ネストしたsrc要素も指定可能。Fileset要素によって更なる選択が可能。

 

ü        srcdir:          Javaソースファイルの場所を指定

ü        destdir:         クラスファイルを保存する場所を指定

ü        classpath:       使用するクラスパスを指定

ü        debug:           デバッグ情報付きでコンパイルするかを指定(on/off)

ü        debuglevel:      -gスイッチで指定されるキーワードリストを指定(lines/vars/source, none

ü        deprecation:     推奨されないAPIが使用されるたびに警告を表示するかどうかを指定

ü        optimize:        最適化オプションつきでコンパイルするかを指定

ü        filtering:       トークンが含まれている場合にフィルタリングを行うように指定(on/off

ü        target:          指定したVMのパージョンに対して、クラスファイルを生成

ü        verbose:         コンパイラが出力する情報を詳細なものにする

ü        source:          Assertionを有効にするように指定する

ü        compiler:        使用するコンパイラを指定

ü        listfiles:       コンパイル対象のソースファイルの一覧を出力する

 

<javac  srcdir      = "${src}/java"

        destdir     = "${build}/classes"

        optimize    = "${javac.optimize}"

        debug       = "${javac.debug}"

        debuglevel  = "lines,vars,source">

        <classpath refid="build.classpath"/>

</javac>

 

junit:     

Ant上からJUnit単体テストを実行する。

 

ü        fork:            Antを実行しているVMとは別のVMでテストを実行

ü        showoutput:      結果を外部ファイル等に書き込み

ü        pathelement:     実行するテストファイルの場所を指定

ü        batchtest:       まとめてテストを実行

ü        todir:           結果を書き込む場所の指定

ü        haltonerror:     テストの結果がErrorの場合にビルドを中止する

 

  <junit fork="true" haltonfailure="false" showoutput="true">
   <classpath refid="class.path"/>
   <classpath>
    <pathelement location="build/classes"/>
   </classpath>
      <formatter type="plain"/>
      <batchtest fork="yes" todir="test">
        <fileset dir="test">
          <include name="**/*Test.java"/>
        </fileset>
      </batchtest>
  </junit>

注)classpath.classファイルの場所を指定するのに対して、実際のテストが記述されているファイルの指定はbatchtest要素のfileset子要素内で指定している。

 

なお、Eclipseからの実行の際は、junit.jarExternalToolsのクラスパスに追加しておく必要がある。

 

 

 

 

macrodef:   http://www.xucker.jpn.org/java/ant/task/macrodef.html (TODO: Update this task)

 

mkdir:

ディレクトリを作成する

 

 

path:       http://homepage1.nifty.com/kuprij/antdoc/types/path.html#path_like

Classpathとともに、パス類似構造の指定に使われる。

PATHCLASSPATHを指定するのに使用する。

 

ü        path:            パスそのものを指定するときに使う。

ü        location:        単一のファイルやディレクトリを指定。

ü        refid:           すでに定義されているパス類似構造のIDを指定。

 

<classpath path = "F:\dev\app\classes\" location = "lib\mylib.jar" />

クラスパスをpathパラメタ及びlocationパラメタを使って指定。

 

まったく同じことが、ネストした要素でもできる。

<classpath>

    <pathelement path = "F:\dev\app\classes\">

    <pathelement location = "lib\mylib.jar">

</classpath>

pathelement を使って定義したほうが、追加などもしやすい。

 

結果、以下のパスが設定される。

F:\dev\app\classes\;${basedir}\lib\hoge.jar;

 

また、

<path id="build.classpath">

<fileset dir="${lib}/dist">

        <include name="**/*.jar"/>

        <include name="**/*.zip"/>

</fileset>

</path>

 

などとして、path類似構造を設定し、のちに、

<classpath refid="build.classpath"/>

 

として、IDで参照することもできる。

 

 

property  http://homepage1.nifty.com/kuprij/antdoc/tasks/property.html

一度設定すれば、プロジェクトのどこからでも使用可能。別のターゲットからでも使える。

設定方法:

-         name,valueの両方を指定

-         指定したいプロパティの内容をファイルで用意し、fileパラメタで指定(Java.properties)

-         指定したいプロパティの内容をリソースで用意し、resourceパラメタで指定(Java.properties)

-         name,refidパラメタですでに指定済みのプロパティを他の名前で指定

-         環境変数を用いるenvironmentパラメタ

-         prefixパラメタを指定すると、file,resourceパラメタでプロパティを指定する際にも、Prefixをつけられる

 

ü        location:        指定されたファイルの絶対パスをプロパティの値として設定

 

<property name="src" location = "src"/>

srcプロパティに、例えばH:\Development\FoxMonodir\FoxMonodir\jara\srcなどといった絶対パスが設定される。

 

    <property file="profile/default.properties"/>

ファイルprofile/default.properties内で、

name=value

の形で定義されているプロパティがインポートされる。

 

scp:        http://www.xucker.jpn.org/java/ant/task/scp.html

sshを用いたファイルのコピー。サーバ側でsshdが動いている必要がある。

注)scpタスクはオプショナルタスクなので、Javaによるssh2の実装であるJschが必要http://www.jcraft.com/jsch/index.htmlからダウンロードできる)

ダウンロードしたjsch.jarANT_HOME/libに配置する必要がある。

 

ü        file:            コピーするファイルを指定

ü        todir:           コピー先のディレクトリを指定

ü        trust:           (yes/no)yesでない場合、known hostファイルが必要になる

ü        port:            ssh接続で使うport番号。deafult22

ü        knownhosts:      trustnoにしたとき必要となるknown hostファイルのパスを指定。デフォルトは${user.home}/.ssh/known_hosts

ü        faileonerror:    エラーが出た場合、タスクの実行をここで終了するかどうかを指定。デフォルトはtrue

ü        password:        パスワードを指定

ü        keyfile#text:    キーを使った認証をする場合PrivateKeyのパスを記入

ü        passphrase:      キーを使った認証をする場合に必要となるパスワード

 

<scp todir="${user}:${password}@${server}:${remote_dir}" trust="yes">

    <fileset dir="${local_dir}">

    </fileset>

</scp>

(結果)

known_hostsファイルを使用せずに、${local_dir}配下のファイルを${user}:${password}@${server}:${remote_dir}にコピーする。

 

SCPエラーメッセージ例)

trustyesにせず、knownhostsも指定しなかった場合

com.jcraft.jsch.JSchException: reject HostKey

 

ユーザー名やパスワードが間違っている場合

com.jcraft.jsch.JSchException: Auth fail

 

パスワードがどこにも記入されておらず、keyfileも指定されていない場合

neither password nor passphrase for user admin has been given. Can't authenticate.

 

 

sshexec:     http://www.stackasterisk.jp/tech/java/ant03_03.jsp

SSH接続でリモートホストに対してコマンドを実行する。Scpと同様、オプショナルタスクとしての設定が必要(Scpの項を参照してください)

 

ü        host:            接続先リモートホスト

ü        username:        ログインユーザ名

ü        command:         実行するコマンド

ü        port:            接続先リモートホストのポート番号。deafult22

ü        trust:           (yes/no)yesでない場合、known hostファイルが必要になる

ü        knownhosts:      trustnoにしたとき必要となるknown hostファイルのパスを指定。デフォルトは${user.home}/.ssh/known_hosts

ü        password:        パスワードを指定

 

<sshexec host="${unix.server}"

       username="${unix.user}"

       password="${unix.password}"         

       trust="true"

       verbose="true"

       command="cd ${deploy.dir}/${build.version}/scripts;./install.sh"

/>    

(結果)

リモートホストにログインした後、まずcd ${deploy.dir}/${build.version}/scriptsを実行。その後、./install.shシェルスクリプトを実行する。

 

tar:

tarファイルを作成する。言うまでも無く、デプロイ時にまずデプロイしたいファイル群を圧縮してひとまとめにしてから、転送したほうが効率がよい。

       <tar tarfile="${deploy_folder}/${project.name}-${profile}-${build.version}.tar">

              <tarfileset dir                     = "${output_folder}/${bin_folder}"

                                  prefix                  = "${build.version}/${bin_folder}"

                                  preserveLeadingSlashes  = "true"

                                  mode                    = "744"

                                  username                = "${unix.user}"

                                  group                   = "${unix.group}">

                     <exclude name="${install_script}"/>

              </tarfileset>

       </tar>

 

taskdef:     http://homepage1.nifty.com/kuprij/antdoc/tasks/taskdef.html

新しいタスクの定義を処理中のプロジェクトに追加する

 

ü        name:            タスクの名前を指定

ü        classname:       タスクが実装されているクラスのFQCN(Fully Qualified Class Name:完全就職クラス名)を指定

ü        file:            タスク定義の含まれたファイル名を指定

ü        resource:        タスク定義の含まれたリソース名を指定

ü        classpath:       使用するクラスパスを指定

ü        classpathref:    使用するクラスパスを参照で指定

ü        loaderref:       使用するタスクを構築するクラスローダを指定

 

<taskdef classpathref="ant.helpers" name="propertyRef"     classname="com.drkw.tokyo.build.anthelpers.PropertyRef"/>

 

 

変数

${user.name}: 現在のユーザ名

@<property>@: Filterタスクで設定したトークン(ファイルのコピー時などに具体的な文字列に置換できる)

 

自作タスク

http://ant.apache.org/manual/develop.html#set-magic

http://ant.apache.org/manual/tutorial-writing-tasks.html(こっちのほうが詳しいかも)

 

1.    org.apache.tools.ant.Task or another classを拡張してJavaのクラスを作成する。

2.    それぞれの属性に対し、public voidで引数を一つだけとるsetterを書く。setXxx…の形式が必要。

3.    自作するタスクがネスとされた要素を含む場合、org.apache.tools.ant.TaskContainerインタフェースを実装する必要がある。

6. public void executeメソッド(引数なし)が実装となる。これはBuildExceptionを投げるよう宣言する必要がある。

 

例1)message属性を持ち、それを表示するタスク(抜粋)

package com.mydomain;
 
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;
 
public class MyVeryOwnTask extends Task {
    private String msg;
 
    // The method executing the task
    public void execute() throws BuildException {
        System.out.println(msg);
    }
 
    // The setter for the "message" attribute
    public void setMessage(String msg) {
        this.msg = msg;
    }
}

 

注1)   タスクを実装したクラスがAntを実行する際のクラスパスに入っている必要がある

注2)   <taskdef>要素をプロジェクトに追加する。

注3)   タスクを使う。^^)

 

こんな感じ。

<?xml version="1.0"?>
 
<project name="OwnTaskExample" default="main" basedir=".">
  <taskdef name="mytask" classname="com.mydomain.MyVeryOwnTask"/>
 
  <target name="main">
    <mytask message="Hello World! MyVeryOwnTask works!"/>
  </target>
</project>

 

例2)ビルドの直前に作成されたタスクを使うには以下のようにする

<?xml version="1.0"?>
 
<project name="OwnTaskExample2" default="main" basedir=".">
 
  <target name="build" >
    <mkdir dir="build"/>
    <javac srcdir="source" destdir="build"/>
  </target>
 
  <target name="declare" depends="build">
    <taskdef name="mytask"
        classname="com.mydomain.MyVeryOwnTask"
        classpath="build"/>
  </target>
 
  <target name="main" depends="declare">
    <mytask message="Hello World! MyVeryOwnTask works!"/>
  </target>
</project>

 

例3)default.propertiesに登録する

タスクの名前と実装クラスの名前を、org.apache.tools.ant.taskdefsにあるdefault.propertiesに登録する。(ant.jarファイルの中に格納されている)

 

ネストした要素のサポート

 

innerという名のネストされた要素をサポートしたいと仮定しよう。まず、このネスとされた要素を表現するクラスを作成する必要がある。たとえば、filesetエレメントを表現したい場合、Antのクラスであるorg.apache.tools.ant.types.FileSetを使うことを考えるかもしれない。

 

ネストされた要素の属性またはネスとされた子要素の属性はタスクで用いられたのと同じ方法で扱われる。(属性を扱うsetterメソッドやネスとされたテキストを扱うaddTextメソッドなど)

 

ネストされた要素innerを表すNestedElementクラスがあると仮定した場合、以下の3つのオプションが可能。

1.       public NestedElement createInner()

2.       public void addInner(NestedElement anInner)

3.       public void addConfiguredInner(NestedElement anInner)

1.はタスク自身にネストされた要素のクラスの作成を強制する。2.と3.はAnt自身がネストされた要素のクラスの作成をそれをタスクに渡す前に作成していなければならず、ネストされた要素のクラスは引数のないpublicなコンストラクタもしくはProjectのクラスを引数に持つpublicなコンストラクタを持っている必要がある。

 

手順は以下。

1.まずネスとされた要素が含む情報を格納するクラスを作成する。これはやはりset<Attributename>セッターで格納される。

2.複数の要素を含むことができる場合、これをリストに格納する。

3.ファクトリメソッドがオブジェクトをインスタンス化し、その参照をリストに格納しAntに返す。

4.executeメソッドが実装部を担う。