diff --git a/main/src/main/scala/sbt/BuildPaths.scala b/main/src/main/scala/sbt/BuildPaths.scala index b66d0e851..ba4219615 100644 --- a/main/src/main/scala/sbt/BuildPaths.scala +++ b/main/src/main/scala/sbt/BuildPaths.scala @@ -121,6 +121,10 @@ object BuildPaths { def outputDirectory(base: File) = base / DefaultTargetName def projectStandard(base: File) = base / "project" + def globalLoggingStandard(base: File): File = + base.getCanonicalFile / DefaultTargetName / GlobalLogging + def globalTaskDirectoryStandard(base: File): File = + base.getCanonicalFile / DefaultTargetName / TaskTempDirectory final val PluginsDirectoryName = "plugins" final val DefaultTargetName = "target" @@ -131,6 +135,8 @@ object BuildPaths { final val GlobalSettingsProperty = "sbt.global.settings" final val DependencyBaseProperty = "sbt.dependency.base" final val GlobalZincProperty = "sbt.global.zinc" + final val GlobalLogging = "global-logging" + final val TaskTempDirectory = "task-temp-directory" def crossPath(base: File, instance: xsbti.compile.ScalaInstance): File = base / ("scala_" + instance.version) diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 9701871c4..42e9eeecf 100755 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -291,7 +291,12 @@ object Defaults extends BuildCommon { }, watchSources :== Nil, // Although this is deprecated, it can't be removed or it breaks += for legacy builds. skip :== false, - taskTemporaryDirectory := { val dir = IO.createTemporaryDirectory; dir.deleteOnExit(); dir }, + taskTemporaryDirectory := { + val base = BuildPaths.globalTaskDirectoryStandard(appConfiguration.value.baseDirectory) + val dir = IO.createUniqueDirectory(base) + ShutdownHooks.add(() => IO.delete(dir)) + dir + }, onComplete := { val tempDirectory = taskTemporaryDirectory.value () => Clean.deleteContents(tempDirectory, _ => false) @@ -697,7 +702,7 @@ object Defaults extends BuildCommon { lazy val projectTasks: Seq[Setting[_]] = Seq( cleanFiles := cleanFilesTask.value, cleanKeepFiles := Vector.empty, - cleanKeepGlobs := historyPath.value.map(_.toGlob).toSeq, + cleanKeepGlobs ++= historyPath.value.map(_.toGlob).toVector, clean := Def.taskDyn(Clean.task(resolvedScoped.value.scope, full = true)).value, consoleProject := consoleProjectTask.value, transitiveDynamicInputs := SettingsGraph.task.value, @@ -2190,7 +2195,12 @@ object Classpaths { sourceArtifactTypes :== Artifact.DefaultSourceTypes.toVector, docArtifactTypes :== Artifact.DefaultDocTypes.toVector, cleanKeepFiles :== Nil, - cleanKeepGlobs :== Nil, + cleanKeepGlobs := { + val base = appConfiguration.value.baseDirectory.getCanonicalFile + val dirs = BuildPaths + .globalLoggingStandard(base) :: BuildPaths.globalTaskDirectoryStandard(base) :: Nil + dirs.flatMap(d => Glob(d) :: Glob(d, RecursiveGlob) :: Nil) + }, fileOutputs :== Nil, sbtDependency := { val app = appConfiguration.value diff --git a/main/src/main/scala/sbt/Main.scala b/main/src/main/scala/sbt/Main.scala index 4da7133ff..d570e6bba 100644 --- a/main/src/main/scala/sbt/Main.scala +++ b/main/src/main/scala/sbt/Main.scala @@ -141,12 +141,17 @@ object StandardMain { val console: ConsoleOut = ConsoleOut.systemOutOverwrite(ConsoleOut.overwriteContaining("Resolving ")) - def initialGlobalLogging: GlobalLogging = + private[this] def initialGlobalLogging(file: Option[File]): GlobalLogging = { + file.foreach(f => if (!f.exists()) IO.createDirectory(f)) GlobalLogging.initial( MainAppender.globalDefault(console), - File.createTempFile("sbt", ".log"), + File.createTempFile("sbt-global-log", ".log", file.orNull), console ) + } + def initialGlobalLogging(file: File): GlobalLogging = initialGlobalLogging(Option(file)) + @deprecated("use version that takes file argument", "1.4.0") + def initialGlobalLogging: GlobalLogging = initialGlobalLogging(None) def initialState( configuration: xsbti.AppConfiguration, @@ -171,7 +176,7 @@ object StandardMain { commands, State.newHistory, initAttrs, - initialGlobalLogging, + initialGlobalLogging(BuildPaths.globalLoggingStandard(configuration.baseDirectory)), None, State.Continue ) diff --git a/scripted-sbt-redux/src/main/scala/sbt/scriptedtest/ScriptedTests.scala b/scripted-sbt-redux/src/main/scala/sbt/scriptedtest/ScriptedTests.scala index db1041c44..e2d27bc1f 100644 --- a/scripted-sbt-redux/src/main/scala/sbt/scriptedtest/ScriptedTests.scala +++ b/scripted-sbt-redux/src/main/scala/sbt/scriptedtest/ScriptedTests.scala @@ -8,24 +8,26 @@ package sbt package scriptedtest -import java.io.{ File, FileNotFoundException } +import java.io.{ File, FileNotFoundException, IOException } import java.net.SocketException +import java.nio.file.Files import java.util.Properties import java.util.concurrent.ForkJoinPool -import scala.collection.GenSeq -import scala.collection.mutable -import scala.collection.parallel.ForkJoinTaskSupport -import scala.util.control.NonFatal -import sbt.internal.scripted._ import sbt.internal.io.Resources +import sbt.internal.scripted._ import sbt.internal.util.{ BufferedLogger, ConsoleOut, FullLogger, Util } +import sbt.io.FileFilter._ import sbt.io.syntax._ import sbt.io.{ DirectoryFilter, HiddenFileFilter, IO } -import sbt.io.FileFilter._ +import sbt.nio.file._ +import sbt.nio.file.syntax._ import sbt.util.{ AbstractLogger, Level, Logger } +import scala.collection.{ GenSeq, mutable } +import scala.collection.parallel.ForkJoinTaskSupport import scala.util.Try +import scala.util.control.NonFatal final class ScriptedTests( resourceBaseDirectory: File, @@ -359,7 +361,17 @@ final class ScriptedTests( // Run the test and delete files (except global that holds local scala jars) val result = runOrHandleDisabled(label, tempTestDir, runTest, buffer) - IO.delete(tempTestDir.*("*" -- "global").get) + val view = FileTreeView.default + val base = tempTestDir.getCanonicalFile.toGlob + val global = base / "global" + val globalLogging = base / ** / "global-logging" + def recursiveFilter(glob: Glob): PathFilter = (glob: PathFilter) || glob / ** + val keep: PathFilter = recursiveFilter(global) || recursiveFilter(globalLogging) + val toDelete = view.list(base / **, !keep).map(_._1).sorted.reverse + toDelete.foreach { p => + try Files.deleteIfExists(p) + catch { case _: IOException => } + } result } }