1#!/usr/bin/env python3 2# Copyright 2024 The ChromiumOS Authors 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6"""Marks all LLVM packages as stable. 7 8This essentially performs the job of annealing: take whatever's in the 9999 9ebuilds, and put it in non-9999 ebuilds. The result is committed to 10chromiumos-overlay, unless there are no changes to make. If the stabilization 11does nothing, no new ebuilds will be created, and nothing will be committed. 12 13The results of this script should _not_ be uploaded. Annealing should be 14responsible for actually stabilizing our ebuilds upstream. 15 16Run this from inside of the chroot. 17""" 18 19import argparse 20import contextlib 21import logging 22from pathlib import Path 23import subprocess 24import sys 25from typing import List 26 27import chroot 28import get_upstream_patch 29import manifest_utils 30import patch_utils 31 32 33CROS_SOURCE_ROOT = Path("/mnt/host/source") 34 35 36@contextlib.contextmanager 37def llvm_checked_out_to(checkout_sha: str): 38 """Checks out LLVM to `checkout_sha`, if necessary. 39 40 Restores LLVM to the prior SHA when exited. 41 """ 42 llvm_dir = CROS_SOURCE_ROOT / manifest_utils.LLVM_PROJECT_PATH 43 original_sha = subprocess.run( 44 ["git", "rev-parse", "HEAD"], 45 check=True, 46 cwd=llvm_dir, 47 stdout=subprocess.PIPE, 48 encoding="utf-8", 49 ).stdout.strip() 50 if checkout_sha == original_sha: 51 logging.info( 52 "LLVM is already checked out to %s; not checking out", checkout_sha 53 ) 54 yield 55 return 56 57 return_code = subprocess.run( 58 ["git", "status", "--porcelain"], 59 check=False, 60 cwd=llvm_dir, 61 ).returncode 62 if return_code: 63 raise ValueError( 64 f"LLVM checkout at {llvm_dir} is unclean; refusing to modify" 65 ) 66 67 logging.info("Checking %s out to SHA %s...", llvm_dir, checkout_sha) 68 69 subprocess.run( 70 ["git", "checkout", checkout_sha], 71 check=True, 72 cwd=llvm_dir, 73 ) 74 try: 75 yield 76 finally: 77 logging.info("Restoring %s to original checkout...", llvm_dir) 78 return_code = subprocess.run( 79 ["git", "checkout", original_sha], 80 check=False, 81 cwd=llvm_dir, 82 ).returncode 83 if return_code: 84 logging.error( 85 "Failed checking llvm-project back out to %s :(", 86 original_sha, 87 ) 88 89 90def resolve_llvm_sha(llvm_next: bool) -> str: 91 sys_devel_llvm = ( 92 CROS_SOURCE_ROOT / "src/third_party/chromiumos-overlay/sys-devel/llvm" 93 ) 94 sha = "llvm-next" if llvm_next else "llvm" 95 return get_upstream_patch.resolve_symbolic_sha(sha, str(sys_devel_llvm)) 96 97 98def main(argv: List[str]) -> None: 99 chroot.VerifyInsideChroot() 100 101 logging.basicConfig( 102 format=">> %(asctime)s: %(levelname)s: %(filename)s:%(lineno)d: " 103 "%(message)s", 104 level=logging.INFO, 105 ) 106 107 parser = argparse.ArgumentParser( 108 description=__doc__, 109 formatter_class=argparse.RawDescriptionHelpFormatter, 110 ) 111 parser.add_argument( 112 "--llvm-next", 113 action="store_true", 114 help=""" 115 If passed, the ebuilds will be stabilized using the current llvm-next 116 hash. 117 """, 118 ) 119 opts = parser.parse_args(argv) 120 desired_sha = resolve_llvm_sha(opts.llvm_next) 121 122 with llvm_checked_out_to(desired_sha): 123 packages_to_stabilize = patch_utils.CHROMEOS_PATCHES_JSON_PACKAGES 124 logging.info("Stabilizing %s...", ", ".join(packages_to_stabilize)) 125 126 cros_overlay = CROS_SOURCE_ROOT / "src/third_party/chromiumos-overlay" 127 return_code = subprocess.run( 128 [ 129 "cros_mark_as_stable", 130 f"--overlays={cros_overlay}", 131 "--packages=" + ":".join(packages_to_stabilize), 132 "commit", 133 ], 134 check=False, 135 stdin=subprocess.DEVNULL, 136 ).returncode 137 sys.exit(return_code) 138 139 140if __name__ == "__main__": 141 main(sys.argv[1:]) 142