1#!/usr/bin/env python 2# 3# Copyright (C) 2022 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"""This script merges two partial target files packages. 18 19One input package contains framework files, and the other contains vendor files. 20 21This script produces a complete, merged target files package: 22 - This package can be used to generate a flashable IMG package. 23 See --output-img. 24 - This package can be used to generate an OTA package. See --output-ota. 25 - The merged package is checked for compatibility between the two inputs. 26 27Usage: merge_target_files [args] 28 29 --framework-target-files framework-target-files-package 30 The input target files package containing framework bits. This is a zip 31 archive or a directory. 32 33 --framework-item-list framework-item-list-file 34 The optional path to a newline-separated config file of items that 35 are extracted as-is from the framework target files package. 36 37 --framework-misc-info-keys framework-misc-info-keys-file 38 The optional path to a newline-separated config file of keys to 39 extract from the framework META/misc_info.txt file. 40 41 --vendor-target-files vendor-target-files-package 42 The input target files package containing vendor bits. This is a zip 43 archive or a directory. 44 45 --vendor-item-list vendor-item-list-file 46 The optional path to a newline-separated config file of items that 47 are extracted as-is from the vendor target files package. 48 49 --boot-image-dir-path 50 The input boot image directory path. This path contains IMAGES/boot.img 51 file. 52 53 --output-target-files output-target-files-package 54 If provided, the output merged target files package. Also a zip archive. 55 56 --output-dir output-directory 57 If provided, the destination directory for saving merged files. Requires 58 the --output-item-list flag. 59 Can be provided alongside --output-target-files, or by itself. 60 61 --output-item-list output-item-list-file. 62 The optional path to a newline-separated config file that specifies the 63 file patterns to copy into the --output-dir. Required if providing 64 the --output-dir flag. 65 66 --output-ota output-ota-package 67 The output ota package. This is a zip archive. Use of this flag may 68 require passing the --path common flag; see common.py. 69 70 --output-img output-img-package 71 The output img package, suitable for use with 'fastboot update'. Use of 72 this flag may require passing the --path common flag; see common.py. 73 74 --output-super-empty output-super-empty-image 75 If provided, creates a super_empty.img file from the merged target 76 files package and saves it at this path. 77 78 --rebuild_recovery 79 Copy the recovery image used by non-A/B devices, used when 80 regenerating vendor images with --rebuild-sepolicy. 81 82 --allow-duplicate-apkapex-keys 83 If provided, duplicate APK/APEX keys are ignored and the value from the 84 framework is used. 85 86 --rebuild-sepolicy 87 If provided, rebuilds odm.img or vendor.img to include merged sepolicy 88 files. If odm is present then odm is preferred. 89 90 --vendor-otatools otatools.zip 91 If provided, use this otatools.zip when recompiling the odm or vendor 92 image to include sepolicy. 93 94 --keep-tmp 95 Keep tempoary files for debugging purposes. 96 97 --avb-resolve-rollback-index-location-conflict 98 If provided, resolve the conflict AVB rollback index location when 99 necessary. 100 101 --allow-partial-ab 102 If provided, allow merging non-AB framework target files with AB vendor 103 target files, which means that only the vendor has AB partitions. 104 105 The following only apply when using the VSDK to perform dexopt on vendor apps: 106 107 --framework-dexpreopt-config 108 If provided, the location of framwework's dexpreopt_config.zip. 109 110 --framework-dexpreopt-tools 111 if provided, the location of framework's dexpreopt_tools.zip. 112 113 --vendor-dexpreopt-config 114 If provided, the location of vendor's dexpreopt_config.zip. 115""" 116 117import logging 118import os 119import shutil 120import subprocess 121import sys 122import zipfile 123 124import add_img_to_target_files 125import build_image 126import build_super_image 127import common 128import img_from_target_files 129import merge_compatibility_checks 130import merge_dexopt 131import merge_meta 132import merge_utils 133import ota_from_target_files 134 135from common import ExternalError 136 137logger = logging.getLogger(__name__) 138 139OPTIONS = common.OPTIONS 140# Always turn on verbose logging. 141OPTIONS.verbose = True 142OPTIONS.framework_target_files = None 143OPTIONS.framework_item_list = [] 144OPTIONS.framework_misc_info_keys = [] 145OPTIONS.vendor_target_files = None 146OPTIONS.vendor_item_list = [] 147OPTIONS.boot_image_dir_path = None 148OPTIONS.output_target_files = None 149OPTIONS.output_dir = None 150OPTIONS.output_item_list = [] 151OPTIONS.output_ota = None 152OPTIONS.output_img = None 153OPTIONS.output_super_empty = None 154OPTIONS.rebuild_recovery = False 155# TODO(b/150582573): Remove this option. 156OPTIONS.allow_duplicate_apkapex_keys = False 157OPTIONS.vendor_otatools = None 158OPTIONS.rebuild_sepolicy = False 159OPTIONS.keep_tmp = False 160OPTIONS.avb_resolve_rollback_index_location_conflict = False 161OPTIONS.allow_partial_ab = False 162OPTIONS.framework_dexpreopt_config = None 163OPTIONS.framework_dexpreopt_tools = None 164OPTIONS.vendor_dexpreopt_config = None 165 166 167def move_only_exists(source, destination): 168 """Judge whether the file exists and then move the file.""" 169 170 if os.path.exists(source): 171 shutil.move(source, destination) 172 173 174def remove_file_if_exists(file_name): 175 """Remove the file if it exists and skip otherwise.""" 176 177 try: 178 os.remove(file_name) 179 except FileNotFoundError: 180 pass 181 182 183def include_extra_in_list(item_list): 184 """ 185 1. Include all `META/*` files in the item list. 186 187 To ensure that `AddImagesToTargetFiles` can still be used with vendor item 188 list that do not specify all of the required META/ files, those files should 189 be included by default. This preserves the backward compatibility of 190 `rebuild_image_with_sepolicy`. 191 192 2. Include `SYSTEM/build.prop` file in the item list. 193 194 To ensure that `AddImagesToTargetFiles` for GRF vendor images, can still 195 access SYSTEM/build.prop to pass GetPartitionFingerprint check in BuildInfo 196 constructor. 197 """ 198 if not item_list: 199 return None 200 return list(item_list) + ['META/*'] + ['SYSTEM/build.prop'] 201 202 203def create_merged_package(temp_dir): 204 """Merges two target files packages into one target files structure. 205 206 Returns: 207 Path to merged package under temp directory. 208 """ 209 # Extract "as is" items from the input framework and vendor partial target 210 # files packages directly into the output temporary directory, since these 211 # items do not need special case processing. 212 213 output_target_files_temp_dir = os.path.join(temp_dir, 'output') 214 merge_utils.CollectTargetFiles( 215 input_zipfile_or_dir=OPTIONS.framework_target_files, 216 output_dir=output_target_files_temp_dir, 217 item_list=OPTIONS.framework_item_list) 218 merge_utils.CollectTargetFiles( 219 input_zipfile_or_dir=OPTIONS.vendor_target_files, 220 output_dir=output_target_files_temp_dir, 221 item_list=OPTIONS.vendor_item_list) 222 223 if OPTIONS.boot_image_dir_path: 224 merge_utils.CollectTargetFiles( 225 input_zipfile_or_dir=OPTIONS.boot_image_dir_path, 226 output_dir=output_target_files_temp_dir, 227 item_list=['IMAGES/boot.img']) 228 229 # Perform special case processing on META/* items. 230 # After this function completes successfully, all the files we need to create 231 # the output target files package are in place. 232 merge_meta.MergeMetaFiles( 233 temp_dir=temp_dir, 234 merged_dir=output_target_files_temp_dir, 235 framework_partitions=OPTIONS.framework_partition_set) 236 237 merge_dexopt.MergeDexopt( 238 temp_dir=temp_dir, output_target_files_dir=output_target_files_temp_dir) 239 240 return output_target_files_temp_dir 241 242 243def generate_missing_images(target_files_dir): 244 """Generate any missing images from target files.""" 245 246 # Regenerate IMAGES in the target directory. 247 248 add_img_args = [ 249 '--verbose', 250 '--add_missing', 251 ] 252 if OPTIONS.rebuild_recovery: 253 add_img_args.append('--rebuild_recovery') 254 if OPTIONS.avb_resolve_rollback_index_location_conflict: 255 add_img_args.append('--avb_resolve_rollback_index_location_conflict') 256 add_img_args.append(target_files_dir) 257 258 add_img_to_target_files.main(add_img_args) 259 260 261def rebuild_image_with_sepolicy(target_files_dir): 262 """Rebuilds odm.img or vendor.img to include merged sepolicy files. 263 264 If odm is present then odm is preferred -- otherwise vendor is used. 265 """ 266 partition = 'vendor' 267 if os.path.exists(os.path.join(target_files_dir, 'ODM')): 268 partition = 'odm' 269 partition_img = '{}.img'.format(partition) 270 partition_map = '{}.map'.format(partition) 271 272 logger.info('Recompiling %s using the merged sepolicy files.', partition_img) 273 274 # Copy the combined SEPolicy file and framework hashes to the image that is 275 # being rebuilt. 276 def copy_selinux_file(input_path, output_filename): 277 input_filename = os.path.join(target_files_dir, input_path) 278 if not os.path.exists(input_filename): 279 input_filename = input_filename.replace('SYSTEM_EXT/', 280 'SYSTEM/system_ext/') \ 281 .replace('PRODUCT/', 'SYSTEM/product/') 282 if not os.path.exists(input_filename): 283 logger.info('Skipping copy_selinux_file for %s', input_filename) 284 return 285 shutil.copy( 286 input_filename, 287 os.path.join(target_files_dir, partition.upper(), 'etc/selinux', 288 output_filename)) 289 290 copy_selinux_file('META/combined_sepolicy', 'precompiled_sepolicy') 291 copy_selinux_file('SYSTEM/etc/selinux/plat_sepolicy_and_mapping.sha256', 292 'precompiled_sepolicy.plat_sepolicy_and_mapping.sha256') 293 copy_selinux_file( 294 'SYSTEM_EXT/etc/selinux/system_ext_sepolicy_and_mapping.sha256', 295 'precompiled_sepolicy.system_ext_sepolicy_and_mapping.sha256') 296 copy_selinux_file('PRODUCT/etc/selinux/product_sepolicy_and_mapping.sha256', 297 'precompiled_sepolicy.product_sepolicy_and_mapping.sha256') 298 299 if not OPTIONS.vendor_otatools: 300 # Remove the partition from the merged target-files archive. It will be 301 # rebuilt later automatically by generate_missing_images(). 302 remove_file_if_exists( 303 os.path.join(target_files_dir, 'IMAGES', partition_img)) 304 return 305 306 # TODO(b/192253131): Remove the need for vendor_otatools by fixing 307 # backwards-compatibility issues when compiling images across releases. 308 if not OPTIONS.vendor_target_files: 309 raise ValueError( 310 'Expected vendor_target_files if vendor_otatools is not None.') 311 logger.info( 312 '%s recompilation will be performed using the vendor otatools.zip', 313 partition_img) 314 315 # Unzip the vendor build's otatools.zip and target-files archive. 316 vendor_otatools_dir = common.MakeTempDir( 317 prefix='merge_target_files_vendor_otatools_') 318 vendor_target_files_dir = common.MakeTempDir( 319 prefix='merge_target_files_vendor_target_files_') 320 common.UnzipToDir(OPTIONS.vendor_otatools, vendor_otatools_dir) 321 merge_utils.CollectTargetFiles( 322 input_zipfile_or_dir=OPTIONS.vendor_target_files, 323 output_dir=vendor_target_files_dir, 324 item_list=include_extra_in_list(OPTIONS.vendor_item_list)) 325 326 # Copy the partition contents from the merged target-files archive to the 327 # vendor target-files archive. 328 shutil.rmtree(os.path.join(vendor_target_files_dir, partition.upper())) 329 shutil.copytree( 330 os.path.join(target_files_dir, partition.upper()), 331 os.path.join(vendor_target_files_dir, partition.upper()), 332 symlinks=True) 333 334 # Delete then rebuild the partition. 335 remove_file_if_exists( 336 os.path.join(vendor_target_files_dir, 'IMAGES', partition_img)) 337 rebuild_partition_command = [ 338 os.path.join(vendor_otatools_dir, 'bin', 'add_img_to_target_files'), 339 '--verbose', 340 '--add_missing', 341 ] 342 if OPTIONS.rebuild_recovery: 343 rebuild_partition_command.append('--rebuild_recovery') 344 rebuild_partition_command.append(vendor_target_files_dir) 345 logger.info('Recompiling %s: %s', partition_img, 346 ' '.join(rebuild_partition_command)) 347 common.RunAndCheckOutput(rebuild_partition_command, verbose=True) 348 349 # Move the newly-created image to the merged target files dir. 350 if not os.path.exists(os.path.join(target_files_dir, 'IMAGES')): 351 os.makedirs(os.path.join(target_files_dir, 'IMAGES')) 352 shutil.move( 353 os.path.join(vendor_target_files_dir, 'IMAGES', partition_img), 354 os.path.join(target_files_dir, 'IMAGES', partition_img)) 355 move_only_exists( 356 os.path.join(vendor_target_files_dir, 'IMAGES', partition_map), 357 os.path.join(target_files_dir, 'IMAGES', partition_map)) 358 359 def copy_recovery_file(filename): 360 for subdir in ('VENDOR', 'SYSTEM/vendor'): 361 source = os.path.join(vendor_target_files_dir, subdir, filename) 362 if os.path.exists(source): 363 dest = os.path.join(target_files_dir, subdir, filename) 364 shutil.copy(source, dest) 365 return 366 logger.info('Skipping copy_recovery_file for %s, file not found', filename) 367 368 if OPTIONS.rebuild_recovery: 369 copy_recovery_file('etc/recovery.img') 370 copy_recovery_file('bin/install-recovery.sh') 371 copy_recovery_file('recovery-from-boot.p') 372 373 374def generate_super_empty_image(target_dir, output_super_empty): 375 """Generates super_empty image from target package. 376 377 Args: 378 target_dir: Path to the target file package which contains misc_info.txt for 379 detailed information for super image. 380 output_super_empty: If provided, copies a super_empty.img file from the 381 target files package to this path. 382 """ 383 # Create super_empty.img using the merged misc_info.txt. 384 385 misc_info_txt = os.path.join(target_dir, 'META', 'misc_info.txt') 386 387 use_dynamic_partitions = common.LoadDictionaryFromFile(misc_info_txt).get( 388 'use_dynamic_partitions') 389 390 if use_dynamic_partitions != 'true' and output_super_empty: 391 raise ValueError( 392 'Building super_empty.img requires use_dynamic_partitions=true.') 393 elif use_dynamic_partitions == 'true': 394 super_empty_img = os.path.join(target_dir, 'IMAGES', 'super_empty.img') 395 build_super_image_args = [ 396 misc_info_txt, 397 super_empty_img, 398 ] 399 build_super_image.main(build_super_image_args) 400 401 # Copy super_empty.img to the user-provided output_super_empty location. 402 if output_super_empty: 403 shutil.copyfile(super_empty_img, output_super_empty) 404 405 406def create_target_files_archive(output_zip, source_dir, temp_dir): 407 """Creates a target_files zip archive from the input source dir. 408 409 Args: 410 output_zip: The name of the zip archive target files package. 411 source_dir: The target directory contains package to be archived. 412 temp_dir: Path to temporary directory for any intermediate files. 413 """ 414 output_target_files_list = os.path.join(temp_dir, 'output.list') 415 output_target_files_meta_dir = os.path.join(source_dir, 'META') 416 417 def files_from_path(target_path, extra_args=None): 418 """Gets files under the given path and return a sorted list.""" 419 find_command = ['find', target_path] + (extra_args or []) 420 find_process = common.Run( 421 find_command, stdout=subprocess.PIPE, verbose=False) 422 return common.RunAndCheckOutput(['sort'], 423 stdin=find_process.stdout, 424 verbose=False) 425 426 # META content appears first in the zip. This is done by the 427 # standard build system for optimized extraction of those files, 428 # so we do the same step for merged target_files.zips here too. 429 meta_content = files_from_path(output_target_files_meta_dir) 430 other_content = files_from_path( 431 source_dir, 432 ['-path', output_target_files_meta_dir, '-prune', '-o', '-print']) 433 434 with open(output_target_files_list, 'w') as f: 435 f.write(meta_content) 436 f.write(other_content) 437 438 command = [ 439 'soong_zip', 440 '-d', 441 '-o', 442 os.path.abspath(output_zip), 443 '-C', 444 source_dir, 445 '-r', 446 output_target_files_list, 447 ] 448 449 logger.info('creating %s', output_zip) 450 common.RunAndCheckOutput(command, verbose=True) 451 logger.info('finished creating %s', output_zip) 452 453 454def merge_target_files(temp_dir): 455 """Merges two target files packages together. 456 457 This function uses framework and vendor target files packages as input, 458 performs various file extractions, special case processing, and finally 459 creates a merged zip archive as output. 460 461 Args: 462 temp_dir: The name of a directory we use when we extract items from the 463 input target files packages, and also a scratch directory that we use for 464 temporary files. 465 """ 466 467 logger.info('starting: merge framework %s and vendor %s into output %s', 468 OPTIONS.framework_target_files, OPTIONS.vendor_target_files, 469 OPTIONS.output_target_files) 470 471 output_target_files_temp_dir = create_merged_package(temp_dir) 472 473 partition_map = common.PartitionMapFromTargetFiles( 474 output_target_files_temp_dir) 475 476 compatibility_errors = merge_compatibility_checks.CheckCompatibility( 477 target_files_dir=output_target_files_temp_dir, 478 partition_map=partition_map) 479 if compatibility_errors: 480 for error in compatibility_errors: 481 logger.error(error) 482 raise ExternalError( 483 'Found incompatibilities in the merged target files package.') 484 485 # Include the compiled policy in an image if requested. 486 if OPTIONS.rebuild_sepolicy: 487 rebuild_image_with_sepolicy(output_target_files_temp_dir) 488 489 generate_missing_images(output_target_files_temp_dir) 490 491 generate_super_empty_image(output_target_files_temp_dir, 492 OPTIONS.output_super_empty) 493 494 # Finally, create the output target files zip archive and/or copy the 495 # output items to the output target files directory. 496 497 if OPTIONS.output_dir: 498 merge_utils.CopyItems(output_target_files_temp_dir, OPTIONS.output_dir, 499 OPTIONS.output_item_list) 500 501 if not OPTIONS.output_target_files: 502 return 503 504 create_target_files_archive(OPTIONS.output_target_files, 505 output_target_files_temp_dir, temp_dir) 506 507 # Create the IMG package from the merged target files package. 508 if OPTIONS.output_img: 509 img_from_target_files.main( 510 [OPTIONS.output_target_files, OPTIONS.output_img]) 511 512 # Create the OTA package from the merged target files package. 513 514 if OPTIONS.output_ota: 515 ota_from_target_files.main( 516 [OPTIONS.output_target_files, OPTIONS.output_ota]) 517 518 519def main(): 520 """The main function. 521 522 Process command line arguments, then call merge_target_files to 523 perform the heavy lifting. 524 """ 525 526 common.InitLogging() 527 528 def option_handler(o, a): 529 if o == '--system-target-files': 530 logger.warning( 531 '--system-target-files has been renamed to --framework-target-files') 532 OPTIONS.framework_target_files = a 533 elif o == '--framework-target-files': 534 OPTIONS.framework_target_files = a 535 elif o == '--system-item-list': 536 logger.warning( 537 '--system-item-list has been renamed to --framework-item-list') 538 OPTIONS.framework_item_list = a 539 elif o == '--framework-item-list': 540 OPTIONS.framework_item_list = a 541 elif o == '--system-misc-info-keys': 542 logger.warning('--system-misc-info-keys has been renamed to ' 543 '--framework-misc-info-keys') 544 OPTIONS.framework_misc_info_keys = a 545 elif o == '--framework-misc-info-keys': 546 OPTIONS.framework_misc_info_keys = a 547 elif o == '--other-target-files': 548 logger.warning( 549 '--other-target-files has been renamed to --vendor-target-files') 550 OPTIONS.vendor_target_files = a 551 elif o == '--vendor-target-files': 552 OPTIONS.vendor_target_files = a 553 elif o == '--other-item-list': 554 logger.warning('--other-item-list has been renamed to --vendor-item-list') 555 OPTIONS.vendor_item_list = a 556 elif o == '--vendor-item-list': 557 OPTIONS.vendor_item_list = a 558 elif o == '--boot-image-dir-path': 559 OPTIONS.boot_image_dir_path = a 560 elif o == '--output-target-files': 561 OPTIONS.output_target_files = a 562 elif o == '--output-dir': 563 OPTIONS.output_dir = a 564 elif o == '--output-item-list': 565 OPTIONS.output_item_list = a 566 elif o == '--output-ota': 567 OPTIONS.output_ota = a 568 elif o == '--output-img': 569 OPTIONS.output_img = a 570 elif o == '--output-super-empty': 571 OPTIONS.output_super_empty = a 572 elif o == '--rebuild_recovery' or o == '--rebuild-recovery': 573 OPTIONS.rebuild_recovery = True 574 elif o == '--allow-duplicate-apkapex-keys': 575 OPTIONS.allow_duplicate_apkapex_keys = True 576 elif o == '--vendor-otatools': 577 OPTIONS.vendor_otatools = a 578 elif o == '--rebuild-sepolicy': 579 OPTIONS.rebuild_sepolicy = True 580 elif o == '--keep-tmp': 581 OPTIONS.keep_tmp = True 582 elif o == '--avb-resolve-rollback-index-location-conflict': 583 OPTIONS.avb_resolve_rollback_index_location_conflict = True 584 elif o == '--allow-partial-ab': 585 OPTIONS.allow_partial_ab = True 586 elif o == '--framework-dexpreopt-config': 587 OPTIONS.framework_dexpreopt_config = a 588 elif o == '--framework-dexpreopt-tools': 589 OPTIONS.framework_dexpreopt_tools = a 590 elif o == '--vendor-dexpreopt-config': 591 OPTIONS.vendor_dexpreopt_config = a 592 else: 593 return False 594 return True 595 596 args = common.ParseOptions( 597 sys.argv[1:], 598 __doc__, 599 extra_long_opts=[ 600 'system-target-files=', 601 'framework-target-files=', 602 'system-item-list=', 603 'framework-item-list=', 604 'system-misc-info-keys=', 605 'framework-misc-info-keys=', 606 'other-target-files=', 607 'vendor-target-files=', 608 'other-item-list=', 609 'vendor-item-list=', 610 'boot-image-dir-path=', 611 'output-target-files=', 612 'output-dir=', 613 'output-item-list=', 614 'output-ota=', 615 'output-img=', 616 'output-super-empty=', 617 'framework-dexpreopt-config=', 618 'framework-dexpreopt-tools=', 619 'vendor-dexpreopt-config=', 620 'rebuild_recovery', 621 'rebuild-recovery', 622 'allow-duplicate-apkapex-keys', 623 'vendor-otatools=', 624 'rebuild-sepolicy', 625 'keep-tmp', 626 'avb-resolve-rollback-index-location-conflict', 627 'allow-partial-ab', 628 ], 629 extra_option_handler=option_handler) 630 631 # pylint: disable=too-many-boolean-expressions 632 if (args or OPTIONS.framework_target_files is None or 633 OPTIONS.vendor_target_files is None or 634 (OPTIONS.output_target_files is None and OPTIONS.output_dir is None) or 635 (OPTIONS.output_dir is not None and not OPTIONS.output_item_list) or 636 (OPTIONS.rebuild_recovery and not OPTIONS.rebuild_sepolicy)): 637 common.Usage(__doc__) 638 sys.exit(1) 639 640 framework_namelist = merge_utils.GetTargetFilesItems( 641 OPTIONS.framework_target_files) 642 vendor_namelist = merge_utils.GetTargetFilesItems( 643 OPTIONS.vendor_target_files) 644 645 if OPTIONS.framework_item_list: 646 OPTIONS.framework_item_list = common.LoadListFromFile( 647 OPTIONS.framework_item_list) 648 else: 649 OPTIONS.framework_item_list = merge_utils.InferItemList( 650 input_namelist=framework_namelist, framework=True) 651 OPTIONS.framework_partition_set = merge_utils.ItemListToPartitionSet( 652 OPTIONS.framework_item_list) 653 654 if OPTIONS.framework_misc_info_keys: 655 OPTIONS.framework_misc_info_keys = common.LoadListFromFile( 656 OPTIONS.framework_misc_info_keys) 657 else: 658 OPTIONS.framework_misc_info_keys = merge_utils.InferFrameworkMiscInfoKeys( 659 input_namelist=framework_namelist) 660 661 if OPTIONS.vendor_item_list: 662 OPTIONS.vendor_item_list = common.LoadListFromFile(OPTIONS.vendor_item_list) 663 else: 664 OPTIONS.vendor_item_list = merge_utils.InferItemList( 665 input_namelist=vendor_namelist, framework=False) 666 OPTIONS.vendor_partition_set = merge_utils.ItemListToPartitionSet( 667 OPTIONS.vendor_item_list) 668 669 if OPTIONS.output_item_list: 670 OPTIONS.output_item_list = common.LoadListFromFile(OPTIONS.output_item_list) 671 672 if not merge_utils.ValidateConfigLists(): 673 sys.exit(1) 674 675 temp_dir = common.MakeTempDir(prefix='merge_target_files_') 676 try: 677 merge_target_files(temp_dir) 678 finally: 679 if OPTIONS.keep_tmp: 680 logger.info('Keeping temp_dir %s', temp_dir) 681 else: 682 common.Cleanup() 683 684 685if __name__ == '__main__': 686 main() 687