From 75edb0afe0526a84f47b93a19d98f869dde7a775 Mon Sep 17 00:00:00 2001 From: eugene yokota Date: Sun, 5 Apr 2026 03:13:23 -0400 Subject: [PATCH] [2.0.x] fix: Fixes metabuild reloading (#9019) **Problem** There seems to be multiple problems around metabuild reloading (reload plugins). 1. Originally reported issue 9006 states that the build can't come back from reload plugins. 2. During the course of fixing, I discovered that when reload plugins is used the project name is set to "project" instead of foo-build etc. 3. Also there was a bug in the rootPaths when reload plugins is used, which results in class not defined error. **Solution** 1. Fix the plugin context so reload plugin still behaves like a metabuild. 2. Fix the rootPaths. --- main/src/main/scala/sbt/internal/Load.scala | 8 ++++--- .../scala/sbt/internal/PluginManagement.scala | 5 +++- .../metabuild/project/FooPlugin.scala | 24 +++++++++++++++++++ .../metabuild/project/project/FooPlugin.scala | 24 +++++++++++++++++++ .../src/sbt-test/project-load/metabuild/test | 9 +++++++ 5 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 sbt-app/src/sbt-test/project-load/metabuild/project/FooPlugin.scala create mode 100644 sbt-app/src/sbt-test/project-load/metabuild/project/project/FooPlugin.scala create mode 100644 sbt-app/src/sbt-test/project-load/metabuild/test diff --git a/main/src/main/scala/sbt/internal/Load.scala b/main/src/main/scala/sbt/internal/Load.scala index 8ca8d88d2..bc7e6c040 100755 --- a/main/src/main/scala/sbt/internal/Load.scala +++ b/main/src/main/scala/sbt/internal/Load.scala @@ -73,10 +73,10 @@ private[sbt] object Load { val launcher = scalaProvider.launcher val stagingDirectory = getStagingDirectory(state, globalBase).getCanonicalFile val javaHome = Util.javaHome - val out = baseDirectory.toPath.resolve("target").resolve("out") + val out = app.baseDirectory.toPath.resolve("target").resolve("out") val rootPaths = Map( "OUT" -> out, - "BASE" -> baseDirectory.toPath, + "BASE" -> app.baseDirectory.toPath, "SBT_BOOT" -> launcher.bootDirectory.toPath, "IVY_HOME" -> launcher.ivyHome.toPath, "JAVA_HOME" -> javaHome, @@ -119,7 +119,9 @@ private[sbt] object Load { ) val evalPluginDef: (BuildStructure, State) => PluginData = EvaluateTask.evalPluginDef val delegates = defaultDelegates - val pluginMgmt = PluginManagement(loader) + import sbt.ProjectExtra.projectReturn + val pluginContext = PluginManagement.Context(false, Project.projectReturn(state).size - 1) + val pluginMgmt = PluginManagement(loader, pluginContext) val inject = InjectSettings(injectGlobal(state), Nil, const(Nil)) SysProp.setSwovalTempDir() SysProp.setIpcSocketTempDir() diff --git a/main/src/main/scala/sbt/internal/PluginManagement.scala b/main/src/main/scala/sbt/internal/PluginManagement.scala index 0a9c94980..e551b3c44 100644 --- a/main/src/main/scala/sbt/internal/PluginManagement.scala +++ b/main/src/main/scala/sbt/internal/PluginManagement.scala @@ -54,12 +54,15 @@ object PluginManagement { val emptyContext: Context = Context(false, 0) def apply(initialLoader: ClassLoader): PluginManagement = + PluginManagement(initialLoader, emptyContext) + + def apply(initialLoader: ClassLoader, context: Context): PluginManagement = PluginManagement( Set.empty, Set.empty, new PluginClassLoader(initialLoader), initialLoader, - emptyContext + context ) def extractOverrides(classpath: Classpath): Set[ModuleID] = diff --git a/sbt-app/src/sbt-test/project-load/metabuild/project/FooPlugin.scala b/sbt-app/src/sbt-test/project-load/metabuild/project/FooPlugin.scala new file mode 100644 index 000000000..5633f3307 --- /dev/null +++ b/sbt-app/src/sbt-test/project-load/metabuild/project/FooPlugin.scala @@ -0,0 +1,24 @@ +package example + +import sbt.* +import Keys.* +import complete.DefaultParsers.{ *, given } + +object FooPlugin extends AutoPlugin: + override def requires = empty + override def trigger = allRequirements + + lazy object autoImport: + @transient + lazy val foo = taskKey[Unit]("foo") + lazy val check = inputKey[Unit]("check") + + import autoImport.* + override def projectSettings: Seq[Def.Setting[?]] = Seq( + foo := println("foo"), + check := { + val args = spaceDelimited("").parsed + assert(name.value.endsWith(args.head), s"${name.value} does not end with ${args.head}") + }, + ) +end FooPlugin diff --git a/sbt-app/src/sbt-test/project-load/metabuild/project/project/FooPlugin.scala b/sbt-app/src/sbt-test/project-load/metabuild/project/project/FooPlugin.scala new file mode 100644 index 000000000..5633f3307 --- /dev/null +++ b/sbt-app/src/sbt-test/project-load/metabuild/project/project/FooPlugin.scala @@ -0,0 +1,24 @@ +package example + +import sbt.* +import Keys.* +import complete.DefaultParsers.{ *, given } + +object FooPlugin extends AutoPlugin: + override def requires = empty + override def trigger = allRequirements + + lazy object autoImport: + @transient + lazy val foo = taskKey[Unit]("foo") + lazy val check = inputKey[Unit]("check") + + import autoImport.* + override def projectSettings: Seq[Def.Setting[?]] = Seq( + foo := println("foo"), + check := { + val args = spaceDelimited("").parsed + assert(name.value.endsWith(args.head), s"${name.value} does not end with ${args.head}") + }, + ) +end FooPlugin diff --git a/sbt-app/src/sbt-test/project-load/metabuild/test b/sbt-app/src/sbt-test/project-load/metabuild/test new file mode 100644 index 000000000..68aec72a2 --- /dev/null +++ b/sbt-app/src/sbt-test/project-load/metabuild/test @@ -0,0 +1,9 @@ +> foo +> reload plugins +> check -build +> foo +> reload plugins +> reload return +> reload return +> compile +> foo