GeekFactory

int128.hatenablog.com

Gradle タスクの直列実行を Collection.inject() で書いてみる

非同期処理の直列実行を Array.reduce() で書いてみる - GeekFactory と同じことを Gradle (Groovy) でやってみます。

Gradle で複数のタスクの依存関係を定義するケースを考えます。Task.dependsOn を使って複数のタスクを指定した場合、タスクの順序は保証されません。例えば、下記のように3つのタスクに対して依存関係を定義してみます。

task somethingA << { println 'A' }
task somethingC << { println 'C' }
task somethingB << { println 'B' }
task something {
  dependsOn somethingA, somethingC, somethingB
}

something タスクを実行すると下記のようになります。dependsOn で指定したものとは異なる順序で実行されています。なお、環境やバージョンによっては結果が違うかもしれません。

:somethingA
A
:somethingB
B
:somethingC
C
:something

タスクの直列化

では、複数のタスクを順序付けして実行するにはどうすればよいでしょうか。タスク間に依存関係のチェーンを定義してみましょう。

task somethingA << { println 'A' }
task somethingC << { println 'C' }
task somethingB << { println 'B' }
task something {}

somethingC.dependsOn somethingA
somethingB.dependsOn somethingC
something.dependsOn somethingB

something タスクを実行すると下記のようになります。意図した順序で実行されていることが分かります。

:somethingA
A
:somethingC
C
:somethingB
B
:something

一般化

タスクのリストに一般化してみましょう。タスクの実行順序を設定する configureSequentialDependencies() 関数を書いてみます。

/**
 * Configure task dependencies to be executed sequentially.
 * 
 * @param top top of chain
 * @param tasks
 */
void configureSequentialDependencies(Task top, List<Task> tasks) {
  tasks.reverse().inject(top) { x, y ->
    x.dependsOn y
    y
  }
}

configureSequentialDependencies(something, [somethingA, somethingC, somethingB])

これで任意のタスクに対して実行順序制約を設定できるようになりました。

スクリプトに書いた順にタスクを実行したいケースは意外とよくあるので、きっと役に立つと思います。