(sbt標準にあったらしい?ので)下の方に追記したよ!
すごく簡単に説明すると、以下のような定義があったときに
lazy val a = project lazy val b = project lazy val c = project
"a"と"b"の"compile"だけを"並列に"実行したい、みたいな。(cのcompileは実行したくない)
なぜかsbt標準にも、外部のsbt pluginでも存在していない気がする・・・?(あったら教えてください) なので、それを書いたのを説明する記事
入社数日にしてsbt職人業務をしてしまった。ていうか、なぜこの機能標準でsbtにないんだ。ちゃんと探せばsbt pluginとしてころがってないかな。
— Kenji Yoshida (@xuwei_k) 2019年2月6日
(どういう機能なのか?の説明書くのすらだるいので、明日以降に気が向いたら書く、かもしれない)
もう少しポイントを説明すると
- "並列" ではなく "直列" でいいなら sbt a/compile b/compile とだけすればいい
- "指定されたものだけ" ではなく "(多少無駄があっても)とにかく全部実行してもいい" なら、単純に sbt compile でいい*1
- 指定するパターンが数え上げられるほどごく少数なら、事前にそれ用のrootプロジェクト作ってaggregateなどでもいい?(もしくはaggregate部分をsbt起動時に -D で引数渡したもので無理やりフィルターとか?)
などがあります。compileで説明しましたが、実際仕事で遭遇したのは、docker:publishでした。 (それなりな容量なので個々のpublish時間かかるし、色々な意味で無駄にpublishしたくない、みたいな理由で?)
とりあえず下に現状作ったものを貼っておきます。(一部?)マクロ使わない版のメソッド使ったけど、他の書き方で書けるのか?は謎。
parserの部分は、以前書いたこれ
val allProjects = Seq[ProjectReference](a, b, c)
の部分を明示的に列挙してるのがダサいので、自動で取得できないかな?と思ったけど、今sbtにその機能あるのかないのかよくわからなかったので、一旦諦めました。
いずれにせよ、その列挙の部分は、tab補完用のparserでしか使ってないので、別に必ずしもなくてもいい部分です。
肝心の並列化は、sbt自体が並列化可能なものは勝手にやるので、taskを組み立てているだけで、こちらとしては明示的に並列にする処理は何も書いていません。
個々のprojectのtaskをSeq[Initialize[Task[T]]]
として取得したものを、joinというメソッドで Initialize[Task[Seq[T]]]
という型に変えているのが、ある意味最大のポイントです。
Scala標準のFutureのsequenctとか、scalaz.Traverse (HaskellのTraversable Functor) のsequenceみたいなことをして、型の入れ子を逆にして、複数のTaskを一つのTaskにしています。
https://github.com/sbt/sbt/blob/v1.2.8/main-settings/src/main/scala/sbt/Structure.scala#L463
追記: sbt標準にallという名前で存在しているらしい・・・!?
all command の出番ですかねhttps://t.co/hWFJQYoz6v
— seraphr (@seraphr) February 7, 2019
*1:明示的にroot定義しなければ、自動でsbtが生成する暗黙のrootでa, b, cは全部aggregateされているので