sbtのworkflow、shellの起動とか
sbtのWorkflow、Stateを新しいものにしつつ回すって話
SBT in Actionでいう"Figure 10.2 - Workflow of sbt’s command engine"の話(どっかに図落ちてないかな)
現時点の最新版のコミット見てる
xsbti.AppMain
public MainResult run(AppConfiguration configuration);
だけ持つインタフェース
継承してるのは以下の3つ。各々、初期状態のState
を用意し、MainLoop.runLogged(state)
へ渡す。初期状態のState
を用意する際は、def initialState(configuration: xsbti.AppConfiguration, initialDefinitions: Seq[Command], preCommands: Seq[String]): State
を用いる
初期状態のState
は以下のようになる
- sbt.xMain
- configuration: Launchの時点で、設定ファイルから読み込んだやつ
- initialDefinition
- defaults(めっちゃたくさんコマンドを使えるようにするコマンド), early(他のコマンドより早く他のコマンドを実行させるやつ)
- preCommands: 以下の3つが順含まれてる
- defaultsを実行して、多くのコマンドを使えるようにする
~/.sbtrc
,.sbtrc
を読み込むやつboot
コマンド ← なるほどdef DefaultBootCommands: Seq[String] = LoadProject :: (IfLast + " " + Shell) :: Nil
- なんのことはなく、プロジェクトを読み込んで(LoadProject=
reload
)sbt shellを起動する(Shell=shell
) IfLast
により、shell
コマンドが最後に実行される
- sbt.ScriptMain:
- configuration: Launchの時点で、設定ファイルから読み込んだやつ
- initialDefinition
- BuiltinCommands.ScriptCommands:
Seq(ignore, exit, Script.command, setLogLevel, early, act, nop)
Script.command
ってのがscript
ってコマンド- sbtの引数に与えられたファイルを実行して設定に追加するやつ
- BuiltinCommands.ScriptCommands:
- preCommands
- 上記
script
コマンドのみが含まれる
- 上記
- sbt.ConsoleMain
- configuration: Launchの時点で、設定ファイルから読み込んだやつ
- initialDefinition
- BuiltinCommands.ConsoleCommands:
Seq(ignore, exit, IvyConsole.command, setLogLevel, early, act, nop)
IvyConsole.command
ってのがivy-console
ってコマンド- 引数からivyの依存(外部urlとかjarとか)取得して、libraryDependenciesの設定とかに追加、その後で
console-quick
だけ実行するようなStateを返す
- BuiltinCommands.ConsoleCommands:
- preCommands
- 上記
ivy-console
コマンドのみが含まれる
- 上記
MainLoop.runManaged(state)
- sbt.TrapExitで囲って
MainLoop.runLogged(state)
へSystem.exit
が呼ばれた際にラップするもの- try
TrapExit.installManager
- SecurityManagerを
TrapExit
のインスンタンスなものに更新
- SecurityManagerを
- finally
TrapExit.uninstallManager(previous)
で元に戻す
MainLoop.runLogged(state)
- shutdownHookを設定
jline.TerminalFactory.get().restore()
runLoggedLoop(state, state.globalLogging.backing)
: 再帰するやつRun loop that evaluates remaining commands and manages changes to global logging configuration.
runAndClearLast
- ↓ な感じ
Command.process
を実行して、引数にはstate.remainingCommands
のheadとremainingCommands
とhistory
をいじったものを与え、その結果を返す- ちなみに
remainingCommands: Seq[String]
- ちなみに
remainingCommands
が無い場合には、Return(Exit(0))
を返す- 正常系なら、上の2つのみがremainingCommandsが無くなるまで実行されて終了する
shell
コマンドでsbt shellに入ったり、コマンドの実行中にremainingCommands
が増えたりもする
/** Runs the next sequence of commands that doesn't require global logging changes.*/ @tailrec def run(state: State): RunNext = state.next match { case State.Continue => run(next(state)) case State.ClearGlobalLog => new ClearGlobalLog(state.continue) case State.KeepLastLog => new KeepGlobalLog(state.continue) case ret: State.Return => new Return(ret.result) } def next(state: State): State = ErrorHandling.wideConvert { state.process(Command.process) } match { case Right(s) => s case Left(t: xsbti.FullReload) => throw t case Left(t) => handleException(t, state) } }
implicit def stateOps(s: State): StateOps = new StateOps { def process(f: (String, State) => State): State = s.remainingCommands match { case Seq() => exit(true) case Seq(x, xs @ _*) => log.debug(s"> $x") f(x, s.copy(remainingCommands = xs, history = x :: s.history)) } ...
次
sbt.State.Next
の話と、Command.process
の話あたり