mirror of https://github.com/sbt/sbt.git
Created Design Overview (markdown)
parent
b5c289b309
commit
c80c0b71d2
|
|
@ -0,0 +1,114 @@
|
|||
# Overview of sbt's Design
|
||||
|
||||
The main execution layers that comprise sbt are the launcher, the command engine, and the build tool, which is subdivided into project configuration and task execution.
|
||||
|
||||
## Launcher
|
||||
|
||||
Execution starts with the [launcher], which is a self-contained jar that pulls down an application and its dependencies according to a configuration file and then runs it.
|
||||
For sbt, this means getting the requested version of sbt (from `project/build.properties`) and the right Scala version and then starting sbt itself.
|
||||
The launcher also provides several services to launched applications, like reloading a different version of the application or retrieving other Scala versions.
|
||||
It is possible to use the launcher to launch other applications as well as documented on the [launcher] page.
|
||||
[Conscript] is a lightweight application distribution mechanism built on top of this functionality.
|
||||
|
||||
## Command Engine
|
||||
|
||||
The next level is the command engine, which is where [State] and [Commands] come in.
|
||||
When sbt is launched, it sets up an initial State that registers the default Commands (`set, reload, alias, ...`) and sets the initial commands to run.
|
||||
The initial commands are: add commands from `.sbtrc` files, load the project, and enter the interactive prompt if no commands were specified.
|
||||
Then, sbt starts the engine with `MainLoop.runLogged(initialState)`, which runs until all commands are processed and then exits.
|
||||
You can see this configuration in [xMain.run], which is the entry-point to sbt.
|
||||
|
||||
State keeps the list of scheduled command strings in remainingCommands.
|
||||
runLogged processes State by:
|
||||
|
||||
1. taking the next command string from remainingCommands (a `Seq[String]`)
|
||||
2. parsing it according to the current `State`'s definedCommands (a `Seq[Command]`)
|
||||
3. producing the command's `State => State` function from this parse
|
||||
4. applying the function to the current `State` (running the command)
|
||||
5. looping back to 1 if the new State has remainingCommands
|
||||
|
||||
There are actually two alternative entry-points to sbt that are defined below the main one, [ScriptMain] and [ConsoleMain], that provide the different front-ends described on the [Scripts] page.
|
||||
In addition, the command engine can be used to write standalone interactive [command line applications].
|
||||
|
||||
## Build tool
|
||||
|
||||
It is on top of this command engine that the build tool part of sbt is built.
|
||||
The build tool part is kicked off with the command that loads the build: `reload` (called `reload` because users usually call it in the context of reloading the build).
|
||||
The other important build-tool-related command runs tasks on a loaded build.
|
||||
|
||||
### Build loading
|
||||
|
||||
The `reload` command's job is to produce a [BuildStructure] and put it in [State] for future commands like task execution to use.
|
||||
[BuildStructure] is the data type that represents everything about a build: projects and relationships, evaluated settings, and logging configuration.
|
||||
It produces a [BuildStructure] by evaluating [build loaders].
|
||||
The default build loader configures sbt using the standard `.sbt` and `project/Build.scala` files that you know.
|
||||
The [build loaders] page shows an example of how one might write a build loader to read from a pom.xml instead (you couldn't define custom tasks or anything like that without another file, though).
|
||||
|
||||
Once the `reload` command has the `BuildStructure` value, it stores it in `State.attributes`, keyed by `Keys.stateBuildStructure`.
|
||||
|
||||
### State.attributes
|
||||
|
||||
Now, a diversion back to `State` to cover attributes...
|
||||
`State.attributes` is a [typesafe map].
|
||||
Keys are of type `AttributeKey[T]` and you can only associate values of type `T` with that key.
|
||||
`State` has convenience methods set/get that delegate to the underlying `attributes` map.
|
||||
|
||||
To pass information between commands, you put data in the `attributes` map.
|
||||
An example of this is [release plugin], which sets `skipTests` according to the command line options.
|
||||
The `release` command itself schedules other commands to run and those can configure themselves from `skipTests` in `State.attributes`.
|
||||
This is one way a command can change the behavior of tasks without needing to reload the project: it sets attributes in `State` and the task accesses `State` via the `state` task.
|
||||
|
||||
### Project.extract
|
||||
|
||||
The `Project.extract(state)` call at its core calls `state.get(Keys.stateBuildStructure)` to get the `BuildStructure` back.
|
||||
It does some other things as well:
|
||||
|
||||
* throws a nicer exception if a project isn't loaded
|
||||
* loads the session with `state.get(Keys.sessionSettings)`
|
||||
* returns the session and structure in an [Extracted] value, which provides a better interface to them
|
||||
|
||||
### Session settings
|
||||
|
||||
The [SessionSettings] datatype tracks a few pieces of information that are not persisted.
|
||||
The two main pieces are:
|
||||
|
||||
* the current project: changed by the `project` command, for example
|
||||
* additional settings: added by the `set` command, for example
|
||||
|
||||
SessionSettings only tracks this information; setting these values on a `SessionSettings` object does not apply the changes.
|
||||
In particular, the project has to be reloaded for the additional settings to take effect.
|
||||
Reloading checks the settings for problems like references to non-existing settings and then the settings are reevaluated.
|
||||
The release plugin has a [reapply] method that shows the proper way to add settings to the current project.
|
||||
|
||||
### Modifying settings
|
||||
|
||||
Given a sequence of settings (`Seq[Setting[_]]`), the `Load.transformSettings` method resolves any unspecified scopes in the raw settings sequence.
|
||||
This usually means associating the settings with the current project.
|
||||
Then, `BuiltinCommands.reapply` actually makes the settings take effect.
|
||||
It checks, processes, and loads the new settings, updates `BuildStructure`, and stuffs everything back into `State`.
|
||||
|
||||
### Tasks
|
||||
|
||||
The task execution command pulls out the current, loaded project from `State` (via `Project.extract`), looks up the task to run, and runs it.
|
||||
Commands can get the values produced by tasks, but tasks don't directly transform `State` or run commands (there are some rare exceptions).
|
||||
Tasks can get the current `State` via the `state` task, which is a special task that gets injected by the task execution command and set to the current `State`.
|
||||
|
||||
## Comments, requests for clarification
|
||||
|
||||
[xMain.run]: http://www.scala-sbt.org/0.12.1/sxr/Main.scala.html#11563
|
||||
[launcher]: http://www.scala-sbt.org/release/docs/Detailed-Topics/Launcher.html
|
||||
[command line applications]: http://www.scala-sbt.org/release/docs/Extending/Command-Line-Applications.html
|
||||
[Scala Days 2012 talk]: http://skillsmatter.com/podcast/scala/tab-completion-parser-combinators
|
||||
[Conscript]: https://github.com/n8han/conscript
|
||||
[State]: http://www.scala-sbt.org/release/docs/Extending/Build-State.html
|
||||
[Commands]: http://www.scala-sbt.org/release/docs/Extending/Commands.html
|
||||
[ScriptMain]: http://www.scala-sbt.org/0.12.1/sxr/Main.scala.html#11564
|
||||
[ConsoleMain]: http://www.scala-sbt.org/0.12.1/sxr/Main.scala.html#11565
|
||||
[Scripts]: http://www.scala-sbt.org/release/docs/Detailed-Topics/Scripts.html
|
||||
[build loaders]: http://www.scala-sbt.org/release/docs/Extending/Build-Loaders.html
|
||||
[BuildStructure]: http://www.scala-sbt.org/0.12.1/api/sbt/Load$$BuildStructure.html
|
||||
[Extracted]: http://www.scala-sbt.org/0.12.1/api/sbt/Extracted.html
|
||||
[typesafe map]: http://www.scala-sbt.org/0.12.1/api/sbt/AttributeMap.html
|
||||
[SessionSettings]: http://www.scala-sbt.org/0.12.1/api/sbt/SessionSettings.html
|
||||
[release plugin]: https://github.com/sbt/sbt-release
|
||||
[reapply]: https://github.com/sbt/sbt-release/blob/master/src/main/scala/ReleaseExtra.scala#L228
|
||||
Loading…
Reference in New Issue