typelevel / fs2

Compositional, streaming I/O library for Scala
https://fs2.io
Other
2.37k stars 601 forks source link

`fs2.io.Watcher#watch` with a relative path to file causes an NPE #3472

Open tom91136 opened 2 months ago

tom91136 commented 2 months ago

It seems that supplying a relative java.nio.file.Path to the watcher's fs2.io.Watcher#watch method causes an NPE:

import fs2.io.Watcher
import fs2.io.file.{Files, Path}
import cats.effect.*
import cats.effect.unsafe.implicits.global

@main def main = {

    java.nio.file.Files.createDirectories(java.nio.file.Path.of("foo"))

    val f = java.nio.file.Path.of("a.json")
    if (!java.nio.file.Files.exists(f)) {
        java.nio.file.Files.createFile(f)
    }

    println(f)
    Watcher
        .default[IO].use{ w => w.watch(f) }
        .unsafeRunSync()
}
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.nio.file.Path.register(java.nio.file.WatchService, java.nio.file.WatchEvent$Kind[], java.nio.file.WatchEvent$Modifier[])" because "path$7" is null
    at fs2.io.Watcher$DefaultWatcher.registerUntracked$$anonfun$1(DeprecatedWatcher.scala:301)
    at blocking @ fs2.io.Watcher$.default(DeprecatedWatcher.scala:153)
    at flatMap @ fs2.io.Watcher$DefaultWatcher.watchFile(DeprecatedWatcher.scala:278)
    at blocking @ fs2.io.Watcher$.default(DeprecatedWatcher.scala:153)
    at flatMap @ fs2.io.Watcher$DefaultWatcher.watch(DeprecatedWatcher.scala:212)
    at of @ fs2.io.Watcher$.fromWatchService(DeprecatedWatcher.scala:180)
    at map @ fs2.io.Watcher$.fromWatchService(DeprecatedWatcher.scala:181)
    at map @ fs2.io.Watcher$.fromFileSystem$$anonfun$2(DeprecatedWatcher.scala:161)
    at blocking @ fs2.io.Watcher$.default(DeprecatedWatcher.scala:153)
    at flatMap @ fs2.io.Watcher$.fromFileSystem(DeprecatedWatcher.scala:161)
    at apply @ fs2.io.Watcher$.fromFileSystem(DeprecatedWatcher.scala:162)

At some point getParent was called on the path parameter:

https://github.com/typelevel/fs2/blob/1e4d752c1301df7e4005fdb5d6d84787e15d1ea3/io/jvm-native/src/main/scala/fs2/io/DeprecatedWatcher.scala#L266

If we resolve the path (e.g call toAbsolutePath) the issues goes away and the watcher works as expected. Happy to add test and fix in a PR if confirmed.

fs2-io version: 3.11.0 Scastie: https://scastie.scala-lang.org/BoemfzqmQh2HAlRCeGnEbA

mpilquist commented 1 month ago

Thanks for reporting. A PR would be great!