先週はGradleプラグインを自作していたが、そもそもGradleスクリプトの基本がよくわからない。
ということでこちらの公式ドキュメントを読みながら、手を動かしてみた。
[タスクの基本]
Gradleのビルドは1つ以上のプロジェクトから構成される。プロジェクトはjarやwarをビルドしたり、デプロイジョブを記述することもできる。
そうしたGradleの仕事はタスクの形で定義される。タスクがビルドで実行される仕事の最小単位となる。クラスをコンパイルしたり、jarをビルドしたり、javadocを生成したり。
これらのタスクは通常プラグインで定義されているが、自分で実装することもできる。
gradleコマンドはカレントディレクトリのbuild.gradle
ファイルまたはbuild.gradle.kts
ファイルを探して、実行する。
新しいディレクトリに以下の内容のbuild.gradle.ktsファイルを作る。
tasks.register("hello") { doLast { println("Hello world!") } }
実行すると以下のようになる。
$ gradle -q hello Hello world!
なるほど、これはシンプルで分かりやすい。
build.gradle.ktsファイルがGradleプロジェクトに相当する。ProjectのAPIをみると、確かにtasksプロパティが確認できる。
tasksプロパティはTaskContainer型で、TaskContainerには5つのregister()メソッドが定義されている。
- register(String name)
- register(String name, Class<T> type)
- register(String name, Class<T> type, Object... constructorArgs)
- register(String name, Class<T> type, Action<? super T> configurationAction)
- register(String name, Action<? super T> configurationAction)
クラスとしてタスクを定義して、それを登録することもできるようだ。
Hello worldの例は、{ ... }
を第2引数にしているので、最後のregister(String name, Action<? super T> configurationAction)
のメソッドを利用していることがわかる。
登録したタスクの内容を後から追加することもできる。
tasks.register("hello") { doLast { println("Hello Earth") } } tasks.named("hello") { doFirst { println("Hello Venus") } } tasks.named("hello") { doLast { println("Hello Mars") } } tasks.named("hello") { doLast { println("Hello Jupiter") } }
上記のタスクhelloを実行すると以下のようになる。
$ gradle -q hello Hello Venus Hello Earth Hello Mars Hello Jupiter
[Kotlinのコードを利用する]
先のHello worldの例でもわかるように、Gradleのビルドスクリプト内ではGroovyやKotlinのコードを記述することができる。
シンプルな例としては、以下のように変数を利用できる。
tasks.register("upper") { doLast { val someString = "mY_nAmE" println("Original: $someString") // Original: mY_nAmE println("Upper case: ${someString.toUpperCase()}") // Upper case: MY_NAME } }
以下のように、関数を定義して利用することもできる。
tasks.register("checksum") { doLast { fileList("./resources").forEach { file -> ant.withGroovyBuilder { "checksum"("file" to file, "property" to "cs_${file.name}") } println("$file.name Checksum: ${ant.properties["cs_${file.name}"]}") } } } fun fileList(dir: String): List<File> = file(dir).listFiles { file: File -> file.isFile }.sorted()
以下のフォルダ構造となっているときに、上記のchecksumを実行する。
$ tree . ├── build.gradle.kts └── resources ├── agile.manifesto.txt └── gradle.manifesto.txt
結果は以下のようになる。
$ gradle -q checksum /(省略)/resources/agile.manifesto.txt.name checksum: faa3983e3f8ad2a53ff9cfd746db6499 /(省略)/resources/gradle.manifesto.txt.name checksum: e4f048aef3c397d4ddaf835b090b8910
buildscript()メソッドを利用すると、外部ライブラリを利用できる。
import org.apache.commons.codec.binary.Base64 buildscript { repositories { mavenCentral() } dependencies { "classpath"(group = "commons-codec", name = "commons-codec", version = "1.2") } } tasks.register("encode") { doLast { val encodedString = Base64().encode("hello world\n".toByteArray()) println(String(encodedString)) // aGVsbG8gd29ybGQK } }
[タスクの依存関係]
タスクとタスクの間には依存関係を定義することができる。
tasks.register("hello") { doLast { println("Hello world!") } } tasks.register("intro") { dependsOn("hello") doLast { println("I'm Gradle") } }
このビルドスクリプトに対して、introタスクを実行すると、以下のようにhelloタスクが先に実行される。
$ gradle -q intro Hello world! I'm Gradle
タスクの依存関係を定義する際に、タスクを定義する順序は関係なく、依存される側のタスクを後に記述してもよい。
tasks.register("taskX") { dependsOn("taskY") doLast { println("taskX") } } tasks.register("taskY") { doLast { println("taskY") } }
ここでtaskXを実行すると以下のようになる。
$ gradle -q taskX taskY taskX
また、依存関係は後から追加することもできる。
repeat(4) { counter -> tasks.register("task$counter") { // task0〜task3を定義 doLast { println("I'm task number $counter") } } } tasks.named("task0") { dependsOn("task2", "task3") // task0の依存関係にtask2、taks3を追加 }
ここでtask0を実行すると、先にtask2とtask3が実行される。
$ gradle -q task0 I'm task number 2 I'm task number 3 I'm task number 0
[デフォルトタスク]
defaultTasks()
メソッドでデフォルトタスクを登録すると、タスクの指定なしでgradle
コマンドを呼び出した場合の処理を定義できる。
defaultTasks("clean", "run") task("clean") { doLast { println("Default Cleaning!") } } tasks.register("run") { doLast { println("Default Running!") } } tasks.register("other") { doLast { println("I'm not a default task!") } }
ここでgradle
コマンドを実行すると、以下のようになる。
$ gradle -q Default Cleaning! Default Running!
[まとめ]
- Gradleプロジェクトを構成するタスクは
tasks.register()
で登録できる - Gradleプロジェクト内でGroovyやKotlinのコードを記述できる
- タスク間の依存関係やデフォルトで実行されるタスクを定義できる
- コードは以下のリポジトリにまとめてある