def prepare(self): if self.config.use_submodules: relative_checkout_path = self.checkout_path.relative_to(self.config.root_path) result = runner.run('git submodule status "{}"'.format(relative_checkout_path)) if result.return_code == 0: match = re.match(r'^(?P<flag> |\-|\+|U)(?P<sha>[a-f0-9]+) (?P<path>.+)( \((?P<description>.+)\))?', result.stdout) flag = match.groupdict()['flag'] if flag == ' ': pass elif flag == '-': raise Exception('Uninitialized submodule {}. Please report this!'.format(self.checkout_path)) elif flag == '+': raise Exception('Submodule {} doesn\'t match expected revision'.format(self.checkout_path)) elif flag == 'U': raise Exception('Submodule {} has merge conflicts'.format(self.checkout_path)) else: if self.checkout_path.exists(): raise Exception('Want to create a submodule in {} but something already exists in there.'.format(self.checkout_path)) logging.debug('Adding submodule for {}'.format(self)) runner.check_run(['git', 'submodule', 'add', '--force', self.identifier.remote_url, self.checkout_path.relative_to(self.config.root_path)]) # runner.check_run(['git', 'submodule', 'add', '--force', self.identifier.remote_url, self.checkout_path.relative_to(self.config.root_path)]) # runner.check_run(['git', 'submodule', 'update', self.checkout_path.relative_to(self.config.root_path)]) logging.debug('Updating {}'.format(self)) self.repository.checkout(self.revision) else: # TODO: This isn't really 'fetch' if self.config.fetch: self.repository.checkout(self.revision) logging.debug('<sub>Copying project to <ref>Carthage/Checkouts</ref></sub>') if self.checkout_path.exists(): shutil.rmtree(self.checkout_path, ignore_errors=True) shutil.copytree(self.repository.path, self.checkout_path, symlinks=True, ignore=shutil.ignore_patterns('.git')) if not self.checkout_path.exists(): raise Exception('No checkout at path: {}'.format(self.checkout_path)) # We only need to bother making a symlink to <root>/Carthage/Build if dependency also has dependencies. if len(self.punic.dependencies_for_project_and_tag(self.identifier, self.revision)): # Make a Carthage/Build symlink inside checked out project. carthage_path = self.checkout_path / 'Carthage' if not carthage_path.exists(): carthage_path.mkdir() carthage_symlink_path = carthage_path / 'Build' if carthage_symlink_path.exists(): if carthage_symlink_path.is_dir(): shutil.rmtree(str(carthage_symlink_path)) else: carthage_symlink_path.unlink() logging.debug('<sub>Creating symlink: <ref>{}</ref> to <ref>{}</ref></sub>'.format(carthage_symlink_path.relative_to(self.config.root_path), self.config.build_path.relative_to(self.config.root_path))) assert self.config.build_path.exists() # TODO: Generate this programatically. os.symlink("../../../Build", str(carthage_symlink_path))
def prepare(self): # TODO: This isn't really 'can_fetch' if self.punic.config.can_fetch: self.repository.checkout(self.revision) logger.debug('<sub>Copying project to <ref>Carthage/Checkouts</ref></sub>') if self.checkout_path.exists(): shutil.rmtree(self.checkout_path) shutil.copytree(self.repository.path, self.checkout_path, ignore=shutil.ignore_patterns('.git')) if not self.checkout_path.exists(): raise Exception('No checkout at path: {}'.format(self.checkout_path)) # We only need to bother making a symlink to <root>/Carthage/Build if dependency also has dependencies. if len(self.punic.dependencies_for_project_and_tag(self.identifier, self.revision)): # Make a Carthage/Build symlink inside checked out project. carthage_path = self.checkout_path / 'Carthage' if not carthage_path.exists(): carthage_path.mkdir() carthage_symlink_path = carthage_path / 'Build' if carthage_symlink_path.exists(): carthage_symlink_path.unlink() logger.debug('<sub>Creating symlink: <ref>{}</ref> to <ref>{}</ref></sub>'.format( carthage_symlink_path.relative_to(self.punic.config.root_path), self.punic.config.build_path.relative_to(self.punic.config.root_path))) assert self.punic.config.build_path.exists() os.symlink(str(self.punic.config.build_path), str(carthage_symlink_path))
def _post_process(self, platform, products): ######################################################################################################## logger.debug("<sub>Post processing</sub>...") # By convention sdk[0] is always the device sdk (e.g. 'iphoneos' and not 'iphonesimulator') device_sdk = platform.device_sdk device_product = products[device_sdk] ######################################################################################################## output_product = copy(device_product) output_product.target_build_dir = self.config.build_path / platform.output_directory_name ######################################################################################################## logger.debug('<sub>Copying binary</sub>...') if output_product.product_path.exists(): shutil.rmtree(output_product.product_path) shutil.copytree(device_product.product_path, output_product.product_path) ######################################################################################################## if len(products) > 1: logger.debug('<sub>Lipo-ing</sub>...') executable_paths = [product.executable_path for product in products.values()] command = ['/usr/bin/xcrun', 'lipo', '-create'] + executable_paths + ['-output', output_product.executable_path] runner.check_run(command) mtime = executable_paths[0].stat().st_mtime os.utime(str(output_product.executable_path), (mtime, mtime)) ######################################################################################################## logger.debug('<sub>Copying swiftmodule files</sub>...') for product in products.values(): for path in product.module_paths: relative_path = path.relative_to(product.product_path) shutil.copyfile(path, output_product.product_path / relative_path) ######################################################################################################## logger.debug('<sub>Copying bcsymbolmap files</sub>...') for product in products.values(): for path in product.bcsymbolmap_paths: shutil.copy(path, output_product.target_build_dir) ######################################################################################################## logger.debug('<sub>Producing dSYM files</sub>...') command = ['/usr/bin/xcrun', 'dsymutil', str(output_product.executable_path), '-o', str(output_product.target_build_dir / (output_product.executable_name + '.dSYM'))] runner.check_run(command) ########################################################################################################
def _post_process(self, platform, products): ######################################################################################################## logger.debug("<sub>Post processing</sub>") # By convention sdk[0] is always the device sdk (e.g. 'iphoneos' and not 'iphonesimulator') device_sdk = platform.device_sdk device_product = products[device_sdk] ######################################################################################################## output_product = copy(device_product) output_product.target_build_dir = self.config.build_path / platform.output_directory_name ######################################################################################################## logger.debug('<sub>Copying binary</sub>') if output_product.product_path.exists(): shutil.rmtree(output_product.product_path) shutil.copytree(device_product.product_path, output_product.product_path) ######################################################################################################## if len(products) > 1: logger.debug('<sub>Lipo-ing</sub>') executable_paths = [product.executable_path for product in products.values()] command = ['/usr/bin/xcrun', 'lipo', '-create'] + executable_paths + ['-output', output_product.executable_path] runner.check_run(command) mtime = executable_paths[0].stat().st_mtime os.utime(str(output_product.executable_path), (mtime, mtime)) ######################################################################################################## logger.debug('<sub>Copying swiftmodule files</sub>') for product in products.values(): for path in product.module_paths: relative_path = path.relative_to(product.product_path) shutil.copyfile(path, output_product.product_path / relative_path) ######################################################################################################## logger.debug('<sub>Copying bcsymbolmap files</sub>') for product in products.values(): for path in product.bcsymbolmap_paths: shutil.copy(path, output_product.target_build_dir) ######################################################################################################## logger.debug('<sub>Producing dSYM files</sub>') command = ['/usr/bin/xcrun', 'dsymutil', str(output_product.executable_path), '-o', str(output_product.target_build_dir / (output_product.executable_name + '.dSYM'))] runner.check_run(command)
def clean(context, derived_data, caches, all): """Clean project & punic environment.""" logger.info("<cmd>Clean</cmd>") punic = context.obj if derived_data or all: logger.info('Erasing derived data directory'.format(**punic.__dict__)) if punic.config.derived_data_path.exists(): shutil.rmtree(punic.config.derived_data_path) if caches or all: if punic.config.repo_cache_directory.exists(): logger.info('Cleaning {}'.format(punic.config.repo_cache_directory)) shutil.rmtree(punic.config.repo_cache_directory ) logger.info('Cleaning run cache') runner.reset()
def clean(context, derived_data, caches, build, all): """Clean project & punic environment.""" logger.info("<cmd>Clean</cmd>") punic = context.obj if build or all: logger.info('Erasing Carthage/Build directory') if punic.config.build_path.exists(): shutil.rmtree(punic.config.build_path) if derived_data or all: logger.info('Erasing derived data directory') if punic.config.derived_data_path.exists(): shutil.rmtree(punic.config.derived_data_path) if caches or all: if punic.config.repo_cache_directory.exists(): logger.info('Erasing {}'.format(punic.config.repo_cache_directory)) shutil.rmtree(punic.config.repo_cache_directory) logger.info('Erasing run cache') runner.reset()
def clean(context, derived_data, caches, build, all): """Clean project & punic environment.""" logging.info("<cmd>Clean</cmd>") punic = context.obj with timeit('clean'): if build or all: logging.info('Erasing Carthage/Build directory') if punic.config.build_path.exists(): shutil.rmtree(punic.config.build_path) if derived_data or all: logging.info('Erasing derived data directory') if punic.config.derived_data_path.exists(): shutil.rmtree(punic.config.derived_data_path) if caches or all: if punic.config.repo_cache_directory.exists(): logging.info('Erasing {}'.format(punic.config.repo_cache_directory)) shutil.rmtree(punic.config.repo_cache_directory) logging.info('Erasing run cache') runner.reset()
def copy_frameworks_main(): sym_root = Path(os.environ['SYMROOT']) valid_architectures = set(os.environ['VALID_ARCHS'].split(' ')) input_file_count = int(os.environ['SCRIPT_INPUT_FILE_COUNT']) input_files = [ Path(os.environ.get('SCRIPT_INPUT_FILE_{}'.format(index))) for index in range(0, input_file_count) ] expanded_identity = os.environ['EXPANDED_CODE_SIGN_IDENTITY_NAME'] built_products_dir = Path(os.environ['BUILT_PRODUCTS_DIR']) frameworks_folder_path = os.environ['FRAMEWORKS_FOLDER_PATH'] frameworks_path = built_products_dir / frameworks_folder_path code_signing_allowed = os.environ['CODE_SIGNING_ALLOWED'] == 'YES' enable_bitcode = os.environ['ENABLE_BITCODE'] == 'YES' project_dir = Path(os.environ['PROJECT_DIR']) platform_display_name = os.environ['PLATFORM_DISPLAY_NAME'] punic_builds_dir = project_dir / 'Carthage' / 'Build' / platform_display_name action = os.environ['ACTION'] for input_path in input_files: logger.info('Processing: "{}"'.format(input_path.name)) # We don't modify the input frameworks but rather the ones in the built products directory output_path = frameworks_path / input_path.name framework_name = input_path.stem logger.info('\tCopying framework "{}" to "$SYMROOT/{}"'.format( framework_name, output_path.relative_to(sym_root))) if output_path.exists(): shutil.rmtree(output_path) def ignore(src, names): src = Path(src) if src.suffix == ".framework": return ['Headers', 'PrivateHeaders', 'Modules'] else: return [] shutil.copytree(input_path, output_path, ignore=ignore) framework_path = output_path binary_path = framework_path / framework_name if code_signing_allowed: # Find out what architectures the framework has output = runner.check_call( ['/usr/bin/xcrun', 'lipo', '-info', binary_path]) match = re.match( r'^Architectures in the fat file: (.+) are: (.+)'.format( binary_path), output) assert match.groups()[0] == str(binary_path) architectures = set(match.groups()[1].strip().split(' ')) logger.info('\tArchitectures: {}'.format(list(architectures))) # Produce a list of architectures that are not valid excluded_architectures = architectures.difference( valid_architectures) # Skip if all architectures are valid if not excluded_architectures: continue # For each invalid architecture strip it from framework for architecture in excluded_architectures: logger.info('\tStripping "{}" from "{}"'.format( architecture, framework_name)) output = runner.check_call([ '/usr/bin/xcrun', 'lipo', '-remove', architecture, '-output', binary_path, binary_path ]) # Resign framework logger.info('\tResigning "{}"/"{}" with "{}"'.format( framework_name, architecture, expanded_identity)) logger.info('\tCode signing: "$SYMROOT/{}"'.format( binary_path.relative_to(sym_root))) # noinspection PyUnusedLocal result = runner.check_call([ '/usr/bin/xcrun', 'codesign', '--force', '--sign', expanded_identity, '--preserve-metadata=identifier,entitlements', binary_path ]) else: logger.info('\tCode signing not allowed. Skipping.') if action == 'install': uuids = uuids_from_binary(binary_path) # Copy dSYM files from $PROJECT_DIRCarthage/Build to $BUILT_PRODUCTS_DIR dsym_path = input_path.parent / (binary_path.name + '.dSYM') if dsym_path.exists(): dsym_output_path = built_products_dir / dsym_path.name logger.info( '\tCopying "$PROJECT_DIR/{}" to "$BUILT_PRODUCTS_DIR"'. format(dsym_path.relative_to(project_dir))) if dsym_output_path.exists(): shutil.rmtree(dsym_output_path) shutil.copytree(dsym_path, dsym_output_path) # Copy bcsymbolmap files from $PROJECT_DIRCarthage/Build to $BUILT_PRODUCTS_DIR if enable_bitcode: for uuid in uuids: bcsymbolmap_path = punic_builds_dir / (uuid + '.bcsymbolmap') logger.info( '\tCopying "$PROJECT_DIR/{}" to "$BUILT_PRODUCTS_DIR"'. format(bcsymbolmap_path.relative_to(project_dir))) shutil.copy(bcsymbolmap_path, built_products_dir)
def copy_frameworks_main(): sym_root = Path(os.environ['SYMROOT']) valid_architectures = set(os.environ['VALID_ARCHS'].split(' ')) input_file_count = int(os.environ['SCRIPT_INPUT_FILE_COUNT']) input_files = [Path(os.environ.get('SCRIPT_INPUT_FILE_{}'.format(index))) for index in range(0, input_file_count)] expanded_identity = os.environ['EXPANDED_CODE_SIGN_IDENTITY_NAME'] built_products_dir = Path(os.environ['BUILT_PRODUCTS_DIR']) frameworks_folder_path = os.environ['FRAMEWORKS_FOLDER_PATH'] frameworks_path = built_products_dir / frameworks_folder_path code_signing_allowed = os.environ['CODE_SIGNING_ALLOWED'] == 'YES' enable_bitcode = os.environ['ENABLE_BITCODE'] == 'YES' project_dir = Path(os.environ['PROJECT_DIR']) platform_display_name = os.environ['PLATFORM_DISPLAY_NAME'] punic_builds_dir = project_dir / 'Carthage' / 'Build' / platform_display_name action = os.environ['ACTION'] for input_path in input_files: logger.info('Processing: "{}"'.format(input_path.name)) # We don't modify the input frameworks but rather the ones in the built products directory output_path = frameworks_path / input_path.name framework_name = input_path.stem logger.info('\tCopying framework "{}" to "$SYMROOT/{}"'.format(framework_name, output_path.relative_to(sym_root))) if output_path.exists(): shutil.rmtree(output_path) shutil.copytree(input_path, output_path) framework_path = output_path binary_path = framework_path / framework_name if code_signing_allowed: # Find out what architectures the framework has output = runner.check_call(['/usr/bin/xcrun', 'lipo', '-info', binary_path]) match = re.match(r'^Architectures in the fat file: (.+) are: (.+)'.format(binary_path), output) assert match.groups()[0] == str(binary_path) architectures = set(match.groups()[1].strip().split(' ')) logger.info('\tArchitectures: {}'.format(list(architectures))) # Produce a list of architectures that are not valid excluded_architectures = architectures.difference(valid_architectures) # Skip if all architectures are valid if not excluded_architectures: continue # For each invalid architecture strip it from framework for architecture in excluded_architectures: logger.info('\tStripping "{}" from "{}"'.format(architecture, framework_name)) output = runner.check_call(['/usr/bin/xcrun', 'lipo', '-remove', architecture, '-output', binary_path, binary_path]) # Resign framework logger.info('\tResigning "{}"/"{}" with "{}"'.format(framework_name, architecture, expanded_identity)) logger.info('\tCode signing: "$SYMROOT/{}"'.format(binary_path.relative_to(sym_root))) # noinspection PyUnusedLocal result = runner.check_call(['/usr/bin/xcrun', 'codesign', '--force', '--sign', expanded_identity, '--preserve-metadata=identifier,entitlements', binary_path]) else: logger.info('\tCode signing not allowed. Skipping.') if action == 'install': uuids = uuids_from_binary(binary_path) # Copy dSYM files from $PROJECT_DIRCarthage/Build to $BUILT_PRODUCTS_DIR dsym_path = input_path.parent / (binary_path.name + '.dSYM') if dsym_path.exists(): dsym_output_path = built_products_dir / dsym_path.name logger.info('\tCopying "$PROJECT_DIR/{}" to "$BUILT_PRODUCTS_DIR"'.format(dsym_path.relative_to(project_dir))) if dsym_output_path.exists(): shutil.rmtree(dsym_output_path) shutil.copytree(dsym_path, dsym_output_path) # Copy bcsymbolmap files from $PROJECT_DIRCarthage/Build to $BUILT_PRODUCTS_DIR if enable_bitcode: for uuid in uuids: bcsymbolmap_path = punic_builds_dir / (uuid + '.bcsymbolmap') logger.info('\tCopying "$PROJECT_DIR/{}" to "$BUILT_PRODUCTS_DIR"'.format(bcsymbolmap_path.relative_to(project_dir))) shutil.copy(bcsymbolmap_path, built_products_dir)
def _post_process(self, platform, products): # type: (punic.platform.Platform, List) ######################################################################################################## logging.debug("<sub>Post processing</sub>...") # TODO: QUESTION: Is it possible that this could mix targets with different SDKs? products_by_name_then_sdk = defaultdict(dict) for product in products: products_by_name_then_sdk[product.full_product_name][ product.sdk] = product for products_by_sdk in products_by_name_then_sdk.values(): products = products_by_sdk.values() # TODO: By convention sdk[0] is always the device sdk (e.g. 'iphoneos' and not 'iphonesimulator') primary_sdk = platform.sdks[0] device_product = products_by_sdk[primary_sdk] ######################################################################################################## output_product = copy(device_product) output_product.target_build_dir = self.config.build_path / platform.output_directory_name ######################################################################################################## logging.debug('<sub>Copying binary</sub>...') if output_product.product_path.exists(): shutil.rmtree(output_product.product_path) if not device_product.product_path.exists(): raise Exception("No product at: {}".format( device_product.product_path)) shutil.copytree(device_product.product_path, output_product.product_path, symlinks=True) ######################################################################################################## if len(products) > 1: logging.debug('<sub>Lipo-ing</sub>...') executable_paths = [ product.executable_path for product in products ] command = ['/usr/bin/xcrun', 'lipo', '-create' ] + executable_paths + [ '-output', output_product.executable_path ] runner.check_run(command) mtime = executable_paths[0].stat().st_mtime os.utime(str(output_product.executable_path), (mtime, mtime)) ######################################################################################################## logging.debug('<sub>Copying swiftmodule files</sub>...') for product in products: for path in product.module_paths: relative_path = path.relative_to(product.product_path) shutil.copyfile( path, output_product.product_path / relative_path) ######################################################################################################## logging.debug('<sub>Copying bcsymbolmap files</sub>...') for product in products: for path in product.bcsymbolmap_paths: shutil.copy(path, output_product.target_build_dir) ######################################################################################################## logging.debug('<sub>Producing dSYM files</sub>...') command = [ '/usr/bin/xcrun', 'dsymutil', str(output_product.executable_path), '-o', str(output_product.target_build_dir / (output_product.executable_name + '.dSYM')) ] runner.check_run(command)
def prepare(self): if self.config.use_submodules: relative_checkout_path = self.checkout_path.relative_to( self.config.root_path) result = runner.run( 'git submodule status "{}"'.format(relative_checkout_path)) if result.return_code == 0: match = re.match( r'^(?P<flag> |\-|\+|U)(?P<sha>[a-f0-9]+) (?P<path>.+)( \((?P<description>.+)\))?', result.stdout) flag = match.groupdict()['flag'] if flag == ' ': pass elif flag == '-': raise Exception( 'Uninitialized submodule {}. Please report this!'. format(self.checkout_path)) elif flag == '+': raise Exception( 'Submodule {} doesn\'t match expected revision'.format( self.checkout_path)) elif flag == 'U': raise Exception('Submodule {} has merge conflicts'.format( self.checkout_path)) else: if self.checkout_path.exists(): raise Exception( 'Want to create a submodule in {} but something already exists in there.' .format(self.checkout_path)) logging.debug('Adding submodule for {}'.format(self)) runner.check_run([ 'git', 'submodule', 'add', '--force', self.identifier.remote_url, self.checkout_path.relative_to(self.config.root_path) ]) # runner.check_run(['git', 'submodule', 'add', '--force', self.identifier.remote_url, self.checkout_path.relative_to(self.config.root_path)]) # runner.check_run(['git', 'submodule', 'update', self.checkout_path.relative_to(self.config.root_path)]) logging.debug('Updating {}'.format(self)) self.repository.checkout(self.revision) else: # TODO: This isn't really 'fetch' if self.config.fetch: self.repository.checkout(self.revision) logging.debug( '<sub>Copying project to <ref>Carthage/Checkouts</ref></sub>' ) if self.checkout_path.exists(): shutil.rmtree(self.checkout_path, ignore_errors=True) shutil.copytree(self.repository.path, self.checkout_path, symlinks=True, ignore=shutil.ignore_patterns('.git')) if not self.checkout_path.exists(): raise Exception('No checkout at path: {}'.format( self.checkout_path)) # We only need to bother making a symlink to <root>/Carthage/Build if dependency also has dependencies. if len( self.punic.dependencies_for_project_and_tag( self.identifier, self.revision)): # Make a Carthage/Build symlink inside checked out project. carthage_path = self.checkout_path / 'Carthage' if not carthage_path.exists(): carthage_path.mkdir() carthage_symlink_path = carthage_path / 'Build' if carthage_symlink_path.exists(): carthage_symlink_path.unlink() logging.debug( '<sub>Creating symlink: <ref>{}</ref> to <ref>{}</ref></sub>'. format( carthage_symlink_path.relative_to(self.config.root_path), self.config.build_path.relative_to(self.config.root_path))) assert self.config.build_path.exists() # TODO: Generate this programatically. os.symlink("../../../Build", str(carthage_symlink_path))
def _post_process(self, platform, products): # type: (punic.platform.Platform, List) ######################################################################################################## logging.debug("<sub>Post processing</sub>...") # TODO: QUESTION: Is it possible that this could mix targets with different SDKs? products_by_name_then_sdk = defaultdict(dict) for product in products: products_by_name_then_sdk[product.full_product_name][product.sdk] = product for products_by_sdk in products_by_name_then_sdk.values(): products = products_by_sdk.values() # TODO: By convention sdk[0] is always the device sdk (e.g. 'iphoneos' and not 'iphonesimulator') primary_sdk = platform.sdks[0] device_product = products_by_sdk[primary_sdk] ######################################################################################################## output_product = copy(device_product) output_product.target_build_dir = self.config.build_path / platform.output_directory_name ######################################################################################################## logging.debug('<sub>Copying binary</sub>...') if output_product.product_path.exists(): shutil.rmtree(output_product.product_path) if not device_product.product_path.exists(): raise Exception("No product at: {}".format(device_product.product_path)) shutil.copytree(device_product.product_path, output_product.product_path, symlinks=True) ######################################################################################################## if len(products) > 1: logging.debug('<sub>Lipo-ing</sub>...') executable_paths = [product.executable_path for product in products] command = ['/usr/bin/xcrun', 'lipo', '-create'] + executable_paths + ['-output', output_product.executable_path] runner.check_run(command) mtime = executable_paths[0].stat().st_mtime os.utime(str(output_product.executable_path), (mtime, mtime)) ######################################################################################################## logging.debug('<sub>Copying swiftmodule files</sub>...') for product in products: for path in product.module_paths: relative_path = path.relative_to(product.product_path) shutil.copyfile(path, output_product.product_path / relative_path) ######################################################################################################## logging.debug('<sub>Copying bcsymbolmap files</sub>...') for product in products: for path in product.bcsymbolmap_paths: shutil.copy(path, output_product.target_build_dir) ######################################################################################################## logging.debug('<sub>Producing dSYM files</sub>...') command = ['/usr/bin/xcrun', 'dsymutil', str(output_product.executable_path), '-o', str(output_product.target_build_dir / (output_product.executable_name + '.dSYM'))] runner.check_run(command) ########################################################################################################