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 or directory 91 If provided, use these otatools 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 target-files archive. 316 vendor_target_files_dir = common.MakeTempDir( 317 prefix='merge_target_files_vendor_target_files_') 318 merge_utils.CollectTargetFiles( 319 input_zipfile_or_dir=OPTIONS.vendor_target_files, 320 output_dir=vendor_target_files_dir, 321 item_list=include_extra_in_list(OPTIONS.vendor_item_list)) 322 323 # Copy the partition contents from the merged target-files archive to the 324 # vendor target-files archive. 325 shutil.rmtree(os.path.join(vendor_target_files_dir, partition.upper())) 326 shutil.copytree( 327 os.path.join(target_files_dir, partition.upper()), 328 os.path.join(vendor_target_files_dir, partition.upper()), 329 symlinks=True) 330 331 # Delete then rebuild the partition. 332 remove_file_if_exists( 333 os.path.join(vendor_target_files_dir, 'IMAGES', partition_img)) 334 rebuild_partition_command = [ 335 os.path.join(OPTIONS.vendor_otatools, 'bin', 'add_img_to_target_files'), 336 '--verbose', 337 '--add_missing', 338 ] 339 if OPTIONS.rebuild_recovery: 340 rebuild_partition_command.append('--rebuild_recovery') 341 rebuild_partition_command.append(vendor_target_files_dir) 342 logger.info('Recompiling %s: %s', partition_img, 343 ' '.join(rebuild_partition_command)) 344 common.RunAndCheckOutput(rebuild_partition_command, verbose=True) 345 346 # Move the newly-created image to the merged target files dir. 347 if not os.path.exists(os.path.join(target_files_dir, 'IMAGES')): 348 os.makedirs(os.path.join(target_files_dir, 'IMAGES')) 349 shutil.move( 350 os.path.join(vendor_target_files_dir, 'IMAGES', partition_img), 351 os.path.join(target_files_dir, 'IMAGES', partition_img)) 352 move_only_exists( 353 os.path.join(vendor_target_files_dir, 'IMAGES', partition_map), 354 os.path.join(target_files_dir, 'IMAGES', partition_map)) 355 356 def copy_recovery_file(filename): 357 for subdir in ('VENDOR', 'SYSTEM/vendor'): 358 source = os.path.join(vendor_target_files_dir, subdir, filename) 359 if os.path.exists(source): 360 dest = os.path.join(target_files_dir, subdir, filename) 361 shutil.copy(source, dest) 362 return 363 logger.info('Skipping copy_recovery_file for %s, file not found', filename) 364 365 if OPTIONS.rebuild_recovery: 366 copy_recovery_file('etc/recovery.img') 367 copy_recovery_file('bin/install-recovery.sh') 368 copy_recovery_file('recovery-from-boot.p') 369 370 371def generate_super_empty_image(target_dir, output_super_empty): 372 """Generates super_empty image from target package. 373 374 Args: 375 target_dir: Path to the target file package which contains misc_info.txt for 376 detailed information for super image. 377 output_super_empty: If provided, copies a super_empty.img file from the 378 target files package to this path. 379 """ 380 # Create super_empty.img using the merged misc_info.txt. 381 382 misc_info_txt = os.path.join(target_dir, 'META', 'misc_info.txt') 383 384 use_dynamic_partitions = common.LoadDictionaryFromFile(misc_info_txt).get( 385 'use_dynamic_partitions') 386 387 if use_dynamic_partitions != 'true' and output_super_empty: 388 raise ValueError( 389 'Building super_empty.img requires use_dynamic_partitions=true.') 390 elif use_dynamic_partitions == 'true': 391 super_empty_img = os.path.join(target_dir, 'IMAGES', 'super_empty.img') 392 build_super_image_args = [ 393 misc_info_txt, 394 super_empty_img, 395 ] 396 build_super_image.main(build_super_image_args) 397 398 # Copy super_empty.img to the user-provided output_super_empty location. 399 if output_super_empty: 400 shutil.copyfile(super_empty_img, output_super_empty) 401 402 403def create_target_files_archive(output_zip, source_dir, temp_dir): 404 """Creates a target_files zip archive from the input source dir. 405 406 Args: 407 output_zip: The name of the zip archive target files package. 408 source_dir: The target directory contains package to be archived. 409 temp_dir: Path to temporary directory for any intermediate files. 410 """ 411 output_target_files_list = os.path.join(temp_dir, 'output.list') 412 output_target_files_meta_dir = os.path.join(source_dir, 'META') 413 414 def files_from_path(target_path, extra_args=None): 415 """Gets files under the given path and return a sorted list.""" 416 find_command = ['find', target_path] + (extra_args or []) 417 find_process = common.Run( 418 find_command, stdout=subprocess.PIPE, verbose=False) 419 return common.RunAndCheckOutput(['sort'], 420 stdin=find_process.stdout, 421 verbose=False) 422 423 # META content appears first in the zip. This is done by the 424 # standard build system for optimized extraction of those files, 425 # so we do the same step for merged target_files.zips here too. 426 meta_content = files_from_path(output_target_files_meta_dir) 427 other_content = files_from_path( 428 source_dir, 429 ['-path', output_target_files_meta_dir, '-prune', '-o', '-print']) 430 431 with open(output_target_files_list, 'w') as f: 432 f.write(meta_content) 433 f.write(other_content) 434 435 command = [ 436 'soong_zip', 437 '-d', 438 '-o', 439 os.path.abspath(output_zip), 440 '-C', 441 source_dir, 442 '-r', 443 output_target_files_list, 444 ] 445 446 logger.info('creating %s', output_zip) 447 common.RunAndCheckOutput(command, verbose=True) 448 logger.info('finished creating %s', output_zip) 449 450 451def merge_target_files(temp_dir): 452 """Merges two target files packages together. 453 454 This function uses framework and vendor target files packages as input, 455 performs various file extractions, special case processing, and finally 456 creates a merged zip archive as output. 457 458 Args: 459 temp_dir: The name of a directory we use when we extract items from the 460 input target files packages, and also a scratch directory that we use for 461 temporary files. 462 """ 463 464 logger.info('starting: merge framework %s and vendor %s into output %s', 465 OPTIONS.framework_target_files, OPTIONS.vendor_target_files, 466 OPTIONS.output_target_files) 467 468 output_target_files_temp_dir = create_merged_package(temp_dir) 469 470 partition_map = common.PartitionMapFromTargetFiles( 471 output_target_files_temp_dir) 472 473 compatibility_errors = merge_compatibility_checks.CheckCompatibility( 474 target_files_dir=output_target_files_temp_dir, 475 partition_map=partition_map) 476 if compatibility_errors: 477 for error in compatibility_errors: 478 logger.error(error) 479 raise ExternalError( 480 'Found incompatibilities in the merged target files package.') 481 482 # Include the compiled policy in an image if requested. 483 if OPTIONS.rebuild_sepolicy: 484 rebuild_image_with_sepolicy(output_target_files_temp_dir) 485 486 generate_missing_images(output_target_files_temp_dir) 487 488 generate_super_empty_image(output_target_files_temp_dir, 489 OPTIONS.output_super_empty) 490 491 # Finally, create the output target files zip archive and/or copy the 492 # output items to the output target files directory. 493 494 if OPTIONS.output_dir: 495 merge_utils.CopyItems(output_target_files_temp_dir, OPTIONS.output_dir, 496 OPTIONS.output_item_list) 497 498 if not OPTIONS.output_target_files: 499 return 500 501 create_target_files_archive(OPTIONS.output_target_files, 502 output_target_files_temp_dir, temp_dir) 503 504 # Create the IMG package from the merged target files package. 505 if OPTIONS.output_img: 506 img_from_target_files.main( 507 [OPTIONS.output_target_files, OPTIONS.output_img]) 508 509 # Create the OTA package from the merged target files package. 510 511 if OPTIONS.output_ota: 512 ota_from_target_files.main( 513 [OPTIONS.output_target_files, OPTIONS.output_ota]) 514 515 516def main(): 517 """The main function. 518 519 Process command line arguments, then call merge_target_files to 520 perform the heavy lifting. 521 """ 522 523 common.InitLogging() 524 525 def option_handler(o, a): 526 if o == '--system-target-files': 527 logger.warning( 528 '--system-target-files has been renamed to --framework-target-files') 529 OPTIONS.framework_target_files = a 530 elif o == '--framework-target-files': 531 OPTIONS.framework_target_files = a 532 elif o == '--system-item-list': 533 logger.warning( 534 '--system-item-list has been renamed to --framework-item-list') 535 OPTIONS.framework_item_list = a 536 elif o == '--framework-item-list': 537 OPTIONS.framework_item_list = a 538 elif o == '--system-misc-info-keys': 539 logger.warning('--system-misc-info-keys has been renamed to ' 540 '--framework-misc-info-keys') 541 OPTIONS.framework_misc_info_keys = a 542 elif o == '--framework-misc-info-keys': 543 OPTIONS.framework_misc_info_keys = a 544 elif o == '--other-target-files': 545 logger.warning( 546 '--other-target-files has been renamed to --vendor-target-files') 547 OPTIONS.vendor_target_files = a 548 elif o == '--vendor-target-files': 549 OPTIONS.vendor_target_files = a 550 elif o == '--other-item-list': 551 logger.warning('--other-item-list has been renamed to --vendor-item-list') 552 OPTIONS.vendor_item_list = a 553 elif o == '--vendor-item-list': 554 OPTIONS.vendor_item_list = a 555 elif o == '--boot-image-dir-path': 556 OPTIONS.boot_image_dir_path = a 557 elif o == '--output-target-files': 558 OPTIONS.output_target_files = a 559 elif o == '--output-dir': 560 OPTIONS.output_dir = a 561 elif o == '--output-item-list': 562 OPTIONS.output_item_list = a 563 elif o == '--output-ota': 564 OPTIONS.output_ota = a 565 elif o == '--output-img': 566 OPTIONS.output_img = a 567 elif o == '--output-super-empty': 568 OPTIONS.output_super_empty = a 569 elif o == '--rebuild_recovery' or o == '--rebuild-recovery': 570 OPTIONS.rebuild_recovery = True 571 elif o == '--allow-duplicate-apkapex-keys': 572 OPTIONS.allow_duplicate_apkapex_keys = True 573 elif o == '--vendor-otatools': 574 OPTIONS.vendor_otatools = a 575 elif o == '--rebuild-sepolicy': 576 OPTIONS.rebuild_sepolicy = True 577 elif o == '--keep-tmp': 578 OPTIONS.keep_tmp = True 579 elif o == '--avb-resolve-rollback-index-location-conflict': 580 OPTIONS.avb_resolve_rollback_index_location_conflict = True 581 elif o == '--allow-partial-ab': 582 OPTIONS.allow_partial_ab = True 583 elif o == '--framework-dexpreopt-config': 584 OPTIONS.framework_dexpreopt_config = a 585 elif o == '--framework-dexpreopt-tools': 586 OPTIONS.framework_dexpreopt_tools = a 587 elif o == '--vendor-dexpreopt-config': 588 OPTIONS.vendor_dexpreopt_config = a 589 else: 590 return False 591 return True 592 593 args = common.ParseOptions( 594 sys.argv[1:], 595 __doc__, 596 extra_long_opts=[ 597 'system-target-files=', 598 'framework-target-files=', 599 'system-item-list=', 600 'framework-item-list=', 601 'system-misc-info-keys=', 602 'framework-misc-info-keys=', 603 'other-target-files=', 604 'vendor-target-files=', 605 'other-item-list=', 606 'vendor-item-list=', 607 'boot-image-dir-path=', 608 'output-target-files=', 609 'output-dir=', 610 'output-item-list=', 611 'output-ota=', 612 'output-img=', 613 'output-super-empty=', 614 'framework-dexpreopt-config=', 615 'framework-dexpreopt-tools=', 616 'vendor-dexpreopt-config=', 617 'rebuild_recovery', 618 'rebuild-recovery', 619 'allow-duplicate-apkapex-keys', 620 'vendor-otatools=', 621 'rebuild-sepolicy', 622 'keep-tmp', 623 'avb-resolve-rollback-index-location-conflict', 624 'allow-partial-ab', 625 ], 626 extra_option_handler=option_handler) 627 628 # pylint: disable=too-many-boolean-expressions 629 if (args or OPTIONS.framework_target_files is None or 630 OPTIONS.vendor_target_files is None or 631 (OPTIONS.output_target_files is None and OPTIONS.output_dir is None) or 632 (OPTIONS.output_dir is not None and not OPTIONS.output_item_list) or 633 (OPTIONS.rebuild_recovery and not OPTIONS.rebuild_sepolicy)): 634 common.Usage(__doc__) 635 sys.exit(1) 636 637 framework_namelist = merge_utils.GetTargetFilesItems( 638 OPTIONS.framework_target_files) 639 vendor_namelist = merge_utils.GetTargetFilesItems( 640 OPTIONS.vendor_target_files) 641 642 if OPTIONS.framework_item_list: 643 OPTIONS.framework_item_list = common.LoadListFromFile( 644 OPTIONS.framework_item_list) 645 else: 646 OPTIONS.framework_item_list = merge_utils.InferItemList( 647 input_namelist=framework_namelist, framework=True) 648 OPTIONS.framework_partition_set = merge_utils.ItemListToPartitionSet( 649 OPTIONS.framework_item_list) 650 651 if OPTIONS.framework_misc_info_keys: 652 OPTIONS.framework_misc_info_keys = common.LoadListFromFile( 653 OPTIONS.framework_misc_info_keys) 654 else: 655 OPTIONS.framework_misc_info_keys = merge_utils.InferFrameworkMiscInfoKeys( 656 input_namelist=framework_namelist) 657 658 if OPTIONS.vendor_item_list: 659 OPTIONS.vendor_item_list = common.LoadListFromFile(OPTIONS.vendor_item_list) 660 else: 661 OPTIONS.vendor_item_list = merge_utils.InferItemList( 662 input_namelist=vendor_namelist, framework=False) 663 OPTIONS.vendor_partition_set = merge_utils.ItemListToPartitionSet( 664 OPTIONS.vendor_item_list) 665 666 if OPTIONS.output_item_list: 667 OPTIONS.output_item_list = common.LoadListFromFile(OPTIONS.output_item_list) 668 669 if OPTIONS.vendor_otatools and zipfile.is_zipfile(OPTIONS.vendor_otatools): 670 vendor_otatools_dir = common.MakeTempDir( 671 prefix='merge_target_files_vendor_otatools_') 672 common.UnzipToDir(OPTIONS.vendor_otatools, vendor_otatools_dir) 673 OPTIONS.vendor_otatools = vendor_otatools_dir 674 675 if not merge_utils.ValidateConfigLists(): 676 sys.exit(1) 677 678 temp_dir = common.MakeTempDir(prefix='merge_target_files_') 679 try: 680 merge_target_files(temp_dir) 681 finally: 682 if OPTIONS.keep_tmp: 683 logger.info('Keeping temp_dir %s', temp_dir) 684 else: 685 common.Cleanup() 686 687 688if __name__ == '__main__': 689 main() 690