mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-15 13:35:19 +00:00
Working state
This commit is contained in:
parent
1965e01680
commit
ac0eb23815
@ -112,7 +112,7 @@ def decrypt_codesigning_directory_recursively(source_base_path, destination_base
|
|||||||
decrypt_codesigning_directory_recursively(source_path, destination_path, password)
|
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):
|
if not os.path.exists(working_dir):
|
||||||
os.makedirs(working_dir, exist_ok=True)
|
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:
|
if always_fetch:
|
||||||
original_working_dir = os.getcwd()
|
original_working_dir = os.getcwd()
|
||||||
os.chdir(encrypted_working_dir)
|
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 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)
|
os.chdir(original_working_dir)
|
||||||
else:
|
else:
|
||||||
os.makedirs(encrypted_working_dir, exist_ok=True)
|
os.makedirs(encrypted_working_dir, exist_ok=True)
|
||||||
original_working_dir = os.getcwd()
|
original_working_dir = os.getcwd()
|
||||||
os.chdir(working_dir)
|
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,
|
repo_url=repo_url,
|
||||||
branch=branch,
|
branch=branch,
|
||||||
target_path=encrypted_working_dir
|
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))
|
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):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def load_data(self, working_dir):
|
||||||
|
raise Exception('Not implemented')
|
||||||
|
|
||||||
def copy_profiles_to_destination(self, destination_path):
|
def copy_profiles_to_destination(self, destination_path):
|
||||||
raise Exception('Not implemented')
|
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):
|
class GitCodesigningSource(CodesigningSource):
|
||||||
self.working_dir = working_dir
|
def __init__(self, repo_url, team_id, bundle_id, codesigning_type, password, always_fetch):
|
||||||
self.repo_url = repo_url
|
self.repo_url = repo_url
|
||||||
self.team_id = team_id
|
self.team_id = team_id
|
||||||
self.bundle_id = bundle_id
|
self.bundle_id = bundle_id
|
||||||
self.profile_type = profile_type
|
self.codesigning_type = codesigning_type
|
||||||
self.password = password
|
self.password = password
|
||||||
self.always_fetch = always_fetch
|
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):
|
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)
|
source_path = self.working_dir + '/decrypted/profiles/{}'.format(self.codesigning_type)
|
||||||
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)
|
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):
|
def __init__(self, directory_path, team_id, bundle_id):
|
||||||
self.directory_path = directory_path
|
self.directory_path = directory_path
|
||||||
self.team_id = team_id
|
self.team_id = team_id
|
||||||
self.bundle_id = bundle_id
|
self.bundle_id = bundle_id
|
||||||
|
|
||||||
|
def load_data(self, working_dir):
|
||||||
|
pass
|
||||||
|
|
||||||
def copy_profiles_to_destination(self, destination_path):
|
def copy_profiles_to_destination(self, destination_path):
|
||||||
profiles_path = self.directory_path
|
copy_profiles_from_directory(source_path=self.directory_path + '/profiles', destination_path=destination_path, team_id=self.team_id, bundle_id=self.bundle_id)
|
||||||
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)
|
|
||||||
|
|
||||||
|
def copy_certificates_to_destination(self, destination_path):
|
||||||
def generate_configuration_repository(path, profile_source):
|
copy_certificates_from_directory(source_path=self.directory_path + '/certs', destination_path=destination_path)
|
||||||
pass
|
|
||||||
|
@ -40,7 +40,7 @@ def import_certificates(certificatesPath):
|
|||||||
|
|
||||||
for file_name in os.listdir(certificatesPath):
|
for file_name in os.listdir(certificatesPath):
|
||||||
file_path = certificatesPath + '/' + file_name
|
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=[
|
run_executable_with_output('security', arguments=[
|
||||||
'import',
|
'import',
|
||||||
file_path,
|
file_path,
|
||||||
|
@ -7,11 +7,12 @@ import sys
|
|||||||
import tempfile
|
import tempfile
|
||||||
import subprocess
|
import subprocess
|
||||||
import shutil
|
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 ProjectGeneration import generate
|
||||||
from BazelLocation import locate_bazel
|
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
|
import RemoteBuild
|
||||||
|
|
||||||
class BazelCommandLine:
|
class BazelCommandLine:
|
||||||
@ -383,7 +384,7 @@ def clean(bazel, arguments):
|
|||||||
bazel_command_line.invoke_clean()
|
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
|
profile_source = None
|
||||||
if arguments.gitCodesigningRepository is not None:
|
if arguments.gitCodesigningRepository is not None:
|
||||||
password = os.getenv('TELEGRAM_CODESIGNING_GIT_PASSWORD')
|
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')
|
print('--gitCodesigningType is required if --gitCodesigningRepository is set')
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
workdir_path = '{}/build-input/configuration-repository-workdir'.format(base_path)
|
profile_source = GitCodesigningSource(
|
||||||
os.makedirs(workdir_path, exist_ok=True)
|
|
||||||
|
|
||||||
profile_source = GitProvisioningProfileSource(
|
|
||||||
working_dir=workdir_path,
|
|
||||||
repo_url=arguments.gitCodesigningRepository,
|
repo_url=arguments.gitCodesigningRepository,
|
||||||
team_id=build_configuration.team_id,
|
team_id=build_configuration.team_id,
|
||||||
bundle_id=build_configuration.bundle_id,
|
bundle_id=build_configuration.bundle_id,
|
||||||
profile_type=arguments.gitCodesigningType,
|
codesigning_type=arguments.gitCodesigningType,
|
||||||
password=password,
|
password=password,
|
||||||
always_fetch=arguments.gitCodesigningAlwaysFetch
|
always_fetch=arguments.gitCodesigningAlwaysFetch
|
||||||
)
|
)
|
||||||
elif arguments.provisioningProfilesPath is not None:
|
elif arguments.codesigningInformationPath is not None:
|
||||||
profile_source = DirectoryProvisioningProfileSource(
|
profile_source = DirectoryCodesigningSource(
|
||||||
directory_path=arguments.provisioningProfilesPath,
|
directory_path=arguments.codesigningInformationPath,
|
||||||
team_id=build_configuration.team_id,
|
team_id=build_configuration.team_id,
|
||||||
bundle_id=build_configuration.bundle_id
|
bundle_id=build_configuration.bundle_id
|
||||||
)
|
)
|
||||||
else:
|
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)
|
configuration_repository_path = '{}/build-input/configuration-repository'.format(base_path)
|
||||||
os.makedirs(configuration_repository_path, exist_ok=True)
|
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)
|
shutil.rmtree(provisioning_path)
|
||||||
os.makedirs(provisioning_path, exist_ok=True)
|
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 = []
|
provisioning_profile_files = []
|
||||||
for file_name in os.listdir(provisioning_path):
|
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'.format(file_name))
|
||||||
file.write('])\n')
|
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):
|
def generate_project(bazel, arguments):
|
||||||
@ -469,10 +482,13 @@ def generate_project(bazel, arguments):
|
|||||||
|
|
||||||
bazel_command_line.set_continue_on_error(arguments.continueOnError)
|
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)
|
resolve_configuration(
|
||||||
|
base_path=os.getcwd(),
|
||||||
if bazel_command_line is not None:
|
bazel_command_line=bazel_command_line,
|
||||||
bazel_command_line.set_configuration_path(configuration_repository_path)
|
arguments=arguments,
|
||||||
|
aps_environment=arguments.apsEnvironment,
|
||||||
|
additional_codesigning_output_path=None
|
||||||
|
)
|
||||||
|
|
||||||
bazel_command_line.set_build_number(arguments.buildNumber)
|
bazel_command_line.set_build_number(arguments.buildNumber)
|
||||||
|
|
||||||
@ -516,7 +532,13 @@ def build(bazel, arguments):
|
|||||||
elif arguments.cacheHost is not None:
|
elif arguments.cacheHost is not None:
|
||||||
bazel_command_line.add_remote_cache(arguments.cacheHost)
|
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_configuration(arguments.configuration)
|
||||||
bazel_command_line.set_build_number(arguments.buildNumber)
|
bazel_command_line.set_build_number(arguments.buildNumber)
|
||||||
@ -528,6 +550,36 @@ def build(bazel, arguments):
|
|||||||
|
|
||||||
bazel_command_line.invoke_build()
|
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):
|
def test(bazel, arguments):
|
||||||
bazel_command_line = BazelCommandLine(
|
bazel_command_line = BazelCommandLine(
|
||||||
@ -542,7 +594,13 @@ def test(bazel, arguments):
|
|||||||
elif arguments.cacheHost is not None:
|
elif arguments.cacheHost is not None:
|
||||||
bazel_command_line.add_remote_cache(arguments.cacheHost)
|
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_configuration('debug_sim_arm64')
|
||||||
bazel_command_line.set_build_number('10000')
|
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 = 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(
|
codesigning_group.add_argument(
|
||||||
'--gitCodesigningRepository',
|
'--gitCodesigningRepository',
|
||||||
help='''
|
help='''
|
||||||
@ -578,15 +629,21 @@ def add_codesigning_common_arguments(current_parser: argparse.ArgumentParser):
|
|||||||
metavar='path'
|
metavar='path'
|
||||||
)
|
)
|
||||||
codesigning_group.add_argument(
|
codesigning_group.add_argument(
|
||||||
'--provisioningProfilesPath',
|
'--codesigningInformationPath',
|
||||||
help='''
|
help='''
|
||||||
Use provisioning profiles from a local directory.
|
Use signing certificates and provisioning profiles from a local directory.
|
||||||
''',
|
''',
|
||||||
metavar='command'
|
metavar='command'
|
||||||
)
|
)
|
||||||
|
|
||||||
current_parser.add_argument(
|
current_parser.add_argument(
|
||||||
'--gitCodesigningType',
|
'--gitCodesigningType',
|
||||||
|
choices=[
|
||||||
|
'development',
|
||||||
|
'adhoc',
|
||||||
|
'appstore',
|
||||||
|
'enterprise'
|
||||||
|
],
|
||||||
required=False,
|
required=False,
|
||||||
help='''
|
help='''
|
||||||
The name of the folder to use inside "profiles" folder in the git repository.
|
The name of the folder to use inside "profiles" folder in the git repository.
|
||||||
@ -793,6 +850,12 @@ if __name__ == '__main__':
|
|||||||
default=False,
|
default=False,
|
||||||
help='Enable sandbox.',
|
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.')
|
remote_build_parser = subparsers.add_parser('remote-build', help='Build the app using a remote environment.')
|
||||||
add_codesigning_common_arguments(remote_build_parser)
|
add_codesigning_common_arguments(remote_build_parser)
|
||||||
@ -802,7 +865,7 @@ if __name__ == '__main__':
|
|||||||
type=str,
|
type=str,
|
||||||
help='DarwinContainers host address.'
|
help='DarwinContainers host address.'
|
||||||
)
|
)
|
||||||
buildParser.add_argument(
|
remote_build_parser.add_argument(
|
||||||
'--configuration',
|
'--configuration',
|
||||||
choices=[
|
choices=[
|
||||||
'debug_universal',
|
'debug_universal',
|
||||||
@ -816,7 +879,7 @@ if __name__ == '__main__':
|
|||||||
help='Build configuration'
|
help='Build configuration'
|
||||||
)
|
)
|
||||||
remote_build_parser.add_argument(
|
remote_build_parser.add_argument(
|
||||||
'--bazelCacheHost',
|
'--cacheHost',
|
||||||
required=False,
|
required=False,
|
||||||
type=str,
|
type=str,
|
||||||
help='Bazel remote cache host address.'
|
help='Bazel remote cache host address.'
|
||||||
@ -850,24 +913,27 @@ if __name__ == '__main__':
|
|||||||
elif args.commandName == 'remote-build':
|
elif args.commandName == 'remote-build':
|
||||||
base_path = os.getcwd()
|
base_path = os.getcwd()
|
||||||
remote_input_path = '{}/build-input/remote-input'.format(base_path)
|
remote_input_path = '{}/build-input/remote-input'.format(base_path)
|
||||||
certificates_path = '{}/certs'.format(remote_input_path)
|
if os.path.exists(remote_input_path):
|
||||||
provisioning_profiles_path = '{}/profiles'.format(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)
|
resolve_configuration(
|
||||||
os.makedirs(provisioning_profiles_path, exist_ok=True)
|
base_path=os.getcwd(),
|
||||||
|
bazel_command_line=None,
|
||||||
configuration_repository_path = resolve_configuration(base_path=os.getcwd(), bazel_command_line=None, arguments=arguments, aps_environment='production')
|
arguments=args,
|
||||||
|
aps_environment='production',
|
||||||
certificates_path = '{}/certs'.format(configuration_repository_path)
|
additional_codesigning_output_path=remote_input_path
|
||||||
provisioning_profiles_path = '{}/profiles'.format(configuration_repository_path)
|
)
|
||||||
|
|
||||||
|
shutil.copyfile(args.configurationPath, remote_input_path + '/configuration.json')
|
||||||
|
|
||||||
RemoteBuild.remote_build(
|
RemoteBuild.remote_build(
|
||||||
darwin_containers_host=args.darwinContainersHost,
|
darwin_containers_host=args.darwinContainersHost,
|
||||||
bazel_cache_host=args.bazelCacheHost,
|
bazel_cache_host=args.cacheHost,
|
||||||
configuration=args.configuration,
|
configuration=args.configuration,
|
||||||
certificates_path=certificates_path,
|
build_input_data_path=remote_input_path
|
||||||
provisioning_profiles_path=provisioning_profiles_path,
|
|
||||||
configurationPath=args.configurationPath
|
|
||||||
)
|
)
|
||||||
elif args.commandName == 'test':
|
elif args.commandName == 'test':
|
||||||
test(bazel=bazel_path, arguments=args)
|
test(bazel=bazel_path, arguments=args)
|
||||||
|
@ -35,7 +35,9 @@ def session_ssh(session, command):
|
|||||||
)
|
)
|
||||||
return os.system(ssh_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
|
from darwin_containers import DarwinContainers
|
||||||
|
|
||||||
base_dir = os.getcwd()
|
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)
|
build_number = build_number_offset + int(commit_count)
|
||||||
print('Build number: {}'.format(build_number))
|
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)
|
image_name = 'macos-{macos_version}-xcode-{xcode_version}'.format(macos_version=macos_version, xcode_version=xcode_version)
|
||||||
|
|
||||||
print('Image name: {}'.format(image_name))
|
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...')
|
print('Opening container session...')
|
||||||
with darwinContainers.workingImageSession(name=image_name) as session:
|
with darwinContainers.workingImageSession(name=image_name) as session:
|
||||||
print('Uploading data to container...')
|
print('Uploading data to container...')
|
||||||
session_scp_upload(session=session, source_path=certificates_path, destination_path='certs')
|
session_scp_upload(session=session, source_path=build_input_data_path, destination_path='telegram-build-input')
|
||||||
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='{base_dir}/{buildbox_dir}/transient-data/source.tar'.format(base_dir=base_dir, buildbox_dir=buildbox_dir), destination_path='')
|
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 = '''
|
guest_build_sh = '''
|
||||||
mkdir telegram-ios
|
set -x
|
||||||
cd telegram-ios
|
set -e
|
||||||
tar -xf ../source.tar
|
|
||||||
|
|
||||||
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()
|
guest_build_file_path = tempfile.mktemp()
|
||||||
with open(guest_build_file_path, 'w+') as file:
|
with open(guest_build_file_path, 'w+') as file:
|
||||||
file.write(guest_build_sh)
|
file.write(guest_build_sh)
|
||||||
@ -114,8 +120,6 @@ def remote_build(darwin_containers_host, bazel_cache_host, configuration, certif
|
|||||||
|
|
||||||
print('Executing remote build...')
|
print('Executing remote build...')
|
||||||
|
|
||||||
if bazel_cache_host is None:
|
|
||||||
bazel_cache_host = ''
|
|
||||||
session_ssh(session=session, command='bash -l guest-build-telegram.sh')
|
session_ssh(session=session, command='bash -l guest-build-telegram.sh')
|
||||||
|
|
||||||
print('Retrieving build artifacts...')
|
print('Retrieving build artifacts...')
|
||||||
@ -125,5 +129,10 @@ def remote_build(darwin_containers_host, bazel_cache_host, configuration, certif
|
|||||||
shutil.rmtree(artifacts_path)
|
shutil.rmtree(artifacts_path)
|
||||||
os.makedirs(artifacts_path, exist_ok=True)
|
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))
|
session_scp_download(session=session, source_path='/Users/Shared/telegram-ios/build/artifacts/*', destination_path='{artifacts_path}/'.format(artifacts_path=artifacts_path))
|
||||||
print('Artifacts have been stored at {}'.format(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)
|
||||||
|
@ -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)
|
|
||||||
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user