Commit 57746f38 authored by xster's avatar xster Committed by GitHub

Guess sign iOS with the first certificate when running in machine mode (#10870)

* Guess sign with the first certificate when multiple are available in machine mode

* review
parent a41e354a
......@@ -341,6 +341,7 @@ class AndroidDevice extends Device {
String kernelPath,
bool prebuiltApplication: false,
bool applicationNeedsRebuild: false,
bool usesTerminalUi: true,
}) async {
if (!await _checkForSupportedAdbVersion() || !await _checkForSupportedAndroidVersion())
return new LaunchResult.failed();
......
......@@ -260,6 +260,7 @@ Future<LaunchResult> _startApp(DriveCommand command) async {
diagnosticPort: command.diagnosticPort,
),
platformArgs: platformArgs,
usesTerminalUi: false,
);
if (!result.started) {
......
......@@ -222,6 +222,11 @@ abstract class Device {
///
/// [platformArgs] allows callers to pass platform-specific arguments to the
/// start call. The build mode is not used by all platforms.
///
/// If [usesTerminalUi] is true, Flutter Tools may attempt to prompt the
/// user to resolve fixable issues such as selecting a signing certificate
/// for iOS device deployment. Set to false if stdin cannot be read from while
/// attempting to start the app.
Future<LaunchResult> startApp(
ApplicationPackage package,
BuildMode mode, {
......@@ -231,7 +236,8 @@ abstract class Device {
Map<String, dynamic> platformArgs,
String kernelPath,
bool prebuiltApplication: false,
bool applicationNeedsRebuild: false
bool applicationNeedsRebuild: false,
bool usesTerminalUi: true,
});
/// Does this device implement support for hot reloading / restarting?
......
......@@ -68,6 +68,7 @@ class FuchsiaDevice extends Device {
bool prebuiltApplication: false,
String kernelPath,
bool applicationNeedsRebuild: false,
bool usesTerminalUi: false,
}) => new Future<Null>.error('unimplemented');
@override
......
......@@ -80,7 +80,7 @@ final RegExp _certificateOrganizationalUnitExtractionPattern = new RegExp(r'OU=(
///
/// Will return null if none are found, if the user cancels or if the Xcode
/// project has a development team set in the project's build settings.
Future<String> getCodeSigningIdentityDevelopmentTeam(BuildableIOSApp iosApp) async{
Future<String> getCodeSigningIdentityDevelopmentTeam({BuildableIOSApp iosApp, bool usesTerminalUi: true}) async{
if (iosApp.buildSettings == null)
return null;
......@@ -115,7 +115,7 @@ Future<String> getCodeSigningIdentityDevelopmentTeam(BuildableIOSApp iosApp) asy
.toSet() // Unique.
.toList();
final String signingIdentity = await _chooseSigningIdentity(validCodeSigningIdentities);
final String signingIdentity = await _chooseSigningIdentity(validCodeSigningIdentities, usesTerminalUi);
// If none are chosen, return null.
if (signingIdentity == null)
......@@ -153,7 +153,7 @@ Future<String> getCodeSigningIdentityDevelopmentTeam(BuildableIOSApp iosApp) asy
?.group(1);
}
Future<String> _chooseSigningIdentity(List<String> validCodeSigningIdentities) async {
Future<String> _chooseSigningIdentity(List<String> validCodeSigningIdentities, bool usesTerminalUi) async {
// The user has no valid code signing identities.
if (validCodeSigningIdentities.isEmpty) {
printError(noCertificatesInstruction, emphasis: true);
......@@ -176,6 +176,11 @@ Future<String> _chooseSigningIdentity(List<String> validCodeSigningIdentities) a
}
}
// If terminal UI can't be used, just attempt with the first valid certificate
// since we can't ask the user.
if (!usesTerminalUi)
return validCodeSigningIdentities.first;
final int count = validCodeSigningIdentities.length;
printStatus(
'Multiple valid development certificates available (your choice will be saved):',
......
......@@ -175,13 +175,20 @@ class IOSDevice extends Device {
bool prebuiltApplication: false,
String kernelPath,
bool applicationNeedsRebuild: false,
bool usesTerminalUi: true,
}) async {
if (!prebuiltApplication) {
// TODO(chinmaygarde): Use mainPath, route.
printTrace('Building ${app.name} for $id');
// Step 1: Build the precompiled/DBC application if necessary.
final XcodeBuildResult buildResult = await buildXcodeProject(app: app, mode: mode, target: mainPath, buildForDevice: true);
final XcodeBuildResult buildResult = await buildXcodeProject(
app: app,
mode: mode,
target: mainPath,
buildForDevice: true,
usesTerminalUi: usesTerminalUi,
);
if (!buildResult.success) {
printError('Could not build the precompiled application for the device.');
await diagnoseXcodeBuildFailure(buildResult, app);
......
......@@ -193,7 +193,8 @@ Future<XcodeBuildResult> buildXcodeProject({
BuildMode mode,
String target: flx.defaultMainPath,
bool buildForDevice,
bool codesign: true
bool codesign: true,
bool usesTerminalUi: true,
}) async {
if (!_checkXcodeVersion())
return new XcodeBuildResult(success: false);
......@@ -205,7 +206,7 @@ Future<XcodeBuildResult> buildXcodeProject({
String developmentTeam;
if (codesign && buildForDevice)
developmentTeam = await getCodeSigningIdentityDevelopmentTeam(app);
developmentTeam = await getCodeSigningIdentityDevelopmentTeam(iosApp: app, usesTerminalUi: usesTerminalUi);
// Before the build, all service definitions must be updated and the dylibs
// copied over to a location that is suitable for Xcodebuild to find them.
......
......@@ -315,6 +315,7 @@ class IOSSimulator extends Device {
String kernelPath,
bool prebuiltApplication: false,
bool applicationNeedsRebuild: false,
bool usesTerminalUi: true,
}) async {
if (!prebuiltApplication) {
printTrace('Building ${app.name} for $id.');
......
......@@ -239,7 +239,8 @@ class FlutterDevice {
route: route,
prebuiltApplication: prebuiltMode,
kernelPath: hotRunner.kernelFilePath,
applicationNeedsRebuild: shouldBuild || hasDirtyDependencies
applicationNeedsRebuild: shouldBuild || hasDirtyDependencies,
usesTerminalUi: hotRunner.usesTerminalUI,
);
final LaunchResult result = await futureResult;
......@@ -298,7 +299,8 @@ class FlutterDevice {
platformArgs: platformArgs,
route: route,
prebuiltApplication: prebuiltMode,
applicationNeedsRebuild: shouldBuild || hasDirtyDependencies
applicationNeedsRebuild: shouldBuild || hasDirtyDependencies,
usesTerminalUi: coldRunner.usesTerminalUI,
);
if (!result.started) {
......
......@@ -38,7 +38,7 @@ void main() {
testUsingContext('No auto-sign if Xcode project settings are not available', () async {
app = new BuildableIOSApp(projectBundleId: 'test.app');
final String developmentTeam = await getCodeSigningIdentityDevelopmentTeam(app);
final String developmentTeam = await getCodeSigningIdentityDevelopmentTeam(iosApp: app);
expect(developmentTeam, isNull);
});
......@@ -49,7 +49,7 @@ void main() {
'DEVELOPMENT_TEAM': 'abc',
},
);
final String developmentTeam = await getCodeSigningIdentityDevelopmentTeam(app);
final String developmentTeam = await getCodeSigningIdentityDevelopmentTeam(iosApp: app);
expect(developmentTeam, isNull);
expect(testLogger.statusText, equals(
'Automatically signing iOS for device deployment using specified development team in Xcode project: abc\n'
......@@ -59,7 +59,7 @@ void main() {
testUsingContext('No auto-sign if security or openssl not available', () async {
when(mockProcessManager.runSync(<String>['which', 'security']))
.thenReturn(exitsFail);
final String developmentTeam = await getCodeSigningIdentityDevelopmentTeam(app);
final String developmentTeam = await getCodeSigningIdentityDevelopmentTeam(iosApp: app);
expect(developmentTeam, isNull);
},
overrides: <Type, Generator>{
......@@ -77,7 +77,7 @@ void main() {
String developmentTeam;
try {
developmentTeam = await getCodeSigningIdentityDevelopmentTeam(app);
developmentTeam = await getCodeSigningIdentityDevelopmentTeam(iosApp: app);
fail('No identity should throw tool error');
} on ToolExit {
expect(developmentTeam, isNull);
......@@ -131,7 +131,7 @@ void main() {
when(mockProcess.stderr).thenReturn(mockStdErr);
when(mockProcess.exitCode).thenReturn(0);
final String developmentTeam = await getCodeSigningIdentityDevelopmentTeam(app);
final String developmentTeam = await getCodeSigningIdentityDevelopmentTeam(iosApp: app);
expect(testLogger.statusText, contains('iPhone Developer: Profile 1 (1111AAAA11)'));
expect(testLogger.errorText, isEmpty);
......@@ -189,7 +189,7 @@ void main() {
when(mockOpenSslProcess.stderr).thenReturn(mockOpenSslStdErr);
when(mockOpenSslProcess.exitCode).thenReturn(0);
final String developmentTeam = await getCodeSigningIdentityDevelopmentTeam(app);
final String developmentTeam = await getCodeSigningIdentityDevelopmentTeam(iosApp: app);
expect(
testLogger.statusText,
......@@ -211,6 +211,68 @@ void main() {
AnsiTerminal: () => testTerminal,
});
testUsingContext('Test multiple identity in machine mode works', () 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: any, workingDirectory: any,
)).thenReturn(new 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 =
new Stream<String>.fromFuture(new Future<String>.error(new Exception('Cannot read from StdIn')));
when(mockProcessManager.runSync(
<String>['security', 'find-certificate', '-c', '1111AAAA11', '-p'],
environment: any,
workingDirectory: any,
)).thenReturn(new ProcessResult(
1, // pid
0, // exitCode
'This is a mock certificate',
'',
));
final MockProcess mockOpenSslProcess = new MockProcess();
final MockStdIn mockOpenSslStdIn = new MockStdIn();
final MockStream mockOpenSslStdErr = new MockStream();
when(mockProcessManager.start(
argThat(contains('openssl')), environment: any, workingDirectory: any,
)).thenReturn(new Future<Process>.value(mockOpenSslProcess));
when(mockOpenSslProcess.stdin).thenReturn(mockOpenSslStdIn);
when(mockOpenSslProcess.stdout).thenReturn(new Stream<List<int>>.fromFuture(
new Future<List<int>>.value(UTF8.encode(
'subject= /CN=iPhone Developer: Profile 1 (1111AAAA11)/OU=5555EEEE55/O=My Team/C=US'
)),
));
when(mockOpenSslProcess.stderr).thenReturn(mockOpenSslStdErr);
when(mockOpenSslProcess.exitCode).thenReturn(0);
final String developmentTeam = await getCodeSigningIdentityDevelopmentTeam(iosApp: app, usesTerminalUi: false);
expect(
testLogger.statusText,
contains('Signing iOS app for device deployment using developer identity: "iPhone Developer: Profile 1 (1111AAAA11)"'),
);
expect(testLogger.errorText, isEmpty);
verify(mockOpenSslStdIn.write('This is a mock certificate'));
expect(developmentTeam, '5555EEEE55');
},
overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
AnsiTerminal: () => testTerminal,
});
testUsingContext('Test saved certificate used', () async {
when(mockProcessManager.runSync(<String>['which', 'security']))
.thenReturn(exitsHappy);
......@@ -257,7 +319,7 @@ void main() {
when(mockOpenSslProcess.exitCode).thenReturn(0);
when(mockConfig.getValue('ios-signing-cert')).thenReturn('iPhone Developer: Profile 3 (3333CCCC33)');
final String developmentTeam = await getCodeSigningIdentityDevelopmentTeam(app);
final String developmentTeam = await getCodeSigningIdentityDevelopmentTeam(iosApp: app);
expect(
testLogger.statusText,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment