xref: /aosp_15_r20/external/toolchain-utils/llvm_tools/stabilize_all_llvm_packages.py (revision 760c253c1ed00ce9abd48f8546f08516e57485fe)
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