1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3# Copyright 2019 The ChromiumOS Authors 4# Use of this source code is governed by a BSD-style license that can be 5# found in the LICENSE file. 6 7"""Updates the LLVM hash and uprevs the build of the specified packages. 8 9For each package, a temporary repo is created and the changes are uploaded 10for review. 11""" 12 13import argparse 14import datetime 15import enum 16import os 17from pathlib import Path 18import re 19import subprocess 20from typing import Dict, Iterable 21 22import chroot 23import failure_modes 24import get_llvm_hash 25import git 26import patch_utils 27import subprocess_helpers 28 29 30DEFAULT_PACKAGES = [ 31 "dev-util/lldb-server", 32 "sys-devel/llvm", 33 "sys-libs/compiler-rt", 34 "sys-libs/libcxx", 35 "sys-libs/llvm-libunwind", 36] 37 38DEFAULT_MANIFEST_PACKAGES = ["sys-devel/llvm"] 39 40 41# Specify which LLVM hash to update 42class LLVMVariant(enum.Enum): 43 """Represent the LLVM hash in an ebuild file to update.""" 44 45 current = "LLVM_HASH" 46 next = "LLVM_NEXT_HASH" 47 48 49# If set to `True`, then the contents of `stdout` after executing a command will 50# be displayed to the terminal. 51verbose = False 52 53 54def defaultCrosRoot() -> Path: 55 """Get default location of chroot_path. 56 57 The logic assumes that the cros_root is ~/chromiumos, unless llvm_tools is 58 inside of a CrOS checkout, in which case that checkout should be used. 59 60 Returns: 61 The best guess location for the cros checkout. 62 """ 63 llvm_tools_path = os.path.realpath(os.path.dirname(__file__)) 64 if llvm_tools_path.endswith("src/third_party/toolchain-utils/llvm_tools"): 65 return Path(llvm_tools_path).parent.parent.parent.parent 66 return Path.home() / "chromiumos" 67 68 69def GetCommandLineArgs(): 70 """Parses the command line for the optional command line arguments. 71 72 Returns: 73 The log level to use when retrieving the LLVM hash or google3 LLVM version, 74 the chroot path to use for executing chroot commands, 75 a list of a package or packages to update their LLVM next hash, 76 and the LLVM version to use when retrieving the LLVM hash. 77 """ 78 79 # Create parser and add optional command-line arguments. 80 parser = argparse.ArgumentParser( 81 description="Updates the build's hash for llvm-next." 82 ) 83 84 # Add argument for a specific chroot path. 85 parser.add_argument( 86 "--chroot_path", 87 type=Path, 88 default=defaultCrosRoot(), 89 help="the path to the chroot (default: %(default)s)", 90 ) 91 92 # Add argument for specific builds to uprev and update their llvm-next hash. 93 parser.add_argument( 94 "--update_packages", 95 default=",".join(DEFAULT_PACKAGES), 96 help="Comma-separated ebuilds to update llvm-next hash for " 97 "(default: %(default)s)", 98 ) 99 100 parser.add_argument( 101 "--manifest_packages", 102 default="", 103 help="Comma-separated ebuilds to update manifests for " 104 "(default: %(default)s)", 105 ) 106 107 # Add argument for whether to display command contents to `stdout`. 108 parser.add_argument( 109 "--verbose", 110 action="store_true", 111 help="display contents of a command to the terminal " 112 "(default: %(default)s)", 113 ) 114 115 # Add argument for the LLVM hash to update 116 parser.add_argument( 117 "--is_llvm_next", 118 action="store_true", 119 help="which llvm hash to update. If specified, update LLVM_NEXT_HASH. " 120 "Otherwise, update LLVM_HASH", 121 ) 122 123 # Add argument for the LLVM version to use. 124 parser.add_argument( 125 "--llvm_version", 126 type=get_llvm_hash.IsSvnOption, 127 required=True, 128 help="which git hash to use. Either a svn revision, or one " 129 f"of {sorted(get_llvm_hash.KNOWN_HASH_SOURCES)}", 130 ) 131 132 # Add argument for the mode of the patch management when handling patches. 133 parser.add_argument( 134 "--failure_mode", 135 default=failure_modes.FailureModes.FAIL.value, 136 choices=[ 137 failure_modes.FailureModes.FAIL.value, 138 failure_modes.FailureModes.CONTINUE.value, 139 failure_modes.FailureModes.DISABLE_PATCHES.value, 140 failure_modes.FailureModes.REMOVE_PATCHES.value, 141 ], 142 help="the mode of the patch manager when handling failed patches " 143 "(default: %(default)s)", 144 ) 145 146 # Add argument for the patch metadata file. 147 parser.add_argument( 148 "--patch_metadata_file", 149 default="PATCHES.json", 150 help="the .json file that has all the patches and their " 151 "metadata if applicable (default: PATCHES.json inside $FILESDIR)", 152 ) 153 154 # Parse the command line. 155 args_output = parser.parse_args() 156 157 # FIXME: We shouldn't be using globals here, but until we fix it, make pylint 158 # stop complaining about it. 159 # pylint: disable=global-statement 160 global verbose 161 162 verbose = args_output.verbose 163 164 return args_output 165 166 167def GetEbuildPathsFromSymLinkPaths(symlinks): 168 """Reads the symlink(s) to get the ebuild path(s) to the package(s). 169 170 Args: 171 symlinks: A list of absolute path symlink/symlinks that point 172 to the package's ebuild. 173 174 Returns: 175 A dictionary where the key is the absolute path of the symlink and the value 176 is the absolute path to the ebuild that was read from the symlink. 177 178 Raises: 179 ValueError: Invalid symlink(s) were provided. 180 """ 181 182 # A dictionary that holds: 183 # key: absolute symlink path 184 # value: absolute ebuild path 185 resolved_paths = {} 186 187 # Iterate through each symlink. 188 # 189 # For each symlink, check that it is a valid symlink, 190 # and then construct the ebuild path, and 191 # then add the ebuild path to the dict. 192 for cur_symlink in symlinks: 193 if not os.path.islink(cur_symlink): 194 raise ValueError(f"Invalid symlink provided: {cur_symlink}") 195 196 # Construct the absolute path to the ebuild. 197 ebuild_path = os.path.realpath(cur_symlink) 198 199 if cur_symlink not in resolved_paths: 200 resolved_paths[cur_symlink] = ebuild_path 201 202 return resolved_paths 203 204 205def UpdateEbuildLLVMHash(ebuild_path, llvm_variant, git_hash, svn_version): 206 """Updates the LLVM hash in the ebuild. 207 208 The build changes are staged for commit in the temporary repo. 209 210 Args: 211 ebuild_path: The absolute path to the ebuild. 212 llvm_variant: Which LLVM hash to update. 213 git_hash: The new git hash. 214 svn_version: The SVN-style revision number of git_hash. 215 216 Raises: 217 ValueError: Invalid ebuild path provided or failed to stage the commit 218 of the changes or failed to update the LLVM hash. 219 """ 220 221 # Iterate through each ebuild. 222 # 223 # For each ebuild, read the file in 224 # advance and then create a temporary file 225 # that gets updated with the new LLVM hash 226 # and revision number and then the ebuild file 227 # gets updated to the temporary file. 228 229 if not os.path.isfile(ebuild_path): 230 raise ValueError(f"Invalid ebuild path provided: {ebuild_path}") 231 232 temp_ebuild_file = f"{ebuild_path}.temp" 233 234 with open(ebuild_path) as ebuild_file: 235 # write updates to a temporary file in case of interrupts 236 with open(temp_ebuild_file, "w") as temp_file: 237 for cur_line in ReplaceLLVMHash( 238 ebuild_file, llvm_variant, git_hash, svn_version 239 ): 240 temp_file.write(cur_line) 241 os.rename(temp_ebuild_file, ebuild_path) 242 243 # Get the path to the parent directory. 244 parent_dir = os.path.dirname(ebuild_path) 245 246 # Stage the changes. 247 subprocess.check_output(["git", "-C", parent_dir, "add", ebuild_path]) 248 249 250def ReplaceLLVMHash(ebuild_lines, llvm_variant, git_hash, svn_version): 251 """Updates the LLVM git hash. 252 253 Args: 254 ebuild_lines: The contents of the ebuild file. 255 llvm_variant: The LLVM hash to update. 256 git_hash: The new git hash. 257 svn_version: The SVN-style revision number of git_hash. 258 259 Yields: 260 lines of the modified ebuild file 261 """ 262 is_updated = False 263 llvm_regex = re.compile( 264 "^" + re.escape(llvm_variant.value) + '="[a-z0-9]+"' 265 ) 266 for cur_line in ebuild_lines: 267 if not is_updated and llvm_regex.search(cur_line): 268 # Update the git hash and revision number. 269 cur_line = f'{llvm_variant.value}="{git_hash}" # r{svn_version}\n' 270 271 is_updated = True 272 273 yield cur_line 274 275 if not is_updated: 276 raise ValueError(f"Failed to update {llvm_variant.value}") 277 278 279def UprevEbuildSymlink(symlink): 280 """Uprevs the symlink's revision number. 281 282 Increases the revision number by 1 and stages the change in 283 the temporary repo. 284 285 Args: 286 symlink: The absolute path of an ebuild symlink. 287 288 Raises: 289 ValueError: Failed to uprev the symlink or failed to stage the changes. 290 """ 291 292 if not os.path.islink(symlink): 293 raise ValueError(f"Invalid symlink provided: {symlink}") 294 295 new_symlink, is_changed = re.subn( 296 r"r([0-9]+).ebuild", 297 lambda match: "r%s.ebuild" % str(int(match.group(1)) + 1), 298 symlink, 299 count=1, 300 ) 301 302 if not is_changed: 303 raise ValueError("Failed to uprev the symlink.") 304 305 # rename the symlink 306 subprocess.check_output( 307 ["git", "-C", os.path.dirname(symlink), "mv", symlink, new_symlink] 308 ) 309 310 311def UprevEbuildToVersion(symlink, svn_version, git_hash): 312 """Uprevs the ebuild's revision number. 313 314 Increases the revision number by 1 and stages the change in 315 the temporary repo. 316 317 Args: 318 symlink: The absolute path of an ebuild symlink. 319 svn_version: The SVN-style revision number of git_hash. 320 git_hash: The new git hash. 321 322 Raises: 323 ValueError: Failed to uprev the ebuild or failed to stage the changes. 324 AssertionError: No llvm version provided for an LLVM uprev 325 """ 326 327 if not os.path.islink(symlink): 328 raise ValueError(f"Invalid symlink provided: {symlink}") 329 330 ebuild = os.path.realpath(symlink) 331 llvm_major_version = get_llvm_hash.GetLLVMMajorVersion(git_hash) 332 # llvm 333 package = os.path.basename(os.path.dirname(symlink)) 334 if not package: 335 raise ValueError("Tried to uprev an unknown package") 336 if package == "llvm": 337 new_ebuild, is_changed = re.subn( 338 r"(\d+)\.(\d+)_pre([0-9]+)_p([0-9]+)", 339 "%s.\\2_pre%s_p%s" 340 % ( 341 llvm_major_version, 342 svn_version, 343 datetime.datetime.today().strftime("%Y%m%d"), 344 ), 345 ebuild, 346 count=1, 347 ) 348 # any other package 349 else: 350 new_ebuild, is_changed = re.subn( 351 r"(\d+)\.(\d+)_pre([0-9]+)", 352 "%s.\\2_pre%s" % (llvm_major_version, svn_version), 353 ebuild, 354 count=1, 355 ) 356 357 if not is_changed: # failed to increment the revision number 358 raise ValueError("Failed to uprev the ebuild.") 359 360 symlink_dir = os.path.dirname(symlink) 361 362 # Rename the ebuild 363 subprocess.check_output( 364 ["git", "-C", symlink_dir, "mv", ebuild, new_ebuild] 365 ) 366 367 # Create a symlink of the renamed ebuild 368 new_symlink = new_ebuild[: -len(".ebuild")] + "-r1.ebuild" 369 subprocess.check_output(["ln", "-s", "-r", new_ebuild, new_symlink]) 370 371 if not os.path.islink(new_symlink): 372 raise ValueError( 373 f'Invalid symlink name: {new_ebuild[:-len(".ebuild")]}' 374 ) 375 376 subprocess.check_output(["git", "-C", symlink_dir, "add", new_symlink]) 377 378 # Remove the old symlink 379 subprocess.check_output(["git", "-C", symlink_dir, "rm", symlink]) 380 381 382def CreatePathDictionaryFromPackages(chroot_path, update_packages): 383 """Creates a symlink and ebuild path pair dictionary from the packages. 384 385 Args: 386 chroot_path: The absolute path to the chroot. 387 update_packages: The filtered packages to be updated. 388 389 Returns: 390 A dictionary where the key is the absolute path to the symlink 391 of the package and the value is the absolute path to the ebuild of 392 the package. 393 """ 394 395 # Construct a list containing the chroot file paths of the package(s). 396 chroot_file_paths = chroot.GetChrootEbuildPaths( 397 chroot_path, update_packages 398 ) 399 400 # Construct a list containing the symlink(s) of the package(s). 401 symlink_file_paths = chroot.ConvertChrootPathsToAbsolutePaths( 402 chroot_path, chroot_file_paths 403 ) 404 405 # Create a dictionary where the key is the absolute path of the symlink to 406 # the package and the value is the absolute path to the ebuild of the package. 407 return GetEbuildPathsFromSymLinkPaths(symlink_file_paths) 408 409 410def RemovePatchesFromFilesDir(patches): 411 """Removes the patches from $FILESDIR of a package. 412 413 Args: 414 patches: A list of absolute paths of patches to remove 415 416 Raises: 417 ValueError: Failed to remove a patch in $FILESDIR. 418 """ 419 420 for patch in patches: 421 subprocess.check_output( 422 ["git", "-C", os.path.dirname(patch), "rm", "-f", patch] 423 ) 424 425 426def StagePatchMetadataFileForCommit(patch_metadata_file_path): 427 """Stages the updated patch metadata file for commit. 428 429 Args: 430 patch_metadata_file_path: The absolute path to the patch metadata file. 431 432 Raises: 433 ValueError: Failed to stage the patch metadata file for commit or invalid 434 patch metadata file. 435 """ 436 437 if not os.path.isfile(patch_metadata_file_path): 438 raise ValueError( 439 f"Invalid patch metadata file provided: {patch_metadata_file_path}" 440 ) 441 442 # Cmd to stage the patch metadata file for commit. 443 subprocess.check_output( 444 [ 445 "git", 446 "-C", 447 os.path.dirname(patch_metadata_file_path), 448 "add", 449 patch_metadata_file_path, 450 ] 451 ) 452 453 454def StagePackagesPatchResultsForCommit(package_info_dict, commit_messages): 455 """Stages the patch results of the packages to the commit message. 456 457 Args: 458 package_info_dict: A dictionary where the key is the package name and the 459 value is a dictionary that contains information about the patches of the 460 package (key). 461 commit_messages: The commit message that has the updated ebuilds and 462 upreving information. 463 464 Returns: 465 commit_messages with new additions 466 """ 467 468 # For each package, check if any patches for that package have 469 # changed, if so, add which patches have changed to the commit 470 # message. 471 for package_name, patch_info_dict in package_info_dict.items(): 472 if ( 473 patch_info_dict["disabled_patches"] 474 or patch_info_dict["removed_patches"] 475 or patch_info_dict["modified_metadata"] 476 ): 477 cur_package_header = f"\nFor the package {package_name}:" 478 commit_messages.append(cur_package_header) 479 480 # Add to the commit message that the patch metadata file was modified. 481 if patch_info_dict["modified_metadata"]: 482 patch_metadata_path = patch_info_dict["modified_metadata"] 483 metadata_file_name = os.path.basename(patch_metadata_path) 484 commit_messages.append( 485 f"The patch metadata file {metadata_file_name} was modified" 486 ) 487 488 StagePatchMetadataFileForCommit(patch_metadata_path) 489 490 # Add each disabled patch to the commit message. 491 if patch_info_dict["disabled_patches"]: 492 commit_messages.append("The following patches were disabled:") 493 494 for patch_path in patch_info_dict["disabled_patches"]: 495 commit_messages.append(os.path.basename(patch_path)) 496 497 # Add each removed patch to the commit message. 498 if patch_info_dict["removed_patches"]: 499 commit_messages.append("The following patches were removed:") 500 501 for patch_path in patch_info_dict["removed_patches"]: 502 commit_messages.append(os.path.basename(patch_path)) 503 504 RemovePatchesFromFilesDir(patch_info_dict["removed_patches"]) 505 506 return commit_messages 507 508 509def UpdateManifests(packages: Iterable[str], chroot_path: Path): 510 """Updates manifest files for packages. 511 512 Args: 513 packages: A list of packages to update manifests for. 514 chroot_path: The absolute path to the chroot. 515 516 Raises: 517 CalledProcessError: ebuild failed to update manifest. 518 """ 519 manifest_ebuilds = chroot.GetChrootEbuildPaths(chroot_path, packages) 520 for ebuild_path in manifest_ebuilds: 521 subprocess_helpers.ChrootRunCommand( 522 chroot_path, ["ebuild", ebuild_path, "manifest"] 523 ) 524 525 526def UpdatePackages( 527 packages: Iterable[str], 528 manifest_packages: Iterable[str], 529 llvm_variant, 530 git_hash, 531 svn_version, 532 chroot_path: Path, 533 mode, 534 git_hash_source, 535 extra_commit_msg, 536): 537 """Updates an LLVM hash and uprevs the ebuild of the packages. 538 539 A temporary repo is created for the changes. The changes are 540 then uploaded for review. 541 542 Args: 543 packages: A list of all the packages that are going to be updated. 544 manifest_packages: A list of packages to update manifests for. 545 llvm_variant: The LLVM hash to update. 546 git_hash: The new git hash. 547 svn_version: The SVN-style revision number of git_hash. 548 chroot_path: The absolute path to the chroot. 549 mode: The mode of the patch manager when handling an applicable patch 550 that failed to apply. 551 Ex. 'FailureModes.FAIL' 552 git_hash_source: The source of which git hash to use based off of. 553 Ex. 'google3', 'tot', or <version> such as 365123 554 extra_commit_msg: extra test to append to the commit message. 555 556 Returns: 557 A nametuple that has two (key, value) pairs, where the first pair is the 558 Gerrit commit URL and the second pair is the change list number. 559 """ 560 561 # Construct a dictionary where the key is the absolute path of the symlink to 562 # the package and the value is the absolute path to the ebuild of the package. 563 paths_dict = CreatePathDictionaryFromPackages(chroot_path, packages) 564 565 repo_path = os.path.dirname(next(iter(paths_dict.values()))) 566 567 branch = "update-" + llvm_variant.value + "-" + git_hash 568 569 git.CreateBranch(repo_path, branch) 570 571 try: 572 commit_message_header = "llvm" 573 if llvm_variant == LLVMVariant.next: 574 commit_message_header = "llvm-next" 575 if git_hash_source in get_llvm_hash.KNOWN_HASH_SOURCES: 576 commit_message_header += ( 577 f"/{git_hash_source}: upgrade to {git_hash} (r{svn_version})" 578 ) 579 else: 580 commit_message_header += f": upgrade to {git_hash} (r{svn_version})" 581 582 commit_lines = [ 583 commit_message_header + "\n", 584 "The following packages have been updated:", 585 ] 586 587 # Holds the list of packages that are updating. 588 packages = [] 589 590 # Iterate through the dictionary. 591 # 592 # For each iteration: 593 # 1) Update the ebuild's LLVM hash. 594 # 2) Uprev the ebuild (symlink). 595 # 3) Add the modified package to the commit message. 596 for symlink_path, ebuild_path in paths_dict.items(): 597 path_to_ebuild_dir = os.path.dirname(ebuild_path) 598 599 UpdateEbuildLLVMHash( 600 ebuild_path, llvm_variant, git_hash, svn_version 601 ) 602 603 if llvm_variant == LLVMVariant.current: 604 UprevEbuildToVersion(symlink_path, svn_version, git_hash) 605 else: 606 UprevEbuildSymlink(symlink_path) 607 608 cur_dir_name = os.path.basename(path_to_ebuild_dir) 609 parent_dir_name = os.path.basename( 610 os.path.dirname(path_to_ebuild_dir) 611 ) 612 613 packages.append(f"{parent_dir_name}/{cur_dir_name}") 614 commit_lines.append(f"{parent_dir_name}/{cur_dir_name}") 615 616 if manifest_packages: 617 UpdateManifests(manifest_packages, chroot_path) 618 commit_lines.append("Updated manifest for:") 619 commit_lines.extend(manifest_packages) 620 621 EnsurePackageMaskContains(chroot_path, git_hash) 622 623 # Handle the patches for each package. 624 package_info_dict = UpdatePackagesPatchMetadataFile( 625 chroot_path, svn_version, packages, mode 626 ) 627 628 # Update the commit message if changes were made to a package's patches. 629 commit_lines = StagePackagesPatchResultsForCommit( 630 package_info_dict, commit_lines 631 ) 632 633 if extra_commit_msg: 634 commit_lines.append(extra_commit_msg) 635 636 change_list = git.UploadChanges(repo_path, branch, commit_lines) 637 638 finally: 639 git.DeleteBranch(repo_path, branch) 640 641 return change_list 642 643 644def EnsurePackageMaskContains(chroot_path, git_hash): 645 """Adds the major version of llvm to package.mask if it's not already present. 646 647 Args: 648 chroot_path: The absolute path to the chroot. 649 git_hash: The new git hash. 650 651 Raises: 652 FileExistsError: package.mask not found in ../../chromiumos-overlay 653 """ 654 655 llvm_major_version = get_llvm_hash.GetLLVMMajorVersion(git_hash) 656 657 overlay_dir = os.path.join( 658 chroot_path, "src/third_party/chromiumos-overlay" 659 ) 660 mask_path = os.path.join( 661 overlay_dir, "profiles/targets/chromeos/package.mask" 662 ) 663 with open(mask_path, "r+") as mask_file: 664 mask_contents = mask_file.read() 665 expected_line = f"=sys-devel/llvm-{llvm_major_version}.0_pre*\n" 666 if expected_line not in mask_contents: 667 mask_file.write(expected_line) 668 669 subprocess.check_output(["git", "-C", overlay_dir, "add", mask_path]) 670 671 672def UpdatePackagesPatchMetadataFile( 673 chroot_path: Path, 674 svn_version: int, 675 packages: Iterable[str], 676 mode: failure_modes.FailureModes, 677) -> Dict[str, patch_utils.PatchInfo]: 678 """Updates the packages metadata file. 679 680 Args: 681 chroot_path: The absolute path to the chroot. 682 svn_version: The version to use for patch management. 683 packages: All the packages to update their patch metadata file. 684 mode: The mode for the patch manager to use when an applicable patch 685 fails to apply. 686 Ex: 'FailureModes.FAIL' 687 688 Returns: 689 A dictionary where the key is the package name and the value is a dictionary 690 that has information on the patches. 691 """ 692 693 # A dictionary where the key is the package name and the value is a dictionary 694 # that has information on the patches. 695 package_info = {} 696 697 llvm_hash = get_llvm_hash.LLVMHash() 698 699 with llvm_hash.CreateTempDirectory() as temp_dir: 700 with get_llvm_hash.CreateTempLLVMRepo(temp_dir) as dirname: 701 # Ensure that 'svn_version' exists in the chromiumum mirror of LLVM by 702 # finding its corresponding git hash. 703 git_hash = get_llvm_hash.GetGitHashFrom(dirname, svn_version) 704 move_head_cmd = ["git", "-C", dirname, "checkout", git_hash, "-q"] 705 subprocess.run(move_head_cmd, stdout=subprocess.DEVNULL, check=True) 706 707 for cur_package in packages: 708 # Get the absolute path to $FILESDIR of the package. 709 chroot_ebuild_str = subprocess_helpers.ChrootRunCommand( 710 chroot_path, ["equery", "w", cur_package] 711 ).strip() 712 if not chroot_ebuild_str: 713 raise RuntimeError( 714 f"could not find ebuild for {cur_package}" 715 ) 716 chroot_ebuild_path = Path( 717 chroot.ConvertChrootPathsToAbsolutePaths( 718 chroot_path, [chroot_ebuild_str] 719 )[0] 720 ) 721 patches_json_fp = ( 722 chroot_ebuild_path.parent / "files" / "PATCHES.json" 723 ) 724 if not patches_json_fp.is_file(): 725 raise RuntimeError( 726 f"patches file {patches_json_fp} is not a file" 727 ) 728 729 src_path = Path(dirname) 730 with patch_utils.git_clean_context(src_path): 731 if ( 732 mode == failure_modes.FailureModes.FAIL 733 or mode == failure_modes.FailureModes.CONTINUE 734 ): 735 patches_info = patch_utils.apply_all_from_json( 736 svn_version=svn_version, 737 llvm_src_dir=src_path, 738 patches_json_fp=patches_json_fp, 739 continue_on_failure=mode 740 == failure_modes.FailureModes.CONTINUE, 741 ) 742 elif mode == failure_modes.FailureModes.REMOVE_PATCHES: 743 patches_info = patch_utils.remove_old_patches( 744 svn_version, src_path, patches_json_fp 745 ) 746 elif mode == failure_modes.FailureModes.DISABLE_PATCHES: 747 patches_info = patch_utils.update_version_ranges( 748 svn_version, src_path, patches_json_fp 749 ) 750 751 package_info[cur_package] = patches_info._asdict() 752 753 return package_info 754 755 756def main(): 757 """Updates the LLVM next hash for each package. 758 759 Raises: 760 AssertionError: The script was run inside the chroot. 761 """ 762 763 chroot.VerifyOutsideChroot() 764 765 args_output = GetCommandLineArgs() 766 767 llvm_variant = LLVMVariant.current 768 if args_output.is_llvm_next: 769 llvm_variant = LLVMVariant.next 770 771 git_hash_source = args_output.llvm_version 772 773 git_hash, svn_version = get_llvm_hash.GetLLVMHashAndVersionFromSVNOption( 774 git_hash_source 775 ) 776 777 # Filter out empty strings. For example "".split{",") returns [""]. 778 packages = set(p for p in args_output.update_packages.split(",") if p) 779 manifest_packages = set( 780 p for p in args_output.manifest_packages.split(",") if p 781 ) 782 if not manifest_packages and not args_output.is_llvm_next: 783 # Set default manifest packages only for the current llvm. 784 manifest_packages = set(DEFAULT_MANIFEST_PACKAGES) 785 change_list = UpdatePackages( 786 packages=packages, 787 manifest_packages=manifest_packages, 788 llvm_variant=llvm_variant, 789 git_hash=git_hash, 790 svn_version=svn_version, 791 chroot_path=args_output.chroot_path, 792 mode=failure_modes.FailureModes(args_output.failure_mode), 793 git_hash_source=git_hash_source, 794 extra_commit_msg=None, 795 ) 796 797 print(f"Successfully updated packages to {git_hash} ({svn_version})") 798 print(f"Gerrit URL: {change_list.url}") 799 print(f"Change list number: {change_list.cl_number}") 800 801 802if __name__ == "__main__": 803 main() 804