@@ -74,15 +74,7 @@ object Watching {
74
74
if (alreadyStale) {
75
75
enterKeyPressed = false
76
76
} else {
77
- enterKeyPressed = watchAndWait(
78
- streams,
79
- watchArgs.setIdle,
80
- streams.in,
81
- watchables,
82
- watchArgs.colors,
83
- useNotify = watchArgs.useNotify,
84
- serverDir = watchArgs.serverDir
85
- )
77
+ enterKeyPressed = watchAndWait(streams, streams.in, watchables, watchArgs)
86
78
}
87
79
}
88
80
throw new IllegalStateException (" unreachable" )
@@ -91,14 +83,11 @@ object Watching {
91
83
92
84
def watchAndWait (
93
85
streams : SystemStreams ,
94
- setIdle : Boolean => Unit ,
95
86
stdin : InputStream ,
96
87
watched : Seq [Watchable ],
97
- colors : Colors ,
98
- useNotify : Boolean ,
99
- serverDir : os.Path
88
+ watchArgs : WatchArgs
100
89
): Boolean = {
101
- setIdle(true )
90
+ watchArgs. setIdle(true )
102
91
val (watchedPollables, watchedPathsSeq) = watched.partitionMap {
103
92
case w : Watchable .Value => Left (w)
104
93
case p : Watchable .Path => Right (p)
@@ -111,82 +100,96 @@ object Watching {
111
100
112
101
streams.err.println {
113
102
val viaFsNotify = if (useNotify) " (via fsnotify)" else " "
114
- colors.info(
103
+ watchArgs. colors.info(
115
104
s " Watching for changes to ${watchedPathsSeq.size} paths $viaFsNotify$watchedValueStr... (Enter to re-run, Ctrl-C to exit) "
116
105
).toString
117
106
}
118
107
119
108
def doWatch (notifiablesChanged : () => Boolean ) = {
120
109
val enterKeyPressed = statWatchWait(watchedPollables, stdin, notifiablesChanged)
121
- setIdle(false )
110
+ watchArgs. setIdle(false )
122
111
enterKeyPressed
123
112
}
124
113
125
- if (useNotify) Using .resource(os.write.outputStream(serverDir / " fsNotifyWatchLog" )) { watchLog =>
126
- def writeToWatchLog (s : String ): Unit = {
127
- watchLog.write(s.getBytes(java.nio.charset.StandardCharsets .UTF_8 ))
128
- watchLog.write('\n ' )
129
- }
114
+ def doWatchPolling () =
115
+ doWatch(notifiablesChanged = () => watchedPathsSeq.exists(p => ! p.validate()))
130
116
131
- @ volatile var pathChangesDetected = false
117
+ def doWatchFsNotify () = {
118
+ Using .resource(os.write.outputStream(watchArgs.serverDir / " fsNotifyWatchLog" )) { watchLog =>
119
+ def writeToWatchLog (s : String ): Unit = {
120
+ watchLog.write(s.getBytes(java.nio.charset.StandardCharsets .UTF_8 ))
121
+ watchLog.write('\n ' )
122
+ }
132
123
133
- // oslib watch only works with folders, so we have to watch the parent folders instead
124
+ @ volatile var pathChangesDetected = false
134
125
135
- writeToWatchLog( s " [watched-paths:unfiltered] ${watchedPathsSet.toSeq.sorted.mkString( " \n " )} " )
126
+ // oslib watch only works with folders, so we have to watch the parent folders instead
136
127
137
- val workspaceRoot = mill.api.WorkspaceRoot .workspaceRoot
128
+ writeToWatchLog(
129
+ s " [watched-paths:unfiltered] ${watchedPathsSet.toSeq.sorted.mkString(" \n " )}"
130
+ )
138
131
139
- /** Paths that are descendants of [[workspaceRoot ]]. */
140
- val pathsUnderWorkspaceRoot = watchedPathsSet.filter { path =>
141
- val isUnderWorkspaceRoot = path.startsWith(workspaceRoot)
142
- if (! isUnderWorkspaceRoot) {
143
- streams.err.println(colors.error(
144
- s " Watched path $path is outside workspace root $workspaceRoot, this is unsupported. "
145
- ).toString())
146
- }
147
-
148
- isUnderWorkspaceRoot
149
- }
132
+ val workspaceRoot = mill.api.WorkspaceRoot .workspaceRoot
150
133
151
- // If I have 'root/a/b/c'
152
- //
153
- // Then I want to watch:
154
- // root/a/b/c
155
- // root/a/b
156
- // root/a
157
- // root
158
- val filterPaths = pathsUnderWorkspaceRoot.flatMap { path =>
159
- path.relativeTo(workspaceRoot).segments.inits.map(segments => workspaceRoot / segments)
160
- }
161
- writeToWatchLog(s " [watched-paths:filtered] ${filterPaths.toSeq.sorted.mkString(" \n " )}" )
162
-
163
- Using .resource(os.watch.watch(
164
- // Just watch the root folder
165
- Seq (workspaceRoot),
166
- filter = path => {
167
- val shouldBeWatched =
168
- filterPaths.contains(path) || watchedPathsSet.exists(watchedPath => path.startsWith(watchedPath))
169
- writeToWatchLog(s " [filter] (shouldBeWatched= $shouldBeWatched) $path" )
170
- shouldBeWatched
171
- },
172
- onEvent = changedPaths => {
173
- // Make sure that the changed paths are actually the ones in our watch list and not some adjacent files in the
174
- // same folder
175
- val hasWatchedPath =
176
- changedPaths.exists(p => watchedPathsSet.exists(watchedPath => p.startsWith(watchedPath)))
177
- writeToWatchLog(s " [changed-paths] (hasWatchedPath= $hasWatchedPath) ${changedPaths.mkString(" \n " )}" )
178
- if (hasWatchedPath) {
179
- pathChangesDetected = true
134
+ /** Paths that are descendants of [[workspaceRoot ]]. */
135
+ val pathsUnderWorkspaceRoot = watchedPathsSet.filter { path =>
136
+ val isUnderWorkspaceRoot = path.startsWith(workspaceRoot)
137
+ if (! isUnderWorkspaceRoot) {
138
+ streams.err.println(watchArgs.colors.error(
139
+ s " Watched path $path is outside workspace root $workspaceRoot, this is unsupported. "
140
+ ).toString())
180
141
}
181
- },
182
- logger = (eventType, data) => writeToWatchLog(s " [watch:event] $eventType: ${pprint.apply(data).plainText}" )
183
- )) { _ =>
184
- doWatch(notifiablesChanged = () => pathChangesDetected)
142
+
143
+ isUnderWorkspaceRoot
144
+ }
145
+
146
+ // If I have 'root/a/b/c'
147
+ //
148
+ // Then I want to watch:
149
+ // root/a/b/c
150
+ // root/a/b
151
+ // root/a
152
+ // root
153
+ val filterPaths = pathsUnderWorkspaceRoot.flatMap { path =>
154
+ path.relativeTo(workspaceRoot).segments.inits.map(segments => workspaceRoot / segments)
155
+ }
156
+ writeToWatchLog(s " [watched-paths:filtered] ${filterPaths.toSeq.sorted.mkString(" \n " )}" )
157
+
158
+ Using .resource(os.watch.watch(
159
+ // Just watch the root folder
160
+ Seq (workspaceRoot),
161
+ filter = path => {
162
+ val shouldBeWatched =
163
+ filterPaths.contains(path) || watchedPathsSet.exists(watchedPath =>
164
+ path.startsWith(watchedPath)
165
+ )
166
+ writeToWatchLog(s " [filter] (shouldBeWatched= $shouldBeWatched) $path" )
167
+ shouldBeWatched
168
+ },
169
+ onEvent = changedPaths => {
170
+ // Make sure that the changed paths are actually the ones in our watch list and not some adjacent files in the
171
+ // same folder
172
+ val hasWatchedPath =
173
+ changedPaths.exists(p =>
174
+ watchedPathsSet.exists(watchedPath => p.startsWith(watchedPath))
175
+ )
176
+ writeToWatchLog(
177
+ s " [changed-paths] (hasWatchedPath= $hasWatchedPath) ${changedPaths.mkString(" \n " )}"
178
+ )
179
+ if (hasWatchedPath) {
180
+ pathChangesDetected = true
181
+ }
182
+ },
183
+ logger = (eventType, data) =>
184
+ writeToWatchLog(s " [watch:event] $eventType: ${pprint.apply(data).plainText}" )
185
+ )) { _ =>
186
+ doWatch(notifiablesChanged = () => pathChangesDetected)
187
+ }
185
188
}
186
189
}
187
- else {
188
- doWatch(notifiablesChanged = () => watchedPathsSeq.exists(p => ! p.validate()) )
189
- }
190
+
191
+ if (watchArgs.useNotify) doWatchFsNotify( )
192
+ else doWatchPolling()
190
193
}
191
194
192
195
/**
0 commit comments