ビルドスクリプトがAntで書かれたレガシーなプロジェクトをGradle移行しようとして工数が見積もりより大幅に膨らんだ話。
- Ant 1.8.2
- Gradle 2.9
GradleのAnt互換な作りは素晴らしい
Gradle ドキュメントが詳しいが、GradleはAntとの親和性が非常に高い。
例えば既存のAntビルドスクリプトがこんな感じであったとき
<project>
<target name="compile">
<javac srcdir="src" destdir="classes" includeantruntime="false"/>
</target>
</project>
Gradleのビルドスクリプトにただ一行、
ant.importBuild 'build.xml'
と書いてあげれば、GradleタスクとしてAntターゲットを取り込むことができる。
取り込んであげたタスクは、普通にGradleタスクとして実行が可能。
$ ant compile
Buildfile: /path/to/build.xml
compile:
BUILD SUCCESSFUL
Total time: 0 seconds
$ gradle compile
:compile
BUILD SUCCESSFUL
痒いところにも手が届く
もしもGradle側の既存タスクと名前が被ってしまう場合も心配無用。Antターゲットの名前を変更してインポートできます。
ant.importBuild('build.xml') {
antTaskName -> "ant.${antTaskName}".toString()
}
$ gradle ant.compile
:ant.compile
BUILD SUCCESSFUL
cf. http://mrhaki.blogspot.jp/2014/12/gradle-goodness-rename-ant-task-names.html
この辺でGradle大好き人間一丁あがり。
これなら簡単に移行できるねーって言ってたら
スクリプトをGradleに書き換える作業は後でやるとして、ひとまずGradleからAntを呼び出す形なら簡単だねと言ってました。当初は。
ant.importBuild
を駆使して実際にスクリプトを書いてみたところ、以下の問題が。
- basedirが無視される
- プロパティの継承で仕様が異なる
basedirが無視される
GradleスクリプトをAntスクリプトと別の場所に置く要件があった場合、つまりAntのbasedir
と、GradleのprojectDir
が異なる場合、
スクリプトが意図通りに動きません。
ありがちなんですが、既存プロジェクトは複数のAntスクリプトをバッチファイルやシェルスクリプトでこねくり回してビルドしてました。
はじめは単純だったんでしょうけど、時を経るごとにAnt同士やスクリプトどうしの依存関係がぐちゃぐちゃに。
そのためかbasedir
の指定が必須な作りになっており、そのままインポートできない、と。
似たことで困っている人はいて、曰くUnresolvedなバグとのこと。
プロパティの継承で仕様が異なる
仕方ないのでbasedir
必須な既存のスクリプトを書き換えて、Gradleからでもインポートできるように変更しました。でもそこで章題の問題が顕在化。
Antは変数の上書きはせず、先勝ちことで知られています。
また、あるAntスクリプト内でant
タスクを使い、別のAntスクリプトを呼び出す場合、プロパティを引き継ぐか否かをinheritAll
属性で制御できます。
既存のプロジェクトには、以下のケースが混在していました。
- バッチファイルから、プロパティを
-D
指定してAntスクリプトを呼びだす - Antスクリプトから複数のAntスクリプトを呼びだす(
inheritAll="true"
) - Antスクリプトから複数のAntスクリプトを呼びだす(
inheritAll="false"
)
Gradleスクリプトで単純にant.importBuild
をすると、2.のケースになってしまいます。
結局この問題も、既存のAntスクリプトに手を加えずに解決することはできませんでした。
そして
どうにか既存の資産を使おうと試行錯誤しましたが、全部Gradleスクリプトに書き換えた方がスッキリするという結論に。
既存のビルドスクリプトがぐちゃぐちゃしているなら、ant.importBuild
を使わずに全部Gradleスクリプトで書き換える前提で見積もりましょう。