Skip to content

Commit ef1227f

Browse files
[flutter_tools] handle FileSystemException trying to delete temp directory from core_devices.dart (#140415)
Fixes flutter/flutter#140416, the top crasher on stable/3.16.4
1 parent ea6017d commit ef1227f

3 files changed

Lines changed: 40 additions & 6 deletions

File tree

packages/flutter_tools/lib/src/ios/core_devices.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import 'package:meta/meta.dart';
66
import 'package:process/process.dart';
77

8+
import '../base/error_handling_io.dart';
89
import '../base/file_system.dart';
910
import '../base/io.dart';
1011
import '../base/logger.dart';
@@ -101,7 +102,7 @@ class IOSCoreDeviceControl {
101102
_logger.printError('Error executing devicectl: $err');
102103
return <Object?>[];
103104
} finally {
104-
tempDirectory.deleteSync(recursive: true);
105+
ErrorHandlingFileSystem.deleteIfExists(tempDirectory, recursive: true);
105106
}
106107
}
107108

packages/flutter_tools/test/general.shard/base/error_handling_io_test.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ void main() {
111111
exceptionHandler = FileExceptionHandler();
112112
});
113113

114-
testWithoutContext('bypasses error handling when withAllowedFailure is used', () {
114+
testWithoutContext('bypasses error handling when noExitOnFailure is used', () {
115115
final ErrorHandlingFileSystem fileSystem = ErrorHandlingFileSystem(
116116
delegate: MemoryFileSystem.test(opHandle: exceptionHandler.opHandle),
117117
platform: windowsPlatform,
@@ -123,17 +123,17 @@ void main() {
123123
FileSystemOp.write,
124124
FileSystemException('', file.path, const OSError('', kUserPermissionDenied)),
125125
);
126-
126+
final Matcher throwsNonToolExit = throwsA(isNot(isA<ToolExit>()));
127127
expect(() => ErrorHandlingFileSystem.noExitOnFailure(
128-
() => file.writeAsStringSync('')), throwsException);
128+
() => file.writeAsStringSync('')), throwsNonToolExit);
129129

130130
// nesting does not unconditionally re-enable errors.
131131
expect(() {
132132
ErrorHandlingFileSystem.noExitOnFailure(() {
133133
ErrorHandlingFileSystem.noExitOnFailure(() { });
134134
file.writeAsStringSync('');
135135
});
136-
}, throwsException);
136+
}, throwsNonToolExit);
137137

138138
// Check that state does not leak.
139139
expect(() => file.writeAsStringSync(''), throwsToolExit());

packages/flutter_tools/test/general.shard/ios/core_devices_test.dart

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import 'package:file/memory.dart';
66
import 'package:file_testing/file_testing.dart';
77
import 'package:flutter_tools/src/base/file_system.dart';
8+
import 'package:flutter_tools/src/base/io.dart';
89
import 'package:flutter_tools/src/base/logger.dart';
910
import 'package:flutter_tools/src/base/version.dart';
1011
import 'package:flutter_tools/src/ios/core_devices.dart';
@@ -35,7 +36,7 @@ void main() {
3536
version: Version(14, 0, 0),
3637
);
3738
xcode = Xcode.test(
38-
processManager: FakeProcessManager.any(),
39+
processManager: fakeProcessManager,
3940
xcodeProjectInterpreter: xcodeProjectInterpreter,
4041
);
4142
deviceControl = IOSCoreDeviceControl(
@@ -86,6 +87,7 @@ void main() {
8687
setUp(() {
8788
logger = BufferLogger.test();
8889
fakeProcessManager = FakeProcessManager.empty();
90+
// TODO(fujino): make this FakeProcessManager.empty()
8991
xcode = Xcode.test(processManager: FakeProcessManager.any());
9092
deviceControl = IOSCoreDeviceControl(
9193
logger: logger,
@@ -1322,6 +1324,37 @@ invalid JSON
13221324
});
13231325

13241326
group('list devices', () {
1327+
testWithoutContext('Handles FileSystemException deleting temp directory', () async {
1328+
final Directory tempDir = fileSystem.systemTempDirectory
1329+
.childDirectory('core_devices.rand0');
1330+
final File tempFile = tempDir.childFile('core_device_list.json');
1331+
final List<String> args = <String>[
1332+
'xcrun',
1333+
'devicectl',
1334+
'list',
1335+
'devices',
1336+
'--timeout',
1337+
'5',
1338+
'--json-output',
1339+
tempFile.path,
1340+
];
1341+
fakeProcessManager.addCommand(FakeCommand(
1342+
command: args,
1343+
onRun: () {
1344+
// Simulate that this command threw and simulataneously the OS
1345+
// deleted the temp directory
1346+
expect(tempFile, exists);
1347+
tempDir.deleteSync(recursive: true);
1348+
expect(tempFile, isNot(exists));
1349+
throw ProcessException(args.first, args.sublist(1));
1350+
},
1351+
));
1352+
1353+
await deviceControl.getCoreDevices();
1354+
expect(logger.errorText, contains('Error executing devicectl: ProcessException'));
1355+
expect(fakeProcessManager, hasNoRemainingExpectations);
1356+
});
1357+
13251358
testWithoutContext('No devices', () async {
13261359
const String deviceControlOutput = '''
13271360
{

0 commit comments

Comments
 (0)