mirror of https://github.com/sbt/sbt.git
Fix @retronym's comments
* Fill out more details in archiecture section. * Leave sections blank we don't have time to write. * Consolidate on `Sub project` vernacular instead of module. * Add a few examples to make statements concrete.
This commit is contained in:
parent
041bc4bf01
commit
af25df1777
|
|
@ -0,0 +1,5 @@
|
|||
=================
|
||||
Command Engine
|
||||
=================
|
||||
|
||||
Placeholder for command engine details.
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
=================
|
||||
Core Principles
|
||||
=================
|
||||
|
||||
This document details the core principles overarching sbt's design and code style. Sbt's core principles can
|
||||
be stated quite simply:
|
||||
|
||||
1. Everything should have a ``Type``, enforced as much as is practical.
|
||||
2. Dependencies should be **explicit**.
|
||||
3. Once learned, a concept should hold throughout **all** parts of sbt.
|
||||
4. Parallel is the default.
|
||||
|
||||
With these principles in mind, let's walk through the core design of sbt.
|
||||
|
||||
|
||||
Introduction to build state
|
||||
===========================
|
||||
This is the first piece you hit when starting sbt. Sbt's command engine is the means by which
|
||||
it processes user requests using the build state. The command engine is essentially a means of applying
|
||||
**state transformations** on the build state, to execute user requests.
|
||||
|
||||
In sbt, commands are functions that take the current build state (``sbt.State``) and produce the next state. In
|
||||
other words, they are essentially functions of ``sbt.State => sbt.State``. However, in reality, Commands are
|
||||
actually string processors which take some string input and act on it, returning the next build state.
|
||||
|
||||
The details of the command engine are covered in :doc:`the command engine section <Command-Engine>`.
|
||||
|
||||
So, the entirety of sbt is driven off the ``sbt.State`` class. Since this class needs to be resilient in the
|
||||
face of custom code and plugins, it needs a mechanism to store the state from any potential client. In
|
||||
dynamic languages, this can be done directly on objects.
|
||||
|
||||
A naive approach in Scala is to use a ``Map<String,Any>``. However, this vioaltes tennant #1: Everythign should have a `Type`.
|
||||
So, sbt defines a new type of map called an ``AttributeMap``. An ``AttributeMap`` is a key-value storage mechanism where
|
||||
keys are both strings *and* expected `Type`s for their value.
|
||||
|
||||
Here is what the typesafe ``AttributeKey`` key looks like ::
|
||||
|
||||
sealed trait AttributeKey[T] {
|
||||
/** The label is the identifier for the key and is camelCase by convention. */
|
||||
def label: String
|
||||
/** The runtime evidence for `T` */
|
||||
def manifest: Manifest[T]
|
||||
}
|
||||
|
||||
These keys store both a `label` (``string``) and some runtime type information (``manifest``). To put or get something on
|
||||
the AttributeMap, we first need to construct one of these keys. Let's look at the basic definition of the ``AttributeMap`` ::
|
||||
|
||||
trait AttributeMap {
|
||||
/** Gets the value of type `T` associated with the key `k` or `None` if no value is associated.
|
||||
* If a key with the same label but a different type is defined, this method will return `None`. */
|
||||
def get[T](k: AttributeKey[T]): Option[T]
|
||||
|
||||
|
||||
/** Adds the mapping `k -> value` to this map, replacing any existing mapping for `k`.
|
||||
* Any mappings for keys with the same label but different types are unaffected. */
|
||||
def put[T](k: AttributeKey[T], value: T): AttributeMap
|
||||
}
|
||||
|
||||
|
||||
Now that there's a definition of what build state is, there needs to be a way to dynamically construct it. In sbt, this is
|
||||
done through the ``Setting[_]`` sequence.
|
||||
|
||||
Introduction to Settings
|
||||
========================
|
||||
|
||||
TODO - Discuss ``Setting[_]``
|
||||
|
||||
TODO - Transition into ``Task[_]``
|
||||
|
||||
TODO - Transition into ``InputTask[_]``
|
||||
|
|
@ -12,6 +12,9 @@ a particular build key. Sbt converts all registered ``Setting[_]`` objects into
|
|||
|
||||
All of sbt's loading semantics are contained within the `Load.scala <../../sxr/sbt/Load.scala.html>` file. It is approximately the following:
|
||||
|
||||
.. Note: This image comes from a google drawing: https://docs.google.com/a/typesafe.com/drawings/d/1Aj_IkOaJpRXJNhrVtVJaS8m-YRcKsympVOj3M2sUz7E/edit
|
||||
.. Feel free to request access to modify as appropriate.
|
||||
|
||||
.. image:: settings-initialization-load-ordering.png
|
||||
|
||||
The blue circles represent actions happening when sbt loads a project. We can see that sbt performs the following actions in load:
|
||||
|
|
@ -26,14 +29,19 @@ The blue circles represent actions happening when sbt loads a project. We can s
|
|||
|
||||
Each of these loads defines several sequences of settings. The diagram shows the two most important:
|
||||
|
||||
* ``buildSettings`` - These are settings defined to be ``in ThisBuild``. They are initialized *once* for the build.
|
||||
* ``buildSettings`` - These are settings defined to be ``in ThisBuild`` or directly against the ``Build`` object. They are initialized *once* for the build.
|
||||
You can add these, e.g. in ``project/build.scala`` ::
|
||||
|
||||
object MyBuild extends Build {
|
||||
override val settings = ...
|
||||
override val settings = Seq(foo := "hi")
|
||||
}
|
||||
|
||||
* ``projectSettings`` - These are settings specific to a project. They are specific to a *particular submodule* in the build. A
|
||||
or in a ``build.sbt`` file ::
|
||||
|
||||
foo in ThisBuild := "hi"
|
||||
|
||||
|
||||
* ``projectSettings`` - These are settings specific to a project. They are specific to a *particular sub project* in the build. A
|
||||
plugin may be contributing its settings to more than on project, in which case the values are duplicated for each project.
|
||||
You add project specific settings, eg. in ``project/build.scala`` ::
|
||||
|
||||
|
|
@ -94,4 +102,30 @@ The AddSettings object provides the following "groups" of settings you can use f
|
|||
Include all local ``*.sbt`` file settings.
|
||||
|
||||
|
||||
*Note: Be very careful when reordering settings. It's easy to accidentally remove core functionality.*
|
||||
*Note: Be very careful when reordering settings. It's easy to accidentally remove core functionality.*
|
||||
|
||||
For example, let's see what happens if we move the ``build.sbt`` files *before* the ``projectSettings``.
|
||||
|
||||
Let's create an example project the following defintiion:
|
||||
|
||||
`project/build.scala` ::
|
||||
|
||||
object MyTestBuild extends Build {
|
||||
|
||||
val testProject = project.in(file(".")).autoSettings(autoPlugins, defaultSbtFiles, projectSettings).settings(
|
||||
version := scalaBinaryVersion.value match {
|
||||
case "2.10" => "1.0-SNAPSHOT"
|
||||
case v => "1.0-for-${v}-SNAPSHOT"
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
This build defines a version string which appends the scala version if the current scala version is not the in the ``2.10.x`` series.
|
||||
Now, when issuing a release we want to lock down the version. Most tools assume this can happen by writing a ``version.sbt`` file:
|
||||
|
||||
`version.sbt` ::
|
||||
|
||||
version := "1.0.0"
|
||||
|
||||
However, when we load this new build, we find that the ``version`` in ``version.sbt`` has been **overriden** by the one defined
|
||||
in ``project/Build.scala`` because of the order we defined for settings, so the new ``version.sbt`` file has no effect.
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
=================
|
||||
Task Engine
|
||||
=================
|
||||
|
||||
Placeholder for task engine design details.
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
Architecture
|
||||
==============
|
||||
|
||||
This is the fledgeling set of documentation about the Architecture of sbt. This will cover all the core components of
|
||||
This is the set of documentation about the Architecture of sbt. This covers all the core components of
|
||||
sbt as well as the general notion of how they all work together. This documentation is suitable for those who wish to
|
||||
have a deeper understanding of sbt's core, but already understand the fundamentals of ``Setting[_]``, ``Task[_]`` and
|
||||
constructing builds.
|
||||
|
|
@ -10,4 +10,7 @@ constructing builds.
|
|||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
Setting-Initialization
|
||||
Core-Principles
|
||||
Setting-Initialization
|
||||
Task-Engine
|
||||
Command-Engine
|
||||
|
|
|
|||
Loading…
Reference in New Issue