def _ExtractBundleFile(target_dir, bundle_extension): """Extract single bundle file with given extension. Args: target_dir: string, the direcotry to be fetched bundle file. bundle_extension: string, the extension of the extracted bundle. Returns: string, the path of extracted bundle which is with given extension. Raises: BundleError: when bundle is not found or multiple bundles are found in the directory. """ extracted_bundles = glob.glob('%s/*.%s' % (target_dir, bundle_extension)) if not extracted_bundles: raise ios_errors.BundleError( 'No file with extension %s is found under %s.' % (bundle_extension, target_dir)) if len(extracted_bundles) > 1: raise ios_errors.BundleError( 'Multiple files with extension %s are found under %s. Can not ' 'determine which is the target bundle. The files are %s.' % (bundle_extension, target_dir, extracted_bundles)) return extracted_bundles[0]
def ExtractTestBundle(compressed_test_path, working_dir): """Creates a temp directory and extracts compressed file of the test bundle. Args: compressed_test_path: string, full path of compressed file. The file extension name must end with .ipa/.zip. working_dir: string, the working directory where the extracted bundle places. Returns: string, the path of extracted bundle, which is {working_dir}/*/Payload/*.xctest or {working_dir}/*/*.xctest Raises: BundleError: when bundle is not found in extracted IPA or multiple files are found in the extracted directory. """ if not (compressed_test_path.endswith('.ipa') or compressed_test_path.endswith('.zip')): ios_errors.BundleError( 'The extension of the compressed file should be .ipa/zip.') unzip_target_dir = tempfile.mkdtemp(dir=working_dir) _UnzipWithShell(compressed_test_path, unzip_target_dir) try: return _ExtractBundleFile(unzip_target_dir, 'xctest') except ios_errors.BundleError: return _ExtractBundleFile('%s/Payload' % unzip_target_dir, 'xctest')
def CodesignBundle(bundle_path, entitlements_plist_path=None, identity=None): """Codesigns the bundle. Args: bundle_path: string, full path of bundle folder. entitlements_plist_path: string, the path of the Entitlement to sign bundle. identity: string, the identity to sign bundle. Raises: ios_errors.BundleError: when failed to codesign the bundle. """ if identity is None: identity = GetCodesignIdentity(bundle_path) try: if entitlements_plist_path is None: subprocess.check_call([ 'codesign', '-f', '--preserve-metadata=identifier,entitlements', '--timestamp=none', '-s', identity, bundle_path ], stdout=subprocess.PIPE, stderr=subprocess.PIPE) else: subprocess.check_call([ 'codesign', '-f', '--entitlements', entitlements_plist_path, '--timestamp=none', '-s', identity, bundle_path ], stdout=subprocess.PIPE, stderr=subprocess.PIPE) except subprocess.CalledProcessError as e: raise ios_errors.BundleError('Failed to codesign the bundle %s: %s' % (bundle_path, e.output))
def GetDevelopmentTeam(bundle_path): """Gets the development team of the bundle. Args: bundle_path: string, full path of bundle folder. Returns: string, the development team of the provided bundle. Raises: ios_errors.BundleError: when failed to get the development team from the bundle. """ command = ('codesign', '-dvv', bundle_path) process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True) output = process.communicate()[0] for line in output.split('\n'): if line.startswith('TeamIdentifier='): return line[len('TeamIdentifier='):] raise ios_errors.BundleError('Failed to extract development team from %s' % output)
def GetCodesignIdentity(bundle_path): """Gets the codesign identity which signs the bundle with. Args: bundle_path: string, full path of bundle folder. Returns: string, the codesign identity which signs the bundle with. Raises: ios_errors.BundleError: when failed to get the signing identity from the bundle. """ command = ('codesign', '-dvv', bundle_path) process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True) output = process.communicate()[0] for line in output.split('\n'): if line.startswith('Authority='): return line[len('Authority='):] raise ios_errors.BundleError('Failed to extract signing identity from %s' % output)
def ExtractApp(compressed_app_path, working_dir): """Creates a temp directory and extracts compressed file of the app there. Args: compressed_app_path: string, full path of compressed file. The file extension name must end with .ipa. working_dir: string, the working directory where the extracted bundle places. Returns: string, the path of extracted bundle, which is {working_dir}/*/Payload/*.app Raises: BundleError: when bundle is not found in extracted IPA or multiple files are found in the extracted directory. """ if not compressed_app_path.endswith('.ipa'): ios_errors.BundleError( 'The extension of the compressed file should be .ipa.') unzip_target_dir = tempfile.mkdtemp(dir=working_dir) _UnzipWithShell(compressed_app_path, unzip_target_dir) return _ExtractBundleFile('%s/Payload' % unzip_target_dir, 'app')