Skip to content

Commit

Permalink
Make best effort file management behavior clearer
Browse files Browse the repository at this point in the history
  • Loading branch information
jchyb committed Jun 26, 2024
1 parent 16e5283 commit e93284f
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 30 deletions.
2 changes: 1 addition & 1 deletion backend/src/main/scala/bloop/BloopClassFileManager.scala
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ final class BloopClassFileManager(
private[this] val generatedFiles = new mutable.HashSet[File]

// Supported compile products by the class file manager
private[this] val supportedCompileProducts = List(".sjsir", ".nir", ".tasty", ".betasty")
val supportedCompileProducts = List(".sjsir", ".nir", ".tasty", ".betasty")
// Files backed up during compilation
private[this] val movedFiles = new mutable.HashMap[File, File]

Expand Down
32 changes: 11 additions & 21 deletions backend/src/main/scala/bloop/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ object Compiler {
val backgroundTasksForFailedCompilation =
new mutable.ListBuffer[CompileBackgroundTasks.Sig]()

def newFileManager: ClassFileManager = {
def newFileManager: BloopClassFileManager = {
new BloopClassFileManager(
Files.createTempDirectory("bloop"),
compileInputs,
Expand Down Expand Up @@ -453,6 +453,7 @@ object Compiler {
() => elapsed,
reporter,
backgroundTasksWhenNewSuccessfulAnalysis,
fileManager,
allInvalidatedClassFilesForProject,
allInvalidatedExtraCompileProducts,
previousSuccessfulProblems,
Expand Down Expand Up @@ -673,6 +674,7 @@ object Compiler {
() => elapsed,
reporter,
backgroundTasksWhenNewSuccessfulAnalysis,
fileManager,
allInvalidatedClassFilesForProject,
allInvalidatedExtraCompileProducts,
previousSuccessfulProblems,
Expand Down Expand Up @@ -871,14 +873,14 @@ object Compiler {
elapsed: () => Long,
reporter: ZincReporter,
backgroundTasksWhenNewSuccessfulAnalysis: mutable.ListBuffer[CompileBackgroundTasks.Sig],
fileManager: BloopClassFileManager,
allInvalidatedClassFilesForProject: mutable.HashSet[File],
allInvalidatedExtraCompileProducts: mutable.HashSet[File],
previousSuccessfulProblems: List[ProblemPerPhase],
errorCause: Option[xsbti.CompileFailed]
): Result = {
val uniqueInputs = compileInputs.uniqueInputs
val readOnlyClassesDir = compileOut.internalReadOnlyClassesDir.underlying
val readOnlyClassesDirPath = readOnlyClassesDir.toString
val newClassesDir = compileOut.internalNewClassesDir.underlying

reporter.processEndCompilation(
Expand All @@ -903,10 +905,6 @@ object Compiler {
Map.empty
)

// Delete all those class files that were invalidated in the external classes dir
val allInvalidated =
allInvalidatedClassFilesForProject ++ allInvalidatedExtraCompileProducts

val backgroundTasksExecution = new CompileBackgroundTasks {
def trigger(
clientClassesObserver: ClientClassesObserver,
Expand All @@ -915,7 +913,6 @@ object Compiler {
clientLogger: Logger
): Task[Unit] = {
val clientClassesDir = clientClassesObserver.classesDir
val clientClassesDirPath = clientClassesDir.toString
val successBackgroundTasks =
backgroundTasksWhenNewSuccessfulAnalysis
.map(f => f(clientClassesDir, clientReporter, clientTracer))
Expand All @@ -933,20 +930,13 @@ object Compiler {
)

val secondTask = Task {
allInvalidated.foreach { f =>
val path = AbsolutePath(f.toPath)
val syntax = path.syntax
if (syntax.startsWith(readOnlyClassesDirPath)) {
val rebasedFile = AbsolutePath(
syntax.replace(readOnlyClassesDirPath, clientClassesDirPath)
)
if (rebasedFile.exists) {
// In practice this deletes previous successful compilation artifacts
// (like '.tasty' and ".class"), which we do not need in clientDir
Files.delete(rebasedFile.underlying)
}
}
}
val deletedCompileProducts =
fileManager.supportedCompileProducts.filter(_ != ".betasty") :+ ".class"
Files
.walk(clientClassesDir.underlying)
.filter(path => Files.isRegularFile(path))
.filter(path => deletedCompileProducts.exists(path.toString.endsWith(_)))
.forEach(Files.delete(_))
}
Task
.gatherUnordered(List(firstTask, secondTask))
Expand Down
42 changes: 34 additions & 8 deletions frontend/src/test/scala/bloop/bsp/BspMetalsClientSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -657,21 +657,25 @@ class BspMetalsClientSpec(
val compiledState = state.compile(`A`, arguments = Some(List("--best-effort"))).toTestState
assertBetastyFile("A.betasty", compiledState, "A")
assertBetastyFile("B.betasty", compiledState, "A")
assertCompilationFile("A.class", compiledState, "A")
updateProject(updatedFile1WithError)
val compiledState2 = state.compile(`A`, arguments = Some(List("--best-effort"))).toTestState
assertBetastyFile("A.betasty", compiledState2, "A")
assertNoBetastyFile("B.betasty", compiledState2, "A")
assertBetastyFile("C.betasty", compiledState2, "A")
assertNoCompilationFile("A.class", compiledState, "A")
updateProject(updatedFile2WithoutError)
val compiledState3 = state.compile(`A`, arguments = Some(List("--best-effort"))).toTestState
assertNoBetastyFile("A.betasty", compiledState3, "A")
assertBetastyFile("B.betasty", compiledState3, "A")
assertBetastyFile("C.betasty", compiledState3, "A")
assertCompilationFile("B.class", compiledState, "A")
updateProject(updatedFile3WithError)
val compiledState4 = state.compile(`A`, arguments = Some(List("--best-effort"))).toTestState
assertNoBetastyFile("A.betasty", compiledState4, "A")
assertBetastyFile("B.betasty", compiledState4, "A")
assertNoBetastyFile("C.betasty", compiledState4, "A")
assertNoCompilationFile("B.class", compiledState, "A")
}
}
}
Expand Down Expand Up @@ -791,26 +795,48 @@ class BspMetalsClientSpec(
classesDir.resolve(s"META-INF/semanticdb/$projectName/src/$sourcePath.semanticdb")
}

private def assertBetastyFile(
expectedBetastyRelativePath: String,
private def assertCompilationFile(
expectedFilePath: String,
state: TestState,
projectName: String
): Unit = {
val project = state.build.getProjectFor(projectName).get
val classesDir = state.client.getUniqueClassesDirFor(project, forceGeneration = true)
val beTastyFile = classesDir.resolve(s"META-INF/best-effort/$expectedBetastyRelativePath")
assertIsFile(beTastyFile)
assertIsFile(classesDir.resolve(expectedFilePath))
}

private def assertNoBetastyFile(
expectedBetastyRelativePath: String,
private def assertNoCompilationFile(
expectedFilePath: String,
state: TestState,
projectName: String
): Unit = {
val project = state.build.getProjectFor(projectName).get
val classesDir = state.client.getUniqueClassesDirFor(project, forceGeneration = true)
val beTastyFile = classesDir.resolve(s"META-INF/best-effort/$expectedBetastyRelativePath")
assertNotFile(beTastyFile)
assertNotFile(classesDir.resolve(expectedFilePath))
}

private def assertBetastyFile(
expectedBetastyRelativePath: String,
state: TestState,
projectName: String
): Unit = {
assertCompilationFile(
s"META-INF/best-effort/$expectedBetastyRelativePath",
state,
projectName
)
}

private def assertNoBetastyFile(
expectedBetastyRelativePath: String,
state: TestState,
projectName: String
): Unit = {
assertNoCompilationFile(
s"META-INF/best-effort/$expectedBetastyRelativePath",
state,
projectName
)
}

private def assertSemanticdbFileFor(
Expand Down

0 comments on commit e93284f

Please sign in to comment.