mirror of https://github.com/sbt/sbt.git
Add debug logging in ClassfileManager
Add logging of various operations the transactional class file manager is
doing. You can pass logger to be used by the transactional class file
manager by using overloaded definition of `ClassfileManager.transactional`
method. The old overload has been deprecated.
The factory methods for class file manager in IncOptions companion object
has been deprecated in favor of using ClassfileManager companion object
directly. The code in Defaults.scala has been updated to use non-deprecated
methods. The logging is turned off by default.
The canonical way of enabling transactional class file manager in sbt
project is:
```
incOptions := incOptions.value.withNewClassfileManager(
sbt.inc.ClassfileManager.transactional(
crossTarget.value / "classes.bak",
(streams in (compile, Compile)).value.log
)
)
```
It's a bit verbose which shows that the api for this is not the best.
However, I don't expect sbt users to need this code very often.
This patch should help debug the problem described in #1184
This commit is contained in:
parent
10afd46785
commit
a7fb54e4df
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue