initial refresh of getting started guide for 0.13: multiple projects and plugins

still todo: Custom-Settings, Full-Def
This commit is contained in:
Mark Harrah 2013-08-07 18:24:19 -04:00
parent 6d981e4c5b
commit 70a54b9848
8 changed files with 253 additions and 369 deletions

View File

@ -4,6 +4,8 @@ Best Practices
This page describes best practices for working with sbt.
.. _global-vs-local-plugins:
`project/` vs. `~/.sbt/`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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