[flutter_tool] Make a couple file operations synchronous (#37044)
diff --git a/packages/flutter_tools/lib/src/cache.dart b/packages/flutter_tools/lib/src/cache.dart
index 876609b..68fd2ad 100644
--- a/packages/flutter_tools/lib/src/cache.dart
+++ b/packages/flutter_tools/lib/src/cache.dart
@@ -141,12 +141,21 @@
if (!_lockEnabled)
return;
assert(_lock == null);
- _lock = await fs.file(fs.path.join(flutterRoot, 'bin', 'cache', 'lockfile')).open(mode: FileMode.write);
+ final File lockFile =
+ fs.file(fs.path.join(flutterRoot, 'bin', 'cache', 'lockfile'));
+ try {
+ _lock = lockFile.openSync(mode: FileMode.write);
+ } on FileSystemException catch (e) {
+ printError('Failed to open or create the artifact cache lockfile: "$e"');
+ printError('Please ensure you have permissions to create or open '
+ '${lockFile.path}');
+ throwToolExit('Failed to open or create the lockfile');
+ }
bool locked = false;
bool printed = false;
while (!locked) {
try {
- await _lock.lock();
+ _lock.lockSync();
locked = true;
} on FileSystemException {
if (!printed) {
diff --git a/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart b/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart
index 0e991b3..de8e4f9 100644
--- a/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart
+++ b/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart
@@ -367,7 +367,13 @@
flutterUsage.suppressAnalytics = true;
_checkFlutterCopy();
- await FlutterVersion.instance.ensureVersionFile();
+ try {
+ await FlutterVersion.instance.ensureVersionFile();
+ } on FileSystemException catch (e) {
+ printError('Failed to write the version file to the artifact cache: "$e".');
+ printError('Please ensure you have permissions in the artifact cache directory.');
+ throwToolExit('Failed to write the version file');
+ }
if (topLevelResults.command?.name != 'upgrade' && topLevelResults['version-check']) {
await FlutterVersion.instance.checkFlutterVersionFreshness();
}
diff --git a/packages/flutter_tools/lib/src/version.dart b/packages/flutter_tools/lib/src/version.dart
index c3c14c4..f1f4a42 100644
--- a/packages/flutter_tools/lib/src/version.dart
+++ b/packages/flutter_tools/lib/src/version.dart
@@ -99,8 +99,8 @@
String get engineRevision => Cache.instance.engineRevision;
String get engineRevisionShort => _shortGitRevision(engineRevision);
- Future<void> ensureVersionFile() {
- return fs.file(fs.path.join(Cache.flutterRoot, 'version')).writeAsString(_frameworkVersion);
+ Future<void> ensureVersionFile() async {
+ fs.file(fs.path.join(Cache.flutterRoot, 'version')).writeAsStringSync(_frameworkVersion);
}
@override
diff --git a/packages/flutter_tools/test/general.shard/cache_test.dart b/packages/flutter_tools/test/general.shard/cache_test.dart
index 07c5c18..f4a8ef4 100644
--- a/packages/flutter_tools/test/general.shard/cache_test.dart
+++ b/packages/flutter_tools/test/general.shard/cache_test.dart
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import 'dart:async';
-
import 'package:file/file.dart';
import 'package:file/memory.dart';
import 'package:file_testing/file_testing.dart';
@@ -11,6 +9,7 @@
import 'package:mockito/mockito.dart';
import 'package:platform/platform.dart';
+import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart' show InternetAddress, SocketException;
@@ -23,7 +22,18 @@
void main() {
group('$Cache.checkLockAcquired', () {
+ MockFileSystem mockFileSystem;
+ MemoryFileSystem memoryFileSystem;
+ MockFile mockFile;
+ MockRandomAccessFile mockRandomAccessFile;
+
setUp(() {
+ mockFileSystem = MockFileSystem();
+ memoryFileSystem = MemoryFileSystem();
+ mockFile = MockFile();
+ mockRandomAccessFile = MockRandomAccessFile();
+ when(mockFileSystem.path).thenReturn(memoryFileSystem.path);
+
Cache.enableLocking();
});
@@ -31,6 +41,7 @@
// Restore locking to prevent potential side-effects in
// tests outside this group (this option is globally shared).
Cache.enableLocking();
+ Cache.releaseLockEarly();
});
test('should throw when locking is not acquired', () {
@@ -43,10 +54,21 @@
});
testUsingContext('should not throw when lock is acquired', () async {
+ when(mockFileSystem.file(argThat(endsWith('lockfile')))).thenReturn(mockFile);
+ when(mockFile.openSync(mode: anyNamed('mode'))).thenReturn(mockRandomAccessFile);
await Cache.lock();
Cache.checkLockAcquired();
+ Cache.releaseLockEarly();
}, overrides: <Type, Generator>{
- FileSystem: () => MockFileSystem(),
+ FileSystem: () => mockFileSystem,
+ });
+
+ testUsingContext('throws tool exit when lockfile open fails', () async {
+ when(mockFileSystem.file(argThat(endsWith('lockfile')))).thenReturn(mockFile);
+ when(mockFile.openSync(mode: anyNamed('mode'))).thenThrow(const FileSystemException());
+ expect(() async => await Cache.lock(), throwsA(isA<ToolExit>()));
+ }, overrides: <Type, Generator>{
+ FileSystem: () => mockFileSystem,
});
testUsingContext('should not throw when FLUTTER_ALREADY_LOCKED is set', () async {
@@ -166,7 +188,7 @@
expect(flattenNameSubdirs(Uri.parse('http://docs.flutter.io/foo/bar')), 'docs.flutter.io/foo/bar');
expect(flattenNameSubdirs(Uri.parse('https://www.flutter.dev')), 'www.flutter.dev');
}, overrides: <Type, Generator>{
- FileSystem: () => MockFileSystem(),
+ FileSystem: () => MemoryFileSystem(),
});
test('Unstable artifacts', () {
@@ -247,21 +269,8 @@
List<String> getPackageDirs() => packageDirs;
}
-class MockFileSystem extends ForwardingFileSystem {
- MockFileSystem() : super(MemoryFileSystem());
-
- @override
- File file(dynamic path) {
- return MockFile();
- }
-}
-
-class MockFile extends Mock implements File {
- @override
- Future<RandomAccessFile> open({ FileMode mode = FileMode.read }) async {
- return MockRandomAccessFile();
- }
-}
+class MockFileSystem extends Mock implements FileSystem {}
+class MockFile extends Mock implements File {}
class MockRandomAccessFile extends Mock implements RandomAccessFile {}
class MockCachedArtifact extends Mock implements CachedArtifact {}
diff --git a/packages/flutter_tools/test/general.shard/runner/flutter_command_runner_test.dart b/packages/flutter_tools/test/general.shard/runner/flutter_command_runner_test.dart
index 3680746..a5c5541 100644
--- a/packages/flutter_tools/test/general.shard/runner/flutter_command_runner_test.dart
+++ b/packages/flutter_tools/test/general.shard/runner/flutter_command_runner_test.dart
@@ -3,6 +3,7 @@
// found in the LICENSE file.
import 'package:file/memory.dart';
+import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/context.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart';
@@ -69,6 +70,17 @@
Platform: () => platform,
}, initializeFlutterRoot: false);
+ testUsingContext('throw tool exit if the version file cannot be written', () async {
+ final MockFlutterVersion version = FlutterVersion.instance;
+ when(version.ensureVersionFile()).thenThrow(const FileSystemException());
+
+ expect(() async => await runner.run(<String>['dummy']), throwsA(isA<ToolExit>()));
+
+ }, overrides: <Type, Generator>{
+ FileSystem: () => fs,
+ Platform: () => platform,
+ }, initializeFlutterRoot: false);
+
testUsingContext('works if --local-engine is specified and --local-engine-src-path is determined by sky_engine', () async {
fs.directory('$_kArbitraryEngineRoot/src/out/ios_debug/gen/dart-pkg/sky_engine/lib/').createSync(recursive: true);
fs.directory('$_kArbitraryEngineRoot/src/out/host_debug').createSync(recursive: true);