From 8cb7e230110e846b577539e61757e815f083294e Mon Sep 17 00:00:00 2001 From: Mark Harrah Date: Fri, 1 Feb 2013 13:10:27 -0500 Subject: [PATCH] Load global plugins in their own class loader and replace the base loader with that. Fixes #272. Also, replace the base classpath with the global classpath. --- main/src/main/scala/sbt/Load.scala | 28 ++++++++++++++----- .../global/plugins/A.scala | 0 .../project/Build.scala | 0 .../sbt-test/project/global-plugin-src/test | 4 +++ .../project/global-plugin/changes/Build.scala | 21 ++++++++++++++ .../global-plugin/changes/global-plugins.sbt | 3 ++ .../project/global-plugin/changes/plugins.sbt | 2 ++ sbt/src/sbt-test/project/global-plugin/test | 19 +++++++++++-- 8 files changed, 67 insertions(+), 10 deletions(-) rename sbt/src/sbt-test/project/{global-plugin => global-plugin-src}/global/plugins/A.scala (100%) rename sbt/src/sbt-test/project/{global-plugin => global-plugin-src}/project/Build.scala (100%) create mode 100644 sbt/src/sbt-test/project/global-plugin-src/test create mode 100644 sbt/src/sbt-test/project/global-plugin/changes/Build.scala create mode 100644 sbt/src/sbt-test/project/global-plugin/changes/global-plugins.sbt create mode 100644 sbt/src/sbt-test/project/global-plugin/changes/plugins.sbt diff --git a/main/src/main/scala/sbt/Load.scala b/main/src/main/scala/sbt/Load.scala index 1e08a69ca..8c760b5c3 100755 --- a/main/src/main/scala/sbt/Load.scala +++ b/main/src/main/scala/sbt/Load.scala @@ -74,15 +74,25 @@ object Load } def buildGlobalSettings(base: File, files: Seq[File], config: LoadBuildConfiguration): ClassLoader => Seq[Setting[_]] = { - val eval = mkEval(data(config.globalPluginClasspath), base, defaultEvalOptions) + val eval = mkEval(data(config.classpath), base, defaultEvalOptions) val imports = baseImports ++ importAllRoot(config.globalPluginNames) loader => EvaluateConfigurations(eval, files, imports)(loader).settings } def loadGlobal(state: State, base: File, global: File, config: LoadBuildConfiguration): LoadBuildConfiguration = - if(base != global && global.exists) - config.copy(globalPlugin = Some(GlobalPlugin.load(global, state, config))) - else + if(base != global && global.exists) { + val gp = GlobalPlugin.load(global, state, config) + val pm = setGlobalPluginLoader(gp, config.pluginManagement) + val cp = (gp.data.fullClasspath ++ config.classpath).distinct + config.copy(globalPlugin = Some(gp), pluginManagement = pm, classpath = cp) + } else config + + private[this] def setGlobalPluginLoader(gp: GlobalPlugin, pm: PluginManagement): PluginManagement = + { + val newLoader = ClasspathUtilities.toLoader(Build.data(gp.data.fullClasspath), pm.initialLoader) + pm.copy(initialLoader = newLoader) + } + def defaultDelegates: LoadedBuild => Scope => Seq[Scope] = (lb: LoadedBuild) => { val rootProject = getRootProject(lb.units) def resolveRef(project: Reference): ResolvedReference = Scope.resolveReference(lb.root, rootProject, project) @@ -441,6 +451,7 @@ object Load expand(auto) } + @deprecated("No longer used.", "0.13.0") def globalPluginClasspath(globalPlugin: Option[GlobalPlugin]): Seq[Attributed[File]] = globalPlugin match { @@ -483,7 +494,7 @@ object Load !(dir * -GlobFilter(DefaultTargetName)).get.isEmpty } def noPlugins(dir: File, config: LoadBuildConfiguration): LoadedPlugins = - loadPluginDefinition(dir, config, PluginData(config.globalPluginClasspath, None, None)) + loadPluginDefinition(dir, config, PluginData(config.classpath, None, None)) def buildPlugins(dir: File, s: State, config: LoadBuildConfiguration): LoadedPlugins = loadPluginDefinition(dir, config, buildPluginDefinition(dir, s, config)) @@ -661,8 +672,11 @@ final case class LoadBuildConfiguration(stagingDirectory: File, classpath: Seq[A pluginManagement: PluginManagement, injectSettings: Load.InjectSettings, globalPlugin: Option[GlobalPlugin], extraBuilds: Seq[URI], log: Logger) { - lazy val (globalPluginClasspath, globalPluginLoader) = Load.pluginDefinitionLoader(this, Load.globalPluginClasspath(globalPlugin)) - lazy val globalPluginNames = if(globalPluginClasspath.isEmpty) Nil else Load.getPluginNames(globalPluginClasspath, globalPluginLoader) + @deprecated("Use `classpath`.", "0.13.0") + lazy val globalPluginClasspath = classpath + @deprecated("Use `pluginManagement.initialLoader`.", "0.13.0") + lazy val globalPluginLoader = pluginManagement.initialLoader + lazy val globalPluginNames = if(classpath.isEmpty) Nil else Load.getPluginNames(classpath, pluginManagement.initialLoader) } final class IncompatiblePluginsException(msg: String, cause: Throwable) extends Exception(msg, cause) \ No newline at end of file diff --git a/sbt/src/sbt-test/project/global-plugin/global/plugins/A.scala b/sbt/src/sbt-test/project/global-plugin-src/global/plugins/A.scala similarity index 100% rename from sbt/src/sbt-test/project/global-plugin/global/plugins/A.scala rename to sbt/src/sbt-test/project/global-plugin-src/global/plugins/A.scala diff --git a/sbt/src/sbt-test/project/global-plugin/project/Build.scala b/sbt/src/sbt-test/project/global-plugin-src/project/Build.scala similarity index 100% rename from sbt/src/sbt-test/project/global-plugin/project/Build.scala rename to sbt/src/sbt-test/project/global-plugin-src/project/Build.scala diff --git a/sbt/src/sbt-test/project/global-plugin-src/test b/sbt/src/sbt-test/project/global-plugin-src/test new file mode 100644 index 000000000..a100beb21 --- /dev/null +++ b/sbt/src/sbt-test/project/global-plugin-src/test @@ -0,0 +1,4 @@ +# tests that a source file in $sbt.global.base/plugins/ is available to the build definition in project/ + +# dummy to ensure project gets loaded +> name diff --git a/sbt/src/sbt-test/project/global-plugin/changes/Build.scala b/sbt/src/sbt-test/project/global-plugin/changes/Build.scala new file mode 100644 index 000000000..64db72659 --- /dev/null +++ b/sbt/src/sbt-test/project/global-plugin/changes/Build.scala @@ -0,0 +1,21 @@ +import sbt._ +import sbt.Keys._ + +object MyBuild extends Build { + lazy val mySettings = Defaults.defaultSettings ++ Seq( + name := "my-test-proj", + organization := "com.example", + check <<= update map checkVersion, + version := "0.1.0-SNAPSHOT") + + lazy val proj = Project("my-test-proj", file("."), settings = mySettings) + + lazy val check = taskKey[Unit]("Verifies that the junit dependency has the older version (4.5)") + + def checkVersion(report: UpdateReport) { + for(mod <- report.allModules) { + if(mod.name == "junit") assert(mod.revision == "4.5", s"JUnit version (${mod.revision}) was not overridden") + } + } +} + diff --git a/sbt/src/sbt-test/project/global-plugin/changes/global-plugins.sbt b/sbt/src/sbt-test/project/global-plugin/changes/global-plugins.sbt new file mode 100644 index 000000000..9e2ae07df --- /dev/null +++ b/sbt/src/sbt-test/project/global-plugin/changes/global-plugins.sbt @@ -0,0 +1,3 @@ +// use a small java library instead of a plugin to avoid incompatibilities when upgrading +// use an old version to check that it will override a newer version in a build definition +libraryDependencies += "junit" % "junit" % "4.5" diff --git a/sbt/src/sbt-test/project/global-plugin/changes/plugins.sbt b/sbt/src/sbt-test/project/global-plugin/changes/plugins.sbt new file mode 100644 index 000000000..0cfd68572 --- /dev/null +++ b/sbt/src/sbt-test/project/global-plugin/changes/plugins.sbt @@ -0,0 +1,2 @@ +// the version should be overridden by the global plugin +libraryDependencies += "junit" % "junit" % "4.8" diff --git a/sbt/src/sbt-test/project/global-plugin/test b/sbt/src/sbt-test/project/global-plugin/test index a100beb21..0d7ace21b 100644 --- a/sbt/src/sbt-test/project/global-plugin/test +++ b/sbt/src/sbt-test/project/global-plugin/test @@ -1,4 +1,17 @@ -# tests that a source file in $sbt.global.base/plugins/ is available to the build definition in project/ +$ copy-file changes/Build.scala project/Build.scala +> reload -# dummy to ensure project gets loaded -> name +# ensure that a new global dependency gets picked up +$ copy-file changes/global-plugins.sbt global/plugins/plugins.sbt +> reload + +# check that the class can be loaded +> eval Class.forName("org.junit.Test") + +# check that it is on the classpath +> eval (x => ()) : (org.junit.Test => Unit) + +# ensure that the global plugin version overrides the local version +$ copy-file changes/plugins.sbt project/plugins.sbt +> reload +> check