mirror of https://github.com/sbt/sbt.git
initial refresh of getting started guide for 0.13: multiple projects and plugins
still todo: Custom-Settings, Full-Def
This commit is contained in:
parent
6d981e4c5b
commit
70a54b9848
|
|
@ -4,6 +4,8 @@ Best Practices
|
|||
|
||||
This page describes best practices for working with sbt.
|
||||
|
||||
.. _global-vs-local-plugins:
|
||||
|
||||
`project/` vs. `~/.sbt/`
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
|||
|
|
@ -12,9 +12,8 @@ example, you might use
|
|||
markdown processing task. A plugin can define a sequence of sbt Settings
|
||||
that are automatically added to all projects or that are explicitly
|
||||
declared for selected projects. For example, a plugin might add a
|
||||
'proguard' task and associated (overridable) settings. Because
|
||||
:doc:`Commands` can be added with the `commands` setting, a plugin can
|
||||
also fulfill the role that processors did in 0.7.x.
|
||||
`proguard` task and associated (overridable) settings.
|
||||
Also, :doc:`Commands` can be added with the `commands` setting
|
||||
|
||||
The :doc:`Plugins-Best-Practices` page describes the
|
||||
currently evolving guidelines to writing sbt plugins. See also the
|
||||
|
|
@ -59,7 +58,7 @@ Specifically,
|
|||
3. Sources in the `project/` project are the build definition files
|
||||
and are compiled using the classpath built from the managed and
|
||||
unmanaged dependencies.
|
||||
4. Project dependencies can be declared in
|
||||
4. Project dependencies can be declared in `project/plugins.sbt` or
|
||||
`project/project/Build.scala` and will be available to the build
|
||||
definition sources. Think of `project/project/` as the build
|
||||
definition for the build definition.
|
||||
|
|
@ -85,14 +84,7 @@ This means that plugins will not see classes or resources from build definitions
|
|||
Global plugins
|
||||
--------------
|
||||
|
||||
In sbt 0.7.x, a processor was a way to add new commands to sbt and
|
||||
distribute them to users. A key feature was the ability to have per-user
|
||||
processors so that once declared, it could be used in all projects for
|
||||
that user. In sbt 0.10+, plugins and processors are unified.
|
||||
Specifically, a plugin can add commands and plugins can be declared
|
||||
globally for a user.
|
||||
|
||||
The `~/.sbt/plugins/` directory is treated as a global plugin
|
||||
The :sublit:`|globalPluginsBase|` directory is treated as a global plugin
|
||||
definition project. It is a normal sbt project whose classpath is
|
||||
available to all sbt project definitions for that user as described
|
||||
above for per-project plugins.
|
||||
|
|
@ -161,35 +153,28 @@ To switch back to the main project:
|
|||
1d) Project dependency
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This variant shows how to use the external project support in sbt 0.10
|
||||
to declare a source dependency on a plugin. This means that the plugin
|
||||
will be built from source and used on the classpath.
|
||||
This variant shows how to use sbt's external project support to declare a source dependency on a plugin.
|
||||
This means that the plugin will be built from source and used on the classpath.
|
||||
|
||||
Edit `project/project/Build.scala`
|
||||
Edit `project/plugins.sbt`
|
||||
|
||||
::
|
||||
|
||||
import sbt._
|
||||
object PluginDef extends Build {
|
||||
override lazy val projects = Seq(root)
|
||||
lazy val root = Project("plugins", file(".")) dependsOn( webPlugin )
|
||||
lazy val webPlugin = uri("git://github.com/JamesEarlDouglas/xsbt-web-plugin")
|
||||
}
|
||||
lazy val root = project.in( file(".") ).dependsOn( assemblyPlugin )
|
||||
lazy val assemblyPlugin = uri("git://github.com/sbt/sbt-assembly")
|
||||
|
||||
If sbt is running, run `reload`.
|
||||
|
||||
Note that this approach can be useful used when developing a plugin. A
|
||||
project that uses the plugin will rebuild the plugin on `reload`. This
|
||||
saves the intermediate steps of `publishLocal` and `cleanPlugins`
|
||||
required in 0.7. It can also be used to work with the development
|
||||
version of a plugin from its repository.
|
||||
Note that this approach can be useful used when developing a plugin.
|
||||
A project that uses the plugin will rebuild the plugin on `reload`.
|
||||
This saves the intermediate steps of `publishLocal` and `update`.
|
||||
It can also be used to work with the development version of a plugin from its repository.
|
||||
|
||||
It is recommended to explicitly specify the commit or tag by appending
|
||||
it to the repository as a fragment:
|
||||
It is recommended to explicitly specify the commit or tag by appending it to the repository as a fragment:
|
||||
|
||||
::
|
||||
|
||||
lazy val webPlugin = uri("git://github.com/JamesEarlDouglas/xsbt-web-plugin#0.9.7")
|
||||
lazy val assemblyPlugin = uri("git://github.com/sbt/sbt-assembly#0.9.1")
|
||||
|
||||
2) Use the library
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
|
@ -222,7 +207,7 @@ Introduction
|
|||
------------
|
||||
|
||||
A minimal plugin is a Scala library that is built against the version of
|
||||
Scala that sbt runs (currently, 2.9.1) or a Java library. Nothing
|
||||
Scala that sbt runs (currently, |scalaRelease|) or a Java library. Nothing
|
||||
special needs to be done for this type of library, as shown in the
|
||||
previous section. A more typical plugin will provide sbt tasks,
|
||||
commands, or settings. This kind of plugin may provide these settings
|
||||
|
|
@ -240,13 +225,18 @@ A plugin can implement `sbt.Plugin`. The contents of a Plugin
|
|||
singleton, declared like `object MyPlugin extends Plugin`, are
|
||||
wildcard imported in `set`, `eval`, and `.sbt` files. Typically,
|
||||
this is used to provide new keys (SettingKey, TaskKey, or InputKey) or
|
||||
core methods without requiring an import or qualification. In addition,
|
||||
the `settings` member of the `Plugin` is automatically appended to
|
||||
each project's settings. This allows a plugin to automatically provide
|
||||
new functionality or new defaults. One main use of this feature is to
|
||||
globally add commands, like a processor in sbt 0.7.x. These features
|
||||
should be used judiciously because the automatic activation removes
|
||||
control from the build author (the user of the plugin).
|
||||
core methods without requiring an import or qualification.
|
||||
|
||||
In addition, a `Plugin` can implement `projectSettings`, `buildSettings`, and `globalSettings` as appropriate.
|
||||
The Plugin's `projectSettings` is automatically appended to each project's settings.
|
||||
The `buildSettings` is appended to each build's settings (that is, `in ThisBuild`).
|
||||
The `globalSettings` is appended once to the global settings (`in Global`).
|
||||
These allow a plugin to automatically provide new functionality or new defaults.
|
||||
One main use of this feature is to globally add commands, such as for IDE plugins.
|
||||
Use `globalSettings` to define the default value of a setting.
|
||||
|
||||
These automatic features should be used judiciously because the automatic activation generally reduces control for the build author (the user of the plugin).
|
||||
Some control is returned to them via `Project.autoSettings`, which changes how automatically added settings are added and in what order.
|
||||
|
||||
Example Plugin
|
||||
--------------
|
||||
|
|
@ -289,32 +279,15 @@ An example of a typical plugin:
|
|||
Usage example
|
||||
-------------
|
||||
|
||||
A light build definition that uses the plugin might look like:
|
||||
A build definition that uses the plugin might look like:
|
||||
|
||||
`build.sbt`
|
||||
|
||||
::
|
||||
|
||||
MyPlugin.newSettings
|
||||
|
||||
newSetting := "light"
|
||||
|
||||
A full build definition that uses this plugin might look like:
|
||||
|
||||
::
|
||||
|
||||
object MyBuild extends Build
|
||||
{
|
||||
lazy val projects = Seq(root)
|
||||
lazy val root = Project("root", file(".")) settings( MyPlugin.newSettings : _*) settings(
|
||||
MyPlugin.newSetting := "full"
|
||||
)
|
||||
}
|
||||
|
||||
Individual settings could be defined in `MyBuild.scala` above or in a
|
||||
`build.sbt` file:
|
||||
|
||||
::
|
||||
|
||||
newSettings := "overridden"
|
||||
newSetting := "example"
|
||||
|
||||
Example command plugin
|
||||
----------------------
|
||||
|
|
@ -358,7 +331,7 @@ Global plugins example
|
|||
----------------------
|
||||
|
||||
The simplest global plugin definition is declaring a library or plugin
|
||||
in `~/.sbt/plugins/build.sbt`:
|
||||
in :sublit:`|globalPluginsBase|\ build.sbt`:
|
||||
|
||||
::
|
||||
|
||||
|
|
@ -369,14 +342,14 @@ user.
|
|||
|
||||
In addition:
|
||||
|
||||
1. Jars may be placed directly in `~/.sbt/plugins/lib/` and will be
|
||||
1. Jars may be placed directly in :sublit:`|globalPluginsBase|\ lib/` and will be
|
||||
available to every build definition for the current user.
|
||||
2. Dependencies on plugins built from source may be declared in
|
||||
~/.sbt/plugins/project/Build.scala\` as described at
|
||||
:sublit:`|globalPluginsBase|\ project/Build.scala` as described at
|
||||
:doc:`/Getting-Started/Full-Def`.
|
||||
3. A Plugin may be directly defined in Scala source files in
|
||||
`~/.sbt/plugins/`, such as `~/.sbt/plugins/MyPlugin.scala`.
|
||||
`~/.sbt/plugins/build.sbt` should contain `sbtPlugin := true`.
|
||||
:sublit:`|globalPluginsBase|`, such as :sublit:`|globalPluginsBase|\ MyPlugin.scala`.
|
||||
:sublit:`|globalPluginsBase|\ /build.sbt` should contain `sbtPlugin := true`.
|
||||
This can be used for quicker turnaround when developing a plugin
|
||||
initially:
|
||||
|
||||
|
|
@ -388,7 +361,7 @@ In addition:
|
|||
overhead of `publishLocal` and cleaning the plugins directory
|
||||
of the project using the plugin.
|
||||
|
||||
These are all consequences of `~/.sbt/plugins/` being a standard
|
||||
These are all consequences of :sublit:`|globalPluginsBase|` being a standard
|
||||
project whose classpath is added to every sbt project's build
|
||||
definition.
|
||||
|
||||
|
|
@ -398,3 +371,6 @@ Best Practices
|
|||
If you're a plugin writer, please consult the :doc:`Plugins-Best-Practices`
|
||||
page; it contains a set of guidelines to help you ensure that your
|
||||
plugin is consistent with and plays well with other plugins.
|
||||
|
||||
.. |globalBase| replace:: ~/.sbt/|version|/
|
||||
.. |globalPluginsBase| replace:: |globalBase|\ plugins/
|
||||
|
|
|
|||
|
|
@ -82,8 +82,8 @@ you can often use the convenient APIs in
|
|||
Use plugins!
|
||||
------------
|
||||
|
||||
If you find you have a lot of custom code in `.scala` files, consider
|
||||
moving it to a plugin for re-use across multiple projects.
|
||||
If you find you have a lot of custom code, consider
|
||||
moving it to a plugin for re-use across multiple builds.
|
||||
|
||||
It's very easy to create a plugin, as :doc:`teased earlier <Using-Plugins>` and :doc:`discussed at more length here </Extending/Plugins>`.
|
||||
|
||||
|
|
@ -93,4 +93,5 @@ Next
|
|||
This page has been a quick taste; there's much much more about custom
|
||||
tasks on the :doc:`/Detailed-Topics/Tasks` page.
|
||||
|
||||
You're at the end of Getting Started! There's a :doc:`brief recap <Summary>`.
|
||||
Move on to :doc:`Full-Def`.
|
||||
|
||||
|
|
|
|||
|
|
@ -265,4 +265,4 @@ the build definition.
|
|||
Next
|
||||
----
|
||||
|
||||
Move on to :doc:`using plugins <Using-Plugins>`.
|
||||
You're at the end of Getting Started! There's a :doc:`brief recap <Summary>`.
|
||||
|
|
|
|||
|
|
@ -245,4 +245,4 @@ dependencies :doc:`on this page </Detailed-Topics/Library-Management>`, if you d
|
|||
answer on this introductory page.
|
||||
|
||||
If you're reading Getting Started in order, for now, you might move on
|
||||
to read :doc:`.scala build definition <Full-Def>`.
|
||||
to read :doc:`Multi-Project`.
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ Multi-Project Builds
|
|||
This page introduces multiple projects in a single build.
|
||||
|
||||
Please read the earlier pages in the Getting Started Guide first, in
|
||||
particular you need to understand :doc:`build.sbt <Basic-Def>` and
|
||||
:doc:`.scala build definition <Full-Def>` before reading this page.
|
||||
particular you need to understand :doc:`build.sbt <Basic-Def>` before
|
||||
reading this page.
|
||||
|
||||
Multiple projects
|
||||
-----------------
|
||||
|
|
@ -15,38 +15,122 @@ It can be useful to keep multiple related projects in a single build,
|
|||
especially if they depend on one another and you tend to modify them
|
||||
together.
|
||||
|
||||
Each sub-project in a build has its own `src/main/scala`, generates
|
||||
Each sub-project in a build has its own source directories, generates
|
||||
its own jar file when you run `package`, and in general works like any
|
||||
other project.
|
||||
|
||||
Defining projects in a `.scala` file
|
||||
--------------------------------------
|
||||
A project is defined by declaring a `lazy val` of type `Project <../../api/sbt/Project.html>`_.
|
||||
For example, ::
|
||||
|
||||
To have multiple projects, you must declare each project and how they
|
||||
relate in a `.scala` file; there's no way to do it in a `.sbt` file.
|
||||
However, you can define settings for each project in `.sbt` files.
|
||||
Here's an example of a `.scala` file which defines a root project
|
||||
`hello`, where the root project aggregates two sub-projects,
|
||||
`hello-foo` and `hello-bar`:
|
||||
lazy val util = project
|
||||
|
||||
lazy val core = project
|
||||
|
||||
The name of the val is used as the project's ID and base directory name.
|
||||
The ID is used to refer to the project at the command line.
|
||||
The base directory may be changed from the default using the `in` method.
|
||||
For example, the following is a more explicit way to write the previous example: ::
|
||||
|
||||
lazy val util = project.in( file("util") )
|
||||
|
||||
lazy val core = project in file("core")
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
Projects in the build can be completely independent of one another, but usually
|
||||
they will be related to one another by some kind of dependency. There are two
|
||||
types of dependencies: aggregate and classpath.
|
||||
|
||||
|
||||
Aggregation
|
||||
~~~~~~~~~~~
|
||||
|
||||
Aggregation means that running a task on the aggregate project will also
|
||||
run it on the aggregated projects. For example, ::
|
||||
|
||||
lazy val root =
|
||||
project.in( file(".") )
|
||||
.aggregate(util, core)
|
||||
|
||||
lazy val util = project
|
||||
|
||||
lazy val core = project
|
||||
|
||||
|
||||
In the above example, the root project aggregates `util` and `core`.
|
||||
Start up sbt with two subprojects as in the example, and try `compile`.
|
||||
You should see that all three projects are compiled.
|
||||
|
||||
*In the project doing the aggregating*, the `root` project in
|
||||
this case, you can control aggregation per-task.
|
||||
For example, to avoid aggregating the `update` task:
|
||||
|
||||
::
|
||||
|
||||
import sbt._
|
||||
import Keys._
|
||||
lazy val root =
|
||||
project.in( file(".") )
|
||||
.aggregate(util, core)
|
||||
.settings(
|
||||
aggregate in update := false
|
||||
)
|
||||
|
||||
object HelloBuild extends Build {
|
||||
lazy val root = Project(id = "hello",
|
||||
base = file(".")) aggregate(foo, bar)
|
||||
[...]
|
||||
|
||||
lazy val foo = Project(id = "hello-foo",
|
||||
base = file("foo"))
|
||||
`aggregate in update` is the `aggregate` key scoped to the `update` task.
|
||||
(See :doc:`scopes <Scopes>`.)
|
||||
|
||||
lazy val bar = Project(id = "hello-bar",
|
||||
base = file("bar"))
|
||||
}
|
||||
Note: aggregation will run the aggregated tasks in parallel and with no
|
||||
defined ordering between them.
|
||||
|
||||
Classpath dependencies
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A project may depend on code in another project. This is done by adding
|
||||
a `dependsOn` method call. For example, if `core` needed
|
||||
`util` on its classpath, you would define `core` as:
|
||||
|
||||
::
|
||||
|
||||
lazy val core = project.dependsOn(util)
|
||||
|
||||
Now code in `core` can use classes from `util`.
|
||||
This also creates an ordering between the projects when compiling them;
|
||||
`util` must be updated and compiled before `core` can be compiled.
|
||||
|
||||
To depend on multiple projects, use multiple arguments to `dependsOn`,
|
||||
like `dependsOn(bar, baz)`.
|
||||
|
||||
Per-configuration classpath dependencies
|
||||
++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
`foo dependsOn(bar)` means that the `compile` configuration in
|
||||
`foo` depends on the `compile` configuration in `bar`. You could
|
||||
write this explicitly as `dependsOn(bar % "compile->compile")`.
|
||||
|
||||
The `->` in `"compile->compile"` means "depends on" so
|
||||
`"test->compile"` means the `test` configuration in `foo` would
|
||||
depend on the `compile` configuration in `bar`.
|
||||
|
||||
Omitting the `->config` part implies `->compile`, so
|
||||
`dependsOn(bar % "test")` means that the `test` configuration in
|
||||
`foo` depends on the `Compile` configuration in `bar`.
|
||||
|
||||
A useful declaration is `"test->test"` which means `test` depends on `test`.
|
||||
This allows you to put utility code for testing in `bar/src/test/scala` and then use that code in `foo/src/test/scala`,
|
||||
for example.
|
||||
|
||||
You can have multiple configurations for a dependency, separated by
|
||||
semicolons. For example,
|
||||
`dependsOn(bar % "test->test;compile->compile")`.
|
||||
|
||||
|
||||
Default root project
|
||||
--------------------
|
||||
|
||||
If a project is not defined for the root directory in the build, sbt creates a default
|
||||
one that aggregates all other projects in the build.
|
||||
|
||||
sbt finds the list of `Project` objects using reflection, looking for
|
||||
fields with type `Project` in the `Build` object.
|
||||
|
||||
Because project `hello-foo` is defined with `base = file("foo")`, it
|
||||
will be contained in the subdirectory `foo`. Its sources could be
|
||||
|
|
@ -93,79 +177,6 @@ You may find it cleaner to put everything including settings in
|
|||
You cannot have a `project` subdirectory or `project/*.scala` files
|
||||
in the sub-projects. `foo/project/Build.scala` would be ignored.
|
||||
|
||||
Aggregation
|
||||
-----------
|
||||
|
||||
Projects in the build can be completely independent of one another, if
|
||||
you want.
|
||||
|
||||
In the above example, however, you can see the method call
|
||||
`aggregate(foo, bar)`. This aggregates `hello-foo` and `hello-bar`
|
||||
underneath the root project.
|
||||
|
||||
Aggregation means that running a task on the aggregate project will also
|
||||
run it on the aggregated projects. Start up sbt with two subprojects as
|
||||
in the example, and try `compile`. You should see that all three
|
||||
projects are compiled.
|
||||
|
||||
*In the project doing the aggregating*, the root `hello` project in
|
||||
this case, you can control aggregation per-task. So for example in
|
||||
`hello/build.sbt` you could avoid aggregating the `update` task:
|
||||
|
||||
::
|
||||
|
||||
aggregate in update := false
|
||||
|
||||
`aggregate in update` is the `aggregate` key scoped to the
|
||||
`update` task, see :doc:`scopes <Scopes>`.
|
||||
|
||||
Note: aggregation will run the aggregated tasks in parallel and with no
|
||||
defined ordering.
|
||||
|
||||
Classpath dependencies
|
||||
----------------------
|
||||
|
||||
A project may depend on code in another project. This is done by adding
|
||||
a `dependsOn` method call. For example, if `hello-foo` needed
|
||||
`hello-bar` on its classpath, you would write in your `Build.scala`:
|
||||
|
||||
::
|
||||
|
||||
lazy val foo = Project(id = "hello-foo",
|
||||
base = file("foo")) dependsOn(bar)
|
||||
|
||||
Now code in `hello-foo` can use classes from `hello-bar`. This also
|
||||
creates an ordering between the projects when compiling them;
|
||||
`hello-bar` must be updated and compiled before `hello-foo` can be
|
||||
compiled.
|
||||
|
||||
To depend on multiple projects, use multiple arguments to `dependsOn`,
|
||||
like `dependsOn(bar, baz)`.
|
||||
|
||||
Per-configuration classpath dependencies
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
`foo dependsOn(bar)` means that the `Compile` configuration in
|
||||
`foo` depends on the `Compile` configuration in `bar`. You could
|
||||
write this explicitly as `dependsOn(bar % "compile->compile")`.
|
||||
|
||||
The `->` in `"compile->compile"` means "depends on" so
|
||||
`"test->compile"` means the `Test` configuration in `foo` would
|
||||
depend on the `Compile` configuration in `bar`.
|
||||
|
||||
Omitting the `->config` part implies `->compile`, so
|
||||
`dependsOn(bar % "test")` means that the `Test` configuration in
|
||||
`foo` depends on the `Compile` configuration in `bar`.
|
||||
|
||||
A useful declaration is `"test->test"` which means `Test` depends on
|
||||
`Test`. This allows you to put utility code for testing in
|
||||
`bar/src/test/scala` and then use that code in `foo/src/test/scala`,
|
||||
for example.
|
||||
|
||||
You can have multiple configurations for a dependency, separated by
|
||||
semicolons. For example,
|
||||
`dependsOn(bar % "test->test;compile->compile")`.
|
||||
|
||||
Navigating projects interactively
|
||||
---------------------------------
|
||||
|
||||
|
|
@ -175,7 +186,35 @@ a task like `compile`, it runs on the current project. So you don't
|
|||
necessarily have to compile the root project, you could compile only a
|
||||
subproject.
|
||||
|
||||
You can run a task in another project by explicitly specifying the
|
||||
project ID, such as `subProjectID/compile`.
|
||||
|
||||
Common code
|
||||
-----------
|
||||
|
||||
The definitions in `.sbt` files are not visible in other `.sbt` files.
|
||||
In order to share code between `.sbt` files, define one or more Scala
|
||||
files in the `project/` directory of the build root. This directory
|
||||
is also an sbt project, but for your build.
|
||||
|
||||
For example:
|
||||
|
||||
`<root>/project/Common.scala` ::
|
||||
|
||||
import sbt._
|
||||
import Keys._
|
||||
|
||||
object Common {
|
||||
def text = "org.example"
|
||||
}
|
||||
|
||||
`<root>`/build.sbt ::
|
||||
|
||||
organization := Common.text
|
||||
|
||||
See :doc:`Full-Def` for details.
|
||||
|
||||
Next
|
||||
----
|
||||
|
||||
Move on to create :doc:`custom settings <Custom-Settings>`.
|
||||
Move on to :doc:`using plugins <Using-Plugins>`.
|
||||
|
|
|
|||
|
|
@ -3,225 +3,66 @@ Using Plugins
|
|||
=============
|
||||
|
||||
Please read the earlier pages in the Getting Started Guide first, in
|
||||
particular you need to understand :doc:`build.sbt <Basic-Def>`,
|
||||
particular you need to understand :doc:`build.sbt <Basic-Def>` and
|
||||
:doc:`library dependencies <Library-Dependencies>`,
|
||||
and :doc:`.scala build definition <Full-Def>` before reading
|
||||
this page.
|
||||
before reading this page.
|
||||
|
||||
What is a plugin?
|
||||
-----------------
|
||||
|
||||
A plugin extends the build definition, most commonly by adding new
|
||||
settings. The new settings could be new tasks. For example, a plugin
|
||||
could add a `code-coverage` task which would generate a test coverage
|
||||
could add a `codeCoverage` task which would generate a test coverage
|
||||
report.
|
||||
|
||||
Adding a plugin
|
||||
---------------
|
||||
Declaring a plugin
|
||||
------------------
|
||||
|
||||
The short answer
|
||||
~~~~~~~~~~~~~~~~
|
||||
If your project is in directory `hello`, edit `hello/project/plugins.sbt` and declare the plugin dependency by passing the plugin's Ivy module ID to `addSbtPlugin`: ::
|
||||
|
||||
If your project is in directory `hello`, edit
|
||||
`hello/project/build.sbt` and add the plugin location as a resolver,
|
||||
then call `addSbtPlugin` with the plugin's Ivy module ID:
|
||||
addSbtPlugin("com.typesafe.sbt" % "sbt-site" % "0.7.0")
|
||||
|
||||
::
|
||||
Not every plugin is located on one of the default repositories and a plugin's documentation may instruct you to also add the repository where it can be found: ::
|
||||
|
||||
resolvers += Classpaths.typesafeResolver
|
||||
resolvers += ...
|
||||
|
||||
addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.0.0")
|
||||
Plugins usually provide settings that get added to a project to enable the plugin's functionality.
|
||||
This is described in the next section.
|
||||
|
||||
|
||||
Adding settings for a plugin
|
||||
----------------------------
|
||||
|
||||
A plugin can declare that its settings be automatically added, in which case you don't have to do anything to add them.
|
||||
However, plugins often avoid this because you wouldn't control which projects in a :doc:`multi-project build <Multi-Project>` would use the plugin.
|
||||
The plugin documentation will indicate how to configure it, but typically it involves adding the base settings for the plugin and customizing as necessary.
|
||||
|
||||
For example, for the sbt-site plugin, add ::
|
||||
|
||||
site.settings
|
||||
|
||||
to a `build.sbt` to enable it for that project.
|
||||
|
||||
If the build defines multiple projects, instead add it directly to the project: ::
|
||||
|
||||
// don't use the site plugin for the `util` project
|
||||
lazy val util = project
|
||||
|
||||
// enable the site plugin for the `core` project
|
||||
lazy val core = project.settings( site.settings : _*)
|
||||
|
||||
If the plugin were located on one of the default repositories, you
|
||||
wouldn't have to add a resolver, of course.
|
||||
|
||||
Global plugins
|
||||
~~~~~~~~~~~~~~
|
||||
--------------
|
||||
|
||||
Plugins can be installed for all your projects at once by dropping them
|
||||
in `~/.sbt/plugins/`. `~/.sbt/plugins/` is an sbt project whose
|
||||
classpath is exported to all sbt build definition projects. Roughly
|
||||
speaking, any `.sbt` files in `~/.sbt/plugins/` behave as if they
|
||||
were in the `project/` directory for all projects, and any `.scala`
|
||||
files in `~/.sbt/plugins/project/` behave as if they were in the
|
||||
`project/project/` directory for all projects.
|
||||
Plugins can be installed for all your projects at once by dropping them in :sublit:`|globalPluginsBase|`.
|
||||
:sublit:`|globalPluginsBase|` is an sbt project whose classpath is exported to all sbt build definition projects.
|
||||
Roughly speaking, any `.sbt` or `.scala` files in :sublit:`|globalPluginsBase|` behave as if they were in the `project/` directory for all projects.
|
||||
|
||||
You can create `~/.sbt/plugins/build.sbt` and put `addSbtPlugin()`
|
||||
You can create :sublit:`|globalPluginsBase|\ build.sbt` and put `addSbtPlugin()`
|
||||
expressions in there to add plugins to all your projects at once.
|
||||
|
||||
How it works
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Be sure you understand the :doc:`recursive nature of sbt projects <Full-Def>`
|
||||
described earlier and how to add a :doc:`managed dependency <Library-Dependencies>`.
|
||||
|
||||
Dependencies for the build definition
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Adding a plugin means *adding a library dependency to the build
|
||||
definition*. To do that, you edit the build definition for the build
|
||||
definition.
|
||||
|
||||
Recall that for a project `hello`, its build definition project lives
|
||||
in `hello/*.sbt` and `hello/project/*.scala`:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
|
||||
hello/ # your project's base directory
|
||||
|
||||
build.sbt # build.sbt is part of the source code for the
|
||||
# build definition project inside project/
|
||||
|
||||
project/ # base directory of the build definition project
|
||||
|
||||
Build.scala # a source file in the project/ project,
|
||||
# that is, a source file in the build definition
|
||||
|
||||
If you wanted to add a managed dependency to project `hello`, you
|
||||
would add to the `libraryDependencies` setting either in
|
||||
`hello/*.sbt` or `hello/project/*.scala`.
|
||||
|
||||
You could add this in `hello/build.sbt`:
|
||||
|
||||
::
|
||||
|
||||
libraryDependencies += "org.apache.derby" % "derby" % "10.4.1.3" % "test"
|
||||
|
||||
If you add that and start up the sbt interactive mode and type
|
||||
`show dependencyClasspath`, you should see the derby jar on your
|
||||
classpath.
|
||||
|
||||
To add a plugin, do the same thing but recursed one level. We want the
|
||||
*build definition project* to have a new dependency. That means changing
|
||||
the `libraryDependencies` setting for the build definition of the
|
||||
build definition.
|
||||
|
||||
The build definition of the build definition, if your project is
|
||||
`hello`, would be in `hello/project/*.sbt` and
|
||||
`hello/project/project/*.scala`.
|
||||
|
||||
The simplest "plugin" has no special sbt support; it's just a jar file.
|
||||
For example, edit `hello/project/build.sbt` and add this line:
|
||||
|
||||
::
|
||||
|
||||
libraryDependencies += "net.liftweb" % "lift-json" % "2.0"
|
||||
|
||||
Now, at the sbt interactive prompt, `reload plugins` to enter the
|
||||
build definition project, and try `show dependencyClasspath`. You
|
||||
should see the lift-json jar on the classpath. This means: you could use
|
||||
classes from lift-json in your `Build.scala` or `build.sbt` to
|
||||
implement a task. You could parse a JSON file and generate other files
|
||||
based on it, for example. Remember, use `reload return` to leave the
|
||||
build definition project and go back to the parent project.
|
||||
|
||||
(Stupid sbt trick: type `reload plugins` over and over. You'll find
|
||||
yourself in the project rooted in
|
||||
`project/project/project/project/project/project/`. Don't worry, it
|
||||
isn't useful. Also, it creates `target` directories all the way down,
|
||||
which you'll have to clean up.)
|
||||
|
||||
`addSbtPlugin`
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
`addSbtPlugin` is just a convenience method. Here's its definition:
|
||||
|
||||
::
|
||||
|
||||
def addSbtPlugin(dependency: ModuleID): Setting[Seq[ModuleID]] =
|
||||
libraryDependencies +=
|
||||
sbtPluginExtra(dependency, (sbtVersion in update).value, scalaVersion.value)
|
||||
|
||||
The appended dependency is based on `sbtVersion in update`
|
||||
(sbt's version scoped to the `update` task) and `scalaVersion` (the
|
||||
version of scala used to compile the project, in this case used to
|
||||
compile the build definition). `sbtPluginExtra` adds the sbt and Scala
|
||||
version information to the module ID.
|
||||
|
||||
`plugins.sbt`
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
Some people like to list plugin dependencies (for a project `hello`)
|
||||
in `hello/project/plugins.sbt` to avoid confusion with
|
||||
`hello/build.sbt`. sbt does not care what `.sbt` files are called,
|
||||
so both `build.sbt` and `project/plugins.sbt` are conventions. sbt
|
||||
*does* of course care where the sbt files are *located*. `hello/*.sbt`
|
||||
would contain dependencies for `hello` and `hello/project/*.sbt`
|
||||
would contain dependencies for `hello`'s build definition.
|
||||
|
||||
Plugins can add settings and imports automatically
|
||||
--------------------------------------------------
|
||||
|
||||
In one sense a plugin is just a jar added to `libraryDependencies` for
|
||||
the build definition; you can then use the jar from build definition
|
||||
code as in the lift-json example above.
|
||||
|
||||
However, jars intended for use as sbt plugins can do more.
|
||||
|
||||
If you download a plugin jar (`here's one for
|
||||
sbteclipse <http://repo.typesafe.com/typesafe/ivy-releases/com.typesafe.sbteclipse/sbteclipse/scala_2.9.1/sbt_0.11.0/1.4.0/jars/sbteclipse.jar>`_)
|
||||
and unpack it with `jar xf`, you'll see that it contains a text file
|
||||
`sbt/sbt.plugins`. In `sbt/sbt.plugins` there's an object name on
|
||||
each line like this:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
com.typesafe.sbteclipse.SbtEclipsePlugin
|
||||
|
||||
`com.typesafe.sbteclipse.SbtEclipsePlugin` is the name of an object
|
||||
that extends `sbt.Plugin`. The `sbt.Plugin` trait is very simple:
|
||||
|
||||
::
|
||||
|
||||
trait Plugin {
|
||||
def settings: Seq[Setting[_]] = Nil
|
||||
}
|
||||
|
||||
sbt looks for objects listed in `sbt/sbt.plugins`. When it finds
|
||||
`com.typesafe.sbteclipse.SbtEclipsePlugin`, it adds
|
||||
`com.typesafe.sbteclipse.SbtEclipsePlugin.settings` to the settings
|
||||
for the project. It also does
|
||||
`import com.typesafe.sbteclipse.SbtEclipsePlugin._` for any `.sbt`
|
||||
files, allowing a plugin to provide values, objects, and methods to
|
||||
`.sbt` files in the build definition.
|
||||
|
||||
Adding settings manually from a plugin
|
||||
--------------------------------------
|
||||
|
||||
If a plugin defines settings in the `settings` field of a `Plugin`
|
||||
object, you don't have to do anything to add them.
|
||||
|
||||
However, plugins often avoid this because you could not control which
|
||||
projects in a :doc:`multi-project build <Multi-Project>` would use the plugin.
|
||||
|
||||
A whole batch of settings can be added by directly referencing the sequence of settings in a `build.sbt` file. So, if a plugin has something like this:
|
||||
|
||||
::
|
||||
|
||||
object MyPlugin extends Plugin {
|
||||
val myPluginSettings = Seq(settings in here)
|
||||
}
|
||||
|
||||
You could add all those settings in `build.sbt` with this syntax:
|
||||
|
||||
::
|
||||
|
||||
myPluginSettings
|
||||
|
||||
Creating a plugin
|
||||
-----------------
|
||||
|
||||
After reading this far, you pretty much know how to *create* an sbt
|
||||
plugin as well. There's one trick to know; set `sbtPlugin := true` in
|
||||
`build.sbt`. If `sbtPlugin` is true, the project will scan its
|
||||
compiled classes for instances of `Plugin`, and list them in
|
||||
`sbt/sbt.plugins` when it packages a jar. `sbtPlugin := true` also
|
||||
adds sbt to the project's classpath, so you can use sbt APIs to
|
||||
implement your plugin.
|
||||
|
||||
Learn more about creating a plugin at :doc:`/Extending/Plugins`
|
||||
and :doc:`/Extending/Plugins-Best-Practices`.
|
||||
This feature should be used sparingly, however.
|
||||
See :ref:`Best Practices <global-vs-local-plugins>`.
|
||||
|
||||
Available Plugins
|
||||
-----------------
|
||||
|
|
@ -236,7 +77,32 @@ Some especially popular plugins are:
|
|||
|
||||
:doc:`Check out the list</Community/Community-Plugins>`.
|
||||
|
||||
|
||||
Creating a Plugin
|
||||
-----------------
|
||||
|
||||
A minimal plugin is a Scala library that is built against the version of Scala that sbt runs, which is currently |scalaVersion|.
|
||||
Nothing special needs to be done for this type of plugin.
|
||||
It can be published as a normal project and declared in `project/plugins.sbt` like a normal dependency (without `addSbtPlugin`).
|
||||
|
||||
A more typical plugin will provide sbt tasks, commands, or settings.
|
||||
This kind of plugin may provide these settings automatically or make them available for the user to explicitly integrate.
|
||||
To create an sbt plugin,
|
||||
|
||||
1. Create a new project for the plugin.
|
||||
2. Set `sbtPlugin := true` for the project in `build.sbt`. This adds a dependency on sbt and will detect and record Plugins that you define.
|
||||
3. (optional) Define an `object` that extends `Plugin`. The contents of this object will be automatically imported in `.sbt` files, so ensure it only contains important API definitions and types.
|
||||
4. Define any custom tasks or settings (see the next section :doc:`Custom-Settings`).
|
||||
5. Collect the default settings to apply to a project in a list for the user to add. Optionally override one or more of Plugin's methods to have settings automatically added to user projects.
|
||||
6. Publish the project. There is a :doc:`community repository </Community/Community-Plugins>` available for open source plugins.
|
||||
|
||||
For more details, including ways of developing plugins, see :doc:`/Extending/Plugins`.
|
||||
For best practices, see :doc:`/Extending/Plugins-Best-Practices`.
|
||||
|
||||
Next
|
||||
----
|
||||
|
||||
Move on to :doc:`multi-project builds <Multi-Project>`.
|
||||
Move on to create :doc:`custom settings <Custom-Settings>`.
|
||||
|
||||
.. |globalBase| replace:: ~/.sbt/|version|/
|
||||
.. |globalPluginsBase| replace:: |globalBase|\ plugins/
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ Getting Started
|
|||
Scopes
|
||||
More-About-Settings
|
||||
Library-Dependencies
|
||||
Full-Def
|
||||
Using-Plugins
|
||||
Multi-Project
|
||||
Using-Plugins
|
||||
Custom-Settings
|
||||
Full-Def
|
||||
Summary
|
||||
|
|
|
|||
Loading…
Reference in New Issue