diff --git a/build-system/Make/BuildConfiguration.py b/build-system/Make/BuildConfiguration.py index 463a44c8e0..3029f6bf08 100644 --- a/build-system/Make/BuildConfiguration.py +++ b/build-system/Make/BuildConfiguration.py @@ -112,7 +112,7 @@ def decrypt_codesigning_directory_recursively(source_base_path, destination_base decrypt_codesigning_directory_recursively(source_path, destination_path, password) -def load_provisioning_profiles_from_git(working_dir, repo_url, branch, password, always_fetch): +def load_codesigning_data_from_git(working_dir, repo_url, branch, password, always_fetch): if not os.path.exists(working_dir): os.makedirs(working_dir, exist_ok=True) @@ -121,15 +121,15 @@ def load_provisioning_profiles_from_git(working_dir, repo_url, branch, password, if always_fetch: original_working_dir = os.getcwd() os.chdir(encrypted_working_dir) - os.system('git fetch') + os.system('GIT_SSH_COMMAND="ssh -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" git fetch') os.system('git checkout "{branch}"'.format(branch=branch)) - os.system('git pull') + os.system('GIT_SSH_COMMAND="ssh -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" git pull') os.chdir(original_working_dir) else: os.makedirs(encrypted_working_dir, exist_ok=True) original_working_dir = os.getcwd() os.chdir(working_dir) - os.system('git clone {repo_url} -b "{branch}" "{target_path}"'.format( + os.system('git -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null clone {repo_url} -b "{branch}" "{target_path}"'.format( repo_url=repo_url, branch=branch, target_path=encrypted_working_dir @@ -185,42 +185,67 @@ def copy_profiles_from_directory(source_path, destination_path, team_id, bundle_ print('Warning: skipping provisioning profile at {} with bundle_id {} (base_name {})'.format(file_path, profile_name, profile_base_name)) -class ProvisioningProfileSource: +def copy_certificates_from_directory(source_path, destination_path): + for file_name in os.listdir(source_path): + file_path = source_path + '/' + file_name + if os.path.isfile(file_path): + if file_path.endswith('.p12') or file_path.endswith('.cer'): + shutil.copyfile(file_path, destination_path + '/' + file_name) + + +class CodesigningSource: def __init__(self): pass + def load_data(self, working_dir): + raise Exception('Not implemented') + def copy_profiles_to_destination(self, destination_path): raise Exception('Not implemented') + def copy_certificates_to_destination(self, destination_path): + raise Exception('Not implemented') -class GitProvisioningProfileSource(ProvisioningProfileSource): - def __init__(self, working_dir, repo_url, team_id, bundle_id, profile_type, password, always_fetch): - self.working_dir = working_dir + +class GitCodesigningSource(CodesigningSource): + def __init__(self, repo_url, team_id, bundle_id, codesigning_type, password, always_fetch): self.repo_url = repo_url self.team_id = team_id self.bundle_id = bundle_id - self.profile_type = profile_type + self.codesigning_type = codesigning_type self.password = password self.always_fetch = always_fetch + def load_data(self, working_dir): + self.working_dir = working_dir + load_codesigning_data_from_git(working_dir=self.working_dir, repo_url=self.repo_url, branch=self.team_id, password=self.password, always_fetch=self.always_fetch) + def copy_profiles_to_destination(self, destination_path): - load_provisioning_profiles_from_git(working_dir=self.working_dir, repo_url=self.repo_url, branch=self.team_id, password=self.password, always_fetch=self.always_fetch) - copy_profiles_from_directory(source_path=self.working_dir + '/decrypted/profiles/{}'.format(self.profile_type), destination_path=destination_path, team_id=self.team_id, bundle_id=self.bundle_id) + source_path = self.working_dir + '/decrypted/profiles/{}'.format(self.codesigning_type) + copy_profiles_from_directory(source_path=source_path, destination_path=destination_path, team_id=self.team_id, bundle_id=self.bundle_id) + + def copy_certificates_to_destination(self, destination_path): + source_path = None + if self.codesigning_type in ['adhoc', 'appstore', 'enterprise']: + source_path = self.working_dir + '/decrypted/certs/distribution' + elif self.codesigning_type == 'development': + source_path = self.working_dir + '/decrypted/certs/development' + else: + raise Exception('Unknown codesigning type {}'.format(self.codesigning_type)) + copy_certificates_from_directory(source_path=source_path, destination_path=destination_path) -class DirectoryProvisioningProfileSource(ProvisioningProfileSource): +class DirectoryCodesigningSource(CodesigningSource): def __init__(self, directory_path, team_id, bundle_id): self.directory_path = directory_path self.team_id = team_id self.bundle_id = bundle_id + def load_data(self, working_dir): + pass + def copy_profiles_to_destination(self, destination_path): - profiles_path = self.directory_path - if not os.path.exists(profiles_path): - print('{} does not exist'.format(profiles_path)) - sys.exit(1) - copy_profiles_from_directory(source_path=profiles_path, destination_path=destination_path, team_id=self.team_id, bundle_id=self.bundle_id) + copy_profiles_from_directory(source_path=self.directory_path + '/profiles', destination_path=destination_path, team_id=self.team_id, bundle_id=self.bundle_id) - -def generate_configuration_repository(path, profile_source): - pass + def copy_certificates_to_destination(self, destination_path): + copy_certificates_from_directory(source_path=self.directory_path + '/certs', destination_path=destination_path) diff --git a/build-system/Make/ImportCertificates.py b/build-system/Make/ImportCertificates.py index 2e6ddd6a1e..c449fe4b5e 100644 --- a/build-system/Make/ImportCertificates.py +++ b/build-system/Make/ImportCertificates.py @@ -40,7 +40,7 @@ def import_certificates(certificatesPath): for file_name in os.listdir(certificatesPath): file_path = certificatesPath + '/' + file_name - if file_path.endwith('.p12') or file_path.endwith('.cer'): + if file_path.endswith('.p12') or file_path.endswith('.cer'): run_executable_with_output('security', arguments=[ 'import', file_path, diff --git a/build-system/Make/Make.py b/build-system/Make/Make.py index f3e5c3ed19..a392e31a71 100644 --- a/build-system/Make/Make.py +++ b/build-system/Make/Make.py @@ -7,11 +7,12 @@ import sys import tempfile import subprocess import shutil +import glob -from BuildEnvironment import resolve_executable, call_executable, BuildEnvironment +from BuildEnvironment import resolve_executable, call_executable, run_executable_with_output, BuildEnvironment from ProjectGeneration import generate from BazelLocation import locate_bazel -from BuildConfiguration import ProvisioningProfileSource, GitProvisioningProfileSource, DirectoryProvisioningProfileSource, BuildConfiguration, build_configuration_from_json +from BuildConfiguration import CodesigningSource, GitCodesigningSource, DirectoryCodesigningSource, BuildConfiguration, build_configuration_from_json import RemoteBuild class BazelCommandLine: @@ -383,7 +384,7 @@ def clean(bazel, arguments): bazel_command_line.invoke_clean() -def resolve_codesigning(arguments, base_path, build_configuration, certificates_path, provisioning_profiles_path): +def resolve_codesigning(arguments, base_path, build_configuration, provisioning_profiles_path, additional_codesigning_output_path): profile_source = None if arguments.gitCodesigningRepository is not None: password = os.getenv('TELEGRAM_CODESIGNING_GIT_PASSWORD') @@ -395,31 +396,36 @@ def resolve_codesigning(arguments, base_path, build_configuration, certificates_ print('--gitCodesigningType is required if --gitCodesigningRepository is set') sys.exit(1) - workdir_path = '{}/build-input/configuration-repository-workdir'.format(base_path) - os.makedirs(workdir_path, exist_ok=True) - - profile_source = GitProvisioningProfileSource( - working_dir=workdir_path, + profile_source = GitCodesigningSource( repo_url=arguments.gitCodesigningRepository, team_id=build_configuration.team_id, bundle_id=build_configuration.bundle_id, - profile_type=arguments.gitCodesigningType, + codesigning_type=arguments.gitCodesigningType, password=password, always_fetch=arguments.gitCodesigningAlwaysFetch ) - elif arguments.provisioningProfilesPath is not None: - profile_source = DirectoryProvisioningProfileSource( - directory_path=arguments.provisioningProfilesPath, + elif arguments.codesigningInformationPath is not None: + profile_source = DirectoryCodesigningSource( + directory_path=arguments.codesigningInformationPath, team_id=build_configuration.team_id, bundle_id=build_configuration.bundle_id ) else: - raise Exception('Neither gitCodesigningRepository nor provisioningProfilesPath are set') + raise Exception('Neither gitCodesigningRepository nor codesigningInformationPath are set') - profile_source.copy_profiles_to_destination(destination_path=provisioning_profiles_path) + workdir_path = '{}/build-input/configuration-repository-workdir'.format(base_path) + os.makedirs(workdir_path, exist_ok=True) + profile_source.load_data(working_dir=workdir_path) + + if provisioning_profiles_path is not None: + profile_source.copy_profiles_to_destination(destination_path=provisioning_profiles_path) + + if additional_codesigning_output_path is not None: + profile_source.copy_profiles_to_destination(destination_path=additional_codesigning_output_path + '/profiles') + profile_source.copy_certificates_to_destination(destination_path=additional_codesigning_output_path + '/certs') -def resolve_configuration(base_path, bazel_command_line: BazelCommandLine, arguments, aps_environment): +def resolve_configuration(base_path, bazel_command_line: BazelCommandLine, arguments, aps_environment, additional_codesigning_output_path): configuration_repository_path = '{}/build-input/configuration-repository'.format(base_path) os.makedirs(configuration_repository_path, exist_ok=True) @@ -438,7 +444,13 @@ def resolve_configuration(base_path, bazel_command_line: BazelCommandLine, argum shutil.rmtree(provisioning_path) os.makedirs(provisioning_path, exist_ok=True) - resolve_codesigning(arguments=arguments, base_path=base_path, build_configuration=build_configuration, certificates_path=None, provisioning_profiles_path=provisioning_path) + resolve_codesigning( + arguments=arguments, + base_path=base_path, + build_configuration=build_configuration, + provisioning_profiles_path=provisioning_path, + additional_codesigning_output_path=additional_codesigning_output_path + ) provisioning_profile_files = [] for file_name in os.listdir(provisioning_path): @@ -451,7 +463,8 @@ def resolve_configuration(base_path, bazel_command_line: BazelCommandLine, argum file.write(' "{}",\n'.format(file_name)) file.write('])\n') - return configuration_repository_path + if bazel_command_line is not None: + bazel_command_line.set_configuration_path(configuration_repository_path) def generate_project(bazel, arguments): @@ -469,10 +482,13 @@ def generate_project(bazel, arguments): bazel_command_line.set_continue_on_error(arguments.continueOnError) - configuration_repository_path = resolve_configuration(base_path=os.getcwd(), bazel_command_line=bazel_command_line, arguments=arguments, aps_environment=arguments.apsEnvironment) - - if bazel_command_line is not None: - bazel_command_line.set_configuration_path(configuration_repository_path) + resolve_configuration( + base_path=os.getcwd(), + bazel_command_line=bazel_command_line, + arguments=arguments, + aps_environment=arguments.apsEnvironment, + additional_codesigning_output_path=None + ) bazel_command_line.set_build_number(arguments.buildNumber) @@ -516,7 +532,13 @@ def build(bazel, arguments): elif arguments.cacheHost is not None: bazel_command_line.add_remote_cache(arguments.cacheHost) - resolve_configuration(base_path=os.getcwd(), bazel_command_line=bazel_command_line, arguments=arguments, aps_environment=arguments.apsEnvironment) + resolve_configuration( + base_path=os.getcwd(), + bazel_command_line=bazel_command_line, + arguments=arguments, + aps_environment=arguments.apsEnvironment, + additional_codesigning_output_path=None + ) bazel_command_line.set_configuration(arguments.configuration) bazel_command_line.set_build_number(arguments.buildNumber) @@ -528,6 +550,36 @@ def build(bazel, arguments): bazel_command_line.invoke_build() + if arguments.outputBuildArtifactsPath is not None: + artifacts_path = arguments.outputBuildArtifactsPath + if os.path.exists(artifacts_path + '/Telegram.ipa'): + os.remove(path) + if os.path.exists(artifacts_path + '/DSYMs'): + shutil.rmtree(artifacts_path + '/DSYMs') + os.makedirs(artifacts_path, exist_ok=True) + os.makedirs(artifacts_path + '/DSYMs', exist_ok=True) + + ipa_paths = glob.glob('bazel-out/applebin_ios-ios_arm*-opt-ST-*/bin/Telegram/Telegram.ipa') + if len(ipa_paths) == 0: + print('Could not find the IPA at bazel-out/applebin_ios-ios_arm*-opt-ST-*/bin/Telegram/Telegram.ipa') + sys.exit(1) + elif len(ipa_paths) > 1: + print('Multiple matching IPA files found: {}'.format(ipa_paths)) + sys.exit(1) + shutil.copyfile(ipa_paths[0], artifacts_path + '/Telegram.ipa') + + dsym_paths = glob.glob('bazel-out/applebin_ios-ios_arm*-opt-ST-*/bin/Telegram/*.dSYM') + for dsym_path in dsym_paths: + file_name = os.path.basename(dsym_path) + shutil.copyfile(ipa_paths[0], artifacts_path + '/DSYMs/{}'.format(file_name)) + run_executable_with_output('zip', arguments=[ + '-9', + '-r', + artifacts_path + '/Telegram.DSYMs.zip', + artifacts_path + '/DSYMs' + ], check_result=True) + shutil.rmtree(artifacts_path + '/DSYMs') + def test(bazel, arguments): bazel_command_line = BazelCommandLine( @@ -542,7 +594,13 @@ def test(bazel, arguments): elif arguments.cacheHost is not None: bazel_command_line.add_remote_cache(arguments.cacheHost) - resolve_configuration(base_path=os.getcwd(), bazel_command_line=bazel_command_line, arguments=arguments, aps_environment=arguments.apsEnvironment) + resolve_configuration( + base_path=os.getcwd(), + bazel_command_line=bazel_command_line, + arguments=arguments, + aps_environment=arguments.apsEnvironment, + additional_codesigning_output_path=None + ) bazel_command_line.set_configuration('debug_sim_arm64') bazel_command_line.set_build_number('10000') @@ -562,13 +620,6 @@ def add_codesigning_common_arguments(current_parser: argparse.ArgumentParser): ) codesigning_group = current_parser.add_mutually_exclusive_group(required=True) - codesigning_group.add_argument( - '--reproducibleCodesigning', - action='store_true', - help=''' - Use locally generated provisioning profiles and certificates for a reproducible build. - ''' - ) codesigning_group.add_argument( '--gitCodesigningRepository', help=''' @@ -578,15 +629,21 @@ def add_codesigning_common_arguments(current_parser: argparse.ArgumentParser): metavar='path' ) codesigning_group.add_argument( - '--provisioningProfilesPath', + '--codesigningInformationPath', help=''' - Use provisioning profiles from a local directory. + Use signing certificates and provisioning profiles from a local directory. ''', metavar='command' ) current_parser.add_argument( '--gitCodesigningType', + choices=[ + 'development', + 'adhoc', + 'appstore', + 'enterprise' + ], required=False, help=''' The name of the folder to use inside "profiles" folder in the git repository. @@ -793,6 +850,12 @@ if __name__ == '__main__': default=False, help='Enable sandbox.', ) + buildParser.add_argument( + '--outputBuildArtifactsPath', + required=False, + help='Store IPA and DSYM at the specified path after a successful build.', + metavar='arguments' + ) remote_build_parser = subparsers.add_parser('remote-build', help='Build the app using a remote environment.') add_codesigning_common_arguments(remote_build_parser) @@ -802,7 +865,7 @@ if __name__ == '__main__': type=str, help='DarwinContainers host address.' ) - buildParser.add_argument( + remote_build_parser.add_argument( '--configuration', choices=[ 'debug_universal', @@ -816,7 +879,7 @@ if __name__ == '__main__': help='Build configuration' ) remote_build_parser.add_argument( - '--bazelCacheHost', + '--cacheHost', required=False, type=str, help='Bazel remote cache host address.' @@ -850,24 +913,27 @@ if __name__ == '__main__': elif args.commandName == 'remote-build': base_path = os.getcwd() remote_input_path = '{}/build-input/remote-input'.format(base_path) - certificates_path = '{}/certs'.format(remote_input_path) - provisioning_profiles_path = '{}/profiles'.format(remote_input_path) + if os.path.exists(remote_input_path): + shutil.rmtree(remote_input_path) + os.makedirs(remote_input_path) + os.makedirs(remote_input_path + '/certs') + os.makedirs(remote_input_path + '/profiles') - os.makedirs(certificates_path, exist_ok=True) - os.makedirs(provisioning_profiles_path, exist_ok=True) - - configuration_repository_path = resolve_configuration(base_path=os.getcwd(), bazel_command_line=None, arguments=arguments, aps_environment='production') - - certificates_path = '{}/certs'.format(configuration_repository_path) - provisioning_profiles_path = '{}/profiles'.format(configuration_repository_path) + resolve_configuration( + base_path=os.getcwd(), + bazel_command_line=None, + arguments=args, + aps_environment='production', + additional_codesigning_output_path=remote_input_path + ) + + shutil.copyfile(args.configurationPath, remote_input_path + '/configuration.json') RemoteBuild.remote_build( darwin_containers_host=args.darwinContainersHost, - bazel_cache_host=args.bazelCacheHost, + bazel_cache_host=args.cacheHost, configuration=args.configuration, - certificates_path=certificates_path, - provisioning_profiles_path=provisioning_profiles_path, - configurationPath=args.configurationPath + build_input_data_path=remote_input_path ) elif args.commandName == 'test': test(bazel=bazel_path, arguments=args) diff --git a/build-system/Make/RemoteBuild.py b/build-system/Make/RemoteBuild.py index e7bb7f2e6c..bdca64501b 100644 --- a/build-system/Make/RemoteBuild.py +++ b/build-system/Make/RemoteBuild.py @@ -35,7 +35,9 @@ def session_ssh(session, command): ) return os.system(ssh_command) -def remote_build(darwin_containers_host, bazel_cache_host, configuration, certificates_path, provisioning_profiles_path, configurationPath): +def remote_build(darwin_containers_host, bazel_cache_host, configuration, build_input_data_path): + macos_version = '12.5' + from darwin_containers import DarwinContainers base_dir = os.getcwd() @@ -63,7 +65,6 @@ def remote_build(darwin_containers_host, bazel_cache_host, configuration, certif build_number = build_number_offset + int(commit_count) print('Build number: {}'.format(build_number)) - macos_version = '12.5' image_name = 'macos-{macos_version}-xcode-{xcode_version}'.format(macos_version=macos_version, xcode_version=xcode_version) print('Image name: {}'.format(image_name)) @@ -83,29 +84,34 @@ def remote_build(darwin_containers_host, bazel_cache_host, configuration, certif print('Opening container session...') with darwinContainers.workingImageSession(name=image_name) as session: print('Uploading data to container...') - session_scp_upload(session=session, source_path=certificates_path, destination_path='certs') - session_scp_upload(session=session, source_path=provisioning_profiles_path, destination_path='profiles') - session_scp_upload(session=session, source_path=configurationPath, destination_path='configuration.json') + session_scp_upload(session=session, source_path=build_input_data_path, destination_path='telegram-build-input') session_scp_upload(session=session, source_path='{base_dir}/{buildbox_dir}/transient-data/source.tar'.format(base_dir=base_dir, buildbox_dir=buildbox_dir), destination_path='') guest_build_sh = ''' - mkdir telegram-ios - cd telegram-ios - tar -xf ../source.tar + set -x + set -e - python3 build-system/Make/ImportCertificates.py --path $HOME/certs + mkdir /Users/Shared/telegram-ios + cd /Users/Shared/telegram-ios + + tar -xf $HOME/source.tar + + python3 build-system/Make/ImportCertificates.py --path $HOME/telegram-build-input/certs + + ''' + + guest_build_sh += 'python3 build-system/Make/Make.py \\' + if bazel_cache_host is not None: + guest_build_sh += '--cacheHost="{}" \\'.format(bazel_cache_host) + guest_build_sh += 'build \\' + guest_build_sh += '' + guest_build_sh += '--buildNumber={} \\'.format(build_number) + guest_build_sh += '--configuration={} \\'.format(configuration) + guest_build_sh += '--configurationPath=$HOME/telegram-build-input/configuration.json \\' + guest_build_sh += '--codesigningInformationPath=$HOME/telegram-build-input \\' + guest_build_sh += '--apsEnvironment=production \\' + guest_build_sh += '--outputBuildArtifactsPath=/Users/Shared/telegram-ios/build/artifacts \\' - python3 build-system/Make/Make.py \\ - build \\ - --buildNumber={build_number} \\ - --configuration={configuration} \\ - --configurationPath=$HOME/configuration.json \\ - --apsEnvironment=production \\ - --provisioningProfilesPath=$HOME/profiles - '''.format( - build_number=build_number, - configuration=configuration - ) guest_build_file_path = tempfile.mktemp() with open(guest_build_file_path, 'w+') as file: file.write(guest_build_sh) @@ -114,8 +120,6 @@ def remote_build(darwin_containers_host, bazel_cache_host, configuration, certif print('Executing remote build...') - if bazel_cache_host is None: - bazel_cache_host = '' session_ssh(session=session, command='bash -l guest-build-telegram.sh') print('Retrieving build artifacts...') @@ -125,5 +129,10 @@ def remote_build(darwin_containers_host, bazel_cache_host, configuration, certif shutil.rmtree(artifacts_path) os.makedirs(artifacts_path, exist_ok=True) - session_scp_download(session=session, source_path='telegram-ios/build/artifacts/*', destination_path='{artifacts_path}/'.format(artifacts_path=artifacts_path)) - print('Artifacts have been stored at {}'.format(artifacts_path)) + session_scp_download(session=session, source_path='/Users/Shared/telegram-ios/build/artifacts/*', destination_path='{artifacts_path}/'.format(artifacts_path=artifacts_path)) + + if os.path.exists(artifacts_path + '/Telegram.ipa'): + print('Artifacts have been stored at {}'.format(artifacts_path)) + else: + print('Telegram.ipa not found') + sys.exit(1) diff --git a/buildbox/build.py b/buildbox/build.py deleted file mode 100644 index 151967507e..0000000000 --- a/buildbox/build.py +++ /dev/null @@ -1,244 +0,0 @@ -#!/usr/bin/python3 - -import argparse -import json -import os -import sys -import shlex -import shutil -import subprocess -import time -import pipes -import tempfile - -def quote_args(seq): - return ' '.join(pipes.quote(arg) for arg in seq) - -def get_clean_env(): - clean_env = os.environ.copy() - return clean_env - -def resolve_executable(program): - def is_executable(fpath): - return os.path.isfile(fpath) and os.access(fpath, os.X_OK) - - for path in get_clean_env()["PATH"].split(os.pathsep): - executable_file = os.path.join(path, program) - if is_executable(executable_file): - return executable_file - return None - - -def run_executable_with_output(path, arguments, check_result=False): - executable_path = resolve_executable(path) - if executable_path is None: - raise Exception('Could not resolve {} to a valid executable file'.format(path)) - - process = subprocess.Popen( - [executable_path] + arguments, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - env=get_clean_env() - ) - output_data, _ = process.communicate() - output_string = output_data.decode('utf-8') - - if check_result: - if process.returncode != 0: - print('Command {} {} finished with non-zero return code and output:\n{}'.format(executable_path, arguments, output_string)) - sys.exit(1) - - return output_string - - - - -def isolated_build(arguments): - if arguments.certificatesPath is not None: - if not os.path.exists(arguments.certificatesPath): - print('{} does not exist'.format(arguments.certificatesPath)) - sys.exit(1) - - keychain_name = 'temp.keychain' - keychain_password = 'secret' - - existing_keychains = run_executable_with_output('security', arguments=['list-keychains'], check_result=True) - if keychain_name in existing_keychains: - run_executable_with_output('security', arguments=['delete-keychain'], check_result=True) - - run_executable_with_output('security', arguments=[ - 'create-keychain', - '-p', - keychain_password, - keychain_name - ], check_result=True) - - existing_keychains = run_executable_with_output('security', arguments=['list-keychains', '-d', 'user']) - existing_keychains.replace('"', '') - - run_executable_with_output('security', arguments=[ - 'list-keychains', - '-d', - 'user', - '-s', - keychain_name, - existing_keychains - ], check_result=True) - - run_executable_with_output('security', arguments=['set-keychain-settings', keychain_name]) - run_executable_with_output('security', arguments=['unlock-keychain', '-p', keychain_password, keychain_name]) - - for file_name in os.listdir(arguments.certificatesPath): - file_path = arguments.certificatesPath + '/' + file_name - if file_path.endwith('.p12') or file_path.endwith('.cer'): - run_executable_with_output('security', arguments=[ - 'import', - file_path, - '-k', - keychain_name, - '-P', - '', - '-T', - '/usr/bin/codesign', - '-T', - '/usr/bin/security' - ], check_result=True) - - run_executable_with_output('security', arguments=[ - 'import', - 'build-system/AppleWWDRCAG3.cer', - '-k', - keychain_name, - '-P', - '', - '-T', - '/usr/bin/codesign', - '-T', - '/usr/bin/security' - ], check_result=True) - - run_executable_with_output('security', arguments=[ - 'set-key-partition-list', - '-S', - 'apple-tool:,apple:', - '-k', - keychain_password, - keychain_name - ], check_result=True) - - build_arguments = ['build-system/Make/Make.py'] - - #build_arguments.append('--bazel="$(pwd)/tools/bazel"') - - if arguments.cacheHost is not None: - build_arguments.append('--cacheHost={}'.format(arguments.cacheHost)) - - build_arguments.append('build') - - build_arguments.append('--configurationPath={}'.format(arguments.configurationPath)) - build_arguments.append('--buildNumber={}'.format(arguments.buildNumber)) - build_arguments.append('--configuration={}'.format(arguments.configuration)) - build_arguments.append('--apsEnvironment=production') - build_arguments.append('--disableParallelSwiftmoduleGeneration') - build_arguments.append('--provisioningProfilesPath={}'.format(arguments.provisioningProfilesPath)) - - build_command = 'python3 ' + quote_args(build_arguments) - print('Running {}'.format(build_command)) - os.system(build_command) - - -if __name__ == '__main__': - parser = argparse.ArgumentParser(prog='build') - - parser.add_argument( - '--verbose', - action='store_true', - default=False, - help='Print debug info' - ) - - subparsers = parser.add_subparsers(dest='commandName', help='Commands') - - remote_build_parser = subparsers.add_parser('remote-build', help='Build the app using a remote environment.') - remote_build_parser.add_argument( - '--darwinContainersHost', - required=True, - type=str, - help='DarwinContainers host address.' - ) - remote_build_parser.add_argument( - '--configuration', - choices=[ - 'appcenter', - 'appstore', - 'reproducible' - ], - required=True, - help='Build configuration' - ) - remote_build_parser.add_argument( - '--bazelCacheHost', - required=False, - type=str, - help='Bazel remote cache host address.' - ) - - isolated_build_parser = subparsers.add_parser('isolated-build', help='Build the app inside an isolated environment.') - isolated_build_parser.add_argument( - '--certificatesPath', - required=False, - type=str, - help='Install codesigning certificates from the specified directory.' - ) - isolated_build_parser.add_argument( - '--provisioningProfilesPath', - required=True, - help=''' - Use codesigning provisioning profiles from a local directory. - ''', - metavar='command' - ) - isolated_build_parser.add_argument( - '--cacheHost', - required=False, - type=str, - help='Bazel cache host url.' - ) - isolated_build_parser.add_argument( - '--configurationPath', - help=''' - Path to a json containing build configuration. - See build-system/appstore-configuration.json for an example. - ''', - required=True, - metavar='path' - ) - isolated_build_parser.add_argument( - '--buildNumber', - required=True, - type=int, - help='Build number.', - metavar='number' - ) - isolated_build_parser.add_argument( - '--configuration', - type=str, - required=True, - help='Build configuration' - ) - - if len(sys.argv) < 2: - parser.print_help() - sys.exit(1) - - args = parser.parse_args() - - if args.commandName is None: - exit(0) - - if args.commandName == 'remote-build': - remote_build(darwin_containers_host=args.darwinContainersHost, bazel_cache_host=args.bazelCacheHost, configuration=args.configuration) - elif args.commandName == 'isolated-build': - isolated_build(arguments=args) - -