Skip to content

Commit fa65b30

Browse files
committed
Add mechanism to avoid relativization in JDKFileTreeWatch
1 parent 71ac833 commit fa65b30

File tree

2 files changed

+50
-19
lines changed

2 files changed

+50
-19
lines changed

src/main/java/engineering/swat/watch/impl/jdk/JDKBaseWatch.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ protected WatchEvent translate(java.nio.file.WatchEvent<?> jdkEvent) {
9999
return event;
100100
}
101101

102-
private WatchEvent.Kind translate(java.nio.file.WatchEvent.Kind<?> jdkKind) {
102+
protected WatchEvent.Kind translate(java.nio.file.WatchEvent.Kind<?> jdkKind) {
103103
if (jdkKind == StandardWatchEventKinds.ENTRY_CREATE) {
104104
return WatchEvent.Kind.CREATED;
105105
}

src/main/java/engineering/swat/watch/impl/jdk/JDKFileTreeWatch.java

Lines changed: 49 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -37,23 +37,61 @@
3737

3838
import org.apache.logging.log4j.LogManager;
3939
import org.apache.logging.log4j.Logger;
40-
import org.checkerframework.checker.initialization.qual.NotOnlyInitialized;
4140

4241
import engineering.swat.watch.WatchEvent;
4342
import engineering.swat.watch.WatchScope;
4443
import engineering.swat.watch.impl.EventHandlingWatch;
4544

4645
public class JDKFileTreeWatch extends JDKBaseWatch {
4746
private final Logger logger = LogManager.getLogger();
47+
private final Path rootPath;
48+
private final Path relativePathParent;
4849
private final Map<Path, JDKFileTreeWatch> childWatches = new ConcurrentHashMap<>();
49-
private final @NotOnlyInitialized JDKBaseWatch internal;
50+
private final JDKBaseWatch internal;
5051

51-
public JDKFileTreeWatch(Path root, Executor exec,
52+
public JDKFileTreeWatch(Path fullPath, Executor exec,
53+
BiConsumer<EventHandlingWatch, WatchEvent> eventHandler) {
54+
this(fullPath, Path.of(""), exec, eventHandler);
55+
}
56+
57+
public JDKFileTreeWatch(Path rootPath, Path relativePathParent, Executor exec,
5258
BiConsumer<EventHandlingWatch, WatchEvent> eventHandler) {
5359

54-
super(root, exec, eventHandler);
60+
super(rootPath.resolve(relativePathParent), exec, eventHandler);
61+
this.rootPath = rootPath;
62+
this.relativePathParent = relativePathParent;
63+
5564
var internalEventHandler = eventHandler.andThen(new ChildWatchesUpdater());
56-
this.internal = new JDKDirectoryWatch(root, exec, internalEventHandler);
65+
this.internal = new JDKDirectoryWatch(path, exec, internalEventHandler) {
66+
67+
// Override to ensure that this watch relativizes events wrt
68+
// `rootPath` (instead of `path`, as is the default behavior)
69+
@Override
70+
public WatchEvent relativize(WatchEvent event) {
71+
return new WatchEvent(event.getKind(), rootPath,
72+
rootPath.relativize(event.calculateFullPath()));
73+
}
74+
75+
// Override to ensure that this watch translates JDK events using
76+
// `rootPath` (instead of `path`, as is the default behavior).
77+
// Events returned by this method do not need to be relativized.
78+
@Override
79+
protected WatchEvent translate(java.nio.file.WatchEvent<?> jdkEvent) {
80+
var kind = translate(jdkEvent.kind());
81+
82+
Path relativePath = null;
83+
if (kind != WatchEvent.Kind.OVERFLOW) {
84+
var child = (Path) jdkEvent.context();
85+
if (child != null) {
86+
relativePath = relativePathParent.resolve(child);
87+
}
88+
}
89+
90+
var event = new WatchEvent(kind, rootPath, relativePath);
91+
logger.trace("Translated: {} to {}", jdkEvent, event);
92+
return event;
93+
}
94+
};
5795
}
5896

5997
/**
@@ -98,27 +136,20 @@ private void acceptDeleted(Path fullPath) {
98136
}
99137
}
100138

101-
private void reportOverflowTo(EventHandlingWatch childWatch) {
102-
var overflow = new WatchEvent(WatchEvent.Kind.OVERFLOW, childWatch.getPath());
139+
private void reportOverflowTo(JDKFileTreeWatch childWatch) {
140+
var overflow = new WatchEvent(WatchEvent.Kind.OVERFLOW,
141+
childWatch.rootPath, childWatch.relativePathParent);
103142
childWatch.handleEvent(overflow);
104143
}
105144
}
106145

107146
private JDKFileTreeWatch openChildWatch(Path child) {
108-
Function<Path, JDKFileTreeWatch> newChildWatch = p -> new JDKFileTreeWatch(child, exec, (w, e) ->
109-
// Same as `eventHandler`, except each event is pre-processed such
110-
// that the last segment of the root path becomes the first segment
111-
// of the relative path. For instance, `foo/bar` (root path) and
112-
// `baz.txt` (relative path) are pre-processed to `foo` (root path)
113-
// and `bar/baz.txt` (relative path). This is to ensure the parent
114-
// directory of a child directory is reported as the root directory
115-
// of the event.
116-
eventHandler.accept(w, relativize(e))
117-
);
147+
Function<Path, JDKFileTreeWatch> newChildWatch = p -> new JDKFileTreeWatch(
148+
rootPath, rootPath.relativize(child), exec, eventHandler);
118149

119150
var childWatch = childWatches.computeIfAbsent(child, newChildWatch);
120151
try {
121-
childWatch.open();
152+
childWatch.startIfFirstTime();
122153
} catch (IOException e) {
123154
logger.error("Could not open (nested) file tree watch for: {} ({})", child, e);
124155
}

0 commit comments

Comments
 (0)