Gradleプラグインの作り方
G* Advent Calendar 2013の19日目です。
Gradleでビルドスクリプトを書いていると、他でも再利用できるタスクや関数が出てくることがあります。ビルドスクリプトの一部をプラグインに切り出すことで、他のGradleプロジェクトで再利用できます。
bluepapa32さんのG* Advent Calendar 12日目の記事でGradleプラグインの作り方が紹介されています。ネタがちょっとかぶってしまいましたが、本稿では違う視点から説明してみたいと思います。
Gradleプラグインの作り方
Gradleプラグインの実体はクラスファイルや設定ファイルを固めたJARです。Gradleプラグインを作るには、Gradleでプロジェクトを作って成果物としてJARを生成するのが簡単です。JARはMaven CentralやGitHubなどで配布します。
例えば、HelloPluginを作る手順は下記になります。
- build.gradle を書く。
- src/main/groovy/HelloPlugin.groovy にプラグインコードを書く。
- /src/main/resources/META-INF/gradle-plugins/hello.properties に設定を書く。これにより
apply plugin: 'hello'
でプラグインを適用できるようになります。 - src/test/groovy/HelloPluginSpec.groovy にテストコードを書く。必要に応じて。
- gradle build でビルドする。
他にもGitリポジトリやTravis CIの設定など面倒ですね。そこで、Gradleプラグインのブランクプロジェクトを作りました。
ブランクプロジェクトの使い方
git clone https://github.com/int128/gradle-plugin-blank.git gradle-hello-plugin
cd gradle-hello-plugin
./gradlew build
主な特徴
- プラグインの空実装が入っています (see HelloPlugin.groovy)
- Spockベースのテストコードが入っています (see HelloPluginSpec.groovy)
- プラグイン名の設定ファイルも入ってます (see hello.properties)
- GroovyDoc JARとsources JARを生成するタスクが入っています。
- Maven Central RepositoryにJARを発行するタスクが入っています。
- Travis CIに対応しています。
- Gradle Wrapperが入っているので、すぐに開発を始められます。
- Gradle、IDEA、Eclipse向けの.gitignoreが入っています。
Gradleプラグインの作り方が分かったところで、何を実装しましょうか?何かお題があってプラグインを実装するより、すでにあるビルドスクリプトから再利用できる部分を抜き出してプラグイン化することが多いと思います。
まずは、プロジェクト内のタスクや関数を共通化する方法から説明します。
apply fromを使う方法
プロジェクト内のタスクや関数を共通化するのであれば、別のスクリプトに切り出して apply from で読み込むだけで十分です。マルチプロジェクトの場合はルートプロジェクトに共通の定義を書けます。
// hoge.gradle def checkHoge() { println 'ほげほげ' }
// build.gradle apply from: 'hoge.gradle' task SomeTask << { checkHoge() }
この方法はとても簡単なので機動力が高い利点がありますが、スクリプトが肥大化するとビルド時間が長くなる欠点もあります。
buildSrcにコードを配置する方法
プロジェクトのbuildSrcに共通的なコードを配置して、プロジェクト内で利用する方法もあります。buildSrc内は特別なプロジェクトになっており、buildSrcの成果物はビルドスクリプトのクラスパスに配置されます。
例で説明しましょう。下記のようにコードを配置します。
- project/
- build.gradle
- buildSrc/
- src/main/groovy/
- Hoge.groovy
- src/main/groovy/
ここでgradleを実行すると、まずbuildSrcがビルドされて、その後projectがビルドされます。
$ ./gradlew :buildSrc:compileJava :buildSrc:compileGroovy :buildSrc:processResources :buildSrc:classes :buildSrc:jar :buildSrc:assemble :buildSrc:compileTestJava :buildSrc:compileTestGroovy :buildSrc:processTestResources :buildSrc:testClasses :buildSrc:test :buildSrc:check :buildSrc:build :help Welcome to Gradle 1.9. (以下略)
projectのビルド時にはbuildSrcの成果物がクラスパスに配置されるため、build.gradleからHogeクラスを使うことができます。
// buildSrc/src/main/groovy/Hoge.groovy class Hoge { static checkHoge() { println 'ほげほげ' } }
// build.gradle import static Hoge.* task SomeTask << { checkHoge() }
buildSrc内は一つのプロジェクトなので、プロダクトコードだけでなくテストコードも配置できます。
- project/
- build.gradle
- buildSrc/
- build.gradle
- src/
- main/groovy/
- Hoge.groovy
- test/groovy/
- HogeSpec.groovy
- main/groovy/
ユーティリティメソッドをbuildSrcに移動することでビルドスクリプトの見通しがよくなり、しかもビルドが早くなります。この方法は簡単な上に利点が多いので、知っておくと便利です。
buildSrcにプラグインクラスを配置してapply pluginする方法
前項の方法では、buildSrc内のクラスからビルドスクリプトのプロジェクトにアクセスすることができません。そこで、buildSrcにプラグインクラスを配置してapply pluginする方法があります。
Pluginインタフェースを実装したクラスをbuildSrcに配置します。Pluginインタフェースのapplyメソッドにはprojectインスタンスが渡されるため、これを使って新しいタスクを定義したりGradle DSLを拡張したりできます。
// buildSrc/src/main/groovy/HogePlugin.groovy import org.gradle.api.Plugin import org.gradle.api.Project class HogePlugin implements Plugin<Project> { void apply(Project project) { project.extensions.checkHoge = { -> println 'ほげほげ' } } }
// build.gradle
apply plugin: HogePlugin
ここでは project.extensions を使ってGradle DSLを拡張していますが、他にも project.container や project.convention.plugins を使う方法があります。Gradle DSLの仕様を読みながら進めるとよいでしょう。