diff --git a/compile/inc/src/main/scala/sbt/inc/ClassfileManager.scala b/compile/inc/src/main/scala/sbt/inc/ClassfileManager.scala index 636c0aec36..e4a449a4e9 100644 --- a/compile/inc/src/main/scala/sbt/inc/ClassfileManager.scala +++ b/compile/inc/src/main/scala/sbt/inc/ClassfileManager.scala @@ -13,7 +13,7 @@ trait ClassfileManager * Any empty ancestor directories of deleted files must not exist either.*/ def delete(classes: Iterable[File]): Unit - /** Called once per compilation step with the class files generated during that step.*/ + /** Called once per compilation step with the class files generated during that step.*/ def generated(classes: Iterable[File]): Unit /** Called once at the end of the whole compilation run, with `success` indicating whether compilation succeeded (true) or not (false).*/ @@ -29,29 +29,45 @@ object ClassfileManager def generated(classes: Iterable[File]) {} def complete(success: Boolean) {} } + @deprecated("Use overloaded variant that takes additional logger argument, instead.", "0.13.5") + def transactional(tempDir0: File): () => ClassfileManager = + transactional(tempDir0, sbt.Logger.Null) /** When compilation fails, this ClassfileManager restores class files to the way they were before compilation.*/ - def transactional(tempDir0: File): () => ClassfileManager = () => new ClassfileManager + def transactional(tempDir0: File, logger: sbt.Logger): () => ClassfileManager = () => new ClassfileManager { val tempDir = tempDir0.getCanonicalFile IO.delete(tempDir) IO.createDirectory(tempDir) + logger.debug(s"Created transactional ClassfileManager with tempDir = $tempDir") private[this] val generatedClasses = new mutable.HashSet[File] private[this] val movedClasses = new mutable.HashMap[File, File] - + + private def showFiles(files: Iterable[File]): String = files.map(f => s"\t$f").mkString("\n") def delete(classes: Iterable[File]) { - for(c <- classes) if(c.exists && !movedClasses.contains(c) && !generatedClasses(c)) + logger.debug(s"About to delete class files:\n${showFiles(classes)}") + val toBeBackedUp = classes.filter(c => c.exists && !movedClasses.contains(c) && !generatedClasses(c)) + logger.debug(s"We backup classs files:\n${showFiles(toBeBackedUp)}") + for(c <- toBeBackedUp) { movedClasses.put(c, move(c)) + } IO.deleteFilesEmptyDirs(classes) } - def generated(classes: Iterable[File]): Unit = generatedClasses ++= classes + def generated(classes: Iterable[File]): Unit = { + logger.debug(s"Registering generated classes:\n${showFiles(classes)}") + generatedClasses ++= classes + } def complete(success: Boolean) { if(!success) { + logger.debug("Rolling back changes to class files.") + logger.debug(s"Removing generated classes:\n${showFiles(generatedClasses)}") IO.deleteFilesEmptyDirs(generatedClasses) + logger.debug(s"Restoring class files: \n${showFiles(movedClasses.map(_._1))}") for( (orig, tmp) <- movedClasses ) IO.move(tmp, orig) } + logger.debug(s"Removing the temporary directory used for backing up class files: $tempDir") IO.delete(tempDir) } diff --git a/compile/inc/src/main/scala/sbt/inc/IncOptions.scala b/compile/inc/src/main/scala/sbt/inc/IncOptions.scala index 0e634aa4fc..70add51834 100644 --- a/compile/inc/src/main/scala/sbt/inc/IncOptions.scala +++ b/compile/inc/src/main/scala/sbt/inc/IncOptions.scala @@ -234,9 +234,12 @@ object IncOptions extends Serializable { private def readResolve(): Object = IncOptions //- EXPANDED CASE CLASS METHOD END -// - def defaultTransactional(tempDir: File): IncOptions = setTransactional(Default, tempDir) + @deprecated("Use IncOptions.Default.withNewClassfileManager(ClassfileManager.transactional(tempDir)), instead.", "0.13.5") + def defaultTransactional(tempDir: File): IncOptions = + setTransactional(Default, tempDir) + @deprecated("Use opts.withNewClassfileManager(ClassfileManager.transactional(tempDir)), instead.", "0.13.5") def setTransactional(opts: IncOptions, tempDir: File): IncOptions = - opts.copy(newClassfileManager = ClassfileManager.transactional(tempDir)) + opts.withNewClassfileManager(ClassfileManager.transactional(tempDir, sbt.Logger.Null)) private val transitiveStepKey = "transitiveStep" private val recompileAllFractionKey = "recompileAllFraction" diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 96390d8692..d240104679 100755 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -215,7 +215,8 @@ object Defaults extends BuildCommon ) def compileBase = inTask(console)(compilersSetting :: Nil) ++ compileBaseGlobal ++ Seq( - incOptions := IncOptions.setTransactional(incOptions.value, crossTarget.value / "classes.bak"), + incOptions := incOptions.value.withNewClassfileManager( + sbt.inc.ClassfileManager.transactional(crossTarget.value / "classes.bak", sbt.Logger.Null)), scalaInstance <<= scalaInstanceTask, crossVersion := (if(crossPaths.value) CrossVersion.binary else CrossVersion.Disabled), crossTarget := makeCrossTarget(target.value, scalaBinaryVersion.value, sbtBinaryVersion.value, sbtPlugin.value, crossPaths.value)