[2.x] fix: clear compiler bridge zinc cache on reboot dev (#9057)

Reboot dev now removes zinc/org.scala-sbt under the resolved global zinc
directory (same layout as ZincComponentManager secondary cache).

Closes #5735
This commit is contained in:
bitloi
2026-04-13 04:28:43 -04:00
committed by GitHub
parent 25dd9b7363
commit 936a7e1ffb
3 changed files with 65 additions and 2 deletions
@@ -149,7 +149,9 @@ $HelpCommand <regular expression>
remaining commands with the exception that the JVM is not shut down.
If 'dev' is specified, the current sbt artifacts from the boot directory
(`~/.sbt/boot` by default) are deleted before restarting.
(under the default global base; `sbt.global.base` selects that location) are deleted
before restarting, and the compiler bridge secondary cache at `zinc/org.scala-sbt`
(honoring `sbt.global.base` and `sbt.global.zinc`) is removed.
This forces an update of sbt and Scala, which is useful when working with development
versions of sbt.
If 'full' is specified, the boot directory is wiped out before restarting.
+13 -1
View File
@@ -22,6 +22,8 @@ import sbt.internal.util.{
Terminal as ITerminal
}
import sbt.io.{ IO, Using }
import sbt.io.syntax.*
import sbt.librarymanagement.SbtArtifacts
import sbt.protocol.*
import sbt.util.{ Logger, LoggerContext }
@@ -75,6 +77,10 @@ private[sbt] object MainLoop:
case e: RebootCurrent =>
deleteLastLog(logBacking)
deleteCurrentArtifacts(state)
deleteZincBridgeSecondaryCache(
state.log,
BuildPaths.getZincDirectory(state, BuildPaths.getGlobalBase(state)),
)
throw new xsbti.FullReload(e.arguments.toArray, false)
case NonFatal(e) =>
System.err.println(
@@ -89,7 +95,6 @@ private[sbt] object MainLoop:
/** Deletes the current sbt artifacts from boot. */
private[sbt] def deleteCurrentArtifacts(state: State): Unit = {
import sbt.io.syntax.*
val provider = state.configuration.provider
val appId = provider.id
// If we can obtain boot directory more accurately it'd be better.
@@ -109,6 +114,13 @@ private[sbt] object MainLoop:
}
}
/** Removes the Zinc compiler bridge secondary cache (`zincDir/org.scala-sbt`). */
private[sbt] def deleteZincBridgeSecondaryCache(log: Logger, zincDir: File): Unit =
val bridgeCache = zincDir / SbtArtifacts.Organization
if bridgeCache.exists() then
log.info(s"deleting $bridgeCache")
IO.delete(bridgeCache)
/** Runs the next sequence of commands with global logging in place. */
def runWithNewLog(state: State, logBacking: GlobalLogBacking): RunNext =
Using.fileWriter(append = true)(logBacking.file) { writer =>
@@ -0,0 +1,49 @@
/*
* sbt
* Copyright 2023, Scala center
* Copyright 2011 - 2022, Lightbend, Inc.
* Copyright 2008 - 2010, Mark Harrah
* Licensed under Apache License 2.0 (see LICENSE)
*/
package sbt
import java.io.File
import sbt.internal.util.{ ConsoleOut, GlobalLogging, MainAppender }
import sbt.io.IO
import sbt.io.syntax.*
import sbt.librarymanagement.SbtArtifacts
import sbt.util.Logger
object MainLoopZincCacheTest extends verify.BasicTestSuite:
private def withTestLog[A](f: Logger => A): A =
val logFile = File.createTempFile("sbt-mlz", ".log")
try
val gl = GlobalLogging.initial(
MainAppender.globalDefault(ConsoleOut.globalProxy),
logFile,
ConsoleOut.globalProxy
)
f(gl.full)
finally IO.delete(logFile)
test("deleteZincBridgeSecondaryCache removes org.scala-sbt under zincDir"):
IO.withTemporaryDirectory: tmp =>
val zincRoot = tmp / "zinc"
val bridge = zincRoot / SbtArtifacts.Organization
IO.write(bridge / "marker.txt", "cached")
withTestLog: log =>
MainLoop.deleteZincBridgeSecondaryCache(log, zincRoot)
assert(!bridge.exists(), s"expected $bridge deleted")
test("deleteZincBridgeSecondaryCache is a no-op when org.scala-sbt is absent"):
IO.withTemporaryDirectory: tmp =>
val zincRoot = tmp / "zinc"
IO.createDirectory(zincRoot)
withTestLog: log =>
MainLoop.deleteZincBridgeSecondaryCache(log, zincRoot)
assert(zincRoot.exists())
end MainLoopZincCacheTest