port sddPluginSbtFile command from https://github.com/sbt/sbt/pull/4211/ to sbt 0.13

This commit is contained in:
Justin Kaeser 2018-07-19 14:30:08 +02:00
parent 226d16a0fe
commit 7fb8a4e88a
5 changed files with 75 additions and 19 deletions

View File

@ -74,7 +74,8 @@ object BasicCommandStrings {
val levelLongOptions = Level.values.toSeq map { "--" + _ }
(s.startsWith(EarlyCommand + "(") && s.endsWith(")")) ||
(levelShortOptions contains s) ||
(levelLongOptions contains s)
(levelLongOptions contains s) ||
(s.startsWith("-" + AddPluginSbtFileCommand) || s.startsWith("--" + AddPluginSbtFileCommand))
}
val OldEarlyCommand = "--"
@ -87,6 +88,14 @@ object BasicCommandStrings {
The order is preserved between all early commands, so `sbt "early(a)" "early(b)"` executes `a` and `b` in order.
"""
def addPluginSbtFileHelp = {
val brief =
(s"--$AddPluginSbtFileCommand=<file>", "Adds the given *.sbt file to the plugin build.")
Help(brief)
}
val AddPluginSbtFileCommand = "addPluginSbtFile"
def ReadCommand = "<"
def ReadFiles = " file1 file2 ..."
def ReadDetailed =

View File

@ -22,20 +22,45 @@ object BasicCommands {
def ignore = Command.command(FailureWall)(idFun)
def early = Command.arb(earlyParser, earlyHelp) { (s, other) => other :: s }
private[this] def levelParser: Parser[String] =
token(Level.Debug.toString) | token(Level.Info.toString) | token(Level.Warn.toString) | token(Level.Error.toString)
private[this] def earlyParser: State => Parser[String] = (s: State) =>
(token(EarlyCommand + "(") flatMap { _ =>
otherCommandParser(s) <~ token(")")
}) |
(token("-") flatMap { _ =>
levelParser
}) |
(token(OldEarlyCommand) flatMap { _ =>
levelParser
})
private[this] def addPluginSbtFileParser: Parser[File] = {
token(AddPluginSbtFileCommand) ~> (":" | "=" | Space) ~> (StringBasic)
.examples("/some/extra.sbt") map {
new File(_)
}
}
private[this] def addPluginSbtFileStringParser: Parser[String] = {
token(
token(AddPluginSbtFileCommand) ~ (":" | "=" | Space) ~ (StringBasic)
.examples("/some/extra.sbt") map {
case s1 ~ s2 ~ s3 => s1 + s2 + s3
}
)
}
private[this] def earlyParser: State => Parser[String] = (s: State) => {
val p1 = token(EarlyCommand + "(") flatMap (_ => otherCommandParser(s) <~ token(")"))
val p2 = (token("-") | token("--")) flatMap (_ => levelParser)
val p3 = (token("-") | token("--")) flatMap (_ => addPluginSbtFileStringParser)
p1 | p2 | p3
}
private[this] def earlyHelp = Help(EarlyCommand, EarlyCommandBrief, EarlyCommandDetailed)
/**
* Adds additional *.sbt to the plugin build.
* This must be combined with early command as: --addPluginSbtFile=/tmp/extra.sbt
*/
def addPluginSbtFile: Command = Command.arb(_ => addPluginSbtFileParser, addPluginSbtFileHelp) {
(s, extraSbtFile) =>
val extraFiles = s.get(BasicKeys.extraMetaSbtFiles).toList.flatten
s.put(BasicKeys.extraMetaSbtFiles, extraFiles :+ extraSbtFile)
}
def help = Command.make(HelpCommand, helpBrief, helpDetailed)(helpParser)
def helpParser(s: State) =

View File

@ -5,6 +5,13 @@ import sbt.template.TemplateResolver
object BasicKeys {
val historyPath = AttributeKey[Option[File]]("history", "The location where command line history is persisted.", 40)
val extraMetaSbtFiles = AttributeKey[Seq[File]](
"extraMetaSbtFile",
"Additional plugin.sbt files.",
10000
)
val shellPrompt = AttributeKey[State => String]("shell-prompt", "The function that constructs the command prompt from the current build state.", 10000)
val watch = AttributeKey[Watched]("watch", "Continuous execution configuration.", 1000)
private[sbt] val interactive = AttributeKey[Boolean]("interactive", "True if commands are currently being entered from an interactive environment.", 10)

View File

@ -479,7 +479,7 @@ object Load {
val memoSettings = new mutable.HashMap[File, LoadedSbtFile]
def loadProjects(ps: Seq[Project], createRoot: Boolean) = {
val result = loadTransitive(ps, normBase, plugs, () => eval, config.injectSettings, Nil, memoSettings, config.log, createRoot, uri, config.pluginManagement.context, Nil)
val result = loadTransitive(ps, normBase, plugs, () => eval, config.injectSettings, Nil, memoSettings, config.log, createRoot, uri, config.pluginManagement.context, Nil, s.get(BasicKeys.extraMetaSbtFiles).getOrElse(Nil))
result
}
val loadedProjectsRaw = timed("Load.loadUnit: loadedProjectsRaw", log) { loadProjects(initialProjects, !hasRootAlreadyDefined) }
@ -578,7 +578,8 @@ object Load {
makeOrDiscoverRoot: Boolean,
buildUri: URI,
context: PluginManagement.Context,
generatedConfigClassFiles: Seq[File]): LoadedProjects =
generatedConfigClassFiles: Seq[File],
extraSbtFiles: Seq[File]): LoadedProjects =
/*timed(s"Load.loadTransitive(${ newProjects.map(_.id) })", log)*/ {
// load all relevant configuration files (.sbt, as .scala already exists at this point)
def discover(auto: AddSettings, base: File): DiscoveredProjects =
@ -600,7 +601,11 @@ object Load {
try plugins.detected.deducePluginsFromProject(p1, log)
catch { case e: AutoPluginException => throw translateAutoPluginException(e, p) }
}
val p2 = this.resolveProject(p1, autoPlugins, plugins, injectSettings, memoSettings, log)
val extra =
if (context.globalPluginProject) extraSbtFiles
else Nil
val p2 =
this.resolveProject(p1, autoPlugins, plugins, injectSettings, memoSettings, extra, log)
val projectLevelExtra =
if (expand) autoPlugins flatMap { _.derivedProjects(p2) map {_.setProjectOrigin(ProjectOrigin.DerivedProject)} }
else Nil
@ -627,21 +632,25 @@ object Load {
case Seq(next, rest @ _*) =>
log.debug(s"[Loading] Loading project ${next.id} @ ${next.base}")
val (finished, discovered, generated) = discoverAndLoad(next)
loadTransitive(rest ++ discovered, buildBase, plugins, eval, injectSettings, acc :+ finished, memoSettings, log, false, buildUri, context, generated ++ generatedConfigClassFiles)
loadTransitive(rest ++ discovered, buildBase, plugins, eval, injectSettings, acc :+ finished, memoSettings, log, false, buildUri, context, generated ++ generatedConfigClassFiles, Nil)
case Nil if makeOrDiscoverRoot =>
log.debug(s"[Loading] Scanning directory ${buildBase}")
discover(AddSettings.defaultSbtFiles, buildBase) match {
val auto =
if (context.globalPluginProject)
AddSettings.seq(AddSettings.defaultSbtFiles, AddSettings.sbtFiles(extraSbtFiles: _*))
else AddSettings.defaultSbtFiles
discover(auto, buildBase) match {
case DiscoveredProjects(Some(root), discovered, files, generated) =>
log.debug(s"[Loading] Found root project ${root.id} w/ remaining ${discovered.map(_.id).mkString(",")}")
val (finalRoot, projectLevelExtra) = timed(s"Load.loadTransitive: finalizeProject($root)", log) {
finalizeProject(root, files, true)
}
loadTransitive(discovered ++ projectLevelExtra, buildBase, plugins, eval, injectSettings, finalRoot +: acc, memoSettings, log, false, buildUri, context, generated ++ generatedConfigClassFiles)
loadTransitive(discovered ++ projectLevelExtra, buildBase, plugins, eval, injectSettings, finalRoot +: acc, memoSettings, log, false, buildUri, context, generated ++ generatedConfigClassFiles, Nil)
// Here we need to create a root project...
case DiscoveredProjects(None, discovered, files, generated) =>
log.debug(s"[Loading] Found non-root projects ${discovered.map(_.id).mkString(",")}")
// Here we do something interesting... We need to create an aggregate root project
val otherProjects = loadTransitive(discovered, buildBase, plugins, eval, injectSettings, acc, memoSettings, log, false, buildUri, context, Nil)
val otherProjects = loadTransitive(discovered, buildBase, plugins, eval, injectSettings, acc, memoSettings, log, false, buildUri, context, Nil, Nil)
val otherGenerated = otherProjects.generatedConfigClassFiles
val existingIds = otherProjects.projects map (_.id)
val refs = existingIds map (id => ProjectRef(buildUri, id))
@ -691,6 +700,7 @@ object Load {
* @param globalUserSettings All the settings contributed from the ~/.sbt/<version> directory
* @param memoSettings A recording of all loaded files (our files should reside in there). We should need not load any
* sbt file to resolve a project.
* @param extraSbtFiles Extra *.sbt files.
* @param log A logger to report auto-plugin issues to.
*/
private[this] def resolveProject(
@ -699,6 +709,7 @@ object Load {
loadedPlugins: sbt.LoadedPlugins,
globalUserSettings: InjectSettings,
memoSettings: mutable.Map[File, LoadedSbtFile],
extraSbtFiles: Seq[File],
log: Logger): Project =
timed(s"Load.resolveProject(${p.id})", log) {
import AddSettings._
@ -740,7 +751,10 @@ object Load {
case q: Sequence => (Seq.empty[Setting[_]] /: q.sequence) { (b, add) => b ++ expandSettings(add) }
}
timed(s"Load.resolveProject(${p.id}): expandSettings(...)", log) {
expandSettings(p.auto)
val auto = if (extraSbtFiles.nonEmpty) {
AddSettings.seq(autoPlugins, buildScalaFiles, userSettings, nonAutoPlugins, AddSettings.defaultSbtFiles, AddSettings.sbtFiles(extraSbtFiles: _*))
} else p.auto
expandSettings(auto)
}
}
// Finally, a project we can use in buildStructure.

View File

@ -95,6 +95,7 @@ object BuiltinCommands {
projects, project, reboot, read, history, set, sessionCommand, inspect, loadProjectImpl, loadFailed,
Cross.crossBuild, Cross.switchVersion, PluginCross.pluginCross, PluginCross.pluginSwitch,
setOnFailure, clearOnFailure, stashOnFailure, popOnFailure, setLogLevel, plugin, plugins,
addPluginSbtFile,
writeSbtVersion, notifyUsersAboutShell,
ifLast, multi, shell, continuous, eval, alias, append, last, lastGrep, export, boot, nop, call, exit, early, initialize, act) ++
compatCommands