タスク定義の << には注意しよう

突然ですが、みなさんは

task hello << {
    println 'Hello, world.'
}
task hello {
    println 'Hello, world.'
}
の違いがわかりますか?

上記の違いはたった2文字 << だけです。
ところが、このたった2文字で 全く意味が変わってしまうので注意しましょう。

この違いというのが

クロージャ ( {...} の中の処理 ) の実行タイミング
です。
前者のように << をつけてタスクを定義した場合は hello タスクの実行時に呼び出されます。
ところが、後者の場合 hello タスクのインスタンス生成時に呼び出されてしまいます。
私は この違いで思いっきり はまってしまいました。
実行されるはずのないタスクがいきなり最初に実行されてしまうのですから...

前者と後者で 実際 何が違うのかと言うと...
まず、前者の場合。
タスク名と クロージャとの間にある << は Groovy ではおなじみの leftShift メソッド を表す演算子ですので

task('hello')        // Project#task(String)
hello.leftShift {
    println 'Hello, world.'
};
と同じです。
更に Task#leftShift(Closure) は内部的に Task#doLast(Closure) を呼び出すため
task('hello')        // Project#task(String)
hello.doLast {
    println 'Hello, world.'
}
とも同じです。
という訳で、<< をつけると クロージャは hello タスク実行時の最後に呼び出されるのです。

後者は << がついていませんので、

task('hello', {                 // Project#task(String, Closure)
    println 'Hello, world.'
})
と同じです。更に、
task('hello')
hello.configure({
    println 'Hello, world.'
})
ともほぼ同じですので、クロージャは タスクの生成後、直ぐに そのタスクの設定のために 実行されるのです。

つまり...

  • タスクの 処理 内容を定義する場合は << が必要
  • タスクの 設定 内容を定義する場合は << は不要
と言うことになります。

後者は Copy タスク や Zip タスク等で

task copySomething(type: Copy) {
    from sourcePath
    into destPath
}
といった感じで タスクを設定するのに使います。
ちなみに これに << をつけてしまうと from や into の設定より Copy タスクが先に実行されてしまいエラーになってしまうので注意しましょう。