mirror of
https://github.com/flutter/flutter
synced 2024-10-13 11:42:54 +00:00
Catch exceptions thrown by runChecked* when possible (#36109)
This commit is contained in:
parent
7b0cc5051b
commit
5a34e7981e
|
@ -378,10 +378,14 @@ class AndroidDevice extends Device {
|
|||
printError('$installResult');
|
||||
return false;
|
||||
}
|
||||
|
||||
await runAdbCheckedAsync(<String>[
|
||||
'shell', 'echo', '-n', _getSourceSha1(app), '>', _getDeviceSha1Path(app),
|
||||
]);
|
||||
try {
|
||||
await runAdbCheckedAsync(<String>[
|
||||
'shell', 'echo', '-n', _getSourceSha1(app), '>', _getDeviceSha1Path(app),
|
||||
]);
|
||||
} on ProcessException catch (error) {
|
||||
printError('adb shell failed to write the SHA hash: $error.');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -390,7 +394,13 @@ class AndroidDevice extends Device {
|
|||
if (!await _checkForSupportedAdbVersion() || !await _checkForSupportedAndroidVersion())
|
||||
return false;
|
||||
|
||||
final String uninstallOut = (await runCheckedAsync(adbCommandForDevice(<String>['uninstall', app.id]))).stdout;
|
||||
String uninstallOut;
|
||||
try {
|
||||
uninstallOut = (await runCheckedAsync(adbCommandForDevice(<String>['uninstall', app.id]))).stdout;
|
||||
} catch (error) {
|
||||
printError('adb uninstall failed: $error');
|
||||
return false;
|
||||
}
|
||||
final RegExp failureExp = RegExp(r'^Failure.*$', multiLine: true);
|
||||
final String failure = failureExp.stringMatch(uninstallOut);
|
||||
if (failure != null) {
|
||||
|
@ -615,13 +625,18 @@ class AndroidDevice extends Device {
|
|||
|
||||
static final RegExp _timeRegExp = RegExp(r'^\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}', multiLine: true);
|
||||
|
||||
/// Return the most recent timestamp in the Android log or null if there is
|
||||
/// Return the most recent timestamp in the Android log or [null] if there is
|
||||
/// no available timestamp. The format can be passed to logcat's -T option.
|
||||
String get lastLogcatTimestamp {
|
||||
final String output = runAdbCheckedSync(<String>[
|
||||
'shell', '-x', 'logcat', '-v', 'time', '-t', '1',
|
||||
]);
|
||||
|
||||
String output;
|
||||
try {
|
||||
output = runAdbCheckedSync(<String>[
|
||||
'shell', '-x', 'logcat', '-v', 'time', '-t', '1',
|
||||
]);
|
||||
} catch (error) {
|
||||
printError('Failed to extract the most recent timestamp from the Android log: $error.');
|
||||
return null;
|
||||
}
|
||||
final Match timeMatch = _timeRegExp.firstMatch(output);
|
||||
return timeMatch?.group(0);
|
||||
}
|
||||
|
@ -940,9 +955,15 @@ class _AndroidDevicePortForwarder extends DevicePortForwarder {
|
|||
List<ForwardedPort> get forwardedPorts {
|
||||
final List<ForwardedPort> ports = <ForwardedPort>[];
|
||||
|
||||
final String stdout = runCheckedSync(device.adbCommandForDevice(
|
||||
<String>['forward', '--list']
|
||||
));
|
||||
String stdout;
|
||||
try {
|
||||
stdout = runCheckedSync(device.adbCommandForDevice(
|
||||
<String>['forward', '--list']
|
||||
));
|
||||
} catch (error) {
|
||||
printError('Failed to list forwarded ports: $error.');
|
||||
return ports;
|
||||
}
|
||||
|
||||
final List<String> lines = LineSplitter.split(stdout).toList();
|
||||
for (String line in lines) {
|
||||
|
|
|
@ -114,16 +114,21 @@ class AndroidApk extends ApplicationPackage {
|
|||
return null;
|
||||
}
|
||||
|
||||
final List<String> aaptArgs = <String>[
|
||||
aaptPath,
|
||||
'dump',
|
||||
'xmltree',
|
||||
apk.path,
|
||||
'AndroidManifest.xml',
|
||||
];
|
||||
String apptStdout;
|
||||
try {
|
||||
apptStdout = runCheckedSync(<String>[
|
||||
aaptPath,
|
||||
'dump',
|
||||
'xmltree',
|
||||
apk.path,
|
||||
'AndroidManifest.xml',
|
||||
]);
|
||||
} catch (error) {
|
||||
printError('Failed to extract manifest from APK: $error.');
|
||||
return null;
|
||||
}
|
||||
|
||||
final ApkManifestData data = ApkManifestData
|
||||
.parseFromXmlDump(runCheckedSync(aaptArgs));
|
||||
final ApkManifestData data = ApkManifestData.parseFromXmlDump(apptStdout);
|
||||
|
||||
if (data == null) {
|
||||
printError('Unable to read manifest info from ${apk.path}.');
|
||||
|
|
|
@ -8,6 +8,7 @@ import 'package:meta/meta.dart';
|
|||
|
||||
import '../base/common.dart';
|
||||
import '../base/file_system.dart';
|
||||
import '../base/io.dart';
|
||||
import '../base/os.dart';
|
||||
import '../base/process.dart';
|
||||
import '../cache.dart';
|
||||
|
@ -98,8 +99,14 @@ class UpgradeCommandRunner {
|
|||
'git', 'status', '-s'
|
||||
], workingDirectory: Cache.flutterRoot);
|
||||
return result.stdout.trim().isNotEmpty;
|
||||
} catch (e) {
|
||||
throwToolExit('git status failed: $e');
|
||||
} on ProcessException catch (error) {
|
||||
throwToolExit(
|
||||
'The tool could not verify the status of the current flutter checkout. '
|
||||
'This might be due to git not being installed or an internal error.'
|
||||
'If it is okay to ignore potential local changes, then re-run this'
|
||||
'command with --force.'
|
||||
'\nError: $error.'
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -132,11 +139,17 @@ class UpgradeCommandRunner {
|
|||
} else {
|
||||
tag = 'v${gitTagVersion.x}.${gitTagVersion.y}.${gitTagVersion.z}';
|
||||
}
|
||||
final RunResult runResult = await runCheckedAsync(<String>[
|
||||
'git', 'reset', '--hard', tag,
|
||||
], workingDirectory: Cache.flutterRoot);
|
||||
if (runResult.exitCode != 0) {
|
||||
throwToolExit('Failed to restore branch from hotfix.');
|
||||
try {
|
||||
await runCheckedAsync(<String>[
|
||||
'git', 'reset', '--hard', tag,
|
||||
], workingDirectory: Cache.flutterRoot);
|
||||
} on ProcessException catch (error) {
|
||||
throwToolExit(
|
||||
'Unable to upgrade Flutter: The tool could not update to the version $tag. '
|
||||
'This may be due to git not being installed or an internal error.'
|
||||
'Please ensure that git is installed on your computer and retry again.'
|
||||
'\nError: $error.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import 'dart:async';
|
|||
|
||||
import '../base/common.dart';
|
||||
import '../base/file_system.dart';
|
||||
import '../base/io.dart';
|
||||
import '../base/os.dart';
|
||||
import '../base/process.dart';
|
||||
import '../base/version.dart';
|
||||
|
@ -34,10 +35,19 @@ class VersionCommand extends FlutterCommand {
|
|||
Version minSupportedVersion = Version.parse('1.2.1');
|
||||
|
||||
Future<List<String>> getTags() async {
|
||||
final RunResult runResult = await runCheckedAsync(
|
||||
<String>['git', 'tag', '-l', 'v*', '--sort=-creatordate'],
|
||||
workingDirectory: Cache.flutterRoot,
|
||||
);
|
||||
RunResult runResult;
|
||||
try {
|
||||
runResult = await runCheckedAsync(
|
||||
<String>['git', 'tag', '-l', 'v*', '--sort=-creatordate'],
|
||||
workingDirectory: Cache.flutterRoot,
|
||||
);
|
||||
} on ProcessException catch (error) {
|
||||
throwToolExit(
|
||||
'Unable to get the tags. '
|
||||
'This might be due to git not being installed or an internal error'
|
||||
'\nError: $error.'
|
||||
);
|
||||
}
|
||||
return runResult.toString().split('\n');
|
||||
}
|
||||
|
||||
|
|
|
@ -120,7 +120,16 @@ Future<Map<String, String>> getCodeSigningIdentityDevelopmentTeam({
|
|||
|
||||
const List<String> findIdentityCommand =
|
||||
<String>['security', 'find-identity', '-p', 'codesigning', '-v'];
|
||||
final List<String> validCodeSigningIdentities = runCheckedSync(findIdentityCommand)
|
||||
|
||||
String findIdentityStdout;
|
||||
try {
|
||||
findIdentityStdout = runCheckedSync(findIdentityCommand);
|
||||
} catch (error) {
|
||||
printTrace('Unexpected failure from find-identity: $error.');
|
||||
return null;
|
||||
}
|
||||
|
||||
final List<String> validCodeSigningIdentities = findIdentityStdout
|
||||
.split('\n')
|
||||
.map<String>((String outputLine) {
|
||||
return _securityFindIdentityDeveloperIdentityExtractionPattern
|
||||
|
@ -148,12 +157,18 @@ Future<Map<String, String>> getCodeSigningIdentityDevelopmentTeam({
|
|||
if (signingCertificateId == null)
|
||||
return null;
|
||||
|
||||
final String signingCertificate = runCheckedSync(
|
||||
<String>['security', 'find-certificate', '-c', signingCertificateId, '-p']
|
||||
);
|
||||
String signingCertificateStdout;
|
||||
try {
|
||||
signingCertificateStdout = runCheckedSync(
|
||||
<String>['security', 'find-certificate', '-c', signingCertificateId, '-p']
|
||||
);
|
||||
} catch (error) {
|
||||
printTrace('Couldn\'t find the certificate: $error.');
|
||||
return null;
|
||||
}
|
||||
|
||||
final Process opensslProcess = await runCommand(const <String>['openssl', 'x509', '-subject']);
|
||||
await (opensslProcess.stdin..write(signingCertificate)).close();
|
||||
await (opensslProcess.stdin..write(signingCertificateStdout)).close();
|
||||
|
||||
final String opensslOutput = await utf8.decodeStream(opensslProcess.stdout);
|
||||
// Fire and forget discard of the stderr stream so we don't hold onto resources.
|
||||
|
|
|
@ -174,15 +174,20 @@ class XcodeProjectInterpreter {
|
|||
}
|
||||
|
||||
Map<String, String> getBuildSettings(String projectPath, String target) {
|
||||
final String out = runCheckedSync(<String>[
|
||||
_executable,
|
||||
'-project',
|
||||
fs.path.absolute(projectPath),
|
||||
'-target',
|
||||
target,
|
||||
'-showBuildSettings',
|
||||
], workingDirectory: projectPath);
|
||||
return parseXcodeBuildSettings(out);
|
||||
try {
|
||||
final String out = runCheckedSync(<String>[
|
||||
_executable,
|
||||
'-project',
|
||||
fs.path.absolute(projectPath),
|
||||
'-target',
|
||||
target,
|
||||
'-showBuildSettings',
|
||||
], workingDirectory: projectPath);
|
||||
return parseXcodeBuildSettings(out);
|
||||
} catch(error) {
|
||||
printTrace('Unexpected failure to get the build settings: $error.');
|
||||
return const <String, String>{};
|
||||
}
|
||||
}
|
||||
|
||||
Future<XcodeProjectInfo> getInfo(String projectPath) async {
|
||||
|
|
|
@ -10,6 +10,7 @@ import 'package:file/memory.dart';
|
|||
import 'package:flutter_tools/src/android/android_console.dart';
|
||||
import 'package:flutter_tools/src/android/android_device.dart';
|
||||
import 'package:flutter_tools/src/android/android_sdk.dart';
|
||||
import 'package:flutter_tools/src/application_package.dart';
|
||||
import 'package:flutter_tools/src/base/config.dart';
|
||||
import 'package:flutter_tools/src/base/file_system.dart';
|
||||
import 'package:flutter_tools/src/base/io.dart';
|
||||
|
@ -365,7 +366,7 @@ flutter:
|
|||
|
||||
testUsingContext('returns the generated host port from stdout', () async {
|
||||
when(mockProcessManager.run(argThat(contains('forward'))))
|
||||
.thenAnswer((_) async => ProcessResult(0, 0, '456', ''));
|
||||
.thenAnswer((_) async => ProcessResult(0, 0, '456', ''));
|
||||
|
||||
expect(await forwarder.forward(123), equals(456));
|
||||
}, overrides: <Type, Generator>{
|
||||
|
@ -374,7 +375,7 @@ flutter:
|
|||
|
||||
testUsingContext('returns the supplied host port when stdout is empty', () async {
|
||||
when(mockProcessManager.run(argThat(contains('forward'))))
|
||||
.thenAnswer((_) async => ProcessResult(0, 0, '', ''));
|
||||
.thenAnswer((_) async => ProcessResult(0, 0, '', ''));
|
||||
|
||||
expect(await forwarder.forward(123, hostPort: 456), equals(456));
|
||||
}, overrides: <Type, Generator>{
|
||||
|
@ -383,7 +384,7 @@ flutter:
|
|||
|
||||
testUsingContext('returns the supplied host port when stdout is the host port', () async {
|
||||
when(mockProcessManager.run(argThat(contains('forward'))))
|
||||
.thenAnswer((_) async => ProcessResult(0, 0, '456', ''));
|
||||
.thenAnswer((_) async => ProcessResult(0, 0, '456', ''));
|
||||
|
||||
expect(await forwarder.forward(123, hostPort: 456), equals(456));
|
||||
}, overrides: <Type, Generator>{
|
||||
|
@ -392,12 +393,34 @@ flutter:
|
|||
|
||||
testUsingContext('throws an error when stdout is not blank nor the host port', () async {
|
||||
when(mockProcessManager.run(argThat(contains('forward'))))
|
||||
.thenAnswer((_) async => ProcessResult(0, 0, '123456', ''));
|
||||
.thenAnswer((_) async => ProcessResult(0, 0, '123456', ''));
|
||||
|
||||
expect(forwarder.forward(123, hostPort: 456), throwsA(isInstanceOf<ProcessException>()));
|
||||
}, overrides: <Type, Generator>{
|
||||
ProcessManager: () => mockProcessManager,
|
||||
});
|
||||
|
||||
testUsingContext('forwardedPorts returns empty list when forward failed', () {
|
||||
when(mockProcessManager.runSync(argThat(contains('forward'))))
|
||||
.thenReturn(ProcessResult(0, 1, '', ''));
|
||||
|
||||
expect(forwarder.forwardedPorts, equals(const <ForwardedPort>[]));
|
||||
}, overrides: <Type, Generator>{
|
||||
ProcessManager: () => mockProcessManager,
|
||||
});
|
||||
});
|
||||
|
||||
group('lastLogcatTimestamp', () {
|
||||
final ProcessManager mockProcessManager = MockProcessManager();
|
||||
final AndroidDevice device = AndroidDevice('1234');
|
||||
|
||||
testUsingContext('returns null if shell command failed', () async {
|
||||
when(mockProcessManager.runSync(argThat(contains('logcat'))))
|
||||
.thenReturn(ProcessResult(0, 1, '', ''));
|
||||
expect(device.lastLogcatTimestamp, isNull);
|
||||
}, overrides: <Type, Generator>{
|
||||
ProcessManager: () => mockProcessManager,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -601,3 +624,10 @@ class MockUnresponsiveAndroidConsoleSocket extends Mock implements Socket {
|
|||
@override
|
||||
void add(List<int> data) {}
|
||||
}
|
||||
|
||||
class AndroidPackageTest extends ApplicationPackage {
|
||||
AndroidPackageTest() : super(id: 'app-id');
|
||||
|
||||
@override
|
||||
String get name => 'app-package';
|
||||
}
|
||||
|
|
|
@ -129,6 +129,15 @@ void main() {
|
|||
),
|
||||
);
|
||||
}, overrides: overrides);
|
||||
|
||||
testUsingContext('returns null when failed to extract manifest', () async {
|
||||
final AndroidSdkVersion sdkVersion = MockitoAndroidSdkVersion();
|
||||
when(sdk.latestVersion).thenReturn(sdkVersion);
|
||||
when(mockProcessManager.runSync(argThat(contains('logcat'))))
|
||||
.thenReturn(ProcessResult(0, 1, '', ''));
|
||||
|
||||
expect(AndroidApk.fromApk(null), isNull);
|
||||
}, overrides: overrides);
|
||||
});
|
||||
|
||||
group('ApkManifestData', () {
|
||||
|
|
|
@ -6,6 +6,7 @@ import 'dart:async';
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter_tools/src/base/common.dart';
|
||||
import 'package:flutter_tools/src/base/io.dart';
|
||||
import 'package:flutter_tools/src/cache.dart';
|
||||
import 'package:flutter_tools/src/commands/version.dart';
|
||||
|
@ -59,12 +60,29 @@ void main() {
|
|||
}, overrides: <Type, Generator>{
|
||||
ProcessManager: () => MockProcessManager(),
|
||||
});
|
||||
|
||||
testUsingContext('exit tool if can\'t get the tags', () async {
|
||||
final VersionCommand command = VersionCommand();
|
||||
|
||||
try {
|
||||
await command.getTags();
|
||||
fail('ToolExit expected');
|
||||
} catch(e) {
|
||||
expect(e, isInstanceOf<ToolExit>());
|
||||
}
|
||||
}, overrides: <Type, Generator>{
|
||||
ProcessManager: () => MockProcessManager(failGitTag: true),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
class MockProcessManager extends Mock implements ProcessManager {
|
||||
MockProcessManager({ this.failGitTag = false });
|
||||
|
||||
String version = '';
|
||||
|
||||
bool failGitTag;
|
||||
|
||||
@override
|
||||
Future<ProcessResult> run(
|
||||
List<dynamic> command, {
|
||||
|
@ -76,6 +94,9 @@ class MockProcessManager extends Mock implements ProcessManager {
|
|||
Encoding stderrEncoding = systemEncoding,
|
||||
}) async {
|
||||
if (command[0] == 'git' && command[1] == 'tag') {
|
||||
if (failGitTag) {
|
||||
return ProcessResult(0, 1, '', '');
|
||||
}
|
||||
return ProcessResult(0, 0, 'v10.0.0\r\nv20.0.0', '');
|
||||
}
|
||||
if (command[0] == 'git' && command[1] == 'checkout') {
|
||||
|
|
|
@ -440,6 +440,62 @@ void main() {
|
|||
Config: () => mockConfig,
|
||||
AnsiTerminal: () => testTerminal,
|
||||
});
|
||||
|
||||
testUsingContext('find-identity failure', () async {
|
||||
when(mockProcessManager.runSync(<String>['which', 'security']))
|
||||
.thenReturn(exitsHappy);
|
||||
when(mockProcessManager.runSync(<String>['which', 'openssl']))
|
||||
.thenReturn(exitsHappy);
|
||||
when(mockProcessManager.runSync(
|
||||
argThat(contains('find-identity')),
|
||||
environment: anyNamed('environment'),
|
||||
workingDirectory: anyNamed('workingDirectory'),
|
||||
)).thenReturn(ProcessResult(0, 1, '', ''));
|
||||
|
||||
final Map<String, String> signingConfigs = await getCodeSigningIdentityDevelopmentTeam(iosApp: app);
|
||||
expect(signingConfigs, isNull);
|
||||
},
|
||||
overrides: <Type, Generator>{
|
||||
ProcessManager: () => mockProcessManager,
|
||||
Config: () => mockConfig,
|
||||
AnsiTerminal: () => testTerminal,
|
||||
});
|
||||
|
||||
testUsingContext('find-certificate failure', () async {
|
||||
when(mockProcessManager.runSync(<String>['which', 'security']))
|
||||
.thenReturn(exitsHappy);
|
||||
when(mockProcessManager.runSync(<String>['which', 'openssl']))
|
||||
.thenReturn(exitsHappy);
|
||||
when(mockProcessManager.runSync(
|
||||
argThat(contains('find-identity')),
|
||||
environment: anyNamed('environment'),
|
||||
workingDirectory: anyNamed('workingDirectory'),
|
||||
)).thenReturn(ProcessResult(
|
||||
1, // pid
|
||||
0, // exitCode
|
||||
'''
|
||||
1) 86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 "iPhone Developer: Profile 1 (1111AAAA11)"
|
||||
2) da4b9237bacccdf19c0760cab7aec4a8359010b0 "iPhone Developer: Profile 2 (2222BBBB22)"
|
||||
3) 5bf1fd927dfb8679496a2e6cf00cbe50c1c87145 "iPhone Developer: Profile 3 (3333CCCC33)"
|
||||
3 valid identities found''',
|
||||
'',
|
||||
));
|
||||
mockTerminalStdInStream =
|
||||
Stream<String>.fromFuture(Future<String>.value('3'));
|
||||
when(mockProcessManager.runSync(
|
||||
<String>['security', 'find-certificate', '-c', '3333CCCC33', '-p'],
|
||||
environment: anyNamed('environment'),
|
||||
workingDirectory: anyNamed('workingDirectory'),
|
||||
)).thenReturn(ProcessResult(1, 1, '', '' ));
|
||||
|
||||
final Map<String, String> signingConfigs = await getCodeSigningIdentityDevelopmentTeam(iosApp: app);
|
||||
expect(signingConfigs, isNull);
|
||||
},
|
||||
overrides: <Type, Generator>{
|
||||
ProcessManager: () => mockProcessManager,
|
||||
Config: () => mockConfig,
|
||||
AnsiTerminal: () => testTerminal,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -143,6 +143,12 @@ void main() {
|
|||
.thenReturn(ProcessResult(1, 0, 'Xcode 8.3.3\nBuild version 8E3004b', ''));
|
||||
expect(xcodeProjectInterpreter.isInstalled, isTrue);
|
||||
});
|
||||
|
||||
testUsingOsxContext('build settings is empty when xcodebuild failed to get the build settings', () {
|
||||
when(mockProcessManager.runSync(argThat(contains(xcodebuild))))
|
||||
.thenReturn(ProcessResult(0, 1, '', ''));
|
||||
expect(xcodeProjectInterpreter.getBuildSettings('', ''), const <String, String>{});
|
||||
});
|
||||
});
|
||||
group('Xcode project properties', () {
|
||||
test('properties from default project can be parsed', () {
|
||||
|
|
Loading…
Reference in a new issue