mirror of https://github.com/sbt/sbt.git
get,set,eval commands
This commit is contained in:
parent
837bb80d40
commit
f1af2c1cbc
|
|
@ -182,7 +182,7 @@ object Load
|
|||
import BuildPaths._
|
||||
import BuildStreams._
|
||||
|
||||
def defaultLoad(state: State, log: Logger): BuildStructure =
|
||||
def defaultLoad(state: State, log: Logger): (() => Eval, BuildStructure) =
|
||||
{
|
||||
val stagingDirectory = defaultStaging.getCanonicalFile // TODO: properly configurable
|
||||
val base = state.configuration.baseDirectory.getCanonicalFile
|
||||
|
|
@ -218,56 +218,66 @@ object Load
|
|||
// 6) Load all configurations using build definitions and plugins (their classpaths and loaded instances).
|
||||
// 7) Combine settings from projects, plugins, and configurations
|
||||
// 8) Evaluate settings
|
||||
def apply(rootBase: File, config: LoadBuildConfiguration): BuildStructure =
|
||||
def apply(rootBase: File, config: LoadBuildConfiguration): (() => Eval, BuildStructure) =
|
||||
{
|
||||
val loaded = load(rootBase, config)
|
||||
val projects = loaded.units
|
||||
val settings = buildConfigurations(loaded, getRootProject(projects), config.injectSettings)
|
||||
val data = Project.make(settings)(config.delegates(loaded))
|
||||
lazy val rootEval = lazyEval(loaded.units(loaded.root).unit)
|
||||
val settings = buildConfigurations(loaded, getRootProject(projects), config.injectSettings, rootEval)
|
||||
val delegates = config.delegates(loaded)
|
||||
val data = Project.make(settings)(delegates)
|
||||
val index = structureIndex(data)
|
||||
val streams = mkStreams(projects, loaded.root, data)
|
||||
new BuildStructure(projects, loaded.root, settings, data, index, streams)
|
||||
(rootEval, new BuildStructure(projects, loaded.root, settings, data, index, streams, delegates))
|
||||
}
|
||||
|
||||
def structureIndex(settings: Settings[Scope]): StructureIndex =
|
||||
new StructureIndex(Index.stringToKeyMap(settings), Index.taskToKeyMap(settings))
|
||||
|
||||
// Reevaluates settings after modifying them. Does not recompile or reload any build components.
|
||||
def reapply(modifySettings: Endo[Seq[Setting[_]]], structure: BuildStructure, delegates: Scope => Seq[Scope]): BuildStructure =
|
||||
def reapply(newSettings: Seq[Setting[_]], structure: BuildStructure): BuildStructure =
|
||||
{
|
||||
val newSettings = modifySettings(structure.settings)
|
||||
val newData = Project.make(newSettings)(delegates)
|
||||
val newData = Project.make(newSettings)(structure.delegates)
|
||||
val newIndex = structureIndex(newData)
|
||||
val newStreams = mkStreams(structure.units, structure.root, newData)
|
||||
new BuildStructure(units = structure.units, root = structure.root, settings = newSettings, data = newData, index = newIndex, streams = newStreams)
|
||||
new BuildStructure(units = structure.units, root = structure.root, settings = newSettings, data = newData, index = newIndex, streams = newStreams, delegates = structure.delegates)
|
||||
}
|
||||
|
||||
def isProjectThis(s: Setting[_]) = s.key.scope.project == This
|
||||
def buildConfigurations(loaded: LoadedBuild, rootProject: URI => String, injectSettings: Seq[Setting[_]]): Seq[Setting[_]] =
|
||||
def buildConfigurations(loaded: LoadedBuild, rootProject: URI => String, injectSettings: Seq[Setting[_]], rootEval: () => Eval): Seq[Setting[_]] =
|
||||
loaded.units.toSeq flatMap { case (uri, build) =>
|
||||
val eval = mkEval(build.unit.definitions, build.unit.plugins, Nil)
|
||||
val eval = if(uri == loaded.root) rootEval else lazyEval(build.unit)
|
||||
val pluginSettings = build.unit.plugins.plugins
|
||||
val (pluginThisProject, pluginGlobal) = pluginSettings partition isProjectThis
|
||||
val projectSettings = build.defined flatMap { case (id, project) =>
|
||||
val srcs = configurationSources(project.base)
|
||||
val settings = injectSettings ++ project.settings ++ pluginThisProject ++ configurations(srcs, eval)
|
||||
|
||||
val ext = ProjectRef(uri, id)
|
||||
val thisScope = Scope(Select(ext), Global, Global, Global)
|
||||
|
||||
// map This to thisScope, Select(p) to mapRef(uri, rootProject, p)
|
||||
Project.transform(Scope.resolveScope(thisScope, uri, rootProject), settings)
|
||||
transformSettings(projectScope(uri, id), uri, rootProject, settings)
|
||||
}
|
||||
pluginGlobal ++ projectSettings
|
||||
}
|
||||
def transformSettings(thisScope: Scope, uri: URI, rootProject: URI => String, settings: Seq[Setting[_]]): Seq[Setting[_]] =
|
||||
Project.transform(Scope.resolveScope(thisScope, uri, rootProject), settings)
|
||||
def projectScope(uri: URI, id: String): Scope = projectScope(ProjectRef(uri, id))
|
||||
def projectScope(project: ProjectRef): Scope = Scope(Select(project), Global, Global, Global)
|
||||
|
||||
|
||||
def lazyEval(unit: BuildUnit): () => Eval =
|
||||
{
|
||||
lazy val eval = mkEval(unit)
|
||||
() => eval
|
||||
}
|
||||
def mkEval(unit: BuildUnit): Eval = mkEval(unit.definitions, unit.plugins, Nil)
|
||||
def mkEval(defs: LoadedDefinitions, plugs: LoadedPlugins, options: Seq[String]): Eval =
|
||||
{
|
||||
val classpathString = Path.makeString(defs.target +: plugs.classpath)
|
||||
val optionsCp = "-cp" +: classpathString +: options // TODO: probably need to properly set up options with CompilerArguments
|
||||
new Eval(optionsCp, s => new ConsoleReporter(s), defs.loader)
|
||||
}
|
||||
def configurations(srcs: Seq[File], eval: Eval): Seq[Setting[_]] =
|
||||
if(srcs.isEmpty) Nil else EvaluateConfigurations(eval, srcs)
|
||||
def configurations(srcs: Seq[File], eval: () => Eval): Seq[Setting[_]] =
|
||||
if(srcs.isEmpty) Nil else EvaluateConfigurations(eval(), srcs)
|
||||
|
||||
def load(file: File, config: LoadBuildConfiguration): LoadedBuild = load(file, uri => loadUnit(uri, RetrieveUnit(config.stagingDirectory, uri), config) )
|
||||
def load(file: File, loader: URI => BuildUnit): LoadedBuild = loadURI(IO.directoryURI(file), loader)
|
||||
|
|
@ -386,7 +396,7 @@ object Load
|
|||
def noPlugins(config: LoadBuildConfiguration): LoadedPlugins = new LoadedPlugins(config.classpath, config.loader, Nil)
|
||||
def buildPlugins(dir: File, config: LoadBuildConfiguration): LoadedPlugins =
|
||||
{
|
||||
val pluginDef = apply(dir, config)
|
||||
val (_,pluginDef) = apply(dir, config)
|
||||
val (pluginClasspath, pluginAnalysis) = config.evalPluginDef(pluginDef)
|
||||
val pluginLoader = ClasspathUtilities.toLoader(pluginClasspath, config.loader)
|
||||
loadPlugins(pluginClasspath, pluginLoader, pluginAnalysis)
|
||||
|
|
@ -431,8 +441,8 @@ object Load
|
|||
discovery(Test.allDefs(analysis)).collect { case (definition, Discovered(_,_,_,true)) => definition.name }
|
||||
}
|
||||
|
||||
def initialSession(structure: BuildStructure): SessionSettings =
|
||||
new SessionSettings(structure.root, rootProjectMap(structure.units), structure.settings, Map.empty, Map.empty)
|
||||
def initialSession(structure: BuildStructure, rootEval: () => Eval): SessionSettings =
|
||||
new SessionSettings(structure.root, rootProjectMap(structure.units), structure.settings, Map.empty, Map.empty, rootEval)
|
||||
|
||||
def rootProjectMap(units: Map[URI, LoadedBuildUnit]): Map[URI, String] =
|
||||
{
|
||||
|
|
@ -466,7 +476,7 @@ object Load
|
|||
def referenced(definition: Project): Seq[ProjectRef] = definition.inherits ++ definition.aggregate ++ definition.dependencies.map(_.project)
|
||||
|
||||
|
||||
final class BuildStructure(val units: Map[URI, LoadedBuildUnit], val root: URI, val settings: Seq[Setting[_]], val data: Settings[Scope], val index: StructureIndex, val streams: Streams)
|
||||
final class BuildStructure(val units: Map[URI, LoadedBuildUnit], val root: URI, val settings: Seq[Setting[_]], val data: Settings[Scope], val index: StructureIndex, val streams: Streams, val delegates: Scope => Seq[Scope])
|
||||
final class LoadBuildConfiguration(val stagingDirectory: File, val classpath: Seq[File], val loader: ClassLoader, val compilers: Compilers, val evalPluginDef: BuildStructure => (Seq[File], Analysis), val delegates: LoadedBuild => Scope => Seq[Scope], val injectSettings: Seq[Setting[_]], val log: Logger)
|
||||
// information that is not original, but can be reconstructed from the rest of BuildStructure
|
||||
final class StructureIndex(val keyMap: Map[String, AttributeKey[_]], val taskToKey: Map[Task[_], ScopedKey[Task[_]]])
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ object Command
|
|||
val HistoryPath = SettingKey[Option[File]]("history")
|
||||
val Analysis = AttributeKey[inc.Analysis]("analysis")
|
||||
val Watch = SettingKey[Watched]("continuous-watch")
|
||||
val Sample = SettingKey[String]("sample-setting")
|
||||
|
||||
def command(name: String)(f: State => State): Command = command(name, Nil)(f)
|
||||
def command(name: String, briefHelp: String, detail: String)(f: State => State): Command = command(name, Help(name, (name, briefHelp), detail) :: Nil)(f)
|
||||
|
|
|
|||
|
|
@ -34,6 +34,37 @@ object CommandSupport
|
|||
val Exit = "exit"
|
||||
val Quit = "quit"
|
||||
|
||||
val EvalCommand = "eval"
|
||||
val evalBrief = (EvalCommand + " <expression>", "Evaluates the given Scala expression and prints the result and type.")
|
||||
val evalDetailed =
|
||||
EvalCommand + """ <expression>
|
||||
Evaluates the given Scala expression and prints the result and type.
|
||||
"""
|
||||
|
||||
val GetCommand = "get"
|
||||
val getBrief = (GetCommand + " <setting-key>", "Prints the value for the given key.")
|
||||
val getDetailed =
|
||||
GetCommand + """ <setting-key>
|
||||
|
||||
Displays the value bound to the key argument using its toString method.
|
||||
<setting-key> is interpreted as a Scala expression of type sbt.ScopedSetting[_].
|
||||
"""
|
||||
|
||||
val SetCommand = "set"
|
||||
val setBrief = (SetCommand + " <setting-expression>", "Evaluates the given Setting and applies to the current project.")
|
||||
val setDetailed =
|
||||
SetCommand + """ <setting-expression>
|
||||
|
||||
Applies the given setting to the current project:
|
||||
1) Constructs the expression provided as an argument by compiling and loading it.
|
||||
2) Appends the new setting to the current project's settings.
|
||||
3) Re-evaluates the build's settings.
|
||||
|
||||
This command does not rebuild the build definitions, plugins, or configurations.
|
||||
It does not automatically persist the setting.
|
||||
This is done by running 'save-settings'.
|
||||
"""
|
||||
|
||||
/** The command name to terminate the program.*/
|
||||
val TerminateAction: String = Exit
|
||||
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ class xMain extends xsbti.AppMain
|
|||
object Commands
|
||||
{
|
||||
def DefaultCommands: Seq[Command] = Seq(ignore, help, reload, read, history, continuous, exit, loadCommands, loadProject, compile, discover,
|
||||
projects, project, setOnFailure, ifLast, multi, shell, alias, append, nop)
|
||||
projects, project, setOnFailure, ifLast, multi, shell, set, get, eval, alias, append, nop)
|
||||
|
||||
def nop = Command.custom(s => success(() => s), Nil)
|
||||
def ignore = Command.command(FailureWall)(identity)
|
||||
|
|
@ -212,6 +212,35 @@ object Commands
|
|||
}
|
||||
}*/
|
||||
|
||||
def eval = Command.single(EvalCommand, evalBrief, evalDetailed) { (s, arg) =>
|
||||
val log = logger(s)
|
||||
val extracted = Project extract s
|
||||
import extracted._
|
||||
val (tpe, value) = session.currentEval().eval(arg, None)
|
||||
log.info("ans: " + tpe + " = " + value.toString)
|
||||
s
|
||||
}
|
||||
def set = Command.single(SetCommand, setBrief, setDetailed) { (s, arg) =>
|
||||
val extracted = Project extract s
|
||||
import extracted._
|
||||
val setting = EvaluateConfigurations.evaluateSetting(session.currentEval(), "", Nil, arg)
|
||||
val append = Load.transformSettings(Load.projectScope(curi, cid), curi, rootProject, setting :: Nil)
|
||||
val newSession = session.appendSettings( append map (a => (a, arg)))
|
||||
logger(s).info("Reapplying settings...")
|
||||
val newStructure = Load.reapply(newSession.mergeSettings, structure)
|
||||
setProject(newSession, newStructure, s)
|
||||
}
|
||||
def get = Command.single(GetCommand, getBrief, getDetailed) { (s, arg) =>
|
||||
val extracted = Project extract s
|
||||
import extracted._
|
||||
val scoped = session.currentEval().eval(arg, Some("sbt.ScopedSetting[_]"))._2.asInstanceOf[ScopedSetting[_]]
|
||||
val resolve = Scope.resolveScope(Load.projectScope(curi, cid), curi, rootProject)
|
||||
(structure.data.get(resolve(scoped.scope), scoped.key)) match {
|
||||
case None => logger(s).error("No entry for key."); s.fail
|
||||
case Some(v) => logger(s).info(v.toString); s
|
||||
}
|
||||
}
|
||||
|
||||
def listBuild(uri: URI, build: Load.LoadedBuildUnit, current: Boolean, currentID: String, log: Logger) =
|
||||
{
|
||||
log.info("In " + uri)
|
||||
|
|
@ -221,10 +250,9 @@ object Commands
|
|||
|
||||
def act = error("TODO")
|
||||
def projects = Command.command(ProjectsCommand, projectsBrief, projectsDetailed ) { s =>
|
||||
val extracted = Project extract s
|
||||
import extracted._
|
||||
val log = logger(s)
|
||||
val session = Project.session(s)
|
||||
val structure = Project.structure(s)
|
||||
val (curi, cid) = session.current
|
||||
listBuild(curi, structure.units(curi), true, cid, log)
|
||||
for( (uri, build) <- structure.units if curi != uri) listBuild(uri, build, false, cid, log)
|
||||
s
|
||||
|
|
@ -260,8 +288,12 @@ object Commands
|
|||
}
|
||||
|
||||
def loadProject = Command.command(LoadProject, LoadProjectBrief, LoadProjectDetailed) { s =>
|
||||
val structure = Load.defaultLoad(s, logger(s))
|
||||
val session = Load.initialSession(structure)
|
||||
val (eval, structure) = Load.defaultLoad(s, logger(s))
|
||||
val session = Load.initialSession(structure, eval)
|
||||
setProject(session, structure, s)
|
||||
}
|
||||
def setProject(session: SessionSettings, structure: Load.BuildStructure, s: State): State =
|
||||
{
|
||||
val newAttrs = s.attributes.put(StructureKey, structure).put(SessionKey, session)
|
||||
val newState = s.copy(attributes = newAttrs)
|
||||
Project.updateCurrent(runExitHooks(newState))
|
||||
|
|
|
|||
|
|
@ -6,14 +6,17 @@ package sbt
|
|||
import java.io.File
|
||||
import java.net.URI
|
||||
import Project._
|
||||
import Types.Endo
|
||||
import Command.{HistoryPath,Watch}
|
||||
import CommandSupport.logger
|
||||
import compile.Eval
|
||||
|
||||
final case class Project(id: String, base: File, aggregate: Seq[ProjectRef] = Nil, dependencies: Seq[Project.ClasspathDependency] = Nil, inherits: Seq[ProjectRef] = Nil,
|
||||
settings: Seq[Project.Setting[_]] = Project.defaultSettings, configurations: Seq[Configuration] = Configurations.default)
|
||||
{
|
||||
def uses = aggregate ++ dependencies.map(_.project)
|
||||
}
|
||||
final case class Extracted(structure: Load.BuildStructure, session: SessionSettings, curi: URI, cid: String, rootProject: URI => String)
|
||||
|
||||
object Project extends Init[Scope]
|
||||
{
|
||||
|
|
@ -27,13 +30,15 @@ object Project extends Init[Scope]
|
|||
def getOrError[T](state: State, key: AttributeKey[T], msg: String): T = state get key getOrElse error(msg)
|
||||
def structure(state: State): Load.BuildStructure = getOrError(state, StructureKey, "No build loaded.")
|
||||
def session(state: State): SessionSettings = getOrError(state, SessionKey, "Session not initialized.")
|
||||
|
||||
def current(state: State): (URI, String) =
|
||||
def extract(state: State): Extracted =
|
||||
{
|
||||
val s = session(state)
|
||||
val uri = s.currentBuild
|
||||
(uri, s.currentProject(uri))
|
||||
val se = session(state)
|
||||
val (curi, cid) = se.current
|
||||
val st = structure(state)
|
||||
Extracted(st, se, curi, cid, Load.getRootProject(st.units))
|
||||
}
|
||||
|
||||
def current(state: State): (URI, String) = session(state).current
|
||||
def currentRef(state: State): ProjectRef =
|
||||
{
|
||||
val (unit, it) = current(state)
|
||||
|
|
@ -80,12 +85,25 @@ object Project extends Init[Scope]
|
|||
|
||||
import SessionSettings._
|
||||
|
||||
final class SessionSettings(val currentBuild: URI, val currentProject: Map[URI, String], val original: Seq[Setting[_]], val prepend: SessionMap, val append: SessionMap) {
|
||||
final case class SessionSettings(currentBuild: URI, currentProject: Map[URI, String], original: Seq[Setting[_]], prepend: SessionMap, append: SessionMap, currentEval: () => Eval)
|
||||
{
|
||||
assert(currentProject contains currentBuild, "Current build (" + currentBuild + ") not associated with a current project.")
|
||||
def setCurrent(build: URI, project: String): SessionSettings = new SessionSettings(build, currentProject.updated(build, project), original, prepend, append)
|
||||
def setCurrent(build: URI, project: String, eval: () => Eval): SessionSettings = copy(currentBuild = build, currentProject = currentProject.updated(build, project), currentEval = eval)
|
||||
def current: (URI, String) = (currentBuild, currentProject(currentBuild))
|
||||
def appendSettings(s: Seq[SessionSetting]): SessionSettings = copy(append = modify(append, _ ++ s))
|
||||
def prependSettings(s: Seq[SessionSetting]): SessionSettings = copy(prepend = modify(prepend, s ++ _))
|
||||
def mergeSettings: Seq[Setting[_]] = merge(prepend) ++ original ++ merge(append)
|
||||
|
||||
private[this] def merge(map: SessionMap): Seq[Setting[_]] = map.values.toSeq.flatten[SessionSetting].map(_._1)
|
||||
private[this] def modify(map: SessionMap, onSeq: Endo[Seq[SessionSetting]]): SessionMap =
|
||||
{
|
||||
val cur = current
|
||||
map.updated(cur, onSeq(map.getOrElse( cur, Nil)))
|
||||
}
|
||||
|
||||
}
|
||||
object SessionSettings {
|
||||
object SessionSettings
|
||||
{
|
||||
type SessionSetting = (Setting[_], String)
|
||||
type SessionMap = Map[(URI, String), Seq[SessionSetting]]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,12 @@ final class ProjectNavigation(s: State)
|
|||
val (uri, pid) = session.current
|
||||
val projects = Load.getBuild(structure.units, uri).defined.keys
|
||||
|
||||
def setProject(uri: URI, id: String) = updateCurrent(s.put(SessionKey, session.setCurrent(uri, id)))
|
||||
def setProject(nuri: URI, nid: String) =
|
||||
{
|
||||
val neval = if(uri == nuri) session.currentEval else mkEval()
|
||||
updateCurrent(s.put(SessionKey, session.setCurrent(nuri, nid, neval)))
|
||||
}
|
||||
def mkEval() = Load.lazyEval(structure.units(uri).unit)
|
||||
def getRoot(uri: URI) = Load.getRootProject(structure.units)(uri)
|
||||
|
||||
def apply(action: Navigate): State =
|
||||
|
|
|
|||
Loading…
Reference in New Issue