[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 05:28:43 -03:00 committed by GitHub
parent 25dd9b7363
commit 936a7e1ffb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 65 additions and 2 deletions

View File

@ -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.

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 =>

View File

@ -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