Unverified Commit 01dc19b9 authored by Jenn Magder's avatar Jenn Magder Committed by GitHub

Pass environment variables through to xcodebuild (#43553)

parent 19e551c7
...@@ -464,6 +464,7 @@ Future<XcodeBuildResult> buildXcodeProject({ ...@@ -464,6 +464,7 @@ Future<XcodeBuildResult> buildXcodeProject({
// e.g. `flutter build bundle`. // e.g. `flutter build bundle`.
buildCommands.add('FLUTTER_SUPPRESS_ANALYTICS=true'); buildCommands.add('FLUTTER_SUPPRESS_ANALYTICS=true');
buildCommands.add('COMPILER_INDEX_STORE_ENABLE=NO'); buildCommands.add('COMPILER_INDEX_STORE_ENABLE=NO');
buildCommands.addAll(environmentVariablesAsXcodeBuildSettings());
final Stopwatch sw = Stopwatch()..start(); final Stopwatch sw = Stopwatch()..start();
initialBuildStatus = logger.startProgress('Running Xcode build...', timeout: timeoutConfiguration.fastOperation); initialBuildStatus = logger.startProgress('Running Xcode build...', timeout: timeoutConfiguration.fastOperation);
......
...@@ -293,9 +293,10 @@ class XcodeProjectInterpreter { ...@@ -293,9 +293,10 @@ class XcodeProjectInterpreter {
'-target', '-target',
target, target,
'-showBuildSettings', '-showBuildSettings',
...environmentVariablesAsXcodeBuildSettings()
]; ];
try { try {
// showBuildSettings is reported to ocassionally timeout. Here, we give it // showBuildSettings is reported to occasionally timeout. Here, we give it
// a lot of wiggle room (locally on Flutter Gallery, this takes ~1s). // a lot of wiggle room (locally on Flutter Gallery, this takes ~1s).
// When there is a timeout, we retry once. // When there is a timeout, we retry once.
final RunResult result = await processUtils.run( final RunResult result = await processUtils.run(
...@@ -329,6 +330,7 @@ class XcodeProjectInterpreter { ...@@ -329,6 +330,7 @@ class XcodeProjectInterpreter {
scheme, scheme,
'-quiet', '-quiet',
'clean', 'clean',
...environmentVariablesAsXcodeBuildSettings()
], workingDirectory: fs.currentDirectory.path); ], workingDirectory: fs.currentDirectory.path);
} }
...@@ -354,6 +356,21 @@ class XcodeProjectInterpreter { ...@@ -354,6 +356,21 @@ class XcodeProjectInterpreter {
} }
} }
/// Environment variables prefixed by FLUTTER_XCODE_ will be passed as build configurations to xcodebuild.
/// This allows developers to pass arbitrary build settings in without the tool needing to make a flag
/// for or be aware of each one. This could be used to set code signing build settings in a CI
/// environment without requiring settings changes in the Xcode project.
List<String> environmentVariablesAsXcodeBuildSettings() {
const String xcodeBuildSettingPrefix = 'FLUTTER_XCODE_';
return platform.environment.entries.where((MapEntry<String, String> mapEntry) {
return mapEntry.key.startsWith(xcodeBuildSettingPrefix);
}).expand<String>((MapEntry<String, String> mapEntry) {
// Remove FLUTTER_XCODE_ prefix from the environment variable to get the build setting.
final String trimmedBuildSettingKey = mapEntry.key.substring(xcodeBuildSettingPrefix.length);
return <String>['$trimmedBuildSettingKey=${mapEntry.value}'];
}).toList();
}
Map<String, String> parseXcodeBuildSettings(String showBuildSettingsOutput) { Map<String, String> parseXcodeBuildSettings(String showBuildSettingsOutput) {
final Map<String, String> settings = <String, String>{}; final Map<String, String> settings = <String, String>{};
for (Match match in showBuildSettingsOutput.split('\n').map<Match>(_settingExpr.firstMatch)) { for (Match match in showBuildSettingsOutput.split('\n').map<Match>(_settingExpr.firstMatch)) {
......
...@@ -79,6 +79,7 @@ Future<void> buildMacOS({ ...@@ -79,6 +79,7 @@ Future<void> buildMacOS({
'OBJROOT=${fs.path.join(flutterBuildDir.absolute.path, 'Build', 'Intermediates.noindex')}', 'OBJROOT=${fs.path.join(flutterBuildDir.absolute.path, 'Build', 'Intermediates.noindex')}',
'SYMROOT=${fs.path.join(flutterBuildDir.absolute.path, 'Build', 'Products')}', 'SYMROOT=${fs.path.join(flutterBuildDir.absolute.path, 'Build', 'Products')}',
'COMPILER_INDEX_STORE_ENABLE=NO', 'COMPILER_INDEX_STORE_ENABLE=NO',
...environmentVariablesAsXcodeBuildSettings()
], trace: true); ], trace: true);
} finally { } finally {
status.cancel(); status.cancel();
......
...@@ -23,7 +23,7 @@ import '../../src/pubspec_schema.dart'; ...@@ -23,7 +23,7 @@ import '../../src/pubspec_schema.dart';
const String xcodebuild = '/usr/bin/xcodebuild'; const String xcodebuild = '/usr/bin/xcodebuild';
void main() { void main() {
group('xcodebuild versioning', () { group('xcodebuild commands', () {
mocks.MockProcessManager mockProcessManager; mocks.MockProcessManager mockProcessManager;
XcodeProjectInterpreter xcodeProjectInterpreter; XcodeProjectInterpreter xcodeProjectInterpreter;
FakePlatform macOS; FakePlatform macOS;
...@@ -172,6 +172,54 @@ void main() { ...@@ -172,6 +172,54 @@ void main() {
FileSystem: () => fs, FileSystem: () => fs,
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
}); });
testUsingOsxContext('build settings contains Flutter Xcode environment variables', () async {
macOS.environment = Map<String, String>.unmodifiable(<String, String>{
'FLUTTER_XCODE_CODE_SIGN_STYLE': 'Manual',
'FLUTTER_XCODE_ARCHS': 'arm64'
});
when(mockProcessManager.runSync(<String>[
xcodebuild,
'-project',
macOS.pathSeparator,
'-target',
'',
'-showBuildSettings',
'CODE_SIGN_STYLE=Manual',
'ARCHS=arm64'
],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment')))
.thenReturn(ProcessResult(1, 0, '', ''));
expect(await xcodeProjectInterpreter.getBuildSettings('', ''), const <String, String>{});
});
testUsingOsxContext('clean contains Flutter Xcode environment variables', () async {
macOS.environment = Map<String, String>.unmodifiable(<String, String>{
'FLUTTER_XCODE_CODE_SIGN_STYLE': 'Manual',
'FLUTTER_XCODE_ARCHS': 'arm64'
});
when(mockProcessManager.runSync(
any,
workingDirectory: anyNamed('workingDirectory')))
.thenReturn(ProcessResult(1, 0, '', ''));
xcodeProjectInterpreter.cleanWorkspace('workspace_path', 'Runner');
final List<dynamic> captured = verify(mockProcessManager.runSync(
captureAny,
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'))).captured;
expect(captured.first, <String>[
xcodebuild,
'-workspace',
'workspace_path',
'-scheme',
'Runner',
'-quiet',
'clean',
'CODE_SIGN_STYLE=Manual',
'ARCHS=arm64'
]);
});
}); });
group('xcodebuild -list', () { group('xcodebuild -list', () {
...@@ -338,6 +386,27 @@ Information about project "Runner": ...@@ -338,6 +386,27 @@ Information about project "Runner":
}); });
}); });
group('environmentVariablesAsXcodeBuildSettings', () {
FakePlatform platform;
setUp(() {
platform = fakePlatform('ignored');
});
testUsingContext('environment variables as Xcode build settings', () {
platform.environment = Map<String, String>.unmodifiable(<String, String>{
'Ignored': 'Bogus',
'FLUTTER_NOT_XCODE': 'Bogus',
'FLUTTER_XCODE_CODE_SIGN_STYLE': 'Manual',
'FLUTTER_XCODE_ARCHS': 'arm64'
});
final List<String> environmentVariablesAsBuildSettings = environmentVariablesAsXcodeBuildSettings();
expect(environmentVariablesAsBuildSettings, <String>['CODE_SIGN_STYLE=Manual', 'ARCHS=arm64']);
}, overrides: <Type, Generator>{
Platform: () => platform
});
});
group('updateGeneratedXcodeProperties', () { group('updateGeneratedXcodeProperties', () {
MockLocalEngineArtifacts mockArtifacts; MockLocalEngineArtifacts mockArtifacts;
MockProcessManager mockProcessManager; MockProcessManager mockProcessManager;
......
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