18833 words
94 minutes
Gradle徹底入門 次世代ビルドツールによる自動化基盤の構築

Gradle徹底入門 次世代ビルドツールによる自動化基盤の構築#

理解したこと#

書籍情報#

形式:書籍 発売日:2014年11月04日 ISBN:9784798136431 価格:本体3,800円+税 仕様:B5変・592ページ 分類:プログラミング・開発 シリーズ:徹底入門

日本語初のGradle解説書、ついに刊行! Groovyベースのビルドツール「Gradle」は、SpringやHibernateなどの著名なOSSで利用されているほか、Androidの公式ビルドツールとして採用されており、これからの開発者やビルド職人には無視することのできないツールのひとつと言えるでしょう。 本書は、GradleのインストールからJavaアプリケーションのビルドやテスト、依存関係の管理、ビルド成果物の公開などのGradleの主要な機能の解説に加え、詳細なスクリプトファイルの記述方法からCIツールやIDEとの連携といった実業務で必要となる範囲までをカバーした日本語初のGradleの解説書となります。 有識者によるGradle 2.0ベース(1.x系ベースの章や2.1のトピックなどもあります)で書き下ろされた500ページを超える本書は「徹底入門」の名に恥じない内容で、これだけ充実したGradle解説書は、日本語ではもちろん英語でも類を見ません。 これからGradleを始める人、Gradleをもっと使いこなしたい人、GradleとJenkinsでCIをやりたい人、AntやMavenからの移行を考えている人…などなど、多くの開発者やビルド職人にお勧めできる一冊です。

第1部[導入編]#

第1章 Gradle の世界#

1.1 Gradleとは#

  • 次世代のビルドツールとして注目を集めているオープンソースのプロダクト

  • Gradleが注目されている理由

    • 既存のビルドツールに比べて優れている点が多い
    • Gradleのビルドスクリプトは非常にシンプルに記述できるという点
    • 具体的には本書を読みすすめると実感できる
  • NOTE

    • 特に、肥大したAntのビルドすくリプの保守に苦労された方や、Mavenに入門しようとしたものの敷居の高さに挫折した方にはおすすめ
  • もう1つの利点

    • AntやMaavenといった既存のビルドツールのエコシステムを最大限活用しているという点がある
    • Gradleは既存のAntタスクやAntビルドスクリプト、さたにMavenリポジトリを利用できるので、過去に蓄積してきた資産は無駄にならない
    • それらの資産を最大限利用して段階的にGradleに移行していくことが可能

1.1.1 ビルドツールとは#

  • ビルドツールとは
    • 定型的な作業を自動化するためのソフトウェア

1.1.2 ビルドツールの歴史#

  • ビルドツールの進化は比較的緩やかですが、時代とともに着実に発展しています。

  • ここでは、その進化の流れをたどってみたいと思います。

  • 元祖ビルドツールMake

    • 元祖はUnix系OSにおけるMakeといって差し支えない
  • JavaのためのビルドツールAnt

    • Antは当時流行のJavaとXMLを採用することで、Makeの弱点であったプラットフォーム依存から脱却することに成功
    • シンプルで使いやすい反面、ちょっと複雑なことをしようとするとビルドスクリプトが長大になる
    • メンテナンスが困難になる
    • ライブラリの依存関係を管理する仕組みが無い
  • ビルドツールの革新者Maven

    • JavaとXMLによるプラットフォーム独立のアーキテクチャはAntと同じですが、ビルドツールにビルドライフサイクルとプロジェクトオブジェクトモデル(POM)という概念を持ち込むことで、Antの弱点であったビルドスクリプトの冗長化を解消
    • また、POMにメタデータをもたせることで、ライブラリの依存関係を自動的に解決する仕組みを構築することに成功
  • そしてGradleへ

1.1.3 Gradleの概要#

  • GradleプロジェクトのWebサイトでは、Gradleとは、Build Automation Evolved すなわち、「ビルド自動化ツールの進化系」であると紹介されている

  • Gradleの特徴

    • 拡張可能なGradleビルド言語(GSL)の提供
    • ビルドの分割や共通部品抽出などの体系化の容易さ
    • IDEなどと連携するため、Gradleを外部からコントロールするためのAPIを提供
    • インクリメンタルビルドや並列ビルドなどでビルドを効率化
    • マルチプロジェクトサポートの柔軟性
    • Maven/Ivyリポジトリからローカルファイルシステムまで多用な依存関係管理手法に対応
    • Antタスクだけでなく、Antプロジェクト全体とのインテグレーションに対応
    • ビルドスクリプトの記述言語としてGroovyを利用
    • GradleラッパーによってGradleがインストールされていない環境でもビルドが実行可能
    • 互換性への配慮
  • Gradle User Guid

  • Gradleユーザーガイド(日本語翻訳版)

1.1.4 Gradleの事例#

  • Gradleが普及している例が紹介されている
  • AntやMavenと比較するとIDE連携やアプリケーションサーバー連携などが課題らしい

1.2 なぜGradleなのか?#

1.2.1 ビルドスクリプトの生産性の高さ#

  • GradleはMavenと同じく、規約ベースのビルドというアプローチを採用している

  • これにより、規約に従ったプロジェクト構造(ディレクトリ構造)を使う限りにおいては、ビルドスクリプトの記述を大幅に省略可能

  • GradleはJVM言語であるGroovyをベースに構築されている

  • GroovyはJavaにはない、リストリテラル/マップリテラル/クロージャといった機能が使える

  • GradleはたんにGroovyの文法を利用するだけでなく、ビルドスクリプトをより簡潔に記述するための独自の文法(DSL)も提供している

  • NOTE

    • XMLは静的な構造を表現することは得意ですが、ビルドスクリプトのような手順(手続き)を表現することには適していない

1.2.2 ビルド手順の制御の容易性#

  • Mavenの偉大な業績として
    • 大半のプロジェクトに適用できる標準的なビルド手順
    • メタデータによるビルド手順の制御
      • という考え方を導入し、それを実現する具体的なアイデアとしてPOMを導入したことが挙げられる

1.2.3 マルチプロジェクト対応#

  • サブプロジェクトに共通するビルドの設定など

    • マルチプロジェクトに含めるサブプロジェクトを定義する機能
    • サブプロジェクトに共通のビルドスクリプトを集約する機能
    • サブプロジェクト間の依存関係を定義する機能
    • 依存関係を考慮してインクリメンタルビルドする機能
  • 機能を列挙してみるとやや複雑そうな印象を受けますが、実際のビルドスクリプトは非常にシンプル

  • HibernateがGradleに乗り換えた理由も「マルチプロジェクト対応が優秀だったから」だそう

1.2.4 部品化の手軽さ#

  • 部品化も簡単だよーという説明

1.2.5 個別インストール不要#

  • AntやMavenを使う際には、利用者の環境にインストールしなければならない

  • ことのあるバージョンを導入してしまう可能性がある

  • このような問題に対処するために、GradleはGradleラッパーという仕組みを提供している

  • Gradleラッパーはプロジェクト内にGradleのブートストラップを仕込むことで、指定されたバージョンのGradleを必要に応じて自動的にインストールして実行してくれる機能

  • 使い方は簡単で、あらかじめGradleのwrapperタスクを実行してブートストラップを生成しておくだけです。

  • それをそのままSubversionやGitなどのバージョン管理システムに登録しておけば、利用者はバージョン管理システムからプロジェクトをチェックアウトし、gradlewコマンドを実行するだけで、Gradleのバイナリがダウンロードされ、ビルドが行われます。

  • Note

    • このGradleラッパーは優れたアイデアで、最近のビルドツールは同様にインストールレスで使えるようにしているものが増えてきているそう

1.2.6 互換性への配慮#

  • 互換性への方針

    • 既存の機能が突然使えなくなるような変更は行わない
    • 機能を除去する場合は、将来的に廃止される可能性を明示して段階的に除去する
    • 新機能は十分なフィードバックを受けて安定してから固定化する
  • ライフサイクル

    • 非公開
    • 実験的
    • 公開
    • 廃止

1.3 他のビルドツールとの比較#

1.3.1 Make vs Gradle#

  • 優位性
    • クロスプラットフォーム対応
    • 依存関係解決の機能

1.3.2 Ant vs Gradle#

  • 優位性
    • 依存関係解決の機能
    • 規約が無いため再利用性が損なわれる
    • 基本機能がシンプルであるがゆえに複雑なことをしようとすると冗長になる

1.3.3 Maven vs Gradle#

第2章 インストールと設定#

2.1 Gradleのインストール#

2.1.1 前提条件#

Gradleを利用するためにはJDK6以上が必要 Gradleは内部にGroovyのライブラリをバンドルしているので、別途Groovyをインストールする必要はない

2.1.2 GVMによるGradleのインストール#

  • MacOSXやLinux、CygwinなどでBashが使える環境であれば、
  • おすすめのインストール方法はGVM(the Groovy enVironment Manager)を利用することです。
  • GVMとは、GroovyやGrailsなどいわゆるGroovyエコシステムに付随するプロダクトのインストールやアップデートを一元的に行うためのツール
Terminal window
// 事前準備
// curl unzipは使えること
// GVMのインストール
curl -s get.gvm.net | bash
// プロキシ設定されていたら
export http_proxy = htpp://<proxyhost>:<port>/
// インストール後は、 `~/.bashrc`が書き換えられ、GVMが利用可能な状態になるので
// .source ~/.gvm/bin/gvm-init.sh を実行して環境設定を更新してください
// インストールされていることを確認
gvm help
// GVMのオフラインモード切り替え
gvm offline enable
gvm offline disable
// Gradleのインストール
gvm install gradle
// インストール可能なGradleのバージョン確認
gvm list gradle
gvm install gradle <version>
// 複数のバージョンのGradleをインストールしている場合切り替えることができる
gvm default gradle <version>

2.1.3 ZIPファイル展開によるインストール#

  • Windowsのインストール方法を説明

2.2 基本的な設定と動作確認#

2.2.1 環境変数の設定#

  • 環境設定

    • gradleコマンドへパスが通っていること
    • java コマンドが実行できること
  • JAVA_OPTS、GRADLE_OPTSの設定についても言及

2.2.2 gradleコマンドの実行#

Terminal window
gradle -v

第3章 スタートアップGradle#

3.1 Groovy特有の文法#

Gradleのビルドスクリプトは、実際にはGroovyのスクリプト しかし、Gradleの提供するDSLのおかげで、Groovyのことはあまり意識せずにビルドスクリプトが記述できるようになっている Groovyの文法はJavaと互換性があるので、Javaを知っていれば文法的に難解な箇所はそれほどないでしょう

とはいえ、Groovy特有の文法を知らないと、Gradleのビルドスクリプトを読み書きするのが難しいのも事実 Gradleでよく使われるものに絞って文法を説明

3.1.1 文字列#

文字列の表記方法として大きく2通りの方法が利用できる

  • シングルクォート:Javaの文字列とほぼ同等の利用方法
  • ダブルクォート:文字列の内部に$記号で動的な内容を埋め込むことができる。内部的には、GroovyのGStringというクラスが使われる

3.1.2 メソッド呼び出し時のカッコ省略#

3.1.3 defによる型指定の省略#

// 型を指定した変数定義
String name = 'John'
// 型を省略下変数定義
def name = 'John'
// Javaにおいて、Object型を指定した場合と同等になる
// ただし、Groovyの場合はダックタイピングの機能があるため、型としてdefを指定した場合でもオブジェクトのメソッドやプロパティは参照できる

3.1.4 クロージャ#

Groovyは言語機能としてクロージャを提供している Java8で導入されたラムダや、他のプログラム言語で言うところの関数オブジェクトのようなものと理解しておいて

クロージャは中括弧を利用して定義し、<クロージャ名>.call()または、通常のメソッド呼び出しと同様に<クロージャ名>()で実行できる

// クロージャ定義
def clos1 = { mes -> println "Hi, $mes"}
// 引数と省略した場合は、暗黙引数itを利用
def clos2 = { println "Hi, $it"}
// クロージャ実行
clos1.call('John')
clos2('Bob')
// メソッド呼び出しと同様にカッコ省略可能
clos2 'Alice'
  • Gradleはクロージャを多用しており、例えば次のようなタスク定義はクロージャによって実現されている
task hello << {
println 'Hello Gradle world!'
}
// 上記を個別に定義した場合は下記のようになる
// タスクへ追加する処理をクロージャとして定義
def clos = { println 'Hello Gradle world!' }
// タスクを定義
task hello {}
// タスクにクロージャを追加
// << は leftShift()の省略形なので以下と等価
hello.leftShift(clos)

3.2 Hello Gradle world#

3.2.1 ビルドスクリプトの作成と実行#

task hello doLast {
println 'Hello Gradle world!'
}
task hello2 doLast {
println 'Hello Gradle world!(hello2)'
}
// doLast欠かないとConfigure扱いになって起動時に処理はしるらしい

3.2.2 ビルドスクリプトと実行結果の解説#

  • 実行結果について説明しているだけ

3.2.3 組み込みタスク#

Gradleはビルドスクリプトで特に何も指定していなくても利用可能なタスクを提供している これらのタスクのことを「組み込みタスク(built-in tasks)」と呼びます タスクの一覧はgradle tasks で確認できる

E:\XXX_POKET\020_資格・学習\JAVA\20200613_Gradle徹底入門\practice\chap3>gradle tasks
> Task :tasks
------------------------------------------------------------
Tasks runnable from root project
------------------------------------------------------------
Build Setup tasks
-----------------
init - Initializes a new Gradle build.
wrapper - Generates Gradle wrapper files.
Help tasks
----------
buildEnvironment - Displays all buildscript dependencies declared in root project 'chap3'.
components - Displays the components produced by root project 'chap3'. [incubating]
dependencies - Displays all dependencies declared in root project 'chap3'.
dependencyInsight - Displays the insight into a specific dependency in root project 'chap3'.
dependentComponents - Displays the dependent components of components in root project 'chap3'. [incubating]
help - Displays a help message.
model - Displays the configuration model of root project 'chap3'. [incubating]
projects - Displays the sub-projects of root project 'chap3'.
properties - Displays the properties of root project 'chap3'.
tasks - Displays the tasks runnable from root project 'chap3'.
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 in 1s
1 actionable task: 1 executed
  • initタスクは「Build Setup tasks」に属しており、ビルドの初期化を行うタスクであるということが読み取れます
  • プラグインを追加することで利用できるタスクも追加されるので、gradle tasksで利用できるタスクを一覧で見れるということを覚えておく

また、よく使う組み込みタスクとして、gradle propertiesがある これはGradleのビルドスクリプトに定義されているプログラムの一覧を表示するタスク

3.2.4 主要なコマンドラインオプション#

  • ログ出力量の少ない順にGradleのコマンドラインオプションを並べると次のようになる

    • -i (--info)
      • ログレベルがINFOになり、ビルドスクリプトのファイル名などの情報が表示されるようになる
    • -s (--stacktrace)
      • 例外発生時にユーザー例外部分のみスタックトレースを表示
    • -S (--full-stacktrace)
      • 例外発生時にすべてのスタックトレースを表示
    • -d (--debug)
      • ログレベルがDEBUGに設定され、非常に詳細な情報が表示される様になる
  • デフォルトのbuild.gradleファイル以外のファイル名のビルドスクリプトを指定する場合

    • gradle -b build-new.gradle

3.3 プロジェクト自動生成とビルド#

3.3.1 initタスクによるプロジェクト自動生成#

gradle init --type java-library
// 生成される
// 途中、使用するDSLなどを聞かれる
  • Gradleの規約はMavenに倣って定義されているので、プロダクションコードは、

    • src/main/java以下
    • テストコードは
      • src/test/java以下に配置される
  • NOTE

    • Gradleは、規約とは異なる場所にJavaソースを配置することもできる
/*
* This file was generated by the Gradle 'init' task.
*
* This generated file contains a sample Java Library project to get you started.
* For more details take a look at the Java Libraries chapter in the Gradle
* User Manual available at https://docs.gradle.org/5.5.1/userguide/java_library_plugin.html
*/
plugins {
// ★Javaプラグインが適用されている
// これによりjavaプロジェクトに対する規約(プロダクションコードをsrc/main/javaに配置するなど)やJavaプロジェクトのビルドに必要なタスクが追加されます
// Apply the java-library plugin to add support for Java Library
id 'java-library'
}
// 昔の書き方として以下があったらしい
apply plugin: 'java'
repositories {
// ★Maven Centralリポジトリを指定
mavenCentral()
// Use jcenter for resolving dependencies.
// You can declare any Maven/Ivy/file repository here.
jcenter()
}
dependencies {
// 'group:name:version'という省略記法でプラグインが記載されている
// compileやtestCompileというキーワードがありますが、これはJavaプラグインによって定義されているコンフィグレーションを意味している 詳しくは第4章で解説
// This dependency is exported to consumers, that is to say found on their compile classpath.
api 'org.apache.commons:commons-math3:3.6.1'
// This dependency is used internally, and not exposed to consumers on their own compile classpath.
implementation 'com.google.guava:guava:27.1-jre'
// Use JUnit test framework
testImplementation 'junit:junit:4.12'
}

3.3.2 ビルド実行と結果確認#

先程自動生成したJavaプロジェクトをそのままビルドしてみましょう

gradle tasks
// 様々なタスクが追加されていることを確認
// ビルド実行
gradle build

ビルド実行直後再度ビルドすると、[UP-TO-DATE]と判断されて、処理がスキップされる様になっている

3.3.3 テスト実行と結果確認#

  • buildタスクの実行によって、testタスクも実行されている
  • 今回の場合、自動生成されたテストコードがコンパイルされ、テストが実行されている

レポートを確認してみる HTML形式レポートが出力されていることを確認

build/test-resultsディレクトリ以下を確認してみると、TEST-LibraryTest.xmlというファイルが生成されていることがわかる これはJUnit4が出力するXML形式のテストレポートで、Jenkinsなど他システムとの連携が必要な場合にはこちらを利用することになる

  • NOTE
    • じつは、先程確認したHTML形式のテストレポートは、このXML形式のテストレポートをGradleのJavaプラグインが加工して生成したもの

3.4 Webアプリケーションのビルド#

WebアプリケーションをビルドしてTomcat上で実行するビルドスクリプトを作成してみる

  • NOTE
    • Gradleの標準プラグインにJettyプラグインがあり、そちらを利用して組み込みJettyによるWebアプリケーションのテストを行うことも可能
    • しかし、このプラグインで起動されるJettyバージョンがJetty6と古く、Servlet3.0など新しいAPIに対応していません。
    • そのため、ここではサードパーティのプラグインを利用する手順を紹介しています。

3.4.1 Webプロジェクトの作成#

前回のjavaプロジェクトの、build.gradleを修正してWebプロジェクトへ発展させる

gradle init --type java-library
/*
* This file was generated by the Gradle 'init' task.
*
* This generated file contains a sample Java Library project to get you started.
* For more details take a look at the Java Libraries chapter in the Gradle
* User Manual available at https://docs.gradle.org/5.5.1/userguide/java_library_plugin.html
*/
// (1) Tomcatプラグイン利用のための設定
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.bmuschko:gradle-tomcat-plugin:2.0'
}
}
plugins {
// Apply the java-library plugin to add support for Java Library
id 'java-library'
// WARプラグイン追加
// id 'war'
// Tomcatプラグイン適用
// id 'com.bmuschko.tomcat'
// id 'com.bmuschko.tomcat-base'
}
apply plugin: 'war'
apply plugin: 'com.bmuschko.tomcat'
repositories {
// セントラルレポジトリ追加
mavenCentral()
// Use jcenter for resolving dependencies.
// You can declare any Maven/Ivy/file repository here.
jcenter()
}
dependencies {
// (4) 依存関係にJava EE 6のAPIを追加
// ビルド時には参照するが、ビルド生成物からは除外する 用に指定している
providedCompile 'javax:javaee-web-api:6.0'
compile 'org.slf4j:slf4j-api:1.7.5'
// This dependency is exported to consumers, that is to say found on their compile classpath.
api 'org.apache.commons:commons-math3:3.6.1'
// This dependency is used internally, and not exposed to consumers on their own compile classpath.
implementation 'com.google.guava:guava:27.1-jre'
// Use JUnit test framework
testImplementation 'junit:junit:4.12'
// (5) Tomcat実行に必要な依存ライブラリの設定
def tomcatVersion = '7.0.52'
tomcat "org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}",
"org.apache.tomcat.embed:tomcat-embed-logging-juli:${tomcatVersion}"
tomcat("org.apache.tomcat.embed:tomcat-embed-jasper:${tomcatVersion}") {
exclude group: 'org.eclipse.jdt.core.compiler', module: 'ecj'
}
}
gradle tomcatRunWar
gradle tRW

Buildエラーは出力されるが、アクセスできたhttp://localhost:8080/chap3-java-web/

3.4.3 WARファイルの生成#

gradle war

3.5 Gradleの便利な機能#

Gradleを使うにあたって知っておくと便利な機能を本章の最後に紹介

3.5.1 Gradleデーモン#

Gradleを本格的に使い始めると、まず気になるところが、gradleコマンドの起動に時間がかかること

この起動時間を解消するために、Gradleは「Gradleデーモン」という機能を提供している Gradleデーモンを利用すると、毎回JavaVMを起動/停止するのではなく、JavaVMを常駐させておくことができる

gradleコマンドを事項してGradleデーモン(JavaVMプロセス)を常駐させてしまえば 2度目以降のビルドは非常に高速に実行される用になります。

gradle --daemon hello
// デフォルトでデーモンを有効にしたい場合
// GRADLE_OPTSに追加する
GRADLE_OPS="-Dorg.gradle.daemon=true"
// gradle.propertiesに追加する
org.gradle.daemon=true
// デーモンは一定時間で停止されるが、明示的に停止する場合以下を実行
gradle --stop

3.5.2 Gradleラッパー#

新しいツールを現在進行中のプロジェクトに適用したい場合、以下の試練がある

  • Gradleの良さを紹介する
  • インストール方法を説明する
  • 使い方を説明する
  • 慣れるまでサポートする

この問題はGradleラッパーで解消できる

  • このメリット
    • 利用するGradleのバージョンを固定できる
    • JenkinsなどのCIツールを実行する環境にGradleをインストールしなくてよい

第2部[基礎編]#

第4章 Java プロジェクトのビルド#

4.1 Javaプロジェクトになぜプラグインが必要なのか?#

標準機能だけでJavaプロジェクトのビルドもできないの?と疑問に思われるかもしれない 実は、Gradleのコア機能は次の2つのみで構成されている

  • 定型的に繰り返し行う作業を自動化するための仕組み
  • 自動化された処理を実行するための部品

Gradleの看板機能であるビルド例外ではなく、自動化の対象となる具体的な作業はすべてプラグインとして実装されており、コア機能からは分離されている 厳密に言えば、Gradleは「ビルドツール」ではなく、「拡張可能な自動化ツール」と呼ぶのが適切なのだと思います。

このように、JavaプロジェクトのビルドにJavaプラグインが必要である背景には、Gradleのアーキテクチャに起因する理由がある

4.2 Javaプラグインとは#

Javaプラグインがどのようなものかを見ていきましょう

  • Javaプラグイン
    • タスク:Javaのビルドに必要
    • 規約:設定を簡略化する
    • プロパティ
    • ソースセット
      • がパッケージングされたビルド機能のコンポーネント

4.2.1 ソースセット#

最も重要なソースセットについて説明

ビルド対象となるソースの種類として、 ・プロダクションコード ・テストコード  ・ユニットテスト  ・インテグレーションテスト と、様々ある

このような構成に対応するためにソースセットという仕組みを提供している

  • 特徴
    • ビルドスクリプト内に自由に追加できる
    • ユニークな名前を持つ
    • コンパイルの入力となるJavaソースおよびリソースのセットが指定できる
    • コンパイルの出力(クラスファイルなど)を生成するパスが指定できる
    • コンパイル時のクラスパス、及び実行時のクラスパスが指定できる
    • ソースセットごとに専用のタスクを提供する
    • ソースセットごとに専用のプロパティを提供する

例えば、テストコードのコンパイルを行う前にプロダクションコードをコンパイルしておく必要がある場合、 テストコードに対応するソースセットのコンパイルタスクの依存関係にプロダクションコードのコンパイルタスクを設定するだけで済みます

Javaプラグインにはあらかじめmainとtestという2つのソースセットが定義されている 2種類のソースセットだけで対応可能なJavaプロジェクトであれば、独自にソースセットを追加する必要はない

4.2.2 タスク#

  • ビルドに必要な作業

    • ソースファイルのコンパイル
    • テスト
    • Javadocの生成
    • JARファイルなどへのアーカイブ
  • GradleのJavaプラグインには、そのすべての機能がタスクとして定義されている

  • 主要なタスク

    • clean
    • build
    • javadoc
    • jar

4.2.3 規約#

規約=約束事

  • Javaプラグイン規約

    • プロダクションコードのソース・ファイルはsrc/main/javaディレクトリ配下に配置していること
    • プロダクションコードのリソースはsrc/main/resourcesディレクトリ配下に配置していること
    • テストコードのソースファイルはsrc/test/javaディレクトリ配下に配置していること
    • テストコードのリソースはsrc/test/resourcesディレクトリ配下に配置していること
  • Mavenを使ったことのある人には馴染みの深いもの

  • 規約に関してはMavenという先輩の知恵を有効活用している

4.2.4 プロパティ#

  • 多くのプロパティにはデフォルト値が設定されている

4.3 Javaプロジェクトへの適用#

本章ではJavaプラグインの仕組みを理解するために、あえて手作業で作成

4.3.1 基本的なビルドの定義と実行#

4.3.2 テストコードを含むビルドの定義と実行#

4.3.3 その他の作業#

  • コンパイルオプションの設定
    • compileJavaタスクやtestCompileJavaタスクなどのJavaCompile型のタスクに対しては、optionsプロパティを利用して詳細なコンパイルオプションを設定できます。
compileJava {
// forkした別プロセスでコンパイルを行う
options.fork = true
// lint を無効化する
options.compilerArgs << '-Xdlint:unchecked'
}
  • JARファイルの設定
jar {
baseName = 'example'
appendix = 'bin'
version = '0.1'
classifier = 'jdk17'
}
// 直接指定する場合
jar {
archiveName = 'example.jar'
}
  • MANIFEST.MFのカスタマイズ

  • Javadoc生成

javadoc {
destinationDir = file("${buildDir/dist/javadoc}")
title = 'example library V0.1'
}
// @linkタグでJava標準APIのJavadocへリンクする場合など、外部のJavadocへのリンクを生成したい場合は次の用にする
javadoc {
options.links << 'http://docs.oracle.com/javase/jp/7/api/'
}
  • ビルド出力のクリーンアップ
    • 削除したい場合
    • Javadocのみ削除したい場合、gradle cleanJavadocを実行

4.4 Javaプラグインの詳細#

Gradleの規約に適合していれば、そこまで深くJavaのプラグインを知らなくてもよいが、 適合していない場合、独自のタスクを組み込んだりカスタマイズしていかなくてはならない

4.4.1 Javaプラグインのタスクの依存関係#

4.4.2 つくの詳細#

Javaプラグインが提供するタスクのうち、重要なものについて説明

テストに関連するタスクは第8章、アーティファクトの公開に関連するタスクは第12章で詳しく説明しているのでここでは割愛

  • compileJavaタスク/compileTestJavaタスク

    • JavaCompile型のタスク
    • javacコマンドによりJavaソースをコンパイルし、クラスファイルを生成します。
    • 対象
      • compileJavaタスク
        • ソースセットmainのjava.srcDirsプロパティで指定したディレクトリに含まれるJavaソース
      • compileTestJavaタスク
        • ソースセットtestのjava.srcDirsプロパティで指定したディレクトリに含まれるJavaソース
    • 拡張子が.javaのファイルのみがコンパイル対象となる
  • processResourcesタスク/processTestResourcesタスク

    • Copy型のタスク
    • プロダクションコードのリソース(.propertiesなど)をクラス出力先にコピーする
    • 対象
      • processResourcesタスク
        • ソースセットmainのresources.srcDisプロパティで指定したディレクトリに含まれるファイル
      • processTestResourcesタスク
        • ソースセットtestのresources.srcDisプロパティで指定したディレクトリに含まれるファイル
  • jarタスク

    • Jar型のタスク
    • JARファイルを生成します
    • dフォルトではアーカイブ対象はソースセットmainのoutputプロパティ、すなわちcompileJavaタスクとprocessResourcesタスクの出力です。
  • javadocタスク

    • Javadoc型のタスク
    • Javadocを生成します

4.5 規約に合わないプロジェクトへの適用法#

新規で作成するプロジェクトはできるだけGradleの規約に合わせることをおすすめします。 既存のプロジェクトにGradleを適用する場合や、プロジェクト特有の事情によってGradleの規約に合わせることができない場合に対応する方法を説明

4.5.1 ディレクトリ構成の変更#

  • src/main/java以下にxmlやpropertiesなどを配置している場合

TODO: 処理の意味が理解できていないので再確認 なぜこれで実現できるのか腑に落ちない

4.5.2 コンフィグレーションによる依存関係の変更#

Gradleには依存関係をグループ化して分類するコンフィグレーションという仕組みがある 依存ライブラリによってはコンパイル時のみ必要で実行時には不要であるものがある このような状況に対応するための仕組みがコンフィグレーションです

  • Javaプラグイン標準コンフィグレーション

    • compile: ソースセットmainのコンパイル時クラスパス。compileJavaタスクが参照
    • runtime: ソースセットmainの実行時クラスパス。デフォルトではコンフィグレーションcompileと同内容が設定
    • testCompile: ソースセットtestのコンパイル時のクラスパス
    • testRuntime: ソースセットtestの実行時クラスパス。
    • archives: このプロジェクトのアーティファクトを表すコンフィグレーション
    • default このプロジェクトに依存するプロジェクトが利用するデフォルトのクラスパス
  • MEMO: implementationとかの説明がない..

4.5.3 ソースセットの追加#

Javaプラグインは標準でmainとtestの2つのソースセットを提供している この2つだけでは足りない場合新しく追加できる インテグレーションテスト用のソースセットがほしいと仮定して作成してみる

sourceSets {
integrationTest
}

Javaプラグインの規約ではソースセットごとのプロパティにもデフォルト値が定義されている

  • Javaソースの配置先はsrc/integrationTest/javaディレクトリ
  • リソースの配置先はsrc/integrationTest/resourcesディレクトリ

作成すると勝手に上記のような規約に沿った形で定義されるみたい 規約に合わない場合は以下の用に定義して対応する

sourceSets {
integrationTest {
java.srcDir file('src/intTest/java')
}
}

TODO: 残りは、IntegrationテストとUnitテストを明確に分けたい場合参照すべし

4.6 Applicationプラグイン#

ApplicationプラグインはJavaアプリケーションを実行したり、配布したりするためのプラグインで、Javaプラグインを拡張して作られている

  • 用途
    • ビルドスクリプト内でメインクラスを指定し、Gradleからアプリケーションを実行する
    • アプリケーションを実行環境に配布するためのアーカイブ(ZIPファイル)を作成する

4.6.1 Applicationプラグインの利用方法#

// applicationプラグインを適用する
apply plugin: 'application'
// メインクラスのFQCN名(完全修飾名)を指定する
mainClassName = 'com.example.cli.SimpleCalc'
apply plugin: 'java'
apply plugin: 'application'
def defaultEncoding = 'UTF-8'
compileJava.options.encoding = defaultEncoding
sourceCompatibility = 1.7
targetCompatibility = 1.7
mainClassName = 'com.example.cli.SimpleCalc'
applicationName = 'SimpleCalc'
repositories {
mavenCentral()
}
dependencies {
compile 'commons-cli:commons-cli:1.2'
}
run {
standardInput = System.in
}
javadoc {
options.links << 'http://docs.oracle.com/javase/jp/7/api/'
}
  • runブロックの内容について
    • 実行するアプリケーションが標準入力を必要とする場合は必須
    • ビルド実行中はGradleが標準入力を処理しているため、アプリケーションに標準入力を渡すために、このようなおまじないが必要になります。

4.6.2 ビルドスクリプトからのアプリケーション実行#

  • Applicationプラグインを適用することで、runタスクが加わります
  • このタスクを実行するとGradleによって指定したアプリケーションが実行されます。

4.6.3 アプリケーション実行用アーカイブの作成#

アプリケーション実行用アーカイブを作成 この機能もApplication プラグインによって提供される アーカイブにドキュメントを追加したい場合は、プロジェクトのsrc/distディレクトリに、それらを配置しておけば自動的にアーカイブに含まれる

gradle distZipを実行する

  • build/libsディレクトリ
    • JARファイルが生成される(実際にJARファイルを生成しているのは
  • build/scriptsディレクトリ
    • アプリケーション実行用のシェルスクリプトとバッチファイルが生成される
    • distZipタスクと連動して実行した、startScriptsタスクが生成
  • build/distributionsディレクトリ
    • build/libsディレクトリやbuild/scriptsディレクトリの出力を含んだアーカイブが作成される

後は、アーカイブを配ってバッチ叩けば実行できるというもの GUIアプリとか配ると便利そう ローカルで起動する系のWEBアプリもこれで配れそう

  • 必要な依存ライブラリを添えろ得て配布物に含める
  • 環境変数や、JavaVMオプションなどを設定するための起動スクリプトを準備する

これらの手間がなくなるのでApplication プラグインは便利

4.7 Warプラグイン#

WarプラグインはJavaベースのWebアプリケーションのビルドを行うためのプラグインで、Application プラグインと同じ句、Javaプラグインを拡張して作られています

4.7.1 Warプラグインの挙動#

Warプラグインの主な機能はWARファイルを生成すること warタスクが実際にwarファイルを生成する

warタスクはJavaプラグインのjarタスクに相当しますが、次のような違いがある

  • ソースセットmainのコンパイル結果(クラスファイル)をWARファイルのWEB-INF/classesに配置する
  • コンフィグレーションruntimeに設定されている依存ライブラリ(JARファイル)をWARファイルのWEB-INF/libに配置する
  • webAppDirNameプロパティに設定されているディレクトリ以下をWARファイルの/に展開する
    • このプロパティに指定するディレクトリは、HTMLファイルやCSSファイルといったWebリソースの置き場を指す

4.7.2 プロパティ#

Warプラグインが提供するプロパティは次の2つ

  • webAppDirName
    • HTMLファイルやJSPファイルなどのWebアプリケーションコンテンツの配置先を、プロジェクトのルートから相対パスで指定
  • webAppDir
    • 前述のwebAppDirNameの設定に基づき、絶対パスが設定される(参照専用)

4.7.3 コンフィグレーション#

Warプラグインが提供するコンフィグレーションは次の2つ

  • providedCompile
    • ソースセットmainのコンパイル時クラスパスのうち、WARファイルへのコピー対象外としたいもの
  • providedRuntime
    • ソースセットmainの実行時クラスパスのうち、WARファイルへのコピー対象外としたいもの

これらのコンフィグレーションは、WARファイルの実行環境が提供している依存ライブラリを指定するときに使う 典型的な利用方法は、ServletAPIなどアプリケーションサーバーに含まれる依存ライブラリをビルド時のみ参照にし、WARファイルからは除外するという使い方

4.7.4 warタスクの設定#

ビルドスクリプトにwarブロックを追加して、warタスクの挙動をカスタマイズできる

例えば、web.xmlを別名で用意しておき、ビルド時にweb.xmlとしてWARファイルにコピーする場合

def env = 'dev'
war {
webXml = file("src/web-${env}.xml")
}
  • Eclipse WTPプラグイン
    • Warプラグインを適用したプロジェクトをEclipseで開く場合、Eclipseプラグインを適用して、gradle eclipseでEclipseプロジェクトを作っただけではEclipseのWTPプロジェクトとして認識されない
    • この場合、Eclipseプラグインを使うのではなく、EclipseWTPプラグインを利用してください

第5章 Gradle の基礎#

本章では、Gradleのアーキテクチャや主要な機能など、理解しておくべきGradleの基礎について解説

5.1 Gradleにおけるビルド#

Gradleでのビルドが何なのかについては明らかにしていませんでした Gradleのビルドが何を指し、どのように実行されるのかを説明する

5.1.1 ビルドとはなにか#

  • wiki
    • ソフトウェアのビルドは、ソースコードファイルを独立したソフトウェア成果物に変換するコンピュータ上で実行されるプロセス、またはその結果を指す。

なにかしらのアクションを実行すること、それがビルドツールにおけるビルドであると言える

  • Gradleでは実行する処理の単位をタスクと呼び、このタスクを実行することがGradleにとってのビルドであり、ビルドを実行するための仕組みがGradleの根幹

5.1.2 ビルドの入力情報#

ビルド実行時に、Gradleが参照するファイルやディレクトリ、パラメータにどのようなものがあり、 それらがどのような役割を果たしているかを理解しておきましょう

  • 初期化スクリプト
    • ビルドの最初で実行されるGroovyスクリプト
    • デフォルトのファイル名はinit.gradleになる
    • 主にユーザー情報や実行環境などの初期設定を行うために使う
    • 初期スクリプトはいくつか指定方法があり、複数のスクリプトファイルを使い分けることができる
  • 設定スクリプト
    • ビルド対象のプロジェクトの設定を行うGroovyスクリプト
    • デフォルトのファイル名はsettings.gradleとなります
    • 主にビルドに参加するプロジェクトを定義する用途で使用
    • マルチプロジェクトでは必須のスクリプトファイル
  • ビルドスクリプト
    • ビルドの入力情報の中で一番大切な「ビルドの定義」を記述するGroovyスクリプト
    • デフォルトのファイル名はbuild.gradleになります
    • 当該プロジェクトの依存関係やタスク定義などをするのが主な用途で、通常のビルドであればこのファイルだけで事足ります。
  • プロパティファイル
    • Gradleが標準で参照するプロパティファイルで、ファイル名はgradle.propertiesとなる
  • 環境変数/コマンドライン引数
  • buildSrcプロジェクト

これらのうち、以下の3つのスクリプトファイルは特に重要 記述した内容がビルド実行時にGradle固有のドメインオブジェクトに移譲される

スクリプトファイルGradleドメインオブジェクト
初期化スクリプトGradleオブジェクト
設定スクリプトSettingsオブジェクト
ビルドスクリプトProjectオブジェクト

5.1.3 ビルドの流れ#

コマンドラインからgreetタスクを実行するときの処理の流れについて見ていく

task greet doLast { println 'hello,' + user }
Terminal window
gradle -Puser=kotetsu greet
  • Gradleビルドの流れ
    • コマンドの解析:
    • スクリプトファイルの初期化:初期化フェーズ
    • プロジェクトの設定:設定フェーズ
    • タスクの実行:実行フェーズ

5.2 アーキテクチャと主要な機能#

5.2.1 物理構造#

Gradleは40近くのJARファイルで構成されるが、大きく分類するとGradle本体、プラグインの2つに分けられる

スクリプトファイルの中で適用されない限りは、基本的にGradleにプラグインはロードされない プラグインを取り除いてスリムにしたGradleを使用することもできる

このプラグイン機構はGradleの特徴の1つと言える

5.2.2 実行基盤を支える仕組みと標準機能#

ビルドで実行する処理の主体はプラグイン側にある Gradle本体が提供するのは、ビルドの実行基盤を支えるための仕組みと標準的な機能になる

  • 実行基盤を支える仕組み
    • 設定の自動ロード
    • プロジェクトの探索
    • タスクグラフ
  • Gradleの標準機能
    • ファイル操作:コンパイル後のファイルの出力先ディレクトリを作成したり、ビルド中の中間ファイルを削除したりとファイルシステムの操作をよく行う
    • ロギング:ビルドの実行中の状態を知るには、処理状態や処理中に起きた問題について出力する機能が必要
      • Gradleではロギングフレームワークを内包した独自のロギング機能により、ログの出力を制御できる

5.3 設定の自動ロード#

5.3.1 初期化スクリプトによる設定#

初期化スクリプトはビルドライフサイクルの初期化フェーズの先頭でロードされるため、ビルド実行時に環境設定を行うのに適している

例えばMavenCentralリポジトリを参照する設定を初期化スクリプトに定義して、実行ユーザーのホームディレクトリの.gradleに配置しておくと、同ユーザーが実行するすべてのGradleのビルドでMaven Centralリポジトリを参照できるようになります。

  • 初期化スクリプトの規約
    • コマンドライン引数 -I (—init-script)で指定する
    • <HOME>/.gradleディレクトリに配置:init.gradleが対象
    • <HOME>/.gradle/init.dディレクトリに配置:.gradleが対象
    • <GRADLE_HOME>/.gradle/init.dディレクトリに配置:gradleが対象

5.3.2 プロパティファイルによる設定#

Gradleが自動的にロードするプロパティファイルは、環境に関する設定を記述する場合に適している gradle.propertiesファイルに記述しておくと、初期化フェーズでロードされ、記述したプロパティが適用される

  • プロパティファイル
    • <PROJECT_HOME>ディレクトリに配置する:gradle.propertiesが対象
    • <HOME>/.gradleディレクトリに配置する:gradle.propertiesが対象
    • コマンドライン引数-D(—system-prop)で指定する:規約なし

5.4 プロジェクトの探索#

5.4.1 プロジェクト構成と探索の関係#

Gradleはビルドを実行する際にプロジェクトと言う概念で対象領域を特定する 通常、gradleコマンドを実行するカレントディレクトリがビルド対象のプロジェクト(カレントのプロジェクト)となる

Gradleはシングルプロジェクトとマルチプロジェクトをサポートしていることもあり、ビルドを実行する前に、カレントのプロジェクトがシングルプロジェクトなのかマルチプロジェクトなのか探索する必要がある このプロジェクトの判定は設定スクリプト(settings.gradle)を利用して行う この設定スクリプトはプロジェクトを特定する上で重要な役割を担っている

  • 設定スクリプトの決まり
    • 設定スクリプトはルートプロジェクトの直下に配置しなければならない
    • マルチプロジェクトの場合には、必ず設定スクリプトを容易しなければならない

5.4.2 設定スクリプトに基づいた構成の特定#

プロジェクトを探索するためには設定スクリプトの有無が最初のポイント

  • 読み込み方法
    • コマンドライン引数の-c(—settings-file)オプションで、ファイルを指定する
      • 引数で指定された場所にあれば読み込む
    • Gradleの規約に従った場所に配置する
      • 1.カレントディレクトリにsettings.gradleがあれば読み込む
      • 2.カレントディレクトリの親ディレクトリにsettings.gradleがあれば、それを設定スクリプトとみなす
      • 3.カレントディレクトリと同じ階層にmasterディレクトリがあり、その配下にsettings.gradleがあればそれを設定スクリプトとみなす
        • ※ただし、コマンドライン引数に-u(—no-search-upward)オプションが含まれていた場合、2,3は行われない
        • カレントディレクトリに設定ファイルが存在しなければシングルプロジェクトとして扱う

5.5 タスクグラフ#

5.5.1 タスクグラフの概要#

Gradleのタスクグラフは、グラフ理論の無閉路有効グラフの考えに基づいて設計されている

5.5.2 タスクグラフの制約#

タスクグラフは基本的に指定されたタスクとそのタスクの依存関係によって構築されますが、依存関係以外にも次の制約によりタスクグラフが制御される場合がある

  • 同一のタスクが実行対象タスクとして指定された場合

  • タスクが順序付けられている場合

  • ファイナライザータスクが設定されている場合

  • 同一のタスクが実行対象タスクとして指定された場合

    • Gradleでは、1つのタスクは1回しか実行されないことが保証されている
    • 同じタスクを複数指定していたり、複数のタスクから依存されているタスクがあったりしても、タスクグラフには1つしか存在しないように制御される
    • 例えば、greetタスクを2回実行する用にしても1回しか実行されない
    • gradle greet greet
  • タスクが順序付けられている場合

    • 明示的に実行対象として指定された場合のみ有効になる
    • タスクの順序付けについては次章で説明
  • ファイナライザータスクが設定されている場合

    • 順序付けのほかに、ファイナライザータスクという指定されたタスクの後に自動で必ず実行される特殊なタスクを定義できる
    • ファイナライザータスクを設定しているタスクを実行した場合には、タスクグラフの構築の際にファイナライザータスクも自動的に追加されることになります。

5.6 ファイル操作#

5.6.1 Gradle標準のファイル操作機能#

  • Gradleのファイルシステムの操作として次の機能を提供
    • ファイルの参照
    • ファイルのコピー
    • ファイルの削除
    • ディレクトリの作成

このうち、ファイルの参照とコピーに関しては提供されているAPIも多く、使い勝手がいい

5.6.2 単一ファイルの参照#

file()を使用する 通常はルートプロジェクトのディレクトリを起点とした相対パスか、Fileオブジェクトを指定する

File javaFile = file('src/main/java/Main.java')
  • ファイルパス以外からのファイル参照
    • file()はファイルパス以外にも、URL/URIオブジェクト、Callableインターフェースやクロージャなどを引数として、ファイルへの参照を取得できる
File index = null
URL url = new URL('file:/index.html')
index = file(url)
URI uri = new URI('file:/index.html')
index = file(uri)
import java.util.concurrent.Callable
index = file(new Callable<String>() {
String call() {
'/index.html'
}
})
index = file { '/index.html' }
  • PathValidationによるファイルの検証
File existDir = file('src/main/existDir', PathValidation.DIRECTORY)

PathValidationには、DIRECTORY,FILE,EXISTS,NONEが定義されている 指定しない場合はNONEが設定されている

5.6.3 ファイルコレクションによるファイルの参照#

複数のファイルを扱う場合には、files()を使用する ビルドスクリプトからfiles()を呼ぶことで、Fileの集合であるファイルコレクションを取得できる

ファイルコレクションはConfigurableFileCollectionインターフェースを実装していますが、操作するためのAPIは親のFileCollectionインターフェースで定義されていることから、このFileCollection インターフェースを中心に説明

  • FileCollection

    • Gradleには、ビルドスクリプト上の記述を簡潔にするためのインターフェースがいくつか用意されている
    • FileCollection はそのインターフェースの一つで、これによりファイルのコレクション操作を簡潔に行える
    • 使用頻度の高いと思われるものを中心に紹介
  • ファイルコレクションの取得

    • files()の引数はfile()が許容する型のオブジェクトを複数渡すようなかたちになります。
    • 引数に渡すパラメータには、ファイルパスのおじ列、File、URL、URIなどを組み合わせることもできる
FileCollection collection = files('file1.txt', 'file2.txt')
collection = files('file1.txt', new File('file2.txt'), new URL('file:/index.html'))
List fileList = [new File('file1.txt'), new File('file2.txt')]
collections = files(fileList)
collections = files(fileList as File[])
  • ファイルコレクションの変換
FileCollection collections = files('file1.txt', 'file2.txt', 'file3.txt')
// as 演算子による変換
List list = collections as List
Set set1 = collections as Set
File[] array = collections as File[]
// getFiles() のGroovy簡略記法
Set set2 = collections.files
// ファイルコレクションに含まれるファイルが1つの場合は、getSingleFile()が使える
File file = collections.singleFile
  • 遅延評価によるファイルコレクションの取得

    • Callableの場合遅延評価されます→実際に参照されたときに実行されるということ
  • ファイルコレクションの演算

    • ファイルコレクションの操作に加算と原産が利用できるらしい
  • ファイルコレクションのフィルタリング

    • ファイルコレクションに条件を指定することで、条件に一致したファイルだけにフィルタリングをすることができる
    • フィルタリングはfilter()にクロージャを渡します
FileCollection collections = files('file1.txt','file2.txt',new URL('file:/index.html'))
FileCollection textFiles = collections.filter{ collectionFile ->
collectionFile.name.endsWith .txt
}
assert textFiles.files.size() == 2
  • その他の機能
    • getAsPath() : ファイルコレクションに含まれているファイルのパスを取得できる
      • このメソッドはファイルごとのパス環境に応じたパス区切り文字で連携つして出力するため、javaコマンドにクラスパス形式でJARファイルのパスを渡すような場合に便利

5.6.4 ファイルツリーによるファイルの参照#

複数のファイルを木構造のファイルツリーとして扱う場合にはfileTree()を使用

FileTree sourceTree = fileTree('src')
  • FileTreeとは

    • FileTreeインターフェースもファイルコレクションを簡潔に操作するためのインターフェースの1つ
    • FileTreeインターフェースはFileCollectionインターフェースを継承しており、階層的にファイルを巡って処理するような機能が拡張されている
  • ファイルのマッチング

  • クロージャによるファイルツリーの取得

  • マップによるファイルツリーの取得

  • 条件に一致するファイルツリーの取得

  • ファイルツリーの探索

TODO: あとで纏める すぐ使える用にスニペットにする?

5.6.5 ファイルのコピー#

ファイルをコピーするには、デフォルトで提供しているCopy型タスクから、独自のタスクを作成する方法と、ビルドスクリプト上でcopy()を使う方法の2通りある

ここでは後者のcopy()を使用したファイルのコピーについて述べる copy()はクロージャを引数としていますが、実際のコピーに関する記述はクロージャ内でCopySpecというインターフェースを使用して行います

copy {
// CopySpec インターフェースのメソッドを使用する
}
  • CopySpecとは
    • ファイルのコピーに特化したGradleが提供するインターフェースの1つ
    • Copyタスクを始めとする、ファイル操作を行うタスクの内部ではCopySpecインターフェースを使用しており、ファイルのコピーを伴うタスクではこのインターフェースを通じて処理が行われる

TODO: 使用する際に詳細見直す テンプレートはクラス自動生成時に有用だと思った

5.6.6 ファイルの削除#

ファイルの削除jは、デフォルトで提供しているDelete型のタスクを使って独自のタスクを作成する方法と、ビルドファイル上でdelete()を使う方法の2通りがある

delete 'target.txt'
// 可変長なので複数指定できる
delete 'target1.txt','target2.txt','target3.txt'

5.6.7 ディレクトリの作成#

ディレクトリを作成するにはビルドスクリプト上でmkdir()を使用する

mkdir 'parent/child/grandchild'
mkdir '../outOfTheProject'
mkdir '/gradle-book/absolutePathDir'
  • Gradleでのファイルの作成方法
    • Gradleにはファイル作成のメソッドはありません。
    • Groovyによって拡張されたFileクラスで作成する
File newFile = file('newFile.txt')
newFile.write('ビルドスクリプトからファイルの生成を行います','UTF-8')

5.7 ロギング#

5.7.1 Gradleでのロギング#

GradleはSLF4Jを拡張したロガーを包含しています。 通常、Gradleを実行した際に出力されるログはこれによるもの

TODO: Gradle用に、QUIETとLIFECYCLEというログレベルが追加されているらしい。時間があるときに抑える

5.7.2 loggerプロパティを使用したロギング#

ビルドスクリプトでログ出力を定義する場合には、loggerプロパティを使用

logger.error = ''
logger.quiet = ''
logger.warn = ''
logger.lifecycle = ''
logger.info = ''
logger.debug = ''
  • 標準出力とloggerプロパティの使い分け
    • 標準出力は一時的に局所のログを出力したい場合にとどめ、
    • 恒久的にログを出力する場合はloggerプロパティを利用することをおすすめ

5.7.3 外部ロギングフレームワークとのマッピング#

TODO: 他のロギングAPIとの対比表を掲載。時間があればみる

5.7.4 ログレベルマッピングの変更#

標準エラーは通常GradleではERRORレベルにマッピングされていますが、運用上の都合からERRORではなくINFOレベルに引き下げて出力させたいといった場合に対応する方法

logging.captureStandardError LogLevel.INFO
println '標準出力'
System.err.println '標準エラー'

MEMO: あまり使わないかも

第6章 スクリプトファイルの記述#

Gradleのスクリプトファイルに記述された内容は実行時にGradleドメインオブジェクトに移譲される 記述したものが内部でどのクラスに異常されてどのように振る舞うのかを知っていると、 スクリプトファイルもより理解しやすくなります。 また、実際のプロジェクトでの多用な要求に対応するためには、タスクの詳細やマルチプロジェクトでのビルドスクリプト記述方法などについても知って置かなければなりません

6.1 スクリプトファイルの構造と共通要素#

6.1.1 スクリプトファイルの構造#

  • Gradleのスクリプトファイル

    • ステートメント
    • スクリプトブロック
  • ステートメント

    • ローカル変数やプロパティの設定、メソッドの実行など、
    • 一般的なプログラミングでのステートメントと同じ意味合いのもの
  • スクリプトブロック

    • Gradle独自の概念で、ある設定をおこなナウための領域を示すもの
    • 実際にはたんにクロージャを引数とするメソッドであり、そんなに難しいものではない
// ステートメント
xxx = ''
// スクリプトブロック
設定 {
// 設定のための領域
}

Groovyスクリプトがベースで有ることには変わりませんので、 通常のGroovyスクリプトと同様にクラスやクロージャを定義することもできる

class Descriptor {
String show() {
'*** これはGroovyスクリプトです。 ***'
}
}
println new Descriptor().show()

6.1.2 スクリプトファイルの共通要素#

変数は欠かせない共通要素 Gradleにはプロパティが手軽に使える仕組みが用意されているので、さまざまな場面で重宝するでしょう

4つの変数

名称概要使用可能なスクリプトファイル
ローカル変数宣言されたスコープで有効な変数すべてのスクリプトファイル
システムプロパティシステムの情報を保持するためのプロパティすべてのスクリプトファイル
拡張プロパティドメインオブジェクトを拡張するためのプロパティすべてのスクリプトファイル
プロジェクトプロパティプロジェクトで使用するためのプロパティビルドスクリプト
  • ローカル変数
def message = 'ローカル変数'
String stringMessage = 'ローカル変数'
// def でも 型指定でもいいよ

型宣言の無いものはGradleでは変数ではなく、移譲されるドメインオブジェクトのプロパティとみなす 変数として宣言するのではなく、オブジェクトにプロパティとして追加したい場合は、後述する拡張プロパティを使用する必要がある →ここイマイチ腑に落ちない

  • システムプロパティ
    • システムプロパティをコマンドライン引数で指定する場合は-D(—system-prop)を使用する
    • これだけならJavaと同じ
    • Gradleには他の指定方法もある
    • Gradleのプロパティファイル(gradle.properties)にsystemPropをプレフィックスとしてつけてプロパティを記述すると、システムプロパティとして識別される
gradle.properties
systemProp.message=Hello
  • 拡張プロパティ
    • Gradleには、スクリプトファイル上からドメインオブジェクトのプロパティを追加する仕組みとして、
    • 拡張プロパティというものがある
    • 拡張プロパティはextという名前で暗黙的に定義されており、使用にあたって特別な制約はない
    • 詳細は後述のGradleドメインオブジェクトExtraPropertiesExtensionで説明
    • 基本的に通常のキーバリュー方式でプロパティの追加と取得ができる
ext {
key1 = 'value1'
key2 = 'value2'
}
  • プロジェクトプロパティ
    • もう1つGradle固有のプロパティとして、プロジェクトプロパティというものがあります。
    • プロジェクトプロパティはビルドスクリプトで使用可能
    • ビルド対象のプロジェクトのプロパティとして利用
    • 拡張プロパティの仕組みを使用しているので、内部的には拡張プロパティとの違いはありません
    • 拡張プロパティと違うところは設定方法で、
      • プロジェクトプロパティはプロパティファイル、環境変数、コマンドライン引数のどれでも設定できる
    • プロパティファイルの場合は、<プロパティ名>=<値>と定義するだけで追加される
    • 環境変数の場合は、ORG_GRADLE_PROJECT_<プロパティ名>=<値>という形式で設定できる
    • コマンドライン引数の場合は、-P<プロパティ名>=<値>または、--project-prop <プロパティ名>=<値>で設定
    • システムプロパティの場合は、org.gradle.project.をプレフィクスでつけることで設定できる

TODO: プロジェクトプロパティのロード順を記載してくれている

6.1.3 スクリプトブロックとドメインオブジェクト#

スクリプトブロックはクロージャを引数とするメソッド

println 'デフォルトの依存関係:'
repositories.each { println it.name }
repositories {
mavenCentral()
}
println 'リポジトリ追加後:'
repositories.each { println it.name }
// このリポジトリブロックをGroovyのプログラム風に記述すると
def closure = { mavenCentral() }
this.reporitories(closure)

スクリプトファイルはGradleのドメインオブジェクトに移譲されています thisはまさにその移譲されたドメインオブジェクトを表しており、この例で言えば、thisはドメインオブジェクトであるProjectオブジェクトになる

6.1.4 主要なスクリプトブロック#

スクリプトファイルに記述するスクリプトブロックがドメインオブジェクトと関係していることがわかったと思いますので、 主要なスクリプトブロックと移譲されるドメインオブジェクトを列挙しておきます

スクリプトブロック概要ドメインオブジェクト
initscript初期化スクリプトのクラスパスの設定を記述するScriptHandler
buildscriptビルドスクリプトのクラスパスの設定を記述するScriptHandler
allprojects当該プロジェクトとそのすべてのサブプロジェクトに関する設定を記述するProject
subprojects当該プロジェクトのサブプロジェクトに対する設定を記述するProject
configurationsコンフィグレーションの設定を記述するConfigurationContainer
dependencies依存関係の解決のための設定を記述するDependencyHandler
repositoriesリポジトリの設定を記述するRepositoryHandler
artifactsビルド成果物(アーティファクト)を公開するための設定を記述ArtifactHandler

6.2 Gradleドメインオブジェクト#

  • 重要なドメインオブジェクトについて
    • Project
    • Task
    • Gradle
    • Settings
    • ExtensionAware
    • ExtraPropertiesExtension

6.2.1 Projectオブジェクト#

ProjectオブジェクトはGradleでの処理対象となる1つの領域を表すドメインオブジェクト ビルドスクリプトからProjectオブジェクトに移譲される

Projectオブジェクトはビルドスクリプト上のすべてのドメインを統括する、Gradleのなかで最も重要なドメインオブジェクト

  • Projectオブジェクトの構造

    • Gradleでなにかを自動化するときには、プロジェクトが必ず1つは存在する
    • マルチプロジェクトを扱うためにはコンポジットな構造である必要があるため、自分自身の親プロジェクト、起点となるルートプロジェクト、自分の下にぶら下がっているプロジェクトのリストを保持する用になっている
  • プロパティ

    • Projectオブジェクトはビルドに必要なすべての情報にアクセスできなければなりません。
    • そのためプロパティも多数存在する
プロパティ概要
nameプロジェクト名。論理名のため物理的なディレクトリと異なる場合もある
descriptionプロジェクトの説明
group
path
projectrDir
status
state
version
  • プロジェクト参照属性
    • 自分に該当するプロジェクトや、自身が属しているルートプロジェクトなど、プロジェクトを参照するためのプロパティ
プロパティ概要
project当該プロジェクトの参照を保持する
rootProjectルートプロジェクト参照を保持する。
parent上位プロジェクトの参照
childProjects子プロジェクトの参照をMapコレクションで保持
allprojects当該プロジェクトに含まれるすべてのプロジェクトの参照をSetコレクションで保持
subprojects当該プロジェクト配下のすべての参照をSetコレクションで保持

rootProjectはシングルプロジェクトの場合は自分自身、マルチプロジェクトの場合は、settings.gradleが置かれたディレクトリのプロジェクトとなる

  • コンテナタイプ属性

    • コンテナタイプのプロパティには、repositoriesやtasksなどビルドスクリプトで定義されたドメインを管理するためのものがある
    • これらの多くはスクリプトブロックが用意されており、スクリプトブロックによって設定を記述する
  • defaultTasksプロパティ

defaultTasks 'showProjectName'
project.description = 'デフォルトタスクの説明のためのプロジェクトです。'
task showProjectName doLast {
println project.name
}
task showDescription doLast {
println project.description
}
// 実行タスクが指定された場合は、デフォルトタスクは実行されない
// 複数のタスクを指定する場合は、
defaultTasks = ['showProjectName','showProjectDescription']
  • 主要なAPI

    • ビルドスクリプトを記述する際には、ProjectオブジェクトのAPIは欠かせません
    • プロパティと同様にAPIも用意されているので使用頻度の高いAPIに絞って紹介
  • プロジェクト参照API

def childInstance = project(':child')
childInstance.description = '子プロジェクトの説明を設定'
// パスとクロージャを引数とするオーバーロードメソッドを使用した場合
project(':child') {
description = '子プロジェクトの説明を設定'
}
  • タスク定義API
    • タスクを定義する際のAPIはtask()です
    • task()はオーバーロードメソッドになっていますが、よく利用されるのはタスク名を引数とするもので、これは本書ですでに何度も登場しています
task hello doLast {
println 'hello gradle world!'
}
  • コールバックAPI

    • Gradleがビルド処理を実行している最中にビルドフェーズ内からコールバックされるAPIとして、beforeEvaluate()afterEvaluate()の2つがある
    • beforeEvaluate()はプロジェクトの評価前ににコールバックされるため、ビルドスクリプトに記述した処理は参できない
      • →よって、プロジェクトの評価前に独自の処理を割り込ませるには、初期化スクリプトもしくは設定スクリプトに記述しておく必要がある
  • TODO: イマイチ使いみちがわからなかった

  • その他のAPI

    • javaexec(): Javaのメインクラスを実行する
    • exec(): 外部のOSコマンドを実行する
    • tarTree(): 指定されたTARファイルを基にしてFileTreeを生成する
    • zipTree(): 指定されたZIPファイルを基にしてFileTreeを生成する
  • この他にも5章で紹介したファイル操作やロギングAPIもあるし他にもある

6.2.2 Taskオブジェクト#

  • TaskオブジェクトはGradleでの対象作業を表すドメインオブジェクトで、ビルドスクリプトで記述されたタスクの定義がProjectオブジェクトを通じてTaskオブジェクトに移譲される

  • つまり、ビルドスクリプトでのタスクに関する記述は、Taskオブジェクトのプロパティへの設定やAPIの呼び出しになるということになります。

  • プロパティ

プロパティ概要
nameタスク名。定義名がそのまま設定される
descriptionタスクの説明。tasksタスクで説明が表示される
groupタスクが属するグループ。tasksタスクの出力時のタスクのグルーピングに使用される
pathタスクのパス。プロジェクトも含めた場合は「:」がセパレータとなる

nameとpathはタスク定義の際に自動的に決まるが、descriptionとgroupは名自適に設定する必要がある

その他のプロパティ

プロパティ概要
enabledタスクの実行可否情報を保持する
stateタスクの実行ステータスを保持する
inputsこのタスクの入力情報を保持する
outputsこのタスクの出力情報を保持する
dependsOnこのタスクが依存するタスクを保持する
mustRunAfter必ず先に実行されなければならないタスクを保持する
shouldRunAfter先に実行されなければならないタスクを保持する
finalizedByこのタスクの後に実行されるファイナライザータスクを保持する

これらのプロパティを使用することで、タスクの実行順を制御したり、状態によって実行をスキップさせたりできる

他に、直接プロパティを操作することはないが、acrionsという重要なプロパティがあるので触れておく acrionsプロパティは、Gradle内部での最小処理単位であるActionオブジェクトのリストになっており、タスクの定義で記述された作業をActionオブジェクトとして保持している このactionsプロパティ内のActionオブジェクトを順次実行することでタスクの処理は行われている

主要なAPI#

  • TaskオブジェクトのAPIは
    • タスクの処理のためのもの
    • タスクの実行に関するもの
    • プロパティのアクセサー
      • の3種類で占めている
API概要
doFirst()タスク処理をActionオブジェクトとしてactionsの先頭に追加
doLast()タスク処理をActionオブジェクトとしてactionsの最後に追加
leftShift()タスク処理をActionオブジェクトとしてactionsの最後に追加
deleteAllActions()actions内のActionオブジェクトを削除
task myActionTask {
doFirst {
println 'First'
}
}
// これらはGradleのDSL記法で
// Groovyで書くと以下になる
List<Action> actions = new ArrayList<Action>()
Closure doFirstAction = { println 'First' }
actions.add(0,doFirstAction)
Closure doLastAction = { println 'Last' }
actions.add(doLastAction)
actions.each{ action ->
actions.execute()
}

6.2.3 Gradleオブジェクト#

実行環境であるGradleを表すドメインオブジェクトで、初期化スクリプトから移譲される 他にも後述するProjectオブジェクトやSettingsオブジェクトがプロパティとして保持しており、すべてのスクリプトファイルからアクセスできる

println gradle.gradleVersion
  • プロパティ
プロパティ概要
gradleHomeDirGradleホームディレクトリを保持する
gradleUserHomeDirホームディレクトリを保持する
gradleVersion実行するGradleのバージョンを保持する
rootProjectルートプロジェクトを保持する
startParameterビルド実行時のパラメータを保持する
taskGraph当該ビルドのタスクグラフを保持する
  • 主要なAPI
    • イベントリスナーについて紹介
    • TODO: 処理順などまとめる

6.2.4 Settingsオブジェクト#

Settingsオブジェクトは設定スクリプトを表すドメインオブジェクトで、設定スクリプトから移譲される 設定スクリプトはマルチプロジェクトのためだけのものではない

  • プロパティ
    • Settingsオブジェクトは設定フェーズで生成されて使用されますが、
    • その段階で扱える情報は自分自身の情報を除くと、Gradleオブジェクトとルートプロジェクトの情報ぐらい

TODO: マルチプロジェクト作成時に再度確認しておく

6.2.5 ExtensionAwareオブジェクト#

ビルド実行時にGradleドメインオブジェクトを他のオブジェクトで拡張可能にするためのドメインオブジェクト

ExtensionAwareオブジェクトには、extensionsという拡張プロパティを格納するためのコンテナがあり、 Projectオブジェクト、TaskオブジェクトなどのGradleドメインオブジェクトの多くは、これに独自のプロパティ追加できる

TODO: メリットがいまいちつかめなかった

6.2.6 ExtraPropertiesExtensionオブジェクト#

ProjectオブジェクトやTaskオブジェクトなどで、extの名前で定義されている拡張プロパティの実態クラス ExtraPropertiesExtensionオブジェクトをはpropertiesというプロパティを持ち、そこにキーとバリューで任意のオブジェクトを保持 そして、has(),set(),get()の3つのAPIを提供し、propertiesに指定のキーが存在するかの確認、キーと値の設定や取得ができる

project.ext.property = 'extに追加下プロパティです。'
println '拡張プロパティの値 :' + project.property
project.ext['property'] = 'extに追加したプロパティです。'
println '拡張プロパティの値:' + project.ext['property']
project.ext {
prop1 = 'aaa'
prop2 = 'bbb'
}
println project.ext.prop1 + project.ext.prop2

6.3 タスクの記述#

6.3.1 タスクの定義方法#

  • ビルドフェーズ
    • 初期化フェーズ
    • 設定フェーズ
    • 実行フェーズ
task hello doLast {
println name + ': Hello Gradle World!'
}
// 設定のためのブロックとなるため設定フェーズで実行される
task hello2 {
println name + ': Hello Gradle World!'
}
// descriptionプロパティを出力する例
showDescription doLast {
println description
}
task showDescription.description = 'showDescriptionタスクです。'
// 順序に違和感があるかもしれないがこの順番で記述しないと行けない
  • Task型を使用した定義
    • Gradleにはあらかじめ特定のアクションを行うための汎用のタスクが数多く用意されている
    • それらは独自のタスクを定義する際に利用できる
    • 汎用タスクはGradle本体が提供する標準のものと、
    • プラグインを適用することで追加されるおのがある
タスク型概要
Copyターゲットとするディレクトリにファイルをコピーする
Delete指定されたファイルまたはディレクトリを削除する
Exec
JavaExec
Sync
Tar
Zip
// これはmyCopyというタスクをCopy型で定義するという記述
task myCopy(type: Copy) {
from 'original'
to 'target'
}
task myCopyExtension(type: Copy){
from 'original'
to 'target'
File newFile = file('original/newFile.txt')
doFirst {
println 'コピー元のファイルに書き込みします'
newFile.write('コピー用のファイルです。','UTF-8')
}
doLast {
File copied = file('original/newFile_copied.txt')
if (newFile.renameTo(copied)) {
println 'コピーが完了しました。'
} else {
println 'コピーできませんでした。'
}
}
}
  • 動的なタスクの定義
    • 複数のサーバーインスタンスをしよいうしている場合に、サーバーごとにIPアドレスを出力するタスクを作成したい場合
def instances = ['AppServer':'192.0.2.10','DBServer':'192.0.2.20','MailServer':'192.0.2.30']
instances.each { serverType, ipAddress ->
task "show${serverType}" doLast {
println ipAddress
}
}
// 便利な記載方法だが、Groovyの書き方なれてないと理解出来なさそう

6.3.2 依存関係の定義方法#

dependsOnというプロパティを使って定義ができる

doing.dependsOn todo
done.dependsOn doing
done.dependsOn doing, reviewing
done.dependsOn {
tasks.findAll { task -> task.name ==~ /.*ing/}
}

6.3.3 タスクルールの定義方法#

異なる設定やパラメータに対して同じような処理を指せる場合には、似た名前のタスクを必要な数だけ作成する必要がある そのような場合はタスクにルールをもたせることで簡潔に記述できる

javaのCleanの例

gradle cleanTest gradle cleanJar などと指定すると、それぞれのディレクトリのみ削除できる

これは、clean<タスク名>というルールを定義することで実現している

tasks.addRule('Pattern: show<TASKS_NAME>: Show task name.') { taskName ->
if (taskName.startsWith('show')) {
task(taskName) doLast {
println '*** ' + taskName + ' ***'
}
}
}

定型的な処理はこのようなルールを作成して定義しておくとよい!! MEMO: これは便利だと思う

6.3.4 タスクの制御#

  • タスクの制御方法
    • 処理内容の制御:組み込みタスクの処理内容は、タスクを再定義して処理を上書くことで既存の処理内容を変更できる
    • 実行可否の制御:タスクの事項条件を判定し、タスクの実行可否を制御できる
    • 実行順の制御:依存関係以外にも順序付けやファイナライザータスクの指定などで、タスクの実行順を制御できる

6.3.5 タスクの上書き#

タスクを上書きする場合、同じタスク名でoverwriteプロパティを有効にして処理を定義するだけ

apply plugin: 'java'
task assemble(overwrite: true) doLast {
println '上書きしました。'
}

6.3.6 タスクの条件実行#

条件によって実行するかしないか制御したい場合

onlyIf()を使用する

task specialTask doLast {
println '特別な処理を実行'
}
specialTask.onlyIf {
buildType == 'partial-build'
}

gradle -PbuildType=partial-build specialTask

6.3.7 タスクの順序付け#

mustRunAfterとshouldRunAfterの使い方 MEMO: あまり意識することなさそうなので割愛

6.3.8 ファイナライザータスク#

// 例外が起きても実行される
normalTask.finalizedBy finalizerTask

6.4 プラグインの記述#

6.4.1 Gradleにおけるプラグイン#

apply()を呼ぶことでプラグインが提供するタスクやプロパティが当該のビルド処理で利用できるようになる

6.4.2 プラグインの適用方法#

apply plugin: 'java'
project.apply(plugin:'java')

このように記述すると「このビルドスクリプトのProjectオブジェクトにJavaプラグインを適用させている」ということがわかる ‘java’はプラグインIDと呼ばれるもの 万が一プラグインIDがなければ、Pluginインターフェースを実装下クラスを指定することで、そのプラグインを適用できる

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

プラグインにはGradle標準以外にも、GithubやMaven Centralリポジトリなどで公開されているものがあります Gradleからみて外部にあるプラグインを利用するには、そのプラグインをダウンロードして読み込む必要があり、プラグインの適用方法も異なります

外部のプラグインを適用する場合は、buildscriptスクリプトブロックにプラグインのある場所とプラグインへの依存関係を設定し、通常のapply()でプラグインを適用

buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.hidetake: gradle-ssh-plugin:0.1.10'
}
}
apply plugin: 'ssh'
  • Gradle2.1 のプラグイン適用方法
    • 今後はこれが主流になるので覚えておきましょう
// Javaプラグイン
plugins {
id 'java'
}
plugins {
id 'org.gradle.java'
}
plugins {
id 'com.example.exampleplugin' version: '1.0'
}

6.5 マルチプロジェクトでのスクリプトファイルの記述#

6.5.1 レイアウトと記述方法のバリエーション#

TODO: 直近使わないので一旦飛ばす

第7章 依存関係の管理#

7.1 依存関係管理の目的#

Gradleを始めとする多くのビルドツールや統合開発環境において、依存関係とは、「そのビルドの外で作成された成果物への参照」のことを指す

  • 依存関係解決の自動化
    • 設定を書いておくと、任意の場所から必要なファイルをダウンロードまたはコピーしてきてプロジェクトに取り込んでくれる
  • 推移的な依存関係の管理
    • 必要な外部ファイルが、さらに別の外部ファイルを必要としていないか把握したり、管理したりできる
  • 依存関係の可視化
    • プロジェクトがどの外部ファイルのどのバージョンに依存しているか、かんたんに表示できる

これら3つの目的を達成するのが本章のテーマ

7.2 依存関係解決の自動化#

  • これら順を追って、ビルドスクリプトの依存関係の設定で使っている
    • configrations
    • dependencies
      • といった設定項目について紹介

7.2.1 コンフィグレーション#

多くのビルドツールでは依存関係をグループに分けて設定しており、Gradleもグループの概念がある

Mavenにはスコープという概念があり、すべての依存関係はcmpileスコープ、runtimeスコープといったグループに属すように定義することになっている GradleにはMavenのようにあらかじめ定義されているグループはないので、まずどのようなグループが必要化をビルドスクリプトで定義しなければいけない

この依存関係を分類するグループをGradleではコンフィグレーションと呼びます これを使って、依存関係を分類します。 これはMavenのスコープとほぼ同義です

configurations {
conf1
}

7.2.2 依存関係の定義#

コンフィグレーションを定義しtら、次はそのコンフィグレーションに割り当てる依存関係を定義

dependencies {
conf1 files("libs/sample-lib.jar")
}
  • 依存関係の指定方法

    • 外部モジュール依存関係
      • インターネット上のMavenリポジトリなどからファイルをダウンロードする。リポジトリの定義が別途必要
    • ファイル依存関係
      • ファイルシステム上のファイルを参照
    • プロジェクト依存関係
      • あるプロジェクトから別のプロジェクトの成果物を参照
    • GradleAPI依存関係
      • 現在使用しているGradleのAPIが含まれるライブラリファイルへの依存関係
    • ローカルGroovy依存関係
      • 現在使用しているGradleが同梱しているGroovyへの依存関係
  • 外部モジュール依存関係

    • おおよそ理解できているので割愛
  • ファイル依存関係

    • おおよそ理解できているので割愛
  • プロジェクト依存関係

dependencies {
compile project(':shared')
}

ルートプロジェクトの直下にあるsharedプロジェクトへの依存関係を宣言している プロジェクト階層は:区切り

  • GradleAPI依存関係
    • ビルドに使用しているGradleのAPIを参照するための依存関係
    • Gradleのプラグインやタスクを作成するときなど、Gradle自体を拡張するときに使う
dependencies {
conf1 gradleApi()
}
task showDeps doLast {
configuration.conf1.each {
println it.absolutePath
}
}
  • ローカルGroovy依存関係
    • ビルド似使用しているGradle似同梱されているGroovyを参照するための依存関係で、次の用にlocalGroovyを呼び出して指定
dependencies {
conf1 localGroovy()
}
task showDeps doLast {
configurations.conf1.each {
println it.absolutePath
}
}

7.2.3 コンフィグレーションの継承#

依存関係のコンフィグレーションは、ほかのコンフィグレーションを継承できる

configurations {
conf1
testConf1.extendsFrom conf1 // testConf1はconf1の依存関係も含む
}
dependencies {
conf1 group: 'org.codehaus.groovy', name: 'groovy-all', version: '2.3.1'
testConf1 group: 'junit', name: 'junit', version: '4.11'
}
task showDeps doLast {
configurations.testConf1.each {
println it.absolutePath
}
}
  • ★用途
    • テスト用のコンフィグレーションにプロダクト用のコンフィグレーションも含めたい
      • といった用途によく利用される

7.2.4 リポジトリ定義#

外部モジュールの依存関係は、依存関係を取得する外部リポジトリを設定しなくてはいけない

  • Mavenリポジトリ
repositories {
maven {
url 'http://'
}
}
  • Maven Central リポ維持鳥
    • よく利用される一部のリポジトリについては、URLを指定しなくてもリポジトリを指定できる
repositories {
mavenCentral()
}
// ローカルリポジトリも以下の様に記載できる
repositories {
mavenLocal()
}
// jcenter mavenリポジトリも
repositories {
jcenter()
}
// Ivyリポジトリも
// 使う予定はあまりないので一旦割愛
  • パスワードで保護されたリポジトリ
repositories {
maven {
url 'http://xxxx'
}
credentials {
username 'user'
password 'pass'
}
}

セキュリティ上、認証情報はビルドスクリプトに直書きするのではなく、どこかバージョン管理システム似コミットされない外部ファイルに記述してそれを参照するのがいい

gradle.propertiesに記述例を紹介

  • フラとディレクトリリポジトリ
    • ローカルファイルシステム上の単純なディレクトリをリポジトリとして指定できる
    • ファイルシステムで共有している場合だったり、ライブラリをバージョン管理システムにあげている場合だったり

7.2.5 動的バージョンと変更性モジュール#

configurations {
conf1
}
dependencies {
conf1 'org.slf4j:slf4j-api:1.7.+' // 1.7系のうち最新版を取得
conf1 'commons-cli:commons-cli:latest.integration' // 不安定版も含めて最新版を取得
conf1 'junit:junit:latest.release' // 不安定版の最新版を取得
}

7.3 推移的な依存関係の管理#

依存関係に指定したJARファイルなどが更に別のファイルを必要としている場合について 名自適に指定した依存関係から依存関係が再帰的に派生することを「推移的な依存関係」とよびます

7.3.1 競合の解決#

推移的な依存関係を管理する場合、避けて通れない問題が、依存関係のバージョン競合

  • 同じ依存のあるモジュールのバージョン違いをどのように解消するか

  • 2つ解決策がある

    • Newest戦略(デフォルト)
      • 取得した依存関係のバージョンが競合した場合、最も新しいバージョンの依存関係を使用
    • Fail戦略
      • 競合した場合は例外を発行してビルドを失敗させる
// Fail戦略を使う場合
configurations.testConf1 {
resolutionStrategy {
failOnVersionConflict() // Fail戦略を採用する
}
}

7.3.2 推移的な依存関係の除外設定#

// Fail戦略を使う場合
configurations.testConf1 {
resolutionStrategy {
failOnVersionConflict() // Fail戦略を採用する
}
}
dependencies {
conf1 group: ''
testConf1(group: '',name: '',version:''){
exclude module: 'groovy-all' // 依存関係から除外する!
}
}

7.3.3 使用するバージョンの強制#

  • バージョン指定して記載するってこと

  • forceで強制している?

  • TODO: 必要になった際に再確認

クライアントモジュール依存関係#

  • 用途

    • 依存しているモジュールのメタデータが誤っていたので上書きたい
    • 導入したモジュールに依存している別のライブラリがあった
  • あまり使わないとおもったので割愛

7.4 使用しているモジュールの調査#

ここでは、さらに依存関係を管理する目的の一つ、使用しているモジュールの調査方法を紹介

具体的には、Gradleが用意している依存関係のレポート用タスク、dependenciesタスクが本節のテーマ

gradel dependencies で実行できる

依存関係をグラフ化して表示することができる

7.5 キャッシュ制御とオフライン実行#

7.5.1 キャッシュ制御#

ビルドツールでは、一般的に一度解決した依存関係を再利用できるよう、ローカルマシンに依存関係をキャッシュする ただGradleのキャシュ管理は他のビルドツールに比べて複雑

  • 次に該当する場合、ネットワークへのアクセスが派生する場合がある
    • repositoriesブロックで、ネットワーク上にあるリポジトリが定義されている
    • 依存関係のうち、「外部モジュール依存関係」が使用されている

できるだけネットワークアクセスを削減できるように、チェックサムと一致するファイルがキャッシュにあれば、それを使用するような仕組みになっている

7.5.2 オフライン実行#

gradle --offline showDeps オフラインで、キャッシュを使ってビルドする キャッシュをつかってビルドできなければ、失敗する

  • 外部ネットワークとつながらない状態でビルドすることもできる
  • イントラネット内にリポジトリサーバーを立てる方法紹介

第3部[実践編]#

第8章 Gradle でのテスト#

Gradleのビルドタスクはプロダクションコードのコンパイルだけでなく、テストコードの粉ピルとテストの実行も行う Gradleを導入してビルドを行うだけで、テストを自動化できる環境が手に入ることになる テストを自動化するにあたって、どのような要件があり、Gradleでどう解決できるかを把握しておく必要がある

8.1 テストの自動化とビルドツール#

8.1.1 テストを取り巻く状況#

8.1.2 自動テスト似おけるビルドツールの要件#

CI導入が一般的になったことで今やCIツールとの親和性は必須の要件

  • 特に以下の3点は重要
    • 環境の差異が吸収できること
    • 特定の範囲でテストを実行できること
    • スローテストを軽減できる仕組みをもっていること
      • 実行に非常に時間がかかるテストは「スローテスト」と呼ばれ、
      • 開発プロジェクトを妨げる問題として、しばしば取り上げられるようになった
      • ビルドツールがあれば暫定対応が容易にできるでしょう

8.2 Gradleによるアプローチ#

Gradleは前述のビルドツールの要件をすべて満たしている かんたんにかけるので紹介します

8.2.1 環境差異の吸収#

  • ビルドツールなら環境差異を吸収する仕組みを持っていることはあたりまえだが、

  • Gradleならシンプルにかける

  • 方法は2つ

    • 環境ごとにファイルを用意する
    • 1ファイル内でグループ化して切り替える
// dev
ext.app_url = 'localhost'
// pro
ext.app_url = 'xxx.xxx.xxx.xxx'
// build.gradle
apply from: "environments/${env}/env.gradle"
task showURL << {
println "App Server: ${app_url}"
}
env.conf
environments {
dev {
app_url = 'localhost'
}
production {
app_url = 'xxx.xxx.xxx.xxx'
}
}
// build.gradle
task showURL << {
def url = new File('config/env.conf').toURL()
def config = new ConfigSlurper("$env").parse(url)
println 'App Server: ' + config.app_url
}

8.2.2 特定の範囲でテストを実行できること#

  • 種類
    • パターンマッチングで特定して実行する
    • テスティングフレームワークの機能を利用して実行する
    • ソースセット単位で実行する
apply plugin: 'java'
sourceCompatibility = 1.7
targetCompatibility = 1.7
def defaultEncoding = 'UTF-8'
[compileJava, compileTestJava]*.options*.encoding = defaultEncoding
repositories {
mavenCentral()
}
dependencies {
testCompile 'junit:junit:4.11'
}
test {
filter {
includeTestsMatching '*UT'
}
reports.html.destination = file("${reports.html.destination}/unit")
reports.junitXml.destination = file("${reports.junitXml.destination}/unit")
}
task integrationTest(type: Test) {
filter {
includeTestsMatching '*IT'
}
reports.html.destination = file("${reports.html.destination}/integration")
reports.junitXml.destination = file("${reports.junitXml.destination}/integration")
}

TODO: 残りの説明割愛、必要になったら見返す

8.2.3 スローテスト対策#

第9章 Android プロジェクトでの適用#

第10章 統合開発環境(IDE)との連携#

第4部発展編#

第11章 Jenkins との連携#

第12章 アーカイブの作成とファイルの公開#

第13章 エキスパートへの道#

第14章 ほかのビルドツールからの移行#

付録 Gradleリファレンス#

Gradle徹底入門 次世代ビルドツールによる自動化基盤の構築
https://tutttuwi.github.io/posts/2020-06_gradle徹底入門_次世代ビルドツールによる自動化基盤の構築/
Author
Tomoaki Tsutsui
Published at
2020-06-13
License
CC BY-NC-SA 4.0