Gradle学習

自分の今のレベルでは情報をうまく体系化できなかったため、この記事は今後少しづつレベルアップして改善させて行けたら良いなと思っています。

Groovyの文法については以下にまとめました。

https://qiita.com/AsahinaKei/items/71449385cc3103c672ba

## タスク
Gradleで行う処理は**タスク**と言う。Gradleにおいてタスクは非常に重要な概念。

Gradleはビルドツールとして知られるが、ビルド作業も数多くあるタスクの内の一つに過ぎず、例えば、`$ gradle build`は`$ gradle`という「タスクを実行するコマンド」によって、`build`という名前の「タスクを実行している」に過ぎない。

タスクはプラグインによって後から追加することができる。

### タスクの定義
タスクを定義するには、`TaskContainer`クラスの`register()`を使用する。

`TaskContainer`オブジェクトは、`Project`オブジェクトの`tasks`プロパティを通じてアクセスする。

`build.gradle`に記述するスクリプトは、実際には`Project`オブジェクトに委譲される(イメージとしては、スクリプトが関数として`Project`オブジェクトに渡され、`Project`オブジェクトが呼び出すような形。実際にはもう少し複雑で、スクリプトがまるごと`Project`のプロパティに格納されたりするわけではない。ただ、委譲される = 「スクリプトが`Project`オブジェクトの持つプロパティやメソッドにアクセスできるようになること」と理解する。)ため、`Project`オブジェクトが持つプロパティである`tasks`にアクセスするには、`build.gradle`内で、ただ単に`tasks`と記述すれば良い。

```gradle:build.gradle
// 方法①(推奨) : タスクの定義が遅延される
tasks.register('hi') {
    doLast {
        println 'hi'
    }
}
```

```gradle:build.gradle
// 方法② : Build script(build.gradle)が評価された時点で、タスクも即座に定義される
task hi {
    doFirst {
        println 'hi'
    }
}
```

```gradle:build.gradle
// 廃止された記法
task hi << {            // 演算子 << は leftShift() と同じ
    println 'hi'
}
```
:::note alert
`<<`を使用した記法は、Gradle 5.0で廃止された。
:::

### タスクの実行
`$ gradle タスク名`で、指定したタスクが実行できる。

タスク名には省略記法もある。`aaaBbbCccDdd`タスクは`$ gradle aBCD`で実行できる。

```shell:
$ gradle hi

> Task :hi
hi
```
:::note info
`$ gradle`コマンドは、カレントディレクトリに配置された`build.gradle`をGradleのプロジェクトとして認識する。
:::

そのため、マルチプロジェクトにおいては
【プロジェクトのルートディレクトリで実行】
ルートディレクトリの`build.gradle`がプロジェクトとして認識される
【サブプロジェクトのディレクトリで実行】
サブディレクトリの`build.gradle`がプロジェクトが認識される

### タスクの編集(アクションの追加)
タスクは定義した後にも処理(アクション)を追加できる。`TaskContainer`クラスの`named()`を使う。

```gradle:build.gradle
// タスクの定義
tasks.register('myTask') {
    doLast {
        println 'タスクの定義'
    }
}
```
```gradle:build.gradle
// アクションの追加
tasks.named('myTask') {
    doFirst {
        println '1回目のdoFirst()'
    }
}
// アクションの追加
tasks.named('myTask') {
    doFirst {
        println '2回目のdoFirst()'
    }
}
```

`doFirst()`を2回実行すると、後に追加したほうが、早いタイミングで実行される。

```shell
$ gradle greet

> Task :myTask
2回目のdoFirst()
1回目のdoFirst()
タスクの定義
```

### 型を指定したタスク定義
Gradleにはあらかじめアクションが定義されたタスクが存在する。また、タスクはプラグインが提供するものもある。公式サイトのDSL Reference では **Task types** と言う表現になっている。

これらのタスクを利用したいときは、利用したいタスクの型を指定して、自分のタスクを定義する。利用したいタスク型が必要とするパラメータは定義の中で設定する。

たとえば、`Copy`タスクは、「ファイルやディレクトリをコピーする」というアクションが定義されたタスクであり、利用する場合に、コピー元のパス・コピー先のパスを設定する必要がある。下のコードでは、その設定を`from()`や、`into()`で行っている。タスクの型を指定してタスク定義する場合、アクション自体はすでに定義されているため、`doFirst()`や`doLast()`によってアクションを定義する必要は無い。

```gradle:build.gradle
// 型(Copy)を指定
tasks.register('copy', Copy) {
    from(file('srcDir'))
    into(buildDir)
}
```

### 組み込みタスク(build-in tasks)
Gradleにあらかじめ定義されたタスクを**組み込みタスク**と言う。

使用できるタスクは`$ gradle tasks`で確認できる。

```shell:
$ gradle tasks

Build Setup tasks
-----------------
init - Initializes a new Gradle build.
wrapper - Generates Gradle wrapper files.
...以下省略
```

### タスクルール

タスクを動的に定義する方法。

同じ処理をパラメータだけ変えて実行したい場合に利用すると、似た定義を何度もしなくて済む。

タスクルールは`Project`オブジェクトの`tasks`プロパティが参照する`TaskContainer`型オブジェクトの`addRules()`を使用する(`project.tasks.addRule()`)。

`addRules()`の第一引数に渡す文字列は`$ gradle tasks`コマンドを実行した時の表示文になる。第二引数にはクロージャーを渡す。クロージャーには、タスク実行時のタスク名が渡される。

```build.gradle
tasks.addRule('Pattern: say<WORD>: Say something.') { taskName ->
    if(taskName.startsWith('say')){
        tasks.register(taskName){
            String word = taskName.substring('say'.size())
            println "The word you specified is ... $word"
        }
    }
}
```

タスクルールが追加されたことを確認。
```shell
$ gradle tasks

Build Setup tasks
-----------------
init - Initializes a new Gradle build.
...省略

Rules
-----
Pattern: say<WORD>: Say something.
```

実際に実行してみる。
```shell
$ gradle sayHello

The word you specified is ... Hello
```

### タスクの依存関係(Task Graphs)
タスクには依存関係がある。**task Graphs** と言う。

例えば、タスクの実行順を A → B に制御したい、みたいなもの。依存関係を定義しておけば、実行時にGradleが制御してくれる。(依存関係の別に実行順を制御する方法もあり、正確には依存関係は実行順を制御するためのものではない)

依存関係が重複しても、Gradleはそれぞれのタスクを1度しか実行しない。
![tasks_graph.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1069520/a5d39733-d16b-4824-6228-9024626e57f0.png)
`$ gradle build`を実行すると、コンソールにいろんなタスク名が表示されるのは、依存している複数のタスクが自動的に実行されているため(`:タスク名`で表示される)。

循環する依存関係は定義できない。

```gradle:build.gradle
tasks.register('first') {
    doLast {
        println 'first task'
    }
}

tasks.register('second') {
    dependsOn tasks.first // 依存関係を追加
    doLast {
        println 'second task'
    }
}

tasks.register('third') {
    dependsOn tasks.second // 依存関係を追加
    doLast {
        println 'third task'
    }
}
```
```shell
$ gradle third

> Task :first
first task

> Task :second
second task

> Task :third
third task
```
`$ gradle second`では`third`しか指定していないが、依存関係をGradleが解決してくれる。

### タスクの実行結果
タスクの実行結果は**ラベル**によって表現される。

これらのラベルはタスク実行後に自動的にコンソールに出力される。同じコマンドを2回実行すると、`UP-TO-DATE`をよく目にする。
+ ラベルなし or `EXECUTED` : 実行済
+ `UP-TO-DATE` : 変更なし
+ `FROM-CACHE` : 前回のキャッシュあり
+ `NO-SOURCE` : 対象が無い

### タスクの上書き

既存のタスクは上書きすることができる。

試しに`java`プラグインが提供する`build`タスクを上書きしてみる。

```gradle:build.gradle
apply plugin: 'java'

Map<String, ?> args = [
    overwrite: true,
    action: {
        println 'Build is overwritten.'
    }
]
task(args, 'build')
```

```shell
$ gradle build

> Task :build
Build is overwritten.
```
:::note alert
組み込みタスクは、この方法で上書きすることができない。
:::

## プロジェクトの作成
Gradleでは(変更することもできるが)、プロジェクトのフォルダ構成を基本的にはMavenの規約に合わせる必要がある。規約とはソースコードは`src/main/java/`に格納するなどのルールや初期設定のこと。Mavenの規約と同じなので、MavenからGradleへの移行はしやすいと言われたりする。

`$ gradle init`コマンドでは規約に沿ったフォルダ構成を自動で作成できる。
```shell
$ gradle init
```

## DSL
DSLとは、Domain-Specific Language（特定のドメイン向け言語）の略称で、特定の問題領域に特化したプログラミング言語のことを指す。

DSLは、一般的なプログラミング言語とは異なり、特定のドメインでの問題解決に最適化されており、そのドメインにおける表現力が高いことが特徴。

DSLには大きく2種類ある。

- Embedded DSL(内部DSL) : 既存の言語を使用して作成されたDSL
- Srandalone DSL(外部DSL) : 新たな文法を持つ言語によって作成されたDSL

GradleのスクリプトはGroovyの内部DSLによって記述するため、文法はあくまでもGroovyの文法で理解できる。

## Gradleのスクリプト
Gradleのスクリプトには以下の種類がある。

- Build script
- Init script
- Settings script

これらのscriptは、３つそれぞれに応じたオブジェクトに委譲される。この時、scriptが委譲されるオブジェクトを *delegate object* と言う。

そのためscriptの中で、*delegate object* のプロパティやメソッドを使用することができる。突然、宣言されていないメソッドが出てきたように感じるのはこのため。

例えば、Build script (`build.gradle`)は`Project`型の *delegate object* に委譲される。そのため、`build.gradle`内では`Project`型のプロパティとメソッドが使用できる。

さらに3種類のscriptは`Script`インターフェースも実装しているため、`Script`インターフェースで定義されたプロパティ、メソッドも使用することができる。

これらの情報は [DSL Reference](https://docs.gradle.org/current/dsl/index.html) という形でGradleの公式サイトに掲載されている。

## スクリプトに使用されるファイル
| スクリプト | ファイル名 | 役割や機能 |
|:-:|:-:|:-:|
| Init script | `init.gradle` | ユーザー情報設定、環境設定  |
| Settings script | `settings.gradle`| マルチプロジェクトにおけるプロジェクト定義 |
| Build script | `build.gradle` | ビルド作業の定義 |
| プロパティファイル | `gradle.properties` | ビルド実行時に読み込まれる |

### Init Script
- ファイル名 : `init.gradle`
- 配置先 : 環境変数を使用する。
    - `<GRADLE_HOME>/init.d/`ディレクトリ
    - `<GRADLE_USER_HOME>/init.d/`ディレクトリ
- 実行されるタイミング : ビルドの最初
- *delegate object*の型 : `Gradle`
- 補足
    - 必須のファイルでは無い
    - Gradle自体の設定を行うもの。Build scriptで使用するライブラリの取得先やバージョンしておいて、複数のプロジェクトで使いまわしたりする。いろんなプロジェクトで特定のライブラリを毎回設定するのが面倒な場合などに使用するものだと思う。そのため、Init Scriptは環境変数で配置先を保持して、プロジェクトディレクトリには配置しない。

### Settings script
- ファイル名 : `settings.gradle`
- 配置先 : ルートプロジェクトの直下　※他の場所にも置ける
- 実行されるタイミング : ビルド前
- *delegate object*の型 : `Settings`
- 補足
    - 必須のファイルでは無い。マルチプロジェクトでは必須
    - マルチプロジェクトにおける、サブプロジェクトの定義

### Build script
- ファイル名 : `build.gradle`
- 配置先 : 
- 実行されるタイミング : ビルド時
- *delegate object*の型 : `Project`

## スクリプトの実行される仕組み

### スクリプトを構成する要素

+ Statement
+ Build script block
+ 変数

#### Statement

Groovyのstatement(文)。

一般的にstatementとはセミコロンで終わる1行の命令。if文の場合は1行で終わらないこともある。
文(statement)に対して、式(expression)は値を評価するコードで、値を返す。言語によって微妙に違うようなので、深入りはしない。

Gradleのスクリプトは *delegate object* に委譲されて実行されるため、statementでは *delegate object* のプロパティやメソッドが使用できる。

#### Build script block

Gradle独自の概念。実体はクロージャーを引数として受け取るメソッド。

Groovyのメソッドは、最後の引数がクロージャーの時は、`()`の外にクロージャーを出すことができる(※<a href="https://qiita.com/AsahinaKei/items/71449385cc3103c672ba" target="_blank" rel="noopener noreferrer">Gradleを理解するためのGroovy学習</a>)。これを利用して Build script block という独自の文法を作り出している(DSL)。

Build script block に処理を記述するということは、*delegate object* が提供するAPIが引数として受け取るクロージャーを定義しているということになる。

例えば、`build.gradle`の`dpendencies`ブロックに処理を記述することを考える。

```gradle:build.gradle
dependencies {
    
}
```

+ `build.gradle`は *delegate object* である`Project`オブジェクトに委譲される
+ `Project`オブジェクトには`dependencies()`というメソッドがある
+ つまり、`dependencies()`は *delegate object* のAPI
+ `dependencies()`は`dependencies(Closure closure)`という定義になっていて、引数の最後がクロージャーなので、クロージャーを`()`の外に出すことができる
+ つまり上記のコードは、`dependencies(Closure closure)`を実行していて、`{}`は`closure`部分のメソッドの引数

さらに、`dependencies()`に渡した`closure`は、別のオブジェクトへ委譲される。この *delegate object* からクロージャーを受け取るオブジェクトを**ドメインオブジェクト**という。

具体的には、`dependencies()`に渡したクロージャーは、`DependencyHandler`オブジェクトへ委譲される。

*delegate object* とドメインオブジェクトの違いは、役割の違いによるものであり、`Project`オブジェクトは *delegate object* としての機能と、ドメインオブジェクトとして機能を併せ持つ。

| Build script block<br>(*delegate object* のメソッド名) | 委譲されるオブジェクト<br>(ドメインオブジェクト) |
|:-:|:-:|
| dependencies | DependencyHandler |
| repositories | RepositoryHandler |
| allprojects | Project |
| subprojects | Project |
| initscript | ScriptHandler |
| buildscript | ScriptHandler |
| configulations | ConfigurationContainer |

##### `Project`オブジェクト

全てのドメインオブジェクト群を管理する。
`Project`オブジェクトから、全てのドメインオブジェクトへアクセスすることができる。
`build.gradle`ファイルと1対1の関係にある。

| プロパティ | 概要 | 型 | readonly |
|:-:|:-:|:-:|:-:|
| `name` | プロジェクト名 | `String` | ⚪︎ |
| `desciption` | プロジェクトに関する説明 | `String` | |
| `group` | プロジェクトが属するグループ | `Object` |  |
| **`tasks`** | プロジェクトのタスク | `TaskContainer` | ⚪︎ |
| **`dependencies`** | プロジェクトのdependency handler | `DependencyHandler` | ⚪︎ |
| `path` | プロジェクトのパス<br>(ファイルシステムのパスではない)<br>ルートプロジェクトの場合、`:`<br>サブプロジェクトの場合、`:child`<br>(`settings.gradle`でサブプロジェクトをchildと定義したとき) | `String` | ⚪︎ |
| `projectDir` | `build.grale`ファイルが配置されている<br>ディレクトリまでのパス | `File` | ⚪︎ |
| `status` | プロジェクトの状態<br>デフォルト値は`release`<br>ライブラリをメタデータと一緒にアップロードする時にのみ使用 | `Object` |  |
| `state` | プロジェクトのビルドの状態<br>`executed`,`failure`,`upToDate`などの値があり、デバッグ時にビルドが今どのフェーズに進んでいるのかを知れる | `ProjectState` | ⚪︎ |
| `version` | プロジェクトのバージョン | `Object` |  |
| `project` | 自分自身への参照<br>明示的に`Project`オブジェクトを使用したい時(プロパティ名やメソッド名が被った時)に使う | `Project` | ⚪︎ |
| `parent` | 親プロジェクトへの参照<br>シングルプロジェクトやマルチプロジェクトのルートプロジェクトではnull | `Project` | ⚪︎ |
| `allprojects` | このプロジェクトとその配下のサブプロジェクト<br>(親プロジェクトは含まない) | `Set<Project>`  | ⚪︎ |
| `subprojects` | サブプロジェクトへの参照 | `Set<Project>` | ⚪︎ |

| メソッド | 引数 | 戻り値の型 | 概要 | オーバーロード |
|:-:|:-:|:-:|:-:|:-:|
| `apply()` | `Closure` closure | void | プラグインの適用 | あり |
| `copy()` | `Closure` closure | `WorkResult` | ファイルのコピー | あり |
| `file()` | `Object` path | `File` | `File`オグジェクトの取得 | あり |
| `fileTree()` | `Object` baseDir | `ConfigurableFileTree` | ファイルツリーの生成 | あり |
| `project()` | `String` path | `Project` | `Project`オブジェクトの取得 | あり |
| `task()` | `String` name<br>`Cosure` closure | `Task` | タスクの定義 | あり |

#### 変数

Gradleで扱う変数には以下の種類がある。

+ ローカル変数
+ システムプロパティ
+ 拡張プロパティ
+ プロジェクトプロパティ(※Build scriptでのみ有効)


##### ローカル変数

スクリプトのトップレベルで宣言した変数や特定のブロックの中で宣言した変数。

Groovyの文法上は、動的な型付けを`def`を用いて行い、また`def`を省略することもできるが、Gradleでは`def`を省略することはできない。

##### システムプロパティ

Gradleで記述したスクリプトはGroovyのスクリプトとしてJVMで実行される。JVMにはシステムプロパティというランタイムに関するKey-Valueのペア情報が存在する。

システムプロパティはコマンドの`-D`オプションで指定するか、`gradle.properties`ファイルに`systemProp`接頭語をつけて設定することができる。

scriptからは`System.getProperty()`で取得することができる。

```properties: gradle.properties
systemProp.hello=hi
```

```gradle:build.gradle
tasks.register('sample'){
    doFirst {
        println System.getProperty('hello')
    }
}
```

```shell
$ gradle sample
> Task :sample
hi
```

##### 拡張プロパティ

スクリプトからドメインオブジェクトのプロパティを追加する仕組み。`ext`ブロックを使用して設定できる。

`projectName`や`version`などはGradleによって自動的に定義されている。

```gradle:build.gradle
ext {
    key1 = 'hello'
}

tasks.register('sample'){
    doFirst {
        println key1
    }
}
```

```shell
$ gradle sample

> Task :sample
hello
```
##### プロジェクトプロパティ

Build scriptで使用可能。設定方法が複数ある。

- 設定方法
    - プロパティファイル(`gradle.properties`)
    - 環境変数
    - コマンドライン引数(`-P`オプション)
   
プロパティファイルで設定する方法は以下の通り。
```properties: gradle.properties
myProp=hello
```

```gradle:build.gradle
// 取得方法も複数ある
tasks.register('sample'){
    doFirst {
        println project.property('myProp')
        println findProperty('myProp')
        println myProp
    }
}
```

```shell
$ gradle sample

> Task :sample
hello
hello
hello
```

## プラグイン
プラグインを追加することで、使用できるタスクや、`Project`オブジェクトのメソッド、プロパティが増える。

### javaプラグイン
```gradle:build.gradle
// binary plugins
apply plugin 'java'

// script plugins
plugins {
    id 'java'
}
```

ここでの`java`はプラグインIDと呼ばれる。プラグインIDの無い場合、`Plugin`インターフェースを実装したクラスを指定してもよい。

```gradle:build.gradle
apply plugin: org.gradle.api.plugins.JavaPlugin
```

`java`プラグインを適用すると、次のものが導入される。
+ タスク
+ ソースセット
+ プロパティ
+ メソッド
+ 規約

#### タスク

`java`プラグインには、さまざまなタスクが用意されているため、適用すると、使用できるタスクが増える。

#### ソースセット

複数のソースファイルを目的別にまとめ、名前をつけて管理する仕組み。ソースセットごとにタスクを定義したり、ソースセットごとにプロパティを定義することができる。

`java`プラグインには`main`、`test`というソースセットが含まれている。

ソースセットは追加することができる。

```gradle
sourceSets {
    newSourceSet
} 
```

`newSourceSet`という名前のソースセットを追加した場合、`newSourceSetCompile`と`newSourceSetRuntime`というConfigurationが追加される。

#### プロパティ

`java`プラグインには、多くのプロパティが含まれる。これらは`Project`オブジェクトのプロパティとして追加される。

あらかじめデフォルト値が設定されているため、値を変更したいときだけ使用する。
+ `sourceCompatibility` : ソースコードのJavaのバージョン
+ `targetCompatibility` : ランタイムのJavaのバージョン
+ `archiveBaseName` : アーカイブファイル(JAR)の名前

```gradle:buidle.gradle
sourceCompatibility = 11
targetCompatibility = JavaVersion.VERSION_11 // enumでも指定できる
archiveBaseName = 'aaaa.jar'
```

(当たり前だが、プロパティによって型が異なり、全てが`String`型というわけではない。個人的に、Gradlenの記述を理解するには、「Groovyのオブジェクトを扱っている」という意識を忘れないことが大事な気がしている。)
##### ソースセットごとのプロパティ
+ `name` : ソースセットの名前
+ `compileClasspath` : コンパイル時のクラスパス
+ `runtimeClasspath` : 実行時のクラスパス
```gradle:build.gradle
println sourceSets.main.compileClasspath
println sourceSets.['main'].compileClasspath
```
ソースセットごとのプロパティには、`Project`オブジェクトからアクセスする。
#### メソッド
+ `manifest()` : JARファイルに含めるマニュフェスト

#### 規約
`java`プラグインを適用することで導入される約束事。
+ アプリケーションのソースファイルは`src/main/java`ディレクトリに配置する
+ リソースファイルは`src/main/resources`ディレクトリに配置する

#### Toolchains
指定したJDKのバージョンがインストールされていない場合、インストールまでを行なってくれるようになる。

### 依存関係とConfiguration

Configurationとはプロジェクトがビルドされる際に必要なライブラリやファイルなどの依存関係を定義するための仕組み。

手作業なら、以下のような作業が必要。

1. ライブラリのファイルをダウンロード
2. ライブラリを配置したパスをクラスパスに追加
3. ライブラリが依存するライブラリがあれば、1の2繰り返し

Gradleでは設定を記述しておくだけで、ライブラリをダウンロード、派生する依存関係の解決などを自動で行ってくれるようになる。

Configurationを分けて依存関係を構成するで、ビルド時のみ、実行時のみ、といった目的ごとに依存関係を管理することができる。

下は、`compile`という`Configuration`に対して依存関係を定義している。

```gradle:build.gradle
dependencies {
    compile 'org.slf4j:slf4j-api:1.7.25'
}
```

#### Configurationの定義

```gradle:build.gradle
configurations {
    myConfiguration
}
```

```gradle:build.gradle
// Configurationの定義
configurations {
    myConfiguration
}
// 依存関係の定義
dependencies {
    myConfiguration 'org.slf4j:slf4j-api:1.7.25'
}
```

#### Configurationの継承
Configurationは継承することができる

継承すると、継承元のConfigurationで定義された依存関係を取り込むことができる。

```gradle:build.gradle
configurations {
    parentConf
    childConf.extendsFrom parentConf
}

dependencies {
    parentConf 'org.slf4j:slf4j-api:1.7.25' // childConfに依存関係が継承される
}
```

#### Maven Central リポジトリにおけるとの依存関係

Maven Central リポジトリを利用するには、まずリポジトリの定義が必要。

```gradle:build.gradle
repositories {
    mavenCentral()
}
```

Maven Central リポジトリのモジュール(ライブラリ)を特定するためには３つの情報が必要。
```
group: 'グループ名', name: 'モジュール名', version: 'バージョン番号'
```
省略記法もある。
```
'グループ名 : モジュール名 : バージョン番号'
```

```gradle:build.gradle
dependencies {
	myConfiguration 'グループ名 : ライブラリ名 : バージョン番号'
}
```

#### ファイルシステムにおける依存関係

独自に作成した汎用メソッドや、複数のプロジェクトから利用したいモジュール(Jarファイル)を利用するには、以下のように記述する。

```gradle:build.gradle
dependencies {
    myConfiguration file('絶対パス or 相対パス')   // 相対パスはプロジェクトのルートディレクトリが基準
}
```

#### Build scriptの中で外部ライブラリを使用したい時

```gradle:build.gradle
import aaa.bbb.ccc.D // 使用したいライブラリ

buildscript {
    repositories {
        mavenCentral() // 取得先リポジトリ
    }
    dependencies {
        classpath group: 'グループ名', name: '', version: 'バージョン番号'
        classpath 'グループ名 : ライブラリ名 : バージョン番号' // 省略記法でも良い
    }
}

tasks.register('hi') {
    doFirst {
        D.method() // Build scriptの中で、ライブラリのメソッドが使える
    }
}
```

## JARファイル

出力されるJARファイルのファイル名はデフォルトでは`<baseName>-<appendix>-<version>-<classifier>.jar`となっている。

これを変更するには以下のようにする。
```gradle:build.gradle
jar {
    baseName = 'aaa'
    appendix = 'bbb'
    version = 'ccc'
    classifier = 'ddd'
}
```
次のような方法もある。
```gradle:build.gradle
jar {
    archiveName = 'aaa.jar'
}
```

```gradle:build.gradle
jar {
    manifest {
        attributes(
            "Implementation-Title": "Gradle",
            "Implementation-Version": archiveVersion)
    }
}
```

## ファイル操作

バリエーションが豊富で、機能も豊富。以下は多数あるAPIの内の一部。

### ファイルの参照

```gradle:build.gradle
File fileA = file('絶対パス or 相対パス')   // 相対パスはプロジェクトのルートディレクトリが基準
```
`file()`は`java.lang.Object`のメソッド。引数には`java.net.URI`や`java.net.URL`のインスタンスを渡しても良い。ここは、Gradleというよりは、Groovyのメソッドとしての使い方。

### 複数ファイルの参照

```gradle:build.gradle
FileCollection fileLists = files('a.text', 'b.text')
```

### ファイルツリー(FileTree)

```gradle:build.gradle
// rootディレクトリから下の階層も含まれる
FileTree root = fileTree('root') 

// * : ０以上の文字列
FileTree htmlFiles1 = fileTree('root').include('*.html')
// ? : 任意の1文字
FileTree htmlFiles2 = fileTree('root').include('?.html')
// ** : ディレクトリ内の全ての階層含む
FileTree allHtmlFiles = fileTree('root').include('**/*.html')
// /で終わる : /以下の全ての階層のファイルを含む
FileTree allHtmlFiles2 = fileTree('root').include('sample/')

// includeの逆
FileTree withoutHtmlFile1 = fileTree('root').exclude('*.html')

// 第2引数にクロージャーを渡すこともできる
FileTree targetFiles = fileTree('root') {
    include '*.html'
    exclude '*.css'
}

// Mapを渡すこともできる
FileTree targetFiles2 = fileTree(dir: 'root', include: '*.html', exclude: '*.css')
```

### コピー

#### Project.copy()を使用する方法

```gradle:build.gradle
// ルートプロジェクト直下のsample.groovyをcloneディレクトリにコピー
copy {
    from 'sample.groovy' // コピー元ファイル (ディレクトリも指定できる)
    into 'clone' // コピー先のディレクトリ
}
```

#### Copy型の組み込みタスクを使用する方法
```gradle:build.gradle
tasks.register('copyReport', Copy) {
    from 'aaa/bbb.text'
    into 'clone'
}
```

## 参考
・<a href="https://amzn.asia/d/459p3fv" target="_blank" rel="noopener noreferrer">プログラミングGROOVY　関谷 和愛 (著), 上原 潤二 (著), 須江 信洋 (著), 中野 靖治 (著)　技術評論社</a>
・<a href="https://amzn.asia/d/aCjUeFu" target="_blank" rel="noopener noreferrer">Gradle徹底入門 次世代ビルドツールによる自動化基盤の構築　綿引 琢磨 (著), 須江 信洋 (著), 林 政利 (著), 今井 勝信 (著)　翔泳社</a>