1// Copyright (c) 2017 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5import 'dart:async'; 6import 'dart:io' as dart_io; 7 8import 'package:file/file.dart'; 9import 'package:file/local.dart' as io; 10import 'package:path/path.dart' as path; 11 12import 'utils.dart'; 13 14const String _kProvisioningConfigFileEnvironmentVariable = 'FLUTTER_DEVICELAB_XCODE_PROVISIONING_CONFIG'; 15const String _kTestXcconfigFileName = 'TestConfig.xcconfig'; 16const FileSystem _fs = io.LocalFileSystem(); 17 18/// Patches the given Xcode project adding provisioning certificates and team 19/// information required to build and run the project, if 20/// FLUTTER_DEVICELAB_XCODE_PROVISIONING_CONFIG is set. If it is not set, 21/// we rely on automatic signing by Xcode. 22Future<void> prepareProvisioningCertificates(String flutterProjectPath) async { 23 final String certificateConfig = await _readProvisioningConfigFile(); 24 if (certificateConfig == null) { 25 // No cert config available, rely on automatic signing by Xcode. 26 return; 27 } 28 29 await _patchXcconfigFilesIfNotPatched(flutterProjectPath); 30 final File testXcconfig = _fs.file(path.join(flutterProjectPath, 'ios/Flutter/$_kTestXcconfigFileName')); 31 await testXcconfig.writeAsString(certificateConfig); 32} 33 34Future<void> runPodInstallForCustomPodfile(String flutterProjectPath) async { 35 final String iosPath = path.join(flutterProjectPath, 'ios'); 36 exec('pod', <String>['install', '--project-directory=$iosPath']); 37} 38 39Future<void> _patchXcconfigFilesIfNotPatched(String flutterProjectPath) async { 40 final List<File> xcconfigFiles = <File>[ 41 _fs.file(path.join(flutterProjectPath, 'ios/Flutter/Flutter.xcconfig')), 42 _fs.file(path.join(flutterProjectPath, 'ios/Flutter/Debug.xcconfig')), 43 _fs.file(path.join(flutterProjectPath, 'ios/Flutter/Release.xcconfig')), 44 ]; 45 46 bool xcconfigFileExists = false; 47 48 for (final File file in xcconfigFiles) { 49 if (await file.exists()) { 50 xcconfigFileExists = true; 51 const String include = '#include "$_kTestXcconfigFileName"'; 52 final String contents = await file.readAsString(); 53 final bool alreadyPatched = contents.contains(include); 54 if (!alreadyPatched) { 55 final IOSink patchOut = file.openWrite(mode: FileMode.append); 56 patchOut.writeln(); // in case EOF is not preceded by line break 57 patchOut.writeln(include); 58 await patchOut.close(); 59 } 60 } 61 } 62 63 if (!xcconfigFileExists) { 64 final String candidatesFormatted = xcconfigFiles.map<String>((File f) => f.path).join(', '); 65 throw 'Failed to locate a xcconfig file to patch with provisioning profile ' 66 'info. Tried: $candidatesFormatted'; 67 } 68} 69 70Future<String> _readProvisioningConfigFile() async { 71 void throwUsageError(String specificMessage) { 72 throw ''' 73================================================================================ 74You are attempting to build an XCode project, which requires a provisioning 75certificate and team information. The test framework attempted to locate an 76.xcconfig file whose path is defined by the environment variable 77$_kProvisioningConfigFileEnvironmentVariable. 78 79$specificMessage 80================================================================================ 81'''.trim(); 82 } 83 84 if (!dart_io.Platform.environment.containsKey(_kProvisioningConfigFileEnvironmentVariable)) { 85 print(''' 86$_kProvisioningConfigFileEnvironmentVariable variable is not defined in your 87environment. Relying on automatic signing by Xcode... 88'''.trim()); 89 return null; 90 } 91 92 final String filePath = dart_io.Platform.environment[_kProvisioningConfigFileEnvironmentVariable]; 93 final File file = _fs.file(filePath); 94 if (!(await file.exists())) { 95 throwUsageError(''' 96File not found: $filePath 97 98It is defined by environment variable $_kProvisioningConfigFileEnvironmentVariable 99'''.trim()); 100 } 101 102 return file.readAsString(); 103} 104