sbt を理解するための sbt 自体のソースの読み方

sbt でわからないことがある場合、だいたい

というような選択肢になります。*1
それで、英語が微妙な自分の場合、結局ソースをみることが多いわけです。それで、今までそれなりにsbtのソースを読んでいるので、自分なりに思った

  • sbtのソースのどこから読めばいいのか?
  • 全体としてどういう構成になっているのか?

をちょっと書いてみようかと思います。


(そろそろsbt0.12が出るはずですが)このblog書いている時点の安定版であるsbt0.11.2を基準にして書きます。まぁこれから書くようなことは、sbt0.12になってもあまり変わらないはずです。

1. まず Keys.scala 読め

https://github.com/sbt/sbt/blob/v0.11.2/main/Keys.scala
とにかくひたすら読みましょう。自分でもこのページ何度読んだか数えきれないくらいです。
sbt *2では、ほぼすべての設定を、 SettingKey や TaskKey 、 InputKey などの型で定義するわけですが、*3 Keys.scala にそれらの定義がまとめて書いてあります。例えばよく使う以下のようなものも全部ここにあります

上記に上げたような一般的によくユーザー側で設定するようなものだけではなく、以下のようなコマンド*4 もすべてここに定義されています

そして、SettingKeysもTaskKeyもすべて、applyのメソッドの第二引数にその説明を記述できるようになっています。そしてほとんどのKeyについて説明がかいてあるのでとにかくまずこれを読みましょう。(wikiに説明が書いてないものでも、こっちにならば書いてある場合もありえるので)

勿論単に説明を読んだりするだけなら sbt のコンソール上から以下のようにhelp使えば

> help scala-version

The version of Scala used for building.

表示されます。が(自分で他のKeyに依存する独自のSettingを書いたり、pluginを書いたりする場合は特に) それぞれのKeyが実際にどういう型で、どのようにScalaソースコード上で定義されているのかをある程度意識して理解しておいたほうがよいので、とにかくこのKeys.scalaを読むことをおすすめします。

2. Defaults.scala

https://github.com/sbt/sbt/blob/v0.11.2/main/Defaults.scala

Keys.scalaはKeyが定義されているだけですが、実際にそのKeyの設定のデフォルトが定義されているのがこのファイルです。たとえば、デフォルトではScalaのメインのソースは src/main/scala に置きますが、これも Defaults.scala で定義されていて以下のような仕組みで決まっています。

こんな感じで、複数のKeyが依存して最終的に src/main/scala という値が決まってます。もちろん、この依存関係を全部完全に把握している必要はないですが、sbt plugin を読んだり書いたりする場合も、このような感じで、どうやって相互のKeyの依存の仕組みを定義するのか、されているのか、を理解する必要があるので。以下、例をいくつか上げておきます

3. sbt 自体のプロジェクトのフォルダ構成が、デフォルト値と異なっている!

理由は知りませんが、なぜか変えてあります。デフォルトではメインのソースをそれぞれのディレクトリの下の src/main/scala に置くわけですが、sbt の場合はそれぞれのプロジェクトの直下がメインのソースのディレクトリを置く場所になっています!これ知らないで読むとわけわからないと思うので注意しましょう。sbt0.13から通常のsrc/main/scalaに置く構成に変わったようです(0.12はそのまま)

また、sbtの場合、 "src/test/scala" に置くような普通のtestもある程度ありますが、それ以外の scriptedPlugin を使ったテストのほうが圧倒的に大量にあります ( "src/sbt-test/" 以下に置く)
scriptedPluginについてはこれを読みましょう
(当たり前ですが)これもscriptedPluginのフォルダ構成や大まかな仕組みわかってないと、なんでこんなネストしたフォルダ構成になっているのか意味が分からないと思うので、もしsbtのテストコードを理解しようと思った場合には、まずscriptedPluginを最低限理解しないといけまん

まとめ?

他にも重要なファイルありますが、(たとえば、コアとなる色々なclassやメソッドが定義されているStructure.scala) Structure.scala はちょっと難易度高いので、まずは上記に書いた Keys.scala と Defaults.scala を読むといいのではないかと思います。

*1:ちなみに現時点ではグーグルさんで検索してもあまりいい情報見つからない可能性が高いので、グーグルさんで検索に時間かけるならwikiをまず見たほうがいいです

*2:0.10以降

*3:これ読みましょう

*4:ここでのcommandは、sbtのCommandの型の意味で言っているのではなく、なにかアクションを起こすようなものという程度の意味で