import java.nio.file._
import sbt.nio.Keys._
import sbt.nio._
import scala.concurrent.duration._
import StandardCopyOption.{ REPLACE_EXISTING => replace }

watchTriggeredMessage := { (i, path: Path, c) =>
  val prev = watchTriggeredMessage.value
  if (path.getFileName.toString == "C.scala")
    throw new IllegalStateException("C.scala should not trigger")
  prev(i, path, c)
}

watchOnIteration := { i: Int =>
  val base = baseDirectory.value.toPath
  val src =
    base.resolve("src").resolve("main").resolve("scala").resolve("sbt").resolve("test")
  val changes = base.resolve("changes")
  Files.copy(changes.resolve("C.scala"), src.resolve("C.scala"), replace)
  if (i < 5) {
    val content =
      new String(Files.readAllBytes(changes.resolve("A.scala"))) + "\n" + ("//" * i)
    Files.write(src.resolve("A.scala"), content.getBytes)
  } else {
    Files.copy(changes.resolve("B.scala"), src.resolve("B.scala"), replace)
  }
  println(s"Waiting for changes...")
  Watch.Ignore
}

watchOnFileInputEvent := { (_, event: Watch.Event) =>
  if (event.path.getFileName.toString == "B.scala") Watch.CancelWatch
  else Watch.Trigger
}

watchAntiEntropy := 0.millis
import java.nio.file._
import java.nio.file.attribute.FileTime

import sbt.nio.Keys._
import sbt.nio._

import scala.concurrent.duration._

watchTriggeredMessage := { (i, path: Path, c) =>
  val prev = watchTriggeredMessage.value
  if (path.getFileName.toString == "C.scala")
    throw new IllegalStateException("C.scala should not trigger")
  prev(i, path, c)
}

watchOnIteration := { i: Int =>
  val base = baseDirectory.value.toPath
  val src =
    base.resolve("src").resolve("main").resolve("scala").resolve("sbt").resolve("test")
  val changes = base.resolve("changes")
  def copy(fileName: String): Unit = {
    val content =
      new String(Files.readAllBytes(changes.resolve(fileName))) + "\n" + ("//" * i)
    Files.write(src.resolve(fileName), content.getBytes)
  }
  val c = src.resolve("C.scala")
  Files.setLastModifiedTime(c, FileTime.fromMillis(Files.getLastModifiedTime(c).toMillis + 1111))
  if (i < 5) copy("A.scala")
  else copy("B.scala")
  println(s"Waiting for changes...")
  Watch.Ignore
}

watchOnFileInputEvent := { (_, event: Watch.Event) =>
  if (event.path.getFileName.toString == "B.scala") Watch.CancelWatch
  else Watch.Trigger
}

watchAntiEntropy := 0.millis
Make scripted watch/on-changes more robust
Make scripted watch/on-changes more robust

I noticed that sometimes this test hangs in ci. I think it may be
because sometimes the event for A got handled while the cache entry for
B.scala was invalidated. Because the test runs ~compile, the next run of
compile would then reset the cache entry for B.scala. The next run of
watchOnIteration invalidtes B.scala again, but this time to the same
hash, so it doesn't actually trigger a file input event. By changing the
content of B.scala every time, we ensure that it should still cause a
file event.

I haven't confirmed that this will fix the sporadic hangs because I
can't reproduce on my machine, but this change won't hurt.
