| #!/usr/bin/env python |
| # |
| # Copyright (C) 2019 The Android Open Source Project |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| # use this file except in compliance with the License. You may obtain a copy of |
| # the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| # License for the specific language governing permissions and limitations under |
| # the License. |
| |
| """ |
| This script merges two partial target files packages (one of which contains |
| system files, and the other contains non-system files) together, producing a |
| complete target files package that can be used to generate an OTA package. |
| |
| Usage: merge_target_files.py [args] |
| |
| --system-target-files system-target-files-zip-archive |
| The input target files package containing system bits. This is a zip |
| archive. |
| |
| --system-item-list system-item-list-file |
| The optional path to a newline-separated config file that replaces the |
| contents of default_system_item_list if provided. |
| |
| --system-misc-info-keys system-misc-info-keys-file |
| The optional path to a newline-separated config file that replaces the |
| contents of default_system_misc_info_keys if provided. |
| |
| --other-target-files other-target-files-zip-archive |
| The input target files package containing other bits. This is a zip |
| archive. |
| |
| --other-item-list other-item-list-file |
| The optional path to a newline-separated config file that replaces the |
| contents of default_other_item_list if provided. |
| |
| --output-target-files output-target-files-package |
| The output merged target files package. Also a zip archive. |
| |
| --rebuild_recovery |
| Rebuild the recovery patch used by non-A/B devices and write it to the |
| system image. |
| |
| --keep-tmp |
| Keep tempoary files for debugging purposes. |
| """ |
| |
| from __future__ import print_function |
| |
| import fnmatch |
| import logging |
| import os |
| import sys |
| import zipfile |
| |
| import common |
| import add_img_to_target_files |
| |
| logger = logging.getLogger(__name__) |
| OPTIONS = common.OPTIONS |
| OPTIONS.verbose = True |
| OPTIONS.system_target_files = None |
| OPTIONS.system_item_list = None |
| OPTIONS.system_misc_info_keys = None |
| OPTIONS.other_target_files = None |
| OPTIONS.other_item_list = None |
| OPTIONS.output_target_files = None |
| OPTIONS.rebuild_recovery = False |
| OPTIONS.keep_tmp = False |
| |
| # default_system_item_list is a list of items to extract from the partial |
| # system target files package as is, meaning these items will land in the |
| # output target files package exactly as they appear in the input partial |
| # system target files package. |
| |
| default_system_item_list = [ |
| 'META/apkcerts.txt', |
| 'META/filesystem_config.txt', |
| 'META/root_filesystem_config.txt', |
| 'META/system_manifest.xml', |
| 'META/system_matrix.xml', |
| 'META/update_engine_config.txt', |
| 'PRODUCT/*', |
| 'ROOT/*', |
| 'SYSTEM/*', |
| ] |
| |
| # system_extract_special_item_list is a list of items to extract from the |
| # partial system target files package that need some special processing, such |
| # as some sort of combination with items from the partial other target files |
| # package. |
| |
| system_extract_special_item_list = [ |
| 'META/*', |
| ] |
| |
| # default_system_misc_info_keys is a list of keys to obtain from the system instance of |
| # META/misc_info.txt. The remaining keys from the other instance. |
| |
| default_system_misc_info_keys = [ |
| 'avb_system_hashtree_enable', |
| 'avb_system_add_hashtree_footer_args', |
| 'avb_system_key_path', |
| 'avb_system_algorithm', |
| 'avb_system_rollback_index_location', |
| 'avb_product_hashtree_enable', |
| 'avb_product_add_hashtree_footer_args', |
| 'avb_product_services_hashtree_enable', |
| 'avb_product_services_add_hashtree_footer_args', |
| 'system_root_image', |
| 'root_dir', |
| 'ab_update', |
| 'default_system_dev_certificate', |
| 'system_size', |
| ] |
| |
| # default_other_item_list is a list of items to extract from the partial |
| # other target files package as is, meaning these items will land in the output |
| # target files package exactly as they appear in the input partial other target |
| # files package. |
| |
| default_other_item_list = [ |
| 'META/boot_filesystem_config.txt', |
| 'META/otakeys.txt', |
| 'META/releasetools.py', |
| 'META/vendor_filesystem_config.txt', |
| 'META/vendor_manifest.xml', |
| 'META/vendor_matrix.xml', |
| 'BOOT/*', |
| 'DATA/*', |
| 'ODM/*', |
| 'OTA/android-info.txt', |
| 'PREBUILT_IMAGES/*', |
| 'RADIO/*', |
| 'VENDOR/*', |
| ] |
| |
| # other_extract_special_item_list is a list of items to extract from the |
| # partial other target files package that need some special processing, such as |
| # some sort of combination with items from the partial system target files |
| # package. |
| |
| other_extract_special_item_list = [ |
| 'META/*', |
| ] |
| |
| |
| def extract_items(target_files, target_files_temp_dir, extract_item_list): |
| """Extract items from target files to temporary directory. |
| |
| This function extracts from the specified target files zip archive into the |
| specified temporary directory, the items specified in the extract item list. |
| |
| Args: |
| target_files: The target files zip archive from which to extract items. |
| |
| target_files_temp_dir: The temporary directory where the extracted items |
| will land. |
| |
| extract_item_list: A list of items to extract. |
| """ |
| |
| logger.info('extracting from %s', target_files) |
| |
| # Filter the extract_item_list to remove any items that do not exist in the |
| # zip file. Otherwise, the extraction step will fail. |
| |
| with zipfile.ZipFile( |
| target_files, |
| 'r', |
| allowZip64=True) as target_files_zipfile: |
| target_files_namelist = target_files_zipfile.namelist() |
| |
| filtered_extract_item_list = [] |
| for pattern in extract_item_list: |
| matching_namelist = fnmatch.filter(target_files_namelist, pattern) |
| if not matching_namelist: |
| logger.warning('no match for %s', pattern) |
| else: |
| filtered_extract_item_list.append(pattern) |
| |
| # Extract from target_files into target_files_temp_dir the |
| # filtered_extract_item_list. |
| |
| common.UnzipToDir( |
| target_files, |
| target_files_temp_dir, |
| filtered_extract_item_list) |
| |
| |
| def read_config_list(config_file_path): |
| """Reads a config file into a list of strings. |
| |
| Expects the file to be newline-separated. |
| |
| Args: |
| config_file_path: The path to the config file to open and read. |
| """ |
| with open(config_file_path) as config_file: |
| return config_file.read().splitlines() |
| |
| |
| def validate_config_lists( |
| system_item_list, |
| system_misc_info_keys, |
| other_item_list): |
| """Performs validations on the merge config lists. |
| |
| Args: |
| system_item_list: The list of items to extract from the partial |
| system target files package as is. |
| |
| system_misc_info_keys: A list of keys to obtain from the system instance |
| of META/misc_info.txt. The remaining keys from the other instance. |
| |
| other_item_list: The list of items to extract from the partial |
| other target files package as is. |
| |
| Returns: |
| False if a validation fails, otherwise true. |
| """ |
| default_combined_item_set = set(default_system_item_list) |
| default_combined_item_set.update(default_other_item_list) |
| |
| combined_item_set = set(system_item_list) |
| combined_item_set.update(other_item_list) |
| |
| # Check that the merge config lists are not missing any item specified |
| # by the default config lists. |
| difference = default_combined_item_set.difference(combined_item_set) |
| if difference: |
| logger.error('Missing merge config items: %s' % list(difference)) |
| logger.error('Please ensure missing items are in either the ' |
| 'system-item-list or other-item-list files provided to ' |
| 'this script.') |
| return False |
| |
| if ('dynamic_partition_list' in system_misc_info_keys) or ( |
| 'super_partition_groups' in system_misc_info_keys): |
| logger.error('Dynamic partition misc info keys should come from ' |
| 'the other instance of META/misc_info.txt.') |
| return False |
| |
| return True |
| |
| |
| def process_ab_partitions_txt( |
| system_target_files_temp_dir, |
| other_target_files_temp_dir, |
| output_target_files_temp_dir): |
| """Perform special processing for META/ab_partitions.txt |
| |
| This function merges the contents of the META/ab_partitions.txt files from |
| the system directory and the other directory, placing the merged result in |
| the output directory. The precondition in that the files are already |
| extracted. The post condition is that the output META/ab_partitions.txt |
| contains the merged content. The format for each ab_partitions.txt a one |
| partition name per line. The output file contains the union of the parition |
| names. |
| |
| Args: |
| system_target_files_temp_dir: The name of a directory containing the |
| special items extracted from the system target files package. |
| |
| other_target_files_temp_dir: The name of a directory containing the |
| special items extracted from the other target files package. |
| |
| output_target_files_temp_dir: The name of a directory that will be used |
| to create the output target files package after all the special cases |
| are processed. |
| """ |
| |
| system_ab_partitions_txt = os.path.join( |
| system_target_files_temp_dir, 'META', 'ab_partitions.txt') |
| |
| other_ab_partitions_txt = os.path.join( |
| other_target_files_temp_dir, 'META', 'ab_partitions.txt') |
| |
| with open(system_ab_partitions_txt) as f: |
| system_ab_partitions = f.read().splitlines() |
| |
| with open(other_ab_partitions_txt) as f: |
| other_ab_partitions = f.read().splitlines() |
| |
| output_ab_partitions = set(system_ab_partitions + other_ab_partitions) |
| |
| output_ab_partitions_txt = os.path.join( |
| output_target_files_temp_dir, 'META', 'ab_partitions.txt') |
| |
| with open(output_ab_partitions_txt, 'w') as output: |
| for partition in sorted(output_ab_partitions): |
| output.write('%s\n' % partition) |
| |
| |
| def append_recovery_to_filesystem_config(output_target_files_temp_dir): |
| """Perform special processing for META/filesystem_config.txt |
| |
| This function appends recovery information to META/filesystem_config.txt |
| so that recovery patch regeneration will succeed. |
| |
| Args: |
| output_target_files_temp_dir: The name of a directory that will be used |
| to create the output target files package after all the special cases |
| are processed. We find filesystem_config.txt here. |
| """ |
| |
| filesystem_config_txt = os.path.join( |
| output_target_files_temp_dir, |
| 'META', |
| 'filesystem_config.txt') |
| |
| with open(filesystem_config_txt, 'a') as f: |
| # TODO(bpeckham) this data is hard coded. It should be generated |
| # programmatically. |
| f.write( |
| 'system/bin/install-recovery.sh 0 0 750 ' |
| 'selabel=u:object_r:install_recovery_exec:s0 capabilities=0x0\n') |
| f.write( |
| 'system/recovery-from-boot.p 0 0 644 ' |
| 'selabel=u:object_r:system_file:s0 capabilities=0x0\n') |
| f.write( |
| 'system/etc/recovery.img 0 0 440 ' |
| 'selabel=u:object_r:install_recovery_exec:s0 capabilities=0x0\n') |
| |
| |
| def process_misc_info_txt( |
| system_target_files_temp_dir, |
| other_target_files_temp_dir, |
| output_target_files_temp_dir, |
| system_misc_info_keys): |
| """Perform special processing for META/misc_info.txt |
| |
| This function merges the contents of the META/misc_info.txt files from the |
| system directory and the other directory, placing the merged result in the |
| output directory. The precondition in that the files are already extracted. |
| The post condition is that the output META/misc_info.txt contains the merged |
| content. |
| |
| Args: |
| system_target_files_temp_dir: The name of a directory containing the |
| special items extracted from the system target files package. |
| |
| other_target_files_temp_dir: The name of a directory containing the |
| special items extracted from the other target files package. |
| |
| output_target_files_temp_dir: The name of a directory that will be used |
| to create the output target files package after all the special cases |
| are processed. |
| |
| system_misc_info_keys: A list of keys to obtain from the system instance |
| of META/misc_info.txt. The remaining keys from the other instance. |
| """ |
| |
| def read_helper(d): |
| misc_info_txt = os.path.join(d, 'META', 'misc_info.txt') |
| with open(misc_info_txt) as f: |
| return list(f.read().splitlines()) |
| |
| system_info_dict = common.LoadDictionaryFromLines( |
| read_helper(system_target_files_temp_dir)) |
| |
| # We take most of the misc info from the other target files. |
| |
| merged_info_dict = common.LoadDictionaryFromLines( |
| read_helper(other_target_files_temp_dir)) |
| |
| # Replace certain values in merged_info_dict with values from |
| # system_info_dict. |
| |
| for key in system_misc_info_keys: |
| merged_info_dict[key] = system_info_dict[key] |
| |
| # Merge misc info keys used for Dynamic Partitions. |
| if (merged_info_dict.get('use_dynamic_partitions') == 'true') and ( |
| system_info_dict.get('use_dynamic_partitions') == 'true'): |
| merged_info_dict['dynamic_partition_list'] = '%s %s' % ( |
| system_info_dict.get('dynamic_partition_list', ''), |
| merged_info_dict.get('dynamic_partition_list', '')) |
| # Partition groups and group sizes are defined by the other (non-system) |
| # misc info file because these values may vary for each board that uses |
| # a shared system image. |
| for partition_group in merged_info_dict['super_partition_groups'].split(' '): |
| if ('super_%s_group_size' % partition_group) not in merged_info_dict: |
| raise common.ExternalError( |
| 'Other META/misc_info.txt does not contain required key ' |
| 'super_%s_group_size.' % partition_group) |
| key = 'super_%s_partition_list' % partition_group |
| merged_info_dict[key] = '%s %s' % ( |
| system_info_dict.get(key, ''), |
| merged_info_dict.get(key, '')) |
| # Ensure that add_img_to_target_files rebuilds super split images for |
| # devices that retrofit dynamic partitions. This flag may have been set to |
| # false in the partial builds to prevent duplicate building of super.img. |
| merged_dict['build_super_partition'] = 'true' |
| |
| output_misc_info_txt = os.path.join( |
| output_target_files_temp_dir, |
| 'META', 'misc_info.txt') |
| |
| sorted_keys = sorted(merged_info_dict.keys()) |
| |
| with open(output_misc_info_txt, 'w') as output: |
| for key in sorted_keys: |
| output.write('{}={}\n'.format(key, merged_info_dict[key])) |
| |
| |
| def process_file_contexts_bin(temp_dir, output_target_files_temp_dir): |
| """Perform special processing for META/file_contexts.bin. |
| |
| This function combines plat_file_contexts and vendor_file_contexts, which are |
| expected to already be extracted in temp_dir, to produce a merged |
| file_contexts.bin that will land in temp_dir at META/file_contexts.bin. |
| |
| Args: |
| temp_dir: The name of a scratch directory that this function can use for |
| intermediate files generated during processing. |
| |
| output_target_files_temp_dir: The name of the working directory that must |
| already contain plat_file_contexts and vendor_file_contexts (in the |
| appropriate sub directories), and to which META/file_contexts.bin will be |
| written. |
| """ |
| |
| # To create a merged file_contexts.bin file, we use the system and vendor |
| # file contexts files as input, the m4 tool to combine them, the sorting tool |
| # to sort, and finally the sefcontext_compile tool to generate the final |
| # output. We currently omit a checkfc step since the files had been checked |
| # as part of the build. |
| |
| # The m4 step concatenates the two input files contexts files. Since m4 |
| # writes to stdout, we receive that into an array of bytes, and then write it |
| # to a file. |
| |
| # Collect the file contexts that we're going to combine from SYSTEM, VENDOR, |
| # PRODUCT, and ODM. We require SYSTEM and VENDOR, but others are optional. |
| |
| file_contexts_list = [] |
| |
| for partition in ['SYSTEM', 'VENDOR', 'PRODUCT', 'ODM']: |
| prefix = 'plat' if partition == 'SYSTEM' else partition.lower() |
| |
| file_contexts = os.path.join( |
| output_target_files_temp_dir, |
| partition, 'etc', 'selinux', prefix + '_file_contexts') |
| |
| mandatory = partition in ['SYSTEM', 'VENDOR'] |
| |
| if mandatory or os.path.isfile(file_contexts): |
| file_contexts_list.append(file_contexts) |
| else: |
| logger.warning('file not found: %s', file_contexts) |
| |
| command = ['m4', '--fatal-warnings', '-s'] + file_contexts_list |
| |
| merged_content = common.RunAndCheckOutput(command, verbose=False) |
| |
| merged_file_contexts_txt = os.path.join(temp_dir, 'merged_file_contexts.txt') |
| |
| with open(merged_file_contexts_txt, 'wb') as f: |
| f.write(merged_content) |
| |
| # The sort step sorts the concatenated file. |
| |
| sorted_file_contexts_txt = os.path.join(temp_dir, 'sorted_file_contexts.txt') |
| command = ['fc_sort', merged_file_contexts_txt, sorted_file_contexts_txt] |
| common.RunAndWait(command, verbose=True) |
| |
| # Finally, the compile step creates the final META/file_contexts.bin. |
| |
| file_contexts_bin = os.path.join( |
| output_target_files_temp_dir, |
| 'META', 'file_contexts.bin') |
| |
| command = [ |
| 'sefcontext_compile', |
| '-o', file_contexts_bin, |
| sorted_file_contexts_txt, |
| ] |
| |
| common.RunAndWait(command, verbose=True) |
| |
| |
| def process_special_cases( |
| temp_dir, |
| system_target_files_temp_dir, |
| other_target_files_temp_dir, |
| output_target_files_temp_dir, |
| system_misc_info_keys, |
| rebuild_recovery |
| ): |
| """Perform special-case processing for certain target files items. |
| |
| Certain files in the output target files package require special-case |
| processing. This function performs all that special-case processing. |
| |
| Args: |
| temp_dir: The name of a scratch directory that this function can use for |
| intermediate files generated during processing. |
| |
| system_target_files_temp_dir: The name of a directory containing the |
| special items extracted from the system target files package. |
| |
| other_target_files_temp_dir: The name of a directory containing the |
| special items extracted from the other target files package. |
| |
| output_target_files_temp_dir: The name of a directory that will be used |
| to create the output target files package after all the special cases |
| are processed. |
| |
| system_misc_info_keys: A list of keys to obtain from the system instance |
| of META/misc_info.txt. The remaining keys from the other instance. |
| |
| rebuild_recovery: If true, rebuild the recovery patch used by non-A/B |
| devices and write it to the system image. |
| """ |
| |
| if 'ab_update' in system_misc_info_keys: |
| process_ab_partitions_txt( |
| system_target_files_temp_dir=system_target_files_temp_dir, |
| other_target_files_temp_dir=other_target_files_temp_dir, |
| output_target_files_temp_dir=output_target_files_temp_dir) |
| |
| if rebuild_recovery: |
| append_recovery_to_filesystem_config( |
| output_target_files_temp_dir=output_target_files_temp_dir) |
| |
| process_misc_info_txt( |
| system_target_files_temp_dir=system_target_files_temp_dir, |
| other_target_files_temp_dir=other_target_files_temp_dir, |
| output_target_files_temp_dir=output_target_files_temp_dir, |
| system_misc_info_keys=system_misc_info_keys) |
| |
| process_file_contexts_bin( |
| temp_dir=temp_dir, |
| output_target_files_temp_dir=output_target_files_temp_dir) |
| |
| |
| def merge_target_files( |
| temp_dir, |
| system_target_files, |
| system_item_list, |
| system_misc_info_keys, |
| other_target_files, |
| other_item_list, |
| output_target_files, |
| rebuild_recovery): |
| """Merge two target files packages together. |
| |
| This function takes system and other target files packages as input, performs |
| various file extractions, special case processing, and finally creates a |
| merged zip archive as output. |
| |
| Args: |
| temp_dir: The name of a directory we use when we extract items from the |
| input target files packages, and also a scratch directory that we use for |
| temporary files. |
| |
| system_target_files: The name of the zip archive containing the system |
| partial target files package. |
| |
| system_item_list: The list of items to extract from the partial system |
| target files package as is, meaning these items will land in the output |
| target files package exactly as they appear in the input partial system |
| target files package. |
| |
| system_misc_info_keys: The list of keys to obtain from the system instance |
| of META/misc_info.txt. The remaining keys from the other instance. |
| |
| other_target_files: The name of the zip archive containing the other |
| partial target files package. |
| |
| other_item_list: The list of items to extract from the partial other |
| target files package as is, meaning these items will land in the output |
| target files package exactly as they appear in the input partial other |
| target files package. |
| |
| output_target_files: The name of the output zip archive target files |
| package created by merging system and other. |
| |
| rebuild_recovery: If true, rebuild the recovery patch used by non-A/B |
| devices and write it to the system image. |
| """ |
| |
| logger.info( |
| 'starting: merge system %s and other %s into output %s', |
| system_target_files, |
| other_target_files, |
| output_target_files) |
| |
| # Create directory names that we'll use when we extract files from system, |
| # and other, and for zipping the final output. |
| |
| system_target_files_temp_dir = os.path.join(temp_dir, 'system') |
| other_target_files_temp_dir = os.path.join(temp_dir, 'other') |
| output_target_files_temp_dir = os.path.join(temp_dir, 'output') |
| |
| # Extract "as is" items from the input system partial target files package. |
| # We extract them directly into the output temporary directory since the |
| # items do not need special case processing. |
| |
| extract_items( |
| target_files=system_target_files, |
| target_files_temp_dir=output_target_files_temp_dir, |
| extract_item_list=system_item_list) |
| |
| # Extract "as is" items from the input other partial target files package. We |
| # extract them directly into the output temporary directory since the items |
| # do not need special case processing. |
| |
| extract_items( |
| target_files=other_target_files, |
| target_files_temp_dir=output_target_files_temp_dir, |
| extract_item_list=other_item_list) |
| |
| # Extract "special" items from the input system partial target files package. |
| # We extract these items to different directory since they require special |
| # processing before they will end up in the output directory. |
| |
| extract_items( |
| target_files=system_target_files, |
| target_files_temp_dir=system_target_files_temp_dir, |
| extract_item_list=system_extract_special_item_list) |
| |
| # Extract "special" items from the input other partial target files package. |
| # We extract these items to different directory since they require special |
| # processing before they will end up in the output directory. |
| |
| extract_items( |
| target_files=other_target_files, |
| target_files_temp_dir=other_target_files_temp_dir, |
| extract_item_list=other_extract_special_item_list) |
| |
| # Now that the temporary directories contain all the extracted files, perform |
| # special case processing on any items that need it. After this function |
| # completes successfully, all the files we need to create the output target |
| # files package are in place. |
| |
| process_special_cases( |
| temp_dir=temp_dir, |
| system_target_files_temp_dir=system_target_files_temp_dir, |
| other_target_files_temp_dir=other_target_files_temp_dir, |
| output_target_files_temp_dir=output_target_files_temp_dir, |
| system_misc_info_keys=system_misc_info_keys, |
| rebuild_recovery=rebuild_recovery) |
| |
| # Regenerate IMAGES in the temporary directory. |
| |
| add_img_args = ['--verbose'] |
| if rebuild_recovery: |
| add_img_args.append('--rebuild_recovery') |
| add_img_args.append(output_target_files_temp_dir) |
| |
| add_img_to_target_files.main(add_img_args) |
| |
| # Finally, create the output target files zip archive. |
| |
| output_zip = os.path.abspath(output_target_files) |
| output_target_files_list = os.path.join(temp_dir, 'output.list') |
| output_target_files_meta_dir = os.path.join( |
| output_target_files_temp_dir, 'META') |
| |
| command = [ |
| 'find', |
| output_target_files_meta_dir, |
| ] |
| # TODO(bpeckham): sort this to be more like build. |
| meta_content = common.RunAndCheckOutput(command, verbose=False) |
| command = [ |
| 'find', |
| output_target_files_temp_dir, |
| '-path', |
| output_target_files_meta_dir, |
| '-prune', |
| '-o', |
| '-print' |
| ] |
| # TODO(bpeckham): sort this to be more like build. |
| other_content = common.RunAndCheckOutput(command, verbose=False) |
| |
| with open(output_target_files_list, 'wb') as f: |
| f.write(meta_content) |
| f.write(other_content) |
| |
| command = [ |
| 'soong_zip', |
| '-d', |
| '-o', output_zip, |
| '-C', output_target_files_temp_dir, |
| '-l', output_target_files_list, |
| ] |
| logger.info('creating %s', output_target_files) |
| common.RunAndWait(command, verbose=True) |
| |
| |
| def call_func_with_temp_dir(func, keep_tmp): |
| """Manage the creation and cleanup of the temporary directory. |
| |
| This function calls the given function after first creating a temporary |
| directory. It also cleans up the temporary directory. |
| |
| Args: |
| func: The function to call. Should accept one parameter, the path to |
| the temporary directory. |
| |
| keep_tmp: Keep the temporary directory after processing is complete. |
| """ |
| |
| # Create a temporary directory. This will serve as the parent of directories |
| # we use when we extract items from the input target files packages, and also |
| # a scratch directory that we use for temporary files. |
| |
| temp_dir = common.MakeTempDir(prefix='merge_target_files_') |
| |
| try: |
| func(temp_dir) |
| except: |
| raise |
| finally: |
| if keep_tmp: |
| logger.info('keeping %s', temp_dir) |
| else: |
| common.Cleanup() |
| |
| |
| def main(): |
| """The main function. |
| |
| Process command line arguments, then call merge_target_files to |
| perform the heavy lifting. |
| """ |
| |
| common.InitLogging() |
| |
| def option_handler(o, a): |
| if o == '--system-target-files': |
| OPTIONS.system_target_files = a |
| elif o == '--system-item-list': |
| OPTIONS.system_item_list = a |
| elif o == '--system-misc-info-keys': |
| OPTIONS.system_misc_info_keys = a |
| elif o == '--other-target-files': |
| OPTIONS.other_target_files = a |
| elif o == '--other-item-list': |
| OPTIONS.other_item_list = a |
| elif o == '--output-target-files': |
| OPTIONS.output_target_files = a |
| elif o == '--rebuild_recovery': |
| OPTIONS.rebuild_recovery = True |
| elif o == '--keep-tmp': |
| OPTIONS.keep_tmp = True |
| else: |
| return False |
| return True |
| |
| args = common.ParseOptions( |
| sys.argv[1:], __doc__, |
| extra_long_opts=[ |
| 'system-target-files=', |
| 'system-item-list=', |
| 'system-misc-info-keys=', |
| 'other-target-files=', |
| 'other-item-list=', |
| 'output-target-files=', |
| 'rebuild_recovery', |
| 'keep-tmp', |
| ], |
| extra_option_handler=option_handler) |
| |
| if (len(args) != 0 or |
| OPTIONS.system_target_files is None or |
| OPTIONS.other_target_files is None or |
| OPTIONS.output_target_files is None): |
| common.Usage(__doc__) |
| sys.exit(1) |
| |
| if OPTIONS.system_item_list: |
| system_item_list = read_config_list(OPTIONS.system_item_list) |
| else: |
| system_item_list = default_system_item_list |
| |
| if OPTIONS.system_misc_info_keys: |
| system_misc_info_keys = read_config_list(OPTIONS.system_misc_info_keys) |
| else: |
| system_misc_info_keys = default_system_misc_info_keys |
| |
| if OPTIONS.other_item_list: |
| other_item_list = read_config_list(OPTIONS.other_item_list) |
| else: |
| other_item_list = default_other_item_list |
| |
| if not validate_config_lists( |
| system_item_list=system_item_list, |
| system_misc_info_keys=system_misc_info_keys, |
| other_item_list=other_item_list): |
| sys.exit(1) |
| |
| call_func_with_temp_dir( |
| lambda temp_dir: merge_target_files( |
| temp_dir=temp_dir, |
| system_target_files=OPTIONS.system_target_files, |
| system_item_list=system_item_list, |
| system_misc_info_keys=system_misc_info_keys, |
| other_target_files=OPTIONS.other_target_files, |
| other_item_list=other_item_list, |
| output_target_files=OPTIONS.output_target_files, |
| rebuild_recovery=OPTIONS.rebuild_recovery), |
| OPTIONS.keep_tmp) |
| |
| |
| if __name__ == '__main__': |
| main() |