「コマンド」はタスクに似ています。sbtコンソールから実行できる名前付き操作です。
ただし、コマンドの実装はビルドの全体の状態(Stateで表される)をパラメータとして受け取り、新しいStateを計算します。つまり、コマンドは他のsbt設定を参照したり変更したりできます。通常、通常のタスクでは不可能なことを行う必要がある場合に、コマンドを使用します。
コマンドには3つの主要な側面があります。
コマンド呼び出しにユーザーが使用する構文、これには以下が含まれます。
sbtでは、タブ補完を含む構文の部分はパーサーコンバイナーで指定されます。Scala標準ライブラリのパーサーコンバイナーに精通している場合は、これらは非常に似ています。アクションの部分は、(State, T) => State
という関数です。ここで、T
はパーサーによって生成されたデータ構造です。パーサーコンバイナーの使い方については、入力の解析ページを参照してください。
Stateは、登録されているすべてのCommand
、実行する残りのコマンド、およびすべてのプロジェクト関連情報など、ビルドの状態へのアクセスを提供します。Stateの詳細については、状態とアクションを参照してください。
最後に、help
コマンドがコマンドのヘルプを表示するために使用する基本的なヘルプ情報が提供される場合があります。
コマンドは、関数State => Parser[T]
とアクション(State, T) => State
を組み合わせたものです。単なるParser[T]
ではなくState => Parser[T]
である理由は、多くの場合、現在のState
を使用してパーサーが構築されるためです。たとえば、現在ロードされているプロジェクト(State
で提供)は、project
コマンドの有効な補完を決定します。一般的なケースと具体的なケースの例については、次のセクションで説明します。
コマンドの作成に関するソースAPIの詳細については、Command.scalaを参照してください。
一般的なコマンドの構築方法は次のようになります。
val action: (State, T) => State = ...
val parser: State => Parser[T] = ...
val command: Command = Command("name")(parser)(action)
引数を受け付けないコマンドを構築するための便利なメソッドがあります。
val action: State => State = ...
val command: Command = Command.command("name")(action)
任意の内容の単一引数を受け付けるコマンドを構築するための便利なメソッドがあります。
// accepts the state and the single argument
val action: (State, String) => State = ...
val command: Command = Command.single("name")(action)
スペースで区切られた複数の引数を受け付けるコマンドを構築するための便利なメソッドがあります。
val action: (State, Seq[String]) => State = ...
// <arg> is the suggestion printed for tab completion on an argument
val command: Command = Command.args("name", "<arg>")(action)
次の例は、プロジェクトにコマンドを追加するサンプルビルドです。試してみるには
build.sbt
とproject/CommandExample.scala
を作成します。hello
、helloAll
、failIfTrue
、color
、およびprintStateコマンドを試してください。build.sbt
の内容です。
import CommandExample._
ThisBuild / organization := "com.example"
ThisBuild / scalaVersion := "2.12.18"
ThisBuild / version := "0.1.0-SNAPSHOT"
lazy val root = (project in file("."))
.settings(
commands ++= Seq(hello, helloAll, failIfTrue, changeColor, printState)
)
project/CommandExample.scala
の内容です。
import sbt._
import Keys._
// imports standard command parsing functionality
import complete.DefaultParsers._
object CommandExample {
// A simple, no-argument command that prints "Hi",
// leaving the current state unchanged.
def hello = Command.command("hello") { state =>
println("Hi!")
state
}
// A simple, multiple-argument command that prints "Hi" followed by the arguments.
// Again, it leaves the current state unchanged.
def helloAll = Command.args("helloAll", "<name>") { (state, args) =>
println("Hi " + args.mkString(" "))
state
}
// A command that demonstrates failing or succeeding based on the input
def failIfTrue = Command.single("failIfTrue") {
case (state, "true") => state.fail
case (state, _) => state
}
// Demonstration of a custom parser.
// The command changes the foreground or background terminal color
// according to the input.
lazy val change = Space ~> (reset | setColor)
lazy val reset = token("reset" ^^^ "\033[0m")
lazy val color = token( Space ~> ("blue" ^^^ "4" | "green" ^^^ "2") )
lazy val select = token( "fg" ^^^ "3" | "bg" ^^^ "4" )
lazy val setColor = (select ~ color) map { case (g, c) => "\033[" + g + c + "m" }
def changeColor = Command("color")(_ => change) { (state, ansicode) =>
print(ansicode)
state
}
// A command that demonstrates getting information out of State.
def printState = Command.command("printState") { state =>
import state._
println(definedCommands.size + " registered commands")
println("commands to run: " + show(remainingCommands))
println()
println("original arguments: " + show(configuration.arguments))
println("base directory: " + configuration.baseDirectory)
println()
println("sbt version: " + configuration.provider.id.version)
println("Scala version (for sbt): " + configuration.provider.scalaProvider.version)
println()
val extracted = Project.extract(state)
import extracted._
println("Current build: " + currentRef.build)
println("Current project: " + currentRef.project)
println("Original setting count: " + session.original.size)
println("Session setting count: " + session.append.size)
state
}
def show[T](s: Seq[T]) =
s.map("'" + _ + "'").mkString("[", ", ", "]")
}