Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions pkgs/watcher/lib/src/directory_watcher.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ import 'dart:io';

import '../watcher.dart';
import 'custom_watcher_factory.dart';
import 'directory_watcher/linux.dart';
import 'directory_watcher/macos.dart';
import 'directory_watcher/windows_resubscribable_watcher.dart';
import 'directory_watcher/linux/linux_directory_watcher.dart';
import 'directory_watcher/recursive/recursive_directory_watcher.dart';

/// Watches the contents of a directory and emits [WatchEvent]s when something
/// in the directory has changed.
Expand Down Expand Up @@ -52,9 +51,11 @@ abstract class DirectoryWatcher implements Watcher {
);
if (customWatcher != null) return customWatcher;
if (Platform.isLinux) return LinuxDirectoryWatcher(directory);
if (Platform.isMacOS) return MacosDirectoryWatcher(directory);
if (Platform.isMacOS) {
return RecursiveDirectoryWatcher(directory, runInIsolate: false);
}
if (Platform.isWindows) {
return WindowsDirectoryWatcher(directory,
return RecursiveDirectoryWatcher(directory,
runInIsolate: runInIsolateOnWindows);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

import 'dart:async';

import '../directory_watcher.dart';
import '../resubscribable.dart';
import '../watch_event.dart';
import 'linux/watch_tree_root.dart';
import '../../directory_watcher.dart';
import '../../resubscribable.dart';
import '../../watch_event.dart';
import 'watch_tree_root.dart';

/// Resubscribable Linux directory watcher that watches using
/// [_LinuxDirectoryWatcher].
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
import 'dart:async';
import 'dart:io';

import '../async_queue.dart';
import '../directory_watcher.dart';
import '../polling.dart';
import '../resubscribable.dart';
import '../watch_event.dart';
import '../../async_queue.dart';
import '../../directory_watcher.dart';
import '../../polling.dart';
import '../../resubscribable.dart';
import '../../watch_event.dart';
import 'directory_list.dart';

/// Periodically polls a directory for changes.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import 'dart:io';
import '../../paths.dart';
import '../../testing.dart';
import '../../watch_event.dart';
import '../event_tree.dart';
import 'event_tree.dart';

/// MacOS or Windows directory tree.
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import '../paths.dart';
import '../../paths.dart';

/// Tree of event paths relative to the watched path.
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
import 'dart:async';
import 'dart:isolate';

import '../resubscribable.dart';
import '../testing.dart';
import '../watch_event.dart';
import 'windows.dart';
import '../../resubscribable.dart';
import '../../testing.dart';
import '../../watch_event.dart';
import 'recursive_directory_watcher.dart';

/// Runs [WindowsManuallyClosedDirectoryWatcher] in an isolate to work around
/// Runs [ManuallyClosedRecursiveDirectoryWatcher] in an isolate to work around
/// a platform limitation.
///
/// On Windows, Directory.watch fails if too many events arrive without being
Expand All @@ -21,7 +21,7 @@ import 'windows.dart';
/// Running the watcher in an isolate makes buffer exhaustion much less likely
/// as there is no unrelated work happening in the isolate that would block
/// processing of events.
class WindowsIsolateDirectoryWatcher implements ManuallyClosedWatcher {
class IsolateRecursiveDirectoryWatcher implements ManuallyClosedWatcher {
@override
final String path;
final ReceivePort _receivePort = ReceivePort();
Expand All @@ -33,7 +33,7 @@ class WindowsIsolateDirectoryWatcher implements ManuallyClosedWatcher {

final void Function(LogEntry)? _log;

WindowsIsolateDirectoryWatcher(this.path)
IsolateRecursiveDirectoryWatcher(this.path)
: _log = logSeparateIsolateForTesting {
_startIsolate(path, _receivePort.sendPort, log: _log != null);
_receivePort.listen((event) => _receiveFromIsolate(event as Event));
Expand Down Expand Up @@ -87,7 +87,7 @@ void _startIsolate(String path, SendPort sendPort, {required bool log}) async {

class _WatcherIsolate {
final String path;
final WindowsManuallyClosedDirectoryWatcher watcher;
final ManuallyClosedRecursiveDirectoryWatcher watcher;
final SendPort sendPort;
final bool log;

Expand All @@ -96,7 +96,7 @@ class _WatcherIsolate {
final Completer<void> _closeCompleter = Completer();

_WatcherIsolate(this.path, this.sendPort, {required this.log})
: watcher = WindowsManuallyClosedDirectoryWatcher(path) {
: watcher = ManuallyClosedRecursiveDirectoryWatcher(path) {
if (log) {
logForTesting = (message) => sendPort.send(Event.log(message));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,34 @@

import 'dart:async';

import '../directory_watcher.dart';
import '../resubscribable.dart';
import '../watch_event.dart';
import 'macos/watched_directory_tree.dart';

/// Resubscribable MacOS directory watcher that watches using
/// [_MacosDirectoryWatcher].
class MacosDirectoryWatcher extends ResubscribableWatcher
import '../../directory_watcher.dart';
import '../../resubscribable.dart';
import '../../watch_event.dart';
import 'isolate_recursive_directory_watcher.dart';
import 'watched_directory_tree.dart';

/// Directory watcher that watches using [WatchedDirectoryTree].
///
/// Optionally, runs the watcher in a new isolate.
class RecursiveDirectoryWatcher extends ResubscribableWatcher
implements DirectoryWatcher {
@override
String get directory => path;

MacosDirectoryWatcher(String directory)
: super(directory, () => _MacosDirectoryWatcher(directory));
/// Watches [directory].
///
/// If [runInIsolate], runs the watcher in an isolate to reduce the chance of
/// hitting the Windows-specific buffer exhaustion failure.
RecursiveDirectoryWatcher(String directory, {required bool runInIsolate})
: super(
directory,
() => runInIsolate
? IsolateRecursiveDirectoryWatcher(directory)
: ManuallyClosedRecursiveDirectoryWatcher(directory));
}

/// Macos directory watcher that watches using [WatchedDirectoryTree].
class _MacosDirectoryWatcher
/// Manually closed directory watcher that watches using [WatchedDirectoryTree].
class ManuallyClosedRecursiveDirectoryWatcher
implements DirectoryWatcher, ManuallyClosedWatcher {
@override
final String path;
Expand All @@ -41,7 +51,7 @@ class _MacosDirectoryWatcher

late final WatchedDirectoryTree _watchTree;

_MacosDirectoryWatcher(this.path) {
ManuallyClosedRecursiveDirectoryWatcher(this.path) {
_watchTree = WatchedDirectoryTree(
watchedDirectory: path,
eventsController: _eventsController,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,18 @@ import '../../event.dart';
import '../../event_batching.dart';
import '../../paths.dart';
import '../../testing.dart';
import '../event_tree.dart';
import 'event_tree.dart';

/// Recursively watches a directory with `Directory.watch` on MacOS or Windows.
/// Watches a directory with `Directory.watch(recursive: true)` on MacOS or
/// Windows.
///
/// Handles incorrect closure of the watch due to a delete event from before
/// the watch started, by re-opening the watch if the directory still exists.
/// See https://github.com/dart-lang/sdk/issues/14373.
///
/// Handles deletion of the watched directory on Windows by watching the parent
/// directory.
class NativeWatch {
class RecursiveNativeWatch {
final AbsolutePath watchedDirectory;

/// Called when [watchedDirectory] is recreated.
Expand All @@ -43,7 +44,7 @@ class NativeWatch {
/// Watches [watchedDirectory].
///
/// Pass [watchedDirectoryWasDeleted], [onEvents] and [onError] handlers.
NativeWatch({
RecursiveNativeWatch({
required this.watchedDirectory,
required void Function() watchedDirectoryWasRecreated,
required void Function() watchedDirectoryWasDeleted,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ import 'dart:async';
import '../../paths.dart';
import '../../testing.dart';
import '../../watch_event.dart';
import '../event_tree.dart';
import 'directory_tree.dart';
import 'native_watch.dart';
import 'event_tree.dart';
import 'recursive_native_watch.dart';

/// MacOS or Windows directory watcher using a [DirectoryTree].
/// Directory watcher using `Directory.watch(recursive: true)` and
/// [DirectoryTree].
///
/// Various platform-specific issues are worked around.
/// Recursive watch is available on MacOS and Windows; contains
/// platform-specific workarounds for both.
///
/// MacOS events from a native watcher can arrive out of order, including in
/// different batches. For example, a modification of `a/1` followed by a
Expand Down Expand Up @@ -48,7 +50,7 @@ class WatchedDirectoryTree {
final StreamController<WatchEvent> _eventsController;
final Completer<void> _readyCompleter;

late final NativeWatch nativeWatch;
late final RecursiveNativeWatch nativeWatch;
late final DirectoryTree directoryTree;

WatchedDirectoryTree(
Expand All @@ -63,7 +65,7 @@ class WatchedDirectoryTree {
}

void _watch() async {
nativeWatch = NativeWatch(
nativeWatch = RecursiveNativeWatch(
watchedDirectory: watchedDirectory,
watchedDirectoryWasRecreated: _watchedDirectoryWasRecreated,
watchedDirectoryWasDeleted: _watchedDirectoryWasDeleted,
Expand Down
42 changes: 0 additions & 42 deletions pkgs/watcher/lib/src/directory_watcher/windows.dart

This file was deleted.

This file was deleted.

2 changes: 1 addition & 1 deletion pkgs/watcher/lib/watcher.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import 'src/watch_event.dart';

export 'src/custom_watcher_factory.dart' show registerCustomWatcher;
export 'src/directory_watcher.dart';
export 'src/directory_watcher/polling.dart';
export 'src/directory_watcher/polling/polling_directory_watcher.dart';
export 'src/file_watcher.dart';
export 'src/file_watcher/polling.dart';
export 'src/watch_event.dart';
Expand Down
2 changes: 1 addition & 1 deletion pkgs/watcher/test/directory_watcher/linux_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
library;

import 'package:test/test.dart';
import 'package:watcher/src/directory_watcher/linux.dart';
import 'package:watcher/src/directory_watcher/linux/linux_directory_watcher.dart';
import 'package:watcher/watcher.dart';

import '../utils.dart';
Expand Down
10 changes: 6 additions & 4 deletions pkgs/watcher/test/directory_watcher/macos_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
library;

import 'package:test/test.dart';
import 'package:watcher/src/directory_watcher/macos.dart';
import 'package:watcher/src/directory_watcher/recursive/recursive_directory_watcher.dart';
import 'package:watcher/watcher.dart';

import '../utils.dart';
Expand All @@ -15,13 +15,15 @@ import 'file_tests.dart';
import 'link_tests.dart';

void main() {
watcherFactory = MacosDirectoryWatcher.new;
watcherFactory =
(directory) => RecursiveDirectoryWatcher(directory, runInIsolate: false);

fileTests(isNative: true);
linkTests(isNative: true);
endToEndTests();

test('DirectoryWatcher creates a MacOSDirectoryWatcher on Mac OS', () {
expect(DirectoryWatcher('.'), const TypeMatcher<MacosDirectoryWatcher>());
test('DirectoryWatcher creates a RecursiveDirectoryWatcher on Mac OS', () {
expect(
DirectoryWatcher('.'), const TypeMatcher<RecursiveDirectoryWatcher>());
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import 'dart:io';
import 'package:path/path.dart' as p;
import 'package:test/test.dart';
import 'package:test_descriptor/test_descriptor.dart' as d;
import 'package:watcher/src/directory_watcher/directory_list.dart';
import 'package:watcher/src/directory_watcher/polling/directory_list.dart';

import '../utils.dart';
import '../../utils.dart';

void main() {
group('directory list', () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import 'dart:io';

import 'package:test/test.dart';
import 'package:watcher/src/directory_watcher/event_tree.dart';
import 'package:watcher/src/directory_watcher/recursive/event_tree.dart';
import 'package:watcher/src/paths.dart';

final separator = Platform.pathSeparator;
Expand Down
Loading
Loading