第13章 ビルドスクリプトの記述

This chapter looks at some of the details of writing a build script.

本章では、ビルドスクリプトの記述についてもう少し詳しく見ていきます。

13.1. Gradleビルド言語The Gradle build language

Gradle provides a domain specific language, or DSL, for describing builds. This build language is based on Groovy, with some additions to make it easier to describe a build.

Gradleは、ビルドシステムを記述するためのドメイン特化言語(DSL)を提供します。 このビルド用言語は、Groovyをベースに、ビルドシステムの記述を簡単にするための機能をいくつか追加したものです。

A build script can contain any Groovy language element. [9] Gradle assumes that each build script is encoded using UTF-8.

13.2. プロジェクトAPIThe Project API

In the tutorial in 7章Javaクイックスタート we used, for example, the apply() method. Where does this method come from? We said earlier that the build script defines a project in Gradle. For each project in the build, Gradle creates an object of type Project and associates this Project object with the build script. As the build script executes, it configures this Project object:

例えば、7章Javaクイックスタートのチュートリアルで使用したapply()メソッド、このメソッドはどこから来たのでしょうか。まず、前述のようにビルドスクリプトはGradleのプロジェクトを定義します。 ビルドに含まれるプロジェクトそれぞれに対し、Project型のインスタンスが一つ作られ、ビルドスクリプトと関連づけられます。ビルドが実行されると、このプロジェクト・インスタンスは以下のように振る舞います。

ビルドスクリプトのリファレンスを見たいときはGetting help writing build scripts

Don't forget that your build script is simply Groovy code that drives the Gradle API. And the Project interface is your starting point for accessing everything in the Gradle API. So, if you're wondering what 'tags' are available in your build script, you can start with the documentation for the Project interface.

ビルドスクリプトは、GradleのAPIを呼び出しているだけの単なるGroovyスクリプトだということを忘れないでください。Projectインターフェースが、GradleのAPIを呼び出すときのスタートポイントです。なので、ビルドスクリプトでどんな「文言」が使えるか分からないときはProjectインターフェースのドキュメントを見ることから始めるといいでしょう。

  • Any method you call in your build script which is not defined in the build script, is delegated to the Project object.

    ビルドスクリプトで呼び出されたメソッドのうち、そのスクリプトで定義されていないものはProjectオブジェクトに委譲されます。

  • Any property you access in your build script, which is not defined in the build script, is delegated to the Project object.

    ビルドスクリプトでのプロパティアクセスも、そのスクリプトで定義されていないプロパティについてはProjectオブジェクトに委譲されます。

Let's try this out and try to access the name property of the Project object.

プロジェクトオブジェクトのnameプロパティにアクセスして試してみましょう。

例13.1 Projectオブジェクトへのアクセス

build.gradle

println name
println project.name

gradle -q check の出力

> gradle -q check
projectApi
projectApi

Both println statements print out the same property. The first uses auto-delegation to the Project object, for properties not defined in the build script. The other statement uses the project property available to any build script, which returns the associated Project object. Only if you define a property or a method which has the same name as a member of the Project object, would you need to use the project property.

どちらのprintlnも出力結果は同じです。最初のprintlnは、ビルドスクリプトで定義されていないプロパティへのアクセスを、暗黙のうちにプロジェクトオブジェクトに委譲しています。もう一方の例では、プロジェクトオブジェクトを返すprojectプロパティを使って、nameにアクセスしています。projectプロパティには、ビルドスクリプトのどこからでもアクセスできます。プロジェクトオブジェクトのプロパティやメソッドと同名のものをビルドスクリプトに定義している場合は、projectプロパティからアクセスすることになるでしょう。

13.2.1. 標準のプロジェクトプロパティStandard project properties

The Project object provides some standard properties, which are available in your build script. The following table lists a few of the commonly used ones.

プロジェクトオブジェクトは標準でいくつかのプロパティを提供しており、ビルドスクリプトでこれらのプロパティにアクセスできます。次の表によく使うプロパティを少しですが載せてみました。

表13.1 プロジェクトプロパティProject Properties

プロパティ名Name Type デフォルト値Default Value
project Project ProjectインスタンスThe Project instance
name String プロジェクトディレクトリの名前The name of the project directory.
path String プロジェクトの絶対パスThe absolute path of the project.
description String プロジェクトの説明A description for the project.
projectDir File ビルドスクリプトのあるディレクトリThe directory containing the build script.
buildDir File projectDir/build
group Object 未設定unspecified
version Object 未設定unspecified
ant AntBuilder AntBuilderインスタンスAn AntBuilder instance

13.3. スクリプトAPIThe Script API

When Gradle executes a script, it compiles the script into a class which implements Script. This means that all of the properties and methods declared by the Script interface are available in your script.

ビルドスクリプトが実行されるときは、スクリプトはScriptを実装したクラスにコンパイルされます。つまり、ビルドスクリプトではScriptインターフェースで宣言されているプロパティとメソッドを全て使うことができるということです。

13.4. 変数の宣言 Declaring variables

There are two kinds of variables that can be declared in a build script: local variables and extra properties.

ビルドスクリプトでは、二つの方法で変数を宣言できます。ローカル変数と拡張プロパティです。

13.4.1. ローカル変数 Local variables

Local variables are declared with the def keyword. They are only visible in the scope where they have been declared. Local variables are a feature of the underlying Groovy language.

ローカル変数は、defキーワードで宣言する変数です。変数のスコープは、変数が宣言されている場所に制限されます。なお、ローカル変数はGroovy言語に依る機能です。

例13.2 ローカル変数を使用する

build.gradle

def dest = "dest"

task copy(type: Copy) {
    from "source"
    into dest
}

13.4.2. 拡張プロパティ Extra properties

All enhanced objects in Gradle's domain model can hold extra user-defined properties. This includes, but is not limited to, projects, tasks, and source sets. Extra properties can be added, read and set via the owning object's ext property. Alternatively, an ext block can be used to add multiple properties at once.

Gradleのドメインモデルを構成する全ての拡張オブジェクトには、ユーザー定義のプロパティ、拡張プロパティを新たに追加することができます。 拡張プロパティを追加できるオブジェクトには、projects、tasks、source setsを始め、様々なオブジェクトがあります。 拡張プロパティをセットしたり読み込んだりするには、対象オブジェクトのextプロパティを使用して下さい。また、extブロックを使って複数のプロパティを一気に追加することもできます。

例13.3 拡張プロパティを使用する

build.gradle

apply plugin: "java"

ext {
    springVersion = "3.1.0.RELEASE"
    emailNotification = "build@master.org"
}

sourceSets.all { ext.purpose = null }

sourceSets {
    main {
        purpose = "production"
    }
    test {
        purpose = "test"
    }
    plugin {
        purpose = "production"
    }
}

task printProperties << {
    println springVersion
    println emailNotification
    sourceSets.matching { it.purpose == "production" }.each { println it.name }
}

gradle -q printProperties の出力

> gradle -q printProperties
3.1.0.RELEASE
build@master.org
main
plugin

In this example, an ext block adds two extra properties to the project object. Additionally, a property named purpose is added to each source set by setting ext.purpose to null (null is a permissible value). Once the properties have been added, they can be read and set like predefined properties.

この例では、extブロックで二つの拡張プロパティをprojectオブジェクトに追加しています。 さらに、ext.purposenullをセットすることで(nullでも構いません)、全てのソースセットにpurposeという拡張プロパティを追加しています。 一度プロパティが追加されれば、定義済みのプロパティと同じように読み込んだり書き込んだりすることができるようになります。

By requiring special syntax for adding a property, Gradle can fail fast when an attempt is made to set a (predefined or extra) property but the property is misspelled or does not exist. Extra properties can be accessed from anywhere their owning object can be accessed, giving them a wider scope than local variables. Extra properties on a project are visible from its subprojects.

For further details on extra properties and their API, see the ExtraPropertiesExtension class in the API documentation.

13.5. Groovyの基本 Some Groovy basics

Groovy provides plenty of features for creating DSLs, and the Gradle build language takes advantage of these. Understanding how the build language works will help you when you write your build script, and in particular, when you start to write custom plugins and tasks.

GroovyにはDSLを作るための機能が豊富に用意されていて、Gradleもその長所を活用しています。Gradleビルド言語がどういう仕組みで動いているか理解すれば、ビルドスクリプトを書くのに、特にカスタムプラグインやタスクを作り始めたときには役に立つはずです。

13.5.1. Groovy JDK

Groovy adds lots of useful methods to the standard Java classes. For example, Iterable gets an each method, which iterates over the elements of the Iterable:

Groovyは、たくさんの便利なメソッドをJavaの標準クラスに追加しています。たとえば、Iterableにはeachというメソッドが追加されていて、要素を走査するときに次のように書くことができます。

例13.4 Groovy JDKのメソッド

build.gradle

// Iterable gets an each() method
configurations.runtime.each { File f -> println f }

Have a look at http://groovy.codehaus.org/groovy-jdk/ for more details.

詳細はhttp://groovy.codehaus.org/groovy-jdk/をご参照ください。

13.5.2. プロパティのアクセサProperty accessors

Groovy automatically converts a property reference into a call to the appropriate getter or setter method.

Groovyは、プロパティ参照を自動的にゲッター/セッターメソッドの呼び出しに変換してくれます。

例13.5 プロパティアクセサ

build.gradle

// Using a getter method
println project.buildDir
println getProject().getBuildDir()

// Using a setter method
project.buildDir = 'target'
getProject().setBuildDir('target')

13.5.3. メソッド呼び出し時のカッコを省略できるOptional parentheses on method calls

Parentheses are optional for method calls.

Groovyではメソッド呼び出しのカッコは省略できます。

例13.6 カッコなしのメソッド呼び出し

build.gradle

test.systemProperty 'some.prop', 'value'
test.systemProperty('some.prop', 'value')

13.5.4. リストリテラル、マップリテラルList and map literals

Groovy provides some shortcuts for defining List and Map instances. Both kinds of literals are straightforward, but map literals have some interesting twists.

Groovyでは、ListMapのインスタンスを作るときにショートカット記法が使えます。

For instance, the “apply” method (where you typically apply plugins) actually takes a map parameter. However, when you have a line like “apply plugin:'java'”, you aren't actually using a map literal, you're actually using “named parameters”, which have almost exactly the same syntax as a map literal (without the wrapping brackets). That named parameter list gets converted to a map when the method is called, but it doesn't start out as a map.

例13.7 マップリテラル、リストリテラル

build.gradle

// List literal
test.includes = ['org/gradle/api/**', 'org/gradle/internal/**']

List<String> list = new ArrayList<String>()
list.add('org/gradle/api/**')
list.add('org/gradle/internal/**')
test.includes = list

// Map literal.
Map<String, String> map = [key1:'value1', key2: 'value2']

// Groovy will coerce named arguments
// into a single map argument
apply plugin: 'java'

13.5.5. メソッド引数の最後にクロージャを使うClosures as the last parameter in a method

The Gradle DSL uses closures in many places. You can find out more about closures here. When the last parameter of a method is a closure, you can place the closure after the method call:

GradleのDSLでは、クロージャ(詳細はこちら)を多用します。Groovyでは、メソッドの最後の引数がクロージャになっている場合、そのメソッドをクロージャをつけて呼び出すことができます。

例13.8 メソッドのクロージャ引数

build.gradle

repositories {
    println "in a closure"
}
repositories() { println "in a closure" }
repositories({ println "in a closure" })

13.5.6. クロージャのdelegateオブジェクトClosure delegate

Each closure has a delegate object, which Groovy uses to look up variable and method references which are not local variables or parameters of the closure. Gradle uses this for configuration closures, where the delegate object is set to the object to be configured.

すべてのクロージャは、delegateオブジェクトを持っています。クロージャ内では、(クロージャ引数やローカル変数以外の)変数やメソッドはdelegateオブジェクトから検索されます。Gradleの設定用クロージャでは、delegateオブジェクトに設定対象のオブジェクトがセットされています。

例13.9 クロージャのdelegate

build.gradle

dependencies {
    assert delegate == project.dependencies
    testCompile('junit:junit:4.11')
    delegate.testCompile('junit:junit:4.11')
}



[9] Any language element except for statement labels.