Update documentation for AutoPlugins.

* Add notes about AutoPlugins vs. RootPlugins in Plugins section
* Modify best practices section to recomend using AutoPlugins.
* Modify Using-Plugins section in getting started to denote
  auto plugins.
This commit is contained in:
Josh Suereth 2014-03-06 13:57:07 -05:00
parent 01bb7ce2fd
commit ea8c0b32a7
3 changed files with 92 additions and 30 deletions

View File

@ -22,20 +22,12 @@ Don't use default package
Users who have their build files in some package will not be able to
use your plugin if it's defined in default (no-name) package.
Avoid overriding `settings`
-----------------------------
Avoid older `sbt.Plugin` mechanism
----------------------------------
sbt will automatically load your plugin's `settings` into the build.
Overriding `val settings` should only be done by plugins intending to
provide commands. Regular plugins defining tasks and settings should
provide a sequence named after the plugin like so:
::
val obfuscateSettings = Seq(...)
This allows build user to choose which subproject the plugin would be
used. See later section for how the settings should be scoped.
sbt has deprecated the old `sbt.Plugin` mechanism in favor of `sbt.AutoPlugin`.
The new mechanism features a set of user-level controls and dependency declarations
that cleans up a lot of long-standing issues with plugins.
Reuse existing keys
-------------------

View File

@ -176,6 +176,10 @@ It is recommended to explicitly specify the commit or tag by appending it to the
lazy val assemblyPlugin = uri("git://github.com/sbt/sbt-assembly#0.9.1")
One caveat to using this method is that the local sbt will try to run the remote plugin's build. It
is quite possible that the plugin's own build uses a different sbt version, as many plugins cross-publish for
several sbt versions. As such, it is recommended to stick with binary artifacts when possible.
2) Use the library
~~~~~~~~~~~~~~~~~~
@ -221,22 +225,25 @@ To make a plugin, create a project and configure `sbtPlugin` to
`true`. Then, write the plugin code and publish your project to a
repository. The plugin can be used as described in the previous section.
A plugin can implement `sbt.Plugin`. The contents of a Plugin
singleton, declared like `object MyPlugin extends Plugin`, are
A plugin can implement `sbt.AutoImpot`. The contents of an AutoImport
singleton, declared like `object MyPlugin extends AutoImport`, 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, a `Plugin` can implement `projectSettings`, `buildSettings`, and `globalSettings` as appropriate.
The Plugin's `projectSettings` is automatically appended to each project's settings.
In addition, a plugin can implement the `AutoPlugin` class. This has additoinal features, such as
* Specifying plugin dependencies.
* Specifying `projectSettings`, `buildSettings`, and `globalSettings` as appropriate.
The AutoPlugin's `projectSettings` is automatically appended to each project's settings, when its dependencies also exist on that project
The `select` method defines the conditions by which this plugin's settings are automatically imported.
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
--------------
@ -258,16 +265,18 @@ An example of a typical plugin:
::
import sbt._
object MyPlugin extends Plugin
object MyPlugin extends AutoPlugin
{
// Only enable this plugin for projects which are JvmModules.
def select = sbt.plugins.JvmModule
// configuration points, like the built in `version`, `libraryDependencies`, or `compile`
// by implementing Plugin, these are automatically imported in a user's `build.sbt`
val newTask = taskKey[Unit]("A new task.")
val newSetting = settingKey[String]("A new setting.")
// a group of settings ready to be added to a Project
// to automatically add them, do
val newSettings = Seq(
// a group of settings that are automatically added to projects.
val projectSettings = Seq(
newSetting := "test",
newTask := println(newSetting.value)
)
@ -289,7 +298,17 @@ A build definition that uses the plugin might look like:
newSetting := "example"
Example command plugin
Root Plugins
------------
Some plugins should always be explicitly enabled on projects. Sbt calls these "RootPlugins", i.e. plugins
that are "root" nodes in the plugin depdendency graph. To define a root plugin, just extend the `sbt.RootPlugin`
interface. This interface is exactly like the `AutoPlugin` interface except that a `select` method is not
needed.
Example command root plugin
----------------------
A basic plugin that adds commands looks like:
@ -310,9 +329,9 @@ A basic plugin that adds commands looks like:
import sbt._
import Keys._
object MyPlugin extends Plugin
object MyPlugin extends RootPlugin
{
override lazy val settings = Seq(commands += myCommand)
override lazy val projectSettings = Seq(commands += myCommand)
lazy val myCommand =
Command.command("hello") { (state: State) =>
@ -327,6 +346,28 @@ included in one plugin (for example, use `commands ++= Seq(a,b)`). See
:doc:`Commands` for defining more useful commands, including ones that
accept arguments and affect the execution state.
For a user to consume this plugin, it requires an explicit include via the `Project` instance.
Here's what their local sbt will look like.
`build.sbt`
::
val root = Project("example-plugin-usage", file(".")).setPlugins(MyPlugin)
The `setPlugins` method allows projects to explicitly define the `RootPlugin`s they wish to consume.
`AutoPlugin`s are automatically added to the project as appropriate.
Projects can also exclude any type of plugin using the `disablePlugins` method. For example, if
we wish to remove the JvmModule settings (`compile`,`test`,`run`), we modify our `build.sbt` as
follows:
::
val root = Project("example-plugin-usage", file(".")).setPlugins(MyPlugin).disablePlugins(plugins.JvmModule)
Global plugins example
----------------------

View File

@ -34,8 +34,36 @@ 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.
As of sbt 0.13.2, there is a new :doc:`auto-plugins <../DetailedTopics/AutoPlugins>` feature that enables plugins
to automatically, and safely, ensure their settings and dependencies are on a project. Most plugins should have
their default settings automatically, however some may require explicit enablement.
If you're using a plugin that requires explicit enablement, then you you have to add the following to your
`build.sbt` ::
lazy val util = project.setPlugins(ThePluginIWant)
Most plugins document whether they need to explicitly enabled. If you're curious which plugins are enabled
for a given project, just run the `plugins` command on the sbt console.
For example ::
> plugins
In file:/home/jsuereth/projects/sbt/test-ivy-issues/
sbt.plugins.IvyModule: enabled in test-ivy-issues
sbt.plugins.JvmModule: enabled in test-ivy-issues
sbt.plugins.GlobalModule: enabled in test-ivy-issues
Here, the plugins output is showing that the sbt default plugins are all enabled. Sbt's default settings are provided via three plugins:
1. GlobalModule: Provides the core parallelism controls for tasks
2. IvyModule: Provides the mechanisms to publish/resolve modules.
3. JvmModule: Provides the mechanisms to compile/test/run/package Java/Scala projects.
However, older plugins often required settings to be added explictly, so that :doc:`multi-project build <Multi-Project>` could have different types of projects. The plugin documentation will indicate how to configure it, but typically for older plugins this involves adding the base settings for the plugin and customizing as necessary.
For example, for the sbt-site plugin, add ::
@ -91,9 +119,10 @@ 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.
3. Define an `object` that extends `AutoPlugin` or `RootPlugin`. 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.
5. Collect the default settings to apply to a project in a list for the user to add. Optionally override one or more of `AutoPlugin`'s methods to have settings automatically added to user projects.
6. (Optional) For non-root plguins, declare dependencies on other plugins by overriding the `select` method.
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`.