Merge pull request #4745 from eatkins/watch-fixes

Watch fixes
This commit is contained in:
eugene yokota 2019-05-30 17:25:28 -04:00 committed by GitHub
commit 63956827e0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 73 additions and 13 deletions

View File

@ -154,6 +154,7 @@ object Defaults extends BuildCommon {
inputFileStamper :== sbt.nio.FileStamper.Hash,
outputFileStamper :== sbt.nio.FileStamper.LastModified,
onChangedBuildSource :== sbt.nio.Keys.WarnOnSourceChanges,
watchTriggeredMessage :== sbt.nio.Watch.defaultOnTriggerMessage,
watchForceTriggerOnAnyChange :== false,
watchPersistFileStamps :== true,
watchTriggers :== Nil,

View File

@ -27,6 +27,7 @@ import sbt.internal.nio._
import sbt.internal.util.complete.Parser._
import sbt.internal.util.complete.{ Parser, Parsers }
import sbt.internal.util.{ AttributeKey, JLine, Util }
import sbt.nio.FileStamper.LastModified
import sbt.nio.Keys.{ fileInputs, _ }
import sbt.nio.Watch.{ Creation, Deletion, Update }
import sbt.nio.file.FileAttributes
@ -531,7 +532,7 @@ private[sbt] object Continuous extends DeprecatedContinuous {
val onEvent: Event => Seq[(Watch.Event, Watch.Action)] = event => {
val path = event.path
def watchEvent(stamper: FileStamper, forceTrigger: Boolean): Option[Watch.Event] = {
def watchEvent(forceTrigger: Boolean): Option[Watch.Event] = {
if (!event.exists) {
Some(Deletion(event))
fileStampCache.remove(event.path) match {
@ -539,7 +540,7 @@ private[sbt] object Continuous extends DeprecatedContinuous {
case _ => Some(Deletion(event))
}
} else {
fileStampCache.update(path, stamper) match {
fileStampCache.update(path, FileStamper.Hash) match {
case (None, Some(_)) => Some(Creation(event))
case (Some(_), None) => Some(Deletion(event))
case (Some(p), Some(c)) =>
@ -563,23 +564,37 @@ private[sbt] object Continuous extends DeprecatedContinuous {
}
if (buildGlobs.exists(_.matches(path))) {
watchEvent(FileStamper.Hash, forceTrigger = false).map(e => e -> Watch.Reload).toSeq
watchEvent(forceTrigger = false).map(e => e -> Watch.Reload).toSeq
} else {
configs
.flatMap { config =>
config
.inputs()
.collectFirst {
case d if d.glob.matches(path) => (d.forceTrigger, true, d.fileStamper)
}
.flatMap {
case (forceTrigger, accepted, stamper) =>
if (accepted) {
watchEvent(stamper, forceTrigger).flatMap { e =>
.filter(_.glob.matches(path))
.sortBy(_.fileStamper match {
case FileStamper.Hash => -1
case FileStamper.LastModified => 0
})
.headOption
.flatMap { d =>
val forceTrigger = d.forceTrigger
d.fileStamper match {
// We do not update the file stamp cache because we only want hashes in that
// cache or else it can mess up the external hooks that use that cache.
case LastModified =>
logger.debug(s"Trigger path detected $path")
val watchEvent =
if (!event.exists) Deletion(event)
else if (fileStampCache.get(path).isDefined) Creation(event)
else Update(event)
val action = config.watchSettings.onFileInputEvent(count.get(), watchEvent)
Some(watchEvent -> action)
case _ =>
watchEvent(forceTrigger).flatMap { e =>
val action = config.watchSettings.onFileInputEvent(count.get(), e)
if (action != Watch.Ignore) Some(e -> action) else None
}
} else None
}
}
} match {
case events if events.isEmpty => Nil
@ -920,7 +935,7 @@ private[sbt] object Continuous extends DeprecatedContinuous {
)(implicit e: Extracted): TriggerMessage = {
lazy val default =
key.get(watchTriggeredMessage).getOrElse(Watch.defaultOnTriggerMessage)
key.get(deprecatedWatchingMessage).map(Left(_)).getOrElse(Right(default))
key.get(deprecatedTriggeredMessage).map(Left(_)).getOrElse(Right(default))
}
private implicit class ScopeOps(val scope: Scope) {

View File

@ -241,7 +241,7 @@ private[sbt] object FileStamp {
def getOrElseUpdate(path: Path, stamper: FileStamper): Option[FileStamp] =
underlying.get(path) match {
case null => updateImpl(path, stamper)
case Left(v) => updateImpl(path, stamper)
case Left(_) => updateImpl(path, stamper)
case Right(v) => Some(v)
}
def remove(key: Path): Option[FileStamp] = {

View File

@ -0,0 +1,26 @@
import java.nio.file.Files
import java.nio.file.attribute.FileTime
import sbt.nio.Watch
import scala.concurrent.duration._
val foo = taskKey[Unit]("foo.txt")
foo / watchForceTriggerOnAnyChange := true
foo / fileInputs := baseDirectory.value.toGlob / "files" / "foo.txt" :: Nil
foo / watchTriggers := baseDirectory.value.toGlob / ** / "foo.txt" :: Nil
foo := {
(foo / allInputFiles).value.foreach { p =>
Files.setLastModifiedTime(p, FileTime.fromMillis(Files.getLastModifiedTime(p).toMillis + 3000))
}
sbt.nio.Stamps.check(foo).value
}
watchAntiEntropy := 0.seconds
watchOnFileInputEvent := { (count, event: Watch.Event) =>
assert(event.path.getFileName.toString == "foo.txt")
if (new String(Files.readAllBytes(event.path)) == "foo") {
if (count < 3) Watch.Trigger
else Watch.CancelWatch
} else new Watch.HandleError(new IllegalStateException("Wrong stamp was set"))
}

View File

@ -0,0 +1 @@
foo

View File

@ -0,0 +1,16 @@
package sbt
package nio
import java.nio.file._
import sbt.nio.Keys._
object Stamps {
def check(key: TaskKey[_]): Def.Initialize[Task[Unit]] = Def.task {
(key / inputFileStamps).value.map {
case (p, FileStamp.Hash(_)) =>
case (p, _) =>
Files.write(p, "fail".getBytes)
throw new IllegalStateException("Got incorrect stamp: $s")
}
}
}

View File

@ -0,0 +1 @@
> ~foo