Skip to content

Commit

Permalink
Merge pull request dart-lang/watcher#99 from scheglov/migrate-null-safe
Browse files Browse the repository at this point in the history
Migrate to null safety.
  • Loading branch information
scheglov authored Dec 16, 2020
2 parents 22a6cb3 + 23206c0 commit d25bfa2
Show file tree
Hide file tree
Showing 20 changed files with 141 additions and 120 deletions.
4 changes: 0 additions & 4 deletions pkgs/watcher/.travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ language: dart

dart:
- dev
- 2.8.4

os:
- linux
Expand All @@ -16,9 +15,6 @@ matrix:
include:
- dart: dev
dart_task: dartfmt
- dart: 2.8.4
dart_task:
dartanalyzer: --fatal-warnings .
- dart: dev
dart_task:
dartanalyzer: --fatal-warnings --fatal-infos .
Expand Down
3 changes: 2 additions & 1 deletion pkgs/watcher/lib/src/async_queue.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ class AsyncQueue<T> {
/// Used to avoid top-leveling asynchronous errors.
final Function _errorHandler;

AsyncQueue(this._processor, {Function onError}) : _errorHandler = onError;
AsyncQueue(this._processor, {required Function onError})
: _errorHandler = onError;

/// Enqueues [item] to be processed and starts asynchronously processing it
/// if a process isn't already running.
Expand Down
25 changes: 13 additions & 12 deletions pkgs/watcher/lib/src/custom_watcher_factory.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import '../watcher.dart';
/// A factory to produce custom watchers for specific file paths.
class _CustomWatcherFactory {
final String id;
final DirectoryWatcher Function(String path, {Duration pollingDelay})
final DirectoryWatcher? Function(String path, {Duration? pollingDelay})
createDirectoryWatcher;
final FileWatcher Function(String path, {Duration pollingDelay})
final FileWatcher? Function(String path, {Duration? pollingDelay})
createFileWatcher;

_CustomWatcherFactory(
Expand All @@ -22,7 +22,7 @@ class _CustomWatcherFactory {
/// registered more than once.
/// [createDirectoryWatcher] and [createFileWatcher] should return watchers for
/// the file paths they are able to handle. If the custom watcher is not able to
/// handle the path it should reuturn null.
/// handle the path it should return null.
/// The paths handled by each custom watch may not overlap, at most one custom
/// matcher may return a non-null watcher for a given path.
///
Expand All @@ -31,9 +31,10 @@ class _CustomWatcherFactory {
/// will be used instead of the default.
void registerCustomWatcher(
String id,
DirectoryWatcher Function(String path, {Duration pollingDelay})
DirectoryWatcher Function(String path, {Duration? pollingDelay})?
createDirectoryWatcher,
FileWatcher Function(String path, {Duration pollingDelay}) createFileWatcher,
FileWatcher Function(String path, {Duration? pollingDelay})?
createFileWatcher,
) {
if (_customWatcherFactories.containsKey(id)) {
throw ArgumentError('A custom watcher with id `$id` '
Expand All @@ -49,10 +50,10 @@ void registerCustomWatcher(
///
/// 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;
DirectoryWatcher? createCustomDirectoryWatcher(String path,
{Duration? pollingDelay}) {
DirectoryWatcher? customWatcher;
String? customFactoryId;
for (var watcherFactory in _customWatcherFactories.values) {
if (customWatcher != null) {
throw StateError('Two `CustomWatcherFactory`s applicable: '
Expand All @@ -69,9 +70,9 @@ DirectoryWatcher createCustomDirectoryWatcher(String path,
///
/// 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;
FileWatcher? createCustomFileWatcher(String path, {Duration? pollingDelay}) {
FileWatcher? customWatcher;
String? customFactoryId;
for (var watcherFactory in _customWatcherFactories.values) {
if (customWatcher != null) {
throw StateError('Two `CustomWatcherFactory`s applicable: '
Expand Down
2 changes: 1 addition & 1 deletion pkgs/watcher/lib/src/directory_watcher.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ abstract class DirectoryWatcher implements Watcher {
/// shorter will give more immediate feedback at the expense of doing more IO
/// and higher CPU usage. Defaults to one second. Ignored for non-polling
/// watchers.
factory DirectoryWatcher(String directory, {Duration pollingDelay}) {
factory DirectoryWatcher(String directory, {Duration? pollingDelay}) {
if (FileSystemEntity.isWatchSupported) {
var customWatcher =
createCustomDirectoryWatcher(directory, pollingDelay: pollingDelay);
Expand Down
23 changes: 14 additions & 9 deletions pkgs/watcher/lib/src/directory_watcher/linux.dart
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ class _LinuxDirectoryWatcher
} else {
_files.add(entity.path);
}
}, onError: (error, StackTrace stackTrace) {
}, onError: (Object error, StackTrace stackTrace) {
_eventsController.addError(error, stackTrace);
close();
}, onDone: () {
Expand Down Expand Up @@ -155,13 +155,16 @@ class _LinuxDirectoryWatcher
files.remove(event.path);
dirs.remove(event.path);

changed.add(event.destination);
var destination = event.destination;
if (destination == null) continue;

changed.add(destination);
if (event.isDirectory) {
files.remove(event.destination);
dirs.add(event.destination);
files.remove(destination);
dirs.add(destination);
} else {
files.add(event.destination);
dirs.remove(event.destination);
files.add(destination);
dirs.remove(destination);
}
} else if (event is FileSystemDeleteEvent) {
files.remove(event.path);
Expand Down Expand Up @@ -221,7 +224,7 @@ class _LinuxDirectoryWatcher
_files.add(entity.path);
_emit(ChangeType.ADD, entity.path);
}
}, onError: (error, StackTrace stackTrace) {
}, onError: (Object error, StackTrace stackTrace) {
// Ignore an exception caused by the dir not existing. It's fine if it
// was added and then quickly removed.
if (error is FileSystemException) return;
Expand Down Expand Up @@ -258,8 +261,10 @@ class _LinuxDirectoryWatcher
/// Like [Stream.listen], but automatically adds the subscription to
/// [_subscriptions] so that it can be canceled when [close] is called.
void _listen<T>(Stream<T> stream, void Function(T) onData,
{Function onError, void Function() onDone, bool cancelOnError}) {
StreamSubscription subscription;
{Function? onError,
void Function()? onDone,
bool cancelOnError = false}) {
late StreamSubscription subscription;
subscription = stream.listen(onData, onError: onError, onDone: () {
_subscriptions.remove(subscription);
onDone?.call();
Expand Down
29 changes: 17 additions & 12 deletions pkgs/watcher/lib/src/directory_watcher/mac_os.dart
Original file line number Diff line number Diff line change
Expand Up @@ -64,19 +64,19 @@ class _MacOSDirectoryWatcher
///
/// This is separate from [_listSubscriptions] because this stream
/// occasionally needs to be resubscribed in order to work around issue 14849.
StreamSubscription<List<FileSystemEvent>> _watchSubscription;
StreamSubscription<List<FileSystemEvent>>? _watchSubscription;

/// The subscription to the [Directory.list] call for the initial listing of
/// the directory to determine its initial state.
StreamSubscription<FileSystemEntity> _initialListSubscription;
StreamSubscription<FileSystemEntity>? _initialListSubscription;

/// The subscriptions to [Directory.list] calls for listing the contents of a
/// subdirectory that was moved into the watched directory.
final _listSubscriptions = <StreamSubscription<FileSystemEntity>>{};

/// The timer for tracking how long we wait for an initial batch of bogus
/// events (see issue 14373).
Timer _bogusEventTimer;
late Timer _bogusEventTimer;

_MacOSDirectoryWatcher(String path)
: path = path,
Expand Down Expand Up @@ -144,18 +144,20 @@ class _MacOSDirectoryWatcher

if (_files.containsDir(path)) continue;

StreamSubscription<FileSystemEntity> subscription;
subscription = Directory(path).list(recursive: true).listen((entity) {
var stream = Directory(path).list(recursive: true);
var subscription = stream.listen((entity) {
if (entity is Directory) return;
if (_files.contains(path)) return;

_emitEvent(ChangeType.ADD, entity.path);
_files.add(entity.path);
}, onError: (e, StackTrace stackTrace) {
_emitError(e, stackTrace);
}, onDone: () {
_listSubscriptions.remove(subscription);
}, cancelOnError: true);
subscription.onDone(() {
_listSubscriptions.remove(subscription);
});
subscription.onError((Object e, StackTrace stackTrace) {
_emitError(e, stackTrace);
});
_listSubscriptions.add(subscription);
} else if (event is FileSystemModifyEvent) {
assert(!event.isDirectory);
Expand Down Expand Up @@ -192,7 +194,10 @@ class _MacOSDirectoryWatcher
var directories = unionAll(batch.map((event) {
if (!event.isDirectory) return <String>{};
if (event is FileSystemMoveEvent) {
return {event.path, event.destination};
var destination = event.destination;
if (destination != null) {
return {event.path, destination};
}
}
return {event.path};
}));
Expand Down Expand Up @@ -224,7 +229,7 @@ class _MacOSDirectoryWatcher
/// If [batch] does contain contradictory events, this returns `null` to
/// indicate that the state of the path on the filesystem should be checked to
/// determine what occurred.
FileSystemEvent _canonicalEvent(Set<FileSystemEvent> batch) {
FileSystemEvent? _canonicalEvent(Set<FileSystemEvent> batch) {
// An empty batch indicates that we've learned earlier that the batch is
// contradictory (e.g. because of a move).
if (batch.isEmpty) return null;
Expand Down Expand Up @@ -394,7 +399,7 @@ class _MacOSDirectoryWatcher
}

/// Emit an error, then close the watcher.
void _emitError(error, StackTrace stackTrace) {
void _emitError(Object error, StackTrace stackTrace) {
_eventsController.addError(error, stackTrace);
close();
}
Expand Down
20 changes: 9 additions & 11 deletions pkgs/watcher/lib/src/directory_watcher/polling.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class PollingDirectoryWatcher extends ResubscribableWatcher
/// will pause between successive polls of the directory contents. Making this
/// shorter will give more immediate feedback at the expense of doing more IO
/// and higher CPU usage. Defaults to one second.
PollingDirectoryWatcher(String directory, {Duration pollingDelay})
PollingDirectoryWatcher(String directory, {Duration? pollingDelay})
: super(directory, () {
return _PollingDirectoryWatcher(
directory, pollingDelay ?? Duration(seconds: 1));
Expand Down Expand Up @@ -56,12 +56,12 @@ class _PollingDirectoryWatcher
/// The previous modification times of the files in the directory.
///
/// Used to tell which files have been modified.
final _lastModifieds = <String, DateTime>{};
final _lastModifieds = <String, DateTime?>{};

/// The subscription used while [directory] is being listed.
///
/// Will be `null` if a list is not currently happening.
StreamSubscription<FileSystemEntity> _listSubscription;
StreamSubscription<FileSystemEntity>? _listSubscription;

/// The queue of files waiting to be processed to see if they have been
/// modified.
Expand All @@ -70,7 +70,10 @@ class _PollingDirectoryWatcher
/// queue exists to let each of those proceed at their own rate. The lister
/// will enqueue files as quickly as it can. Meanwhile, files are dequeued
/// and processed sequentially.
AsyncQueue<String> _filesToProcess;
late final AsyncQueue<String?> _filesToProcess = AsyncQueue<String?>(
_processFile, onError: (Object e, StackTrace stackTrace) {
if (!_events.isClosed) _events.addError(e, stackTrace);
});

/// The set of files that have been seen in the current directory listing.
///
Expand All @@ -79,11 +82,6 @@ class _PollingDirectoryWatcher
final _polledFiles = <String>{};

_PollingDirectoryWatcher(this.path, this._pollingDelay) {
_filesToProcess =
AsyncQueue<String>(_processFile, onError: (e, StackTrace stackTrace) {
if (!_events.isClosed) _events.addError(e, stackTrace);
});

_poll();
}

Expand Down Expand Up @@ -120,7 +118,7 @@ class _PollingDirectoryWatcher

if (entity is! File) return;
_filesToProcess.add(entity.path);
}, onError: (error, StackTrace stackTrace) {
}, onError: (Object error, StackTrace stackTrace) {
if (!isDirectoryNotFoundException(error)) {
// It's some unknown error. Pipe it over to the event stream so the
// user can see it.
Expand All @@ -136,7 +134,7 @@ class _PollingDirectoryWatcher

/// Processes [file] to determine if it has been modified since the last
/// time it was scanned.
Future<void> _processFile(String file) async {
Future<void> _processFile(String? file) async {
// `null` is the sentinel which means the directory listing is complete.
if (file == null) {
await _completePoll();
Expand Down
Loading

0 comments on commit d25bfa2

Please sign in to comment.