AutoPlugins appropriately participate in AddSettings.

* Add new AutoPlugins type to AddSettings.
* Ensure any Plugins filter doesn't just automatically always add
  autoplugins every time.
* Load.scala can now adjust AutoPlugins ordering

Note: Adjusting autoplugin ordering is dangerous BUT doing a glob
      of "put autoplugin settings here" is generally ok.
This commit is contained in:
Josh Suereth 2014-03-05 18:03:00 -05:00
parent ac9391066b
commit a44a14f2c8
3 changed files with 36 additions and 10 deletions

View File

@ -12,22 +12,23 @@ object AddSettings
private[sbt] final class Sequence(val sequence: Seq[AddSettings]) extends AddSettings
private[sbt] final object User extends AddSettings
private[sbt] final class Plugins(val include: Plugin => Boolean) extends AddSettings
private[sbt] final class AutoPlugins(val include: AutoPlugin => Boolean) extends AddSettings
private[sbt] final class DefaultSbtFiles(val include: File => Boolean) extends AddSettings
private[sbt] final class SbtFiles(val files: Seq[File]) extends AddSettings
// Settings created with the Project().settings() commands in build.scala files.
private[sbt] final object ProjectSettings extends AddSettings
/** Adds all settings from a plugin to a project. */
val allPlugins: AddSettings = plugins(const(true))
/** Adds all settings from autoplugins. */
val autoPlugins: AddSettings = plugins(_.isInstanceOf[AutoPlugin])
val autoPlugins: AddSettings = new AutoPlugins(const(true))
/** Settings specified in Build.scala `Project` constructors. */
val projectSettings: AddSettings = ProjectSettings
/** All plugins that aren't auto plugins. */
val nonAutoPlugins: AddSettings = plugins(!_.isInstanceOf[AutoPlugin])
val nonAutoPlugins: AddSettings = plugins(const(true))
/** Adds all settings from a plugin to a project. */
val allPlugins: AddSettings = seq(autoPlugins, nonAutoPlugins)
/** Allows the plugins whose names match the `names` filter to automatically add settings to a project. */
def plugins(include: Plugin => Boolean): AddSettings = new Plugins(include)

View File

@ -505,19 +505,23 @@ object Load
def loadSettingsFile(src: File): LoadedSbtFile =
EvaluateConfigurations.evaluateSbtFile(eval(), src, IO.readLines(src), loadedPlugins.detected.imports, 0)(loader)
import AddSettings.{User,SbtFiles,DefaultSbtFiles,Plugins,Sequence, ProjectSettings}
import AddSettings.{User,SbtFiles,DefaultSbtFiles,Plugins,AutoPlugins,Sequence, ProjectSettings}
def pluginSettings(f: Plugins) = {
val included = loadedPlugins.detected.plugins.values.filter(f.include) // don't apply the filter to AutoPlugins, only Plugins
val oldStyle = included.flatMap(p => p.settings.filter(isProjectThis) ++ p.projectSettings)
val autoStyle = autoPlugins.flatMap(_.projectSettings)
oldStyle ++ autoStyle
included.flatMap(p => p.settings.filter(isProjectThis) ++ p.projectSettings)
}
// Filter the AutoPlugin settings we included based on which ones are
// intended in the AddSettings.AutoPlugins filter.
def autoPluginSettings(f: AutoPlugins) =
autoPlugins.filter(f.include).flatMap(_.projectSettings)
def expand(auto: AddSettings): LoadedSbtFile = auto match {
case ProjectSettings => settings(projectSettings)
case User => settings(injectSettings.projectLoaded(loader))
case sf: SbtFiles => loadSettings( sf.files.map(f => IO.resolve(projectBase, f)))
case sf: DefaultSbtFiles => loadSettings( defaultSbtFiles.filter(sf.include))
case p: Plugins => settings(pluginSettings(p))
case p: AutoPlugins => settings(autoPluginSettings(p))
case q: Sequence => (LoadedSbtFile.empty /: q.sequence) { (b,add) => b.merge( expand(add) ) }
}
expand(auto)

View File

@ -72,6 +72,24 @@ abstract class AutoPlugin extends Plugins.Basic
// TODO?: def commands: Seq[Command]
def unary_! : Exclude = Exclude(this)
/** If this plugin requries itself to be included, it means we're actually a nature,
* not a normal plugin. The user must specifically enable this plugin
* but other plugins can rely on its existence.
*/
final def isRoot: Boolean =
this match {
case _: RootAutoPlugin => true
case _ => false
}
}
/**
* A root AutoPlugin is a plugin which must be explicitly enabled by users in their `setPlugins` method
* on a project. However, RootAutoPlugins represent the "root" of a tree of dependent auto-plugins.
*/
abstract class RootAutoPlugin extends AutoPlugin {
final def select: Plugins = this
}
/** An error that occurs when auto-plugins aren't configured properly.
@ -104,7 +122,10 @@ object Plugins
val byAtom = defined.map(x => (Atom(x.label), x))
val byAtomMap = byAtom.toMap
if(byAtom.size != byAtomMap.size) duplicateProvidesError(byAtom)
val clauses = Clauses( defined.map(d => asClause(d)) )
// Ignore clauses for plugins that just require themselves be specified.
// Avoids the requirement for pure Nature strings *and* possible
// circular dependencies in the logic.
val clauses = Clauses( defined.filterNot(_.isRoot).map(d => asClause(d)) )
requestedPlugins =>
Logic.reduce(clauses, flattenConvert(requestedPlugins).toSet) match {
case Left(problem) => throw AutoPluginException(problem)