sbt の Task で、メインの任意のメソッドを実行してその結果を取得する

だいぶニッチな需要な気がしますが、つまり

  • メインのコードやライブラリに依存した処理なので、project/ 以下のScalaファイルに色々書くだけでは無理*1
  • sbtのデフォルトでは、(task経由で)mainメソッドを実行させることはできても、その結果を直接Scalaのオブジェクトとして取得できない(そもそもmainには戻り値ないし、取得できても成功か失敗かのsys.exitの値くらいだし)

という感じです。まぁとにかくサンプル書いたので貼っておきます。もっと短く書ける方法あったら教えて下さい

あと、sbtは0.12.3(つまりScala2.9.2)なのに、mainはScala2.10など、sbt側と本体側でScalaのversionが異なる場合は、Scala標準ライブラリのクラス(SeqとかTupleとかその他全部)を使うと、受け渡しの際にバイナリ互換性が保証されないわけで、基本的にはArrayやStringなど、単にJavaのクラスを使ったほうがよいです。*2

以前、

というやりとりがありましたが、

「そういえば、testLoaderはデフォルトでKeyがあるけど、mainのClassLoader取得できないんだろうか?」

「testLoaderの定義場所
https://github.com/sbt/sbt/blob/v0.12.3-RC1/main/Defaults.scala#L278
https://github.com/sbt/sbt/blob/v0.12.3-RC1/testing/TestFramework.scala#L202-L210
を適当に読んで真似たらできた 」

という感じです。ClassLoaderさえ取得出来れば、あとはリフレクション経由で呼び出すだけです。

ちなみに、作ったあとに気が付きましたが、わざわざmainClassLoaderというKey作らずに、testLoaderのKeyを使っても普通は呼び出せるはずですが、まぁ「mainだけに依存した処理」なのに、testのコードまでコンパイルするのは無駄なので、一応意味はあるかな・・・(´・ω・`)

*1:色々書いてもいいけど、そうすると処理が重複するので避けたい

*2:sbt0.13がでればScala2.10の場合それ考えなくていいのだけれど・・・