Gradle：ビルドスクリプトの基本


Androidアプリを使っていると当たり前のようにGradleを使いますが実際のところあまり中身をわかっていないように思ったので調べてみます。

## Gradleとはなにか

Java環境におけるビルドシステム。（ビルドシステムといえば現在までにMakeやAnt,Mavenあたりがよく使われています）

公式サイトはこちらです。
https://gradle.org/

GradleはAndroidのビルドシステムとして採用されていることもあり、既に多くの利用者がいます。

Gradleのメリットはビルドの記述をGroovy（のDSL=ドメイン固有言語）で書けるので、かなり柔軟性が高いことです。

## まずは動かしてみる

MacOSの場合はbrewを使って簡単にインストールできます。

### Gradleのインストール

```bash
$ brew install gradle
$ gradle --version

------------------------------------------------------------
Gradle 2.5
------------------------------------------------------------

Build time:   2015-07-08 07:38:37 UTC
Build number: none
Revision:     093765bccd3ee722ed5310583e5ed140688a8c2b

Groovy:       2.3.10
Ant:          Apache Ant(TM) version 1.9.3 compiled on December 23 2013
JVM:          1.8.0_05 (Oracle Corporation 25.5-b02)
OS:           Mac OS X 10.10.3 x86_64
```

### ビルドスクリプトを作成

まずは`build.gradle`を作成します。

```bash
$ mkdir test
$ cd test
$ touch build.gradle
```

タスクを確認みると、この時点で既にいくつかのタスクが定義されています。

```bash
$ gradle tasks
:tasks

------------------------------------------------------------
All tasks runnable from root project
------------------------------------------------------------

Build Setup tasks
-----------------
init - Initializes a new Gradle build. [incubating]
wrapper - Generates Gradle wrapper files. [incubating]

Help tasks
----------
components - Displays the components produced by root project 'test'. [incubating]
dependencies - Displays all dependencies declared in root project 'test'.
dependencyInsight - Displays the insight into a specific dependency in root project 'test'.
help - Displays a help message.
model - Displays the configuration model of root project 'test'. [incubating]
projects - Displays the sub-projects of root project 'test'.
properties - Displays the properties of root project 'test'.
tasks - Displays the tasks runnable from root project 'test'.

To see all tasks and more detail, run gradle tasks --all

To see more detail about a task, run gradle help --task <task>

BUILD SUCCESSFUL

Total time: 0.96 secs
```

タスクは`gradle components`や`gradle help`、`gradle projects`などのように`gradle タスク名`で実行できます。

ここまでで特徴的なのは`wrapper`というタスクです。
実行してみましょう。

```bash
$ gradle wrapper
...
BUILD SUCCESSFUL

Total time: 0.862 secs

$ ls -al
total 24
drwxr-xr-x@ 7 shoma2da  staff   238  8 13 20:36 .
drwx------@ 8 shoma2da  staff   272  8 13 20:30 ..
drwxr-xr-x@ 3 shoma2da  staff   102  8 13 20:36 .gradle
-rw-r--r--@ 1 shoma2da  staff     0  8 13 20:34 build.gradle
drwxr-xr-x@ 3 shoma2da  staff   102  8 13 20:36 gradle
-rwxr-xr-x@ 1 shoma2da  staff  5080  8 13 20:36 gradlew
-rw-r--r--@ 1 shoma2da  staff  2404  8 13 20:36 gradlew.bat
```

`gradle`ディレクトリや`gradlew`、`gradlew.bat`が生成されました。
Androidアプリを作るときにもお馴染みのファイルですね。

これはGradleの環境を閉じ込めたラッパーファイル群で、マシン本体にGradleが入っていなくてもGradleによるビルドを行えるようにするためのものです。 **これらのファイルは必ずバージョン管理システムで管理するようにしましょう。**

使い方は`./gradlew tasks`などのような形です。（Windowsは`gradle.bat`を使う）

念のためバージョン確認。やっぱり一緒でした。

```bash
$ gradle --version
.
------------------------------------------------------------
Gradle 2.5
------------------------------------------------------------

Build time:   2015-07-08 07:38:37 UTC
Build number: none
Revision:     093765bccd3ee722ed5310583e5ed140688a8c2b

Groovy:       2.3.10
Ant:          Apache Ant(TM) version 1.9.3 compiled on December 23 2013
JVM:          1.8.0_05 (Oracle Corporation 25.5-b02)
OS:           Mac OS X 10.10.3 x86_64


$ ./gradlew --version

------------------------------------------------------------
Gradle 2.5
------------------------------------------------------------

Build time:   2015-07-08 07:38:37 UTC
Build number: none
Revision:     093765bccd3ee722ed5310583e5ed140688a8c2b

Groovy:       2.3.10
Ant:          Apache Ant(TM) version 1.9.3 compiled on December 23 2013
JVM:          1.8.0_05 (Oracle Corporation 25.5-b02)
OS:           Mac OS X 10.10.3 x86_64
```

それでは準備が整いましたのでタスクの作成に入っていきます。

```groovy:build.gradle
task hello {
    doLast {
        println 'Hello world!'
    }
}

//以下でも同じです
//task hello << {
//    println 'Hello world!'
//}
```

実行してみます。

```bash
$ ./gradlew hello
:hello
Hello world!

BUILD SUCCESSFUL

Total time: 1.584 secs
```

`Hello world!`が表示されました。

`build.gradle`はGroovy言語で書かれているため、普通のプログラミングができます。

```groovy
task count << {
    4.times { print "$it " }
}
```

```bash
$ ./gradlew count
:count
0 1 2 3 
BUILD SUCCESSFUL

Total time: 0.759 secs
```

## 別のタスクに依存したタスク

ここからしばらくは基本的には公式ドキュメントを読みながら写経がてらのメモになります。
https://docs.gradle.org/current/userguide/tutorial_using_tasks.html

`intro`というタスクを`hello`に依存させています。

```groovy
task hello << {
    println 'Hello world!'
}
task intro(dependsOn: hello) << {
    println "I'm Gradle"
}
```

`intro`の実行時には`hello`が先に実行されます。

```bash
$ ./gradlew intro
:hello
Hello world!
:intro
I'm Gradle

BUILD SUCCESSFUL

Total time: 0.952 secs
```

## 動的なタスク生成

文字列でタスクを定義できます。

```groovy
4.times { counter ->
    task "task$counter" << {
        println "${counter}番目のタスクです"
    }
}
```

```bash
$ ./gradlew tasks
...
Other tasks
-----------
task0
task1
task2
task3

$ ./gradlew task1 
:task1
1番目のタスクです

BUILD SUCCESSFUL

Total time: 0.914 secs
```

## 既にあるタスクの前や後ろに処理を追加する

`hello`タスクの前後に処理を追加していきます。

```groovy
task hello << {
    println 'Hello Earth'
}
hello.doFirst {
    println 'Hello Venus'
}
hello.doLast {
    println 'Hello Mars'
}
hello << {
    println 'Hello Jupiter'
}
```

```bash
$ ./gradlew hello
:hello
Hello Venus
Hello Earth
Hello Mars
Hello Jupiter

BUILD SUCCESSFUL

Total time: 1.228 secs
```

## 既にあるタスクをオブジェクトとして使用する

`$hello.name`という部分でタスク名を取り出しています。

```groovy
task hello << {
    println 'Hello world!'
}
hello.doLast {
    println "Greetings from the $hello.name task."
}
```

## タスクに独自のプロパティを設定する

`myTask`というタスクのプロパティとして`myProperty`を設定しました。
他のタスクからの読み取りも可能です。

```
task myTask {
    ext.myProperty = "myValue"
}

task printTaskProperties << {
    println myTask.myProperty
}
```

## メソッドを使う

ふつうのGroovyスクリプトなので当然メソッドも使えます。もちろんクラスも使えます。

```groovy
task checksum << {
    fileList('../antLoadfileResources').each {File file ->
        ant.checksum(file: file, property: "cs_$file.name")
        println "$file.name Checksum: ${ant.properties["cs_$file.name"]}"
    }
}

task loadfile << {
    fileList('../antLoadfileResources').each {File file ->
        ant.loadfile(srcFile: file, property: file.name)
        println "I'm fond of $file.name"
    }
}

File[] fileList(String dir) {
    file(dir).listFiles({file -> file.isFile() } as FileFilter).sort()
}
```

## デフォルトタスク

デフォルトタスクを設定できます。ビルド実行時にタスクを指定しなかった場合はデフォルトタスクが順に設定されます。

```groovy
defaultTasks 'clean', 'run'

task clean << {
    println 'Default Cleaning!'
}

task run << {
    println 'Default Running!'
}

task other << {
    println "I'm not a default task!"
}
```

```bash
$ ./gradlew 
:clean
Default Cleaning!
:run
Default Running!

BUILD SUCCESSFUL

Total time: 0.92 secs
```

とりあえずここまで。もう少し深く調べていこうと思います。