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:
Josh Suereth 2014-03-10 14:22:56 -04:00
parent 041bc4bf01
commit af25df1777
5 changed files with 123 additions and 6 deletions

View File

@ -0,0 +1,5 @@
=================
Command Engine
=================
Placeholder for command engine details.

View File

@ -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[_]``

View File

@ -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.

View File

@ -0,0 +1,5 @@
=================
Task Engine
=================
Placeholder for task engine design details.

View File

@ -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