第15章 タスク詳解

In the introductory tutorial (6章ビルドスクリプトの基本) you learned how to create simple tasks. You also learned how to add additional behavior to these tasks later on, and you learned how to create dependencies between tasks. This was all about simple tasks, but Gradle takes the concept of tasks further. Gradle supports enhanced tasks, which are tasks that have their own properties and methods. This is really different from what you are used to with Ant targets. Such enhanced tasks are either provided by you or built into Gradle.

6章ビルドスクリプトの基本」の入門的なチュートリアルでは、簡単なタスクの作り方や、後からタスクにアクションを追加する方法について学びました。 さらに、タスク間の依存関係を定義する方法についても学びました。 単純なタスクについてはこんなところですが、Gradleはタスクという概念をもっと進化させています。 拡張タスク、つまり自身のプロパティやメソッドを持ったタスクを使うことができるのです。 これは、今まで使われてきたAntのターゲットとは全く異なる概念です。 拡張タスクは、Gradleがデフォルトで用意しているものもありますし、自分自身で新たに作成することもできます。

15.1. タスクの定義Defining tasks

We have already seen how to define tasks using a keyword style in 6章ビルドスクリプトの基本. There are a few variations on this style, which you may need to use in certain situations. For example, the keyword style does not work in expressions.

6章ビルドスクリプトの基本」で、キーワードを使ったタスク定義を紹介しましたが、タスクの定義方法は他にも少しあります。ときには、それらの方法が必要になることもあるでしょう。たとえば、式の中ではキーワード形式の定義方法を使うことができません。

例15.1 タスクを定義する

build.gradle

task(hello) << {
    println "hello"
}

task(copy, type: Copy) {
    from(file('srcDir'))
    into(buildDir)
}

You can also use strings for the task names:

タスク名に文字列を使うこともできます。

例15.2 タスクを定義する - タスク名に文字列を使用

build.gradle

task('hello') <<
{
    println "hello"
}

task('copy', type: Copy) {
    from(file('srcDir'))
    into(buildDir)
}

There is an alternative syntax for defining tasks, which you may prefer to use:

他にもいくつかシンタックスが用意されています。もしかすると、これらのシンタックスの方が好みに合うという人もいるかもしれません。

例15.3 その他のタスク定義方法

build.gradle

tasks.create(name: 'hello') << {
    println "hello"
}

tasks.create(name: 'copy', type: Copy) {
    from(file('srcDir'))
    into(buildDir)
}

Here we add tasks to the tasks collection. Have a look at TaskContainer for more variations of the create() method.

この例では、tasksコレクションにタスクを追加しています。create()メソッドのバリエーションについてはTaskContainerをご参照ください。

15.2. タスクを配置するLocating tasks

You often need to locate the tasks that you have defined in the build file, for example, to configure them or use them for dependencies. There are a number of ways of doing this. Firstly, each task is available as a property of the project, using the task name as the property name:

ビルドファイルから、定義済みのタスクを探して取得したい、というケースがよくあります。例えば、既存のタスクの設定を変更したり、依存関係を定義するために参照したいといった場面です。タスクを取得する方法はたくさんありますが、まずはプロジェクトのプロパティとしてアクセスする方法を見てみましょう。タスク名がプロパティ名として使用できます。

例15.4 タスクにプロパティとしてアクセスする

build.gradle

task hello

println hello.name
println project.hello.name

Tasks are also available through the tasks collection.

tasksコレクションからタスクを持ってくることもできます。

例15.5 tasksコレクションからタスクにアクセスする

build.gradle

task hello

println tasks.hello.name
println tasks['hello'].name

You can access tasks from any project using the task's path using the tasks.getByPath() method. You can call the getByPath() method with a task name, or a relative path, or an absolute path.

tasks.getByPath()を使えば、あらゆるプロジェクトのタスクにアクセスできます。getByPath()にはタスク名のほか、タスクの相対パスや絶対パスを渡すことが可能です。

例15.6 パスを使ってタスクにアクセスする

build.gradle

project(':projectA') {
    task hello
}

task hello

println tasks.getByPath('hello').path
println tasks.getByPath(':hello').path
println tasks.getByPath('projectA:hello').path
println tasks.getByPath(':projectA:hello').path

gradle -q hello の出力

> gradle -q hello
:hello
:hello
:projectA:hello
:projectA:hello

Have a look at TaskContainer for more options for locating tasks.

そのほかの方法については、TaskContainerをご参照ください。

15.3. タスクの設定を変更するConfiguring tasks

As an example, let's look at the Copy task provided by Gradle. To create a Copy task for your build, you can declare in your build script:

例として、Gradleに用意されているCopyタスクを見てみましょう。Copyタスクを自分のビルドで作成するには、ビルドスクリプトで次のように宣言します。

例15.7 copyタスクの作成

build.gradle

task myCopy(type: Copy)

This creates a copy task with no default behavior. The task can be configured using its API (see Copy). The following examples show several different ways to achieve the same configuration.

作成されたコピータスクには、デフォルトでは何の動作も設定されていません。 タスクは、タスクのAPI(Copy参照)を使って設定することができます。 次のいくつかの例は、どれも同じ設定を行うものです。

Just to be clear, realize that the name of this task is “myCopy”, but it is of typeCopy”. You can have multiple tasks of the same type, but with different names. You'll find this gives you a lot of power to implement cross-cutting concerns across all tasks of a particular type.

例15.8 タスクの設定 - 様々な方法

build.gradle

Copy myCopy = task(myCopy, type: Copy)
myCopy.from 'resources'
myCopy.into 'target'
myCopy.include('**/*.txt', '**/*.xml', '**/*.properties')

This is similar to the way we would configure objects in Java. You have to repeat the context (myCopy) in the configuration statement every time. This is a redundancy and not very nice to read.

これは、普段私たちがJavaオブジェクトを設定するのと同じ方法で設定する方法です。この方法では、設定処理を呼び出すたびに同じコンテキスト(myCopy)を何度も書く必要があります。これは冗長だし、あまり可読性もよくありません。

There is another way of configuring a task. It also preserves the context and it is arguably the most readable. It is usually our favorite.

タスクの設定には別の方法があります。この方法でも同様にコンテキストは保持されますし、おそらく最も可読性の高い方法です。私たちは、普段この方法を好んで使っています。

例15.9 タスクの設定 - クロージャの使用

build.gradle

task myCopy(type: Copy)

myCopy {
   from 'resources'
   into 'target'
   include('**/*.txt', '**/*.xml', '**/*.properties')
}

This works for any task. Line 3 of the example is just a shortcut for the tasks.getByName() method. It is important to note that if you pass a closure to the getByName() method, this closure is applied to configure the task, not when the task executes.

この方法は、あらゆるタスクで使用できます。3行目のコードは、tasks.getByName()の単なるショートカットです。大事なことは、getByName()メソッドにクロージャを渡すと、そのクロージャがタスクが実行されるときではなく、設定されるときに適用されるという点です。

You can also use a configuration closure when you define a task.

また、タスクを定義するときに、同時に設定クロージャを使うこともできます。

例15.10 クロージャを伴うタスク定義

build.gradle

task copy(type: Copy) {
   from 'resources'
   into 'target'
   include('**/*.txt', '**/*.xml', '**/*.properties')
}

Don't forget about the build phases

A task has both configuration and actions. When using the <<, you are simply using a shortcut to define an action. Code defined in the configuration section of your task will get executed during the configuration phase of the build regardless of what task was targeted. See 56章ビルドのライフサイクル for more details about the build lifecycle.

15.4. タスクに依存関係を追加するAdding dependencies to a task

There are several ways you can define the dependencies of a task. In 「タスクの依存関係Task dependencies you were introduced to defining dependencies using task names. Task names can refer to tasks in the same project as the task, or to tasks in other projects. To refer to a task in another project, you prefix the name of the task with the path of the project it belongs to. The following is an example which adds a dependency from projectA:taskX to projectB:taskY:

タスクの依存関係を定義する方法はいくつかあります。「タスクの依存関係Task dependenciesでは、タスク名を使って依存関係を定義する方法を紹介しました。タスク名を使うと、同じプロジェクトのタスク、または別のプロジェクトのタスクも参照できます。別のプロジェクトのタスクを参照するには、タスク名に、そのタスクが属しているプロジェクトのパスをプレフィックスとして付けてください。次の例では、projectA:taskXからprojectB:taskYへの依存関係を定義しています。

例15.11 別プロジェクトのタスクとの依存関係を定義する

build.gradle

project('projectA') {
    task taskX(dependsOn: ':projectB:taskY') << {
        println 'taskX'
    }
}

project('projectB') {
    task taskY << {
        println 'taskY'
    }
}

gradle -q taskX の出力

> gradle -q taskX
taskY
taskX

Instead of using a task name, you can define a dependency using a Task object, as shown in this example:

タスク名を使う代わりに、次の例のように、Taskオブジェクトを使って依存関係を定義することも出来ます。

例15.12 taskオブジェクトを使った依存関係定義

build.gradle

task taskX << {
    println 'taskX'
}

task taskY << {
    println 'taskY'
}

taskX.dependsOn taskY

gradle -q taskX の出力

> gradle -q taskX
taskY
taskX

For more advanced uses, you can define a task dependency using a closure. When evaluated, the closure is passed the task whose dependencies are being calculated. The closure should return a single Task or collection of Task objects, which are then treated as dependencies of the task. The following example adds a dependency from taskX to all the tasks in the project whose name starts with lib:

より上級ユーザー向けの方法として、クロージャを使って依存関係を定義することが出来ます。評価フェーズ時に、そのクロージャは、依存関係を算出中のタスクに渡されます。そのクロージャは、一つのTaskオブジェクトかTaskオブジェクトのコレクションを返さなければなりません。返されたタスクが依存タスクとして設定されます。次の例では、taskXから、名前がlibで始まる全てのタスクへの依存関係を設定しています。

例15.13 クロージャを使った依存関係定義

build.gradle

task taskX << {
    println 'taskX'
}

taskX.dependsOn {
    tasks.findAll { task -> task.name.startsWith('lib') }
}

task lib1 << {
    println 'lib1'
}

task lib2 << {
    println 'lib2'
}

task notALib << {
    println 'notALib'
}

gradle -q taskX の出力

> gradle -q taskX
lib1
lib2
taskX

For more information about task dependencies, see the Task API.

さらにタスクの依存関係に関する情報を得るには、Task APIを参照してください。

15.5. Ordering tasks

Task ordering is an incubating feature. Please be aware that this feature may change in later Gradle versions.

In some cases it is useful to control the order in which 2 tasks will execute, without introducing an explicit dependency between those tasks. The primary difference between a task ordering and a task dependency is that an ordering rule does not influence which tasks will be executed, only the order in which they will be executed.

Task ordering can be useful in a number of scenarios:

  • Enforce sequential ordering of tasks: eg. 'build' never runs before 'clean'.
  • Run build validations early in the build: eg. validate I have the correct credentials before starting the work for a release build.
  • Get feedback faster by running quick verification tasks before long verification tasks: eg. unit tests should run before integration tests.
  • A task that aggregates the results of all tasks of a particular type: eg. test report task combines the outputs of all executed test tasks.

There are two ordering rules available: “must run after” and “should run after”.

When you use the “must run after” ordering rule you specify that taskB must always run after taskA, whenever both taskA and taskB will be run. This is expressed as taskB.mustRunAfter(taskA). The “should run after” ordering rule is similar but less strict as it will be ignored in two situations. Firstly if using that rule introduces an ordering cycle. Secondly when using parallel execution and all dependencies of a task have been satisfied apart from the “should run after” task, then this task will be run regardless of whether its “should run after” dependencies have been run or not. You should use “should run after” where the ordering is helpful but not strictly required.

With these rules present it is still possible to execute taskA without taskB and vice-versa.

例15.14 Adding a 'must run after' task ordering

build.gradle

task taskX << {
    println 'taskX'
}
task taskY << {
    println 'taskY'
}
taskY.mustRunAfter taskX

gradle -q taskY taskX の出力

> gradle -q taskY taskX
taskX
taskY

例15.15 Adding a 'should run after' task ordering

build.gradle

task taskX << {
    println 'taskX'
}
task taskY << {
    println 'taskY'
}
taskY.shouldRunAfter taskX

gradle -q taskY taskX の出力

> gradle -q taskY taskX
taskX
taskY

In the examples above, it is still possible to execute taskY without causing taskX to run:

例15.16 Task ordering does not imply task execution

gradle -q taskY の出力

> gradle -q taskY
taskY

To specify a “must run after” or “should run after” ordering between 2 tasks, you use the Task.mustRunAfter() and Task.shouldRunAfter() methods. These methods accept a task instance, a task name or any other input accepted by Task.dependsOn().

Note that “B.mustRunAfter(A)” or “B.shouldRunAfter(A)” does not imply any execution dependency between the tasks:

  • It is possible to execute tasks A and B independently. The ordering rule only has an effect when both tasks are scheduled for execution.
  • When run with --continue, it is possible for B to execute in the event that A fails.

As mentioned before, the “should run after” ordering rule will be ignored if it introduces an ordering cycle:

例15.17 A 'should run after' task ordering is ignored if it introduces an ordering cycle

build.gradle

task taskX << {
    println 'taskX'
}
task taskY << {
    println 'taskY'
}
task taskZ << {
    println 'taskZ'
}
taskX.dependsOn taskY
taskY.dependsOn taskZ
taskZ.shouldRunAfter taskX

gradle -q taskX の出力

> gradle -q taskX
taskZ
taskY
taskX

15.6. タスクに説明書きを追加するAdding a description to a task

You can add a description to your task. This description is displayed when executing gradle tasks.

定義したタスクに、説明書きを追加できます。追加した説明は、たとえばgradle tasksを実行したときなどに表示されます。

例15.18 タスクに説明書きを追加する

build.gradle

task copy(type: Copy) {
   description 'Copies the resource directory to the target directory.'
   from 'resources'
   into 'target'
   include('**/*.txt', '**/*.xml', '**/*.properties')
}

15.7. タスクの置き換えReplacing tasks

Sometimes you want to replace a task. For example, if you want to exchange a task added by the Java plugin with a custom task of a different type. You can achieve this with:

ときには、タスクを置き換えたくなることがあります。例えば、Javaプラグインによって追加されたタスクを、別のタイプのカスタムタスクに入れ替えたいといった場合です。これは、次のようにして実現できます。

例15.19 タスクの上書き

build.gradle

task copy(type: Copy)

task copy(overwrite: true) << {
    println('I am the new one.')
}

gradle -q copy の出力

> gradle -q copy
I am the new one.

This will replace a task of type Copy with the task you've defined, because it uses the same name. When you define the new task, you have to set the overwrite property to true. Otherwise Gradle throws an exception, saying that a task with that name already exists.

ここでは、Copyタイプのタスクを、シンプルな別のタスクに置き換えています。タスクを作成するときに、overwriteプロパティをtrueにセットしなければなりません。そうしないと、Gradleは例外を投げ、すでに同名のタスクが定義済みだと警告してきます。

15.8. タスクをスキップするSkipping tasks

Gradle offers multiple ways to skip the execution of a task.

Gradleは、タスクの実行をスキップする方法を複数用意しています。

15.8.1. 述語を使うUsing a predicate

You can use the onlyIf() method to attach a predicate to a task. The task's actions are only executed if the predicate evaluates to true. You implement the predicate as a closure. The closure is passed the task as a parameter, and should return true if the task should execute and false if the task should be skipped. The predicate is evaluated just before the task is due to be executed.

onlyIf()メソッドを使って、タスクに述語を付けることができます。タスクは、付加された述語がtrueと評価されたときのみ実行されます。述語は、一つのクロージャとして実装します。そのクロージャには、対象のタスクが引数に渡されます。タスクが実行されるべきならこのクロージャはtrueを返し、スキップされるべきならfalseを返さなければなりません。述語は、タスクが実行される直前に評価されます。

例15.20 述語でタスクをスキップ

build.gradle

task hello << {
    println 'hello world'
}

hello.onlyIf { !project.hasProperty('skipHello') }

gradle hello -PskipHello の出力

> gradle hello -PskipHello
:hello SKIPPED

BUILD SUCCESSFUL

Total time: 1 secs

15.8.2. StopExecutionExceptionを使うUsing StopExecutionException

If the logic for skipping a task can't be expressed with predicate, you can use the StopExecutionException. If this exception is thrown by an action, the further execution of this action as well as the execution of any following action of this task is skipped. The build continues with executing the next task.

タスクスキップのルールが述語で表現できない場合、StopExecutionExceptionを使うことができます。この例外がタスクのアクションから投げられたら、実行中のアクション、およびそのタスクの残りのアクションはすべてスキップされます。ビルド自体は継続されるので、次のタスクが実行されることになります。

例15.21 StopExecutionExceptionでタスクをスキップ

build.gradle

task compile << {
    println 'We are doing the compile.'
}

compile.doFirst {
    // Here you would put arbitrary conditions in real life.
    // But this is used in an integration test so we want defined behavior.
    if (true) { throw new StopExecutionException() }
}
task myTask(dependsOn: 'compile') << {
   println 'I am not affected'
}

gradle -q myTask の出力

> gradle -q myTask
I am not affected

This feature is helpful if you work with tasks provided by Gradle. It allows you to add conditional execution of the built-in actions of such a task. [12]

この機能は、Gradleが標準提供しているタスクが絡んでいるときに役に立ちます。このようなビルドインのタスクを、条件付きで実行させることができるのです。 [13]

15.8.3. タスクの有効化と無効化Enabling and disabling tasks

Every task has an enabled flag which defaults to true. Setting it to false prevents the execution of any of the task's actions.

すべてのタスクは、enabledフラグを持っており、デフォルトではtrueに設定されています。このフラグをfalseにすると、そのタスクのすべてのアクションが実行されなくなります。

例15.22 タスクの有効化と無効化

build.gradle

task disableMe << {
    println 'This should not be printed if the task is disabled.'
}
disableMe.enabled = false

gradle disableMe の出力

> gradle disableMe
:disableMe SKIPPED

BUILD SUCCESSFUL

Total time: 1 secs

15.9. 更新されていないタスクをスキップするSkipping tasks that are up-to-date

If you are using one of the tasks that come with Gradle, such as a task added by the Java plugin, you might have noticed that Gradle will skip tasks that are up-to-date. This behaviour is also available for your tasks, not just for built-in tasks.

JavaプラグインのようなGradleが提供しているタスクを使ったとき、Gradleが未更新(UP-TO-DATE)のタスクをスキップすることに気づかれたかもしれません。この動作は、ビルドインのタスクだけでなく、任意のタスクに組み込むことができます。

15.9.1. タスクの入力物と出力物を宣言するDeclaring a task's inputs and outputs

Let's have a look at an example. Here our task generates several output files from a source XML file. Let's run it a couple of times.

一つ例を見てみましょう。ここでは、定義したタスクが、XMLのソースファイルを元にいくつかのファイルを出力しています。このタスクを、何度か実行してみます。

例15.23 生成タスク

build.gradle

task transform {
    ext.srcFile = file('mountains.xml')
    ext.destDir = new File(buildDir, 'generated')
    doLast {
        println "Transforming source file."
        destDir.mkdirs()
        def mountains = new XmlParser().parse(srcFile)
        mountains.mountain.each { mountain ->
            def name = mountain.name[0].text()
            def height = mountain.height[0].text()
            def destFile = new File(destDir, "${name}.txt")
            destFile.text = "$name -> ${height}\n"
        }
    }
}

gradle transform の出力

> gradle transform
:transform
Transforming source file.

gradle transform の出力

> gradle transform
:transform
Transforming source file.

Notice that Gradle executes this task a second time, and does not skip the task even though nothing has changed. Our example task was defined using an action closure. Gradle has no idea what the closure does and cannot automatically figure out whether the task is up-to-date or not. To use Gradle's up-to-date checking, you need to declare the inputs and outputs of the task.

タスクを2回目に実行したとき、なにも変更されていないにもかかわらず、タスクの実行がスキップされなかったことに注目してください。この例にあるタスクでは、ひとつのクロージャを使ってアクションを定義していますが、Gradleにはこのクロージャが何をしているか知る手段がなく、タスクがUP-TO-DATEなのかどうかを自動的に決定することができないのです。GradleのUP-TO-DATEチェックを使うには、タスクの入力と出力を宣言する必要があります。

Each task has an inputs and outputs property, which you use to declare the inputs and outputs of the task. Below, we have changed our example to declare that it takes the source XML file as an input and produces output to a destination directory. Let's run it a couple of times.

すべてのタスクにはinputsプロパティとoutputsプロパティがあります。これが入力と出力を宣言するために使うプロパティです。次の例では、先ほどの例を修正し、このタスクがXMLのソースファイルを入力とし、あるディレクトリに出力ファイルを生成することを宣言しています。

例15.24 タスクの入力と出力を宣言

build.gradle

task transform {
    ext.srcFile = file('mountains.xml')
    ext.destDir = new File(buildDir, 'generated')
    inputs.file srcFile
    outputs.dir destDir
    doLast {
        println "Transforming source file."
        destDir.mkdirs()
        def mountains = new XmlParser().parse(srcFile)
        mountains.mountain.each { mountain ->
            def name = mountain.name[0].text()
            def height = mountain.height[0].text()
            def destFile = new File(destDir, "${name}.txt")
            destFile.text = "$name -> ${height}\n"
        }
    }
}

gradle transform の出力

> gradle transform
:transform
Transforming source file.

gradle transform の出力

> gradle transform
:transform UP-TO-DATE

Now, Gradle knows which files to check to determine whether the task is up-to-date or not.

これで、GradleはタスクがUP-TO-DATEなのかどうかを決定するため、どのファイルをチェックするべきか知ることができます。

The task's inputs property is of type TaskInputs. The task's outputs property is of type TaskOutputs.

タスクのinputsプロパティはTaskInputs型、outputsプロパティはTaskOutputs型です。

A task with no defined outputs will never be considered up-to-date. For scenarios where the outputs of a task are not files, or for more complex scenarios, the TaskOutputs.upToDateWhen() method allows you to calculate programmatically if the tasks outputs should be considered up to date.

A task with only outputs defined will be considered up-to-date if those outputs are unchanged since the previous build.

15.9.2. どのように動作するのか?How does it work?

Before a task is executed for the first time, Gradle takes a snapshot of the inputs. This snapshot contains the set of input files and a hash of the contents of each file. Gradle then executes the task. If the task completes successfully, Gradle takes a snapshot of the outputs. This snapshot contains the set of output files and a hash of the contents of each file. Gradle persists both snapshots for the next time the task is executed.

タスクが初回に実行されるとき、実行前にGradleは入力物のスナップショットをとります。このスナップショットには、入力ファイルのセットと、それぞれのファイル内容のハッシュが含まれています。Gradleは、その後、タスクを実行します。もしタスクが正常に終了すれば、Gradleは出力物のスナップショットを保存します。このスナップショットには、やはり出力ファイルのセットと、それぞれのファイル内容のハッシュが含まれていて、Gradleが、出力ディレクトリ内でファイルが作成または変更、削除されたことを検知するために使用されます。Gradleは、次回そのタスクが実行されたときのために、双方のスナップショットを保管します。

Each time after that, before the task is executed, Gradle takes a new snapshot of the inputs and outputs. If the new snapshots are the same as the previous snapshots, Gradle assumes that the outputs are up to date and skips the task. If they are not the same, Gradle executes the task. Gradle persists both snapshots for the next time the task is executed.

この後は、タスクが実行される前に毎回、入力物と出力物のスナップショットを新しく作成します。 もし、新しいスナップショットが、前回のスナップショットと同じなら、Gradleは出力がUP-TO-DATEだと見なし、タスクをスキップします。 スナップショットが異なっていれば、Gradleはタスクを実行し、次回実行されるときのためにスナップショットを保存しなおします。

Note that if a task has an output directory specified, any files added to that directory since the last time it was executed are ignored and will NOT cause the task to be out of date. This is so unrelated tasks may share an output directory without interfering with each other. If this is not the behaviour you want for some reason, consider using TaskOutputs.upToDateWhen()

15.10. タスクルールTask rules

Sometimes you want to have a task whose behavior depends on a large or infinite number value range of parameters. A very nice and expressive way to provide such tasks are task rules:

ときには、広範囲、または無限大な範囲のパラメータに応じた動作を行うタスクを定義したくなることがあります。このようなタスクを定義するための、表現力のあるよい方法がタスクルールです。

例15.25 タスクルール

build.gradle

tasks.addRule("Pattern: ping<ID>") { String taskName ->
    if (taskName.startsWith("ping")) {
        task(taskName) << {
            println "Pinging: " + (taskName - 'ping')
        }
    }
}

gradle -q pingServer1 の出力

> gradle -q pingServer1
Pinging: Server1

The String parameter is used as a description for the rule, which is shown with gradle tasks.

文字列が引数に渡されていますが、これはルールの説明として使用されます。例えば、gradle tasksを実行したときなどに表示されます。

Rules not only used when calling tasks from the command line. You can also create dependsOn relations on rule based tasks:

ルールは、ただコマンドラインからのタスク呼び出しにのみ使えるものではありません。dependsOnによる依存関係定義のときも、ルールベースのタスクを使うことができます。

例15.26 ルールベース・タスクの依存関係

build.gradle

tasks.addRule("Pattern: ping<ID>") { String taskName ->
    if (taskName.startsWith("ping")) {
        task(taskName) << {
            println "Pinging: " + (taskName - 'ping')
        }
    }
}

task groupPing {
    dependsOn pingServer1, pingServer2
}

gradle -q groupPing の出力

> gradle -q groupPing
Pinging: Server1
Pinging: Server2

If you run “gradle -q tasks” you won't find a task named “pingServer1” or “pingServer2”, but this script is executing logic based on the request to run those tasks.

15.11. Finalizer tasks

Finalizers tasks are an incubating feature (see 「試験的 Incubating).

Finalizer tasks are automatically added to the task graph when the finalized task is scheduled to run.

例15.27 Adding a task finalizer

build.gradle

task taskX << {
    println 'taskX'
}
task taskY << {
    println 'taskY'
}

taskX.finalizedBy taskY

gradle -q taskX の出力

> gradle -q taskX
taskX
taskY

Finalizer tasks will be executed even if the finalized task fails.

例15.28 Task finalizer for a failing task

build.gradle

task taskX << {
    println 'taskX'
    throw new RuntimeException()
}
task taskY << {
    println 'taskY'
}

taskX.finalizedBy taskY

gradle -q taskX の出力

> gradle -q taskX
taskX
taskY

On the other hand, finalizer tasks are not executed if the finalized task didn't do any work, for example if it is considered up to date or if a dependent task fails.

Finalizer tasks are useful in situations where the build creates a resource that has to be cleaned up regardless of the build failing or succeeding. An example of such a resource is a web container that is started before an integration test task and which should be always shut down, even if some of the tests fail.

To specify a finalizer task you use the Task.finalizedBy() method. This method accepts a task instance, a task name, or any other input accepted by Task.dependsOn().

15.12. まとめSummary

If you are coming from Ant, an enhanced Gradle task like Copy seems like a cross between an Ant target and an Ant task. Although Ant's tasks and targets are really different entities, Gradle combines these notions into a single entity. Simple Gradle tasks are like Ant's targets, but enhanced Gradle tasks also include aspects of Ant tasks. All of Gradle's tasks share a common API and you can create dependencies between them. These tasks are much easier to configure than an Ant task. They make full use of the type system, and are more expressive and easier to maintain.

以前にAntを使ったことがあれば、Copyのような拡張タスクは、Antのターゲットとタスクの間をとったようなものに見えるでしょう。 Antのタスクとターゲットは実際には異なるエンティティですが、Gradleはこれらの記法を1つのエンティティにまとめています。 単純なGradleのタスクはAntのターゲットのようなものだし、拡張タスクはAntタスクの性質を含んでいます。 すべてのGradleタスクは、同じのAPIを共有していて、タスク間の依存関係を定義することができます。 このため、GradleのタスクはAntタスクに比べて、より設定しやすいものになっているでしょう。 Gradleのタスクは、型システムをフル活用しており、より表現力豊かで、メンテナンス性もよくなっています。



[12] You might be wondering why there is neither an import for the StopExecutionException nor do we access it via its fully qualified name. The reason is, that Gradle adds a set of default imports to your script. These imports are customizable (see 付録E IDE対応の現状と、IDEによらない開発支援Existing IDE Support and how to cope without it).

[13] なぜimport文も完全修飾名も使用せずStopExecutionExceptionにアクセスできているのか不思議に思われたかもしれません。これは、Gradleがデフォルトでスクリプトにいくつかのimportを追加しているからです。このimportのセットはカスタマイズ可能です(付録E IDE対応の現状と、IDEによらない開発支援Existing IDE Support and how to cope without it参照)。