mirror of https://github.com/sbt/sbt.git
Unifies AutoPlugin and AutoImport. Fixes #1188
* AutoImport trait is subsumed by def autoImport method under AutoPlugin class. * When def autoImport is overridden by a lazy val or a val, *.sbt automatically imports autoImport._.
This commit is contained in:
parent
4315049337
commit
2c654b2d90
|
|
@ -89,16 +89,22 @@ final class DetectedModules[T](val modules: Seq[(String, T)])
|
||||||
def values: Seq[T] = modules.map(_._2)
|
def values: Seq[T] = modules.map(_._2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Auto-detected auto plugin. */
|
||||||
|
case class DetectedAutoPlugin(val name: String, val value: AutoPlugin, val hasStableAutoImport: Boolean)
|
||||||
|
|
||||||
/** Auto-discovered modules for the build definition project. These include modules defined in build definition sources
|
/** Auto-discovered modules for the build definition project. These include modules defined in build definition sources
|
||||||
* as well as modules in binary dependencies.
|
* as well as modules in binary dependencies.
|
||||||
*
|
*
|
||||||
* @param builds The [[Build]]s detected in the build definition. This does not include the default [[Build]] that sbt creates if none is defined.
|
* @param builds The [[Build]]s detected in the build definition. This does not include the default [[Build]] that sbt creates if none is defined.
|
||||||
*/
|
*/
|
||||||
final class DetectedPlugins(val plugins: DetectedModules[Plugin], val autoImports: DetectedModules[AutoImport], val autoPlugins: DetectedModules[AutoPlugin], val builds: DetectedModules[Build])
|
final class DetectedPlugins(val plugins: DetectedModules[Plugin], val autoPlugins: Seq[DetectedAutoPlugin], val builds: DetectedModules[Build])
|
||||||
{
|
{
|
||||||
/** Sequence of import expressions for the build definition. This includes the names of the [[Plugin]], [[Build]], and [[AutoImport]] modules, but not the [[AutoPlugin]] modules. */
|
/** Sequence of import expressions for the build definition. This includes the names of the [[Plugin]], [[Build]], and [[AutoImport]] modules, but not the [[AutoPlugin]] modules. */
|
||||||
lazy val imports: Seq[String] = BuildUtil.getImports(plugins.names ++ builds.names ++ autoImports.names)
|
lazy val imports: Seq[String] = BuildUtil.getImports(plugins.names ++ builds.names ++
|
||||||
|
(autoPlugins flatMap { case DetectedAutoPlugin(name, ap, hasAutoImport) =>
|
||||||
|
if (hasAutoImport) Some(name + ".autoImport")
|
||||||
|
else None
|
||||||
|
}))
|
||||||
/** A function to select the right [[AutoPlugin]]s from [[autoPlugins]] for a [[Project]]. */
|
/** A function to select the right [[AutoPlugin]]s from [[autoPlugins]] for a [[Project]]. */
|
||||||
lazy val deducePlugins: (Plugins, Logger) => Seq[AutoPlugin] = Plugins.deducer(autoPlugins.values.toList)
|
lazy val deducePlugins: (Plugins, Logger) => Seq[AutoPlugin] = Plugins.deducer(autoPlugins.values.toList)
|
||||||
}
|
}
|
||||||
|
|
@ -115,7 +121,7 @@ final class LoadedPlugins(val base: File, val pluginData: PluginData, val loader
|
||||||
@deprecated("Use the primary constructor.", "0.13.2")
|
@deprecated("Use the primary constructor.", "0.13.2")
|
||||||
def this(base: File, pluginData: PluginData, loader: ClassLoader, plugins: Seq[Plugin], pluginNames: Seq[String]) =
|
def this(base: File, pluginData: PluginData, loader: ClassLoader, plugins: Seq[Plugin], pluginNames: Seq[String]) =
|
||||||
this(base, pluginData, loader,
|
this(base, pluginData, loader,
|
||||||
new DetectedPlugins(new DetectedModules(pluginNames zip plugins), new DetectedModules(Nil), new DetectedModules(Nil), new DetectedModules(Nil))
|
new DetectedPlugins(new DetectedModules(pluginNames zip plugins), Nil, new DetectedModules(Nil))
|
||||||
)
|
)
|
||||||
|
|
||||||
@deprecated("Use detected.plugins.values.", "0.13.2")
|
@deprecated("Use detected.plugins.values.", "0.13.2")
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,7 @@ object Keys
|
||||||
val crossVersion = SettingKey[CrossVersion]("cross-version", "Configures handling of the Scala version when cross-building.", CSetting)
|
val crossVersion = SettingKey[CrossVersion]("cross-version", "Configures handling of the Scala version when cross-building.", CSetting)
|
||||||
val classpathOptions = SettingKey[ClasspathOptions]("classpath-options", "Configures handling of Scala classpaths.", DSetting)
|
val classpathOptions = SettingKey[ClasspathOptions]("classpath-options", "Configures handling of Scala classpaths.", DSetting)
|
||||||
val definedSbtPlugins = TaskKey[Set[String]]("defined-sbt-plugins", "The set of names of Plugin implementations defined by this project.", CTask)
|
val definedSbtPlugins = TaskKey[Set[String]]("defined-sbt-plugins", "The set of names of Plugin implementations defined by this project.", CTask)
|
||||||
val discoveredSbtPlugins = TaskKey[PluginDiscovery.DiscoveredNames]("discovered-sbt-plugins", "The names of sbt plugin-related modules (modules that extend Build, Plugin, AutoImport, AutoPlugin) defined by this project.", CTask)
|
val discoveredSbtPlugins = TaskKey[PluginDiscovery.DiscoveredNames]("discovered-sbt-plugins", "The names of sbt plugin-related modules (modules that extend Build, Plugin, AutoPlugin) defined by this project.", CTask)
|
||||||
val sbtPlugin = SettingKey[Boolean]("sbt-plugin", "If true, enables adding sbt as a dependency and auto-generation of the plugin descriptor file.", BMinusSetting)
|
val sbtPlugin = SettingKey[Boolean]("sbt-plugin", "If true, enables adding sbt as a dependency and auto-generation of the plugin descriptor file.", BMinusSetting)
|
||||||
val printWarnings = TaskKey[Unit]("print-warnings", "Shows warnings from compilation, including ones that weren't printed initially.", BPlusTask)
|
val printWarnings = TaskKey[Unit]("print-warnings", "Shows warnings from compilation, including ones that weren't printed initially.", BPlusTask)
|
||||||
val fileInputOptions = SettingKey[Seq[String]]("file-input-options", "Options that take file input, which may invalidate the cache.", CSetting)
|
val fileInputOptions = SettingKey[Seq[String]]("file-input-options", "Options that take file input, which may invalidate the cache.", CSetting)
|
||||||
|
|
|
||||||
|
|
@ -125,7 +125,7 @@ object BuiltinCommands
|
||||||
|
|
||||||
def aboutPlugins(e: Extracted): String =
|
def aboutPlugins(e: Extracted): String =
|
||||||
{
|
{
|
||||||
def list(b: BuildUnit) = b.plugins.detected.autoPlugins.values.map(_.label) ++ b.plugins.detected.plugins.names
|
def list(b: BuildUnit) = b.plugins.detected.autoPlugins.map(_.value.label) ++ b.plugins.detected.plugins.names
|
||||||
val allPluginNames = e.structure.units.values.flatMap(u => list(u.unit)).toSeq.distinct
|
val allPluginNames = e.structure.units.values.flatMap(u => list(u.unit)).toSeq.distinct
|
||||||
if(allPluginNames.isEmpty) "" else allPluginNames.mkString("Available Plugins: ", ", ", "")
|
if(allPluginNames.isEmpty) "" else allPluginNames.mkString("Available Plugins: ", ", ", "")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,12 +15,11 @@ object PluginDiscovery
|
||||||
final val AutoPlugins = "sbt/sbt.autoplugins"
|
final val AutoPlugins = "sbt/sbt.autoplugins"
|
||||||
final val Plugins = "sbt/sbt.plugins"
|
final val Plugins = "sbt/sbt.plugins"
|
||||||
final val Builds = "sbt/sbt.builds"
|
final val Builds = "sbt/sbt.builds"
|
||||||
final val AutoImports = "sbt/sbt.autoimports"
|
|
||||||
}
|
}
|
||||||
/** Names of top-level modules that subclass sbt plugin-related classes: [[Plugin]], [[AutoImport]], [[AutoPlugin]], and [[Build]]. */
|
/** Names of top-level modules that subclass sbt plugin-related classes: [[Plugin]], [[AutoPlugin]], and [[Build]]. */
|
||||||
final class DiscoveredNames(val plugins: Seq[String], val autoImports: Seq[String], val autoPlugins: Seq[String], val builds: Seq[String])
|
final class DiscoveredNames(val plugins: Seq[String], val autoPlugins: Seq[String], val builds: Seq[String])
|
||||||
|
|
||||||
def emptyDiscoveredNames: DiscoveredNames = new DiscoveredNames(Nil, Nil, Nil, Nil)
|
def emptyDiscoveredNames: DiscoveredNames = new DiscoveredNames(Nil, Nil, Nil)
|
||||||
|
|
||||||
/** Discovers and loads the sbt-plugin-related top-level modules from the classpath and source analysis in `data` and using the provided class `loader`. */
|
/** Discovers and loads the sbt-plugin-related top-level modules from the classpath and source analysis in `data` and using the provided class `loader`. */
|
||||||
def discoverAll(data: PluginData, loader: ClassLoader): DetectedPlugins =
|
def discoverAll(data: PluginData, loader: ClassLoader): DetectedPlugins =
|
||||||
|
|
@ -35,8 +34,10 @@ object PluginDiscovery
|
||||||
"sbt.plugins.GlobalModule" -> sbt.plugins.GlobalModule
|
"sbt.plugins.GlobalModule" -> sbt.plugins.GlobalModule
|
||||||
)
|
)
|
||||||
val detectedAutoPugins = discover[AutoPlugin](AutoPlugins)
|
val detectedAutoPugins = discover[AutoPlugin](AutoPlugins)
|
||||||
val allAutoPlugins = new DetectedModules(defaultAutoPlugins ++ detectedAutoPugins.modules)
|
val allAutoPlugins = (defaultAutoPlugins ++ detectedAutoPugins.modules) map { case (name, value) =>
|
||||||
new DetectedPlugins(discover[Plugin](Plugins), discover[AutoImport](AutoImports), allAutoPlugins, discover[Build](Builds))
|
DetectedAutoPlugin(name, value, sbt.Plugins.hasStableAutoImport(value, loader))
|
||||||
|
}
|
||||||
|
new DetectedPlugins(discover[Plugin](Plugins), allAutoPlugins, discover[Build](Builds))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Discovers the sbt-plugin-related top-level modules from the provided source `analysis`. */
|
/** Discovers the sbt-plugin-related top-level modules from the provided source `analysis`. */
|
||||||
|
|
@ -44,7 +45,7 @@ object PluginDiscovery
|
||||||
{
|
{
|
||||||
def discover[T](implicit mf: reflect.ClassManifest[T]): Seq[String] =
|
def discover[T](implicit mf: reflect.ClassManifest[T]): Seq[String] =
|
||||||
sourceModuleNames(analysis, mf.erasure.getName)
|
sourceModuleNames(analysis, mf.erasure.getName)
|
||||||
new DiscoveredNames(discover[Plugin], discover[AutoImport], discover[AutoPlugin], discover[Build])
|
new DiscoveredNames(discover[Plugin], discover[AutoPlugin], discover[Build])
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: for 0.14.0, consider consolidating into a single file, which would make the classpath search 4x faster
|
// TODO: for 0.14.0, consider consolidating into a single file, which would make the classpath search 4x faster
|
||||||
|
|
@ -56,7 +57,6 @@ object PluginDiscovery
|
||||||
writeDescriptor(names.plugins, dir, Plugins) ::
|
writeDescriptor(names.plugins, dir, Plugins) ::
|
||||||
writeDescriptor(names.autoPlugins, dir, AutoPlugins) ::
|
writeDescriptor(names.autoPlugins, dir, AutoPlugins) ::
|
||||||
writeDescriptor(names.builds, dir, Builds) ::
|
writeDescriptor(names.builds, dir, Builds) ::
|
||||||
writeDescriptor(names.autoImports, dir, AutoImports) ::
|
|
||||||
Nil
|
Nil
|
||||||
files.flatMap(_.toList)
|
files.flatMap(_.toList)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,6 @@ TODO:
|
||||||
import Plugins._
|
import Plugins._
|
||||||
import annotation.tailrec
|
import annotation.tailrec
|
||||||
|
|
||||||
/** Marks a top-level object so that sbt will wildcard import it for .sbt files, `consoleProject`, and `set`. */
|
|
||||||
trait AutoImport
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
An AutoPlugin defines a group of settings and the conditions where the settings are automatically added to a build (called "activation").
|
An AutoPlugin defines a group of settings and the conditions where the settings are automatically added to a build (called "activation").
|
||||||
The `requires` and `trigger` methods together define the conditions, and a method like `projectSettings` defines the settings to add.
|
The `requires` and `trigger` methods together define the conditions, and a method like `projectSettings` defines the settings to add.
|
||||||
|
|
@ -66,6 +63,10 @@ abstract class AutoPlugin extends Plugins.Basic with PluginsFunctions
|
||||||
|
|
||||||
override def toString: String = label
|
override def toString: String = label
|
||||||
|
|
||||||
|
/** When this method is overridden with a val or a lazy val, `autoImport._` is automatically
|
||||||
|
* imported to *.sbt scripts. */
|
||||||
|
def autoImport: Any = ()
|
||||||
|
|
||||||
/** The [[Configuration]]s to add to each project that activates this AutoPlugin.*/
|
/** The [[Configuration]]s to add to each project that activates this AutoPlugin.*/
|
||||||
def projectConfigurations: Seq[Configuration] = Nil
|
def projectConfigurations: Seq[Configuration] = Nil
|
||||||
|
|
||||||
|
|
@ -307,4 +308,16 @@ ${listConflicts(conflicting)}""")
|
||||||
case Exclude(a) => !model(a)
|
case Exclude(a) => !model(a)
|
||||||
case ap: AutoPlugin => model(ap)
|
case ap: AutoPlugin => model(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private[sbt] def hasStableAutoImport(ap: AutoPlugin, loader: ClassLoader): Boolean = {
|
||||||
|
import reflect.runtime.{universe => ru}
|
||||||
|
import util.control.Exception.catching
|
||||||
|
val m = ru.runtimeMirror(loader)
|
||||||
|
val im = m.reflect(ap)
|
||||||
|
val fmOpt = catching(classOf[ScalaReflectionException]) opt {
|
||||||
|
val autoImportSym = im.symbol.asType.toType.declaration(ru.newTermName("autoImport")).asTerm
|
||||||
|
im.reflectField(autoImportSym)
|
||||||
|
}
|
||||||
|
fmOpt.isDefined
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -108,7 +108,7 @@ private[sbt] object PluginsDebug
|
||||||
structure.units.values.toList.flatMap(availableAutoPlugins).map(plugin => (plugin.label, plugin)).toMap
|
structure.units.values.toList.flatMap(availableAutoPlugins).map(plugin => (plugin.label, plugin)).toMap
|
||||||
}
|
}
|
||||||
private[this] def availableAutoPlugins(build: LoadedBuildUnit): Seq[AutoPlugin] =
|
private[this] def availableAutoPlugins(build: LoadedBuildUnit): Seq[AutoPlugin] =
|
||||||
build.unit.plugins.detected.autoPlugins.values
|
build.unit.plugins.detected.autoPlugins map {_.value}
|
||||||
|
|
||||||
def help(plugin: AutoPlugin, s: State): String =
|
def help(plugin: AutoPlugin, s: State): String =
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import sbttest.{Q}
|
||||||
|
|
||||||
// disablePlugins(Q) will prevent R from being auto-added
|
// disablePlugins(Q) will prevent R from being auto-added
|
||||||
lazy val projA = project.addPlugins(A, B).disablePlugins(Q)
|
lazy val projA = project.addPlugins(A, B).disablePlugins(Q)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
|
package sbttest // you need package http://stackoverflow.com/questions/9822008/
|
||||||
|
|
||||||
import sbt._
|
import sbt._
|
||||||
import sbt.Keys.{name, resolvedScoped}
|
import sbt.Keys.{name, resolvedScoped}
|
||||||
import java.util.concurrent.atomic.{AtomicInteger => AInt}
|
import java.util.concurrent.atomic.{AtomicInteger => AInt}
|
||||||
|
|
||||||
object AI extends AutoImport
|
object Imports
|
||||||
{
|
{
|
||||||
trait EmptyAutoPlugin extends AutoPlugin {
|
trait EmptyAutoPlugin extends AutoPlugin {
|
||||||
def requires = empty
|
def requires = empty
|
||||||
|
|
@ -21,7 +23,12 @@ object AI extends AutoImport
|
||||||
lazy val check = settingKey[Unit]("Verifies settings are as they should be.")
|
lazy val check = settingKey[Unit]("Verifies settings are as they should be.")
|
||||||
}
|
}
|
||||||
|
|
||||||
import AI._
|
object X extends AutoPlugin {
|
||||||
|
override lazy val autoImport = Imports
|
||||||
|
def select = Plugins.empty
|
||||||
|
}
|
||||||
|
|
||||||
|
import Imports._
|
||||||
|
|
||||||
object D extends AutoPlugin {
|
object D extends AutoPlugin {
|
||||||
def requires: Plugins = E
|
def requires: Plugins = E
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,22 @@
|
||||||
|
package sbttest // you need package http://stackoverflow.com/questions/9822008/
|
||||||
|
|
||||||
import sbt._
|
import sbt._
|
||||||
import Keys._
|
import Keys._
|
||||||
|
|
||||||
|
object Imports {
|
||||||
object C extends AutoImport {
|
|
||||||
object bN extends AutoPlugin {
|
object bN extends AutoPlugin {
|
||||||
def requires = empty
|
def requires = empty
|
||||||
def trigger = allRequirements
|
def trigger = allRequirements
|
||||||
}
|
}
|
||||||
lazy val check = taskKey[Unit]("Checks that the AutoPlugin and Build are automatically added.")
|
lazy val check = taskKey[Unit]("Checks that the AutoPlugin and Build are automatically added.")
|
||||||
}
|
}
|
||||||
|
|
||||||
import C._
|
object C extends AutoPlugin {
|
||||||
|
override lazy val autoImport = Imports
|
||||||
|
def select = Plugins.empty
|
||||||
|
}
|
||||||
|
|
||||||
|
import Imports._
|
||||||
|
|
||||||
object A extends AutoPlugin {
|
object A extends AutoPlugin {
|
||||||
def requires = bN
|
def requires = bN
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue