diff --git a/main/src/main/scala/sbt/EvaluateConfigurations.scala b/main/src/main/scala/sbt/EvaluateConfigurations.scala index e2726f09c..eacc0f569 100644 --- a/main/src/main/scala/sbt/EvaluateConfigurations.scala +++ b/main/src/main/scala/sbt/EvaluateConfigurations.scala @@ -40,7 +40,7 @@ object EvaluateConfigurations loader => l(loader).settings } - private[this] def evaluateSbtFile(eval: Eval, file: File, lines: Seq[String], imports: Seq[String], offset: Int): ClassLoader => LoadedSbtFile = + private[sbt] def evaluateSbtFile(eval: Eval, file: File, lines: Seq[String], imports: Seq[String], offset: Int): ClassLoader => LoadedSbtFile = { val name = file.getPath val parsed = parseConfiguration(lines, imports, offset) diff --git a/main/src/main/scala/sbt/Load.scala b/main/src/main/scala/sbt/Load.scala index 71e63eaef..489cb9630 100755 --- a/main/src/main/scala/sbt/Load.scala +++ b/main/src/main/scala/sbt/Load.scala @@ -413,15 +413,15 @@ object Load lazy val eval = mkEval(plugs.classpath, defDir, Nil) val initialProjects = defs.flatMap(_.projectDefinitions(normBase).map(resolveBase(normBase))) - val loadedProjects = loadTransitive(initialProjects, imports, plugs, () => eval, config.injectSettings, Nil) + val loadedProjects = loadTransitive(initialProjects, imports, plugs, () => eval, config.injectSettings, Nil, new mutable.HashMap) val loadedDefs = new sbt.LoadedDefinitions(defDir, Nil, plugs.loader, defs, loadedProjects, defNames) new sbt.BuildUnit(uri, normBase, loadedDefs, plugs) } - private[this] def loadTransitive(newProjects: Seq[Project], imports: Seq[String], plugins: sbt.LoadedPlugins, eval: () => Eval, injectSettings: InjectSettings, acc: Seq[Project]): Seq[Project] = + private[this] def loadTransitive(newProjects: Seq[Project], imports: Seq[String], plugins: sbt.LoadedPlugins, eval: () => Eval, injectSettings: InjectSettings, acc: Seq[Project], memoSettings: mutable.Map[File, LoadedSbtFile]): Seq[Project] = { val loaded = newProjects map { project => - val loadedSbtFiles = loadSettings(project.auto, project.base, imports, plugins, eval, injectSettings) + val loadedSbtFiles = loadSettings(project.auto, project.base, imports, plugins, eval, injectSettings, memoSettings) val transformed = project.copy(settings = (project.settings: Seq[Setting[_]]) ++ loadedSbtFiles.settings) (transformed, loadedSbtFiles.projects) } @@ -432,20 +432,31 @@ object Load if(nextProjects.isEmpty) loadedProjects else - loadTransitive(nextProjects, imports, plugins, eval, injectSettings, loadedProjects) + loadTransitive(nextProjects, imports, plugins, eval, injectSettings, loadedProjects, memoSettings) } - private[this] def loadSettings(auto: AddSettings, projectBase: File, buildImports: Seq[String], loadedPlugins: sbt.LoadedPlugins, eval: ()=>Eval, injectSettings: InjectSettings): LoadedSbtFile = + private[this] def loadSettings(auto: AddSettings, projectBase: File, buildImports: Seq[String], loadedPlugins: sbt.LoadedPlugins, eval: ()=>Eval, injectSettings: InjectSettings, memoSettings: mutable.Map[File, LoadedSbtFile]): LoadedSbtFile = { lazy val defaultSbtFiles = configurationSources(projectBase) def settings(ss: Seq[Setting[_]]) = new LoadedSbtFile(ss, Nil, Nil) val loader = loadedPlugins.loader - import AddSettings.{User,SbtFiles,DefaultSbtFiles,Plugins,Sequence} + def merge(ls: Seq[LoadedSbtFile]): LoadedSbtFile = (LoadedSbtFile.empty /: ls) { _ merge _ } + def loadSettings(fs: Seq[File]): LoadedSbtFile = + merge( fs.sortBy(_.getName).map(memoLoadSettingsFile) ) + def memoLoadSettingsFile(src: File): LoadedSbtFile = memoSettings.get(src) getOrElse { + val lf = loadSettingsFile(src) + memoSettings.put(src, lf.clearProjects) // don't load projects twice + lf + } + def loadSettingsFile(src: File): LoadedSbtFile = + EvaluateConfigurations.evaluateSbtFile(eval(), src, IO.readLines(src), buildImports, 0)(loader) + + import AddSettings.{User,SbtFiles,DefaultSbtFiles,Plugins,Sequence} def expand(auto: AddSettings): LoadedSbtFile = auto match { case User => settings(injectSettings.projectLoaded(loader)) - case sf: SbtFiles => configurations( sf.files.map(f => IO.resolve(projectBase, f)), eval, buildImports )(loader) - case sf: DefaultSbtFiles => configurations( defaultSbtFiles.filter(sf.include), eval, buildImports )(loader) + case sf: SbtFiles => loadSettings( sf.files.map(f => IO.resolve(projectBase, f))) + case sf: DefaultSbtFiles => loadSettings( defaultSbtFiles.filter(sf.include)) case f: Plugins => settings(loadedPlugins.plugins.filter(f.include).flatMap(p => p.settings.filter(isProjectThis) ++ p.projectSettings)) case q: Sequence => (LoadedSbtFile.empty /: q.sequence) { (b,add) => b.merge( expand(add) ) } } diff --git a/main/src/main/scala/sbt/LoadedSbtFile.scala b/main/src/main/scala/sbt/LoadedSbtFile.scala index b8c86dd2e..0f007c002 100644 --- a/main/src/main/scala/sbt/LoadedSbtFile.scala +++ b/main/src/main/scala/sbt/LoadedSbtFile.scala @@ -8,6 +8,7 @@ private[sbt] final class LoadedSbtFile(val settings: Seq[Setting[_]], val projec { def merge(o: LoadedSbtFile): LoadedSbtFile = new LoadedSbtFile(settings ++ o.settings, projects ++ o.projects, importedDefs ++ o.importedDefs) + def clearProjects = new LoadedSbtFile(settings, Nil, importedDefs) } private[sbt] object LoadedSbtFile {