diff --git a/io/src/main/scala/sbt/internal/io/EventMonitor.scala b/io/src/main/scala/sbt/internal/io/EventMonitor.scala index 3e74106f..cfe7f7ba 100644 --- a/io/src/main/scala/sbt/internal/io/EventMonitor.scala +++ b/io/src/main/scala/sbt/internal/io/EventMonitor.scala @@ -130,8 +130,11 @@ private[sbt] object EventMonitor { def getFilesForKey(key: WatchKey): collection.Seq[Path] = key match { case null => Nil case k => - val allEvents = k.pollEvents.asScala - .map(e => k.watchable.asInstanceOf[Path].resolve(e.context.asInstanceOf[Path])) + val rawEvents = k.pollEvents + k.reset() + val allEvents = rawEvents.asScala.flatMap { e => + Option(e.context).map(c => k.watchable.asInstanceOf[Path].resolve(c.asInstanceOf[Path])) + } logger.debug(s"Received events:\n${allEvents.mkString("\n")}") val (exist, notExist) = allEvents.partition(Files.exists(_)) val (updatedDirectories, updatedFiles) = exist.partition(Files.isDirectory(_)) diff --git a/io/src/main/scala/sbt/io/MacOSXWatchService.scala b/io/src/main/scala/sbt/io/MacOSXWatchService.scala index 68719708..96eae239 100644 --- a/io/src/main/scala/sbt/io/MacOSXWatchService.scala +++ b/io/src/main/scala/sbt/io/MacOSXWatchService.scala @@ -155,7 +155,7 @@ private class MacOSXWatchKey(val watchable: JPath, queueSize: Int, kinds: WatchE Collections.unmodifiableList(result) } - override def reset(): Boolean = { events.clear(); true } + override def reset(): Boolean = true override def toString = s"MacOSXWatchKey($watchable)" diff --git a/io/src/test/scala/sbt/internal/io/SourceModificationWatchSpec.scala b/io/src/test/scala/sbt/internal/io/SourceModificationWatchSpec.scala index 8140ea4b..51caa0ff 100644 --- a/io/src/test/scala/sbt/internal/io/SourceModificationWatchSpec.scala +++ b/io/src/test/scala/sbt/internal/io/SourceModificationWatchSpec.scala @@ -348,6 +348,30 @@ abstract class SourceModificationWatchSpec( } finally monitor.close() } + it should "reset keys" in IO.withTemporaryDirectory { dir => + val parentDir = dir / "src" / "watchme" + val file = parentDir / "Foo.scala" + + writeNewFile(file, "foo") + // Longer timeout because there are many file system operations + val deadline = 5.seconds.fromNow + val monitor = defaultMonitor(getService, parentDir, tc = () => deadline.isOverdue) + try { + val n = 1000 + val triggered0 = watchTest(monitor) { + (0 to n).foreach(i => IO.write(parentDir / s"Foo$i.scala", s"foo$i")) + } + assert(triggered0) + assert(IO.read(file) == s"foo") + + val triggered1 = watchTest(monitor) { + IO.write(file, "baz") + } + assert(triggered1) + assert(IO.read(file) == "baz") + } finally monitor.close() + } + "WatchService.poll" should "throw a `ClosedWatchServiceException` if used after `close`" in { val service = getService service.close()