sbtマルチプロジェクトの設定


Qiita::Teamに一度書いたものを、外部公開用に書き直し。まぁ、社内に限定しなくちゃいけない内容じゃないし。

- 依存関係のないプロジェクトを複数まとめたい
- タスクの呼び出しをプロジェクトごとに行えるようにしたい
- 独自タスクを追加したい
- https://github.com/myahal/scalaMultiTest

## 手順

SBTプロジェクトを作る。最終的にはこんな感じのディレクトリ構造になる

```
└── scalaMultiTest
    ├── README.md
    ├── build.sbt
    ├── project
    │   ├── TaskTest.scala
    │   ├── build.properties
    │   └── plugins.sbt
    ├── project1
    │   └── src
    │       └── main
    │           └── scala-2.11
    │               └── Proj1.scala
    └── project2
        └── src
            └── main
                └── scala-2.11
                    └── Proj2.scala
```

使用したいプラグインとかはproject/plugins.sbtに記述している。今回はassemblyを使いたいので、以下の行を追加。

```
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.13.0")
```

sbtに独自タスクを追加する場合はprojectの下にscalaプログラムとして追加した。今回はproject/TestTask.scala。
実際のプロジェクトではassemblyした結果を起動スクリプトなどと一緒にアーカイブしてS3にプッシュしたりするけど、今回はテストスクリプトで。呼び出し時にパラメータを二つ渡す。

```
object TaskTest {
  def push(name:String, key:String): Unit = {
    println("TaskTest push called")
    println(name)
    println(key)
  }
}
```

sbtの設定はscalaMultiTest/build.sbtに記述。

```
import sbt._

lazy val pushName = settingKey[String]("test name")
lazy val pushKey = settingKey[String]("test key")

lazy val push = taskKey[Unit]("push zip to S3 for CodeDeploy Test")

lazy val commonSettings = Seq (
  version := "1.0",
  scalaVersion := "2.11.7",
    push := {
    TaskTest.push(pushName.value, pushKey.value)
  }
)

lazy val root = (project in file(".")).
  aggregate(proj1, proj2).
  settings(
    name := "multitest",
    pushName := "push name is root",
    pushKey := "push key is root"
  )

lazy val proj1 = (project in file("project1")).
    settings(commonSettings: _*).
    settings (
      name := "project1",
      pushName := "push name is project1",
      pushKey := "push key is project1"
    )


lazy val proj2 = (project in file("project2")).
  settings(commonSettings: _*).
  settings(
    name := "project2",
    pushName := "push name is project2",
    pushKey := "push key is project2"
  )

```

すべてのプロジェクトに共通する設定はcommonSettingsに記述。

```
lazy val commonSettings = Seq (
  version := "1.0",
  scalaVersion := "2.11.7",
    push := {
    TaskTest.push(pushName.value, pushKey.value)
  }
)
```

これを個別のプロジェクトで読み込んでいる。
個別プロジェクトは、共通設定の読み込みと、カスタムタスクのためのパラメータ設定などを行っている。

```
lazy val proj1 = (project in file("project1")).
    settings(commonSettings: _*).
    settings (
      name := "project1",
      pushName := "push name is project1",
      pushKey := "push key is project1"
    )
```

ルートプロジェクト。project1とproject2をまとめる役割として設定。ルートプロジェクトを対象としてsbtのタスクを呼び出すと、project1とproject2に対しても実行されるようにaggregationの設定を追加してある。

```
lazy val root = (project in file(".")).
  aggregate(proj1, proj2).
  settings(
    name := "multitest",
    pushName := "push name is root",
    pushKey := "push key is root"
  )
```

カスタムタスクのための設定のための変数を用意。pushNameとpushKeyはタスクに渡すパラメータ。実際に渡す値は各プロジェクトで設定。
pushはタスクキー。pushというsbtタスクが追加される。実際に何を呼び出すかはcommonSettingsで設定。

```
lazy val pushName = settingKey[String]("test name")
lazy val pushKey = settingKey[String]("test key")

lazy val push = taskKey[Unit]("push zip to S3 for CodeDeploy Test")
```

## sbtでの実行例

```
$ sbt
> projects
[info] In file:/Users/miya/src/multitest/
[info]     proj1
[info]     proj2
[info]   * root
> push
TaskTest push called
push name is project1
push key is project1
TaskTest push called
push name is project2
push key is project2
[success] Total time: 0 s, completed 2016/01/15 18:58:56
> project proj1
[info] Set current project to project1 (in build file:/Users/miya/src/multitest/)
> push
TaskTest push called
push name is project1
push key is project1
[success] Total time: 0 s, completed 2016/01/15 18:59:02
> run
[info] Running Proj1
project1
[success] Total time: 0 s, completed 2016/01/15 18:59:06
> project proj2
[info] Set current project to project2 (in build file:/Users/miya/src/multitest/)
> run
[info] Running Proj2
project2
[success] Total time: 0 s, completed 2016/01/15 18:59:23
> push
TaskTest push called
push name is project2
push key is project2
[success] Total time: 0 s, completed 2016/01/15 18:59:25
```

sbt起動直後はrootが操作対象。どんなプロジェクトが指定できるかはprojectsで一覧表示できる。project <project名>で操作対象を切り替える。
rootを操作対象にしている時にpushを実行するとaggregate設定のためにproject1, project2を対象としてタスクが実行される。