diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 21fa1ca7..01ee331f 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -8,6 +8,7 @@ on: pull_request: branches: - main + - improved-overflow-support-main jobs: test: diff --git a/src/main/java/engineering/swat/watch/WatchEvent.java b/src/main/java/engineering/swat/watch/WatchEvent.java index 4d4874d5..3edb87c4 100644 --- a/src/main/java/engineering/swat/watch/WatchEvent.java +++ b/src/main/java/engineering/swat/watch/WatchEvent.java @@ -68,6 +68,10 @@ public enum Kind { private final Path rootPath; private final Path relativePath; + public WatchEvent(Kind kind, Path rootPath) { + this(kind, rootPath, null); + } + public WatchEvent(Kind kind, Path rootPath, @Nullable Path relativePath) { this.kind = kind; this.rootPath = rootPath; diff --git a/src/main/java/engineering/swat/watch/impl/jdk/JDKBaseWatch.java b/src/main/java/engineering/swat/watch/impl/jdk/JDKBaseWatch.java index fb90755a..d0dc6c67 100644 --- a/src/main/java/engineering/swat/watch/impl/jdk/JDKBaseWatch.java +++ b/src/main/java/engineering/swat/watch/impl/jdk/JDKBaseWatch.java @@ -90,27 +90,29 @@ protected boolean startIfFirstTime() throws IOException { } protected WatchEvent translate(java.nio.file.WatchEvent jdkEvent) { - WatchEvent.Kind kind; - if (jdkEvent.kind() == StandardWatchEventKinds.ENTRY_CREATE) { - kind = WatchEvent.Kind.CREATED; - } - else if (jdkEvent.kind() == StandardWatchEventKinds.ENTRY_MODIFY) { - kind = WatchEvent.Kind.MODIFIED; - } - else if (jdkEvent.kind() == StandardWatchEventKinds.ENTRY_DELETE) { - kind = WatchEvent.Kind.DELETED; - } - else if (jdkEvent.kind() == StandardWatchEventKinds.OVERFLOW) { - kind = WatchEvent.Kind.OVERFLOW; - } - else { - throw new IllegalArgumentException("Unexpected watch event: " + jdkEvent); - } + var kind = translate(jdkEvent.kind()); var rootPath = path; - var relativePath = kind == WatchEvent.Kind.OVERFLOW ? Path.of("") : (@Nullable Path)jdkEvent.context(); + var relativePath = kind == WatchEvent.Kind.OVERFLOW ? null : (@Nullable Path) jdkEvent.context(); var event = new WatchEvent(kind, rootPath, relativePath); logger.trace("Translated: {} to {}", jdkEvent, event); return event; } + + private WatchEvent.Kind translate(java.nio.file.WatchEvent.Kind jdkKind) { + if (jdkKind == StandardWatchEventKinds.ENTRY_CREATE) { + return WatchEvent.Kind.CREATED; + } + if (jdkKind == StandardWatchEventKinds.ENTRY_MODIFY) { + return WatchEvent.Kind.MODIFIED; + } + if (jdkKind == StandardWatchEventKinds.ENTRY_DELETE) { + return WatchEvent.Kind.DELETED; + } + if (jdkKind == StandardWatchEventKinds.OVERFLOW) { + return WatchEvent.Kind.OVERFLOW; + } + + throw new IllegalArgumentException("Unexpected watch kind: " + jdkKind); + } } diff --git a/src/main/java/engineering/swat/watch/impl/jdk/JDKDirectoryWatch.java b/src/main/java/engineering/swat/watch/impl/jdk/JDKDirectoryWatch.java index fcb6004e..82a8d097 100644 --- a/src/main/java/engineering/swat/watch/impl/jdk/JDKDirectoryWatch.java +++ b/src/main/java/engineering/swat/watch/impl/jdk/JDKDirectoryWatch.java @@ -58,7 +58,7 @@ public JDKDirectoryWatch(Path directory, Executor exec, Consumer eve this.nativeRecursive = nativeRecursive; } - private void handleChanges(List> events) { + private void handleJDKEvents(List> events) { exec.execute(() -> { for (var ev : events) { try { @@ -85,6 +85,6 @@ public synchronized void close() throws IOException { protected synchronized void start() throws IOException { assert bundledJDKWatcher == null; var key = new SubscriptionKey(path, nativeRecursive); - bundledJDKWatcher = BUNDLED_JDK_WATCHERS.subscribe(key, this::handleChanges); + bundledJDKWatcher = BUNDLED_JDK_WATCHERS.subscribe(key, this::handleJDKEvents); } } diff --git a/src/main/java/engineering/swat/watch/impl/jdk/JDKFileWatch.java b/src/main/java/engineering/swat/watch/impl/jdk/JDKFileWatch.java index bd27b83c..ae572d00 100644 --- a/src/main/java/engineering/swat/watch/impl/jdk/JDKFileWatch.java +++ b/src/main/java/engineering/swat/watch/impl/jdk/JDKFileWatch.java @@ -33,7 +33,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.Nullable; import engineering.swat.watch.WatchEvent; @@ -45,17 +44,23 @@ */ public class JDKFileWatch extends JDKBaseWatch { private final Logger logger = LogManager.getLogger(); - private final Path parent; - private final Path fileName; - private volatile @MonotonicNonNull JDKDirectoryWatch parentWatch; + private final JDKBaseWatch internal; public JDKFileWatch(Path file, Executor exec, Consumer eventHandler) { super(file, exec, eventHandler); var message = "The root path is not a valid path for a file watch"; - this.parent = requireNonNull(path.getParent(), message); - this.fileName = requireNonNull(path.getFileName(), message); - assert !parent.equals(path); + var parent = requireNonNull(file.getParent(), message); + var fileName = requireNonNull(file.getFileName(), message); + assert !parent.equals(file); + + this.internal = new JDKDirectoryWatch(parent, exec, e -> { + if (fileName.equals(e.getRelativePath())) { + eventHandler.accept(e); + } + }); + + logger.debug("File watch (for: {}) is in reality a directory watch (for: {}) with a filter (for: {})", file, parent, fileName); } private static Path requireNonNull(@Nullable Path p, String message) { @@ -65,26 +70,15 @@ private static Path requireNonNull(@Nullable Path p, String message) { return p; } - private void filter(WatchEvent event) { - if (fileName.equals(event.getRelativePath())) { - eventHandler.accept(event); - } - } - // -- JDKBaseWatch -- @Override public synchronized void close() throws IOException { - if (parentWatch != null) { - parentWatch.close(); - } + internal.close(); } @Override protected synchronized void start() throws IOException { - assert parentWatch == null; - parentWatch = new JDKDirectoryWatch(parent, exec, this::filter); - parentWatch.open(); - logger.debug("File watch (for: {}) is in reality a directory watch (for: {}) with a filter (for: {})", path, parent, fileName); + internal.open(); } }