mirror of https://github.com/sbt/sbt.git
[2.x] fix: clear compiler bridge zinc cache on reboot dev
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:
parent
7218b2a1ac
commit
47302ccfc2
|
|
@ -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.
|
||||
(`~/.sbt/boot` by default) are deleted before restarting, and the compiler bridge
|
||||
secondary cache (`zinc/org.scala-sbt` under the global sbt directory, respecting
|
||||
`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.
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import sbt.internal.util.{
|
|||
Terminal as ITerminal
|
||||
}
|
||||
import sbt.io.{ IO, Using }
|
||||
import sbt.librarymanagement.SbtArtifacts
|
||||
import sbt.protocol.*
|
||||
import sbt.util.{ Logger, LoggerContext }
|
||||
|
||||
|
|
@ -75,6 +76,7 @@ private[sbt] object MainLoop:
|
|||
case e: RebootCurrent =>
|
||||
deleteLastLog(logBacking)
|
||||
deleteCurrentArtifacts(state)
|
||||
deleteZincBridgeSecondaryCache(state)
|
||||
throw new xsbti.FullReload(e.arguments.toArray, false)
|
||||
case NonFatal(e) =>
|
||||
System.err.println(
|
||||
|
|
@ -109,6 +111,15 @@ private[sbt] object MainLoop:
|
|||
}
|
||||
}
|
||||
|
||||
/** Removes the Zinc compiler bridge secondary cache (`…/zinc/org.scala-sbt`). */
|
||||
private[sbt] def deleteZincBridgeSecondaryCache(state: State): Unit =
|
||||
import sbt.io.syntax.*
|
||||
val zincDir = BuildPaths.getZincDirectory(state, BuildPaths.getGlobalBase(state))
|
||||
val bridgeCache = zincDir / SbtArtifacts.Organization
|
||||
if bridgeCache.exists() then
|
||||
state.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,176 @@
|
|||
/*
|
||||
* 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 java.util.concurrent.Callable
|
||||
|
||||
import sbt.internal.util.{ AttributeMap, ConsoleOut, GlobalLogging, MainAppender }
|
||||
import sbt.io.IO
|
||||
import sbt.io.syntax.*
|
||||
import sbt.librarymanagement.SbtArtifacts
|
||||
|
||||
import xsbti.{
|
||||
AppConfiguration,
|
||||
AppMain,
|
||||
AppProvider,
|
||||
ApplicationID as XApplicationID,
|
||||
ComponentProvider,
|
||||
CrossValue,
|
||||
GlobalLock,
|
||||
Launcher,
|
||||
Repository,
|
||||
ScalaProvider,
|
||||
}
|
||||
|
||||
object MainLoopZincCacheTest extends verify.BasicTestSuite:
|
||||
|
||||
private object Stubs:
|
||||
val NoGlobalLock: GlobalLock = new GlobalLock:
|
||||
def apply[T](lockFile: File, run: Callable[T]): T = run.call()
|
||||
|
||||
lazy val componentProvider: ComponentProvider = new ComponentProvider:
|
||||
def componentLocation(id: String): File = new File(id)
|
||||
def component(id: String): Array[File] = Array.empty
|
||||
def defineComponent(id: String, jars: Array[File]): Unit = ()
|
||||
def addToComponent(id: String, jars: Array[File]): Boolean = false
|
||||
def lockFile(): File = new File(System.getProperty("java.io.tmpdir"), "stub-components.lock")
|
||||
|
||||
lazy val launcher: Launcher = new Launcher:
|
||||
def getScala(version: String): ScalaProvider = Stubs.scalaProvider
|
||||
def getScala(version: String, reason: String): ScalaProvider = Stubs.scalaProvider
|
||||
def getScala(version: String, reason: String, scalaOrg: String): ScalaProvider =
|
||||
Stubs.scalaProvider
|
||||
def app(id: XApplicationID, version: String): AppProvider = Stubs.appProvider
|
||||
def topLoader(): ClassLoader = classOf[String].getClassLoader
|
||||
def globalLock(): GlobalLock = NoGlobalLock
|
||||
def bootDirectory(): File = new File(System.getProperty("java.io.tmpdir"))
|
||||
def ivyRepositories(): Array[Repository] = Array.empty
|
||||
def appRepositories(): Array[Repository] = Array.empty
|
||||
def isOverrideRepositories: Boolean = false
|
||||
def ivyHome(): File = new File(System.getProperty("java.io.tmpdir"))
|
||||
def checksums(): Array[String] = Array.empty
|
||||
|
||||
lazy val scalaProvider: ScalaProvider = new ScalaProvider:
|
||||
def launcher(): Launcher = Stubs.launcher
|
||||
def version(): String = "3.8.3"
|
||||
def loader(): ClassLoader = classOf[String].getClassLoader
|
||||
def jars(): Array[File] = Array.empty
|
||||
def libraryJar(): File = new File("scala-library.jar")
|
||||
def compilerJar(): File = new File("scala-compiler.jar")
|
||||
def app(id: XApplicationID): AppProvider = Stubs.appProvider
|
||||
|
||||
val appId: sbt.ApplicationID = sbt.ApplicationID(
|
||||
"org.scala-sbt",
|
||||
"sbt",
|
||||
"2.0.0",
|
||||
"sbt.xMain",
|
||||
Seq.empty,
|
||||
CrossValue.Disabled,
|
||||
Seq.empty,
|
||||
)
|
||||
|
||||
lazy val appProvider: AppProvider = new AppProvider:
|
||||
def scalaProvider(): ScalaProvider = Stubs.scalaProvider
|
||||
def id(): XApplicationID = appId
|
||||
def loader(): ClassLoader = classOf[String].getClassLoader
|
||||
def mainClass(): Class[? <: AppMain] = classOf[xMain]
|
||||
def entryPoint(): Class[?] = classOf[xMain]
|
||||
def newMain(): AppMain = new xMain()
|
||||
def mainClasspath(): Array[File] = Array.empty
|
||||
def components(): ComponentProvider = Stubs.componentProvider
|
||||
|
||||
def appConfiguration(baseDir: File): AppConfiguration = new AppConfiguration:
|
||||
def arguments(): Array[String] = Array.empty
|
||||
def baseDirectory(): File = baseDir
|
||||
def provider(): AppProvider = Stubs.appProvider
|
||||
|
||||
end Stubs
|
||||
|
||||
private def mkState(zincRoot: File, logFile: File, baseDir: File) =
|
||||
val attrs = AttributeMap.empty
|
||||
.put(BuildPaths.globalBaseDirectory, zincRoot.getParentFile)
|
||||
.put(BuildPaths.globalZincDirectory, zincRoot)
|
||||
State(
|
||||
configuration = Stubs.appConfiguration(baseDir),
|
||||
definedCommands = Nil,
|
||||
exitHooks = Set.empty,
|
||||
onFailure = None,
|
||||
remainingCommands = Nil,
|
||||
history = State.newHistory,
|
||||
attributes = attrs,
|
||||
globalLogging = GlobalLogging.initial(
|
||||
MainAppender.globalDefault(ConsoleOut.globalProxy),
|
||||
logFile,
|
||||
ConsoleOut.globalProxy
|
||||
),
|
||||
currentCommand = None,
|
||||
next = State.Continue
|
||||
)
|
||||
|
||||
test("deleteZincBridgeSecondaryCache removes org.scala-sbt under global zinc"):
|
||||
IO.withTemporaryDirectory: tmp =>
|
||||
val zincRoot = tmp / "zinc"
|
||||
val bridge = zincRoot / SbtArtifacts.Organization
|
||||
IO.write(bridge / "marker.txt", "cached")
|
||||
val logFile = File.createTempFile("sbt-mlz", ".log")
|
||||
try
|
||||
MainLoop.deleteZincBridgeSecondaryCache(mkState(zincRoot, logFile, tmp))
|
||||
assert(!bridge.exists(), s"expected $bridge deleted")
|
||||
finally IO.delete(logFile)
|
||||
|
||||
test("deleteZincBridgeSecondaryCache is a no-op when org.scala-sbt is absent"):
|
||||
IO.withTemporaryDirectory: tmp =>
|
||||
val zincRoot = tmp / "zinc"
|
||||
IO.createDirectory(zincRoot)
|
||||
val logFile = File.createTempFile("sbt-mlz", ".log")
|
||||
try
|
||||
MainLoop.deleteZincBridgeSecondaryCache(mkState(zincRoot, logFile, tmp))
|
||||
assert(zincRoot.exists())
|
||||
finally IO.delete(logFile)
|
||||
|
||||
test("deleteZincBridgeSecondaryCache respects sbt.global.zinc system property"):
|
||||
IO.withTemporaryDirectory: customZinc =>
|
||||
val prop = BuildPaths.GlobalZincProperty
|
||||
val prev = sys.props.get(prop)
|
||||
try
|
||||
sys.props(prop) = customZinc.getAbsolutePath
|
||||
val bridge = customZinc / SbtArtifacts.Organization
|
||||
IO.write(bridge / "x.jar", Array.emptyByteArray)
|
||||
val logFile = File.createTempFile("sbt-mlz", ".log")
|
||||
try
|
||||
val attrs = AttributeMap.empty.put(
|
||||
BuildPaths.globalBaseDirectory,
|
||||
customZinc.getParentFile / "unused-base"
|
||||
)
|
||||
val state = State(
|
||||
configuration = Stubs.appConfiguration(customZinc.getParentFile),
|
||||
definedCommands = Nil,
|
||||
exitHooks = Set.empty,
|
||||
onFailure = None,
|
||||
remainingCommands = Nil,
|
||||
history = State.newHistory,
|
||||
attributes = attrs,
|
||||
globalLogging = GlobalLogging.initial(
|
||||
MainAppender.globalDefault(ConsoleOut.globalProxy),
|
||||
logFile,
|
||||
ConsoleOut.globalProxy
|
||||
),
|
||||
currentCommand = None,
|
||||
next = State.Continue
|
||||
)
|
||||
MainLoop.deleteZincBridgeSecondaryCache(state)
|
||||
assert(!bridge.exists())
|
||||
finally IO.delete(logFile)
|
||||
finally
|
||||
prev match
|
||||
case Some(v) => sys.props(prop) = v
|
||||
case None => sys.props.remove(prop)
|
||||
|
||||
end MainLoopZincCacheTest
|
||||
Loading…
Reference in New Issue