1. Def.inputTaskDyn を使用した動的入力タスクの定義

Def.inputTaskDyn を使用した動的入力タスクの定義 

プラグインによって、`openbrowser` というブラウザを開くタスクが既に存在すると仮定します。入力タスクの後にタスクをシーケンスする方法は次のとおりです。

build.sbt v1 

lazy val runopen = inputKey[Unit]("run and then open the browser")
lazy val openbrowser = taskKey[Unit]("open the browser")

lazy val root = (project in file("."))
  .settings(
    runopen := (Def.inputTaskDyn {
      import sbt.complete.Parsers.spaceDelimited
      val args = spaceDelimited("<args>").parsed
      Def.taskDyn {
        (Compile / run).toTask(" " + args.mkString(" ")).value
        openbrowser
      }
    }).evaluated,
    openbrowser := {
      println("open browser!")
    }
  )

build.sbt v2 

`Compile / run` を再接続しようとすると、複雑になります。内部の `Compile / run` への参照は既に継続タスク内にあるため、単に `runopen` を `Compile / run` に再接続すると、循環参照が作成されます。循環を断ち切るために、`Compile / run` のクローンである `Compile / actualRun` を導入します。

lazy val actualRun = inputKey[Unit]("The actual run task")
lazy val openbrowser = taskKey[Unit]("open the browser")

lazy val root = (project in file("."))
  .settings(
    Compile / run := (Def.inputTaskDyn {
      import sbt.complete.Parsers.spaceDelimited
      val args = spaceDelimited("<args>").parsed
      Def.taskDyn {
        (Compile / actualRun).toTask(" " + args.mkString(" ")).value
        openbrowser
      }
    }).evaluated,
    Comile / actualRun := Defaults.runTask(
      Runtime / fullClasspath,
      Compile / run / mainClass,
      Compile / run / runner
    ).evaluated,
    openbrowser := {
      println("open browser!")
    }
  )

* 一部のタスク(例: `testOnly`)は末尾のスペースで失敗することに注意してください。そのため、空の `args` を処理するには、`toTask` 用に構築された文字列の右トリム(`.replaceAll("\s+$", "")`)が必要になる場合があります。

`Compile / actualRun` の実装は、Defaults.scala の `run` タスクの実装からコピーペーストされました。

これで、シェルから `run foo` を呼び出すと、渡された引数で `Compile / actualRun` が評価され、次に `openbrowser` タスクが評価されます。