Index: build/config/ios/codesign.py |
diff --git a/build/config/ios/codesign.py b/build/config/ios/codesign.py |
index b7fc8bef31f11cae4808dc58fccccca47ba32568..c1065c75e5c76826ef47442256a2fac4489760a6 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,6 +166,11 @@ def FindProvisioningProfile(bundle_identifier, provisioning_profile_short_name): |
valid_provisioning_profiles.append(provisioning_profile) |
if not valid_provisioning_profiles: |
+ if required: |
+ sys.stderr.write( |
+ 'No mobile provisioning profile found for "%s".\n' % |
+ bundle_identifier) |
+ sys.exit(1) |
return None |
# Select the most specific mobile provisioning profile, i.e. the one with |
@@ -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,120 @@ def GenerateEntitlements(path, provisioning_profile, bundle_identifier): |
return entitlements |
-def CodeSignBundle(binary, bundle, args, preserve=False): |
- """Cryptographically signs bundle. |
+class Action(object): |
- 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 implementing one action supported by the script.""" |
+ |
+ @classmethod |
+ def Register(cls, subparsers): |
+ parser = subparsers.add_parser(cls.name, help=cls.help) |
+ parser.set_defaults(func=cls._Execute) |
+ cls._Register(parser) |
+ |
+ |
+class CodeSignBundleAction(Action): |
+ |
+ """Class implementing the code-sign-bundle action.""" |
+ |
+ name = 'code-sign-bundle' |
+ help = 'perform code signature for a bundle' |
+ |
+ @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) |
- codesign_command = [ |
- 'xcrun', 'codesign', '--force', '--sign', |
- args.identity if args.identity else '-', |
- '--timestamp=none', bundle.path, |
- ] |
+ CodeSignBundle(bundle.path, args.identity, codesign_extra_args) |
- 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): |
-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) |
+ """Class implementing the generate-entitlements action.""" |
+ name = 'generate-entitlements' |
+ help = '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) |