Add scripted test for symlink source monitoring

The swoval library automatically watches the _target_ of symlinks. I had
been meaning to add a scripted test to ensure that in sbt continuous
builds detect changes to the target of symlinks. The naive approach of
just watching all of the files in the source directory doesn't work
because the native watch process will just watch the symlink node itself
and not detect updates to its target. This test would have thus failed
with 1.2.8.

Watching symlinked files doesn't work at the moment on windows, but does
work on mac and linux. Eventually I'd like there to be feature parity,
but, for now, we'll just skip the file target test on windows. At least
this test makes it explicit what does and doesn't work on each platform.
This commit is contained in:
Ethan Atkins 2019-07-26 09:51:30 -07:00
parent 349d365bab
commit bbd88e04dc
5 changed files with 66 additions and 0 deletions

View File

@ -0,0 +1,46 @@
import java.nio.file.{ Files, Paths }
import java.nio.file.StandardCopyOption.REPLACE_EXISTING
val createSymlinks = taskKey[Unit]("create symlinks to source files and directories")
createSymlinks := {
val base = baseDirectory.value.toPath
val srcDir = base / "src" / "main" / "scala"
val foo = Files.createDirectories(srcDir / "file-source") / "Foo.scala"
Files.createSymbolicLink(srcDir / "sources", Files.createDirectories(base / "sources"))
Files.deleteIfExists(foo)
Files.createSymbolicLink(foo, base / "file-source" / "Foo.scala")
}
ThisBuild / watchOnFileInputEvent := {
val srcDir = baseDirectory.value.toPath / "src" / "main" / "scala"
(_: Int, event: Watch.Event) =>
event.path match {
case p if p == (srcDir / "file-source" / "Foo.scala") => Watch.CancelWatch
case p if p == (srcDir / "sources" / "Bar.scala") => Watch.CancelWatch
case _ => Watch.Ignore
}
}
val copySource = inputKey[Unit]("copy a source file from changes")
copySource := {
val relative = Def.spaceDelimited("").parsed.head.split("/") match {
case Array(head) => Paths.get(head)
case Array(head, tail @ _*) => tail.foldLeft(Paths.get(head))(_ / _)
}
val base = baseDirectory.value.toPath
Files.copy((base / "changes").resolve(relative), base.resolve(relative), REPLACE_EXISTING)
}
val removeLink = inputKey[Unit]("remove a symlink")
removeLink := {
val relative = Def.spaceDelimited("").parsed.head.split("/") match {
case Array(head) => Paths.get(head)
case Array(head, tail @ _*) => tail.foldLeft(Paths.get(head))(_ / _)
}
val srcDir = baseDirectory.value.toPath / "src" / "main" / "scala"
Files.deleteIfExists(srcDir.resolve(relative))
}
commands += Command.single("skipWindows") { (state, command) =>
if (scala.util.Properties.isWin) state else command :: state
}

View File

@ -0,0 +1 @@
class Foo {}

View File

@ -0,0 +1,3 @@
package sources
class Bar

View File

@ -0,0 +1 @@
class Foo

View File

@ -0,0 +1,15 @@
> createSymlinks
> skipWindows ~compile; copySource file-source/Foo.scala
> ~compile; copySource sources/Bar.scala
> skipWindows ~compile; removeLink file-source/Foo.scala
> ~compile; removeLink sources
> ~compile; createSymlinks
> copySource sources/Bar.scala
> ~compile; removeLink sources/Bar.scala