mirror of https://github.com/sbt/sbt.git
Do not use temporary directories in java.io.tmpdir
sbt should not by default create files in the location specified by java.io.tmpdir (which is the default behavior of apis like IO.createTemporaryDirectory or Files.createTempFile) because they have a tendency to leak and it also isn't even guaranteed that the user has write permissions there (though this is unlikely). Doing so creates the possibility for leaks I git grepped for `createTemp` and found these apis. After this change, the files created by sbt should largely be localized to the project and sbt global base directories.
This commit is contained in:
parent
f0d1e075db
commit
283d486796
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue