mirror of https://github.com/sbt/sbt.git
Merge pull request #1263 from sbt/wip/docs-and-cleanups
addPlugins => enablePlugins
This commit is contained in:
commit
583391a069
|
|
@ -11,21 +11,51 @@ package sbt
|
|||
import Scope.GlobalScope
|
||||
import scala.annotation.tailrec
|
||||
|
||||
|
||||
/**
|
||||
* This file is responsible for compiling the .sbt files used to configure sbt builds.
|
||||
*
|
||||
* Compilation is done in three phases:
|
||||
*
|
||||
* 1. Parsing high-level constructs (definitions, settings, imports)
|
||||
* 2. Compiling scala code into local .class files
|
||||
* 3. Evaluating the expressions and obtaining in-memory objects of the results (Setting[_] instances, or val references).
|
||||
*
|
||||
*
|
||||
*/
|
||||
object EvaluateConfigurations
|
||||
{
|
||||
/**
|
||||
* This represents the parsed expressions in a build sbt, as well as where they were defined.
|
||||
*/
|
||||
private[this] final class ParsedFile(val imports: Seq[(String,Int)], val definitions: Seq[(String,LineRange)], val settings: Seq[(String,LineRange)])
|
||||
|
||||
/** The keywords we look for when classifying a string as a definition. */
|
||||
private[this] val DefinitionKeywords = Seq("lazy val ", "def ", "val ")
|
||||
|
||||
/** Using an evaluating instance of the scala compiler, a sequence of files and
|
||||
* the default imports to use, this method will take a ClassLoader of sbt-classes and
|
||||
* return a parsed, compiled + evaluated [[LoadedSbtFile]]. The result has
|
||||
* raw sbt-types that can be accessed and used.
|
||||
*/
|
||||
def apply(eval: Eval, srcs: Seq[File], imports: Seq[String]): ClassLoader => LoadedSbtFile =
|
||||
{
|
||||
val loadFiles = srcs.sortBy(_.getName) map { src => evaluateSbtFile(eval, src, IO.readLines(src), imports, 0) }
|
||||
loader => (LoadedSbtFile.empty /: loadFiles) { (loaded, load) => loaded merge load(loader) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a given .sbt file and evaluates it into a sequence of setting values.
|
||||
*/
|
||||
def evaluateConfiguration(eval: Eval, src: File, imports: Seq[String]): ClassLoader => Seq[Setting[_]] =
|
||||
evaluateConfiguration(eval, src, IO.readLines(src), imports, 0)
|
||||
|
||||
/**
|
||||
* Parses a sequence of build.sbt lines into a [[ParsedFile]]. The result contains
|
||||
* a fragmentation of all imports, settings and definitions.
|
||||
*
|
||||
* @param buildinImports The set of import statements to add to those parsed in the .sbt file.
|
||||
*/
|
||||
private[this] def parseConfiguration(lines: Seq[String], builtinImports: Seq[String], offset: Int): ParsedFile =
|
||||
{
|
||||
val (importStatements, settingsAndDefinitions) = splitExpressions(lines)
|
||||
|
|
@ -34,12 +64,33 @@ object EvaluateConfigurations
|
|||
new ParsedFile(allImports, definitions, settings)
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates a parsed sbt configuration file.
|
||||
*
|
||||
* @param eval The evaluating scala compiler instance we use to handle evaluating scala configuration.
|
||||
* @param file The file we've parsed
|
||||
* @param imports The default imports to use in this .sbt configuration
|
||||
* @param lines The lines of the configurtion we'd like to evaluate.
|
||||
*
|
||||
* @return Just the Setting[_] instances defined in the .sbt file.
|
||||
*/
|
||||
def evaluateConfiguration(eval: Eval, file: File, lines: Seq[String], imports: Seq[String], offset: Int): ClassLoader => Seq[Setting[_]] =
|
||||
{
|
||||
val l = evaluateSbtFile(eval, file, lines, imports, offset)
|
||||
loader => l(loader).settings
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates a parsed sbt configuration file.
|
||||
*
|
||||
* @param eval The evaluating scala compiler instance we use to handle evaluating scala configuration.
|
||||
* @param file The file we've parsed
|
||||
* @param lines The lines of the configurtion we'd like to evaluate.
|
||||
* @param imports The default imports to use in this .sbt configuration.
|
||||
*
|
||||
* @return A function which can take an sbt classloader and return the raw types/configuratoin
|
||||
* which was compiled/parsed for the given file.
|
||||
*/
|
||||
private[sbt] def evaluateSbtFile(eval: Eval, file: File, lines: Seq[String], imports: Seq[String], offset: Int): ClassLoader => LoadedSbtFile =
|
||||
{
|
||||
val name = file.getPath
|
||||
|
|
@ -58,6 +109,7 @@ object EvaluateConfigurations
|
|||
val loadSettings = flatten(settings)
|
||||
loader => new LoadedSbtFile(loadSettings(loader), projects(loader), importDefs)
|
||||
}
|
||||
/** move a project to be relative to this file after we've evaluated it. */
|
||||
private[this] def resolveBase(f: File, p: Project) = p.copy(base = IO.resolve(f, p.base))
|
||||
def flatten(mksettings: Seq[ClassLoader => Seq[Setting[_]]]): ClassLoader => Seq[Setting[_]] =
|
||||
loader => mksettings.flatMap(_ apply loader)
|
||||
|
|
@ -66,10 +118,26 @@ object EvaluateConfigurations
|
|||
def addOffsetToRange(offset: Int, ranges: Seq[(String,LineRange)]): Seq[(String,LineRange)] =
|
||||
ranges.map { case (s, r) => (s, r shift offset) }
|
||||
|
||||
/**
|
||||
* The name of the class we cast DSL "setting" (vs. definition) lines to.
|
||||
*/
|
||||
val SettingsDefinitionName = {
|
||||
val _ = classOf[sbt.Def.SettingsDefinition] // this line exists to try to provide a compile-time error when the following line needs to be changed
|
||||
"sbt.Def.SettingsDefinition"
|
||||
}
|
||||
/**
|
||||
* This actually compiles a scala expression which represents a Seq[Setting[_]], although the
|
||||
* expression may be just a single setting.
|
||||
*
|
||||
* @param eval The mechanism to compile and evaluate Scala expressions.
|
||||
* @param name The name for the thing we're compiling
|
||||
* @param imports The scala imports to have in place when we compile the expression
|
||||
* @param expression The scala expression we're compiling
|
||||
* @param range The original position in source of the expression, for error messages.
|
||||
*
|
||||
* @return A method that given an sbt classloader, can return the actual Seq[Setting[_]] defined by
|
||||
* the expression.
|
||||
*/
|
||||
def evaluateSetting(eval: Eval, name: String, imports: Seq[(String,Int)], expression: String, range: LineRange): ClassLoader => Seq[Setting[_]] =
|
||||
{
|
||||
val result = try {
|
||||
|
|
@ -86,6 +154,10 @@ object EvaluateConfigurations
|
|||
private[this] def fstS(f: String => Boolean): ((String,Int)) => Boolean = { case (s,i) => f(s) }
|
||||
private[this] def firstNonSpaceIs(lit: String) = (_: String).view.dropWhile(isSpace).startsWith(lit)
|
||||
private[this] def or[A](a: A => Boolean, b: A => Boolean): A => Boolean = in => a(in) || b(in)
|
||||
/**
|
||||
* Splits a set of lines into (imports, expressions). That is,
|
||||
* anything on the right of the tuple is a scala expression (definition or setting).
|
||||
*/
|
||||
def splitExpressions(lines: Seq[String]): (Seq[(String,Int)], Seq[(String,LineRange)]) =
|
||||
{
|
||||
val blank = (_: String).forall(isSpace)
|
||||
|
|
|
|||
|
|
@ -41,11 +41,11 @@ Steps for users:
|
|||
|
||||
For example, given plugins Web and Javascript (perhaps provided by plugins added with addSbtPlugin),
|
||||
|
||||
<Project>.addPlugins( Web && Javascript )
|
||||
<Project>.enablePlugins( Web && Javascript )
|
||||
|
||||
will activate `MyPlugin` defined above and have its settings automatically added. If the user instead defines
|
||||
|
||||
<Project>.addPlugins( Web && Javascript ).disablePlugins(MyPlugin)
|
||||
<Project>.enablePlugins( Web && Javascript ).disablePlugins(MyPlugin)
|
||||
|
||||
then the `MyPlugin` settings (and anything that activates only when `MyPlugin` is activated) will not be added.
|
||||
|
||||
|
|
|
|||
|
|
@ -145,8 +145,8 @@ sealed trait Project extends ProjectDefinition[ProjectReference]
|
|||
def setSbtFiles(files: File*): Project = copy(auto = AddSettings.append( AddSettings.clearSbtFiles(auto), AddSettings.sbtFiles(files: _*)) )
|
||||
|
||||
/** Sets the [[AutoPlugin]]s of this project.
|
||||
A [[AutoPlugin]] is a common label that is used by plugins to determine what settings, if any, to add to a project. */
|
||||
def addPlugins(ns: Plugins*): Project = setPlugins(ns.foldLeft(plugins)(Plugins.and))
|
||||
A [[AutoPlugin]] is a common label that is used by plugins to determine what settings, if any, to enable on a project. */
|
||||
def enablePlugins(ns: Plugins*): Project = setPlugins(ns.foldLeft(plugins)(Plugins.and))
|
||||
|
||||
/** Disable the given plugins on this project. */
|
||||
def disablePlugins(ps: AutoPlugin*): Project =
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
// disablePlugins(Q) will prevent R from being auto-added
|
||||
lazy val projA = project.addPlugins(A, B).disablePlugins(Q)
|
||||
lazy val projA = project.enablePlugins(A, B).disablePlugins(Q)
|
||||
|
||||
// without B, Q is not added
|
||||
lazy val projB = project.addPlugins(A)
|
||||
lazy val projB = project.enablePlugins(A)
|
||||
|
||||
// with both A and B, Q is selected, which in turn selects R, but not S
|
||||
lazy val projC = project.addPlugins(A, B)
|
||||
lazy val projC = project.enablePlugins(A, B)
|
||||
|
||||
// with no natures defined, nothing is auto-added
|
||||
lazy val projD = project
|
||||
|
||||
// with S selected, Q is loaded automatically, which in turn selects R
|
||||
lazy val projE = project.addPlugins(S)
|
||||
lazy val projE = project.enablePlugins(S)
|
||||
|
||||
check := {
|
||||
val adel = (del in projA).?.value // should be None
|
||||
|
|
|
|||
|
|
@ -23,5 +23,5 @@ object A extends AutoPlugin {
|
|||
}
|
||||
|
||||
object B extends Build {
|
||||
lazy val extra = project.addPlugins(bN)
|
||||
lazy val extra = project.enablePlugins(bN)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue