Skip to content

Commit 4c7dae1

Browse files
authored
Fix for skipped tests on Windows. (#2204)
1 parent 50b4514 commit 4c7dae1

File tree

3 files changed

+39
-36
lines changed

3 files changed

+39
-36
lines changed

pkgs/watcher/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
the file was created immediately before the watcher was created. Now, if the
55
file exists when the watcher is created then this modify event is not sent.
66
This matches the Linux native and polling (Windows) watchers.
7+
- Bug fix: with `DirectoryWatcher` on Windows, a move over an existing file was
8+
reported incorrectly. For example, if `a` and `b` already exist, then `a` is
9+
moved onto `b`, it would be reported as three events: delete `a`, delete `b`,
10+
create `b`. Now it's reported as two events: delete `a`, modify `b`. This
11+
matches the behavior of the Linux and MacOS watchers.
712

813
## 1.1.4
914

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

Lines changed: 34 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,8 @@ class _EventBatcher {
3030
final List<Event> events = [];
3131
Timer? timer;
3232

33-
void addEvent(FileSystemEvent event, void Function() callback) {
34-
final convertedEvent = Event.checkAndConvert(event);
35-
if (convertedEvent == null) return;
36-
events.add(convertedEvent);
33+
void addEvent(Event event, void Function() callback) {
34+
events.add(event);
3735
timer?.cancel();
3836
timer = Timer(_batchDelay, callback);
3937
}
@@ -166,8 +164,28 @@ class _WindowsDirectoryWatcher
166164
);
167165
}
168166

169-
void _onEvent(FileSystemEvent event) {
167+
void _onEvent(FileSystemEvent fileSystemEvent) {
170168
assert(isReady);
169+
final event = Event.checkAndConvert(fileSystemEvent);
170+
if (event == null) return;
171+
if (event.type == EventType.moveFile) {
172+
_batchEvent(Event.delete(event.path));
173+
final destination = event.destination;
174+
if (destination != null) {
175+
_batchEvent(Event.createFile(destination));
176+
}
177+
} else if (event.type == EventType.moveDirectory) {
178+
_batchEvent(Event.delete(event.path));
179+
final destination = event.destination;
180+
if (destination != null) {
181+
_batchEvent(Event.createDirectory(destination));
182+
}
183+
} else {
184+
_batchEvent(event);
185+
}
186+
}
187+
188+
void _batchEvent(Event event) {
171189
final batcher = _eventBatchers.putIfAbsent(event.path, _EventBatcher.new);
172190
batcher.addEvent(event, () {
173191
_eventBatchers.remove(event.path);
@@ -225,7 +243,7 @@ class _WindowsDirectoryWatcher
225243
_emitEvent(ChangeType.REMOVE, removedPath);
226244
}
227245

228-
// Move events are removed by `_canonicalEvent` and never returned by
246+
// Move events are removed by `_onEvent` and never returned by
229247
// `_eventsBasedOnFileSystem`.
230248
case EventType.moveFile:
231249
case EventType.moveDirectory:
@@ -240,38 +258,27 @@ class _WindowsDirectoryWatcher
240258
}
241259

242260
/// Sort all the events in a batch into sets based on their path.
243-
///
244-
/// Events for [path] are discarded.
245261
Map<String, Set<Event>> _sortEvents(List<Event> batch) {
246262
var eventsForPaths = <String, Set<Event>>{};
247263

248-
// Events within created or moved directories are not needed as the
249-
// directory's full contents will be listed.
250-
var directories = unionAll(
251-
batch.map((event) {
252-
if (event.type == EventType.createDirectory ||
253-
event.type == EventType.moveDirectory) {
254-
final destination = event.destination;
255-
return {event.path, if (destination != null) destination};
256-
}
257-
return const <String>{};
258-
}),
259-
);
264+
// Events within directories that already have create events are not needed
265+
// as the directory's full content will be listed.
266+
var createdDirectories = unionAll(batch.map((event) {
267+
return event.type == EventType.createDirectory
268+
? {event.path}
269+
: const <String>{};
270+
}));
260271

261-
bool isInModifiedDirectory(String path) =>
262-
directories.any((dir) => path != dir && p.isWithin(dir, path));
272+
bool isInCreatedDirectory(String path) =>
273+
createdDirectories.any((dir) => path != dir && p.isWithin(dir, path));
263274

264275
void addEvent(String path, Event event) {
265-
if (isInModifiedDirectory(path)) return;
276+
if (isInCreatedDirectory(path)) return;
266277
eventsForPaths.putIfAbsent(path, () => <Event>{}).add(event);
267278
}
268279

269280
for (var event in batch) {
270281
addEvent(event.path, event);
271-
final destination = event.destination;
272-
if (destination != null) {
273-
addEvent(destination, event);
274-
}
275282
}
276283

277284
return eventsForPaths;
@@ -300,11 +307,6 @@ class _WindowsDirectoryWatcher
300307
return null;
301308
}
302309

303-
// Move events are always resolved by checking the filesystem.
304-
if (type == EventType.moveFile || type == EventType.moveDirectory) {
305-
return null;
306-
}
307-
308310
return batch.firstWhere((e) => e.type == type);
309311
}
310312

pkgs/watcher/test/directory_watcher/shared.dart

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,6 @@ void sharedTests() {
137137

138138
renameFile('from.txt', 'to.txt');
139139
await inAnyOrder([isRemoveEvent('from.txt'), isModifyEvent('to.txt')]);
140-
}, onPlatform: {
141-
'windows': const Skip('https://github.com/dart-lang/watcher/issues/125')
142140
});
143141
});
144142

@@ -280,8 +278,6 @@ void sharedTests() {
280278
isRemoveEvent('old'),
281279
isAddEvent('new')
282280
]);
283-
}, onPlatform: {
284-
'windows': const Skip('https://github.com/dart-lang/watcher/issues/21')
285281
});
286282

287283
test('emits events for many nested files added at once', () async {

0 commit comments

Comments
 (0)