Chromium Code Reviews| Index: build/config/ios/codesign.py |
| diff --git a/build/config/ios/codesign.py b/build/config/ios/codesign.py |
| index b7fc8bef31f11cae4808dc58fccccca47ba32568..4cc0820d6ed31cd6587fac57572f5356d562d235 100644 |
| --- a/build/config/ios/codesign.py |
| +++ b/build/config/ios/codesign.py |
| @@ -13,13 +13,6 @@ import sys |
| import tempfile |
| -class InstallationError(Exception): |
| - """Signals a local installation error that prevents code signing.""" |
| - |
| - def __init__(self, fmt, *args): |
| - super(Exception, self).__init__(fmt % args) |
| - |
| - |
| def GetProvisioningProfilesDir(): |
| """Returns the location of the installed mobile provisioning profiles. |
| @@ -151,36 +144,18 @@ class Entitlements(object): |
| plistlib.writePlist(self._data, target_path) |
| -def FindProvisioningProfile(bundle_identifier, provisioning_profile_short_name): |
| +def FindProvisioningProfile(bundle_identifier, required): |
| """Finds mobile provisioning profile to use to sign bundle. |
| Args: |
| bundle_identifier: the identifier of the bundle to sign. |
| - provisioning_profile_short_path: optional short name of the mobile |
| - provisioning profile file to use to sign (will still be checked |
| - to see if it can sign bundle). |
| Returns: |
| The ProvisioningProfile object that can be used to sign the Bundle |
| object or None if no matching provisioning profile was found. |
| """ |
| - provisioning_profiles_dir = GetProvisioningProfilesDir() |
| - |
| - # First check if there is a mobile provisioning profile installed with |
| - # the requested short name. If this is the case, restrict the search to |
| - # that mobile provisioning profile, otherwise consider all the installed |
| - # mobile provisioning profiles. |
| - provisioning_profile_paths = [] |
| - if provisioning_profile_short_name: |
| - provisioning_profile_path = os.path.join( |
| - provisioning_profiles_dir, |
| - provisioning_profile_short_name + '.mobileprovision') |
| - if os.path.isfile(provisioning_profile_path): |
| - provisioning_profile_paths.append(provisioning_profile_path) |
| - |
| - if not provisioning_profile_paths: |
| - provisioning_profile_paths = glob.glob( |
| - os.path.join(provisioning_profiles_dir, '*.mobileprovision')) |
| + provisioning_profile_paths = glob.glob( |
| + os.path.join(GetProvisioningProfilesDir(), '*.mobileprovision')) |
| # Iterate over all installed mobile provisioning profiles and filter those |
| # that can be used to sign the bundle. |
| @@ -191,7 +166,12 @@ def FindProvisioningProfile(bundle_identifier, provisioning_profile_short_name): |
| valid_provisioning_profiles.append(provisioning_profile) |
| if not valid_provisioning_profiles: |
| - return None |
| + if not required: |
| + return None |
| + sys.stderr.write( |
| + 'No mobile provisioning profile found for "%s".\n' % |
| + bundle_identifier) |
| + sys.exit(1) |
|
Dirk Pranke
2016/08/08 22:15:36
nit: this is minor, but I'd write this as:
if req
sdefresne
2016/08/08 22:28:55
Done.
|
| # Select the most specific mobile provisioning profile, i.e. the one with |
| # the longest application identifier pattern. |
| @@ -200,18 +180,34 @@ def FindProvisioningProfile(bundle_identifier, provisioning_profile_short_name): |
| key=lambda p: len(p.application_identifier_pattern)) |
| -def InstallFramework(framework_path, bundle, args): |
| +def CodeSignBundle(bundle_path, identity, extra_args): |
| + process = subprocess.Popen(['xcrun', 'codesign', '--force', '--sign', |
| + identity, '--timestamp=none'] + list(extra_args) + [bundle_path], |
| + stderr=subprocess.PIPE) |
| + _, stderr = process.communicate() |
| + if process.returncode: |
| + sys.stderr.write(stderr) |
| + sys.exit(process.returncode) |
| + for line in stderr.splitlines(): |
| + if line.endswith(': replacing existing signature'): |
| + # Ignore warning about replacing existing signature as this should only |
| + # happen when re-signing system frameworks (and then it is expected). |
| + continue |
| + sys.stderr.write(line) |
| + sys.stderr.write('\n') |
| + |
| + |
| +def InstallSystemFramework(framework_path, bundle_path, args): |
| """Install framework from |framework_path| to |bundle| and code-re-sign it.""" |
| installed_framework_path = os.path.join( |
| - bundle.path, 'Frameworks', os.path.basename(framework_path)) |
| + bundle_path, 'Frameworks', os.path.basename(framework_path)) |
| if os.path.exists(installed_framework_path): |
| shutil.rmtree(installed_framework_path) |
| shutil.copytree(framework_path, installed_framework_path) |
| - |
| - framework_bundle = Bundle(installed_framework_path) |
| - CodeSignBundle(framework_bundle.binary_path, framework_bundle, args, True) |
| + CodeSignBundle(installed_framework_path, args.identity, |
| + ['--deep', '--preserve-metadata=identifier,entitlements']) |
| def GenerateEntitlements(path, provisioning_profile, bundle_identifier): |
| @@ -235,121 +231,130 @@ def GenerateEntitlements(path, provisioning_profile, bundle_identifier): |
| return entitlements |
| -def CodeSignBundle(binary, bundle, args, preserve=False): |
| - """Cryptographically signs bundle. |
| - |
| - Args: |
| - bundle: the Bundle object to sign. |
| - args: a dictionary with configuration settings for the code signature, |
| - need to define 'entitlements_path', 'provisioning_profile_short_name', |
| - 'deep_signature' and 'identify' keys. |
| - """ |
| - provisioning_profile = FindProvisioningProfile( |
| - bundle.identifier, args.provisioning_profile_short_name) |
| - if provisioning_profile: |
| - provisioning_profile.Install(bundle) |
| - else: |
| - sys.stderr.write( |
| - 'Warning: no mobile provisioning profile found for "%s", some features ' |
| - 'may not be functioning properly.\n' % bundle.identifier) |
| - |
| - if preserve: |
| - process = subprocess.Popen([ |
| - 'xcrun', 'codesign', '--force', |
| - '--sign', args.identity if args.identity else '-', |
| - '--deep', '--preserve-metadata=identifier,entitlements', |
| - '--timestamp=none', bundle.path], stderr=subprocess.PIPE) |
| - _, stderr = process.communicate() |
| - if process.returncode: |
| - sys.stderr.write(stderr) |
| - sys.exit(process.returncode) |
| - for line in stderr.splitlines(): |
| - # Ignore expected warning as we are replacing the signature on purpose. |
| - if not line.endswith(': replacing existing signature'): |
| - sys.stderr.write(line + '\n') |
| - else: |
| - signature_file = os.path.join( |
| - bundle.path, '_CodeSignature', 'CodeResources') |
| +class Action(object): |
| + |
| + """Class implementing one action supported by the script.""" |
| + |
| + @classmethod |
| + def Register(cls, subparsers): |
| + parser = subparsers.add_parser(cls._GetName(), help=cls._GetHelp()) |
| + parser.set_defaults(func=cls._Execute) |
| + cls._Register(parser) |
| + |
| + |
| +class CodeSignBundleAction(Action): |
| + |
| + """Class implementing the code-sign-bundle action.""" |
| + |
| + @staticmethod |
| + def _GetName(): |
| + return 'code-sign-bundle' |
| + |
| + @staticmethod |
| + def _GetHelp(): |
| + return 'perform code signature for a bundle' |
|
Dirk Pranke
2016/08/08 22:15:36
this would more idiomatically be:
name = 'code-
sdefresne
2016/08/08 22:28:55
Done.
|
| + |
| + @staticmethod |
| + def _Register(parser): |
| + parser.add_argument( |
| + '--entitlements', '-e', dest='entitlements_path', |
| + help='path to the entitlements file to use') |
| + parser.add_argument( |
| + 'path', help='path to the iOS bundle to codesign') |
| + parser.add_argument( |
| + '--identity', '-i', required=True, |
| + help='identity to use to codesign') |
| + parser.add_argument( |
| + '--binary', '-b', required=True, |
| + help='path to the iOS bundle binary') |
| + parser.add_argument( |
| + '--framework', '-F', action='append', default=[], dest="frameworks", |
| + help='install and resign system framework') |
| + |
| + @staticmethod |
| + def _Execute(args): |
| + if not args.identity: |
| + args.identity = '-' |
| + |
| + bundle = Bundle(args.path) |
| + |
| + # Find mobile provisioning profile and embeds it into the bundle (if a code |
| + # signing identify has been provided, fails if no valid mobile provisioning |
| + # is found). |
| + provisioning_profile_required = args.identity != '-' |
| + provisioning_profile = FindProvisioningProfile( |
| + bundle.identifier, provisioning_profile_required) |
| + if provisioning_profile: |
| + provisioning_profile.Install(bundle) |
| + |
| + # Delete existing code signature. |
| + signature_file = os.path.join(args.path, '_CodeSignature', 'CodeResources') |
| if os.path.isfile(signature_file): |
| os.unlink(signature_file) |
| + # Install system frameworks if requested. |
| + for framework_path in args.frameworks: |
| + InstallSystemFramework(framework_path, args.path, args) |
| + |
| + # Copy main binary into bundle. |
| if os.path.isfile(bundle.binary_path): |
| os.unlink(bundle.binary_path) |
| - shutil.copy(binary, bundle.binary_path) |
| + shutil.copy(args.binary, bundle.binary_path) |
| + |
| + # Embeds entitlements into the code signature (if code signing identify has |
| + # been provided). |
| + codesign_extra_args = [] |
| + if provisioning_profile: |
| + temporary_entitlements_file = tempfile.NamedTemporaryFile(suffix='.xcent') |
| + codesign_extra_args.extend( |
| + ['--entitlements', temporary_entitlements_file.name]) |
| + |
| + entitlements = GenerateEntitlements( |
| + args.entitlements_path, provisioning_profile, bundle.identifier) |
| + entitlements.WriteTo(temporary_entitlements_file.name) |
| + |
| + CodeSignBundle(bundle.path, args.identity, codesign_extra_args) |
| - codesign_command = [ |
| - 'xcrun', 'codesign', '--force', '--sign', |
| - args.identity if args.identity else '-', |
| - '--timestamp=none', bundle.path, |
| - ] |
| - with tempfile.NamedTemporaryFile(suffix='.xcent') as temporary_file_path: |
| - if provisioning_profile and args.identity: |
| - entitlements = GenerateEntitlements( |
| - args.entitlements_path, provisioning_profile, bundle.identifier) |
| - entitlements.WriteTo(temporary_file_path.name) |
| - codesign_command.extend(['--entitlements', temporary_file_path.name]) |
| - subprocess.check_call(codesign_command) |
| +class GenerateEntitlementsAction(Action): |
| + """Class implementing the generate-entitlements action.""" |
| -def MainCodeSignBundle(args): |
| - """Adapter to call CodeSignBundle from Main.""" |
| - bundle = Bundle(args.path) |
| - for framework in args.frameworks: |
| - InstallFramework(framework, bundle, args) |
| - CodeSignBundle(args.binary, bundle, args) |
| + @staticmethod |
| + def _GetName(): |
| + return 'generate-entitlements' |
| + @staticmethod |
| + def _GetHelp(): |
| + return 'generate entitlements file' |
| -def MainGenerateEntitlements(args): |
| - """Adapter to call GenerateEntitlements from Main.""" |
| - info_plist = LoadPlistFile(args.info_plist) |
| - bundle_identifier = info_plist['CFBundleIdentifier'] |
| - provisioning_profile = FindProvisioningProfile( |
| - bundle_identifier, args.provisioning_profile_short_name) |
| + @staticmethod |
| + def _Register(parser): |
| + parser.add_argument( |
| + '--entitlements', '-e', dest='entitlements_path', |
| + help='path to the entitlements file to use') |
| + parser.add_argument( |
| + 'path', help='path to the entitlements file to generate') |
| + parser.add_argument( |
| + '--info-plist', '-p', required=True, |
| + help='path to the bundle Info.plist') |
| - entitlements = GenerateEntitlements( |
| - args.entitlements_path, provisioning_profile, bundle_identifier) |
| - entitlements.WriteTo(args.path) |
| + @staticmethod |
| + def _Execute(args): |
| + info_plist = LoadPlistFile(args.info_plist) |
| + bundle_identifier = info_plist['CFBundleIdentifier'] |
| + provisioning_profile = FindProvisioningProfile(bundle_identifier, False) |
| + entitlements = GenerateEntitlements( |
| + args.entitlements_path, provisioning_profile, bundle_identifier) |
| + entitlements.WriteTo(args.path) |
| def Main(): |
| parser = argparse.ArgumentParser('codesign iOS bundles') |
| - parser.add_argument( |
| - '--provisioning-profile', '-p', dest='provisioning_profile_short_name', |
| - help='short name of the mobile provisioning profile to use (' |
| - 'if undefined, will autodetect the mobile provisioning ' |
| - 'to use)') |
| - parser.add_argument( |
| - '--entitlements', '-e', dest='entitlements_path', |
| - help='path to the entitlements file to use') |
| subparsers = parser.add_subparsers() |
| - code_sign_bundle_parser = subparsers.add_parser( |
| - 'code-sign-bundle', |
| - help='code sign a bundle') |
| - code_sign_bundle_parser.add_argument( |
| - 'path', help='path to the iOS bundle to codesign') |
| - code_sign_bundle_parser.add_argument( |
| - '--identity', '-i', required=True, |
| - help='identity to use to codesign') |
| - code_sign_bundle_parser.add_argument( |
| - '--binary', '-b', required=True, |
| - help='path to the iOS bundle binary') |
| - code_sign_bundle_parser.add_argument( |
| - '--framework', '-F', action='append', default=[], dest="frameworks", |
| - help='install and resign system framework') |
| - code_sign_bundle_parser.set_defaults(func=MainCodeSignBundle) |
| - |
| - generate_entitlements_parser = subparsers.add_parser( |
| - 'generate-entitlements', |
| - help='generate entitlements file') |
| - generate_entitlements_parser.add_argument( |
| - 'path', help='path to the entitlements file to generate') |
| - generate_entitlements_parser.add_argument( |
| - '--info-plist', '-p', required=True, |
| - help='path to the bundle Info.plist') |
| - generate_entitlements_parser.set_defaults( |
| - func=MainGenerateEntitlements) |
| + for action in [ CodeSignBundleAction, GenerateEntitlementsAction ]: |
| + action.Register(subparsers) |
| args = parser.parse_args() |
| args.func(args) |