Skip to content

Commit

Permalink
Merge pull request #47 from olafurpg/watch
Browse files Browse the repository at this point in the history
Polish file watching
  • Loading branch information
olafurpg authored Aug 20, 2018
2 parents d3d6212 + fdc57c4 commit cfe35af
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 48 deletions.
4 changes: 4 additions & 0 deletions vork/src/main/scala/vork/MainSettings.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package vork

import java.io.InputStream
import java.nio.charset.Charset
import java.nio.file.Path
import java.nio.file.PathMatcher
Expand Down Expand Up @@ -54,6 +55,9 @@ final class MainSettings private (
def withReporter(reporter: Reporter): MainSettings = {
copy(reporter = reporter)
}
def withInputStream(inputStream: InputStream): MainSettings = {
copy(settings.copy(inputStream = inputStream))
}

private[this] implicit def cwd: AbsolutePath = settings.cwd
private[this] def copy(
Expand Down
44 changes: 32 additions & 12 deletions vork/src/main/scala/vork/internal/cli/MainOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ package vork.internal.cli
import com.vladsch.flexmark.util.options.MutableDataSet
import io.methvin.watcher.DirectoryChangeEvent
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.SimpleFileVisitor
import java.nio.file.StandardCopyOption
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
import metaconfig.Configured
import scala.meta.Input
Expand All @@ -15,8 +14,8 @@ import scala.meta.io.AbsolutePath
import scala.util.control.NonFatal
import scalafix.internal.diff.DiffUtils
import vork.Reporter
import vork.internal.io.FileWatcher
import vork.internal.io.IO
import vork.internal.io.VorkFileListener
import vork.internal.markdown.Markdown
import vork.internal.markdown.MarkdownLinks
import vork.internal.markdown.MarkdownLinter
Expand All @@ -33,6 +32,7 @@ final class MainOps(
}

def handleMarkdown(file: InputFile): Unit = synchronized {
clearScreen()
reporter.reset()
reporter.info(s"Compiling ${file.in}")
val start = System.nanoTime()
Expand All @@ -47,6 +47,7 @@ final class MainOps(
val end = System.nanoTime()
val elapsed = TimeUnit.NANOSECONDS.toMillis(end - start)
reporter.info(f" done => ${file.out} ($elapsed%,d ms)")
waitingForFileChanges()
}
}

Expand All @@ -56,14 +57,6 @@ final class MainOps(
reporter.info(s"Copied ${file.out.toNIO}")
}

def handleWatchEvent(event: DirectoryChangeEvent): Unit = {
val path = AbsolutePath(event.path())
settings.toInputFile(path) match {
case Some(inputFile) => handleFile(inputFile)
case None => ()
}
lint()
}
def handleFile(file: InputFile): Unit = {
try {
if (!settings.matches(file.relpath)) ()
Expand Down Expand Up @@ -117,8 +110,35 @@ final class MainOps(
IO.cleanTarget(settings.out)
}
generateCompleteSite()
runFileWatcher()
}

def handleWatchEvent(event: DirectoryChangeEvent): Unit = {
val path = AbsolutePath(event.path())
settings.toInputFile(path) match {
case Some(inputFile) => handleFile(inputFile)
case None => ()
}
lint()
}

def runFileWatcher(): Unit = {
if (settings.watch) {
val executor = Executors.newFixedThreadPool(1)
val watcher = VorkFileListener.create(settings.in, executor, System.in)(handleWatchEvent)
watcher.watchUntilInterrupted()
}
}

def clearScreen(): Unit = {
if (settings.watch) {
print("\033[H\033[2J")
}
}

def waitingForFileChanges(): Unit = {
if (settings.watch) {
FileWatcher.watch(settings.in, handleWatchEvent)
reporter.println(s"Waiting for file changes (press enter to interrupt)")
}
}

Expand Down
10 changes: 9 additions & 1 deletion vork/src/main/scala/vork/internal/cli/Settings.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package vork.internal.cli

import java.io.InputStream
import java.nio.charset.Charset
import java.nio.charset.IllegalCharsetNameException
import java.nio.charset.StandardCharsets
Expand Down Expand Up @@ -82,7 +83,10 @@ case class Settings(
@Description("The working directory to use for making relative paths absolute.")
cwd: AbsolutePath,
@Hidden()
stringModifiers: List[StringModifier] = Nil
stringModifiers: List[StringModifier] = Nil,
@Hidden()
@Description("The input stream to listen for enter key during file watching.")
inputStream: InputStream = System.in
) {

def toInputFile(infile: AbsolutePath): Option[InputFile] = {
Expand Down Expand Up @@ -174,6 +178,8 @@ object Settings extends MetaconfigScalametaImplicits {
ConfError.message(s"Charset name '$str' is illegal").notOk
}
}
implicit val inputStreamDecoder: ConfDecoder[InputStream] =
ConfDecoder.stringConfDecoder.map(_ => System.in)

implicit val pathEncoder: ConfEncoder[AbsolutePath] =
ConfEncoder.StringEncoder.contramap { path =>
Expand All @@ -184,5 +190,7 @@ object Settings extends MetaconfigScalametaImplicits {
ConfEncoder.StringEncoder.contramap(_.toString())
implicit val charsetEncoder: ConfEncoder[Charset] =
ConfEncoder.StringEncoder.contramap(_.name())
implicit val inputStreamEncoder: ConfEncoder[InputStream] =
ConfEncoder.StringEncoder.contramap(_ => "<input stream>")

}
35 changes: 0 additions & 35 deletions vork/src/main/scala/vork/internal/io/FileWatcher.scala

This file was deleted.

60 changes: 60 additions & 0 deletions vork/src/main/scala/vork/internal/io/VorkFileListener.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package vork.internal.io

import io.methvin.watcher.DirectoryChangeEvent
import io.methvin.watcher.DirectoryChangeEvent.EventType
import io.methvin.watcher.DirectoryChangeListener
import io.methvin.watcher.DirectoryWatcher
import java.io.InputStream
import java.nio.file.Files
import java.util.Scanner
import java.util.concurrent.Executor
import java.util.concurrent.ExecutorService
import scala.meta.io.AbsolutePath
import scala.collection.JavaConverters._

final class VorkFileListener(
executor: ExecutorService,
in: InputStream,
runAction: DirectoryChangeEvent => Unit
) extends DirectoryChangeListener {
private var myIsWatching: Boolean = true
private var watcher: DirectoryWatcher = _
private def blockUntilEnterKey(): Unit = {
try {
new Scanner(in).nextLine()
} catch {
case _: NoSuchElementException =>
}
}
def watchUntilInterrupted(): Unit = {
watcher.watchAsync(executor)
blockUntilEnterKey()
executor.shutdown()
myIsWatching = false
watcher.close()
}
override def isWatching: Boolean = myIsWatching
override def onEvent(event: DirectoryChangeEvent): Unit = {
val targetFile = event.path()
if (Files.isRegularFile(targetFile)) {
event.eventType() match {
case EventType.CREATE => runAction(event)
case EventType.MODIFY => runAction(event)
case EventType.OVERFLOW => runAction(event)
case EventType.DELETE => () // We don't do anything when a file is deleted
}
}
}
}

object VorkFileListener {
def create(dir: AbsolutePath, executor: ExecutorService, in: InputStream)(
runAction: DirectoryChangeEvent => Unit
): VorkFileListener = {
val listener = new VorkFileListener(executor, in, runAction)
val watcher = DirectoryWatcher.create(List(dir.toNIO).asJava, listener, true)
listener.watcher = watcher
listener
}

}
1 change: 1 addition & 0 deletions website/src/main/scala/vork/website/Website.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ object Website {
.withCleanTarget(false)
.withTest(isTest)
.withReportRelativePaths(true)
.withWatch(true)
val context = settings.settings.validate(settings.reporter).get
val stringModifier = new VorkStringModifier(context)
val exitCode = Main.process(settings.withStringModifiers(List(stringModifier)))
Expand Down

0 comments on commit cfe35af

Please sign in to comment.