diff --git a/main/src/main/scala/sbt/internal/Load.scala b/main/src/main/scala/sbt/internal/Load.scala index 01d0c3741..e7ca88338 100755 --- a/main/src/main/scala/sbt/internal/Load.scala +++ b/main/src/main/scala/sbt/internal/Load.scala @@ -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. * 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. * - * @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 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 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 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 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. - * - * 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( newProjects: Seq[Project], @@ -847,9 +849,35 @@ private[sbt] object Load { extraSbtFiles: Seq[File] ): LoadedProjects = /*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) - 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) + } + // Step two: // a. Apply all the project manipulations from .sbt files in order // b. Deduce the auto plugins for the project @@ -859,42 +887,34 @@ private[sbt] object Load { files: Seq[File], expand: Boolean ): (Project, Seq[Project]) = { - val configFiles = files flatMap { f => - memoSettings.get(f) - } - val p1: Project = - configFiles.flatMap(_.manipulations).foldLeft(p) { (prev, t) => - t(prev) - } + val configFiles = files.flatMap(f => memoSettings.get(f)) + val p1: Project = Function.chain(configFiles.flatMap(_.manipulations))(p) val autoPlugins: Seq[AutoPlugin] = try plugins.detected.deducePluginsFromProject(p1, log) catch { case e: AutoPluginException => throw translateAutoPluginException(e, p) } - val extra = - if (context.globalPluginProject) extraSbtFiles - else Nil - val p2 = - this.resolveProject(p1, autoPlugins, plugins, injectSettings, memoSettings, extra, log) + val extra = if (context.globalPluginProject) extraSbtFiles else Nil + val p2 = resolveProject(p1, autoPlugins, plugins, injectSettings, memoSettings, extra, log) val projectLevelExtra = - if (expand) autoPlugins flatMap { - _.derivedProjects(p2) map { _.setProjectOrigin(ProjectOrigin.DerivedProject) } + if (expand) { + autoPlugins.flatMap( + _.derivedProjects(p2).map(_.setProjectOrigin(ProjectOrigin.DerivedProject)) + ) } else Nil (p2, projectLevelExtra) } + // 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): (Project, Seq[Project], Seq[File]) = { - val (root, discovered, files, generated) = - discover(AddSettings.allDefaults, p.base) match { - case DiscoveredProjects(Some(root), rest, files, generated) => - // TODO - We assume here the project defined in a build.sbt WINS because the original was - // a phony. However, we may want to 'merge' the two, or only do this if the original was a default - // generated project. - (root, rest, files, generated) - case DiscoveredProjects(None, rest, files, generated) => (p, rest, files, generated) - } - val (finalRoot, projectLevelExtra) = - finalizeProject(root, files, true) - (finalRoot, discovered ++ projectLevelExtra, generated) + def discoverAndLoad(p: Project, rest: Seq[Project]): LoadedProjects = { + val DiscoveredProjects(rootOpt, discovered, files, generated) = discover(p.base) + // TODO: We assume here the project defined in a build.sbt WINS because the original was a + // phony. However, we may want to 'merge' the two, or only do this if the original was a + // default generated project. + val root = rootOpt.getOrElse(p) + val (finalRoot, projectLevelExtra) = finalizeProject(root, files, true) + val newProjects = rest ++ discovered ++ projectLevelExtra + val newAcc = acc :+ finalRoot + val newGenerated = generated ++ generatedConfigClassFiles + load(newProjects, newAcc, newGenerated) } // 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 { 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, - Nil - ) + discoverAndLoad(next, rest) case Nil if makeOrDiscoverRoot => - log.debug(s"[Loading] Scanning directory ${buildBase}") - 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, - 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(",")}") + log.debug(s"[Loading] Scanning directory $buildBase") + val DiscoveredProjects(rootOpt, discovered, files, generated) = discover(buildBase) + val discoveredIdsStr = discovered.map(_.id).mkString(",") + val (root, expand, moreProjects, otherProjects) = rootOpt match { + case Some(root) => + log.debug(s"[Loading] Found root project ${root.id} w/ remaining $discoveredIdsStr") + (root, true, discovered, LoadedProjects(Nil, Nil)) + case None => + log.debug(s"[Loading] Found non-root projects $discoveredIdsStr") // 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, - 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 = + val otherProjects = load(discovered, acc, Nil) + val root = { + val existingIds = otherProjects.projects.map(_.id) + val defaultID = autoID(buildBase, context, existingIds) + val refs = existingIds.map(id => ProjectRef(buildUri, id)) if (discovered.isEmpty || java.lang.Boolean.getBoolean("sbt.root.ivyplugin")) BuildDef.defaultAggregatedProject(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) - log.debug( - s"[Loading] Done in ${buildBase}, returning: ${result.map(_.id).mkString("(", ", ", ")")}" - ) - LoadedProjects(result, generated ++ otherGenerated ++ generatedConfigClassFiles) + (root, false, Nil, otherProjects) } + 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 => - log.debug( - s"[Loading] Done in ${buildBase}, returning: ${acc.map(_.id).mkString("(", ", ", ")")}" - ) + val projectIds = acc.map(_.id).mkString("(", ", ", ")") + log.debug(s"[Loading] Done in $buildBase, returning: $projectIds") LoadedProjects(acc, generatedConfigClassFiles) } }