diff --git a/packages/flutter_tools/lib/src/base/error_handling_io.dart b/packages/flutter_tools/lib/src/base/error_handling_io.dart index 2298cf66260..6c0006897e1 100644 --- a/packages/flutter_tools/lib/src/base/error_handling_io.dart +++ b/packages/flutter_tools/lib/src/base/error_handling_io.dart @@ -24,6 +24,10 @@ import 'platform.dart'; // ToolExit and a message that is more clear than the FileSystemException by // itself. +/// On windows this is error code 2: ERROR_FILE_NOT_FOUND, and on +/// macOS/Linux it is error code 2/ENOENT: No such file or directory. +const int kSystemCannotFindFile = 2; + /// A [FileSystem] that throws a [ToolExit] on certain errors. /// /// If a [FileSystem] error is not caused by the Flutter tool, and can only be @@ -83,10 +87,6 @@ class ErrorHandlingFileSystem extends ForwardingFileSystem { // Certain error codes indicate the file could not be found. It could have // been deleted by a different program while the tool was running. // if it still exists, the file likely exists on a read-only volume. - // - // On windows this is error code 2: ERROR_FILE_NOT_FOUND, and on - // macOS/Linux it is error code 2/ENOENT: No such file or directory. - const int kSystemCannotFindFile = 2; if (err?.osError?.errorCode != kSystemCannotFindFile || _noExitOnFailure) { rethrow; } @@ -105,7 +105,18 @@ class ErrorHandlingFileSystem extends ForwardingFileSystem { @override Directory get currentDirectory { - return _runSync(() => directory(delegate.currentDirectory), platform: _platform); + try { + return _runSync(() => directory(delegate.currentDirectory), platform: _platform); + } on FileSystemException catch (err) { + // Special handling for OS error 2 for current directory only. + if (err.osError.errorCode == kSystemCannotFindFile) { + throwToolExit( + 'Unable to read current working directory. This can happen if the directory the ' + 'Flutter tool was run from was moved or deleted.' + ); + } + rethrow; + } } @override diff --git a/packages/flutter_tools/test/general.shard/base/error_handling_io_test.dart b/packages/flutter_tools/test/general.shard/base/error_handling_io_test.dart index 6bec81fc194..04572a58790 100644 --- a/packages/flutter_tools/test/general.shard/base/error_handling_io_test.dart +++ b/packages/flutter_tools/test/general.shard/base/error_handling_io_test.dart @@ -8,6 +8,7 @@ import 'dart:io' as io; // ignore: dart_io_import; import 'package:file/file.dart'; import 'package:file/memory.dart'; +import 'package:file_testing/file_testing.dart'; import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/error_handling_io.dart'; import 'package:flutter_tools/src/base/file_system.dart'; @@ -370,6 +371,7 @@ void main() { const int eperm = 1; const int enospc = 28; const int eacces = 13; + MockFileSystem mockFileSystem; ErrorHandlingFileSystem fs; @@ -475,6 +477,19 @@ void main() { expect(() => directory.existsSync(), throwsToolExit(message: expectedMessage)); }); + + testWithoutContext('When the current working directory disappears', () async { + setupReadMocks( + mockFileSystem: mockFileSystem, + fs: fs, + errorCode: kSystemCannotFindFile, + ); + + expect(() => fs.currentDirectory, throwsToolExit(message: 'Unable to read current working directory')); + + // Error is not caught by other operations. + expect(() => fs.file('foo').readAsStringSync(), throwsFileSystemException(kSystemCannotFindFile)); + }); }); group('throws ToolExit on macOS', () {