Throw when more than one custom factory is applicable
diff --git a/pkgs/watcher/lib/src/custom_watcher_factory.dart b/pkgs/watcher/lib/src/custom_watcher_factory.dart index ffac06b..b7f81fa 100644 --- a/pkgs/watcher/lib/src/custom_watcher_factory.dart +++ b/pkgs/watcher/lib/src/custom_watcher_factory.dart
@@ -10,23 +10,20 @@ /// Tries to create a [DirectoryWatcher] for the provided path. /// - /// Should return `null` if the path is not supported by this factory. + /// Returns `null` if the path is not supported by this factory. DirectoryWatcher createDirectoryWatcher(String path, {Duration pollingDelay}); /// Tries to create a [FileWatcher] for the provided path. /// - /// Should return `null` if the path is not supported by this factory. + /// Returns `null` if the path is not supported by this factory. FileWatcher createFileWatcher(String path, {Duration pollingDelay}); } /// Registers a custom watcher. /// -/// It's only allowed to register a watcher once per [id]. The [supportsPath] -/// will be called to determine if the [createWatcher] should be used instead of -/// the built-in watchers. -/// -/// Note that we will try [CustomWatcherFactory] one by one in the order they -/// were registered. +/// It's only allowed to register a watcher factory once per [id] and at most +/// one factory should apply to any given file (creating a [Watcher] will fail +/// otherwise). void registerCustomWatcherFactory(CustomWatcherFactory customFactory) { if (_customWatcherFactories.containsKey(customFactory.id)) { throw ArgumentError('A custom watcher with id `${customFactory.id}` ' @@ -35,8 +32,48 @@ _customWatcherFactories[customFactory.id] = customFactory; } -/// Unregisters a custom watcher and returns it (returns `null` if it was never -/// registered). +/// Tries to create a custom [DirectoryWatcher] and returns it. +/// +/// Returns `null` if no custom watcher was applicable and throws a [StateError] +/// if more than one was. +DirectoryWatcher createCustomDirectoryWatcher(String path, + {Duration pollingDelay}) { + DirectoryWatcher customWatcher; + String customFactoryId; + for (var watcherFactory in customWatcherFactories) { + if (customWatcher != null) { + throw StateError('Two `CustomWatcherFactory`s applicable: ' + '`$customFactoryId` and `${watcherFactory.id}` for `$path`'); + } + customWatcher = + watcherFactory.createDirectoryWatcher(path, pollingDelay: pollingDelay); + customFactoryId = watcherFactory.id; + } + return customWatcher; +} + +/// Tries to create a custom [FileWatcher] and returns it. +/// +/// Returns `null` if no custom watcher was applicable and throws a [StateError] +/// if more than one was. +FileWatcher createCustomFileWatcher(String path, {Duration pollingDelay}) { + FileWatcher customWatcher; + String customFactoryId; + for (var watcherFactory in customWatcherFactories) { + if (customWatcher != null) { + throw StateError('Two `CustomWatcherFactory`s applicable: ' + '`$customFactoryId` and `${watcherFactory.id}` for `$path`'); + } + customWatcher = + watcherFactory.createFileWatcher(path, pollingDelay: pollingDelay); + customFactoryId = watcherFactory.id; + } + return customWatcher; +} + +/// Unregisters a custom watcher and returns it. +/// +/// Returns `null` if the id was never registered. CustomWatcherFactory unregisterCustomWatcherFactory(String id) => _customWatcherFactories.remove(id);
diff --git a/pkgs/watcher/lib/src/directory_watcher.dart b/pkgs/watcher/lib/src/directory_watcher.dart index 858d020..3fe5004 100644 --- a/pkgs/watcher/lib/src/directory_watcher.dart +++ b/pkgs/watcher/lib/src/directory_watcher.dart
@@ -30,14 +30,9 @@ /// watchers. factory DirectoryWatcher(String directory, {Duration pollingDelay}) { if (FileSystemEntity.isWatchSupported) { - for (var custom in customWatcherFactories) { - var watcher = custom.createDirectoryWatcher(directory, - pollingDelay: pollingDelay); - if (watcher != null) { - return watcher; - } - } - + var customWatcher = + createCustomDirectoryWatcher(directory, pollingDelay: pollingDelay); + if (customWatcher != null) return customWatcher; if (Platform.isLinux) return LinuxDirectoryWatcher(directory); if (Platform.isMacOS) return MacOSDirectoryWatcher(directory); if (Platform.isWindows) return WindowsDirectoryWatcher(directory);
diff --git a/pkgs/watcher/lib/src/file_watcher.dart b/pkgs/watcher/lib/src/file_watcher.dart index 0b7afc7..c41e5e6 100644 --- a/pkgs/watcher/lib/src/file_watcher.dart +++ b/pkgs/watcher/lib/src/file_watcher.dart
@@ -30,12 +30,9 @@ /// and higher CPU usage. Defaults to one second. Ignored for non-polling /// watchers. factory FileWatcher(String file, {Duration pollingDelay}) { - for (var custom in customWatcherFactories) { - var watcher = custom.createFileWatcher(file, pollingDelay: pollingDelay); - if (watcher != null) { - return watcher; - } - } + var customWatcher = + createCustomFileWatcher(file, pollingDelay: pollingDelay); + if (customWatcher != null) return customWatcher; // [File.watch] doesn't work on Windows, but // [FileSystemEntity.isWatchSupported] is still true because directory
diff --git a/pkgs/watcher/test/custom_watcher_factory_test.dart b/pkgs/watcher/test/custom_watcher_factory_test.dart index 784769c..6d9ed40 100644 --- a/pkgs/watcher/test/custom_watcher_factory_test.dart +++ b/pkgs/watcher/test/custom_watcher_factory_test.dart
@@ -1,19 +1,19 @@ import 'dart:async'; -import 'dart:io'; import 'package:test/test.dart'; import 'package:watcher/watcher.dart'; void main() { _MemFs memFs; + final defaultFactoryId = 'MemFs'; setUp(() { memFs = _MemFs(); - registerCustomWatcherFactory(_MemFsWatcherFactory(memFs)); + registerCustomWatcherFactory(_MemFsWatcherFactory(defaultFactoryId, memFs)); }); tearDown(() async { - unregisterCustomWatcherFactory('MemFs'); + unregisterCustomWatcherFactory(defaultFactoryId); }); test('notifes for files', () async { @@ -43,8 +43,7 @@ }); test('unregister works', () async { - var memFactory = _MemFsWatcherFactory(memFs); - unregisterCustomWatcherFactory(memFactory.id); + unregisterCustomWatcherFactory(defaultFactoryId); var events = <WatchEvent>[]; var watcher = FileWatcher('file.txt'); @@ -59,9 +58,19 @@ }); test('registering twice throws', () async { - expect(() => registerCustomWatcherFactory(_MemFsWatcherFactory(memFs)), + expect( + () => registerCustomWatcherFactory( + _MemFsWatcherFactory(defaultFactoryId, memFs)), throwsA(isA<ArgumentError>())); }); + + test('finding two applicable factories throws', () async { + // Note that _MemFsWatcherFactory always returns a watcher, so having two + // will always produce a conflict. + registerCustomWatcherFactory(_MemFsWatcherFactory('Different id', memFs)); + expect(() => FileWatcher('file.txt'), throwsA(isA<StateError>())); + expect(() => DirectoryWatcher('dir'), throwsA(isA<StateError>())); + }); } class _MemFs { @@ -115,11 +124,9 @@ } class _MemFsWatcherFactory implements CustomWatcherFactory { + final String id; final _MemFs _memFs; - _MemFsWatcherFactory(this._memFs); - - @override - String get id => 'MemFs'; + _MemFsWatcherFactory(this.id, this._memFs); @override DirectoryWatcher createDirectoryWatcher(String path,