From bbd88e04dcdb91e23c76c20b01bca41eaed6b06e Mon Sep 17 00:00:00 2001 From: Ethan Atkins Date: Fri, 26 Jul 2019 09:51:30 -0700 Subject: [PATCH] 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. --- sbt/src/sbt-test/watch/symlinks/build.sbt | 46 +++++++++++++++++++ .../symlinks/changes/file-source/Foo.scala | 1 + .../watch/symlinks/changes/sources/Bar.scala | 3 ++ .../watch/symlinks/file-source/Foo.scala | 1 + sbt/src/sbt-test/watch/symlinks/test | 15 ++++++ 5 files changed, 66 insertions(+) create mode 100644 sbt/src/sbt-test/watch/symlinks/build.sbt create mode 100644 sbt/src/sbt-test/watch/symlinks/changes/file-source/Foo.scala create mode 100644 sbt/src/sbt-test/watch/symlinks/changes/sources/Bar.scala create mode 100644 sbt/src/sbt-test/watch/symlinks/file-source/Foo.scala create mode 100644 sbt/src/sbt-test/watch/symlinks/test diff --git a/sbt/src/sbt-test/watch/symlinks/build.sbt b/sbt/src/sbt-test/watch/symlinks/build.sbt new file mode 100644 index 000000000..09e1b7ad3 --- /dev/null +++ b/sbt/src/sbt-test/watch/symlinks/build.sbt @@ -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 +} diff --git a/sbt/src/sbt-test/watch/symlinks/changes/file-source/Foo.scala b/sbt/src/sbt-test/watch/symlinks/changes/file-source/Foo.scala new file mode 100644 index 000000000..f72abf33f --- /dev/null +++ b/sbt/src/sbt-test/watch/symlinks/changes/file-source/Foo.scala @@ -0,0 +1 @@ +class Foo {} \ No newline at end of file diff --git a/sbt/src/sbt-test/watch/symlinks/changes/sources/Bar.scala b/sbt/src/sbt-test/watch/symlinks/changes/sources/Bar.scala new file mode 100644 index 000000000..f124ae515 --- /dev/null +++ b/sbt/src/sbt-test/watch/symlinks/changes/sources/Bar.scala @@ -0,0 +1,3 @@ +package sources + +class Bar \ No newline at end of file diff --git a/sbt/src/sbt-test/watch/symlinks/file-source/Foo.scala b/sbt/src/sbt-test/watch/symlinks/file-source/Foo.scala new file mode 100644 index 000000000..43c42f145 --- /dev/null +++ b/sbt/src/sbt-test/watch/symlinks/file-source/Foo.scala @@ -0,0 +1 @@ +class Foo \ No newline at end of file diff --git a/sbt/src/sbt-test/watch/symlinks/test b/sbt/src/sbt-test/watch/symlinks/test new file mode 100644 index 000000000..70ab7d943 --- /dev/null +++ b/sbt/src/sbt-test/watch/symlinks/test @@ -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