Skip to content

Commit

Permalink
Delete pickle classes dir when all targets are compiled
Browse files Browse the repository at this point in the history
  • Loading branch information
jvican committed May 23, 2019
1 parent 1fcd2e8 commit 19a3223
Show file tree
Hide file tree
Showing 10 changed files with 57 additions and 45 deletions.
@@ -1,4 +1,5 @@
package sbt.internal.inc.bloop.internal

import java.io.File
import xsbti.api.AnalyzedClass
import xsbti.compile.analysis.ReadStamps
Expand Down
Expand Up @@ -20,6 +20,7 @@ import xsbti.compile._

import scala.util.control.NonFatal
import sbt.internal.inc.JarUtils
import scala.concurrent.Promise

/**
*
Expand All @@ -45,11 +46,7 @@ final class BloopHighLevelCompiler(
private[this] final val setup = config.currentSetup
private[this] final val classpath = config.classpath.map(_.getAbsoluteFile)

private[this] val JavaCompleted: CompletableFuture[Unit] = {
val cf = new CompletableFuture[Unit]()
cf.complete(())
cf
}
private[this] val JavaCompleted: Promise[Unit] = Promise.successful(())

/**
* Compile
Expand Down Expand Up @@ -94,7 +91,7 @@ final class BloopHighLevelCompiler(
}

// Note `pickleURI` has already been used to create the analysis callback in `BloopZincCompiler`
val (pipeline: Boolean, batches: Option[Int], completeJava: CompletableFuture[Unit], fireJavaCompilation: Task[JavaSignal], transitiveJavaSources: List[File], separateJavaAndScala: Boolean) = {
val (pipeline: Boolean, batches: Option[Int], completeJava: Promise[Unit], fireJavaCompilation: Task[JavaSignal], transitiveJavaSources: List[File], separateJavaAndScala: Boolean) = {
compileMode match {
case CompileMode.Sequential => (false, None, JavaCompleted, Task.now(JavaSignal.ContinueCompilation), Nil, false)
case CompileMode.Parallel(batches) => (false, Some(batches), JavaCompleted, Task.now(JavaSignal.ContinueCompilation), Nil, false)
Expand All @@ -106,8 +103,8 @@ final class BloopHighLevelCompiler(
}

// Complete empty java promise if there are no java sources
if (javaSources.isEmpty && !completeJava.isDone)
completeJava.complete(())
if (javaSources.isEmpty && !completeJava.isCompleted)
completeJava.trySuccess(())

val compileScala: Task[Unit] = {
if (scalaSources.isEmpty) Task.now(())
Expand All @@ -134,8 +131,7 @@ final class BloopHighLevelCompiler(
} catch {
case NonFatal(t) =>
// If scala compilation happens, complete the java promise so that it doesn't block
if (!completeJava.isDone)
completeJava.completeExceptionally(t)
completeJava.tryFailure(t)
throw t
}
}
Expand Down Expand Up @@ -164,14 +160,13 @@ final class BloopHighLevelCompiler(
val javaOptions = setup.options.javacOptions.toArray[String]
try {
javac.compile(javaSources, javaOptions, setup.output, callback, incToolOptions, config.reporter, logger, config.progress)
if (!completeJava.isDone)
completeJava.complete(())
completeJava.trySuccess(())
()
} catch {
case f: CompileFailed =>
// Intercept and report manually because https://github.com/sbt/zinc/issues/520
config.reporter.printSummary()
completeJava.completeExceptionally(f)
completeJava.tryFailure(f)
throw f
}
}
Expand Down
2 changes: 1 addition & 1 deletion bsp
Submodule bsp updated from 03e9b7 to faf8c0
Expand Up @@ -138,8 +138,7 @@ object ResultsCache {
CompileProducts(classesDir, classesDir, r, r, Set.empty, Map.empty)
ResultBundle(
Result.Success(inputs, reporter, products, 0L, dummyTasks, false),
Some(LastSuccessfulResult(inputs, products, Task.now(()))),
CancelableFuture.successful(())
Some(LastSuccessfulResult(inputs, products, Task.now(())))
)
case None =>
logger.debug(
Expand Down
43 changes: 26 additions & 17 deletions frontend/src/main/scala/bloop/engine/tasks/CompileTask.scala
Expand Up @@ -38,6 +38,7 @@ import sbt.internal.inc.AnalyzingCompiler
import xsbti.compile.{PreviousResult, CompileAnalysis, MiniSetup}

import scala.concurrent.Promise
import bloop.io.Paths

object CompileTask {
private implicit val logContext: DebugFilter = DebugFilter.Compilation
Expand Down Expand Up @@ -187,6 +188,9 @@ object CompileTask {
postCompilationTasks.runAsync(ExecutionContext.ioScheduler)
}

val deletePickleDirTask =
Task.fork(Task.eval(Paths.delete(compileOut.internalNewPickleDir)))

// Populate the last successful result if result was success
result match {
case s: Compiler.Result.Success =>
Expand All @@ -208,12 +212,15 @@ object CompileTask {

// Memoize so that no matter how many times it's run, only once it's executed
val last = LastSuccessfulResult(bundle.oracleInputs, s.products, populatingTask)
ResultBundle(s, Some(last), runningTasks)
ResultBundle(s, Some(last), runningTasks, deletePickleDirTask)
case f: Compiler.Result.Failed =>
ResultBundle(result, None, runPostCompilationTasks(f.backgroundTasks))
val runningTasks = runPostCompilationTasks(f.backgroundTasks)
ResultBundle(result, None, runningTasks, deletePickleDirTask)
case c: Compiler.Result.Cancelled =>
ResultBundle(result, None, runPostCompilationTasks(c.backgroundTasks))
case result => ResultBundle(result, None, CancelableFuture.successful(()))
val runningTasks = runPostCompilationTasks(c.backgroundTasks)
ResultBundle(result, None, runningTasks, deletePickleDirTask)
case result =>
ResultBundle(result, None, CancelableFuture.unit, deletePickleDirTask)
}
}
}
Expand Down Expand Up @@ -310,22 +317,24 @@ object CompileTask {
}
}

val backgroundTasks = Task
.gatherUnordered {
results.flatMap {
case FinalNormalCompileResult(_, results: ResultBundle) =>
List(
Task
.fromFuture(results.runningBackgroundTasks)
.executeOn(ExecutionContext.ioScheduler)
)
case _ => Nil
}
val backgroundTasks = Task.gatherUnordered {
results.flatMap {
case FinalNormalCompileResult(_, results) =>
val tasksAtEndOfBuildCompilation = results.deletePickleDirTask.flatMap { _ =>
Task
.fromFuture(results.runningBackgroundTasks)
.executeOn(ExecutionContext.ioScheduler)
}
List(tasksAtEndOfBuildCompilation)
case _ => Nil
}
.executeOn(ExecutionContext.ioScheduler)
}

// Block on all background task operations to fully populate classes directories
backgroundTasks.map(_ => newState).doOnFinish(_ => Task(rootTracer.terminate()))
backgroundTasks
.executeOn(ExecutionContext.ioScheduler)
.map(_ => newState)
.doOnFinish(_ => Task(rootTracer.terminate()))
}
}
}
Expand Down
Expand Up @@ -81,10 +81,10 @@ final case class CompileBundle(
def prepareSourcesAndInstance: Either[ResultBundle, CompileSourcesAndInstance] = {
import monix.execution.CancelableFuture
def earlyError(msg: String): ResultBundle =
ResultBundle(Compiler.Result.GlobalError(msg), None, CancelableFuture.unit)
ResultBundle(Compiler.Result.GlobalError(msg), None)
def empty: ResultBundle = {
val last = Some(LastSuccessfulResult.empty(project))
ResultBundle(Compiler.Result.Empty, last, CancelableFuture.unit)
ResultBundle(Compiler.Result.Empty, last)
}

val uniqueSources = javaSources ++ scalaSources
Expand Down
Expand Up @@ -331,8 +331,7 @@ object CompileGraph {
enrichResultDag(resultDag) { (p: PartialCompileResult) =>
p match {
case s: PartialSuccess =>
val failedBundle =
ResultBundle(failedDeduplicationResult, None, CancelableFuture.unit)
val failedBundle = ResultBundle(failedDeduplicationResult, None)
s.copy(result = s.result.map(_ => failedBundle))
case result => result
}
Expand Down Expand Up @@ -621,7 +620,7 @@ object CompileGraph {
* `FailPromise` exception that makes the partial result be recognized as error.
*/
def toPartialFailure(bundle: CompileBundle, res: Compiler.Result): PartialFailure = {
val results = Task.now(ResultBundle(res, None, CancelableFuture.unit))
val results = Task.now(ResultBundle(res, None))
PartialFailure(bundle.project, CompileExceptions.FailPromise, results)
}

Expand Down Expand Up @@ -655,7 +654,7 @@ object CompileGraph {
if (failed.nonEmpty) {
// Register the name of the projects we're blocked on (intransitively)
val blockedResult = Compiler.Result.Blocked(failed.map(_.name))
val blocked = Task.now(ResultBundle(blockedResult, None, CancelableFuture.unit))
val blocked = Task.now(ResultBundle(blockedResult, None))
Task.now(Parent(PartialFailure(project, BlockURI, blocked), dagResults))
} else {
val results: List[PartialSuccess] = {
Expand All @@ -669,7 +668,7 @@ object CompileGraph {
var dependentProducts = new mutable.ListBuffer[(Project, CompileProducts)]()
var dependentResults = new mutable.ListBuffer[(File, PreviousResult)]()
results.foreach {
case (p, ResultBundle(s: Compiler.Result.Success, _, _)) =>
case (p, ResultBundle(s: Compiler.Result.Success, _, _, _)) =>
val newProducts = s.products
dependentProducts.+=(p -> newProducts)
val newResult = newProducts.resultForDependentCompilationsInSameRun
Expand Down Expand Up @@ -767,7 +766,7 @@ object CompileGraph {
if (failed.nonEmpty) {
// Register the name of the projects we're blocked on (intransitively)
val blockedResult = Compiler.Result.Blocked(failed.map(_.name))
val blocked = Task.now(ResultBundle(blockedResult, None, CancelableFuture.unit))
val blocked = Task.now(ResultBundle(blockedResult, None))
Task.now(Parent(PartialFailure(project, BlockURI, blocked), dagResults))
} else {
val results: List[PartialSuccess] = {
Expand Down
Expand Up @@ -58,7 +58,7 @@ object PartialCompileResult {

case object PartialEmpty extends PartialCompileResult {
override final val result: Task[ResultBundle] =
Task.now(ResultBundle(Compiler.Result.Empty, None, CancelableFuture.unit))
Task.now(ResultBundle(Compiler.Result.Empty, None))
}

case class PartialFailure(
Expand Down
Expand Up @@ -4,14 +4,21 @@ import bloop.Compiler
import bloop.engine.caches.LastSuccessfulResult

import monix.execution.CancelableFuture
import monix.eval.Task

case class ResultBundle(
fromCompiler: Compiler.Result,
successful: Option[LastSuccessfulResult],
runningBackgroundTasks: CancelableFuture[Unit]
runningBackgroundTasks: CancelableFuture[Unit],
deletePickleDirTask: Task[Unit]
)

object ResultBundle {
val empty: ResultBundle =
ResultBundle(Compiler.Result.Empty, None, CancelableFuture.successful(()))
ResultBundle(Compiler.Result.Empty, None, CancelableFuture.successful(()), Task.unit)

def apply(
fromCompiler: Compiler.Result,
successful: Option[LastSuccessfulResult]
): ResultBundle = ResultBundle(fromCompiler, successful, CancelableFuture.unit, Task.unit)
}
4 changes: 3 additions & 1 deletion frontend/src/test/scala/bloop/CompileSpec.scala
Expand Up @@ -308,7 +308,9 @@ object CompileSpec extends bloop.testing.BaseSuite {
// Check that initial classes directory doesn't exist either
assertNonExistingInternalClassesDir(secondCompiledState)(compiledState, List(`A`))
// There should only be 2 dirs: current classes dir and external (no empty classes dir)
assert(list(workspace.resolve("target").resolve("a")).size == 2)
val targetA = workspace.resolve("target").resolve("a")
val classesDirInA = list(targetA).map(ap => ap.toRelative(targetA).syntax)
assert(classesDirInA.size == 2)
}
}

Expand Down

0 comments on commit 19a3223

Please sign in to comment.