diff --git a/src/sphinx/Extending/Plugins-Best-Practices.rst b/src/sphinx/Extending/Plugins-Best-Practices.rst index 6b4d80564..c7adb5655 100644 --- a/src/sphinx/Extending/Plugins-Best-Practices.rst +++ b/src/sphinx/Extending/Plugins-Best-Practices.rst @@ -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 ------------------- diff --git a/src/sphinx/Extending/Plugins.rst b/src/sphinx/Extending/Plugins.rst index 18cae5ee6..3d510a8ba 100644 --- a/src/sphinx/Extending/Plugins.rst +++ b/src/sphinx/Extending/Plugins.rst @@ -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 ---------------------- diff --git a/src/sphinx/Getting-Started/Using-Plugins.rst b/src/sphinx/Getting-Started/Using-Plugins.rst index 5dfc05db9..57dcc0a1d 100644 --- a/src/sphinx/Getting-Started/Using-Plugins.rst +++ b/src/sphinx/Getting-Started/Using-Plugins.rst @@ -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 ` 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 ` 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 ` available for open source plugins. For more details, including ways of developing plugins, see :doc:`/Extending/Plugins`.