1#!/usr/bin/env python 2# 3# Copyright (C) 2019 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); you may not 6# use this file except in compliance with the License. You may obtain a copy of 7# the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14# License for the specific language governing permissions and limitations under 15# the License. 16 17""" 18This script merges two partial target files packages (one of which contains 19system files, and the other contains non-system files) together, producing a 20complete target files package that can be used to generate an OTA package. 21 22Usage: merge_target_files.py [args] 23 24 --system-target-files system-target-files-zip-archive 25 The input target files package containing system bits. This is a zip 26 archive. 27 28 --system-item-list system-item-list-file 29 The optional path to a newline-separated config file that replaces the 30 contents of default_system_item_list if provided. 31 32 --system-misc-info-keys system-misc-info-keys-file 33 The optional path to a newline-separated config file that replaces the 34 contents of default_system_misc_info_keys if provided. 35 36 --other-target-files other-target-files-zip-archive 37 The input target files package containing other bits. This is a zip 38 archive. 39 40 --other-item-list other-item-list-file 41 The optional path to a newline-separated config file that replaces the 42 contents of default_other_item_list if provided. 43 44 --output-target-files output-target-files-package 45 The output merged target files package. Also a zip archive. 46 47 --rebuild_recovery 48 Rebuild the recovery patch used by non-A/B devices and write it to the 49 system image. 50 51 --keep-tmp 52 Keep tempoary files for debugging purposes. 53""" 54 55from __future__ import print_function 56 57import fnmatch 58import logging 59import os 60import sys 61import zipfile 62 63import common 64import add_img_to_target_files 65 66logger = logging.getLogger(__name__) 67OPTIONS = common.OPTIONS 68OPTIONS.verbose = True 69OPTIONS.system_target_files = None 70OPTIONS.system_item_list = None 71OPTIONS.system_misc_info_keys = None 72OPTIONS.other_target_files = None 73OPTIONS.other_item_list = None 74OPTIONS.output_target_files = None 75OPTIONS.rebuild_recovery = False 76OPTIONS.keep_tmp = False 77 78# default_system_item_list is a list of items to extract from the partial 79# system target files package as is, meaning these items will land in the 80# output target files package exactly as they appear in the input partial 81# system target files package. 82 83default_system_item_list = [ 84 'META/apkcerts.txt', 85 'META/filesystem_config.txt', 86 'META/root_filesystem_config.txt', 87 'META/system_manifest.xml', 88 'META/system_matrix.xml', 89 'META/update_engine_config.txt', 90 'PRODUCT/*', 91 'ROOT/*', 92 'SYSTEM/*', 93] 94 95# system_extract_special_item_list is a list of items to extract from the 96# partial system target files package that need some special processing, such 97# as some sort of combination with items from the partial other target files 98# package. 99 100system_extract_special_item_list = [ 101 'META/*', 102] 103 104# default_system_misc_info_keys is a list of keys to obtain from the system instance of 105# META/misc_info.txt. The remaining keys from the other instance. 106 107default_system_misc_info_keys = [ 108 'avb_system_hashtree_enable', 109 'avb_system_add_hashtree_footer_args', 110 'avb_system_key_path', 111 'avb_system_algorithm', 112 'avb_system_rollback_index_location', 113 'avb_product_hashtree_enable', 114 'avb_product_add_hashtree_footer_args', 115 'avb_product_services_hashtree_enable', 116 'avb_product_services_add_hashtree_footer_args', 117 'system_root_image', 118 'root_dir', 119 'ab_update', 120 'default_system_dev_certificate', 121 'system_size', 122] 123 124# default_other_item_list is a list of items to extract from the partial 125# other target files package as is, meaning these items will land in the output 126# target files package exactly as they appear in the input partial other target 127# files package. 128 129default_other_item_list = [ 130 'META/boot_filesystem_config.txt', 131 'META/otakeys.txt', 132 'META/releasetools.py', 133 'META/vendor_filesystem_config.txt', 134 'META/vendor_manifest.xml', 135 'META/vendor_matrix.xml', 136 'BOOT/*', 137 'DATA/*', 138 'ODM/*', 139 'OTA/android-info.txt', 140 'PREBUILT_IMAGES/*', 141 'RADIO/*', 142 'VENDOR/*', 143] 144 145# other_extract_special_item_list is a list of items to extract from the 146# partial other target files package that need some special processing, such as 147# some sort of combination with items from the partial system target files 148# package. 149 150other_extract_special_item_list = [ 151 'META/*', 152] 153 154 155def extract_items(target_files, target_files_temp_dir, extract_item_list): 156 """Extract items from target files to temporary directory. 157 158 This function extracts from the specified target files zip archive into the 159 specified temporary directory, the items specified in the extract item list. 160 161 Args: 162 target_files: The target files zip archive from which to extract items. 163 164 target_files_temp_dir: The temporary directory where the extracted items 165 will land. 166 167 extract_item_list: A list of items to extract. 168 """ 169 170 logger.info('extracting from %s', target_files) 171 172 # Filter the extract_item_list to remove any items that do not exist in the 173 # zip file. Otherwise, the extraction step will fail. 174 175 with zipfile.ZipFile( 176 target_files, 177 'r', 178 allowZip64=True) as target_files_zipfile: 179 target_files_namelist = target_files_zipfile.namelist() 180 181 filtered_extract_item_list = [] 182 for pattern in extract_item_list: 183 matching_namelist = fnmatch.filter(target_files_namelist, pattern) 184 if not matching_namelist: 185 logger.warning('no match for %s', pattern) 186 else: 187 filtered_extract_item_list.append(pattern) 188 189 # Extract from target_files into target_files_temp_dir the 190 # filtered_extract_item_list. 191 192 common.UnzipToDir( 193 target_files, 194 target_files_temp_dir, 195 filtered_extract_item_list) 196 197 198def read_config_list(config_file_path): 199 """Reads a config file into a list of strings. 200 201 Expects the file to be newline-separated. 202 203 Args: 204 config_file_path: The path to the config file to open and read. 205 """ 206 with open(config_file_path) as config_file: 207 return config_file.read().splitlines() 208 209 210def validate_config_lists( 211 system_item_list, 212 system_misc_info_keys, 213 other_item_list): 214 """Performs validations on the merge config lists. 215 216 Args: 217 system_item_list: The list of items to extract from the partial 218 system target files package as is. 219 220 system_misc_info_keys: A list of keys to obtain from the system instance 221 of META/misc_info.txt. The remaining keys from the other instance. 222 223 other_item_list: The list of items to extract from the partial 224 other target files package as is. 225 226 Returns: 227 False if a validation fails, otherwise true. 228 """ 229 default_combined_item_set = set(default_system_item_list) 230 default_combined_item_set.update(default_other_item_list) 231 232 combined_item_set = set(system_item_list) 233 combined_item_set.update(other_item_list) 234 235 # Check that the merge config lists are not missing any item specified 236 # by the default config lists. 237 difference = default_combined_item_set.difference(combined_item_set) 238 if difference: 239 logger.error('Missing merge config items: %s' % list(difference)) 240 logger.error('Please ensure missing items are in either the ' 241 'system-item-list or other-item-list files provided to ' 242 'this script.') 243 return False 244 245 if ('dynamic_partition_list' in system_misc_info_keys) or ( 246 'super_partition_groups' in system_misc_info_keys): 247 logger.error('Dynamic partition misc info keys should come from ' 248 'the other instance of META/misc_info.txt.') 249 return False 250 251 return True 252 253 254def process_ab_partitions_txt( 255 system_target_files_temp_dir, 256 other_target_files_temp_dir, 257 output_target_files_temp_dir): 258 """Perform special processing for META/ab_partitions.txt 259 260 This function merges the contents of the META/ab_partitions.txt files from 261 the system directory and the other directory, placing the merged result in 262 the output directory. The precondition in that the files are already 263 extracted. The post condition is that the output META/ab_partitions.txt 264 contains the merged content. The format for each ab_partitions.txt a one 265 partition name per line. The output file contains the union of the parition 266 names. 267 268 Args: 269 system_target_files_temp_dir: The name of a directory containing the 270 special items extracted from the system target files package. 271 272 other_target_files_temp_dir: The name of a directory containing the 273 special items extracted from the other target files package. 274 275 output_target_files_temp_dir: The name of a directory that will be used 276 to create the output target files package after all the special cases 277 are processed. 278 """ 279 280 system_ab_partitions_txt = os.path.join( 281 system_target_files_temp_dir, 'META', 'ab_partitions.txt') 282 283 other_ab_partitions_txt = os.path.join( 284 other_target_files_temp_dir, 'META', 'ab_partitions.txt') 285 286 with open(system_ab_partitions_txt) as f: 287 system_ab_partitions = f.read().splitlines() 288 289 with open(other_ab_partitions_txt) as f: 290 other_ab_partitions = f.read().splitlines() 291 292 output_ab_partitions = set(system_ab_partitions + other_ab_partitions) 293 294 output_ab_partitions_txt = os.path.join( 295 output_target_files_temp_dir, 'META', 'ab_partitions.txt') 296 297 with open(output_ab_partitions_txt, 'w') as output: 298 for partition in sorted(output_ab_partitions): 299 output.write('%s\n' % partition) 300 301 302def append_recovery_to_filesystem_config(output_target_files_temp_dir): 303 """Perform special processing for META/filesystem_config.txt 304 305 This function appends recovery information to META/filesystem_config.txt 306 so that recovery patch regeneration will succeed. 307 308 Args: 309 output_target_files_temp_dir: The name of a directory that will be used 310 to create the output target files package after all the special cases 311 are processed. We find filesystem_config.txt here. 312 """ 313 314 filesystem_config_txt = os.path.join( 315 output_target_files_temp_dir, 316 'META', 317 'filesystem_config.txt') 318 319 with open(filesystem_config_txt, 'a') as f: 320 # TODO(bpeckham) this data is hard coded. It should be generated 321 # programmatically. 322 f.write( 323 'system/bin/install-recovery.sh 0 0 750 ' 324 'selabel=u:object_r:install_recovery_exec:s0 capabilities=0x0\n') 325 f.write( 326 'system/recovery-from-boot.p 0 0 644 ' 327 'selabel=u:object_r:system_file:s0 capabilities=0x0\n') 328 f.write( 329 'system/etc/recovery.img 0 0 440 ' 330 'selabel=u:object_r:install_recovery_exec:s0 capabilities=0x0\n') 331 332 333def process_misc_info_txt( 334 system_target_files_temp_dir, 335 other_target_files_temp_dir, 336 output_target_files_temp_dir, 337 system_misc_info_keys): 338 """Perform special processing for META/misc_info.txt 339 340 This function merges the contents of the META/misc_info.txt files from the 341 system directory and the other directory, placing the merged result in the 342 output directory. The precondition in that the files are already extracted. 343 The post condition is that the output META/misc_info.txt contains the merged 344 content. 345 346 Args: 347 system_target_files_temp_dir: The name of a directory containing the 348 special items extracted from the system target files package. 349 350 other_target_files_temp_dir: The name of a directory containing the 351 special items extracted from the other target files package. 352 353 output_target_files_temp_dir: The name of a directory that will be used 354 to create the output target files package after all the special cases 355 are processed. 356 357 system_misc_info_keys: A list of keys to obtain from the system instance 358 of META/misc_info.txt. The remaining keys from the other instance. 359 """ 360 361 def read_helper(d): 362 misc_info_txt = os.path.join(d, 'META', 'misc_info.txt') 363 with open(misc_info_txt) as f: 364 return list(f.read().splitlines()) 365 366 system_info_dict = common.LoadDictionaryFromLines( 367 read_helper(system_target_files_temp_dir)) 368 369 # We take most of the misc info from the other target files. 370 371 merged_info_dict = common.LoadDictionaryFromLines( 372 read_helper(other_target_files_temp_dir)) 373 374 # Replace certain values in merged_info_dict with values from 375 # system_info_dict. 376 377 for key in system_misc_info_keys: 378 merged_info_dict[key] = system_info_dict[key] 379 380 # Merge misc info keys used for Dynamic Partitions. 381 if (merged_info_dict.get('use_dynamic_partitions') == 'true') and ( 382 system_info_dict.get('use_dynamic_partitions') == 'true'): 383 merged_info_dict['dynamic_partition_list'] = '%s %s' % ( 384 system_info_dict.get('dynamic_partition_list', ''), 385 merged_info_dict.get('dynamic_partition_list', '')) 386 # Partition groups and group sizes are defined by the other (non-system) 387 # misc info file because these values may vary for each board that uses 388 # a shared system image. 389 for partition_group in merged_info_dict['super_partition_groups'].split(' '): 390 if ('super_%s_group_size' % partition_group) not in merged_info_dict: 391 raise common.ExternalError( 392 'Other META/misc_info.txt does not contain required key ' 393 'super_%s_group_size.' % partition_group) 394 key = 'super_%s_partition_list' % partition_group 395 merged_info_dict[key] = '%s %s' % ( 396 system_info_dict.get(key, ''), 397 merged_info_dict.get(key, '')) 398 399 output_misc_info_txt = os.path.join( 400 output_target_files_temp_dir, 401 'META', 'misc_info.txt') 402 403 sorted_keys = sorted(merged_info_dict.keys()) 404 405 with open(output_misc_info_txt, 'w') as output: 406 for key in sorted_keys: 407 output.write('{}={}\n'.format(key, merged_info_dict[key])) 408 409 410def process_file_contexts_bin(temp_dir, output_target_files_temp_dir): 411 """Perform special processing for META/file_contexts.bin. 412 413 This function combines plat_file_contexts and vendor_file_contexts, which are 414 expected to already be extracted in temp_dir, to produce a merged 415 file_contexts.bin that will land in temp_dir at META/file_contexts.bin. 416 417 Args: 418 temp_dir: The name of a scratch directory that this function can use for 419 intermediate files generated during processing. 420 421 output_target_files_temp_dir: The name of the working directory that must 422 already contain plat_file_contexts and vendor_file_contexts (in the 423 appropriate sub directories), and to which META/file_contexts.bin will be 424 written. 425 """ 426 427 # To create a merged file_contexts.bin file, we use the system and vendor 428 # file contexts files as input, the m4 tool to combine them, the sorting tool 429 # to sort, and finally the sefcontext_compile tool to generate the final 430 # output. We currently omit a checkfc step since the files had been checked 431 # as part of the build. 432 433 # The m4 step concatenates the two input files contexts files. Since m4 434 # writes to stdout, we receive that into an array of bytes, and then write it 435 # to a file. 436 437 # Collect the file contexts that we're going to combine from SYSTEM, VENDOR, 438 # PRODUCT, and ODM. We require SYSTEM and VENDOR, but others are optional. 439 440 file_contexts_list = [] 441 442 for partition in ['SYSTEM', 'VENDOR', 'PRODUCT', 'ODM']: 443 prefix = 'plat' if partition == 'SYSTEM' else partition.lower() 444 445 file_contexts = os.path.join( 446 output_target_files_temp_dir, 447 partition, 'etc', 'selinux', prefix + '_file_contexts') 448 449 mandatory = partition in ['SYSTEM', 'VENDOR'] 450 451 if mandatory or os.path.isfile(file_contexts): 452 file_contexts_list.append(file_contexts) 453 else: 454 logger.warning('file not found: %s', file_contexts) 455 456 command = ['m4', '--fatal-warnings', '-s'] + file_contexts_list 457 458 merged_content = common.RunAndCheckOutput(command, verbose=False) 459 460 merged_file_contexts_txt = os.path.join(temp_dir, 'merged_file_contexts.txt') 461 462 with open(merged_file_contexts_txt, 'wb') as f: 463 f.write(merged_content) 464 465 # The sort step sorts the concatenated file. 466 467 sorted_file_contexts_txt = os.path.join(temp_dir, 'sorted_file_contexts.txt') 468 command = ['fc_sort', merged_file_contexts_txt, sorted_file_contexts_txt] 469 common.RunAndWait(command, verbose=True) 470 471 # Finally, the compile step creates the final META/file_contexts.bin. 472 473 file_contexts_bin = os.path.join( 474 output_target_files_temp_dir, 475 'META', 'file_contexts.bin') 476 477 command = [ 478 'sefcontext_compile', 479 '-o', file_contexts_bin, 480 sorted_file_contexts_txt, 481 ] 482 483 common.RunAndWait(command, verbose=True) 484 485 486def process_special_cases( 487 temp_dir, 488 system_target_files_temp_dir, 489 other_target_files_temp_dir, 490 output_target_files_temp_dir, 491 system_misc_info_keys, 492 rebuild_recovery 493): 494 """Perform special-case processing for certain target files items. 495 496 Certain files in the output target files package require special-case 497 processing. This function performs all that special-case processing. 498 499 Args: 500 temp_dir: The name of a scratch directory that this function can use for 501 intermediate files generated during processing. 502 503 system_target_files_temp_dir: The name of a directory containing the 504 special items extracted from the system target files package. 505 506 other_target_files_temp_dir: The name of a directory containing the 507 special items extracted from the other target files package. 508 509 output_target_files_temp_dir: The name of a directory that will be used 510 to create the output target files package after all the special cases 511 are processed. 512 513 system_misc_info_keys: A list of keys to obtain from the system instance 514 of META/misc_info.txt. The remaining keys from the other instance. 515 516 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B 517 devices and write it to the system image. 518 """ 519 520 if 'ab_update' in system_misc_info_keys: 521 process_ab_partitions_txt( 522 system_target_files_temp_dir=system_target_files_temp_dir, 523 other_target_files_temp_dir=other_target_files_temp_dir, 524 output_target_files_temp_dir=output_target_files_temp_dir) 525 526 if rebuild_recovery: 527 append_recovery_to_filesystem_config( 528 output_target_files_temp_dir=output_target_files_temp_dir) 529 530 process_misc_info_txt( 531 system_target_files_temp_dir=system_target_files_temp_dir, 532 other_target_files_temp_dir=other_target_files_temp_dir, 533 output_target_files_temp_dir=output_target_files_temp_dir, 534 system_misc_info_keys=system_misc_info_keys) 535 536 process_file_contexts_bin( 537 temp_dir=temp_dir, 538 output_target_files_temp_dir=output_target_files_temp_dir) 539 540 541def merge_target_files( 542 temp_dir, 543 system_target_files, 544 system_item_list, 545 system_misc_info_keys, 546 other_target_files, 547 other_item_list, 548 output_target_files, 549 rebuild_recovery): 550 """Merge two target files packages together. 551 552 This function takes system and other target files packages as input, performs 553 various file extractions, special case processing, and finally creates a 554 merged zip archive as output. 555 556 Args: 557 temp_dir: The name of a directory we use when we extract items from the 558 input target files packages, and also a scratch directory that we use for 559 temporary files. 560 561 system_target_files: The name of the zip archive containing the system 562 partial target files package. 563 564 system_item_list: The list of items to extract from the partial system 565 target files package as is, meaning these items will land in the output 566 target files package exactly as they appear in the input partial system 567 target files package. 568 569 system_misc_info_keys: The list of keys to obtain from the system instance 570 of META/misc_info.txt. The remaining keys from the other instance. 571 572 other_target_files: The name of the zip archive containing the other 573 partial target files package. 574 575 other_item_list: The list of items to extract from the partial other 576 target files package as is, meaning these items will land in the output 577 target files package exactly as they appear in the input partial other 578 target files package. 579 580 output_target_files: The name of the output zip archive target files 581 package created by merging system and other. 582 583 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B 584 devices and write it to the system image. 585 """ 586 587 logger.info( 588 'starting: merge system %s and other %s into output %s', 589 system_target_files, 590 other_target_files, 591 output_target_files) 592 593 # Create directory names that we'll use when we extract files from system, 594 # and other, and for zipping the final output. 595 596 system_target_files_temp_dir = os.path.join(temp_dir, 'system') 597 other_target_files_temp_dir = os.path.join(temp_dir, 'other') 598 output_target_files_temp_dir = os.path.join(temp_dir, 'output') 599 600 # Extract "as is" items from the input system partial target files package. 601 # We extract them directly into the output temporary directory since the 602 # items do not need special case processing. 603 604 extract_items( 605 target_files=system_target_files, 606 target_files_temp_dir=output_target_files_temp_dir, 607 extract_item_list=system_item_list) 608 609 # Extract "as is" items from the input other partial target files package. We 610 # extract them directly into the output temporary directory since the items 611 # do not need special case processing. 612 613 extract_items( 614 target_files=other_target_files, 615 target_files_temp_dir=output_target_files_temp_dir, 616 extract_item_list=other_item_list) 617 618 # Extract "special" items from the input system partial target files package. 619 # We extract these items to different directory since they require special 620 # processing before they will end up in the output directory. 621 622 extract_items( 623 target_files=system_target_files, 624 target_files_temp_dir=system_target_files_temp_dir, 625 extract_item_list=system_extract_special_item_list) 626 627 # Extract "special" items from the input other partial target files package. 628 # We extract these items to different directory since they require special 629 # processing before they will end up in the output directory. 630 631 extract_items( 632 target_files=other_target_files, 633 target_files_temp_dir=other_target_files_temp_dir, 634 extract_item_list=other_extract_special_item_list) 635 636 # Now that the temporary directories contain all the extracted files, perform 637 # special case processing on any items that need it. After this function 638 # completes successfully, all the files we need to create the output target 639 # files package are in place. 640 641 process_special_cases( 642 temp_dir=temp_dir, 643 system_target_files_temp_dir=system_target_files_temp_dir, 644 other_target_files_temp_dir=other_target_files_temp_dir, 645 output_target_files_temp_dir=output_target_files_temp_dir, 646 system_misc_info_keys=system_misc_info_keys, 647 rebuild_recovery=rebuild_recovery) 648 649 # Regenerate IMAGES in the temporary directory. 650 651 add_img_args = ['--verbose'] 652 if rebuild_recovery: 653 add_img_args.append('--rebuild_recovery') 654 add_img_args.append(output_target_files_temp_dir) 655 656 add_img_to_target_files.main(add_img_args) 657 658 # Finally, create the output target files zip archive. 659 660 output_zip = os.path.abspath(output_target_files) 661 output_target_files_list = os.path.join(temp_dir, 'output.list') 662 output_target_files_meta_dir = os.path.join( 663 output_target_files_temp_dir, 'META') 664 665 command = [ 666 'find', 667 output_target_files_meta_dir, 668 ] 669 # TODO(bpeckham): sort this to be more like build. 670 meta_content = common.RunAndCheckOutput(command, verbose=False) 671 command = [ 672 'find', 673 output_target_files_temp_dir, 674 '-path', 675 output_target_files_meta_dir, 676 '-prune', 677 '-o', 678 '-print' 679 ] 680 # TODO(bpeckham): sort this to be more like build. 681 other_content = common.RunAndCheckOutput(command, verbose=False) 682 683 with open(output_target_files_list, 'wb') as f: 684 f.write(meta_content) 685 f.write(other_content) 686 687 command = [ 688 'soong_zip', 689 '-d', 690 '-o', output_zip, 691 '-C', output_target_files_temp_dir, 692 '-l', output_target_files_list, 693 ] 694 logger.info('creating %s', output_target_files) 695 common.RunAndWait(command, verbose=True) 696 697 698def call_func_with_temp_dir(func, keep_tmp): 699 """Manage the creation and cleanup of the temporary directory. 700 701 This function calls the given function after first creating a temporary 702 directory. It also cleans up the temporary directory. 703 704 Args: 705 func: The function to call. Should accept one parameter, the path to 706 the temporary directory. 707 708 keep_tmp: Keep the temporary directory after processing is complete. 709 """ 710 711 # Create a temporary directory. This will serve as the parent of directories 712 # we use when we extract items from the input target files packages, and also 713 # a scratch directory that we use for temporary files. 714 715 temp_dir = common.MakeTempDir(prefix='merge_target_files_') 716 717 try: 718 func(temp_dir) 719 except: 720 raise 721 finally: 722 if keep_tmp: 723 logger.info('keeping %s', temp_dir) 724 else: 725 common.Cleanup() 726 727 728def main(): 729 """The main function. 730 731 Process command line arguments, then call merge_target_files to 732 perform the heavy lifting. 733 """ 734 735 common.InitLogging() 736 737 def option_handler(o, a): 738 if o == '--system-target-files': 739 OPTIONS.system_target_files = a 740 elif o == '--system-item-list': 741 OPTIONS.system_item_list = a 742 elif o == '--system-misc-info-keys': 743 OPTIONS.system_misc_info_keys = a 744 elif o == '--other-target-files': 745 OPTIONS.other_target_files = a 746 elif o == '--other-item-list': 747 OPTIONS.other_item_list = a 748 elif o == '--output-target-files': 749 OPTIONS.output_target_files = a 750 elif o == '--rebuild_recovery': 751 OPTIONS.rebuild_recovery = True 752 elif o == '--keep-tmp': 753 OPTIONS.keep_tmp = True 754 else: 755 return False 756 return True 757 758 args = common.ParseOptions( 759 sys.argv[1:], __doc__, 760 extra_long_opts=[ 761 'system-target-files=', 762 'system-item-list=', 763 'system-misc-info-keys=', 764 'other-target-files=', 765 'other-item-list=', 766 'output-target-files=', 767 'rebuild_recovery', 768 'keep-tmp', 769 ], 770 extra_option_handler=option_handler) 771 772 if (len(args) != 0 or 773 OPTIONS.system_target_files is None or 774 OPTIONS.other_target_files is None or 775 OPTIONS.output_target_files is None): 776 common.Usage(__doc__) 777 sys.exit(1) 778 779 if OPTIONS.system_item_list: 780 system_item_list = read_config_list(OPTIONS.system_item_list) 781 else: 782 system_item_list = default_system_item_list 783 784 if OPTIONS.system_misc_info_keys: 785 system_misc_info_keys = read_config_list(OPTIONS.system_misc_info_keys) 786 else: 787 system_misc_info_keys = default_system_misc_info_keys 788 789 if OPTIONS.other_item_list: 790 other_item_list = read_config_list(OPTIONS.other_item_list) 791 else: 792 other_item_list = default_other_item_list 793 794 if not validate_config_lists( 795 system_item_list=system_item_list, 796 system_misc_info_keys=system_misc_info_keys, 797 other_item_list=other_item_list): 798 sys.exit(1) 799 800 call_func_with_temp_dir( 801 lambda temp_dir: merge_target_files( 802 temp_dir=temp_dir, 803 system_target_files=OPTIONS.system_target_files, 804 system_item_list=system_item_list, 805 system_misc_info_keys=system_misc_info_keys, 806 other_target_files=OPTIONS.other_target_files, 807 other_item_list=other_item_list, 808 output_target_files=OPTIONS.output_target_files, 809 rebuild_recovery=OPTIONS.rebuild_recovery), 810 OPTIONS.keep_tmp) 811 812 813if __name__ == '__main__': 814 main() 815