Merge pull request #4819 from dwijnand/cleanup-Load.loadTransitive

Cleanup Load.loadTransitive
This commit is contained in:
eugene yokota 2019-08-29 23:24:29 -04:00 committed by GitHub
commit ea778e9a5c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 83 additions and 114 deletions

View File

@ -811,25 +811,27 @@ private[sbt] object Load {
* 1. The first `Project` instance we encounter defines AddSettings and gets to specify where we pull other settings. * 1. The first `Project` instance we encounter defines AddSettings and gets to specify where we pull other settings.
* 2. Any project manipulation (enable/disablePlugins) is ok to be added in the order we encounter it. * 2. Any project manipulation (enable/disablePlugins) is ok to be added in the order we encounter it.
* *
* Any further setting is ignored, as even the SettingSet API should be deprecated/removed with sbt 1.0. * Any further setting is ignored.
* *
* Note: Lots of internal details in here that shouldn't be otherwise exposed. * Note: Lots of internal details in here that shouldn't be otherwise exposed.
* *
* @param newProjects A sequence of projects we have not yet loaded, but will try to. Must not be Nil * 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.
*
* @param newProjects A sequence of projects we have not yet loaded, but will try to.
* @param buildBase The `baseDirectory` for the entire build. * @param buildBase The `baseDirectory` for the entire build.
* @param plugins A misnomer, this is actually the compiled BuildDefinition (classpath and such) for this project. * @param plugins A misnomer, this is actually the compiled BuildDefinition (classpath and such) for this project.
* @param eval A mechanism of generating an "Eval" which can compile scala code for us. * @param eval A mechanism of generating an "Eval" which can compile scala code for us.
* @param injectSettings Settings we need to inject into projects. * @param injectSettings Settings we need to inject into projects.
* @param acc An accumulated list of loaded projects. TODO - how do these differ from newProjects? * @param acc An accumulated list of loaded projects, originally in newProjects.
* @param memoSettings A recording of all sbt files that have been loaded so far. * @param memoSettings A recording of all sbt files that have been loaded so far.
* @param log The logger used for this project. * @param log The logger used for this project.
* @param makeOrDiscoverRoot True if we should autogenerate a root project. * @param makeOrDiscoverRoot True if we should auto-generate a root project.
* @param buildUri The URI of the build this is loading * @param buildUri The URI of the build this is loading
* @param context The plugin management context for autogenerated IDs. * @param context The plugin management context for autogenerated IDs.
* @param generatedConfigClassFiles
* @param extraSbtFiles
* @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],
@ -847,9 +849,35 @@ private[sbt] object Load {
extraSbtFiles: Seq[File] extraSbtFiles: Seq[File]
): LoadedProjects = ): LoadedProjects =
/*timed(s"Load.loadTransitive(${ newProjects.map(_.id) })", log)*/ { /*timed(s"Load.loadTransitive(${ newProjects.map(_.id) })", log)*/ {
def load(newProjects: Seq[Project], acc: Seq[Project], generated: Seq[File]) = {
loadTransitive(
newProjects,
buildBase,
plugins,
eval,
injectSettings,
acc,
memoSettings,
log,
false,
buildUri,
context,
generated,
Nil
)
}
// load all relevant configuration files (.sbt, as .scala already exists at this point) // load all relevant configuration files (.sbt, as .scala already exists at this point)
def discover(auto: AddSettings, base: File): DiscoveredProjects = def discover(base: File): DiscoveredProjects = {
val auto =
if (base == buildBase) AddSettings.allDefaults
else if (context.globalPluginProject)
AddSettings.seq(AddSettings.defaultSbtFiles, AddSettings.sbtFiles(extraSbtFiles: _*))
else AddSettings.defaultSbtFiles
discoverProjects(auto, base, plugins, eval, memoSettings) discoverProjects(auto, base, plugins, eval, memoSettings)
}
// Step two: // Step two:
// a. Apply all the project manipulations from .sbt files in order // a. Apply all the project manipulations from .sbt files in order
// b. Deduce the auto plugins for the project // b. Deduce the auto plugins for the project
@ -859,42 +887,34 @@ private[sbt] object Load {
files: Seq[File], files: Seq[File],
expand: Boolean expand: Boolean
): (Project, Seq[Project]) = { ): (Project, Seq[Project]) = {
val configFiles = files flatMap { f => val configFiles = files.flatMap(f => memoSettings.get(f))
memoSettings.get(f) val p1: Project = Function.chain(configFiles.flatMap(_.manipulations))(p)
}
val p1: Project =
configFiles.flatMap(_.manipulations).foldLeft(p) { (prev, t) =>
t(prev)
}
val autoPlugins: Seq[AutoPlugin] = val autoPlugins: Seq[AutoPlugin] =
try plugins.detected.deducePluginsFromProject(p1, log) try plugins.detected.deducePluginsFromProject(p1, log)
catch { case e: AutoPluginException => throw translateAutoPluginException(e, p) } catch { case e: AutoPluginException => throw translateAutoPluginException(e, p) }
val extra = val extra = if (context.globalPluginProject) extraSbtFiles else Nil
if (context.globalPluginProject) extraSbtFiles val p2 = resolveProject(p1, autoPlugins, plugins, injectSettings, memoSettings, extra, log)
else Nil
val p2 =
this.resolveProject(p1, autoPlugins, plugins, injectSettings, memoSettings, extra, log)
val projectLevelExtra = val projectLevelExtra =
if (expand) autoPlugins flatMap { if (expand) {
_.derivedProjects(p2) map { _.setProjectOrigin(ProjectOrigin.DerivedProject) } autoPlugins.flatMap(
_.derivedProjects(p2).map(_.setProjectOrigin(ProjectOrigin.DerivedProject))
)
} else Nil } else Nil
(p2, projectLevelExtra) (p2, projectLevelExtra)
} }
// Discover any new project definition for the base directory of this project, and load all settings. // Discover any new project definition for the base directory of this project, and load all settings.
// Also return any newly discovered project instances. def discoverAndLoad(p: Project, rest: Seq[Project]): LoadedProjects = {
def discoverAndLoad(p: Project): (Project, Seq[Project], Seq[File]) = { val DiscoveredProjects(rootOpt, discovered, files, generated) = discover(p.base)
val (root, discovered, files, generated) = // TODO: We assume here the project defined in a build.sbt WINS because the original was a
discover(AddSettings.allDefaults, p.base) match { // phony. However, we may want to 'merge' the two, or only do this if the original was a
case DiscoveredProjects(Some(root), rest, files, generated) => // default generated project.
// TODO - We assume here the project defined in a build.sbt WINS because the original was val root = rootOpt.getOrElse(p)
// a phony. However, we may want to 'merge' the two, or only do this if the original was a default val (finalRoot, projectLevelExtra) = finalizeProject(root, files, true)
// generated project. val newProjects = rest ++ discovered ++ projectLevelExtra
(root, rest, files, generated) val newAcc = acc :+ finalRoot
case DiscoveredProjects(None, rest, files, generated) => (p, rest, files, generated) val newGenerated = generated ++ generatedConfigClassFiles
} load(newProjects, newAcc, newGenerated)
val (finalRoot, projectLevelExtra) =
finalizeProject(root, files, true)
(finalRoot, discovered ++ projectLevelExtra, generated)
} }
// Load all config files AND finalize the project at the root directory, if it exists. // Load all config files AND finalize the project at the root directory, if it exists.
@ -902,92 +922,41 @@ private[sbt] object Load {
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, generated) = discoverAndLoad(next) discoverAndLoad(next, rest)
loadTransitive(
rest ++ discovered,
buildBase,
plugins,
eval,
injectSettings,
acc :+ finished,
memoSettings,
log,
false,
buildUri,
context,
generated ++ generatedConfigClassFiles,
Nil
)
case Nil if makeOrDiscoverRoot => case Nil if makeOrDiscoverRoot =>
log.debug(s"[Loading] Scanning directory ${buildBase}") log.debug(s"[Loading] Scanning directory $buildBase")
val auto = val DiscoveredProjects(rootOpt, discovered, files, generated) = discover(buildBase)
if (context.globalPluginProject) val discoveredIdsStr = discovered.map(_.id).mkString(",")
AddSettings.seq(AddSettings.defaultSbtFiles, AddSettings.sbtFiles(extraSbtFiles: _*)) val (root, expand, moreProjects, otherProjects) = rootOpt match {
else AddSettings.defaultSbtFiles case Some(root) =>
discover(auto, buildBase) match { log.debug(s"[Loading] Found root project ${root.id} w/ remaining $discoveredIdsStr")
case DiscoveredProjects(Some(root), discovered, files, generated) => (root, true, discovered, LoadedProjects(Nil, Nil))
log.debug( case None =>
s"[Loading] Found root project ${root.id} w/ remaining ${discovered.map(_.id).mkString(",")}" log.debug(s"[Loading] Found non-root projects $discoveredIdsStr")
)
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,
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 // Here we do something interesting... We need to create an aggregate root project
val otherProjects = loadTransitive( val otherProjects = load(discovered, acc, Nil)
discovered, val root = {
buildBase, val existingIds = otherProjects.projects.map(_.id)
plugins, val defaultID = autoID(buildBase, context, existingIds)
eval, val refs = existingIds.map(id => ProjectRef(buildUri, id))
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))
val defaultID = autoID(buildBase, context, existingIds)
val root0 =
if (discovered.isEmpty || java.lang.Boolean.getBoolean("sbt.root.ivyplugin")) if (discovered.isEmpty || java.lang.Boolean.getBoolean("sbt.root.ivyplugin"))
BuildDef.defaultAggregatedProject(defaultID, buildBase, refs) BuildDef.defaultAggregatedProject(defaultID, buildBase, refs)
else BuildDef.generatedRootWithoutIvyPlugin(defaultID, buildBase, refs) else BuildDef.generatedRootWithoutIvyPlugin(defaultID, buildBase, refs)
val (root, _) = timed(s"Load.loadTransitive: finalizeProject2($root0)", log) {
finalizeProject(root0, files, false)
} }
val result = root +: (acc ++ otherProjects.projects) (root, false, Nil, otherProjects)
log.debug(
s"[Loading] Done in ${buildBase}, returning: ${result.map(_.id).mkString("(", ", ", ")")}"
)
LoadedProjects(result, generated ++ otherGenerated ++ generatedConfigClassFiles)
} }
val (finalRoot, projectLevelExtra) =
timed(s"Load.loadTransitive: finalizeProject($root)", log) {
finalizeProject(root, files, expand)
}
val newProjects = moreProjects ++ projectLevelExtra
val newAcc = finalRoot +: (acc ++ otherProjects.projects)
val newGenerated =
generated ++ otherProjects.generatedConfigClassFiles ++ generatedConfigClassFiles
load(newProjects, newAcc, newGenerated)
case Nil => case Nil =>
log.debug( val projectIds = acc.map(_.id).mkString("(", ", ", ")")
s"[Loading] Done in ${buildBase}, returning: ${acc.map(_.id).mkString("(", ", ", ")")}" log.debug(s"[Loading] Done in $buildBase, returning: $projectIds")
)
LoadedProjects(acc, generatedConfigClassFiles) LoadedProjects(acc, generatedConfigClassFiles)
} }
} }