Build Logs

gmethvin/directory-watcher • 3.7.0-RC2:2025-04-09

Errors

94

Warnings

2600

Total Lines

2988

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