例えばsbtで
- マルチプロジェクトで子プロジェクトの特定のMainクラスを実行
- Settingを変更しつつコマンドを実行
などしたくなったこと有りませんか?
そんなときは、ルートプロジェクトでオレオレコマンドを定義すると一発で実行できるようになります。
プロジェクトを切り替えて子プロジェクトのコマンドを実行
sbt:root> project core
sbt:core> runMain MainClass arg1 arg2
のようなコマンドを一発で実行したい場合は、以下のようにコマンドを定義することで
build.sbt
lazy val root = (project in file(".")).setting(
commands ++= Seq(
Command.args("codeGen","<args>")((state, args) => {
// project coreを実行して、projectが切り替わったStateを取得
val projectChanged: State = MainLoop.processCommand(Exec("project core", None), state)
// projectが切り替わったStateを渡してコマンドを実行
MainLoop.processCommand(Exec(s"runMain MainClass ${args.mkString(" ")}", None), projectChanged)
state // project切り替え前のStateを戻すことで、実行時と同じprojectの状態に戻る
})
)
)
lazy val core = (project in file("core")).setting(
)
以下のコマンドで一発実行できるようになります
sbt:root> myRun arg1 arg2
# MainClass has run
sbt:root>
commandに関連するメソッドは戻り地にStateを帰すようになっています。Stateは普遍なオブジェクトで、戻り値のStateはコマンドなどの実行などで状態が変化したStateが帰ってきます。
Settingを変更してコマンドを実行
設定値を元に他の設定を変更しコマンド実行
sbt:root> show myOption1
sbt:root> set myOption2 := "hoge"
sbt:root> runMain Main1
※ myOption2にセットする値は、myOption1の値に依存
build.sbt
lazy val root = (project in file(".")).setting(
commands ++= Seq(
Command.command("updateAndRun")(state => {
val extracted = Project.extract(state)
// settingの値を取得
val value = extracted.get(myOption1)
// 取得した値に応じて、他のKeyを変更
val settingUpdated: State = value match {
case "update to hoge" => extracted.appendWithSession(Seq(myOption2 := "hoge"), state)
case "update to fuga" => extracted.appendWithSession(Seq(myOption2 := "fuga"), state)
}
MainLoop.processCommand(Exec(s"runMain Main", None), settingUpdated)
})
)
)
と定義しておけば、
sbt:root> updateAndRun
で一連の操作が実行されます。