Make most ios_workflow host tool calls async (#10260)

Does not yet migrate hasIdeviceId since that results in a cascade of
breaking interface changes that's significant enough for a separate
patch.
This commit is contained in:
Chris Bracken 2017-05-22 16:09:48 -07:00 committed by GitHub
parent 9a908f7558
commit dd1456ffbc
3 changed files with 70 additions and 58 deletions

View file

@ -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/platform.dart';
import '../base/process.dart';
@ -32,53 +33,55 @@ class IOSWorkflow extends DoctorValidator implements Workflow {
bool get hasIDeviceId => exitsHappy(<String>['idevice_id', '-h']);
bool get hasWorkingLibimobiledevice {
Future<bool> get hasWorkingLibimobiledevice async {
// Verify that libimobiledevice tools are installed.
if (!hasIDeviceId)
return false;
// If a device is attached, verify that we can get its name.
final String result = runSync(<String>['idevice_id', '-l']);
if (result.isNotEmpty && !exitsHappy(<String>['idevicename']))
final ProcessResult result = (await runAsync(<String>['idevice_id', '-l'])).processResult;
if (result.exitCode == 0 && result.stdout.isNotEmpty && !await exitsHappyAsync(<String>['idevicename']))
return false;
return true;
}
bool get hasIDeviceInstaller => exitsHappy(<String>['ideviceinstaller', '-h']);
Future<bool> get hasIDeviceInstaller => exitsHappyAsync(<String>['ideviceinstaller', '-h']);
bool get hasIosDeploy => exitsHappy(<String>['ios-deploy', '--version']);
Future<bool> get hasIosDeploy => exitsHappyAsync(<String>['ios-deploy', '--version']);
String get iosDeployMinimumVersion => '1.9.0';
String get iosDeployVersionText => runSync(<String>['ios-deploy', '--version']).replaceAll('\n', '');
Future<String> get iosDeployVersionText async =>
(await runAsync(<String>['ios-deploy', '--version'])).processResult.stdout.replaceAll('\n', '');
bool get hasHomebrew => os.which('brew') != null;
bool get hasPythonSixModule => kPythonSix.isInstalled;
bool get hasCocoaPods => exitsHappy(<String>['pod', '--version']);
Future<bool> get hasCocoaPods => exitsHappyAsync(<String>['pod', '--version']);
String get cocoaPodsMinimumVersion => '1.0.0';
String get cocoaPodsVersionText => runSync(<String>['pod', '--version']).trim();
Future<String> get cocoaPodsVersionText async =>
(await runAsync(<String>['pod', '--version'])).processResult.stdout.trim();
bool get _iosDeployIsInstalledAndMeetsVersionCheck {
if (!hasIosDeploy)
Future<bool> get _iosDeployIsInstalledAndMeetsVersionCheck async {
if (!await hasIosDeploy)
return false;
try {
final Version version = new Version.parse(iosDeployVersionText);
final Version version = new Version.parse(await iosDeployVersionText);
return version >= new Version.parse(iosDeployMinimumVersion);
} on FormatException catch (_) {
return false;
}
}
bool get isCocoaPodsInstalledAndMeetsVersionCheck {
if (!hasCocoaPods)
Future<bool> get isCocoaPodsInstalledAndMeetsVersionCheck async {
if (!await hasCocoaPods)
return false;
try {
final Version installedVersion = new Version.parse(cocoaPodsVersionText);
final Version installedVersion = new Version.parse(await cocoaPodsVersionText);
return installedVersion >= new Version.parse(cocoaPodsMinimumVersion);
} on FormatException {
return false;
@ -86,11 +89,8 @@ class IOSWorkflow extends DoctorValidator implements Workflow {
}
/// Whether CocoaPods ran 'pod setup' once where the costly pods' specs are cloned.
bool get isCocoaPodsInitialized {
return fs.isDirectorySync(
fs.path.join(homeDirPath, '.cocoapods', 'repos', 'master')
);
}
Future<bool> get isCocoaPodsInitialized =>
fs.isDirectory(fs.path.join(homeDirPath, '.cocoapods', 'repos', 'master'));
@override
Future<ValidationResult> validate() async {
@ -152,7 +152,7 @@ class IOSWorkflow extends DoctorValidator implements Workflow {
if (hasHomebrew) {
brewStatus = ValidationType.installed;
if (!hasWorkingLibimobiledevice) {
if (!await hasWorkingLibimobiledevice) {
brewStatus = ValidationType.partial;
messages.add(new ValidationMessage.error(
'libimobiledevice is incompatible with the installed Xcode version. To update, run:\n'
@ -162,7 +162,7 @@ class IOSWorkflow extends DoctorValidator implements Workflow {
));
}
if (!hasIDeviceInstaller) {
if (!await hasIDeviceInstaller) {
brewStatus = ValidationType.partial;
messages.add(new ValidationMessage.error(
'ideviceinstaller not available; this is used to discover connected iOS devices.\n'
@ -174,12 +174,12 @@ class IOSWorkflow extends DoctorValidator implements Workflow {
}
// Check ios-deploy is installed at meets version requirements.
if (hasIosDeploy) {
messages.add(new ValidationMessage('ios-deploy $iosDeployVersionText'));
if (await hasIosDeploy) {
messages.add(new ValidationMessage('ios-deploy ${await iosDeployVersionText}'));
}
if (!_iosDeployIsInstalledAndMeetsVersionCheck) {
if (!await _iosDeployIsInstalledAndMeetsVersionCheck) {
brewStatus = ValidationType.partial;
if (hasIosDeploy) {
if (await hasIosDeploy) {
messages.add(new ValidationMessage.error(
'ios-deploy out of date ($iosDeployMinimumVersion is required). To upgrade:\n'
' brew update\n'
@ -194,9 +194,9 @@ class IOSWorkflow extends DoctorValidator implements Workflow {
}
}
if (isCocoaPodsInstalledAndMeetsVersionCheck) {
if (isCocoaPodsInitialized) {
messages.add(new ValidationMessage('CocoaPods version $cocoaPodsVersionText'));
if (await isCocoaPodsInstalledAndMeetsVersionCheck) {
if (await isCocoaPodsInitialized) {
messages.add(new ValidationMessage('CocoaPods version ${await cocoaPodsVersionText}'));
} else {
brewStatus = ValidationType.partial;
messages.add(new ValidationMessage.error(
@ -209,7 +209,7 @@ class IOSWorkflow extends DoctorValidator implements Workflow {
}
} else {
brewStatus = ValidationType.partial;
if (!hasCocoaPods) {
if (!await hasCocoaPods) {
messages.add(new ValidationMessage.error(
'CocoaPods not installed.\n'
'$noCocoaPodsConsequence\n'

View file

@ -365,7 +365,7 @@ final String cocoaPodsUpgradeInstructions = '''
Future<Null> _runPodInstall(Directory bundle, String engineDirectory) async {
if (fs.file(fs.path.join(bundle.path, 'Podfile')).existsSync()) {
if (!doctor.iosWorkflow.isCocoaPodsInstalledAndMeetsVersionCheck) {
if (!await doctor.iosWorkflow.isCocoaPodsInstalledAndMeetsVersionCheck) {
final String minimumVersion = doctor.iosWorkflow.cocoaPodsMinimumVersion;
printError(
'Warning: CocoaPods version $minimumVersion or greater not installed. Skipping pod install.\n'
@ -376,7 +376,7 @@ Future<Null> _runPodInstall(Directory bundle, String engineDirectory) async {
);
return;
}
if (!doctor.iosWorkflow.isCocoaPodsInitialized) {
if (!await doctor.iosWorkflow.isCocoaPodsInitialized) {
printError(
'Warning: CocoaPods installed but not initialized. Skipping pod install.\n'
'$noCocoaPodsConsequence\n'

View file

@ -2,6 +2,8 @@
// 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/memory.dart';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/file_system.dart';
@ -30,10 +32,11 @@ void main() {
testUsingContext('Emit missing status when nothing is installed', () async {
when(xcode.isInstalled).thenReturn(false);
when(xcode.xcodeSelectPath).thenReturn(null);
final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget()
..hasPythonSixModule = false
..hasHomebrew = false
..hasIosDeploy = false;
final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(
hasPythonSixModule: false,
hasHomebrew: false,
hasIosDeploy: false,
);
final ValidationResult result = await workflow.validate();
expect(result.type, ValidationType.missing);
}, overrides: <Type, Generator>{ Xcode: () => xcode });
@ -82,8 +85,7 @@ void main() {
.thenReturn('Xcode 8.2.1\nBuild version 8C1002\n');
when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true);
when(xcode.eulaSigned).thenReturn(true);
final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget()
..hasPythonSixModule = false;
final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(hasPythonSixModule: false);
final ValidationResult result = await workflow.validate();
expect(result.type, ValidationType.partial);
}, overrides: <Type, Generator>{ Xcode: () => xcode });
@ -94,8 +96,7 @@ void main() {
.thenReturn('Xcode 8.2.1\nBuild version 8C1002\n');
when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true);
when(xcode.eulaSigned).thenReturn(true);
final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget()
..hasHomebrew = false;
final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(hasHomebrew: false);
final ValidationResult result = await workflow.validate();
expect(result.type, ValidationType.partial);
}, overrides: <Type, Generator>{ Xcode: () => xcode });
@ -106,8 +107,7 @@ void main() {
.thenReturn('Xcode 8.2.1\nBuild version 8C1002\n');
when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true);
when(xcode.eulaSigned).thenReturn(true);
final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget()
..hasWorkingLibimobiledevice = false;
final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(hasWorkingLibimobiledevice: false);
final ValidationResult result = await workflow.validate();
expect(result.type, ValidationType.partial);
}, overrides: <Type, Generator>{ Xcode: () => xcode });
@ -118,8 +118,7 @@ void main() {
.thenReturn('Xcode 8.2.1\nBuild version 8C1002\n');
when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true);
when(xcode.eulaSigned).thenReturn(true);
final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget()
..hasIosDeploy = false;
final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(hasIosDeploy: false);
final ValidationResult result = await workflow.validate();
expect(result.type, ValidationType.partial);
}, overrides: <Type, Generator>{ Xcode: () => xcode });
@ -130,8 +129,7 @@ void main() {
.thenReturn('Xcode 8.2.1\nBuild version 8C1002\n');
when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true);
when(xcode.eulaSigned).thenReturn(true);
final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget()
..iosDeployVersionText = '1.8.0';
final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(iosDeployVersionText: '1.8.0');
final ValidationResult result = await workflow.validate();
expect(result.type, ValidationType.partial);
}, overrides: <Type, Generator>{ Xcode: () => xcode });
@ -142,8 +140,7 @@ void main() {
.thenReturn('Xcode 8.2.1\nBuild version 8C1002\n');
when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true);
when(xcode.eulaSigned).thenReturn(true);
final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget()
..hasCocoaPods = false;
final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(hasCocoaPods: false);
final ValidationResult result = await workflow.validate();
expect(result.type, ValidationType.partial);
}, overrides: <Type, Generator>{ Xcode: () => xcode });
@ -154,8 +151,7 @@ void main() {
.thenReturn('Xcode 8.2.1\nBuild version 8C1002\n');
when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true);
when(xcode.eulaSigned).thenReturn(true);
final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget()
..cocoaPodsVersionText = '0.39.0';
final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(cocoaPodsVersionText: '0.39.0');
final ValidationResult result = await workflow.validate();
expect(result.type, ValidationType.partial);
}, overrides: <Type, Generator>{ Xcode: () => xcode });
@ -215,27 +211,43 @@ class MockXcode extends Mock implements Xcode {}
class MockProcessManager extends Mock implements ProcessManager {}
class IOSWorkflowTestTarget extends IOSWorkflow {
@override
bool hasPythonSixModule = true;
IOSWorkflowTestTarget({
this.hasPythonSixModule: true,
this.hasHomebrew: true,
bool hasWorkingLibimobiledevice: true,
bool hasIosDeploy: true,
String iosDeployVersionText: '1.9.0',
bool hasIDeviceInstaller: true,
bool hasCocoaPods: true,
String cocoaPodsVersionText: '1.2.0',
}) : hasWorkingLibimobiledevice = new Future<bool>.value(hasWorkingLibimobiledevice),
hasIosDeploy = new Future<bool>.value(hasIosDeploy),
iosDeployVersionText = new Future<String>.value(iosDeployVersionText),
hasIDeviceInstaller = new Future<bool>.value(hasIDeviceInstaller),
hasCocoaPods = new Future<bool>.value(hasCocoaPods),
cocoaPodsVersionText = new Future<String>.value(cocoaPodsVersionText);
@override
bool hasHomebrew = true;
final bool hasPythonSixModule;
@override
bool hasWorkingLibimobiledevice = true;
final bool hasHomebrew;
@override
bool hasIosDeploy = true;
final Future<bool> hasWorkingLibimobiledevice;
@override
String iosDeployVersionText = '1.9.0';
final Future<bool> hasIosDeploy;
@override
bool get hasIDeviceInstaller => true;
final Future<String> iosDeployVersionText;
@override
bool hasCocoaPods = true;
final Future<bool> hasIDeviceInstaller;
@override
String cocoaPodsVersionText = '1.2.0';
final Future<bool> hasCocoaPods;
@override
final Future<String> cocoaPodsVersionText;
}