Build Logs
gmethvin/directory-watcher • scheduled_3.7.1-RC1-bin-20250411-98c84c3-NIGHTLY
Errors
94
Warnings
2600
Total Lines
2926
1##################################
2Clonning https://github.com/gmethvin/directory-watcher.git into repo using revision v0.18.0
3##################################
4Note: switching to '32693b3e0e99c20f84b65e071f9ba7fdeba579b6'.
5
6You are in 'detached HEAD' state. You can look around, make experimental
7changes and commit them, and you can discard any commits you make in this
8state without impacting any branches by switching back to a branch.
9
10If you want to create a new branch to retain commits you create, you may
11do so (now or later) by using -c with the switch command. Example:
12
13 git switch -c <new-branch-name>
14
15Or undo this operation with:
16
17 git switch -
18
19Turn off this advice by setting config variable advice.detachedHead to false
20
21----
22Preparing build for 3.7.1-RC1-bin-20250411-98c84c3-NIGHTLY
23Scala binary version found: 3.7
24Implicitly using source version 3.7-migration
25Scala binary version found: 3.7
26Implicitly using source version 3.7-migration
27Would try to apply common scalacOption (best-effort, sbt/mill only):
28Append: ,-source:3.7-migration,-Wconf:msg=can be rewritten automatically under:s
29Remove: ,-deprecation,-feature,-Xfatal-warnings,-Werror,MATCH:.*-Wconf.*any:e,-migration,
30----
31Starting build for 3.7.1-RC1-bin-20250411-98c84c3-NIGHTLY
32Execute tests: false
33sbt project found:
34Sbt version 1.7.1 is not supported, minimal supported version is 1.8.3
35Enforcing usage of sbt in version 1.8.3
36No prepare script found for project gmethvin/directory-watcher
37##################################
38Scala version: 3.7.1-RC1-bin-20250411-98c84c3-NIGHTLY
39Targets: io.methvin%directory-watcher-better-files
40Project projectConfig: { "projects": { "exclude": [], "overrides": {} }, "java": { "version": "17" }, "sbt": { "commands": [], "options": [] }, "mill": { "options": [] }, "tests": "compile-only", "migrationVersions": [], "sourcePatches": [] }
41##################################
42Using extra scalacOptions: ,-source:3.7-migration,-Wconf:msg=can be rewritten automatically under:s
43Filtering out scalacOptions: ,-deprecation,-feature,-Xfatal-warnings,-Werror,MATCH:.*-Wconf.*any:e,-migration,
44[sbt_options] declare -a sbt_options=()
45[process_args] java_version = '17'
46[copyRt] java9_rt = '/root/.sbt/1.0/java9-rt-ext-eclipse_adoptium_17_0_8/rt.jar'
47# Executing command line:
48java
49-Xms512M
50-Xmx4096M
51-Xss2M
52-XX:MaxMetaspaceSize=1024M
53-Dcommunitybuild.scala=3.7.1-RC1-bin-20250411-98c84c3-NIGHTLY
54-Dcommunitybuild.project.dependencies.add=
55-Xmx7G
56-Xms4G
57-Xss8M
58-Dsbt.script=/root/.sdkman/candidates/sbt/current/bin/sbt
59-Dscala.ext.dirs=/root/.sbt/1.0/java9-rt-ext-eclipse_adoptium_17_0_8
60-jar
61/root/.sdkman/candidates/sbt/1.9.6/bin/sbt-launch.jar
62"setCrossScalaVersions 3.7.1-RC1-bin-20250411-98c84c3-NIGHTLY"
63"++3.7.1-RC1-bin-20250411-98c84c3-NIGHTLY -v"
64"mapScalacOptions ",-source:3.7-migration,-Wconf:msg=can be rewritten automatically under:s" ",-deprecation,-feature,-Xfatal-warnings,-Werror,MATCH:.*-Wconf.*any:e,-migration,""
65"set every credentials := Nil"
66"excludeLibraryDependency com.github.ghik:zerowaste_{scalaVersion} com.olegpy:better-monadic-for_3 org.polyvariant:better-tostring_{scalaVersion} org.wartremover:wartremover_{scalaVersion}"
67"removeScalacOptionsStartingWith -P:wartremover"
68
69moduleMappings
70"runBuild 3.7.1-RC1-bin-20250411-98c84c3-NIGHTLY """{
71 "projects": {
72 "exclude": [],
73 "overrides": {}
74 },
75 "java": {
76 "version": "17"
77 },
78 "sbt": {
79 "commands": [],
80 "options": []
81 },
82 "mill": {
83 "options": []
84 },
85 "tests": "compile-only",
86 "migrationVersions": [],
87 "sourcePatches": []
88}""" io.methvin%directory-watcher-better-files"
89
90[info] [launcher] getting org.scala-sbt sbt 1.8.3 (this may take some time)...
91[info] [launcher] getting Scala 2.12.17 (for sbt)...
92[info] welcome to sbt 1.8.3 (Eclipse Adoptium Java 17.0.8)
93[info] loading settings for project repo-build from plugins.sbt ...
94[info] loading project definition from /build/repo/project
95[info] compiling 2 Scala sources to /build/repo/project/target/scala-2.12/sbt-1.0/classes ...
96[info] Non-compiled module 'compiler-bridge_2.12' for Scala 2.12.17. Compiling...
97[info] Compilation completed in 8.502s.
98[info] done compiling
99[info] loading settings for project root from build.sbt,version.sbt ...
100[info] set current project to root (in build file:/build/repo/)
101Execute setCrossScalaVersions: 3.7.1-RC1-bin-20250411-98c84c3-NIGHTLY
102OpenCB::Changing crossVersion 3.2.2 -> 3.7.1-RC1-bin-20250411-98c84c3-NIGHTLY in directory-watcher-better-files/crossScalaVersions
103OpenCB::Changing crossVersion 3.2.2 -> 3.7.1-RC1-bin-20250411-98c84c3-NIGHTLY in root/crossScalaVersions
104OpenCB::Changing crossVersion 3.2.2 -> 3.7.1-RC1-bin-20250411-98c84c3-NIGHTLY in directory-watcher/crossScalaVersions
105[info] set current project to root (in build file:/build/repo/)
106[info] Setting Scala version to 3.7.1-RC1-bin-20250411-98c84c3-NIGHTLY on 3 projects.
107[info] Switching Scala version on:
108[info] * root (3.7.1-RC1-bin-20250411-98c84c3-NIGHTLY)
109[info] directory-watcher (3.7.1-RC1-bin-20250411-98c84c3-NIGHTLY)
110[info] directory-watcher-better-files (3.7.1-RC1-bin-20250411-98c84c3-NIGHTLY, 2.13.10, 2.12.10)
111[info] Excluding projects:
112[info] Reapplying settings...
113[info] set current project to root (in build file:/build/repo/)
114Execute mapScalacOptions: ,-source:3.7-migration,-Wconf:msg=can be rewritten automatically under:s ,-deprecation,-feature,-Xfatal-warnings,-Werror,MATCH:.*-Wconf.*any:e,-migration,
115[info] Reapplying settings...
116[info] set current project to root (in build file:/build/repo/)
117[info] Defining Global / credentials, credentials and 1 others.
118[info] The new values will be used by Global / pgpSelectPassphrase, Global / pgpSigningKey and 14 others.
119[info] Run `last` for details.
120[info] Reapplying settings...
121[info] set current project to root (in build file:/build/repo/)
122Execute excludeLibraryDependency: com.github.ghik:zerowaste_{scalaVersion} com.olegpy:better-monadic-for_3 org.polyvariant:better-tostring_{scalaVersion} org.wartremover:wartremover_{scalaVersion}
123[info] Reapplying settings...
124OpenCB::Failed to reapply settings in excludeLibraryDependency: Reference to undefined setting:
125
126 Global / allExcludeDependencies from Global / allExcludeDependencies (CommunityBuildPlugin.scala:315)
127 Did you mean allExcludeDependencies ?
128 , retry without global scopes
129[info] Reapplying settings...
130[info] set current project to root (in build file:/build/repo/)
131Execute removeScalacOptionsStartingWith: -P:wartremover
132[info] Reapplying settings...
133[info] set current project to root (in build file:/build/repo/)
134[success] Total time: 0 s, completed Apr 12, 2025, 1:45:20 AM
135Build config: {
136 "projects": {
137 "exclude": [],
138 "overrides": {}
139 },
140 "java": {
141 "version": "17"
142 },
143 "sbt": {
144 "commands": [],
145 "options": []
146 },
147 "mill": {
148 "options": []
149 },
150 "tests": "compile-only",
151 "migrationVersions": [],
152 "sourcePatches": []
153}
154Parsed config: Success(ProjectBuildConfig(ProjectsConfig(List(),Map()),CompileOnly,List()))
155Starting build...
156Projects: Set(directory-watcher-better-files, directory-watcher)
157Starting build for ProjectRef(file:/build/repo/,directory-watcher-better-files) (directory-watcher-better-files)...
158OpenCB::Exclude Scala3 specific scalacOption `-source:3.7-migration` in Scala 2.12.17 module Global
159OpenCB::Would not apply setting `-source:3.7-migration`: Project has predefined source version: Some(-source:3.7-migration)
160Compile scalacOptions: List(-target:jvm-1.8, -source:3.7-migration, -Wconf:msg=can be rewritten automatically under:s)
161[info] scalafmt: Formatting 1 Scala sources (/build/repo/better-files)...
162[info] compiling 28 Java sources to /build/repo/core/target/classes ...
163[info] scalafmt: Formatting 1 Scala sources (/build/repo/better-files)...
164[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CarbonAPI.java:20:1: <T>loadLibrary(java.lang.String,java.lang.Class<T>) in com.sun.jna.Native has been deprecated
165[warn] Native.loadLibrary
166[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CarbonAPI.java:20:1: redundant cast to io.methvin.watchservice.jna.CarbonAPI
167[warn] (CarbonAPI) Native.loadLibrary("Carbon", CarbonAPI.class)
168[info] done compiling
169[info] compiling 1 Scala source to /build/repo/better-files/target/scala-3.7.1-RC1-bin-20250411-98c84c3-NIGHTLY/classes ...
170[warn] bad option '-target:jvm-1.8' was ignored
171[warn] one warning found
172[info] done compiling
173[info] Main Scala API documentation to /build/repo/better-files/target/scala-3.7.1-RC1-bin-20250411-98c84c3-NIGHTLY/api...
174[warn] bad option '-target:jvm-1.8' was ignored
175[info] Skipping unused scalacOptions: -Wconf, -source
176[warn] Flag -classpath set repeatedly
177[warn] two warnings found
178[info] Main Scala API documentation successful.
179[info] compiling 1 Scala source to /build/repo/better-files/target/scala-3.7.1-RC1-bin-20250411-98c84c3-NIGHTLY/test-classes ...
180[warn] bad option '-target:jvm-1.8' was ignored
181[warn] one warning found
182[info] done compiling
183[info] Wrote /build/repo/better-files/target/scala-3.7.1-RC1-bin-20250411-98c84c3-NIGHTLY/directory-watcher-better-files_3-0.18.0.pom
184[info] Main Scala API documentation to /build/repo/better-files/target/scala-3.7.1-RC1-bin-20250411-98c84c3-NIGHTLY/api...
185[warn] bad option '-target:jvm-1.8' was ignored
186[info] Skipping unused scalacOptions: -Wconf, -source
187[warn] Flag -classpath set repeatedly
188[warn] two warnings found
189[info] Main Scala API documentation successful.
190[info] :: delivering :: io.methvin#directory-watcher-better-files_3;0.18.0 :: 0.18.0 :: release :: Sat Apr 12 01:45:42 CEST 2025
191[info] delivering ivy file to /build/repo/better-files/target/scala-3.7.1-RC1-bin-20250411-98c84c3-NIGHTLY/ivy-0.18.0.xml
192[info] published directory-watcher-better-files_3 to /root/.ivy2/local/io.methvin/directory-watcher-better-files_3/0.18.0/poms/directory-watcher-better-files_3.pom
193[info] published directory-watcher-better-files_3 to /root/.ivy2/local/io.methvin/directory-watcher-better-files_3/0.18.0/jars/directory-watcher-better-files_3.jar
194[info] published directory-watcher-better-files_3 to /root/.ivy2/local/io.methvin/directory-watcher-better-files_3/0.18.0/srcs/directory-watcher-better-files_3-sources.jar
195[info] published directory-watcher-better-files_3 to /root/.ivy2/local/io.methvin/directory-watcher-better-files_3/0.18.0/docs/directory-watcher-better-files_3-javadoc.jar
196[info] published ivy to /root/.ivy2/local/io.methvin/directory-watcher-better-files_3/0.18.0/ivys/ivy.xml
197Starting build for ProjectRef(file:/build/repo/,directory-watcher) (directory-watcher)...
198Compile scalacOptions: List(-target:jvm-1.8, -source:3.7-migration, -Wconf:msg=can be rewritten automatically under:s)
199[info] Main Java API documentation to /build/repo/core/target/api...
200[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CarbonAPI.java:18:1: no comment
201[warn] public interface CarbonAPI extends Library {
202[warn] // sbt uses JNA 4.5.0, so use JNA 4.x's API
203[warn] CarbonAPI INSTANCE = (CarbonAPI) Native.loadLibrary("Carbon", CarbonAPI.class);
204[warn]
205[warn] CFArrayRef CFArrayCreate(
206[warn] CFAllocatorRef allocator, // always set to Pointer.NULL
207[warn] Pointer[] values,
208[warn] CFIndex numValues,
209[warn] Void callBacks // always set to Pointer.NULL
210[warn] );
211[warn]
212[warn] CFStringRef CFStringCreateWithCharacters(
213[warn] Void alloc, // always pass NULL
214[warn] char[] chars,
215[warn] CFIndex numChars);
216[warn]
217[warn] public FSEventStreamRef FSEventStreamCreate(
218[warn] Pointer v, // always use Pointer.NULL
219[warn] FSEventStreamCallback callback,
220[warn] Pointer context, // always use Pointer.NULL
221[warn] CFArrayRef pathsToWatch,
222[warn] long sinceWhen, // use -1 for events since now
223[warn] double latency, // in seconds
224[warn] int flags // 0 is good for now
225[warn] );
226[warn]
227[warn] boolean FSEventStreamStart(FSEventStreamRef streamRef);
228[warn]
229[warn] void FSEventStreamStop(FSEventStreamRef streamRef);
230[warn]
231[warn] void FSEventStreamScheduleWithRunLoop(
232[warn] FSEventStreamRef streamRef, CFRunLoopRef runLoop, CFStringRef runLoopMode);
233[warn]
234[warn] void FSEventStreamUnscheduleFromRunLoop(
235[warn] FSEventStreamRef streamRef, CFRunLoopRef runLoop, CFStringRef runLoopMode);
236[warn]
237[warn] void FSEventStreamInvalidate(FSEventStreamRef streamRef);
238[warn]
239[warn] void FSEventStreamRelease(FSEventStreamRef streamRef);
240[warn]
241[warn] CFRunLoopRef CFRunLoopGetCurrent();
242[warn]
243[warn] void CFRunLoopRun();
244[warn]
245[warn] void CFRunLoopStop(CFRunLoopRef runLoopRef);
246[warn]
247[warn] public interface FSEventStreamCallback extends Callback {
248[warn] @SuppressWarnings({"UnusedDeclaration"})
249[warn] void invoke(
250[warn] FSEventStreamRef streamRef,
251[warn] Pointer clientCallBackInfo,
252[warn] NativeLong numEvents,
253[warn] Pointer eventPaths,
254[warn] Pointer eventFlags,
255[warn] Pointer eventIds);
256[warn] }
257[warn] }
258[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CarbonAPI.java:64:1: no comment
259[warn] public interface FSEventStreamCallback extends Callback {
260[warn] @SuppressWarnings({"UnusedDeclaration"})
261[warn] void invoke(
262[warn] FSEventStreamRef streamRef,
263[warn] Pointer clientCallBackInfo,
264[warn] NativeLong numEvents,
265[warn] Pointer eventPaths,
266[warn] Pointer eventFlags,
267[warn] Pointer eventIds);
268[warn] }
269[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CarbonAPI.java:20:1: no comment
270[warn] CarbonAPI INSTANCE = (CarbonAPI) Native.loadLibrary("Carbon", CarbonAPI.class);
271[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CarbonAPI.java:22:1: no comment
272[warn] CFArrayRef CFArrayCreate(
273[warn] CFAllocatorRef allocator, // always set to Pointer.NULL
274[warn] Pointer[] values,
275[warn] CFIndex numValues,
276[warn] Void callBacks // always set to Pointer.NULL
277[warn] );
278[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CarbonAPI.java:58:1: no comment
279[warn] CFRunLoopRef CFRunLoopGetCurrent();
280[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CarbonAPI.java:60:1: no comment
281[warn] void CFRunLoopRun();
282[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CarbonAPI.java:62:1: no comment
283[warn] void CFRunLoopStop(CFRunLoopRef runLoopRef);
284[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CarbonAPI.java:29:1: no comment
285[warn] CFStringRef CFStringCreateWithCharacters(
286[warn] Void alloc, // always pass NULL
287[warn] char[] chars,
288[warn] CFIndex numChars);
289[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CarbonAPI.java:34:1: no comment
290[warn] public FSEventStreamRef FSEventStreamCreate(
291[warn] Pointer v, // always use Pointer.NULL
292[warn] FSEventStreamCallback callback,
293[warn] Pointer context, // always use Pointer.NULL
294[warn] CFArrayRef pathsToWatch,
295[warn] long sinceWhen, // use -1 for events since now
296[warn] double latency, // in seconds
297[warn] int flags // 0 is good for now
298[warn] );
299[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CarbonAPI.java:54:1: no comment
300[warn] void FSEventStreamInvalidate(FSEventStreamRef streamRef);
301[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CarbonAPI.java:56:1: no comment
302[warn] void FSEventStreamRelease(FSEventStreamRef streamRef);
303[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CarbonAPI.java:48:1: no comment
304[warn] void FSEventStreamScheduleWithRunLoop(
305[warn] FSEventStreamRef streamRef, CFRunLoopRef runLoop, CFStringRef runLoopMode);
306[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CarbonAPI.java:44:1: no comment
307[warn] boolean FSEventStreamStart(FSEventStreamRef streamRef);
308[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CarbonAPI.java:46:1: no comment
309[warn] void FSEventStreamStop(FSEventStreamRef streamRef);
310[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CarbonAPI.java:51:1: no comment
311[warn] void FSEventStreamUnscheduleFromRunLoop(
312[warn] FSEventStreamRef streamRef, CFRunLoopRef runLoop, CFStringRef runLoopMode);
313[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CarbonAPI.java:66:1: no comment
314[warn] @SuppressWarnings({"UnusedDeclaration"})
315[warn] void invoke(
316[warn] FSEventStreamRef streamRef,
317[warn] Pointer clientCallBackInfo,
318[warn] NativeLong numEvents,
319[warn] Pointer eventPaths,
320[warn] Pointer eventFlags,
321[warn] Pointer eventIds);
322[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CFAllocatorRef.java:18:1: no comment
323[warn] public class CFAllocatorRef extends PointerByReference {}
324[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CFArrayRef.java:18:1: no comment
325[warn] public class CFArrayRef extends PointerByReference {}
326[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CFIndex.java:18:1: no comment
327[warn] public class CFIndex extends NativeLong {
328[warn] private static final long serialVersionUID = 0;
329[warn]
330[warn] public static CFIndex valueOf(int i) {
331[warn] CFIndex idx = new CFIndex();
332[warn] idx.setValue(i);
333[warn] return idx;
334[warn] }
335[warn] }
336[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CFIndex.java:21:1: no comment
337[warn] public static CFIndex valueOf(int i) {
338[warn] CFIndex idx = new CFIndex();
339[warn] idx.setValue(i);
340[warn] return idx;
341[warn] }
342[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CFRunLoopRef.java:18:1: no comment
343[warn] public class CFRunLoopRef extends PointerByReference {}
344[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CFStringRef.java:18:1: no comment
345[warn] public class CFStringRef extends PointerByReference {
346[warn]
347[warn] public static CFStringRef toCFString(String s) {
348[warn] final char[] chars = s.toCharArray();
349[warn] int length = chars.length;
350[warn] return CarbonAPI.INSTANCE.CFStringCreateWithCharacters(null, chars, CFIndex.valueOf(length));
351[warn] }
352[warn] }
353[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CFStringRef.java:20:1: no comment
354[warn] public static CFStringRef toCFString(String s) {
355[warn] final char[] chars = s.toCharArray();
356[warn] int length = chars.length;
357[warn] return CarbonAPI.INSTANCE.CFStringCreateWithCharacters(null, chars, CFIndex.valueOf(length));
358[warn] }
359[warn] /build/repo/core/src/main/java/io/methvin/watcher/changeset/ChangeSet.java:5:1: no comment
360[warn] public interface ChangeSet {
361[warn] Set<ChangeSetEntry> created();
362[warn]
363[warn] Set<ChangeSetEntry> modified();
364[warn]
365[warn] Set<ChangeSetEntry> deleted();
366[warn] }
367[warn] /build/repo/core/src/main/java/io/methvin/watcher/changeset/ChangeSet.java:6:1: no comment
368[warn] Set<ChangeSetEntry> created();
369[warn] /build/repo/core/src/main/java/io/methvin/watcher/changeset/ChangeSet.java:10:1: no comment
370[warn] Set<ChangeSetEntry> deleted();
371[warn] /build/repo/core/src/main/java/io/methvin/watcher/changeset/ChangeSet.java:8:1: no comment
372[warn] Set<ChangeSetEntry> modified();
373[warn] /build/repo/core/src/main/java/io/methvin/watcher/changeset/ChangeSetEntry.java:7:1: no comment
374[warn] public final class ChangeSetEntry {
375[warn]
376[warn] private final Path path;
377[warn] private final boolean isDirectory;
378[warn] private final FileHash hash;
379[warn] private final Path rootPath;
380[warn]
381[warn] ChangeSetEntry(Path path, boolean isDirectory, FileHash hash, Path rootPath) {
382[warn] this.path = path;
383[warn] this.isDirectory = isDirectory;
384[warn] this.hash = hash;
385[warn] this.rootPath = rootPath;
386[warn] }
387[warn]
388[warn] public Path path() {
389[warn] return path;
390[warn] }
391[warn]
392[warn] public boolean isDirectory() {
393[warn] return isDirectory;
394[warn] }
395[warn]
396[warn] public FileHash hash() {
397[warn] return hash;
398[warn] }
399[warn]
400[warn] public Path rootPath() {
401[warn] return rootPath;
402[warn] }
403[warn]
404[warn] @Override
405[warn] public boolean equals(Object o) {
406[warn] if (this == o) {
407[warn] return true;
408[warn] }
409[warn] if (o == null || getClass() != o.getClass()) {
410[warn] return false;
411[warn] }
412[warn]
413[warn] ChangeSetEntry that = (ChangeSetEntry) o;
414[warn]
415[warn] return isDirectory == that.isDirectory
416[warn] && path.equals(that.path)
417[warn] && hash.equals(that.hash)
418[warn] && rootPath.equals(that.rootPath);
419[warn] }
420[warn]
421[warn] @Override
422[warn] public int hashCode() {
423[warn] return Objects.hash(path, isDirectory, rootPath, hash);
424[warn] }
425[warn] }
426[warn] /build/repo/core/src/main/java/io/methvin/watcher/changeset/ChangeSetEntry.java:29:1: no comment
427[warn] public FileHash hash() {
428[warn] return hash;
429[warn] }
430[warn] /build/repo/core/src/main/java/io/methvin/watcher/changeset/ChangeSetEntry.java:25:1: no comment
431[warn] public boolean isDirectory() {
432[warn] return isDirectory;
433[warn] }
434[warn] /build/repo/core/src/main/java/io/methvin/watcher/changeset/ChangeSetEntry.java:21:1: no comment
435[warn] public Path path() {
436[warn] return path;
437[warn] }
438[warn] /build/repo/core/src/main/java/io/methvin/watcher/changeset/ChangeSetEntry.java:33:1: no comment
439[warn] public Path rootPath() {
440[warn] return rootPath;
441[warn] }
442[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeListener.java:61:1: no @return
443[warn] default boolean isWatching() {
444[warn] return true;
445[warn] }
446[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeListener.java:72:1: no @param for e
447[warn] default void onException(Exception e) {
448[warn] // Ignore exceptions by default (they will be logged by the watcher)
449[warn] }
450[warn] /build/repo/core/src/main/java/io/methvin/watcher/changeset/ChangeSetListener.java:10:1: no comment
451[warn] public final class ChangeSetListener implements DirectoryChangeListener {
452[warn]
453[warn] private Map<Path, ChangeSetBuilder> changeBuilders = new HashMap<>();
454[warn]
455[warn] private final Object lock = new Object() {};
456[warn]
457[warn] @Override
458[warn] public void onEvent(DirectoryChangeEvent event) {
459[warn] Path rootPath = event.rootPath();
460[warn] Path path = event.path();
461[warn]
462[warn] synchronized (lock) {
463[warn] // Maintain a ChangeSet per rootPath
464[warn] ChangeSetBuilder builder = changeBuilders.get(rootPath);
465[warn] if (builder == null) {
466[warn] builder = new ChangeSetBuilder();
467[warn] changeBuilders.put(rootPath, builder);
468[warn] }
469[warn]
470[warn] ChangeSetEntry entry =
471[warn] new ChangeSetEntry(path, event.isDirectory(), event.hash(), event.rootPath());
472[warn]
473[warn] switch (event.eventType()) {
474[warn] case CREATE:
475[warn] builder.addCreated(entry);
476[warn] break;
477[warn] case MODIFY:
478[warn] builder.addModified(entry);
479[warn] break;
480[warn] case DELETE:
481[warn] builder.addDeleted(entry);
482[warn] break;
483[warn] case OVERFLOW:
484[warn] throw new IllegalStateException("OVERFLOW not yet handled");
485[warn] }
486[warn] }
487[warn] }
488[warn]
489[warn] public Map<Path, ChangeSet> getChangeSet() {
490[warn] Map<Path, ChangeSetBuilder> returnBuilders;
491[warn] synchronized (lock) {
492[warn] returnBuilders = changeBuilders;
493[warn] changeBuilders = new HashMap<>();
494[warn] }
495[warn] return returnBuilders.entrySet().stream()
496[warn] .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue().toChangeSet()));
497[warn] }
498[warn] }
499[warn] /build/repo/core/src/main/java/io/methvin/watcher/changeset/ChangeSetListener.java:48:1: no comment
500[warn] public Map<Path, ChangeSet> getChangeSet() {
501[warn] Map<Path, ChangeSetBuilder> returnBuilders;
502[warn] synchronized (lock) {
503[warn] returnBuilders = changeBuilders;
504[warn] changeBuilders = new HashMap<>();
505[warn] }
506[warn] return returnBuilders.entrySet().stream()
507[warn] .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue().toChangeSet()));
508[warn] }
509[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeListener.java:58:1: no comment
510[warn] void onEvent(DirectoryChangeEvent event) throws IOException;
511[warn] /build/repo/core/src/main/java/io/methvin/watcher/visitor/DefaultFileTreeVisitor.java:10:1: no comment
512[warn] public class DefaultFileTreeVisitor implements FileTreeVisitor {
513[warn] @Override
514[warn] public void recursiveVisitFiles(Path file, Callback onDirectory, Callback onFile)
515[warn] throws IOException {
516[warn] SimpleFileVisitor<Path> visitor =
517[warn] new SimpleFileVisitor<Path>() {
518[warn] @Override
519[warn] public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
520[warn] throws IOException {
521[warn] onDirectory.call(dir);
522[warn] return FileVisitResult.CONTINUE;
523[warn] }
524[warn]
525[warn] @Override
526[warn] public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
527[warn] throws IOException {
528[warn] onFile.call(file);
529[warn] return FileVisitResult.CONTINUE;
530[warn] }
531[warn]
532[warn] @Override
533[warn] public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
534[warn] onFailure(file, exc);
535[warn] return FileVisitResult.CONTINUE;
536[warn] }
537[warn]
538[warn] @Override
539[warn] public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
540[warn] if (exc != null) onFailure(dir, exc);
541[warn] return FileVisitResult.CONTINUE;
542[warn] }
543[warn] };
544[warn] Files.walkFileTree(file, visitor);
545[warn] }
546[warn]
547[warn] // To be overridden if needed
548[warn] protected void onFailure(Path path, IOException exception) throws IOException {}
549[warn] }
550[warn] /build/repo/core/src/main/java/io/methvin/watcher/visitor/DefaultFileTreeVisitor.java:46:1: no comment
551[warn] protected void onFailure(Path path, IOException exception) throws IOException {}
552[warn] /build/repo/core/src/main/java/io/methvin/watcher/visitor/FileTreeVisitor.java:16:1: no comment
553[warn] void recursiveVisitFiles(Path file, Callback onDirectory, Callback onFile) throws IOException;
554[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeEvent.java:22:1: no comment
555[warn] public final class DirectoryChangeEvent {
556[warn] public enum EventType {
557[warn]
558[warn] /* A new file was created */
559[warn] CREATE(StandardWatchEventKinds.ENTRY_CREATE),
560[warn]
561[warn] /* An existing file was modified */
562[warn] MODIFY(StandardWatchEventKinds.ENTRY_MODIFY),
563[warn]
564[warn] /* A file was deleted */
565[warn] DELETE(StandardWatchEventKinds.ENTRY_DELETE),
566[warn]
567[warn] /* An overflow occurred; some events were lost */
568[warn] OVERFLOW(StandardWatchEventKinds.OVERFLOW);
569[warn]
570[warn] private WatchEvent.Kind<?> kind;
571[warn]
572[warn] EventType(WatchEvent.Kind<?> kind) {
573[warn] this.kind = kind;
574[warn] }
575[warn]
576[warn] public WatchEvent.Kind<?> getWatchEventKind() {
577[warn] return kind;
578[warn] }
579[warn] }
580[warn]
581[warn] private final EventType eventType;
582[warn] private final boolean isDirectory;
583[warn] private final Path path;
584[warn] private final FileHash hash;
585[warn] private final int count;
586[warn] private final Path rootPath;
587[warn]
588[warn] public DirectoryChangeEvent(
589[warn] EventType eventType,
590[warn] boolean isDirectory,
591[warn] Path path,
592[warn] FileHash hash,
593[warn] int count,
594[warn] Path rootPath) {
595[warn] this.eventType = eventType;
596[warn] this.isDirectory = isDirectory;
597[warn] this.hash = hash;
598[warn] this.path = path;
599[warn] this.count = count;
600[warn] this.rootPath = rootPath;
601[warn] }
602[warn]
603[warn] public EventType eventType() {
604[warn] return eventType;
605[warn] }
606[warn]
607[warn] public Path path() {
608[warn] return path;
609[warn] }
610[warn]
611[warn] public int count() {
612[warn] return count;
613[warn] }
614[warn]
615[warn] public Path rootPath() {
616[warn] return rootPath;
617[warn] }
618[warn]
619[warn] public boolean isDirectory() {
620[warn] return isDirectory;
621[warn] }
622[warn]
623[warn] public FileHash hash() {
624[warn] return hash;
625[warn] }
626[warn]
627[warn] @Override
628[warn] public boolean equals(Object o) {
629[warn] if (this == o) {
630[warn] return true;
631[warn] }
632[warn] if (o == null || getClass() != o.getClass()) {
633[warn] return false;
634[warn] }
635[warn]
636[warn] DirectoryChangeEvent that = (DirectoryChangeEvent) o;
637[warn]
638[warn] return count == that.count
639[warn] && eventType == that.eventType
640[warn] && isDirectory == that.isDirectory
641[warn] && Objects.equals(path, that.path)
642[warn] && Objects.equals(rootPath, that.rootPath)
643[warn] && Objects.equals(hash, that.hash);
644[warn] }
645[warn]
646[warn] @Override
647[warn] public int hashCode() {
648[warn] return Objects.hash(eventType, isDirectory, path, count, rootPath, hash);
649[warn] }
650[warn]
651[warn] @Override
652[warn] public String toString() {
653[warn] return "DirectoryChangeEvent{"
654[warn] + "eventType="
655[warn] + eventType
656[warn] + ", isDirectory="
657[warn] + isDirectory
658[warn] + ", path="
659[warn] + path
660[warn] + ", count="
661[warn] + count
662[warn] + ", rootPath="
663[warn] + rootPath
664[warn] + ", hash="
665[warn] + ((hash == null) ? "(null)" : hash) // don't want the printout to be too long
666[warn] + '}';
667[warn] }
668[warn] }
669[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeEvent.java:23:1: no comment
670[warn] public enum EventType {
671[warn]
672[warn] /* A new file was created */
673[warn] CREATE(StandardWatchEventKinds.ENTRY_CREATE),
674[warn]
675[warn] /* An existing file was modified */
676[warn] MODIFY(StandardWatchEventKinds.ENTRY_MODIFY),
677[warn]
678[warn] /* A file was deleted */
679[warn] DELETE(StandardWatchEventKinds.ENTRY_DELETE),
680[warn]
681[warn] /* An overflow occurred; some events were lost */
682[warn] OVERFLOW(StandardWatchEventKinds.OVERFLOW);
683[warn]
684[warn] private WatchEvent.Kind<?> kind;
685[warn]
686[warn] EventType(WatchEvent.Kind<?> kind) {
687[warn] this.kind = kind;
688[warn] }
689[warn]
690[warn] public WatchEvent.Kind<?> getWatchEventKind() {
691[warn] return kind;
692[warn] }
693[warn] }
694[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeEvent.java:55:1: no comment
695[warn] public DirectoryChangeEvent(
696[warn] EventType eventType,
697[warn] boolean isDirectory,
698[warn] Path path,
699[warn] FileHash hash,
700[warn] int count,
701[warn] Path rootPath) {
702[warn] this.eventType = eventType;
703[warn] this.isDirectory = isDirectory;
704[warn] this.hash = hash;
705[warn] this.path = path;
706[warn] this.count = count;
707[warn] this.rootPath = rootPath;
708[warn] }
709[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeEvent.java:78:1: no comment
710[warn] public int count() {
711[warn] return count;
712[warn] }
713[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeEvent.java:70:1: no comment
714[warn] public EventType eventType() {
715[warn] return eventType;
716[warn] }
717[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeEvent.java:90:1: no comment
718[warn] public FileHash hash() {
719[warn] return hash;
720[warn] }
721[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeEvent.java:86:1: no comment
722[warn] public boolean isDirectory() {
723[warn] return isDirectory;
724[warn] }
725[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeEvent.java:74:1: no comment
726[warn] public Path path() {
727[warn] return path;
728[warn] }
729[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeEvent.java:82:1: no comment
730[warn] public Path rootPath() {
731[warn] return rootPath;
732[warn] }
733[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeEvent.java:43:1: no comment
734[warn] public WatchEvent.Kind<?> getWatchEventKind() {
735[warn] return kind;
736[warn] }
737[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeEvent.java:26:1: no comment
738[warn] CREATE(StandardWatchEventKinds.ENTRY_CREATE)
739[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeEvent.java:32:1: no comment
740[warn] DELETE(StandardWatchEventKinds.ENTRY_DELETE)
741[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeEvent.java:29:1: no comment
742[warn] MODIFY(StandardWatchEventKinds.ENTRY_MODIFY)
743[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeEvent.java:35:1: no comment
744[warn] OVERFLOW(StandardWatchEventKinds.OVERFLOW)
745[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeListener.java:24:1: no comment
746[warn] static DirectoryChangeListener of(DirectoryChangeListener... listeners) {
747[warn] return new DirectoryChangeListener() {
748[warn] @Override
749[warn] public void onEvent(DirectoryChangeEvent event) throws IOException {
750[warn] for (DirectoryChangeListener listener : listeners) {
751[warn] listener.onEvent(event);
752[warn] }
753[warn] }
754[warn]
755[warn] @Override
756[warn] public void onException(Exception e) {
757[warn] for (DirectoryChangeListener listener : listeners) {
758[warn] listener.onException(e);
759[warn] }
760[warn] }
761[warn]
762[warn] @Override
763[warn] public void onIdle(int count) {
764[warn] for (DirectoryChangeListener listener : listeners) {
765[warn] listener.onIdle(count);
766[warn] }
767[warn] }
768[warn]
769[warn] @Override
770[warn] public boolean isWatching() {
771[warn] boolean anyWatching = false;
772[warn] for (DirectoryChangeListener listener : listeners) {
773[warn] anyWatching |= listener.isWatching();
774[warn] }
775[warn] return anyWatching;
776[warn] }
777[warn] };
778[warn] }
779[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeListener.java:65:1: no comment
780[warn] default void onIdle(int count) {
781[warn] // ignore onIdle by default
782[warn] }
783[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:172:1: no @return
784[warn] public static Builder builder() {
785[warn] return new Builder();
786[warn] }
787[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:214:1: no @return
788[warn] public CompletableFuture<Void> watchAsync() {
789[warn] return watchAsync(ForkJoinPool.commonPool());
790[warn] }
791[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:227:1: no @return
792[warn] public CompletableFuture<Void> watchAsync(Executor executor) {
793[warn] try {
794[warn] registerPaths();
795[warn] return CompletableFuture.supplyAsync(
796[warn] () -> {
797[warn] runEventLoop();
798[warn] return null;
799[warn] },
800[warn] executor);
801[warn] } catch (Throwable t) {
802[warn] CompletableFuture<Void> f = new CompletableFuture<>();
803[warn] f.completeExceptionally(t);
804[warn] return f;
805[warn] }
806[warn] }
807[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:46:1: no comment
808[warn] public class DirectoryWatcher {
809[warn]
810[warn] /**
811[warn] * A builder for a {@link DirectoryWatcher}. Use {@code DirectoryWatcher.builder()} to get a new
812[warn] * instance.
813[warn] */
814[warn] public static final class Builder {
815[warn] private List<Path> paths = Collections.emptyList();
816[warn] private DirectoryChangeListener listener = (event -> {});
817[warn] private Logger logger = null;
818[warn] private FileHasher fileHasher = FileHasher.DEFAULT_FILE_HASHER;
819[warn] private WatchService watchService = null;
820[warn] private FileTreeVisitor fileTreeVisitor = null;
821[warn]
822[warn] private Builder() {}
823[warn]
824[warn] /** Set multiple paths to watch. */
825[warn] public Builder paths(List<Path> paths) {
826[warn] this.paths = paths;
827[warn] return this;
828[warn] }
829[warn]
830[warn] /** Set a single path to watch. */
831[warn] public Builder path(Path path) {
832[warn] return paths(Collections.singletonList(path));
833[warn] }
834[warn]
835[warn] /** Set a listener that will be called when a directory change event occurs. */
836[warn] public Builder listener(DirectoryChangeListener listener) {
837[warn] this.listener = listener;
838[warn] return this;
839[warn] }
840[warn]
841[warn] /**
842[warn] * Set a {@link WatchService} implementation that will be used by the watcher.
843[warn] *
844[warn] * <p>By default, this detects your OS and either uses the native JVM watcher or the macOS
845[warn] * watcher.
846[warn] */
847[warn] public Builder watchService(WatchService watchService) {
848[warn] this.watchService = watchService;
849[warn] return this;
850[warn] }
851[warn]
852[warn] /**
853[warn] * Set a logger to be used by the watcher. This defaults to {@code
854[warn] * LoggerFactory.getLogger(DirectoryWatcher.class)}
855[warn] */
856[warn] public Builder logger(Logger logger) {
857[warn] this.logger = logger;
858[warn] return this;
859[warn] }
860[warn]
861[warn] /**
862[warn] * Defines whether file hashing should be used to catch duplicate events. Defaults to {@code
863[warn] * true}.
864[warn] */
865[warn] public Builder fileHashing(boolean enabled) {
866[warn] this.fileHasher = enabled ? FileHasher.DEFAULT_FILE_HASHER : null;
867[warn] return this;
868[warn] }
869[warn]
870[warn] /**
871[warn] * Defines the file hasher to be used by the watcher.
872[warn] *
873[warn] * <p>Note: will implicitly enable file hashing. Setting to null is equivalent to {@code
874[warn] * fileHashing(false)}
875[warn] */
876[warn] public Builder fileHasher(FileHasher fileHasher) {
877[warn] this.fileHasher = fileHasher;
878[warn] return this;
879[warn] }
880[warn]
881[warn] /** Defines the file tree visitor to be used by the watcher. */
882[warn] public Builder fileTreeVisitor(FileTreeVisitor fileTreeVisitor) {
883[warn] this.fileTreeVisitor = fileTreeVisitor;
884[warn] return this;
885[warn] }
886[warn]
887[warn] public DirectoryWatcher build() throws IOException {
888[warn] if (fileTreeVisitor == null) {
889[warn] fileTreeVisitor = FileTreeVisitor.DEFAULT_FILE_TREE_VISITOR;
890[warn] }
891[warn] if (watchService == null) {
892[warn] osDefaultWatchService(fileTreeVisitor);
893[warn] }
894[warn] if (logger == null) {
895[warn] staticLogger();
896[warn] }
897[warn] return new DirectoryWatcher(
898[warn] paths, listener, watchService, fileHasher, fileTreeVisitor, logger);
899[warn] }
900[warn]
901[warn] private Builder osDefaultWatchService(FileTreeVisitor fileTreeVisitor) throws IOException {
902[warn] boolean isMac = System.getProperty("os.name").toLowerCase().contains("mac");
903[warn] if (isMac) {
904[warn] return watchService(
905[warn] new MacOSXListeningWatchService(
906[warn] new MacOSXListeningWatchService.Config() {
907[warn] @Override
908[warn] public FileHasher fileHasher() {
909[warn] /**
910[warn] * Always return null here. When MacOSXListeningWatchService is used with
911[warn] * DirectoryWatcher, then the hashing should happen within DirectoryWatcher. If
912[warn] * users wish to override this then they must instantiate
913[warn] * MacOSXListeningWatchService and pass it to DirectoryWatcher.
914[warn] */
915[warn] return null;
916[warn] }
917[warn]
918[warn] @Override
919[warn] public FileTreeVisitor fileTreeVisitor() {
920[warn] return fileTreeVisitor;
921[warn] }
922[warn] }));
923[warn] } else {
924[warn] return watchService(FileSystems.getDefault().newWatchService());
925[warn] }
926[warn] }
927[warn]
928[warn] private Builder staticLogger() {
929[warn] return logger(LoggerFactory.getLogger(DirectoryWatcher.class));
930[warn] }
931[warn] }
932[warn]
933[warn] /** Get a new builder for a {@link DirectoryWatcher}. */
934[warn] public static Builder builder() {
935[warn] return new Builder();
936[warn] }
937[warn]
938[warn] private final Logger logger;
939[warn] private final WatchService watchService;
940[warn] private final List<Path> paths;
941[warn] private final boolean isMac;
942[warn] private final DirectoryChangeListener listener;
943[warn] private final FileHasher fileHasher;
944[warn] private final FileTreeVisitor fileTreeVisitor;
945[warn]
946[warn] private final Map<Path, Path> registeredPathToRootPath = new HashMap<>();;
947[warn] private final SortedMap<Path, FileHash> pathHashes = new ConcurrentSkipListMap<>();
948[warn] private final Set<Path> directories =
949[warn] Collections.newSetFromMap(new ConcurrentHashMap<Path, Boolean>());
950[warn] private final Map<WatchKey, Path> keyRoots = new ConcurrentHashMap<>();
951[warn]
952[warn] private volatile boolean closed = false;
953[warn]
954[warn] // set to null until we check if FILE_TREE is supported
955[warn] private Boolean fileTreeSupported = null;
956[warn]
957[warn] public DirectoryWatcher(
958[warn] List<Path> paths,
959[warn] DirectoryChangeListener listener,
960[warn] WatchService watchService,
961[warn] FileHasher fileHasher,
962[warn] FileTreeVisitor fileTreeVisitor,
963[warn] Logger logger) {
964[warn] this.paths = paths.stream().map(p -> p.toAbsolutePath()).collect(Collectors.toList());
965[warn] this.listener = listener;
966[warn] this.watchService = watchService;
967[warn] this.isMac = watchService instanceof MacOSXListeningWatchService;
968[warn] this.fileHasher = fileHasher;
969[warn] this.fileTreeVisitor = fileTreeVisitor;
970[warn] this.logger = logger;
971[warn] }
972[warn]
973[warn] /**
974[warn] * Asynchronously watch the directories using {@code ForkJoinPool.commonPool()} as the executor
975[warn] */
976[warn] public CompletableFuture<Void> watchAsync() {
977[warn] return watchAsync(ForkJoinPool.commonPool());
978[warn] }
979[warn]
980[warn] /**
981[warn] * Start watching for changes asynchronously.
982[warn] *
983[warn] * <p>The future completes when the listener stops listening or the watcher is closed.
984[warn] *
985[warn] * <p>This method will block until the watcher is initialized and successfully watching.
986[warn] *
987[warn] * @param executor the executor to use to watch asynchronously
988[warn] */
989[warn] public CompletableFuture<Void> watchAsync(Executor executor) {
990[warn] try {
991[warn] registerPaths();
992[warn] return CompletableFuture.supplyAsync(
993[warn] () -> {
994[warn] runEventLoop();
995[warn] return null;
996[warn] },
997[warn] executor);
998[warn] } catch (Throwable t) {
999[warn] CompletableFuture<Void> f = new CompletableFuture<>();
1000[warn] f.completeExceptionally(t);
1001[warn] return f;
1002[warn] }
1003[warn] }
1004[warn]
1005[warn] /**
1006[warn] * Watch for changes; block until the listener stops listening or the watcher is closed.
1007[warn] *
1008[warn] * @throws IllegalStateException if the directory watcher is closed when watch() is called.
1009[warn] */
1010[warn] public void watch() {
1011[warn] registerPaths();
1012[warn] runEventLoop();
1013[warn] }
1014[warn]
1015[warn] public Map<Path, FileHash> pathHashes() {
1016[warn] return Collections.unmodifiableMap(pathHashes);
1017[warn] }
1018[warn]
1019[warn] public DirectoryChangeListener getListener() {
1020[warn] return listener;
1021[warn] }
1022[warn]
1023[warn] public void close() throws IOException {
1024[warn] watchService.close();
1025[warn] closed = true;
1026[warn] }
1027[warn]
1028[warn] public boolean isClosed() {
1029[warn] return closed;
1030[warn] }
1031[warn]
1032[warn] private boolean isFileTreeSupported() {
1033[warn] if (fileTreeSupported == null) {
1034[warn] throw new IllegalStateException("fileTreeSupported not initialized");
1035[warn] }
1036[warn] return fileTreeSupported;
1037[warn] }
1038[warn]
1039[warn] private void registerPaths() {
1040[warn] try {
1041[warn] PathUtils.initWatcherState(paths, fileHasher, fileTreeVisitor, pathHashes, directories);
1042[warn]
1043[warn] for (Path path : paths) {
1044[warn] registerAll(path, path);
1045[warn] }
1046[warn] } catch (IOException e) {
1047[warn] throw new UncheckedIOException(e);
1048[warn] }
1049[warn] }
1050[warn]
1051[warn] private void runEventLoop() {
1052[warn] if (closed) {
1053[warn] throw new IllegalStateException("watcher already closed");
1054[warn] }
1055[warn] int eventCount = 0;
1056[warn] while (listener.isWatching()) {
1057[warn] // wait for key to be signalled
1058[warn] WatchKey key;
1059[warn] try {
1060[warn] key = watchService.poll();
1061[warn] if (key == null) {
1062[warn] listener.onIdle(eventCount);
1063[warn] key = watchService.take();
1064[warn] }
1065[warn] } catch (InterruptedException | ClosedWatchServiceException e) {
1066[warn] return;
1067[warn] }
1068[warn] for (WatchEvent<?> event : key.pollEvents()) {
1069[warn] eventCount++;
1070[warn] try {
1071[warn] WatchEvent.Kind<?> kind = event.kind();
1072[warn] // Context for directory entry event is the file name of entry
1073[warn] WatchEvent<Path> ev = PathUtils.cast(event);
1074[warn] int count = ev.count();
1075[warn] Path eventPath = ev.context();
1076[warn] if (!keyRoots.containsKey(key)) {
1077[warn] throw new IllegalStateException(
1078[warn] "WatchService returned key [" + key + "] but it was not found in keyRoots!");
1079[warn] }
1080[warn] Path registeredPath = keyRoots.get(key);
1081[warn] Path rootPath = registeredPathToRootPath.get(registeredPath);
1082[warn] Path childPath = eventPath == null ? null : keyRoots.get(key).resolve(eventPath);
1083[warn] logger.debug("{} [{}]", kind, childPath);
1084[warn] /*
1085[warn] * If a directory is created, and we're watching recursively, then register it
1086[warn] * and its sub-directories.
1087[warn] */
1088[warn] if (kind == OVERFLOW) {
1089[warn] onEvent(EventType.OVERFLOW, false, childPath, count, rootPath);
1090[warn] } else if (eventPath == null) {
1091[warn] throw new IllegalStateException("WatchService returned a null path for " + kind.name());
1092[warn] } else if (kind == ENTRY_CREATE) {
1093[warn] boolean isDirectory = Files.isDirectory(childPath, NOFOLLOW_LINKS);
1094[warn] if (isDirectory) {
1095[warn] if (!isFileTreeSupported()) {
1096[warn] registerAll(childPath, rootPath);
1097[warn] }
1098[warn] /*
1099[warn] * Our custom Mac service sends subdirectory changes but the Windows/Linux do
1100[warn] * not. Walk the file tree to make sure we send create events for any files that
1101[warn] * were created.
1102[warn] */
1103[warn] if (!isMac) {
1104[warn] fileTreeVisitor.recursiveVisitFiles(
1105[warn] childPath,
1106[warn] dir -> notifyCreateEvent(true, dir, count, rootPath),
1107[warn] file -> notifyCreateEvent(false, file, count, rootPath));
1108[warn] } else {
1109[warn] notifyCreateEvent(true, childPath, count, rootPath);
1110[warn] }
1111[warn] } else {
1112[warn] notifyCreateEvent(false, childPath, count, rootPath);
1113[warn] }
1114[warn] } else if (kind == ENTRY_MODIFY) {
1115[warn] boolean isDirectory = directories.contains(childPath);
1116[warn]
1117[warn] if (fileHasher == null) {
1118[warn] onEvent(EventType.MODIFY, isDirectory, childPath, count, rootPath);
1119[warn] } else {
1120[warn] /*
1121[warn] * Note that existingHash may be null due to the file being created before we
1122[warn] * start listening It's important we don't discard the event in this case
1123[warn] */
1124[warn] FileHash existingHash = pathHashes.get(childPath);
1125[warn]
1126[warn] /*
1127[warn] * newHash can be null when using File#delete() on windows - it generates MODIFY
1128[warn] * and DELETE in succession. In this case the MODIFY event can be safely ignored
1129[warn] */
1130[warn] FileHash newHash = PathUtils.hash(fileHasher, childPath);
1131[warn]
1132[warn] if (newHash != null && !newHash.equals(existingHash)) {
1133[warn] pathHashes.put(childPath, newHash);
1134[warn] onEvent(EventType.MODIFY, isDirectory, childPath, count, rootPath);
1135[warn] } else if (newHash == null) {
1136[warn] logger.debug(
1137[warn] "Failed to hash modified file [{}]. It may have been deleted.", childPath);
1138[warn] }
1139[warn] }
1140[warn] } else if (kind == ENTRY_DELETE) {
1141[warn] if (fileHasher == null) {
1142[warn] boolean isDirectory = directories.remove(childPath);
1143[warn] // hashing is disabled, so just notify on the path we got the event for
1144[warn] onEvent(EventType.DELETE, isDirectory, childPath, count, rootPath);
1145[warn] } else {
1146[warn] // hashing is enabled, so delete the hashes
1147[warn] for (Path path : PathUtils.subtreePaths(pathHashes, childPath)) {
1148[warn] boolean isDirectory = directories.remove(path);
1149[warn] pathHashes.remove(path);
1150[warn] onEvent(EventType.DELETE, isDirectory, path, count, rootPath);
1151[warn] }
1152[warn] }
1153[warn] }
1154[warn] } catch (Exception e) {
1155[warn] logger.debug("DirectoryWatcher got an exception while watching!", e);
1156[warn] listener.onException(e);
1157[warn] }
1158[warn] }
1159[warn] boolean valid = key.reset();
1160[warn] if (!valid) {
1161[warn] logger.debug("WatchKey for [{}] no longer valid; removing.", key.watchable());
1162[warn] // remove the key from the keyRoots
1163[warn] Path registeredPath = keyRoots.remove(key);
1164[warn]
1165[warn] // Also remove from the registeredPathToRootPath maps
1166[warn] registeredPathToRootPath.remove(registeredPath);
1167[warn]
1168[warn] // if there are no more keys left to watch, we can break out
1169[warn] if (keyRoots.isEmpty()) {
1170[warn] logger.debug("No more directories left to watch; terminating watcher.");
1171[warn] break;
1172[warn] }
1173[warn] }
1174[warn] }
1175[warn] try {
1176[warn] close();
1177[warn] } catch (IOException e) {
1178[warn] throw new UncheckedIOException(e);
1179[warn] }
1180[warn] }
1181[warn]
1182[warn] private void onEvent(
1183[warn] EventType eventType, boolean isDirectory, Path childPath, int count, Path rootPath)
1184[warn] throws IOException {
1185[warn] logger.debug("-> {} [{}] (isDirectory: {})", eventType, childPath, isDirectory);
1186[warn] FileHash hash = pathHashes.get(childPath);
1187[warn] listener.onEvent(
1188[warn] new DirectoryChangeEvent(eventType, isDirectory, childPath, hash, count, rootPath));
1189[warn] }
1190[warn]
1191[warn] private void registerAll(final Path start, final Path context) throws IOException {
1192[warn] if (!Boolean.FALSE.equals(fileTreeSupported)) {
1193[warn] // Try using FILE_TREE modifier since we aren't certain that it's unsupported
1194[warn] try {
1195[warn] register(start, true, context);
1196[warn] // Assume FILE_TREE is supported
1197[warn] fileTreeSupported = true;
1198[warn] } catch (UnsupportedOperationException e) {
1199[warn] // UnsupportedOperationException should only happen if FILE_TREE is unsupported
1200[warn] logger.debug("Assuming ExtendedWatchEventModifier.FILE_TREE is not supported", e);
1201[warn] fileTreeSupported = false;
1202[warn] // If we failed to use the FILE_TREE modifier, try again without
1203[warn] registerAll(start, context);
1204[warn] }
1205[warn] } else {
1206[warn] // Since FILE_TREE is unsupported, register root directory and sub-directories
1207[warn] fileTreeVisitor.recursiveVisitFiles(start, dir -> register(dir, false, context), file -> {});
1208[warn] }
1209[warn] }
1210[warn]
1211[warn] // Internal method to be used by registerAll
1212[warn] private void register(Path directory, boolean useFileTreeModifier, Path context)
1213[warn] throws IOException {
1214[warn] logger.debug("Registering [{}].", directory);
1215[warn] Watchable watchable = isMac ? new WatchablePath(directory) : directory;
1216[warn] WatchEvent.Modifier[] modifiers =
1217[warn] useFileTreeModifier
1218[warn] ? new WatchEvent.Modifier[] {ExtendedWatchEventModifier.FILE_TREE}
1219[warn] : new WatchEvent.Modifier[] {};
1220[warn] WatchEvent.Kind<?>[] kinds =
1221[warn] new WatchEvent.Kind<?>[] {ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY};
1222[warn] WatchKey watchKey = watchable.register(watchService, kinds, modifiers);
1223[warn] keyRoots.put(watchKey, directory);
1224[warn] registeredPathToRootPath.put(directory, context);
1225[warn] }
1226[warn]
1227[warn] private void notifyCreateEvent(boolean isDirectory, Path path, int count, Path rootPath)
1228[warn] throws IOException {
1229[warn] if (fileHasher != null) {
1230[warn] FileHash newHash = PathUtils.hash(fileHasher, path);
1231[warn] if (newHash == null) {
1232[warn] // Hashing could fail for locked files on Windows.
1233[warn] // Skip notification only if we confirm the file does not exist.
1234[warn] if (Files.notExists(path)) {
1235[warn] logger.debug("Failed to hash created file [{}]. It may have been deleted.", path);
1236[warn] // Skip notifying the event.
1237[warn] return;
1238[warn] } else {
1239[warn] // Just warn here and continue to notify the event.
1240[warn] logger.debug("Failed to hash created file [{}]. It may be locked.", path);
1241[warn] }
1242[warn] } else {
1243[warn] FileHash oldHash = pathHashes.put(path, newHash);
1244[warn] if (oldHash != null) {
1245[warn] if (oldHash == newHash) {
1246[warn] // Creates might occur just before we traverse and notify for files in a new directory.
1247[warn] // We generally want to skip the duplicate if the hash has not changed.
1248[warn] logger.debug("Skipping duplicate create event for file [{}].", path);
1249[warn] return;
1250[warn] } else {
1251[warn] // This might happen if events were discarded and perhaps we missed a DELETE event.
1252[warn] logger.debug("Sending MODIFY instead of CREATE for existing hashed file [{}].", path);
1253[warn] onEvent(EventType.MODIFY, isDirectory, path, count, rootPath);
1254[warn] return;
1255[warn] }
1256[warn] }
1257[warn] }
1258[warn] }
1259[warn] if (isDirectory) {
1260[warn] directories.add(path);
1261[warn] }
1262[warn] onEvent(EventType.CREATE, isDirectory, path, count, rootPath);
1263[warn] }
1264[warn] }
1265[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:195:1: no comment
1266[warn] public DirectoryWatcher(
1267[warn] List<Path> paths,
1268[warn] DirectoryChangeListener listener,
1269[warn] WatchService watchService,
1270[warn] FileHasher fileHasher,
1271[warn] FileTreeVisitor fileTreeVisitor,
1272[warn] Logger logger) {
1273[warn] this.paths = paths.stream().map(p -> p.toAbsolutePath()).collect(Collectors.toList());
1274[warn] this.listener = listener;
1275[warn] this.watchService = watchService;
1276[warn] this.isMac = watchService instanceof MacOSXListeningWatchService;
1277[warn] this.fileHasher = fileHasher;
1278[warn] this.fileTreeVisitor = fileTreeVisitor;
1279[warn] this.logger = logger;
1280[warn] }
1281[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:261:1: no comment
1282[warn] public void close() throws IOException {
1283[warn] watchService.close();
1284[warn] closed = true;
1285[warn] }
1286[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:257:1: no comment
1287[warn] public DirectoryChangeListener getListener() {
1288[warn] return listener;
1289[warn] }
1290[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:266:1: no comment
1291[warn] public boolean isClosed() {
1292[warn] return closed;
1293[warn] }
1294[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:253:1: no comment
1295[warn] public Map<Path, FileHash> pathHashes() {
1296[warn] return Collections.unmodifiableMap(pathHashes);
1297[warn] }
1298[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:63:1: no @param for paths
1299[warn] public Builder paths(List<Path> paths) {
1300[warn] this.paths = paths;
1301[warn] return this;
1302[warn] }
1303[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:69:1: no @param for path
1304[warn] public Builder path(Path path) {
1305[warn] return paths(Collections.singletonList(path));
1306[warn] }
1307[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:74:1: no @param for listener
1308[warn] public Builder listener(DirectoryChangeListener listener) {
1309[warn] this.listener = listener;
1310[warn] return this;
1311[warn] }
1312[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:85:1: no @param for watchService
1313[warn] public Builder watchService(WatchService watchService) {
1314[warn] this.watchService = watchService;
1315[warn] return this;
1316[warn] }
1317[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:94:1: no @param for logger
1318[warn] public Builder logger(Logger logger) {
1319[warn] this.logger = logger;
1320[warn] return this;
1321[warn] }
1322[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:103:1: no @param for enabled
1323[warn] public Builder fileHashing(boolean enabled) {
1324[warn] this.fileHasher = enabled ? FileHasher.DEFAULT_FILE_HASHER : null;
1325[warn] return this;
1326[warn] }
1327[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:114:1: no @param for fileHasher
1328[warn] public Builder fileHasher(FileHasher fileHasher) {
1329[warn] this.fileHasher = fileHasher;
1330[warn] return this;
1331[warn] }
1332[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:120:1: no @param for fileTreeVisitor
1333[warn] public Builder fileTreeVisitor(FileTreeVisitor fileTreeVisitor) {
1334[warn] this.fileTreeVisitor = fileTreeVisitor;
1335[warn] return this;
1336[warn] }
1337[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:125:1: no comment
1338[warn] public DirectoryWatcher build() throws IOException {
1339[warn] if (fileTreeVisitor == null) {
1340[warn] fileTreeVisitor = FileTreeVisitor.DEFAULT_FILE_TREE_VISITOR;
1341[warn] }
1342[warn] if (watchService == null) {
1343[warn] osDefaultWatchService(fileTreeVisitor);
1344[warn] }
1345[warn] if (logger == null) {
1346[warn] staticLogger();
1347[warn] }
1348[warn] return new DirectoryWatcher(
1349[warn] paths, listener, watchService, fileHasher, fileTreeVisitor, logger);
1350[warn] }
1351[warn] /build/repo/core/src/main/java/io/methvin/watcher/hashing/FileHash.java:40:1: no comment
1352[warn] public static FileHash directory() {
1353[warn] return DIRECTORY;
1354[warn] }
1355[warn] /build/repo/core/src/main/java/io/methvin/watcher/hashing/FileHash.java:30:1: no comment
1356[warn] public static FileHash fromBytes(byte[] value) {
1357[warn] return new ByteArrayFileHash(Arrays.copyOf(value, value.length));
1358[warn] }
1359[warn] /build/repo/core/src/main/java/io/methvin/watcher/hashing/FileHash.java:34:1: no comment
1360[warn] public static FileHash fromLong(long value) {
1361[warn] ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
1362[warn] buffer.putLong(value);
1363[warn] return new ByteArrayFileHash(buffer.array());
1364[warn] }
1365[warn] /build/repo/core/src/main/java/io/methvin/watcher/hashing/FileHasher.java:63:1: no comment
1366[warn] FileHash hash(Path path) throws IOException;
1367[warn] /build/repo/core/src/main/java/io/methvin/watcher/visitor/FileTreeVisitor.java:7:1: no comment
1368[warn] public interface FileTreeVisitor {
1369[warn]
1370[warn] /** The default file tree visitor instance, which uses Files.walkFileTree. */
1371[warn] FileTreeVisitor DEFAULT_FILE_TREE_VISITOR = new DefaultFileTreeVisitor();
1372[warn]
1373[warn] interface Callback {
1374[warn] void call(Path p) throws IOException;
1375[warn] }
1376[warn]
1377[warn] void recursiveVisitFiles(Path file, Callback onDirectory, Callback onFile) throws IOException;
1378[warn] }
1379[warn] /build/repo/core/src/main/java/io/methvin/watcher/visitor/FileTreeVisitor.java:12:1: no comment
1380[warn] interface Callback {
1381[warn] void call(Path p) throws IOException;
1382[warn] }
1383[warn] /build/repo/core/src/main/java/io/methvin/watcher/visitor/FileTreeVisitor.java:13:1: no comment
1384[warn] void call(Path p) throws IOException;
1385[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/FSEventStreamRef.java:18:1: no comment
1386[warn] public class FSEventStreamRef extends PointerByReference {}
1387[warn] /build/repo/core/src/main/java/io/methvin/watchservice/MacOSXListeningWatchService.java:172:1: no comment
1388[warn] public static class CFRunLoopThread extends Thread {
1389[warn] private final FSEventStreamRef streamRef;
1390[warn] private CFRunLoopRef runLoopRef;
1391[warn] private boolean isClosed = false;
1392[warn]
1393[warn] public CFRunLoopThread(FSEventStreamRef streamRef, File file) {
1394[warn] super("WatchService for " + file);
1395[warn] this.streamRef = streamRef;
1396[warn] }
1397[warn]
1398[warn] @Override
1399[warn] public void run() {
1400[warn] synchronized (streamRef) {
1401[warn] if (isClosed) return;
1402[warn] runLoopRef = CarbonAPI.INSTANCE.CFRunLoopGetCurrent();
1403[warn] final CFStringRef runLoopMode = CFStringRef.toCFString("kCFRunLoopDefaultMode");
1404[warn] CarbonAPI.INSTANCE.FSEventStreamScheduleWithRunLoop(streamRef, runLoopRef, runLoopMode);
1405[warn] CarbonAPI.INSTANCE.FSEventStreamStart(streamRef);
1406[warn] }
1407[warn] CarbonAPI.INSTANCE.CFRunLoopRun();
1408[warn] }
1409[warn]
1410[warn] public void close() {
1411[warn] synchronized (streamRef) {
1412[warn] if (isClosed) return;
1413[warn] if (runLoopRef != null) {
1414[warn] CarbonAPI.INSTANCE.CFRunLoopStop(runLoopRef);
1415[warn] CarbonAPI.INSTANCE.FSEventStreamStop(streamRef);
1416[warn] CarbonAPI.INSTANCE.FSEventStreamInvalidate(streamRef);
1417[warn] }
1418[warn] CarbonAPI.INSTANCE.FSEventStreamRelease(streamRef);
1419[warn] isClosed = true;
1420[warn] }
1421[warn] }
1422[warn] }
1423[warn] /build/repo/core/src/main/java/io/methvin/watchservice/MacOSXListeningWatchService.java:118:1: no comment
1424[warn] public MacOSXListeningWatchService() {
1425[warn] this(new Config() {});
1426[warn] }
1427[warn] /build/repo/core/src/main/java/io/methvin/watchservice/MacOSXListeningWatchService.java:109:1: no comment
1428[warn] public MacOSXListeningWatchService(Config config) {
1429[warn] this.latency = config.latency();
1430[warn] this.queueSize = config.queueSize();
1431[warn] this.fileTreeVisitor = config.fileTreeVisitor();
1432[warn] FileHasher hasher = config.fileHasher();
1433[warn] this.fileLevelEvents = hasher == null || config.fileLevelEvents();
1434[warn] this.fileHasher = hasher == null ? INCREMENTING_FILE_HASHER : hasher;
1435[warn] }
1436[warn] /build/repo/core/src/main/java/io/methvin/watchservice/AbstractWatchService.java:69:1: no @param for key
1437[warn] public void cancelled(AbstractWatchKey key) {}
1438[warn] /build/repo/core/src/main/java/io/methvin/watchservice/MacOSXListeningWatchService.java:217:1: no comment
1439[warn] public synchronized void close(
1440[warn] CFRunLoopThread runLoopThread, CarbonAPI.FSEventStreamCallback callback, Path path) {
1441[warn] threadList.remove(runLoopThread);
1442[warn] callbackList.remove(callback);
1443[warn] pathsWatching.remove(path);
1444[warn] runLoopThread.close();
1445[warn] }
1446[warn] /build/repo/core/src/main/java/io/methvin/watchservice/AbstractWatchService.java:57:1: no @return
1447[warn] public boolean isOpen() {
1448[warn] return open.get();
1449[warn] }
1450[warn] /build/repo/core/src/main/java/io/methvin/watchservice/AbstractWatchService.java:52:1: no @param for watchable
1451[warn] public abstract AbstractWatchKey register(
1452[warn] WatchablePath watchable, Iterable<? extends WatchEvent.Kind<?>> eventTypes)
1453[warn] throws IOException;
1454[info] 100 warnings
1455[warn] Loading source file DirectoryWatcher.java...
1456[warn] Loading source file DirectoryChangeListener.java...
1457[warn] Loading source file DirectoryChangeEvent.java...
1458[warn] Loading source file PathUtils.java...
1459[warn] Loading source file OnTimeoutListener.java...
1460[warn] Loading source file AbstractWatchService.java...
1461[warn] Loading source file MacOSXWatchKey.java...
1462[warn] Loading source file AbstractWatchKey.java...
1463[warn] Loading source file MacOSXListeningWatchService.java...
1464[warn] Loading source file WatchablePath.java...
1465[warn] Loading source file ByteArrayFileHash.java...
1466[warn] Loading source file Murmur3F.java...
1467[warn] Loading source file FileHash.java...
1468[warn] Loading source file FileHasher.java...
1469[warn] Loading source file DefaultFileTreeVisitor.java...
1470[warn] Loading source file FileTreeVisitor.java...
1471[warn] Loading source file ChangeSetEntry.java...
1472[warn] Loading source file ChangeSetListener.java...
1473[warn] Loading source file ChangeSet.java...
1474[warn] Loading source file ChangeSetBuilder.java...
1475[warn] Loading source file ChangeSetImpl.java...
1476[warn] Loading source file CFArrayRef.java...
1477[warn] Loading source file CFIndex.java...
1478[warn] Loading source file CFAllocatorRef.java...
1479[warn] Loading source file FSEventStreamRef.java...
1480[warn] Loading source file CarbonAPI.java...
1481[warn] Loading source file CFStringRef.java...
1482[warn] Loading source file CFRunLoopRef.java...
1483[warn] Constructing Javadoc information...
1484[warn] Building index for all the packages and classes...
1485[warn] Standard Doclet version 17.0.8+7
1486[warn] Building tree for all the packages and classes...
1487[warn] Generating /build/repo/core/target/api/io/methvin/watchservice/jna/CarbonAPI.html...
1488[warn] Generating /build/repo/core/target/api/io/methvin/watchservice/jna/CarbonAPI.FSEventStreamCallback.html...
1489[warn] Generating /build/repo/core/target/api/io/methvin/watchservice/jna/CFAllocatorRef.html...
1490[warn] Generating /build/repo/core/target/api/io/methvin/watchservice/jna/CFArrayRef.html...
1491[warn] Generating /build/repo/core/target/api/io/methvin/watchservice/jna/CFIndex.html...
1492[warn] Generating /build/repo/core/target/api/io/methvin/watchservice/jna/CFRunLoopRef.html...
1493[warn] Generating /build/repo/core/target/api/io/methvin/watchservice/jna/CFStringRef.html...
1494[warn] Generating /build/repo/core/target/api/io/methvin/watcher/changeset/ChangeSet.html...
1495[warn] Generating /build/repo/core/target/api/io/methvin/watcher/changeset/ChangeSetEntry.html...
1496[warn] Generating /build/repo/core/target/api/io/methvin/watcher/changeset/ChangeSetListener.html...
1497[warn] Generating /build/repo/core/target/api/io/methvin/watcher/visitor/DefaultFileTreeVisitor.html...
1498[warn] Generating /build/repo/core/target/api/io/methvin/watcher/DirectoryChangeEvent.html...
1499[warn] Generating /build/repo/core/target/api/io/methvin/watcher/DirectoryChangeEvent.EventType.html...
1500[warn] Generating /build/repo/core/target/api/io/methvin/watcher/DirectoryChangeListener.html...
1501[warn] Generating /build/repo/core/target/api/io/methvin/watcher/DirectoryWatcher.html...
1502[warn] Generating /build/repo/core/target/api/io/methvin/watcher/DirectoryWatcher.Builder.html...
1503[warn] Generating /build/repo/core/target/api/io/methvin/watcher/hashing/FileHash.html...
1504[warn] Generating /build/repo/core/target/api/io/methvin/watcher/hashing/FileHasher.html...
1505[warn] Generating /build/repo/core/target/api/io/methvin/watcher/visitor/FileTreeVisitor.html...
1506[warn] Generating /build/repo/core/target/api/io/methvin/watcher/visitor/FileTreeVisitor.Callback.html...
1507[warn] Generating /build/repo/core/target/api/io/methvin/watchservice/jna/FSEventStreamRef.html...
1508[warn] Generating /build/repo/core/target/api/io/methvin/watchservice/MacOSXListeningWatchService.html...
1509[warn] Generating /build/repo/core/target/api/io/methvin/watchservice/MacOSXListeningWatchService.CFRunLoopThread.html...
1510[warn] Generating /build/repo/core/target/api/io/methvin/watchservice/MacOSXListeningWatchService.Config.html...
1511[warn] Generating /build/repo/core/target/api/io/methvin/watcher/hashing/Murmur3F.html...
1512[warn] Generating /build/repo/core/target/api/io/methvin/watcher/OnTimeoutListener.html...
1513[warn] Generating /build/repo/core/target/api/io/methvin/watcher/PathUtils.html...
1514[warn] Generating /build/repo/core/target/api/io/methvin/watchservice/WatchablePath.html...
1515[warn] Generating /build/repo/core/target/api/io/methvin/watcher/package-summary.html...
1516[warn] Generating /build/repo/core/target/api/io/methvin/watcher/package-tree.html...
1517[warn] Generating /build/repo/core/target/api/io/methvin/watcher/changeset/package-summary.html...
1518[warn] Generating /build/repo/core/target/api/io/methvin/watcher/changeset/package-tree.html...
1519[warn] Generating /build/repo/core/target/api/io/methvin/watcher/hashing/package-summary.html...
1520[warn] Generating /build/repo/core/target/api/io/methvin/watcher/hashing/package-tree.html...
1521[warn] Generating /build/repo/core/target/api/io/methvin/watcher/visitor/package-summary.html...
1522[warn] Generating /build/repo/core/target/api/io/methvin/watcher/visitor/package-tree.html...
1523[warn] Generating /build/repo/core/target/api/io/methvin/watchservice/package-summary.html...
1524[warn] Generating /build/repo/core/target/api/io/methvin/watchservice/package-tree.html...
1525[warn] Generating /build/repo/core/target/api/io/methvin/watchservice/jna/package-summary.html...
1526[warn] Generating /build/repo/core/target/api/io/methvin/watchservice/jna/package-tree.html...
1527[warn] Generating /build/repo/core/target/api/constant-values.html...
1528[warn] Generating /build/repo/core/target/api/serialized-form.html...
1529[warn] Generating /build/repo/core/target/api/overview-tree.html...
1530[warn] Generating /build/repo/core/target/api/index.html...
1531[warn] Building index for all classes...
1532[warn] Generating /build/repo/core/target/api/allclasses-index.html...
1533[warn] Generating /build/repo/core/target/api/allpackages-index.html...
1534[warn] Generating /build/repo/core/target/api/index-all.html...
1535[warn] Generating /build/repo/core/target/api/overview-summary.html...
1536[warn] Generating /build/repo/core/target/api/help-doc.html...
1537[info] Main Java API documentation successful.
1538[info] compiling 6 Java sources to /build/repo/core/target/test-classes ...
1539[warn] /build/repo/core/src/test/java/io/methvin/watcher/DirectoryWatcherOnDiskTest.java:557:1: unchecked generic array creation for varargs parameter of type java.util.List<java.nio.file.Path>[]
1540[warn] updatePaths(paths1)
1541[warn] /build/repo/core/src/test/java/io/methvin/watcher/DirectoryWatcherOnDiskTest.java:562:1: unchecked generic array creation for varargs parameter of type java.util.List<java.nio.file.Path>[]
1542[warn] updatePaths(paths2, paths3)
1543[warn] /build/repo/core/src/test/java/io/methvin/watcher/DirectoryWatcherOnDiskTest.java:762:1: Possible heap pollution from parameterized vararg type java.util.List<java.nio.file.Path>
1544[warn] List<Path>... paths
1545[warn] /build/repo/core/src/test/java/io/methvin/watchservice/FileSystem.java:89:1: fileAppend(java.lang.String,java.lang.String) in org.codehaus.plexus.util.FileUtils has been deprecated
1546[warn] FileUtils.fileAppend
1547[info] done compiling
1548[info] Wrote /build/repo/core/target/directory-watcher-0.18.0.pom
1549[info] Main Java API documentation to /build/repo/core/target/api...
1550[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CarbonAPI.java:18:1: no comment
1551[warn] public interface CarbonAPI extends Library {
1552[warn] // sbt uses JNA 4.5.0, so use JNA 4.x's API
1553[warn] CarbonAPI INSTANCE = (CarbonAPI) Native.loadLibrary("Carbon", CarbonAPI.class);
1554[warn]
1555[warn] CFArrayRef CFArrayCreate(
1556[warn] CFAllocatorRef allocator, // always set to Pointer.NULL
1557[warn] Pointer[] values,
1558[warn] CFIndex numValues,
1559[warn] Void callBacks // always set to Pointer.NULL
1560[warn] );
1561[warn]
1562[warn] CFStringRef CFStringCreateWithCharacters(
1563[warn] Void alloc, // always pass NULL
1564[warn] char[] chars,
1565[warn] CFIndex numChars);
1566[warn]
1567[warn] public FSEventStreamRef FSEventStreamCreate(
1568[warn] Pointer v, // always use Pointer.NULL
1569[warn] FSEventStreamCallback callback,
1570[warn] Pointer context, // always use Pointer.NULL
1571[warn] CFArrayRef pathsToWatch,
1572[warn] long sinceWhen, // use -1 for events since now
1573[warn] double latency, // in seconds
1574[warn] int flags // 0 is good for now
1575[warn] );
1576[warn]
1577[warn] boolean FSEventStreamStart(FSEventStreamRef streamRef);
1578[warn]
1579[warn] void FSEventStreamStop(FSEventStreamRef streamRef);
1580[warn]
1581[warn] void FSEventStreamScheduleWithRunLoop(
1582[warn] FSEventStreamRef streamRef, CFRunLoopRef runLoop, CFStringRef runLoopMode);
1583[warn]
1584[warn] void FSEventStreamUnscheduleFromRunLoop(
1585[warn] FSEventStreamRef streamRef, CFRunLoopRef runLoop, CFStringRef runLoopMode);
1586[warn]
1587[warn] void FSEventStreamInvalidate(FSEventStreamRef streamRef);
1588[warn]
1589[warn] void FSEventStreamRelease(FSEventStreamRef streamRef);
1590[warn]
1591[warn] CFRunLoopRef CFRunLoopGetCurrent();
1592[warn]
1593[warn] void CFRunLoopRun();
1594[warn]
1595[warn] void CFRunLoopStop(CFRunLoopRef runLoopRef);
1596[warn]
1597[warn] public interface FSEventStreamCallback extends Callback {
1598[warn] @SuppressWarnings({"UnusedDeclaration"})
1599[warn] void invoke(
1600[warn] FSEventStreamRef streamRef,
1601[warn] Pointer clientCallBackInfo,
1602[warn] NativeLong numEvents,
1603[warn] Pointer eventPaths,
1604[warn] Pointer eventFlags,
1605[warn] Pointer eventIds);
1606[warn] }
1607[warn] }
1608[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CarbonAPI.java:64:1: no comment
1609[warn] public interface FSEventStreamCallback extends Callback {
1610[warn] @SuppressWarnings({"UnusedDeclaration"})
1611[warn] void invoke(
1612[warn] FSEventStreamRef streamRef,
1613[warn] Pointer clientCallBackInfo,
1614[warn] NativeLong numEvents,
1615[warn] Pointer eventPaths,
1616[warn] Pointer eventFlags,
1617[warn] Pointer eventIds);
1618[warn] }
1619[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CarbonAPI.java:20:1: no comment
1620[warn] CarbonAPI INSTANCE = (CarbonAPI) Native.loadLibrary("Carbon", CarbonAPI.class);
1621[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CarbonAPI.java:22:1: no comment
1622[warn] CFArrayRef CFArrayCreate(
1623[warn] CFAllocatorRef allocator, // always set to Pointer.NULL
1624[warn] Pointer[] values,
1625[warn] CFIndex numValues,
1626[warn] Void callBacks // always set to Pointer.NULL
1627[warn] );
1628[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CarbonAPI.java:58:1: no comment
1629[warn] CFRunLoopRef CFRunLoopGetCurrent();
1630[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CarbonAPI.java:60:1: no comment
1631[warn] void CFRunLoopRun();
1632[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CarbonAPI.java:62:1: no comment
1633[warn] void CFRunLoopStop(CFRunLoopRef runLoopRef);
1634[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CarbonAPI.java:29:1: no comment
1635[warn] CFStringRef CFStringCreateWithCharacters(
1636[warn] Void alloc, // always pass NULL
1637[warn] char[] chars,
1638[warn] CFIndex numChars);
1639[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CarbonAPI.java:34:1: no comment
1640[warn] public FSEventStreamRef FSEventStreamCreate(
1641[warn] Pointer v, // always use Pointer.NULL
1642[warn] FSEventStreamCallback callback,
1643[warn] Pointer context, // always use Pointer.NULL
1644[warn] CFArrayRef pathsToWatch,
1645[warn] long sinceWhen, // use -1 for events since now
1646[warn] double latency, // in seconds
1647[warn] int flags // 0 is good for now
1648[warn] );
1649[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CarbonAPI.java:54:1: no comment
1650[warn] void FSEventStreamInvalidate(FSEventStreamRef streamRef);
1651[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CarbonAPI.java:56:1: no comment
1652[warn] void FSEventStreamRelease(FSEventStreamRef streamRef);
1653[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CarbonAPI.java:48:1: no comment
1654[warn] void FSEventStreamScheduleWithRunLoop(
1655[warn] FSEventStreamRef streamRef, CFRunLoopRef runLoop, CFStringRef runLoopMode);
1656[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CarbonAPI.java:44:1: no comment
1657[warn] boolean FSEventStreamStart(FSEventStreamRef streamRef);
1658[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CarbonAPI.java:46:1: no comment
1659[warn] void FSEventStreamStop(FSEventStreamRef streamRef);
1660[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CarbonAPI.java:51:1: no comment
1661[warn] void FSEventStreamUnscheduleFromRunLoop(
1662[warn] FSEventStreamRef streamRef, CFRunLoopRef runLoop, CFStringRef runLoopMode);
1663[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CarbonAPI.java:66:1: no comment
1664[warn] @SuppressWarnings({"UnusedDeclaration"})
1665[warn] void invoke(
1666[warn] FSEventStreamRef streamRef,
1667[warn] Pointer clientCallBackInfo,
1668[warn] NativeLong numEvents,
1669[warn] Pointer eventPaths,
1670[warn] Pointer eventFlags,
1671[warn] Pointer eventIds);
1672[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CFAllocatorRef.java:18:1: no comment
1673[warn] public class CFAllocatorRef extends PointerByReference {}
1674[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CFArrayRef.java:18:1: no comment
1675[warn] public class CFArrayRef extends PointerByReference {}
1676[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CFIndex.java:18:1: no comment
1677[warn] public class CFIndex extends NativeLong {
1678[warn] private static final long serialVersionUID = 0;
1679[warn]
1680[warn] public static CFIndex valueOf(int i) {
1681[warn] CFIndex idx = new CFIndex();
1682[warn] idx.setValue(i);
1683[warn] return idx;
1684[warn] }
1685[warn] }
1686[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CFIndex.java:21:1: no comment
1687[warn] public static CFIndex valueOf(int i) {
1688[warn] CFIndex idx = new CFIndex();
1689[warn] idx.setValue(i);
1690[warn] return idx;
1691[warn] }
1692[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CFRunLoopRef.java:18:1: no comment
1693[warn] public class CFRunLoopRef extends PointerByReference {}
1694[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CFStringRef.java:18:1: no comment
1695[warn] public class CFStringRef extends PointerByReference {
1696[warn]
1697[warn] public static CFStringRef toCFString(String s) {
1698[warn] final char[] chars = s.toCharArray();
1699[warn] int length = chars.length;
1700[warn] return CarbonAPI.INSTANCE.CFStringCreateWithCharacters(null, chars, CFIndex.valueOf(length));
1701[warn] }
1702[warn] }
1703[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/CFStringRef.java:20:1: no comment
1704[warn] public static CFStringRef toCFString(String s) {
1705[warn] final char[] chars = s.toCharArray();
1706[warn] int length = chars.length;
1707[warn] return CarbonAPI.INSTANCE.CFStringCreateWithCharacters(null, chars, CFIndex.valueOf(length));
1708[warn] }
1709[warn] /build/repo/core/src/main/java/io/methvin/watcher/changeset/ChangeSet.java:5:1: no comment
1710[warn] public interface ChangeSet {
1711[warn] Set<ChangeSetEntry> created();
1712[warn]
1713[warn] Set<ChangeSetEntry> modified();
1714[warn]
1715[warn] Set<ChangeSetEntry> deleted();
1716[warn] }
1717[warn] /build/repo/core/src/main/java/io/methvin/watcher/changeset/ChangeSet.java:6:1: no comment
1718[warn] Set<ChangeSetEntry> created();
1719[warn] /build/repo/core/src/main/java/io/methvin/watcher/changeset/ChangeSet.java:10:1: no comment
1720[warn] Set<ChangeSetEntry> deleted();
1721[warn] /build/repo/core/src/main/java/io/methvin/watcher/changeset/ChangeSet.java:8:1: no comment
1722[warn] Set<ChangeSetEntry> modified();
1723[warn] /build/repo/core/src/main/java/io/methvin/watcher/changeset/ChangeSetEntry.java:7:1: no comment
1724[warn] public final class ChangeSetEntry {
1725[warn]
1726[warn] private final Path path;
1727[warn] private final boolean isDirectory;
1728[warn] private final FileHash hash;
1729[warn] private final Path rootPath;
1730[warn]
1731[warn] ChangeSetEntry(Path path, boolean isDirectory, FileHash hash, Path rootPath) {
1732[warn] this.path = path;
1733[warn] this.isDirectory = isDirectory;
1734[warn] this.hash = hash;
1735[warn] this.rootPath = rootPath;
1736[warn] }
1737[warn]
1738[warn] public Path path() {
1739[warn] return path;
1740[warn] }
1741[warn]
1742[warn] public boolean isDirectory() {
1743[warn] return isDirectory;
1744[warn] }
1745[warn]
1746[warn] public FileHash hash() {
1747[warn] return hash;
1748[warn] }
1749[warn]
1750[warn] public Path rootPath() {
1751[warn] return rootPath;
1752[warn] }
1753[warn]
1754[warn] @Override
1755[warn] public boolean equals(Object o) {
1756[warn] if (this == o) {
1757[warn] return true;
1758[warn] }
1759[warn] if (o == null || getClass() != o.getClass()) {
1760[warn] return false;
1761[warn] }
1762[warn]
1763[warn] ChangeSetEntry that = (ChangeSetEntry) o;
1764[warn]
1765[warn] return isDirectory == that.isDirectory
1766[warn] && path.equals(that.path)
1767[warn] && hash.equals(that.hash)
1768[warn] && rootPath.equals(that.rootPath);
1769[warn] }
1770[warn]
1771[warn] @Override
1772[warn] public int hashCode() {
1773[warn] return Objects.hash(path, isDirectory, rootPath, hash);
1774[warn] }
1775[warn] }
1776[warn] /build/repo/core/src/main/java/io/methvin/watcher/changeset/ChangeSetEntry.java:29:1: no comment
1777[warn] public FileHash hash() {
1778[warn] return hash;
1779[warn] }
1780[warn] /build/repo/core/src/main/java/io/methvin/watcher/changeset/ChangeSetEntry.java:25:1: no comment
1781[warn] public boolean isDirectory() {
1782[warn] return isDirectory;
1783[warn] }
1784[warn] /build/repo/core/src/main/java/io/methvin/watcher/changeset/ChangeSetEntry.java:21:1: no comment
1785[warn] public Path path() {
1786[warn] return path;
1787[warn] }
1788[warn] /build/repo/core/src/main/java/io/methvin/watcher/changeset/ChangeSetEntry.java:33:1: no comment
1789[warn] public Path rootPath() {
1790[warn] return rootPath;
1791[warn] }
1792[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeListener.java:61:1: no @return
1793[warn] default boolean isWatching() {
1794[warn] return true;
1795[warn] }
1796[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeListener.java:72:1: no @param for e
1797[warn] default void onException(Exception e) {
1798[warn] // Ignore exceptions by default (they will be logged by the watcher)
1799[warn] }
1800[warn] /build/repo/core/src/main/java/io/methvin/watcher/changeset/ChangeSetListener.java:10:1: no comment
1801[warn] public final class ChangeSetListener implements DirectoryChangeListener {
1802[warn]
1803[warn] private Map<Path, ChangeSetBuilder> changeBuilders = new HashMap<>();
1804[warn]
1805[warn] private final Object lock = new Object() {};
1806[warn]
1807[warn] @Override
1808[warn] public void onEvent(DirectoryChangeEvent event) {
1809[warn] Path rootPath = event.rootPath();
1810[warn] Path path = event.path();
1811[warn]
1812[warn] synchronized (lock) {
1813[warn] // Maintain a ChangeSet per rootPath
1814[warn] ChangeSetBuilder builder = changeBuilders.get(rootPath);
1815[warn] if (builder == null) {
1816[warn] builder = new ChangeSetBuilder();
1817[warn] changeBuilders.put(rootPath, builder);
1818[warn] }
1819[warn]
1820[warn] ChangeSetEntry entry =
1821[warn] new ChangeSetEntry(path, event.isDirectory(), event.hash(), event.rootPath());
1822[warn]
1823[warn] switch (event.eventType()) {
1824[warn] case CREATE:
1825[warn] builder.addCreated(entry);
1826[warn] break;
1827[warn] case MODIFY:
1828[warn] builder.addModified(entry);
1829[warn] break;
1830[warn] case DELETE:
1831[warn] builder.addDeleted(entry);
1832[warn] break;
1833[warn] case OVERFLOW:
1834[warn] throw new IllegalStateException("OVERFLOW not yet handled");
1835[warn] }
1836[warn] }
1837[warn] }
1838[warn]
1839[warn] public Map<Path, ChangeSet> getChangeSet() {
1840[warn] Map<Path, ChangeSetBuilder> returnBuilders;
1841[warn] synchronized (lock) {
1842[warn] returnBuilders = changeBuilders;
1843[warn] changeBuilders = new HashMap<>();
1844[warn] }
1845[warn] return returnBuilders.entrySet().stream()
1846[warn] .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue().toChangeSet()));
1847[warn] }
1848[warn] }
1849[warn] /build/repo/core/src/main/java/io/methvin/watcher/changeset/ChangeSetListener.java:48:1: no comment
1850[warn] public Map<Path, ChangeSet> getChangeSet() {
1851[warn] Map<Path, ChangeSetBuilder> returnBuilders;
1852[warn] synchronized (lock) {
1853[warn] returnBuilders = changeBuilders;
1854[warn] changeBuilders = new HashMap<>();
1855[warn] }
1856[warn] return returnBuilders.entrySet().stream()
1857[warn] .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue().toChangeSet()));
1858[warn] }
1859[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeListener.java:58:1: no comment
1860[warn] void onEvent(DirectoryChangeEvent event) throws IOException;
1861[warn] /build/repo/core/src/main/java/io/methvin/watcher/visitor/DefaultFileTreeVisitor.java:10:1: no comment
1862[warn] public class DefaultFileTreeVisitor implements FileTreeVisitor {
1863[warn] @Override
1864[warn] public void recursiveVisitFiles(Path file, Callback onDirectory, Callback onFile)
1865[warn] throws IOException {
1866[warn] SimpleFileVisitor<Path> visitor =
1867[warn] new SimpleFileVisitor<Path>() {
1868[warn] @Override
1869[warn] public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
1870[warn] throws IOException {
1871[warn] onDirectory.call(dir);
1872[warn] return FileVisitResult.CONTINUE;
1873[warn] }
1874[warn]
1875[warn] @Override
1876[warn] public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
1877[warn] throws IOException {
1878[warn] onFile.call(file);
1879[warn] return FileVisitResult.CONTINUE;
1880[warn] }
1881[warn]
1882[warn] @Override
1883[warn] public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
1884[warn] onFailure(file, exc);
1885[warn] return FileVisitResult.CONTINUE;
1886[warn] }
1887[warn]
1888[warn] @Override
1889[warn] public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
1890[warn] if (exc != null) onFailure(dir, exc);
1891[warn] return FileVisitResult.CONTINUE;
1892[warn] }
1893[warn] };
1894[warn] Files.walkFileTree(file, visitor);
1895[warn] }
1896[warn]
1897[warn] // To be overridden if needed
1898[warn] protected void onFailure(Path path, IOException exception) throws IOException {}
1899[warn] }
1900[warn] /build/repo/core/src/main/java/io/methvin/watcher/visitor/DefaultFileTreeVisitor.java:46:1: no comment
1901[warn] protected void onFailure(Path path, IOException exception) throws IOException {}
1902[warn] /build/repo/core/src/main/java/io/methvin/watcher/visitor/FileTreeVisitor.java:16:1: no comment
1903[warn] void recursiveVisitFiles(Path file, Callback onDirectory, Callback onFile) throws IOException;
1904[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeEvent.java:22:1: no comment
1905[warn] public final class DirectoryChangeEvent {
1906[warn] public enum EventType {
1907[warn]
1908[warn] /* A new file was created */
1909[warn] CREATE(StandardWatchEventKinds.ENTRY_CREATE),
1910[warn]
1911[warn] /* An existing file was modified */
1912[warn] MODIFY(StandardWatchEventKinds.ENTRY_MODIFY),
1913[warn]
1914[warn] /* A file was deleted */
1915[warn] DELETE(StandardWatchEventKinds.ENTRY_DELETE),
1916[warn]
1917[warn] /* An overflow occurred; some events were lost */
1918[warn] OVERFLOW(StandardWatchEventKinds.OVERFLOW);
1919[warn]
1920[warn] private WatchEvent.Kind<?> kind;
1921[warn]
1922[warn] EventType(WatchEvent.Kind<?> kind) {
1923[warn] this.kind = kind;
1924[warn] }
1925[warn]
1926[warn] public WatchEvent.Kind<?> getWatchEventKind() {
1927[warn] return kind;
1928[warn] }
1929[warn] }
1930[warn]
1931[warn] private final EventType eventType;
1932[warn] private final boolean isDirectory;
1933[warn] private final Path path;
1934[warn] private final FileHash hash;
1935[warn] private final int count;
1936[warn] private final Path rootPath;
1937[warn]
1938[warn] public DirectoryChangeEvent(
1939[warn] EventType eventType,
1940[warn] boolean isDirectory,
1941[warn] Path path,
1942[warn] FileHash hash,
1943[warn] int count,
1944[warn] Path rootPath) {
1945[warn] this.eventType = eventType;
1946[warn] this.isDirectory = isDirectory;
1947[warn] this.hash = hash;
1948[warn] this.path = path;
1949[warn] this.count = count;
1950[warn] this.rootPath = rootPath;
1951[warn] }
1952[warn]
1953[warn] public EventType eventType() {
1954[warn] return eventType;
1955[warn] }
1956[warn]
1957[warn] public Path path() {
1958[warn] return path;
1959[warn] }
1960[warn]
1961[warn] public int count() {
1962[warn] return count;
1963[warn] }
1964[warn]
1965[warn] public Path rootPath() {
1966[warn] return rootPath;
1967[warn] }
1968[warn]
1969[warn] public boolean isDirectory() {
1970[warn] return isDirectory;
1971[warn] }
1972[warn]
1973[warn] public FileHash hash() {
1974[warn] return hash;
1975[warn] }
1976[warn]
1977[warn] @Override
1978[warn] public boolean equals(Object o) {
1979[warn] if (this == o) {
1980[warn] return true;
1981[warn] }
1982[warn] if (o == null || getClass() != o.getClass()) {
1983[warn] return false;
1984[warn] }
1985[warn]
1986[warn] DirectoryChangeEvent that = (DirectoryChangeEvent) o;
1987[warn]
1988[warn] return count == that.count
1989[warn] && eventType == that.eventType
1990[warn] && isDirectory == that.isDirectory
1991[warn] && Objects.equals(path, that.path)
1992[warn] && Objects.equals(rootPath, that.rootPath)
1993[warn] && Objects.equals(hash, that.hash);
1994[warn] }
1995[warn]
1996[warn] @Override
1997[warn] public int hashCode() {
1998[warn] return Objects.hash(eventType, isDirectory, path, count, rootPath, hash);
1999[warn] }
2000[warn]
2001[warn] @Override
2002[warn] public String toString() {
2003[warn] return "DirectoryChangeEvent{"
2004[warn] + "eventType="
2005[warn] + eventType
2006[warn] + ", isDirectory="
2007[warn] + isDirectory
2008[warn] + ", path="
2009[warn] + path
2010[warn] + ", count="
2011[warn] + count
2012[warn] + ", rootPath="
2013[warn] + rootPath
2014[warn] + ", hash="
2015[warn] + ((hash == null) ? "(null)" : hash) // don't want the printout to be too long
2016[warn] + '}';
2017[warn] }
2018[warn] }
2019[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeEvent.java:23:1: no comment
2020[warn] public enum EventType {
2021[warn]
2022[warn] /* A new file was created */
2023[warn] CREATE(StandardWatchEventKinds.ENTRY_CREATE),
2024[warn]
2025[warn] /* An existing file was modified */
2026[warn] MODIFY(StandardWatchEventKinds.ENTRY_MODIFY),
2027[warn]
2028[warn] /* A file was deleted */
2029[warn] DELETE(StandardWatchEventKinds.ENTRY_DELETE),
2030[warn]
2031[warn] /* An overflow occurred; some events were lost */
2032[warn] OVERFLOW(StandardWatchEventKinds.OVERFLOW);
2033[warn]
2034[warn] private WatchEvent.Kind<?> kind;
2035[warn]
2036[warn] EventType(WatchEvent.Kind<?> kind) {
2037[warn] this.kind = kind;
2038[warn] }
2039[warn]
2040[warn] public WatchEvent.Kind<?> getWatchEventKind() {
2041[warn] return kind;
2042[warn] }
2043[warn] }
2044[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeEvent.java:55:1: no comment
2045[warn] public DirectoryChangeEvent(
2046[warn] EventType eventType,
2047[warn] boolean isDirectory,
2048[warn] Path path,
2049[warn] FileHash hash,
2050[warn] int count,
2051[warn] Path rootPath) {
2052[warn] this.eventType = eventType;
2053[warn] this.isDirectory = isDirectory;
2054[warn] this.hash = hash;
2055[warn] this.path = path;
2056[warn] this.count = count;
2057[warn] this.rootPath = rootPath;
2058[warn] }
2059[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeEvent.java:78:1: no comment
2060[warn] public int count() {
2061[warn] return count;
2062[warn] }
2063[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeEvent.java:70:1: no comment
2064[warn] public EventType eventType() {
2065[warn] return eventType;
2066[warn] }
2067[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeEvent.java:90:1: no comment
2068[warn] public FileHash hash() {
2069[warn] return hash;
2070[warn] }
2071[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeEvent.java:86:1: no comment
2072[warn] public boolean isDirectory() {
2073[warn] return isDirectory;
2074[warn] }
2075[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeEvent.java:74:1: no comment
2076[warn] public Path path() {
2077[warn] return path;
2078[warn] }
2079[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeEvent.java:82:1: no comment
2080[warn] public Path rootPath() {
2081[warn] return rootPath;
2082[warn] }
2083[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeEvent.java:43:1: no comment
2084[warn] public WatchEvent.Kind<?> getWatchEventKind() {
2085[warn] return kind;
2086[warn] }
2087[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeEvent.java:26:1: no comment
2088[warn] CREATE(StandardWatchEventKinds.ENTRY_CREATE)
2089[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeEvent.java:32:1: no comment
2090[warn] DELETE(StandardWatchEventKinds.ENTRY_DELETE)
2091[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeEvent.java:29:1: no comment
2092[warn] MODIFY(StandardWatchEventKinds.ENTRY_MODIFY)
2093[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeEvent.java:35:1: no comment
2094[warn] OVERFLOW(StandardWatchEventKinds.OVERFLOW)
2095[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeListener.java:24:1: no comment
2096[warn] static DirectoryChangeListener of(DirectoryChangeListener... listeners) {
2097[warn] return new DirectoryChangeListener() {
2098[warn] @Override
2099[warn] public void onEvent(DirectoryChangeEvent event) throws IOException {
2100[warn] for (DirectoryChangeListener listener : listeners) {
2101[warn] listener.onEvent(event);
2102[warn] }
2103[warn] }
2104[warn]
2105[warn] @Override
2106[warn] public void onException(Exception e) {
2107[warn] for (DirectoryChangeListener listener : listeners) {
2108[warn] listener.onException(e);
2109[warn] }
2110[warn] }
2111[warn]
2112[warn] @Override
2113[warn] public void onIdle(int count) {
2114[warn] for (DirectoryChangeListener listener : listeners) {
2115[warn] listener.onIdle(count);
2116[warn] }
2117[warn] }
2118[warn]
2119[warn] @Override
2120[warn] public boolean isWatching() {
2121[warn] boolean anyWatching = false;
2122[warn] for (DirectoryChangeListener listener : listeners) {
2123[warn] anyWatching |= listener.isWatching();
2124[warn] }
2125[warn] return anyWatching;
2126[warn] }
2127[warn] };
2128[warn] }
2129[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryChangeListener.java:65:1: no comment
2130[warn] default void onIdle(int count) {
2131[warn] // ignore onIdle by default
2132[warn] }
2133[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:172:1: no @return
2134[warn] public static Builder builder() {
2135[warn] return new Builder();
2136[warn] }
2137[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:214:1: no @return
2138[warn] public CompletableFuture<Void> watchAsync() {
2139[warn] return watchAsync(ForkJoinPool.commonPool());
2140[warn] }
2141[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:227:1: no @return
2142[warn] public CompletableFuture<Void> watchAsync(Executor executor) {
2143[warn] try {
2144[warn] registerPaths();
2145[warn] return CompletableFuture.supplyAsync(
2146[warn] () -> {
2147[warn] runEventLoop();
2148[warn] return null;
2149[warn] },
2150[warn] executor);
2151[warn] } catch (Throwable t) {
2152[warn] CompletableFuture<Void> f = new CompletableFuture<>();
2153[warn] f.completeExceptionally(t);
2154[warn] return f;
2155[warn] }
2156[warn] }
2157[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:46:1: no comment
2158[warn] public class DirectoryWatcher {
2159[warn]
2160[warn] /**
2161[warn] * A builder for a {@link DirectoryWatcher}. Use {@code DirectoryWatcher.builder()} to get a new
2162[warn] * instance.
2163[warn] */
2164[warn] public static final class Builder {
2165[warn] private List<Path> paths = Collections.emptyList();
2166[warn] private DirectoryChangeListener listener = (event -> {});
2167[warn] private Logger logger = null;
2168[warn] private FileHasher fileHasher = FileHasher.DEFAULT_FILE_HASHER;
2169[warn] private WatchService watchService = null;
2170[warn] private FileTreeVisitor fileTreeVisitor = null;
2171[warn]
2172[warn] private Builder() {}
2173[warn]
2174[warn] /** Set multiple paths to watch. */
2175[warn] public Builder paths(List<Path> paths) {
2176[warn] this.paths = paths;
2177[warn] return this;
2178[warn] }
2179[warn]
2180[warn] /** Set a single path to watch. */
2181[warn] public Builder path(Path path) {
2182[warn] return paths(Collections.singletonList(path));
2183[warn] }
2184[warn]
2185[warn] /** Set a listener that will be called when a directory change event occurs. */
2186[warn] public Builder listener(DirectoryChangeListener listener) {
2187[warn] this.listener = listener;
2188[warn] return this;
2189[warn] }
2190[warn]
2191[warn] /**
2192[warn] * Set a {@link WatchService} implementation that will be used by the watcher.
2193[warn] *
2194[warn] * <p>By default, this detects your OS and either uses the native JVM watcher or the macOS
2195[warn] * watcher.
2196[warn] */
2197[warn] public Builder watchService(WatchService watchService) {
2198[warn] this.watchService = watchService;
2199[warn] return this;
2200[warn] }
2201[warn]
2202[warn] /**
2203[warn] * Set a logger to be used by the watcher. This defaults to {@code
2204[warn] * LoggerFactory.getLogger(DirectoryWatcher.class)}
2205[warn] */
2206[warn] public Builder logger(Logger logger) {
2207[warn] this.logger = logger;
2208[warn] return this;
2209[warn] }
2210[warn]
2211[warn] /**
2212[warn] * Defines whether file hashing should be used to catch duplicate events. Defaults to {@code
2213[warn] * true}.
2214[warn] */
2215[warn] public Builder fileHashing(boolean enabled) {
2216[warn] this.fileHasher = enabled ? FileHasher.DEFAULT_FILE_HASHER : null;
2217[warn] return this;
2218[warn] }
2219[warn]
2220[warn] /**
2221[warn] * Defines the file hasher to be used by the watcher.
2222[warn] *
2223[warn] * <p>Note: will implicitly enable file hashing. Setting to null is equivalent to {@code
2224[warn] * fileHashing(false)}
2225[warn] */
2226[warn] public Builder fileHasher(FileHasher fileHasher) {
2227[warn] this.fileHasher = fileHasher;
2228[warn] return this;
2229[warn] }
2230[warn]
2231[warn] /** Defines the file tree visitor to be used by the watcher. */
2232[warn] public Builder fileTreeVisitor(FileTreeVisitor fileTreeVisitor) {
2233[warn] this.fileTreeVisitor = fileTreeVisitor;
2234[warn] return this;
2235[warn] }
2236[warn]
2237[warn] public DirectoryWatcher build() throws IOException {
2238[warn] if (fileTreeVisitor == null) {
2239[warn] fileTreeVisitor = FileTreeVisitor.DEFAULT_FILE_TREE_VISITOR;
2240[warn] }
2241[warn] if (watchService == null) {
2242[warn] osDefaultWatchService(fileTreeVisitor);
2243[warn] }
2244[warn] if (logger == null) {
2245[warn] staticLogger();
2246[warn] }
2247[warn] return new DirectoryWatcher(
2248[warn] paths, listener, watchService, fileHasher, fileTreeVisitor, logger);
2249[warn] }
2250[warn]
2251[warn] private Builder osDefaultWatchService(FileTreeVisitor fileTreeVisitor) throws IOException {
2252[warn] boolean isMac = System.getProperty("os.name").toLowerCase().contains("mac");
2253[warn] if (isMac) {
2254[warn] return watchService(
2255[warn] new MacOSXListeningWatchService(
2256[warn] new MacOSXListeningWatchService.Config() {
2257[warn] @Override
2258[warn] public FileHasher fileHasher() {
2259[warn] /**
2260[warn] * Always return null here. When MacOSXListeningWatchService is used with
2261[warn] * DirectoryWatcher, then the hashing should happen within DirectoryWatcher. If
2262[warn] * users wish to override this then they must instantiate
2263[warn] * MacOSXListeningWatchService and pass it to DirectoryWatcher.
2264[warn] */
2265[warn] return null;
2266[warn] }
2267[warn]
2268[warn] @Override
2269[warn] public FileTreeVisitor fileTreeVisitor() {
2270[warn] return fileTreeVisitor;
2271[warn] }
2272[warn] }));
2273[warn] } else {
2274[warn] return watchService(FileSystems.getDefault().newWatchService());
2275[warn] }
2276[warn] }
2277[warn]
2278[warn] private Builder staticLogger() {
2279[warn] return logger(LoggerFactory.getLogger(DirectoryWatcher.class));
2280[warn] }
2281[warn] }
2282[warn]
2283[warn] /** Get a new builder for a {@link DirectoryWatcher}. */
2284[warn] public static Builder builder() {
2285[warn] return new Builder();
2286[warn] }
2287[warn]
2288[warn] private final Logger logger;
2289[warn] private final WatchService watchService;
2290[warn] private final List<Path> paths;
2291[warn] private final boolean isMac;
2292[warn] private final DirectoryChangeListener listener;
2293[warn] private final FileHasher fileHasher;
2294[warn] private final FileTreeVisitor fileTreeVisitor;
2295[warn]
2296[warn] private final Map<Path, Path> registeredPathToRootPath = new HashMap<>();;
2297[warn] private final SortedMap<Path, FileHash> pathHashes = new ConcurrentSkipListMap<>();
2298[warn] private final Set<Path> directories =
2299[warn] Collections.newSetFromMap(new ConcurrentHashMap<Path, Boolean>());
2300[warn] private final Map<WatchKey, Path> keyRoots = new ConcurrentHashMap<>();
2301[warn]
2302[warn] private volatile boolean closed = false;
2303[warn]
2304[warn] // set to null until we check if FILE_TREE is supported
2305[warn] private Boolean fileTreeSupported = null;
2306[warn]
2307[warn] public DirectoryWatcher(
2308[warn] List<Path> paths,
2309[warn] DirectoryChangeListener listener,
2310[warn] WatchService watchService,
2311[warn] FileHasher fileHasher,
2312[warn] FileTreeVisitor fileTreeVisitor,
2313[warn] Logger logger) {
2314[warn] this.paths = paths.stream().map(p -> p.toAbsolutePath()).collect(Collectors.toList());
2315[warn] this.listener = listener;
2316[warn] this.watchService = watchService;
2317[warn] this.isMac = watchService instanceof MacOSXListeningWatchService;
2318[warn] this.fileHasher = fileHasher;
2319[warn] this.fileTreeVisitor = fileTreeVisitor;
2320[warn] this.logger = logger;
2321[warn] }
2322[warn]
2323[warn] /**
2324[warn] * Asynchronously watch the directories using {@code ForkJoinPool.commonPool()} as the executor
2325[warn] */
2326[warn] public CompletableFuture<Void> watchAsync() {
2327[warn] return watchAsync(ForkJoinPool.commonPool());
2328[warn] }
2329[warn]
2330[warn] /**
2331[warn] * Start watching for changes asynchronously.
2332[warn] *
2333[warn] * <p>The future completes when the listener stops listening or the watcher is closed.
2334[warn] *
2335[warn] * <p>This method will block until the watcher is initialized and successfully watching.
2336[warn] *
2337[warn] * @param executor the executor to use to watch asynchronously
2338[warn] */
2339[warn] public CompletableFuture<Void> watchAsync(Executor executor) {
2340[warn] try {
2341[warn] registerPaths();
2342[warn] return CompletableFuture.supplyAsync(
2343[warn] () -> {
2344[warn] runEventLoop();
2345[warn] return null;
2346[warn] },
2347[warn] executor);
2348[warn] } catch (Throwable t) {
2349[warn] CompletableFuture<Void> f = new CompletableFuture<>();
2350[warn] f.completeExceptionally(t);
2351[warn] return f;
2352[warn] }
2353[warn] }
2354[warn]
2355[warn] /**
2356[warn] * Watch for changes; block until the listener stops listening or the watcher is closed.
2357[warn] *
2358[warn] * @throws IllegalStateException if the directory watcher is closed when watch() is called.
2359[warn] */
2360[warn] public void watch() {
2361[warn] registerPaths();
2362[warn] runEventLoop();
2363[warn] }
2364[warn]
2365[warn] public Map<Path, FileHash> pathHashes() {
2366[warn] return Collections.unmodifiableMap(pathHashes);
2367[warn] }
2368[warn]
2369[warn] public DirectoryChangeListener getListener() {
2370[warn] return listener;
2371[warn] }
2372[warn]
2373[warn] public void close() throws IOException {
2374[warn] watchService.close();
2375[warn] closed = true;
2376[warn] }
2377[warn]
2378[warn] public boolean isClosed() {
2379[warn] return closed;
2380[warn] }
2381[warn]
2382[warn] private boolean isFileTreeSupported() {
2383[warn] if (fileTreeSupported == null) {
2384[warn] throw new IllegalStateException("fileTreeSupported not initialized");
2385[warn] }
2386[warn] return fileTreeSupported;
2387[warn] }
2388[warn]
2389[warn] private void registerPaths() {
2390[warn] try {
2391[warn] PathUtils.initWatcherState(paths, fileHasher, fileTreeVisitor, pathHashes, directories);
2392[warn]
2393[warn] for (Path path : paths) {
2394[warn] registerAll(path, path);
2395[warn] }
2396[warn] } catch (IOException e) {
2397[warn] throw new UncheckedIOException(e);
2398[warn] }
2399[warn] }
2400[warn]
2401[warn] private void runEventLoop() {
2402[warn] if (closed) {
2403[warn] throw new IllegalStateException("watcher already closed");
2404[warn] }
2405[warn] int eventCount = 0;
2406[warn] while (listener.isWatching()) {
2407[warn] // wait for key to be signalled
2408[warn] WatchKey key;
2409[warn] try {
2410[warn] key = watchService.poll();
2411[warn] if (key == null) {
2412[warn] listener.onIdle(eventCount);
2413[warn] key = watchService.take();
2414[warn] }
2415[warn] } catch (InterruptedException | ClosedWatchServiceException e) {
2416[warn] return;
2417[warn] }
2418[warn] for (WatchEvent<?> event : key.pollEvents()) {
2419[warn] eventCount++;
2420[warn] try {
2421[warn] WatchEvent.Kind<?> kind = event.kind();
2422[warn] // Context for directory entry event is the file name of entry
2423[warn] WatchEvent<Path> ev = PathUtils.cast(event);
2424[warn] int count = ev.count();
2425[warn] Path eventPath = ev.context();
2426[warn] if (!keyRoots.containsKey(key)) {
2427[warn] throw new IllegalStateException(
2428[warn] "WatchService returned key [" + key + "] but it was not found in keyRoots!");
2429[warn] }
2430[warn] Path registeredPath = keyRoots.get(key);
2431[warn] Path rootPath = registeredPathToRootPath.get(registeredPath);
2432[warn] Path childPath = eventPath == null ? null : keyRoots.get(key).resolve(eventPath);
2433[warn] logger.debug("{} [{}]", kind, childPath);
2434[warn] /*
2435[warn] * If a directory is created, and we're watching recursively, then register it
2436[warn] * and its sub-directories.
2437[warn] */
2438[warn] if (kind == OVERFLOW) {
2439[warn] onEvent(EventType.OVERFLOW, false, childPath, count, rootPath);
2440[warn] } else if (eventPath == null) {
2441[warn] throw new IllegalStateException("WatchService returned a null path for " + kind.name());
2442[warn] } else if (kind == ENTRY_CREATE) {
2443[warn] boolean isDirectory = Files.isDirectory(childPath, NOFOLLOW_LINKS);
2444[warn] if (isDirectory) {
2445[warn] if (!isFileTreeSupported()) {
2446[warn] registerAll(childPath, rootPath);
2447[warn] }
2448[warn] /*
2449[warn] * Our custom Mac service sends subdirectory changes but the Windows/Linux do
2450[warn] * not. Walk the file tree to make sure we send create events for any files that
2451[warn] * were created.
2452[warn] */
2453[warn] if (!isMac) {
2454[warn] fileTreeVisitor.recursiveVisitFiles(
2455[warn] childPath,
2456[warn] dir -> notifyCreateEvent(true, dir, count, rootPath),
2457[warn] file -> notifyCreateEvent(false, file, count, rootPath));
2458[warn] } else {
2459[warn] notifyCreateEvent(true, childPath, count, rootPath);
2460[warn] }
2461[warn] } else {
2462[warn] notifyCreateEvent(false, childPath, count, rootPath);
2463[warn] }
2464[warn] } else if (kind == ENTRY_MODIFY) {
2465[warn] boolean isDirectory = directories.contains(childPath);
2466[warn]
2467[warn] if (fileHasher == null) {
2468[warn] onEvent(EventType.MODIFY, isDirectory, childPath, count, rootPath);
2469[warn] } else {
2470[warn] /*
2471[warn] * Note that existingHash may be null due to the file being created before we
2472[warn] * start listening It's important we don't discard the event in this case
2473[warn] */
2474[warn] FileHash existingHash = pathHashes.get(childPath);
2475[warn]
2476[warn] /*
2477[warn] * newHash can be null when using File#delete() on windows - it generates MODIFY
2478[warn] * and DELETE in succession. In this case the MODIFY event can be safely ignored
2479[warn] */
2480[warn] FileHash newHash = PathUtils.hash(fileHasher, childPath);
2481[warn]
2482[warn] if (newHash != null && !newHash.equals(existingHash)) {
2483[warn] pathHashes.put(childPath, newHash);
2484[warn] onEvent(EventType.MODIFY, isDirectory, childPath, count, rootPath);
2485[warn] } else if (newHash == null) {
2486[warn] logger.debug(
2487[warn] "Failed to hash modified file [{}]. It may have been deleted.", childPath);
2488[warn] }
2489[warn] }
2490[warn] } else if (kind == ENTRY_DELETE) {
2491[warn] if (fileHasher == null) {
2492[warn] boolean isDirectory = directories.remove(childPath);
2493[warn] // hashing is disabled, so just notify on the path we got the event for
2494[warn] onEvent(EventType.DELETE, isDirectory, childPath, count, rootPath);
2495[warn] } else {
2496[warn] // hashing is enabled, so delete the hashes
2497[warn] for (Path path : PathUtils.subtreePaths(pathHashes, childPath)) {
2498[warn] boolean isDirectory = directories.remove(path);
2499[warn] pathHashes.remove(path);
2500[warn] onEvent(EventType.DELETE, isDirectory, path, count, rootPath);
2501[warn] }
2502[warn] }
2503[warn] }
2504[warn] } catch (Exception e) {
2505[warn] logger.debug("DirectoryWatcher got an exception while watching!", e);
2506[warn] listener.onException(e);
2507[warn] }
2508[warn] }
2509[warn] boolean valid = key.reset();
2510[warn] if (!valid) {
2511[warn] logger.debug("WatchKey for [{}] no longer valid; removing.", key.watchable());
2512[warn] // remove the key from the keyRoots
2513[warn] Path registeredPath = keyRoots.remove(key);
2514[warn]
2515[warn] // Also remove from the registeredPathToRootPath maps
2516[warn] registeredPathToRootPath.remove(registeredPath);
2517[warn]
2518[warn] // if there are no more keys left to watch, we can break out
2519[warn] if (keyRoots.isEmpty()) {
2520[warn] logger.debug("No more directories left to watch; terminating watcher.");
2521[warn] break;
2522[warn] }
2523[warn] }
2524[warn] }
2525[warn] try {
2526[warn] close();
2527[warn] } catch (IOException e) {
2528[warn] throw new UncheckedIOException(e);
2529[warn] }
2530[warn] }
2531[warn]
2532[warn] private void onEvent(
2533[warn] EventType eventType, boolean isDirectory, Path childPath, int count, Path rootPath)
2534[warn] throws IOException {
2535[warn] logger.debug("-> {} [{}] (isDirectory: {})", eventType, childPath, isDirectory);
2536[warn] FileHash hash = pathHashes.get(childPath);
2537[warn] listener.onEvent(
2538[warn] new DirectoryChangeEvent(eventType, isDirectory, childPath, hash, count, rootPath));
2539[warn] }
2540[warn]
2541[warn] private void registerAll(final Path start, final Path context) throws IOException {
2542[warn] if (!Boolean.FALSE.equals(fileTreeSupported)) {
2543[warn] // Try using FILE_TREE modifier since we aren't certain that it's unsupported
2544[warn] try {
2545[warn] register(start, true, context);
2546[warn] // Assume FILE_TREE is supported
2547[warn] fileTreeSupported = true;
2548[warn] } catch (UnsupportedOperationException e) {
2549[warn] // UnsupportedOperationException should only happen if FILE_TREE is unsupported
2550[warn] logger.debug("Assuming ExtendedWatchEventModifier.FILE_TREE is not supported", e);
2551[warn] fileTreeSupported = false;
2552[warn] // If we failed to use the FILE_TREE modifier, try again without
2553[warn] registerAll(start, context);
2554[warn] }
2555[warn] } else {
2556[warn] // Since FILE_TREE is unsupported, register root directory and sub-directories
2557[warn] fileTreeVisitor.recursiveVisitFiles(start, dir -> register(dir, false, context), file -> {});
2558[warn] }
2559[warn] }
2560[warn]
2561[warn] // Internal method to be used by registerAll
2562[warn] private void register(Path directory, boolean useFileTreeModifier, Path context)
2563[warn] throws IOException {
2564[warn] logger.debug("Registering [{}].", directory);
2565[warn] Watchable watchable = isMac ? new WatchablePath(directory) : directory;
2566[warn] WatchEvent.Modifier[] modifiers =
2567[warn] useFileTreeModifier
2568[warn] ? new WatchEvent.Modifier[] {ExtendedWatchEventModifier.FILE_TREE}
2569[warn] : new WatchEvent.Modifier[] {};
2570[warn] WatchEvent.Kind<?>[] kinds =
2571[warn] new WatchEvent.Kind<?>[] {ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY};
2572[warn] WatchKey watchKey = watchable.register(watchService, kinds, modifiers);
2573[warn] keyRoots.put(watchKey, directory);
2574[warn] registeredPathToRootPath.put(directory, context);
2575[warn] }
2576[warn]
2577[warn] private void notifyCreateEvent(boolean isDirectory, Path path, int count, Path rootPath)
2578[warn] throws IOException {
2579[warn] if (fileHasher != null) {
2580[warn] FileHash newHash = PathUtils.hash(fileHasher, path);
2581[warn] if (newHash == null) {
2582[warn] // Hashing could fail for locked files on Windows.
2583[warn] // Skip notification only if we confirm the file does not exist.
2584[warn] if (Files.notExists(path)) {
2585[warn] logger.debug("Failed to hash created file [{}]. It may have been deleted.", path);
2586[warn] // Skip notifying the event.
2587[warn] return;
2588[warn] } else {
2589[warn] // Just warn here and continue to notify the event.
2590[warn] logger.debug("Failed to hash created file [{}]. It may be locked.", path);
2591[warn] }
2592[warn] } else {
2593[warn] FileHash oldHash = pathHashes.put(path, newHash);
2594[warn] if (oldHash != null) {
2595[warn] if (oldHash == newHash) {
2596[warn] // Creates might occur just before we traverse and notify for files in a new directory.
2597[warn] // We generally want to skip the duplicate if the hash has not changed.
2598[warn] logger.debug("Skipping duplicate create event for file [{}].", path);
2599[warn] return;
2600[warn] } else {
2601[warn] // This might happen if events were discarded and perhaps we missed a DELETE event.
2602[warn] logger.debug("Sending MODIFY instead of CREATE for existing hashed file [{}].", path);
2603[warn] onEvent(EventType.MODIFY, isDirectory, path, count, rootPath);
2604[warn] return;
2605[warn] }
2606[warn] }
2607[warn] }
2608[warn] }
2609[warn] if (isDirectory) {
2610[warn] directories.add(path);
2611[warn] }
2612[warn] onEvent(EventType.CREATE, isDirectory, path, count, rootPath);
2613[warn] }
2614[warn] }
2615[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:195:1: no comment
2616[warn] public DirectoryWatcher(
2617[warn] List<Path> paths,
2618[warn] DirectoryChangeListener listener,
2619[warn] WatchService watchService,
2620[warn] FileHasher fileHasher,
2621[warn] FileTreeVisitor fileTreeVisitor,
2622[warn] Logger logger) {
2623[warn] this.paths = paths.stream().map(p -> p.toAbsolutePath()).collect(Collectors.toList());
2624[warn] this.listener = listener;
2625[warn] this.watchService = watchService;
2626[warn] this.isMac = watchService instanceof MacOSXListeningWatchService;
2627[warn] this.fileHasher = fileHasher;
2628[warn] this.fileTreeVisitor = fileTreeVisitor;
2629[warn] this.logger = logger;
2630[warn] }
2631[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:261:1: no comment
2632[warn] public void close() throws IOException {
2633[warn] watchService.close();
2634[warn] closed = true;
2635[warn] }
2636[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:257:1: no comment
2637[warn] public DirectoryChangeListener getListener() {
2638[warn] return listener;
2639[warn] }
2640[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:266:1: no comment
2641[warn] public boolean isClosed() {
2642[warn] return closed;
2643[warn] }
2644[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:253:1: no comment
2645[warn] public Map<Path, FileHash> pathHashes() {
2646[warn] return Collections.unmodifiableMap(pathHashes);
2647[warn] }
2648[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:63:1: no @param for paths
2649[warn] public Builder paths(List<Path> paths) {
2650[warn] this.paths = paths;
2651[warn] return this;
2652[warn] }
2653[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:69:1: no @param for path
2654[warn] public Builder path(Path path) {
2655[warn] return paths(Collections.singletonList(path));
2656[warn] }
2657[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:74:1: no @param for listener
2658[warn] public Builder listener(DirectoryChangeListener listener) {
2659[warn] this.listener = listener;
2660[warn] return this;
2661[warn] }
2662[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:85:1: no @param for watchService
2663[warn] public Builder watchService(WatchService watchService) {
2664[warn] this.watchService = watchService;
2665[warn] return this;
2666[warn] }
2667[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:94:1: no @param for logger
2668[warn] public Builder logger(Logger logger) {
2669[warn] this.logger = logger;
2670[warn] return this;
2671[warn] }
2672[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:103:1: no @param for enabled
2673[warn] public Builder fileHashing(boolean enabled) {
2674[warn] this.fileHasher = enabled ? FileHasher.DEFAULT_FILE_HASHER : null;
2675[warn] return this;
2676[warn] }
2677[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:114:1: no @param for fileHasher
2678[warn] public Builder fileHasher(FileHasher fileHasher) {
2679[warn] this.fileHasher = fileHasher;
2680[warn] return this;
2681[warn] }
2682[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:120:1: no @param for fileTreeVisitor
2683[warn] public Builder fileTreeVisitor(FileTreeVisitor fileTreeVisitor) {
2684[warn] this.fileTreeVisitor = fileTreeVisitor;
2685[warn] return this;
2686[warn] }
2687[warn] /build/repo/core/src/main/java/io/methvin/watcher/DirectoryWatcher.java:125:1: no comment
2688[warn] public DirectoryWatcher build() throws IOException {
2689[warn] if (fileTreeVisitor == null) {
2690[warn] fileTreeVisitor = FileTreeVisitor.DEFAULT_FILE_TREE_VISITOR;
2691[warn] }
2692[warn] if (watchService == null) {
2693[warn] osDefaultWatchService(fileTreeVisitor);
2694[warn] }
2695[warn] if (logger == null) {
2696[warn] staticLogger();
2697[warn] }
2698[warn] return new DirectoryWatcher(
2699[warn] paths, listener, watchService, fileHasher, fileTreeVisitor, logger);
2700[warn] }
2701[warn] /build/repo/core/src/main/java/io/methvin/watcher/hashing/FileHash.java:40:1: no comment
2702[warn] public static FileHash directory() {
2703[warn] return DIRECTORY;
2704[warn] }
2705[warn] /build/repo/core/src/main/java/io/methvin/watcher/hashing/FileHash.java:30:1: no comment
2706[warn] public static FileHash fromBytes(byte[] value) {
2707[warn] return new ByteArrayFileHash(Arrays.copyOf(value, value.length));
2708[warn] }
2709[warn] /build/repo/core/src/main/java/io/methvin/watcher/hashing/FileHash.java:34:1: no comment
2710[warn] public static FileHash fromLong(long value) {
2711[warn] ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
2712[warn] buffer.putLong(value);
2713[warn] return new ByteArrayFileHash(buffer.array());
2714[warn] }
2715[warn] /build/repo/core/src/main/java/io/methvin/watcher/hashing/FileHasher.java:63:1: no comment
2716[warn] FileHash hash(Path path) throws IOException;
2717[warn] /build/repo/core/src/main/java/io/methvin/watcher/visitor/FileTreeVisitor.java:7:1: no comment
2718[warn] public interface FileTreeVisitor {
2719[warn]
2720[warn] /** The default file tree visitor instance, which uses Files.walkFileTree. */
2721[warn] FileTreeVisitor DEFAULT_FILE_TREE_VISITOR = new DefaultFileTreeVisitor();
2722[warn]
2723[warn] interface Callback {
2724[warn] void call(Path p) throws IOException;
2725[warn] }
2726[warn]
2727[warn] void recursiveVisitFiles(Path file, Callback onDirectory, Callback onFile) throws IOException;
2728[warn] }
2729[warn] /build/repo/core/src/main/java/io/methvin/watcher/visitor/FileTreeVisitor.java:12:1: no comment
2730[warn] interface Callback {
2731[warn] void call(Path p) throws IOException;
2732[warn] }
2733[warn] /build/repo/core/src/main/java/io/methvin/watcher/visitor/FileTreeVisitor.java:13:1: no comment
2734[warn] void call(Path p) throws IOException;
2735[warn] /build/repo/core/src/main/java/io/methvin/watchservice/jna/FSEventStreamRef.java:18:1: no comment
2736[warn] public class FSEventStreamRef extends PointerByReference {}
2737[warn] /build/repo/core/src/main/java/io/methvin/watchservice/MacOSXListeningWatchService.java:172:1: no comment
2738[warn] public static class CFRunLoopThread extends Thread {
2739[warn] private final FSEventStreamRef streamRef;
2740[warn] private CFRunLoopRef runLoopRef;
2741[warn] private boolean isClosed = false;
2742[warn]
2743[warn] public CFRunLoopThread(FSEventStreamRef streamRef, File file) {
2744[warn] super("WatchService for " + file);
2745[warn] this.streamRef = streamRef;
2746[warn] }
2747[warn]
2748[warn] @Override
2749[warn] public void run() {
2750[warn] synchronized (streamRef) {
2751[warn] if (isClosed) return;
2752[warn] runLoopRef = CarbonAPI.INSTANCE.CFRunLoopGetCurrent();
2753[warn] final CFStringRef runLoopMode = CFStringRef.toCFString("kCFRunLoopDefaultMode");
2754[warn] CarbonAPI.INSTANCE.FSEventStreamScheduleWithRunLoop(streamRef, runLoopRef, runLoopMode);
2755[warn] CarbonAPI.INSTANCE.FSEventStreamStart(streamRef);
2756[warn] }
2757[warn] CarbonAPI.INSTANCE.CFRunLoopRun();
2758[warn] }
2759[warn]
2760[warn] public void close() {
2761[warn] synchronized (streamRef) {
2762[warn] if (isClosed) return;
2763[warn] if (runLoopRef != null) {
2764[warn] CarbonAPI.INSTANCE.CFRunLoopStop(runLoopRef);
2765[warn] CarbonAPI.INSTANCE.FSEventStreamStop(streamRef);
2766[warn] CarbonAPI.INSTANCE.FSEventStreamInvalidate(streamRef);
2767[warn] }
2768[warn] CarbonAPI.INSTANCE.FSEventStreamRelease(streamRef);
2769[warn] isClosed = true;
2770[warn] }
2771[warn] }
2772[warn] }
2773[warn] /build/repo/core/src/main/java/io/methvin/watchservice/MacOSXListeningWatchService.java:118:1: no comment
2774[warn] public MacOSXListeningWatchService() {
2775[warn] this(new Config() {});
2776[warn] }
2777[warn] /build/repo/core/src/main/java/io/methvin/watchservice/MacOSXListeningWatchService.java:109:1: no comment
2778[warn] public MacOSXListeningWatchService(Config config) {
2779[warn] this.latency = config.latency();
2780[warn] this.queueSize = config.queueSize();
2781[warn] this.fileTreeVisitor = config.fileTreeVisitor();
2782[warn] FileHasher hasher = config.fileHasher();
2783[warn] this.fileLevelEvents = hasher == null || config.fileLevelEvents();
2784[warn] this.fileHasher = hasher == null ? INCREMENTING_FILE_HASHER : hasher;
2785[warn] }
2786[warn] /build/repo/core/src/main/java/io/methvin/watchservice/AbstractWatchService.java:69:1: no @param for key
2787[warn] public void cancelled(AbstractWatchKey key) {}
2788[warn] /build/repo/core/src/main/java/io/methvin/watchservice/MacOSXListeningWatchService.java:217:1: no comment
2789[warn] public synchronized void close(
2790[warn] CFRunLoopThread runLoopThread, CarbonAPI.FSEventStreamCallback callback, Path path) {
2791[warn] threadList.remove(runLoopThread);
2792[warn] callbackList.remove(callback);
2793[warn] pathsWatching.remove(path);
2794[warn] runLoopThread.close();
2795[warn] }
2796[warn] /build/repo/core/src/main/java/io/methvin/watchservice/AbstractWatchService.java:57:1: no @return
2797[warn] public boolean isOpen() {
2798[warn] return open.get();
2799[warn] }
2800[warn] /build/repo/core/src/main/java/io/methvin/watchservice/AbstractWatchService.java:52:1: no @param for watchable
2801[warn] public abstract AbstractWatchKey register(
2802[warn] WatchablePath watchable, Iterable<? extends WatchEvent.Kind<?>> eventTypes)
2803[warn] throws IOException;
2804[info] 100 warnings
2805[warn] Loading source file DirectoryWatcher.java...
2806[warn] Loading source file DirectoryChangeListener.java...
2807[warn] Loading source file DirectoryChangeEvent.java...
2808[warn] Loading source file PathUtils.java...
2809[warn] Loading source file OnTimeoutListener.java...
2810[warn] Loading source file AbstractWatchService.java...
2811[warn] Loading source file MacOSXWatchKey.java...
2812[warn] Loading source file AbstractWatchKey.java...
2813[warn] Loading source file MacOSXListeningWatchService.java...
2814[warn] Loading source file WatchablePath.java...
2815[warn] Loading source file ByteArrayFileHash.java...
2816[warn] Loading source file Murmur3F.java...
2817[warn] Loading source file FileHash.java...
2818[warn] Loading source file FileHasher.java...
2819[warn] Loading source file DefaultFileTreeVisitor.java...
2820[warn] Loading source file FileTreeVisitor.java...
2821[warn] Loading source file ChangeSetEntry.java...
2822[warn] Loading source file ChangeSetListener.java...
2823[warn] Loading source file ChangeSet.java...
2824[warn] Loading source file ChangeSetBuilder.java...
2825[warn] Loading source file ChangeSetImpl.java...
2826[warn] Loading source file CFArrayRef.java...
2827[warn] Loading source file CFIndex.java...
2828[warn] Loading source file CFAllocatorRef.java...
2829[warn] Loading source file FSEventStreamRef.java...
2830[warn] Loading source file CarbonAPI.java...
2831[warn] Loading source file CFStringRef.java...
2832[warn] Loading source file CFRunLoopRef.java...
2833[warn] Constructing Javadoc information...
2834[warn] Building index for all the packages and classes...
2835[warn] Standard Doclet version 17.0.8+7
2836[warn] Building tree for all the packages and classes...
2837[warn] Generating /build/repo/core/target/api/io/methvin/watchservice/jna/CarbonAPI.html...
2838[warn] Generating /build/repo/core/target/api/io/methvin/watchservice/jna/CarbonAPI.FSEventStreamCallback.html...
2839[warn] Generating /build/repo/core/target/api/io/methvin/watchservice/jna/CFAllocatorRef.html...
2840[warn] Generating /build/repo/core/target/api/io/methvin/watchservice/jna/CFArrayRef.html...
2841[warn] Generating /build/repo/core/target/api/io/methvin/watchservice/jna/CFIndex.html...
2842[warn] Generating /build/repo/core/target/api/io/methvin/watchservice/jna/CFRunLoopRef.html...
2843[warn] Generating /build/repo/core/target/api/io/methvin/watchservice/jna/CFStringRef.html...
2844[warn] Generating /build/repo/core/target/api/io/methvin/watcher/changeset/ChangeSet.html...
2845[warn] Generating /build/repo/core/target/api/io/methvin/watcher/changeset/ChangeSetEntry.html...
2846[warn] Generating /build/repo/core/target/api/io/methvin/watcher/changeset/ChangeSetListener.html...
2847[warn] Generating /build/repo/core/target/api/io/methvin/watcher/visitor/DefaultFileTreeVisitor.html...
2848[warn] Generating /build/repo/core/target/api/io/methvin/watcher/DirectoryChangeEvent.html...
2849[warn] Generating /build/repo/core/target/api/io/methvin/watcher/DirectoryChangeEvent.EventType.html...
2850[warn] Generating /build/repo/core/target/api/io/methvin/watcher/DirectoryChangeListener.html...
2851[warn] Generating /build/repo/core/target/api/io/methvin/watcher/DirectoryWatcher.html...
2852[warn] Generating /build/repo/core/target/api/io/methvin/watcher/DirectoryWatcher.Builder.html...
2853[warn] Generating /build/repo/core/target/api/io/methvin/watcher/hashing/FileHash.html...
2854[warn] Generating /build/repo/core/target/api/io/methvin/watcher/hashing/FileHasher.html...
2855[warn] Generating /build/repo/core/target/api/io/methvin/watcher/visitor/FileTreeVisitor.html...
2856[warn] Generating /build/repo/core/target/api/io/methvin/watcher/visitor/FileTreeVisitor.Callback.html...
2857[warn] Generating /build/repo/core/target/api/io/methvin/watchservice/jna/FSEventStreamRef.html...
2858[warn] Generating /build/repo/core/target/api/io/methvin/watchservice/MacOSXListeningWatchService.html...
2859[warn] Generating /build/repo/core/target/api/io/methvin/watchservice/MacOSXListeningWatchService.CFRunLoopThread.html...
2860[warn] Generating /build/repo/core/target/api/io/methvin/watchservice/MacOSXListeningWatchService.Config.html...
2861[warn] Generating /build/repo/core/target/api/io/methvin/watcher/hashing/Murmur3F.html...
2862[warn] Generating /build/repo/core/target/api/io/methvin/watcher/OnTimeoutListener.html...
2863[warn] Generating /build/repo/core/target/api/io/methvin/watcher/PathUtils.html...
2864[warn] Generating /build/repo/core/target/api/io/methvin/watchservice/WatchablePath.html...
2865[warn] Generating /build/repo/core/target/api/io/methvin/watcher/package-summary.html...
2866[warn] Generating /build/repo/core/target/api/io/methvin/watcher/package-tree.html...
2867[warn] Generating /build/repo/core/target/api/io/methvin/watcher/changeset/package-summary.html...
2868[warn] Generating /build/repo/core/target/api/io/methvin/watcher/changeset/package-tree.html...
2869[warn] Generating /build/repo/core/target/api/io/methvin/watcher/hashing/package-summary.html...
2870[warn] Generating /build/repo/core/target/api/io/methvin/watcher/hashing/package-tree.html...
2871[warn] Generating /build/repo/core/target/api/io/methvin/watcher/visitor/package-summary.html...
2872[warn] Generating /build/repo/core/target/api/io/methvin/watcher/visitor/package-tree.html...
2873[warn] Generating /build/repo/core/target/api/io/methvin/watchservice/package-summary.html...
2874[warn] Generating /build/repo/core/target/api/io/methvin/watchservice/package-tree.html...
2875[warn] Generating /build/repo/core/target/api/io/methvin/watchservice/jna/package-summary.html...
2876[warn] Generating /build/repo/core/target/api/io/methvin/watchservice/jna/package-tree.html...
2877[warn] Generating /build/repo/core/target/api/constant-values.html...
2878[warn] Generating /build/repo/core/target/api/serialized-form.html...
2879[warn] Generating /build/repo/core/target/api/overview-tree.html...
2880[warn] Generating /build/repo/core/target/api/index.html...
2881[warn] Building index for all classes...
2882[warn] Generating /build/repo/core/target/api/allclasses-index.html...
2883[warn] Generating /build/repo/core/target/api/allpackages-index.html...
2884[warn] Generating /build/repo/core/target/api/index-all.html...
2885[warn] Generating /build/repo/core/target/api/overview-summary.html...
2886[warn] Generating /build/repo/core/target/api/help-doc.html...
2887[info] Main Java API documentation successful.
2888[info] :: delivering :: io.methvin#directory-watcher;0.18.0 :: 0.18.0 :: release :: Sat Apr 12 01:45:44 CEST 2025
2889[info] delivering ivy file to /build/repo/core/target/ivy-0.18.0.xml
2890[info] published directory-watcher to /root/.ivy2/local/io.methvin/directory-watcher/0.18.0/poms/directory-watcher.pom
2891[info] published directory-watcher to /root/.ivy2/local/io.methvin/directory-watcher/0.18.0/jars/directory-watcher.jar
2892[info] published directory-watcher to /root/.ivy2/local/io.methvin/directory-watcher/0.18.0/srcs/directory-watcher-sources.jar
2893[info] published directory-watcher to /root/.ivy2/local/io.methvin/directory-watcher/0.18.0/docs/directory-watcher-javadoc.jar
2894[info] published ivy to /root/.ivy2/local/io.methvin/directory-watcher/0.18.0/ivys/ivy.xml
2895
2896************************
2897Build summary:
2898[{
2899 "module": "directory-watcher-better-files",
2900 "compile": {"status": "ok", "tookMs": 8104, "warnings": 0, "errors": 0, "sourceVersion": "3.7-migration"},
2901 "doc": {"status": "ok", "tookMs": 1390, "files": 336, "totalSizeKb": 6297},
2902 "test-compile": {"status": "ok", "tookMs": 2752, "warnings": 0, "errors": 0, "sourceVersion": "3.7-migration"},
2903 "test": {"status": "skipped", "tookMs": 0, "passed": 0, "failed": 0, "ignored": 0, "skipped": 0, "total": 0, "byFramework": []},
2904 "publish": {"status": "ok", "tookMs": 989},
2905 "metadata": {
2906 "crossScalaVersions": ["3.2.2", "2.13.10", "2.12.10"]
2907}
2908},{
2909 "module": "directory-watcher",
2910 "compile": {"status": "ok", "tookMs": 47, "warnings": 0, "errors": 0, "sourceVersion": "3.7-migration"},
2911 "doc": {"status": "ok", "tookMs": 988, "files": 69, "totalSizeKb": 781},
2912 "test-compile": {"status": "ok", "tookMs": 603, "warnings": 0, "errors": 0, "sourceVersion": "3.7-migration"},
2913 "test": {"status": "skipped", "tookMs": 0, "passed": 0, "failed": 0, "ignored": 0, "skipped": 0, "total": 0, "byFramework": []},
2914 "publish": {"status": "ok", "tookMs": 561},
2915 "metadata": {
2916 "crossScalaVersions": ["3.2.2"]
2917}
2918}]
2919************************
2920[success] Total time: 24 s, completed Apr 12, 2025, 1:45:44 AM
2921Checking patch project/plugins.sbt...
2922Checking patch project/build.properties...
2923Checking patch build.sbt...
2924Applied patch project/plugins.sbt cleanly.
2925Applied patch project/build.properties cleanly.
2926Applied patch build.sbt cleanly.