Update io

The new io verion removes the PathFinder <-> Glob implicit translations.
It also has a number of small bug fixes related to directory listing via
FileTreeView.
This commit is contained in:
Ethan Atkins 2019-05-05 19:03:32 -07:00
parent 2ab8fed8fd
commit b6ad077a72
26 changed files with 74 additions and 71 deletions

View File

@ -37,6 +37,7 @@ import sbt.internal.librarymanagement.mavenint.{
SbtPomExtraProperties
}
import sbt.internal.librarymanagement.{ CustomHttp => _, _ }
import sbt.internal.nio.Globs
import sbt.internal.server.{
Definition,
LanguageServerProtocol,
@ -67,7 +68,7 @@ import sbt.librarymanagement.ivy._
import sbt.librarymanagement.syntax._
import sbt.nio.Watch
import sbt.nio.Keys._
import sbt.nio.file.FileTreeView
import sbt.nio.file.{ FileTreeView, Glob, RecursiveGlob }
import sbt.nio.file.syntax._
import sbt.std.TaskExtra._
import sbt.testing.{ AnnotatedFingerprint, Framework, Runner, SubclassFingerprint }
@ -254,15 +255,15 @@ object Defaults extends BuildCommon {
buildStructure := Project.structure(state.value),
settingsData := buildStructure.value.data,
settingsData / fileInputs := {
val baseDir = file(".").getCanonicalFile
val sourceFilter = ("*.sbt" || "*.scala" || "*.java")
val baseDir = file(".").getCanonicalFile()
val sourceFilter = "*.{sbt,scala,java}"
val projectDir = baseDir / "project"
Seq(
baseDir * "*.sbt",
projectDir * sourceFilter,
Glob(baseDir, "*.sbt"),
Glob(projectDir, sourceFilter),
// We only want to recursively look in source because otherwise we have to search
// the project target directories which is expensive.
projectDir / "src" ** sourceFilter,
Glob(projectDir / "src", RecursiveGlob / sourceFilter),
)
},
trapExit :== true,
@ -419,8 +420,11 @@ object Defaults extends BuildCommon {
case NothingFilter | HiddenFileFilter => include
case exclude => include -- exclude
}
val baseSources = if (sourcesInBase.value) baseDirectory.value * filter :: Nil else Nil
unmanagedSourceDirectories.value.map(_ ** filter) ++ baseSources
val baseSources =
if (sourcesInBase.value) Globs(baseDirectory.value.toPath, recursive = false, filter) :: Nil
else Nil
unmanagedSourceDirectories.value
.map(d => Globs(d.toPath, recursive = true, filter)) ++ baseSources
},
unmanagedSources := (unmanagedSources / inputFileStamps).value.map(_._1.toFile),
managedSourceDirectories := Seq(sourceManaged.value),
@ -451,9 +455,9 @@ object Defaults extends BuildCommon {
case NothingFilter | HiddenFileFilter => include
case exclude => include -- exclude
}
unmanagedResourceDirectories.value.map(_ ** filter)
unmanagedResourceDirectories.value.map(d => Globs(d.toPath, recursive = true, filter))
},
unmanagedResources := (unmanagedResources / allInputFiles).value.map(_.toFile),
unmanagedResources := (unmanagedResources / inputFileStamps).value.map(_._1.toFile),
resourceGenerators :== Nil,
resourceGenerators += Def.task {
PluginDiscovery.writeDescriptors(discoveredSbtPlugins.value, resourceManaged.value)
@ -596,7 +600,7 @@ object Defaults extends BuildCommon {
compileInputsSettings
) ++ configGlobal ++ defaultCompileSettings ++ compileAnalysisSettings ++ Seq(
clean := Clean.task(ThisScope, full = false).value,
fileOutputs := Seq(classDirectory.value ** "*.class"),
fileOutputs := Seq(Glob(classDirectory.value, RecursiveGlob / "*.class")),
compile := compileTask.value,
internalDependencyConfigurations := InternalDependencies.configurations.value,
manipulateBytecode := compileIncremental.value,
@ -1249,7 +1253,7 @@ object Defaults extends BuildCommon {
): Initialize[Task[Seq[File]]] = Def.task {
val filter = include.toTask.value -- exclude.toTask.value
val view = fileTreeView.value
view.list(dirs.toTask.value.map(_ ** filter)).collect {
view.list(dirs.toTask.value.map(f => Globs(f.toPath, recursive = true, filter))).collect {
case (p, a) if !a.isDirectory => p.toFile
}
}
@ -3063,7 +3067,8 @@ object Classpaths {
Def.taskDyn {
val dirs = productDirectories.value
val view = fileTreeView.value
def containsClassFile(): Boolean = view.list(dirs.map(_ ** "*.class")).nonEmpty
def containsClassFile(): Boolean =
view.list(dirs.map(Glob(_, RecursiveGlob / "*.class"))).nonEmpty
TrackLevel.intersection(track, exportToInternal.value) match {
case TrackLevel.TrackAlways =>
Def.task {

View File

@ -10,20 +10,17 @@ package sbt
import java.io.File
import java.lang.reflect.Method
import sbt.Def._
import sbt.Keys._
import sbt.Project._
import sbt.internal.inc.ModuleUtilities
import sbt.internal.inc.classpath.ClasspathUtilities
import sbt.internal.util.complete.{ DefaultParsers, Parser }
import sbt.io._
import sbt.io.syntax._
import sbt.internal.util.complete.{ Parser, DefaultParsers }
import sbt.librarymanagement._
import sbt.librarymanagement.syntax._
import sbt.internal.inc.classpath.ClasspathUtilities
import sbt.internal.inc.ModuleUtilities
import Def._
import Keys._
import Project._
import sbt.nio.file.{ Glob, RecursiveGlob }
object ScriptedPlugin extends AutoPlugin {
@ -89,7 +86,7 @@ object ScriptedPlugin extends AutoPlugin {
use(analysis, pub)
},
scripted := scriptedTask.evaluated,
watchTriggers in scripted += sbtTestDirectory.value ** AllPassFilter
watchTriggers in scripted += Glob(sbtTestDirectory.value, RecursiveGlob)
)
private[sbt] def scriptedTestsTask: Initialize[Task[AnyRef]] =

View File

@ -14,7 +14,6 @@ import java.nio.file.{ DirectoryNotEmptyException, Files, Path }
import sbt.Def._
import sbt.Keys._
import sbt.Project.richInitializeTask
import sbt.io.AllPassFilter
import sbt.io.syntax._
import sbt.nio.Keys._
import sbt.nio.file._
@ -54,7 +53,7 @@ private[sbt] object Clean {
private[this] def cleanFilter(scope: Scope): Def.Initialize[Task[Path => Boolean]] = Def.task {
val excludes = (cleanKeepFiles in scope).value.map {
// This mimics the legacy behavior of cleanFilesTask
case f if f.isDirectory => f * AllPassFilter
case f if f.isDirectory => Glob(f, AnyPath)
case f => f.toGlob
} ++ (cleanKeepGlobs in scope).value
p: Path => excludes.exists(_.matches(p))

View File

@ -12,9 +12,9 @@ import sbt.Keys._
import sbt.Project.richInitializeTask
import sbt._
import sbt.internal.io.Source
import sbt.internal.nio.Globs
import sbt.internal.util.AttributeMap
import sbt.internal.util.complete.Parser
import sbt.io.syntax._
import sbt.nio.FileStamper
import sbt.nio.Keys._
import sbt.nio.file.Glob
@ -25,7 +25,7 @@ private[sbt] object SettingsGraph {
private implicit class SourceOps(val source: Source) {
def toGlob: Glob = {
val filter = source.includeFilter -- source.excludeFilter
if (source.recursive) source.base ** filter else source.base * filter
Globs.apply(source.base.toPath, source.recursive, filter)
}
}
private[sbt] def task: Def.Initialize[Task[Seq[DynamicInput]]] =

View File

@ -15,10 +15,10 @@ import org.scalatest.{ FlatSpec, Matchers }
import sbt.WatchSpec._
import sbt.internal.nio.{ FileEvent, FileEventMonitor, FileTreeRepository }
import sbt.io._
import sbt.io.syntax._
import sbt.nio.Watch
import sbt.nio.Watch.{ NullLogger, _ }
import sbt.nio.file.{ FileAttributes, Glob }
import sbt.nio.file.{ FileAttributes, Glob, RecursiveGlob }
import sbt.nio.file.syntax._
import sbt.util.Logger
import scala.collection.mutable
@ -84,13 +84,13 @@ class WatchSpec extends FlatSpec with Matchers {
}
"Watch" should "stop" in IO.withTemporaryDirectory { dir =>
val task = new Task
watch(task, TestDefaults.callbacks(inputs = Seq(dir.toRealPath ** AllPassFilter))) shouldBe CancelWatch
watch(task, TestDefaults.callbacks(inputs = Seq(dir.toRealPath.toGlob / RecursiveGlob))) shouldBe CancelWatch
}
it should "trigger" in IO.withTemporaryDirectory { dir =>
val triggered = new AtomicBoolean(false)
val task = new Task
val callbacks = TestDefaults.callbacks(
inputs = Seq(dir.toRealPath ** AllPassFilter),
inputs = Seq(dir.toRealPath.toGlob / RecursiveGlob),
onStartWatch = () => if (task.getCount == 2) CancelWatch else Ignore,
onWatchEvent = _ => { triggered.set(true); Trigger },
watchingMessage = () => {
@ -107,7 +107,7 @@ class WatchSpec extends FlatSpec with Matchers {
val bar = realDir.toPath.resolve("bar")
val task = new Task
val callbacks = TestDefaults.callbacks(
inputs = Seq(realDir ** AllPassFilter),
inputs = Seq(realDir.toGlob / RecursiveGlob),
onStartWatch = () => if (task.getCount == 2) CancelWatch else Ignore,
onWatchEvent = e => if (e.path == foo) Trigger else Ignore,
triggeredMessage = e => { queue += e.path; None },
@ -126,7 +126,7 @@ class WatchSpec extends FlatSpec with Matchers {
val bar = realDir.toPath.resolve("bar")
val task = new Task
val callbacks = TestDefaults.callbacks(
inputs = Seq(realDir ** AllPassFilter),
inputs = Seq(realDir.toGlob / RecursiveGlob),
onStartWatch = () => if (task.getCount == 3) CancelWatch else Ignore,
onWatchEvent = e => if (e.path != realDir.toPath) Trigger else Ignore,
triggeredMessage = e => { queue += e.path; None },
@ -148,19 +148,19 @@ class WatchSpec extends FlatSpec with Matchers {
val exception = new IllegalStateException("halt")
val task = new Task { override def apply(): Unit = throw exception }
val callbacks = TestDefaults.callbacks(
Seq(dir.toRealPath ** AllPassFilter),
Seq(dir.toRealPath.toGlob / RecursiveGlob),
)
watch(task, callbacks) shouldBe new HandleError(exception)
}
it should "reload" in IO.withTemporaryDirectory { dir =>
val task = new Task
val callbacks = TestDefaults.callbacks(
inputs = Seq(dir.toRealPath ** AllPassFilter),
inputs = Seq(dir.toRealPath.toGlob / RecursiveGlob),
onStartWatch = () => Ignore,
onWatchEvent = _ => Reload,
onWatchEvent = _ => Watch.Reload,
watchingMessage = () => { new File(dir, "file").createNewFile(); None }
)
watch(task, callbacks) shouldBe Reload
watch(task, callbacks) shouldBe Watch.Reload
}
}

View File

@ -9,7 +9,7 @@ object Dependencies {
val baseScalaVersion = scala212
// sbt modules
private val ioVersion = "1.3.0-M9"
private val ioVersion = "1.3.0-M10"
private val utilVersion = "1.3.0-M6"
private val lmVersion =
sys.props.get("sbt.build.lm.version") match {

View File

@ -5,6 +5,6 @@ cleanKeepFiles ++= Seq(
target.value / "keepfile"
)
cleanKeepGlobs += target.value / "keepdir" ** AllPassFilter
cleanKeepGlobs += target.value.toGlob / "keepdir" / **
// This is necessary because recursive globs do not include the base directory.
cleanKeepGlobs += Glob(target.value / "keepdir")

View File

@ -2,8 +2,8 @@ import sbt.nio.Keys._
val foo = taskKey[Unit]("foo")
foo / fileInputs := Seq(
(baseDirectory.value / "base").toGlob / "*.md",
(baseDirectory.value / "base").toGlob / "*.txt",
baseDirectory.value.toGlob / "base" / "*.md",
baseDirectory.value.toGlob / "base" / "*.txt",
)
val checkModified = taskKey[Unit]("check that modified files are returned")

View File

@ -3,7 +3,7 @@
// Check that we can correctly extract Foo.txt with a recursive source
val foo = taskKey[Seq[File]]("Retrieve Foo.txt")
foo / fileInputs += baseDirectory.value ** "*.txt"
foo / fileInputs += baseDirectory.value.toGlob / ** / "*.txt"
foo := (foo / allInputFiles).value.map(_.toFile)
@ -14,7 +14,7 @@ checkFoo := assert(foo.value == Seq(baseDirectory.value / "base/subdir/nested-su
// Check that we can correctly extract Bar.md with a non-recursive source
val bar = taskKey[Seq[File]]("Retrieve Bar.md")
bar / fileInputs += baseDirectory.value / "base/subdir/nested-subdir" * "*.md"
bar / fileInputs += baseDirectory.value.toGlob / "base/subdir/nested-subdir/*.md"
bar := (bar / allInputFiles).value.map(_.toFile)
@ -25,7 +25,7 @@ checkBar := assert(bar.value == Seq(baseDirectory.value / "base/subdir/nested-su
// Check that we can correctly extract Bar.md and Foo.md with a non-recursive source
val all = taskKey[Seq[File]]("Retrieve all files")
all / fileInputs += baseDirectory.value / "base" / "subdir" / "nested-subdir" * AllPassFilter
all / fileInputs += baseDirectory.value.toGlob / "base" / "subdir" / "nested-subdir" / *
val checkAll = taskKey[Unit]("Check that the Bar.md file is retrieved")
@ -39,8 +39,8 @@ checkAll := {
val set = taskKey[Seq[File]]("Specify redundant sources in a set")
set / fileInputs ++= Seq(
baseDirectory.value / "base" ** -DirectoryFilter,
baseDirectory.value / "base" / "subdir" / "nested-subdir" * -DirectoryFilter
baseDirectory.value.toGlob / "base" / **,
baseDirectory.value.toGlob / "base" / "subdir" / "nested-subdir" / *
)
val depth = taskKey[Seq[File]]("Specify redundant sources with limited depth")

View File

@ -21,7 +21,7 @@ object Build {
(Compile / unmanagedResources / fileInputs).value,
Test / cached / fileInputs := (Test / unmanagedSources / fileInputs).value ++
(Test / unmanagedResources / fileInputs).value,
Compile / newInputs / fileInputs += baseDirectory.value * "*.sc",
Compile / newInputs / fileInputs += baseDirectory.value.toGlob / "*.sc",
Compile / unmanagedSources / fileInputs ++= (Compile / newInputs / fileInputs).value,
checkCompile := {
val actual = (Compile / compile / transitiveDynamicInputs).value.map(_.glob).toSet

View File

@ -8,6 +8,6 @@ setStringValue := setStringValueImpl.evaluated
checkStringValue := checkStringValueImpl.evaluated
setStringValue / watchTriggers := baseDirectory.value * "string.txt" :: Nil
setStringValue / watchTriggers := baseDirectory.value.toGlob / "string.txt" :: Nil
watchOnFileInputEvent := { (_, _) => sbt.nio.Watch.CancelWatch }

View File

@ -18,7 +18,7 @@ object Build {
}
lazy val foo = project.settings(
watchStartMessage := { (count: Int, _, _) => Some(s"FOO $count") },
Compile / compile / watchTriggers += baseDirectory.value * "foo.txt",
Compile / compile / watchTriggers += baseDirectory.value.toGlob / "foo.txt",
Compile / compile / watchStartMessage := { (count: Int, _, _) =>
// this checks that Compile / compile / watchStartMessage
// is preferred to Compile / watchStartMessage
@ -35,7 +35,9 @@ object Build {
checkStringValue := checkStringValueImpl.evaluated,
watchOnFileInputEvent := { (_, _) => Watch.CancelWatch }
)
lazy val bar = project.settings(fileInputs in setStringValue += baseDirectory.value * "foo.txt")
lazy val bar = project.settings(
fileInputs in setStringValue += baseDirectory.value.toGlob / "foo.txt"
)
lazy val root = (project in file(".")).aggregate(foo, bar).settings(
watchOnFileInputEvent := { (_, _) => Watch.CancelWatch }
)

View File

@ -23,7 +23,7 @@ object Build {
}
lazy val root = (project in file(".")).settings(
reloadFile := baseDirectory.value / "reload",
foo / fileInputs += baseDirectory.value * "foo.txt",
foo / fileInputs += baseDirectory.value.toGlob / "foo.txt",
foo := (foo / allInputFiles).value,
setStringValue := Def.taskDyn {
// This hides foo / fileInputs from the input graph

View File

@ -4,4 +4,4 @@ val root = Build.root
val foo = Build.foo
val bar = Build.bar
Global / watchTriggers += baseDirectory.value * "baz.txt"
Global / watchTriggers += baseDirectory.value.toGlob / "baz.txt"

View File

@ -46,14 +46,14 @@ object Build {
},
checkTriggers := {
val actual = triggers((Compile / compile / transitiveDynamicInputs).value).toSet
val base = baseDirectory.value.getParentFile
val base = baseDirectory.value.getParentFile.toGlob
// This checks that since foo depends on bar there is a transitive trigger generated
// for the "bar.txt" trigger added to bar / Compile / unmanagedResources (which is a
// transitive dependency of
val expected: Set[Glob] = Set(base * "baz.txt", (base / "bar") * "bar.txt")
val expected: Set[Glob] = Set(base / "baz.txt", base / "bar" / "bar.txt")
assert(actual == expected)
},
Test / test / watchTriggers += (baseDirectory.value / "test.txt").toGlob,
Test / test / watchTriggers += baseDirectory.value.toGlob / "test.txt",
Test / checkTriggers := {
val testTriggers = triggers((Test / test / transitiveDynamicInputs).value).toSet
// This validates that since the "test.txt" trigger is only added to the Test / test task,
@ -61,34 +61,34 @@ object Build {
// are found in the test above for the compile configuration because of the transitive
// classpath dependency that is added in Defaults.internalDependencies.
val compileTriggers = triggers((Test / compile / transitiveDynamicInputs).value).toSet
val base = baseDirectory.value.getParentFile
val base = baseDirectory.value.getParentFile.toGlob
val expected: Set[Glob] =
Set(base * "baz.txt", (base / "bar") * "bar.txt", (base / "foo") * "test.txt")
Set(base / "baz.txt", base / "bar" / "bar.txt", base / "foo" / "test.txt")
assert(testTriggers == expected)
assert((testTriggers - ((base / "foo") * "test.txt")) == compileTriggers)
assert((testTriggers - (base / "foo" / "test.txt")) == compileTriggers)
},
)
.dependsOn(bar)
lazy val bar = project.settings(
fileInputs in setStringValue += baseDirectory.value * "foo.txt",
setStringValue / watchTriggers += baseDirectory.value * "bar.txt",
fileInputs in setStringValue += baseDirectory.value.toGlob / "foo.txt",
setStringValue / watchTriggers += baseDirectory.value.toGlob / "bar.txt",
// This trigger should transitively propagate to foo / compile and foo / Test / compile
Compile / unmanagedResources / watchTriggers += baseDirectory.value * "bar.txt",
Compile / unmanagedResources / watchTriggers += baseDirectory.value.toGlob / "bar.txt",
checkTriggers := {
val base = baseDirectory.value.getParentFile
val base = baseDirectory.value.getParentFile.toGlob
val actual = triggers((Compile / compile / transitiveDynamicInputs).value).toSet
val expected: Set[Glob] = Set((base / "bar") * "bar.txt", base * "baz.txt")
val expected: Set[Glob] = Set(base / "bar" / "bar.txt", base / "baz.txt")
assert(actual == expected)
},
// This trigger should not transitively propagate to any foo task
Test / unmanagedResources / watchTriggers += baseDirectory.value * "bar-test.txt",
Test / unmanagedResources / watchTriggers += baseDirectory.value.toGlob / "bar-test.txt",
Test / checkTriggers := {
val testTriggers = triggers((Test / test / transitiveDynamicInputs).value).toSet
val compileTriggers = triggers((Test / compile / transitiveDynamicInputs).value).toSet
val base = baseDirectory.value.getParentFile
val base = baseDirectory.value.getParentFile.toGlob
val expected: Set[Glob] =
Set(base * "baz.txt", (base / "bar") * "bar.txt", (base / "bar") * "bar-test.txt")
Set(base / "baz.txt", base / "bar" / "bar.txt", base / "bar" / "bar-test.txt")
assert(testTriggers == expected)
assert(testTriggers == compileTriggers)
},
@ -101,7 +101,7 @@ object Build {
},
checkTriggers := {
val actual = triggers((Compile / compile / transitiveDynamicInputs).value)
val expected: Seq[Glob] = baseDirectory.value * "baz.txt" :: Nil
val expected: Seq[Glob] = baseDirectory.value.toGlob / "baz.txt" :: Nil
assert(actual == expected)
},
)

View File

View File

@ -19,7 +19,7 @@ object Build {
}
lazy val root = (project in file(".")).settings(
reloadFile := baseDirectory.value / "reload",
setStringValue / watchTriggers += baseDirectory.value * "foo.txt",
setStringValue / watchTriggers += baseDirectory.value.toGlob / "foo.txt",
setStringValue := setStringValueImpl.evaluated,
checkStringValue := checkStringValueImpl.evaluated,
watchOnFileInputEvent := { (_, _) => Watch.CancelWatch },

View File

@ -17,7 +17,7 @@ object Build {
assert(IO.read(file(stringFile)) == string)
}
lazy val root = (project in file(".")).settings(
setStringValue / watchTriggers += baseDirectory.value * "foo.txt",
setStringValue / watchTriggers += baseDirectory.value.toGlob / "foo.txt",
setStringValue := setStringValueImpl.evaluated,
checkStringValue := checkStringValueImpl.evaluated,
watchStartMessage := { (_, _, _) =>

View File

@ -19,7 +19,7 @@ object Build {
}
lazy val root = (project in file(".")).settings(
reloadFile := baseDirectory.value / "reload",
setStringValue / watchTriggers += baseDirectory.value * "foo.txt",
setStringValue / watchTriggers += baseDirectory.value.toGlob / "foo.txt",
setStringValue := setStringValueImpl.evaluated,
checkStringValue := checkStringValueImpl.evaluated,
watchStartMessage := { (_, _, _) =>