Skip to content

Commit 246ce10

Browse files
committed
Hacking.
1 parent 733cdfa commit 246ce10

File tree

4 files changed

+195
-162
lines changed

4 files changed

+195
-162
lines changed

pkgs/watcher/lib/src/directory_watcher/linux.dart

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -163,30 +163,35 @@ class _LinuxDirectoryWatcher
163163

164164
changed.add(event.path);
165165

166-
if (event.isMove) {
167-
files.remove(event.path);
168-
dirs.remove(event.path);
169-
170-
var destination = event.destination;
171-
if (destination == null) continue;
166+
switch (event.type) {
167+
case EventType.moveFile:
168+
files.remove(event.path);
169+
var destination = event.destination;
170+
if (destination == null) continue;
171+
changed.add(destination);
172+
files.add(destination);
173+
dirs.remove(destination);
172174

173-
changed.add(destination);
174-
if (event.isDirectory!) {
175+
case EventType.moveDirectory:
176+
dirs.remove(event.path);
177+
var destination = event.destination;
178+
if (destination == null) continue;
175179
files.remove(destination);
176180
dirs.add(destination);
177-
} else {
178-
files.add(destination);
179-
dirs.remove(destination);
180-
}
181-
} else if (event is FileSystemDeleteEvent) {
182-
files.remove(event.path);
183-
dirs.remove(event.path);
184-
} else if (event.isDirectory!) {
185-
files.remove(event.path);
186-
dirs.add(event.path);
187-
} else {
188-
files.add(event.path);
189-
dirs.remove(event.path);
181+
182+
case EventType.delete:
183+
files.remove(event.path);
184+
dirs.remove(event.path);
185+
186+
case EventType.createFile:
187+
case EventType.modifyFile:
188+
files.add(event.path);
189+
dirs.remove(event.path);
190+
191+
case EventType.createDirectory:
192+
case EventType.modifyDirectory:
193+
files.remove(event.path);
194+
dirs.add(event.path);
190195
}
191196
}
192197

pkgs/watcher/lib/src/directory_watcher/mac_os.dart

Lines changed: 79 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,8 @@ class _MacOSDirectoryWatcher
133133
: [canonicalEvent];
134134

135135
for (var event in events) {
136-
if (event.isCreate) {
137-
if (!event.isDirectory!) {
136+
switch (event.type) {
137+
case EventType.createFile:
138138
// If we already know about the file, treat it like a modification.
139139
// This can happen if a file is copied on top of an existing one.
140140
// We'll see an ADD event for the latter file when from the user's
@@ -144,47 +144,55 @@ class _MacOSDirectoryWatcher
144144

145145
_emitEvent(type, path);
146146
_files.add(path);
147-
continue;
148-
}
149-
150-
if (_files.containsDir(path)) continue;
151-
152-
var stream = Directory(path)
153-
.list(recursive: true)
154-
.ignoring<PathNotFoundException>();
155-
var subscription = stream.listen((entity) {
156-
if (entity is Directory) return;
157-
if (_files.contains(path)) return;
158-
159-
_emitEvent(ChangeType.ADD, entity.path);
160-
_files.add(entity.path);
161-
}, cancelOnError: true);
162-
subscription.onDone(() {
163-
_listSubscriptions.remove(subscription);
164-
});
165-
subscription.onError(_emitError);
166-
_listSubscriptions.add(subscription);
167-
} else if (event.isModify) {
168-
assert(!event.isDirectory!);
169-
_emitEvent(ChangeType.MODIFY, path);
170-
} else {
171-
assert(event.isDelete);
172-
for (var removedPath in _files.remove(path)) {
173-
_emitEvent(ChangeType.REMOVE, removedPath);
174-
}
147+
148+
case EventType.createDirectory:
149+
if (_files.containsDir(path)) continue;
150+
151+
var stream = Directory(path)
152+
.list(recursive: true)
153+
.ignoring<PathNotFoundException>();
154+
var subscription = stream.listen((entity) {
155+
if (entity is Directory) return;
156+
if (_files.contains(path)) return;
157+
158+
_emitEvent(ChangeType.ADD, entity.path);
159+
_files.add(entity.path);
160+
}, cancelOnError: true);
161+
subscription.onDone(() {
162+
_listSubscriptions.remove(subscription);
163+
});
164+
subscription.onError(_emitError);
165+
_listSubscriptions.add(subscription);
166+
167+
case EventType.modifyFile:
168+
_emitEvent(ChangeType.MODIFY, path);
169+
170+
case EventType.delete:
171+
for (var removedPath in _files.remove(path)) {
172+
_emitEvent(ChangeType.REMOVE, removedPath);
173+
}
174+
175+
// Guaranteed not present by `_sortEvents`.
176+
case EventType.moveFile:
177+
case EventType.moveDirectory:
178+
case EventType.modifyDirectory:
179+
throw StateError(event.type.name);
175180
}
176181
}
177182
});
178183
}
179184

180185
/// Sort all the events in a batch into sets based on their path.
181186
///
182-
/// A single input event may result in multiple events in the returned map;
183-
/// for example, a MOVE event becomes a DELETE event for the source and a
184-
/// CREATE event for the destination.
187+
/// Events for `path` are discarded.
188+
///
189+
/// Events under directories that are created or modified are discarded.
185190
///
186-
/// The returned events won't contain any [FileSystemMoveEvent]s, nor will it
187-
/// contain any events relating to [path].
191+
/// Three event types are not expected on MacOS, if encountered they will be
192+
/// dropped with an assert fail to signal in tests. The types are:
193+
/// [EventType.moveFile], [EventType.moveDirectory] and
194+
/// [EventType.modifyDirectory]. See
195+
/// https://github.com/dart-lang/sdk/issues/14806.
188196
Map<String, Set<Event>> _sortEvents(List<Event> batch) {
189197
var eventsForPaths = <String, Set<Event>>{};
190198

@@ -193,25 +201,29 @@ class _MacOSDirectoryWatcher
193201
// really deleted, that's handled by [_onDone].
194202
batch = batch.where((event) => event.path != path).toList();
195203

196-
// Events within directories that already have events are superfluous; the
197-
// directory's full contents will be examined anyway, so we ignore such
198-
// events. Emitting them could cause useless or out-of-order events.
199-
var directories = unionAll(batch.map((event) {
200-
if (event.isDelete || !event.isDirectory!) return <String>{};
201-
return event.paths;
204+
// Events within directories that already have create events are not needed
205+
// as the directory's full content will be listed.
206+
var createdDirectories = unionAll(batch.map((event) {
207+
return event.type == EventType.createDirectory
208+
? event.paths
209+
: const <String>{};
202210
}));
203211

204-
bool isInModifiedDirectory(String path) =>
205-
directories.any((dir) => path != dir && p.isWithin(dir, path));
212+
bool isInCreatedDirectory(String path) =>
213+
createdDirectories.any((dir) => path != dir && p.isWithin(dir, path));
206214

207215
void addEvent(String path, Event event) {
208-
if (isInModifiedDirectory(path)) return;
216+
if (isInCreatedDirectory(path)) return;
209217
eventsForPaths.putIfAbsent(path, () => <Event>{}).add(event);
210218
}
211219

212220
for (var event in batch) {
213-
// The Mac OS watcher doesn't emit move events. See issue 14806.
214-
assert(!event.isMove);
221+
if (event.type == EventType.moveFile ||
222+
event.type == EventType.moveDirectory ||
223+
event.type == EventType.modifyDirectory) {
224+
assert(false);
225+
continue;
226+
}
215227
addEvent(event.path, event);
216228
}
217229

@@ -233,6 +245,7 @@ class _MacOSDirectoryWatcher
233245
// contradictory (e.g. because of a move).
234246
if (batch.isEmpty) return null;
235247

248+
var path = batch.first.path;
236249
var type = batch.first.type;
237250
var isDirectory = batch.first.isDirectory;
238251
var hadModifyEvent = false;
@@ -246,50 +259,54 @@ class _MacOSDirectoryWatcher
246259
// safely assume the file was modified after a CREATE or before the
247260
// REMOVE; otherwise there will also be a REMOVE or CREATE event
248261
// (respectively) that will be contradictory.
249-
if (event.isModify) {
262+
if (event.type == EventType.modifyFile) {
250263
hadModifyEvent = true;
251264
continue;
252265
}
253266
assert(event.isCreate || event.isDelete);
254267

255268
// If we previously thought this was a MODIFY, we now consider it to be a
256269
// CREATE or REMOVE event. This is safe for the same reason as above.
257-
if (type == EventType.modify) {
270+
if (type == EventType.modifyFile) {
258271
type = event.type;
259272
continue;
260273
}
261274

262275
// A CREATE event contradicts a REMOVE event and vice versa.
263-
assert(type == EventType.create || type == EventType.delete);
276+
assert(type == EventType.createFile ||
277+
type == EventType.createDirectory ||
278+
type == EventType.delete);
264279
if (type != event.type) return null;
265280
}
266281

267282
// If we got a CREATE event for a file we already knew about, that comes
268283
// from FSEvents reporting an add that happened prior to the watch
269284
// beginning. If we also received a MODIFY event, we want to report that,
270285
// but not the CREATE.
271-
if (type == EventType.create &&
286+
if (type == EventType.createFile &&
272287
hadModifyEvent &&
273-
_files.contains(batch.first.path)) {
274-
type = EventType.modify;
288+
_files.contains(path)) {
289+
type = EventType.modifyFile;
275290
}
276291

277292
switch (type) {
278-
case EventType.create:
293+
case EventType.createDirectory:
279294
// Issue 16003 means that a CREATE event for a directory can indicate
280295
// that the directory was moved and then re-created.
281296
// [_eventsBasedOnFileSystem] will handle this correctly by producing a
282297
// DELETE event followed by a CREATE event if the directory exists.
283-
if (isDirectory!) return null;
284-
return Event.createFile(batch.first.path);
298+
return null;
299+
300+
case EventType.createFile:
285301
case EventType.delete:
286-
return Event.delete(batch.first.path);
287-
case EventType.modify:
288-
return isDirectory!
289-
? Event.modifyDirectory(batch.first.path)
290-
: Event.modifyFile(batch.first.path);
291-
default:
292-
throw StateError('unreachable');
302+
case EventType.modifyFile:
303+
return batch.firstWhere((e) => e.type == type);
304+
305+
// Guaranteed not present by `_sortEvents`.
306+
case EventType.moveFile:
307+
case EventType.moveDirectory:
308+
case EventType.modifyDirectory:
309+
throw StateError(type.name);
293310
}
294311
}
295312

0 commit comments

Comments
 (0)