mirror of https://github.com/sbt/sbt.git
Merge pull request #1456 from sbt/wip/build-sbt-vals-in-set-command
Export build.sbt values inside sbt.
This commit is contained in:
commit
9df5882766
|
|
@ -101,8 +101,7 @@ final class Eval(optionsNoncp: Seq[String], classpath: Seq[File], mkReporter: Se
|
||||||
syntheticModule(fullParser, importTrees, trees.toList, moduleName)
|
syntheticModule(fullParser, importTrees, trees.toList, moduleName)
|
||||||
}
|
}
|
||||||
def extra(run: Run, unit: CompilationUnit) = {
|
def extra(run: Run, unit: CompilationUnit) = {
|
||||||
val tpes = valTypes.map(tpe => rootMirror.getRequiredClass(tpe).tpe)
|
atPhase(run.typerPhase.next) { (new ValExtractor(valTypes.toSet)).getVals(unit.body) }
|
||||||
atPhase(run.typerPhase.next) { (new ValExtractor(tpes)).getVals(unit.body) }
|
|
||||||
}
|
}
|
||||||
def read(file: File) = IO.readLines(file)
|
def read(file: File) = IO.readLines(file)
|
||||||
def write(value: Seq[String], file: File) = IO.writeLines(file, value)
|
def write(value: Seq[String], file: File) = IO.writeLines(file, value)
|
||||||
|
|
@ -215,11 +214,16 @@ final class Eval(optionsNoncp: Seq[String], classpath: Seq[File], mkReporter: Se
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/** Tree traverser that obtains the names of vals in a top-level module whose type is a subtype of one of `types`.*/
|
/** Tree traverser that obtains the names of vals in a top-level module whose type is a subtype of one of `types`.*/
|
||||||
private[this] final class ValExtractor(types: Seq[Type]) extends Traverser {
|
private[this] final class ValExtractor(tpes: Set[String]) extends Traverser {
|
||||||
private[this] var vals = List[String]()
|
private[this] var vals = List[String]()
|
||||||
def getVals(t: Tree): List[String] = { vals = Nil; traverse(t); vals }
|
def getVals(t: Tree): List[String] = { vals = Nil; traverse(t); vals }
|
||||||
|
def isAcceptableType(tpe: Type): Boolean = {
|
||||||
|
tpe.baseClasses.exists { sym =>
|
||||||
|
tpes.contains(sym.fullName)
|
||||||
|
}
|
||||||
|
}
|
||||||
override def traverse(tree: Tree): Unit = tree match {
|
override def traverse(tree: Tree): Unit = tree match {
|
||||||
case ValDef(_, n, actualTpe, _) if isTopLevelModule(tree.symbol.owner) && types.exists(_ <:< actualTpe.tpe) =>
|
case ValDef(_, n, actualTpe, _) if isTopLevelModule(tree.symbol.owner) && isAcceptableType(actualTpe.tpe) =>
|
||||||
vals ::= nme.localToGetter(n).encoded
|
vals ::= nme.localToGetter(n).encoded
|
||||||
case _ => super.traverse(tree)
|
case _ => super.traverse(tree)
|
||||||
}
|
}
|
||||||
|
|
@ -387,7 +391,7 @@ final class Eval(optionsNoncp: Seq[String], classpath: Seq[File], mkReporter: Se
|
||||||
private[this] def index(a: Array[Int], i: Int): Int = if (i < 0 || i >= a.length) 0 else a(i)
|
private[this] def index(a: Array[Int], i: Int): Int = if (i < 0 || i >= a.length) 0 else a(i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private object Eval {
|
private[sbt] object Eval {
|
||||||
def optBytes[T](o: Option[T])(f: T => Array[Byte]): Array[Byte] = seqBytes(o.toSeq)(f)
|
def optBytes[T](o: Option[T])(f: T => Array[Byte]): Array[Byte] = seqBytes(o.toSeq)(f)
|
||||||
def stringSeqBytes(s: Seq[String]): Array[Byte] = seqBytes(s)(bytes)
|
def stringSeqBytes(s: Seq[String]): Array[Byte] = seqBytes(s)(bytes)
|
||||||
def seqBytes[T](s: Seq[T])(f: T => Array[Byte]): Array[Byte] = bytes(s map f)
|
def seqBytes[T](s: Seq[T])(f: T => Array[Byte]): Array[Byte] = bytes(s map f)
|
||||||
|
|
|
||||||
|
|
@ -50,15 +50,15 @@ final class LoadedBuildUnit(val unit: BuildUnit, val defined: Map[String, Resolv
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The classpath to use when compiling against this build unit's publicly visible code.
|
* The classpath to use when compiling against this build unit's publicly visible code.
|
||||||
* It includes build definition and plugin classes, but not classes for .sbt file statements and expressions.
|
* It includes build definition and plugin classes and classes for .sbt file statements and expressions.
|
||||||
*/
|
*/
|
||||||
def classpath: Seq[File] = unit.definitions.target ++ unit.plugins.classpath
|
def classpath: Seq[File] = unit.definitions.target ++ unit.plugins.classpath ++ unit.definitions.dslDefinitions.classpath
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The class loader to use for this build unit's publicly visible code.
|
* The class loader to use for this build unit's publicly visible code.
|
||||||
* It includes build definition and plugin classes, but not classes for .sbt file statements and expressions.
|
* It includes build definition and plugin classes and classes for .sbt file statements and expressions.
|
||||||
*/
|
*/
|
||||||
def loader = unit.definitions.loader
|
def loader = unit.definitions.dslDefinitions.classloader(unit.definitions.loader)
|
||||||
|
|
||||||
/** The imports to use for .sbt files, `consoleProject` and other contexts that use code from the build definition. */
|
/** The imports to use for .sbt files, `consoleProject` and other contexts that use code from the build definition. */
|
||||||
def imports = BuildUtil.getImports(unit)
|
def imports = BuildUtil.getImports(unit)
|
||||||
|
|
@ -80,7 +80,21 @@ final class LoadedBuildUnit(val unit: BuildUnit, val defined: Map[String, Resolv
|
||||||
* and their `settings` and `configurations` updated as appropriate.
|
* and their `settings` and `configurations` updated as appropriate.
|
||||||
* @param buildNames No longer used and will be deprecated once feasible.
|
* @param buildNames No longer used and will be deprecated once feasible.
|
||||||
*/
|
*/
|
||||||
final class LoadedDefinitions(val base: File, val target: Seq[File], val loader: ClassLoader, val builds: Seq[Build], val projects: Seq[Project], val buildNames: Seq[String])
|
final class LoadedDefinitions(
|
||||||
|
val base: File,
|
||||||
|
val target: Seq[File],
|
||||||
|
val loader: ClassLoader,
|
||||||
|
val builds: Seq[Build],
|
||||||
|
val projects: Seq[Project],
|
||||||
|
val buildNames: Seq[String],
|
||||||
|
val dslDefinitions: DefinedSbtValues) {
|
||||||
|
def this(base: File,
|
||||||
|
target: Seq[File],
|
||||||
|
loader: ClassLoader,
|
||||||
|
builds: Seq[Build],
|
||||||
|
projects: Seq[Project],
|
||||||
|
buildNames: Seq[String]) = this(base, target, loader, builds, projects, buildNames, DefinedSbtValues.empty)
|
||||||
|
}
|
||||||
|
|
||||||
/** Auto-detected top-level modules (as in `object X`) of type `T` paired with their source names. */
|
/** Auto-detected top-level modules (as in `object X`) of type `T` paired with their source names. */
|
||||||
final class DetectedModules[T](val modules: Seq[(String, T)]) {
|
final class DetectedModules[T](val modules: Seq[(String, T)]) {
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ object BuildUtil {
|
||||||
|
|
||||||
def baseImports: Seq[String] = "import sbt._, Keys._, dsl._" :: Nil
|
def baseImports: Seq[String] = "import sbt._, Keys._, dsl._" :: Nil
|
||||||
|
|
||||||
def getImports(unit: BuildUnit): Seq[String] = unit.plugins.detected.imports
|
def getImports(unit: BuildUnit): Seq[String] = unit.plugins.detected.imports ++ unit.definitions.dslDefinitions.imports
|
||||||
|
|
||||||
@deprecated("Use getImports(Seq[String]).", "0.13.2")
|
@deprecated("Use getImports(Seq[String]).", "0.13.2")
|
||||||
def getImports(pluginNames: Seq[String], buildNames: Seq[String]): Seq[String] = getImports(pluginNames ++ buildNames)
|
def getImports(pluginNames: Seq[String], buildNames: Seq[String]): Seq[String] = getImports(pluginNames ++ buildNames)
|
||||||
|
|
|
||||||
|
|
@ -9,14 +9,16 @@ object ConsoleProject {
|
||||||
def apply(state: State, extra: String, cleanupCommands: String = "", options: Seq[String] = Nil)(implicit log: Logger) {
|
def apply(state: State, extra: String, cleanupCommands: String = "", options: Seq[String] = Nil)(implicit log: Logger) {
|
||||||
val extracted = Project extract state
|
val extracted = Project extract state
|
||||||
val cpImports = new Imports(extracted, state)
|
val cpImports = new Imports(extracted, state)
|
||||||
|
|
||||||
val bindings = ("currentState" -> state) :: ("extracted" -> extracted) :: ("cpHelpers" -> cpImports) :: Nil
|
val bindings = ("currentState" -> state) :: ("extracted" -> extracted) :: ("cpHelpers" -> cpImports) :: Nil
|
||||||
val unit = extracted.currentUnit
|
val unit = extracted.currentUnit
|
||||||
val compiler = Compiler.compilers(ClasspathOptions.repl)(state.configuration, log).scalac
|
val compiler = Compiler.compilers(ClasspathOptions.repl)(state.configuration, log).scalac
|
||||||
val imports = BuildUtil.getImports(unit.unit) ++ BuildUtil.importAll(bindings.map(_._1))
|
val imports = BuildUtil.getImports(unit.unit) ++ BuildUtil.importAll(bindings.map(_._1))
|
||||||
val importString = imports.mkString("", ";\n", ";\n\n")
|
val importString = imports.mkString("", ";\n", ";\n\n")
|
||||||
val initCommands = importString + extra
|
val initCommands = importString + extra
|
||||||
(new Console(compiler))(unit.classpath, options, initCommands, cleanupCommands)(Some(unit.loader), bindings)
|
// TODO - Hook up dsl classpath correctly...
|
||||||
|
(new Console(compiler))(
|
||||||
|
unit.classpath, options, initCommands, cleanupCommands
|
||||||
|
)(Some(unit.loader), bindings)
|
||||||
}
|
}
|
||||||
/** Conveniences for consoleProject that shouldn't normally be used for builds. */
|
/** Conveniences for consoleProject that shouldn't normally be used for builds. */
|
||||||
final class Imports private[sbt] (extracted: Extracted, state: State) {
|
final class Imports private[sbt] (extracted: Extracted, state: State) {
|
||||||
|
|
|
||||||
|
|
@ -99,12 +99,13 @@ object EvaluateConfigurations {
|
||||||
// detection for which project project manipulations should be applied.
|
// detection for which project project manipulations should be applied.
|
||||||
val name = file.getPath
|
val name = file.getPath
|
||||||
val parsed = parseConfiguration(lines, imports, offset)
|
val parsed = parseConfiguration(lines, imports, offset)
|
||||||
val (importDefs, projects) = if (parsed.definitions.isEmpty) (Nil, (l: ClassLoader) => Nil) else {
|
val (importDefs, definitions) =
|
||||||
val definitions = evaluateDefinitions(eval, name, parsed.imports, parsed.definitions)
|
if (parsed.definitions.isEmpty) (Nil, DefinedSbtValues.empty) else {
|
||||||
val imp = BuildUtil.importAllRoot(definitions.enclosingModule :: Nil)
|
val definitions = evaluateDefinitions(eval, name, parsed.imports, parsed.definitions)
|
||||||
val projs = (loader: ClassLoader) => definitions.values(loader).map(p => resolveBase(file.getParentFile, p.asInstanceOf[Project]))
|
val imp = BuildUtil.importAllRoot(definitions.enclosingModule :: Nil)
|
||||||
(imp, projs)
|
val projs = (loader: ClassLoader) => definitions.values(loader).map(p => resolveBase(file.getParentFile, p.asInstanceOf[Project]))
|
||||||
}
|
(imp, DefinedSbtValues(definitions))
|
||||||
|
}
|
||||||
val allImports = importDefs.map(s => (s, -1)) ++ parsed.imports
|
val allImports = importDefs.map(s => (s, -1)) ++ parsed.imports
|
||||||
val dslEntries = parsed.settings map {
|
val dslEntries = parsed.settings map {
|
||||||
case (dslExpression, range) =>
|
case (dslExpression, range) =>
|
||||||
|
|
@ -112,6 +113,10 @@ object EvaluateConfigurations {
|
||||||
}
|
}
|
||||||
eval.unlinkDeferred()
|
eval.unlinkDeferred()
|
||||||
loader => {
|
loader => {
|
||||||
|
val projects =
|
||||||
|
definitions.values(loader).collect {
|
||||||
|
case p: Project => resolveBase(file.getParentFile, p)
|
||||||
|
}
|
||||||
val (settingsRaw, manipulationsRaw) =
|
val (settingsRaw, manipulationsRaw) =
|
||||||
dslEntries map (_ apply loader) partition {
|
dslEntries map (_ apply loader) partition {
|
||||||
case internals.ProjectSettings(_) => true
|
case internals.ProjectSettings(_) => true
|
||||||
|
|
@ -124,9 +129,8 @@ object EvaluateConfigurations {
|
||||||
val manipulations = manipulationsRaw map {
|
val manipulations = manipulationsRaw map {
|
||||||
case internals.ProjectManipulation(f) => f
|
case internals.ProjectManipulation(f) => f
|
||||||
}
|
}
|
||||||
val ps = projects(loader)
|
|
||||||
// TODO -get project manipulations.
|
// TODO -get project manipulations.
|
||||||
new LoadedSbtFile(settings, ps, importDefs, manipulations)
|
new LoadedSbtFile(settings, projects, importDefs, manipulations, definitions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/** move a project to be relative to this file after we've evaluated it. */
|
/** move a project to be relative to this file after we've evaluated it. */
|
||||||
|
|
@ -184,7 +188,7 @@ object EvaluateConfigurations {
|
||||||
* @return A method that given an sbt classloader, can return the actual Seq[Setting[_]] defined by
|
* @return A method that given an sbt classloader, can return the actual Seq[Setting[_]] defined by
|
||||||
* the expression.
|
* the expression.
|
||||||
*/
|
*/
|
||||||
@deprecated("Build DSL now includes non-Setting[_] type settings.", "0.13.6")
|
@deprecated("Build DSL now includes non-Setting[_] type settings.", "0.13.6") // Note: This method is used by the SET command, so we may want to evaluate that sucker a bit.
|
||||||
def evaluateSetting(eval: Eval, name: String, imports: Seq[(String, Int)], expression: String, range: LineRange): ClassLoader => Seq[Setting[_]] =
|
def evaluateSetting(eval: Eval, name: String, imports: Seq[(String, Int)], expression: String, range: LineRange): ClassLoader => Seq[Setting[_]] =
|
||||||
{
|
{
|
||||||
evaluateDslEntry(eval, name, imports, expression, range) andThen {
|
evaluateDslEntry(eval, name, imports, expression, range) andThen {
|
||||||
|
|
@ -231,11 +235,12 @@ object EvaluateConfigurations {
|
||||||
val trimmed = line.trim
|
val trimmed = line.trim
|
||||||
DefinitionKeywords.exists(trimmed startsWith _)
|
DefinitionKeywords.exists(trimmed startsWith _)
|
||||||
}
|
}
|
||||||
private[this] def evaluateDefinitions(eval: Eval, name: String, imports: Seq[(String, Int)], definitions: Seq[(String, LineRange)]) =
|
private[this] def extractedValTypes: Seq[String] =
|
||||||
|
Seq(classOf[Project], classOf[InputKey[_]], classOf[TaskKey[_]], classOf[SettingKey[_]]).map(_.getName)
|
||||||
|
private[this] def evaluateDefinitions(eval: Eval, name: String, imports: Seq[(String, Int)], definitions: Seq[(String, LineRange)]): compiler.EvalDefinitions =
|
||||||
{
|
{
|
||||||
val convertedRanges = definitions.map { case (s, r) => (s, r.start to r.end) }
|
val convertedRanges = definitions.map { case (s, r) => (s, r.start to r.end) }
|
||||||
val findTypes = (classOf[Project] :: /*classOf[Build] :: */ Nil).map(_.getName)
|
eval.evalDefinitions(convertedRanges, new EvalImports(imports, name), name, extractedValTypes)
|
||||||
eval.evalDefinitions(convertedRanges, new EvalImports(imports, name), name, findTypes)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
object Index {
|
object Index {
|
||||||
|
|
|
||||||
|
|
@ -426,9 +426,13 @@ object Load {
|
||||||
val defaultProjects = loadProjects(projectsFromBuild(b, normBase), false)
|
val defaultProjects = loadProjects(projectsFromBuild(b, normBase), false)
|
||||||
(defaultProjects ++ loadedProjectsRaw, b)
|
(defaultProjects ++ loadedProjectsRaw, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
val defs = if (defsScala.isEmpty) defaultBuildIfNone :: Nil else defsScala
|
val defs = if (defsScala.isEmpty) defaultBuildIfNone :: Nil else defsScala
|
||||||
val loadedDefs = new sbt.LoadedDefinitions(defDir, Nil, plugs.loader, defs, loadedProjects, plugs.detected.builds.names)
|
// HERE we pull out the defined vals from memoSettings and unify them all so
|
||||||
|
// we can use them later.
|
||||||
|
val valDefinitions = memoSettings.values.foldLeft(DefinedSbtValues.empty) { (prev, sbtFile) =>
|
||||||
|
prev.zip(sbtFile.definitions)
|
||||||
|
}
|
||||||
|
val loadedDefs = new sbt.LoadedDefinitions(defDir, Nil, plugs.loader, defs, loadedProjects, plugs.detected.builds.names, valDefinitions)
|
||||||
new sbt.BuildUnit(uri, normBase, loadedDefs, plugs)
|
new sbt.BuildUnit(uri, normBase, loadedDefs, plugs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -479,6 +483,9 @@ object Load {
|
||||||
* @param context The plugin management context for autogenerated IDs.
|
* @param context The plugin management context for autogenerated IDs.
|
||||||
*
|
*
|
||||||
* @return The completely resolved/updated sequence of projects defined, with all settings expanded.
|
* @return The completely resolved/updated sequence of projects defined, with all settings expanded.
|
||||||
|
*
|
||||||
|
* TODO - We want to attach the known (at this time) vals/lazy vals defined in each project's
|
||||||
|
* build.sbt to that project so we can later use this for the `set` command.
|
||||||
*/
|
*/
|
||||||
private[this] def loadTransitive(
|
private[this] def loadTransitive(
|
||||||
newProjects: Seq[Project],
|
newProjects: Seq[Project],
|
||||||
|
|
@ -518,12 +525,11 @@ object Load {
|
||||||
// Continue loading if we find any more.
|
// Continue loading if we find any more.
|
||||||
newProjects match {
|
newProjects match {
|
||||||
case Seq(next, rest @ _*) =>
|
case Seq(next, rest @ _*) =>
|
||||||
log.debug(s"[Loading] Loading project ${next.id} @ ${next.base}")
|
log.debug(s"[Loading] Loading project ${next.id} @ ${next.base}")
|
||||||
val (finished, discovered) = discoverAndLoad(next)
|
val (finished, discovered) = discoverAndLoad(next)
|
||||||
loadTransitive(rest ++ discovered, buildBase, plugins, eval, injectSettings, acc :+ finished, memoSettings, log, false, buildUri, context)
|
loadTransitive(rest ++ discovered, buildBase, plugins, eval, injectSettings, acc :+ finished, memoSettings, log, false, buildUri, context)
|
||||||
case Nil if makeOrDiscoverRoot =>
|
case Nil if makeOrDiscoverRoot =>
|
||||||
log.debug(s"[Loading] Scanning directory ${buildBase}")
|
log.debug(s"[Loading] Scanning directory ${buildBase}")
|
||||||
// TODO - Here we want to fully discover everything and make a default build...
|
|
||||||
discover(AddSettings.defaultSbtFiles, buildBase) match {
|
discover(AddSettings.defaultSbtFiles, buildBase) match {
|
||||||
case DiscoveredProjects(Some(root), discovered, files) =>
|
case DiscoveredProjects(Some(root), discovered, files) =>
|
||||||
log.debug(s"[Loading] Found root project ${root.id} w/ remaining ${discovered.map(_.id).mkString(",")}")
|
log.debug(s"[Loading] Found root project ${root.id} w/ remaining ${discovered.map(_.id).mkString(",")}")
|
||||||
|
|
@ -651,6 +657,8 @@ object Load {
|
||||||
// Classloader of the build
|
// Classloader of the build
|
||||||
val loader = loadedPlugins.loader
|
val loader = loadedPlugins.loader
|
||||||
// How to load an individual file for use later.
|
// How to load an individual file for use later.
|
||||||
|
// TODO - We should import vals defined in other sbt files here, if we wish to
|
||||||
|
// share. For now, build.sbt files have their own unique namespace.
|
||||||
def loadSettingsFile(src: File): LoadedSbtFile =
|
def loadSettingsFile(src: File): LoadedSbtFile =
|
||||||
EvaluateConfigurations.evaluateSbtFile(eval(), src, IO.readLines(src), loadedPlugins.detected.imports, 0)(loader)
|
EvaluateConfigurations.evaluateSbtFile(eval(), src, IO.readLines(src), loadedPlugins.detected.imports, 0)(loader)
|
||||||
// How to merge SbtFiles we read into one thing
|
// How to merge SbtFiles we read into one thing
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package sbt
|
package sbt
|
||||||
|
|
||||||
import Def.Setting
|
import Def.Setting
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the exported contents of a .sbt file. Currently, that includes the list of settings,
|
* Represents the exported contents of a .sbt file. Currently, that includes the list of settings,
|
||||||
|
|
@ -10,15 +11,69 @@ private[sbt] final class LoadedSbtFile(
|
||||||
val settings: Seq[Setting[_]],
|
val settings: Seq[Setting[_]],
|
||||||
val projects: Seq[Project],
|
val projects: Seq[Project],
|
||||||
val importedDefs: Seq[String],
|
val importedDefs: Seq[String],
|
||||||
val manipulations: Seq[Project => Project]) {
|
val manipulations: Seq[Project => Project],
|
||||||
|
// TODO - we may want to expose a simpler interface on top of here for the set command,
|
||||||
|
// rather than what we have now...
|
||||||
|
val definitions: DefinedSbtValues) {
|
||||||
@deprecated("LoadedSbtFiles are no longer directly merged.", "0.13.6")
|
@deprecated("LoadedSbtFiles are no longer directly merged.", "0.13.6")
|
||||||
def merge(o: LoadedSbtFile): LoadedSbtFile =
|
def merge(o: LoadedSbtFile): LoadedSbtFile =
|
||||||
new LoadedSbtFile(settings ++ o.settings, projects ++ o.projects, importedDefs ++ o.importedDefs, manipulations)
|
new LoadedSbtFile(
|
||||||
|
settings ++ o.settings,
|
||||||
|
projects ++ o.projects,
|
||||||
|
importedDefs ++ o.importedDefs,
|
||||||
|
manipulations,
|
||||||
|
definitions zip o.definitions)
|
||||||
|
|
||||||
def clearProjects = new LoadedSbtFile(settings, Nil, importedDefs, manipulations)
|
def clearProjects = new LoadedSbtFile(settings, Nil, importedDefs, manipulations, definitions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the `val`/`lazy val` definitions defined within a build.sbt file
|
||||||
|
* which we can reference in other settings.
|
||||||
|
*/
|
||||||
|
private[sbt] final class DefinedSbtValues(val sbtFiles: Seq[compiler.EvalDefinitions]) {
|
||||||
|
|
||||||
|
def values(parent: ClassLoader): Seq[Any] =
|
||||||
|
sbtFiles flatMap (_ values parent)
|
||||||
|
|
||||||
|
def classloader(parent: ClassLoader): ClassLoader =
|
||||||
|
sbtFiles.foldLeft(parent) { (cl, e) => e.loader(cl) }
|
||||||
|
|
||||||
|
def imports: Seq[String] = {
|
||||||
|
// TODO - Sanity check duplicates and such, so users get a nice warning rather
|
||||||
|
// than explosion.
|
||||||
|
for {
|
||||||
|
file <- sbtFiles
|
||||||
|
m = file.enclosingModule
|
||||||
|
v <- file.valNames
|
||||||
|
} yield s"import ${m}.${v}"
|
||||||
|
}
|
||||||
|
def generated: Seq[File] =
|
||||||
|
sbtFiles flatMap (_.generated)
|
||||||
|
|
||||||
|
// Returns a classpath for the generated .sbt files.
|
||||||
|
def classpath: Seq[File] =
|
||||||
|
generated.map(_.getParentFile).distinct
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Joins the defines of this build.sbt with another.
|
||||||
|
* TODO - we may want to figure out scoping rules, as this could lead to
|
||||||
|
* ambiguities.
|
||||||
|
*/
|
||||||
|
def zip(other: DefinedSbtValues): DefinedSbtValues =
|
||||||
|
new DefinedSbtValues(sbtFiles ++ other.sbtFiles)
|
||||||
|
}
|
||||||
|
private[sbt] object DefinedSbtValues {
|
||||||
|
/** Construct a DefinedSbtValues object directly from the underlying representation. */
|
||||||
|
def apply(eval: compiler.EvalDefinitions): DefinedSbtValues =
|
||||||
|
new DefinedSbtValues(Seq(eval))
|
||||||
|
/** Construct an empty value object. */
|
||||||
|
def empty = new DefinedSbtValues(Nil)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private[sbt] object LoadedSbtFile {
|
private[sbt] object LoadedSbtFile {
|
||||||
/** Represents an empty .sbt file: no Projects, imports, or settings.*/
|
/** Represents an empty .sbt file: no Projects, imports, or settings.*/
|
||||||
def empty = new LoadedSbtFile(Nil, Nil, Nil, Nil)
|
def empty = new LoadedSbtFile(Nil, Nil, Nil, Nil, DefinedSbtValues.empty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -234,7 +234,19 @@ object BuiltinCommands {
|
||||||
case (s, (all, arg)) =>
|
case (s, (all, arg)) =>
|
||||||
val extracted = Project extract s
|
val extracted = Project extract s
|
||||||
import extracted._
|
import extracted._
|
||||||
val settings = EvaluateConfigurations.evaluateSetting(session.currentEval(), "<set>", imports(extracted), arg, LineRange(0, 0))(currentLoader)
|
val dslVals = extracted.currentUnit.unit.definitions.dslDefinitions
|
||||||
|
// TODO - This is possibly inefficient (or stupid). We should try to only attach the
|
||||||
|
// classloader + imports NEEDED to compile the set command, rather than
|
||||||
|
// just ALL of them.
|
||||||
|
val ims = (imports(extracted) ++ dslVals.imports.map(i => (i, -1)))
|
||||||
|
val cl = dslVals.classloader(currentLoader)
|
||||||
|
val settings = EvaluateConfigurations.evaluateSetting(
|
||||||
|
session.currentEval(),
|
||||||
|
"<set>",
|
||||||
|
ims,
|
||||||
|
arg,
|
||||||
|
LineRange(0, 0)
|
||||||
|
)(cl)
|
||||||
val setResult = if (all) SettingCompletions.setAll(extracted, settings) else SettingCompletions.setThis(s, extracted, settings, arg)
|
val setResult = if (all) SettingCompletions.setAll(extracted, settings) else SettingCompletions.setThis(s, extracted, settings, arg)
|
||||||
s.log.info(setResult.quietSummary)
|
s.log.info(setResult.quietSummary)
|
||||||
s.log.debug(setResult.verboseSummary)
|
s.log.debug(setResult.verboseSummary)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
|
||||||
|
TaskKey[Unit]("checkName", "") := {
|
||||||
|
assert(name.value == "hello-world", "Name is not hello-worled, failed to set!")
|
||||||
|
}
|
||||||
|
|
||||||
|
val notExistingThing = settingKey[Int]("Something new")
|
||||||
|
|
||||||
|
TaskKey[Unit]("checkBuildSbtDefined", "") := {
|
||||||
|
assert(notExistingThing.?.value == Some(5), "Failed to set a settingKey defined in build.sbt")
|
||||||
|
}
|
||||||
|
|
||||||
|
commands ++= Seq(
|
||||||
|
Command.command("helloWorldTest") { state: State =>
|
||||||
|
"""set name := "hello-world"""" ::
|
||||||
|
"checkName" ::
|
||||||
|
state
|
||||||
|
},
|
||||||
|
Command.command("buildSbtTest") { state: State =>
|
||||||
|
"""set notExistingThing := 5""" ::
|
||||||
|
"checkBuildSbtDefined" ::
|
||||||
|
state
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
> helloWorldTest
|
||||||
|
> buildSbtTest
|
||||||
Loading…
Reference in New Issue