xref: /aosp_15_r20/external/toolchain-utils/pgo_tools/update_llvm_manifest.py (revision 760c253c1ed00ce9abd48f8546f08516e57485fe)
1*760c253cSXin Li#!/usr/bin/env python3
2*760c253cSXin Li# Copyright 2024 The ChromiumOS Authors
3*760c253cSXin Li# Use of this source code is governed by a BSD-style license that can be
4*760c253cSXin Li# found in the LICENSE file.
5*760c253cSXin Li
6*760c253cSXin Li"""Updates the Manifest file for LLVM.
7*760c253cSXin Li
8*760c253cSXin LiOften used to pull a new PGO profile in.
9*760c253cSXin Li"""
10*760c253cSXin Li
11*760c253cSXin Liimport argparse
12*760c253cSXin Liimport contextlib
13*760c253cSXin Liimport logging
14*760c253cSXin Lifrom pathlib import Path
15*760c253cSXin Liimport re
16*760c253cSXin Liimport subprocess
17*760c253cSXin Liimport sys
18*760c253cSXin Lifrom typing import Generator, List
19*760c253cSXin Li
20*760c253cSXin Liimport pgo_tools
21*760c253cSXin Li
22*760c253cSXin Li
23*760c253cSXin Li@contextlib.contextmanager
24*760c253cSXin Lidef temporarily_add_llvm_next_pgo_to_src_uri(
25*760c253cSXin Li    llvm_9999_ebuild: Path,
26*760c253cSXin Li) -> Generator[None, None, None]:
27*760c253cSXin Li    old_contents = llvm_9999_ebuild.read_text(encoding="utf-8")
28*760c253cSXin Li
29*760c253cSXin Li    profdata_prefix = "gs://chromeos-localmirror/distfiles/llvm-profdata-"
30*760c253cSXin Li    profdata_re = re.compile(
31*760c253cSXin Li        # Leave room for a suffix on this, in case we're on the Nth version of
32*760c253cSXin Li        # llvm-profdata for some reason.
33*760c253cSXin Li        re.escape(profdata_prefix + "${LLVM_HASH}")
34*760c253cSXin Li        + r"\S*\.xz\s"
35*760c253cSXin Li    )
36*760c253cSXin Li    found_urls = list(profdata_re.finditer(old_contents))
37*760c253cSXin Li    if len(found_urls) != 1:
38*760c253cSXin Li        raise ValueError(
39*760c253cSXin Li            f"Want 1 instance of {profdata_re} in {llvm_9999_ebuild}; found "
40*760c253cSXin Li            f"{len(found_urls)}"
41*760c253cSXin Li        )
42*760c253cSXin Li
43*760c253cSXin Li    # Insert the new profdata URL right after the old one. The combination of
44*760c253cSXin Li    # USE variables gating this file doesn't have to make sense; the URL just
45*760c253cSXin Li    # has to be visible to Portage.
46*760c253cSXin Li
47*760c253cSXin Li    # Note that the regex ended with `\s`, so `.end()` will be after a space.
48*760c253cSXin Li    insert_url = profdata_prefix + "${LLVM_NEXT_HASH}.xz "
49*760c253cSXin Li    insert_point = found_urls[0].end()
50*760c253cSXin Li    new_contents = (
51*760c253cSXin Li        old_contents[:insert_point] + insert_url + old_contents[insert_point:]
52*760c253cSXin Li    )
53*760c253cSXin Li
54*760c253cSXin Li    llvm_9999_ebuild.write_text(new_contents, encoding="utf-8")
55*760c253cSXin Li    try:
56*760c253cSXin Li        yield
57*760c253cSXin Li    finally:
58*760c253cSXin Li        llvm_9999_ebuild.write_text(old_contents, encoding="utf-8")
59*760c253cSXin Li
60*760c253cSXin Li
61*760c253cSXin Lidef update_manifest(llvm_9999_ebuild: Path):
62*760c253cSXin Li    subprocess.run(
63*760c253cSXin Li        ["ebuild", llvm_9999_ebuild, "manifest"],
64*760c253cSXin Li        check=True,
65*760c253cSXin Li        stdin=subprocess.DEVNULL,
66*760c253cSXin Li    )
67*760c253cSXin Li
68*760c253cSXin Li
69*760c253cSXin Lidef main(argv: List[str]) -> None:
70*760c253cSXin Li    logging.basicConfig(
71*760c253cSXin Li        format=">> %(asctime)s: %(levelname)s: %(filename)s:%(lineno)d: "
72*760c253cSXin Li        "%(message)s",
73*760c253cSXin Li        level=logging.INFO,
74*760c253cSXin Li    )
75*760c253cSXin Li
76*760c253cSXin Li    pgo_tools.exit_if_not_in_chroot()
77*760c253cSXin Li
78*760c253cSXin Li    my_dir = Path(__file__).resolve().parent
79*760c253cSXin Li    parser = argparse.ArgumentParser(
80*760c253cSXin Li        description=__doc__,
81*760c253cSXin Li        formatter_class=argparse.RawDescriptionHelpFormatter,
82*760c253cSXin Li    )
83*760c253cSXin Li    parser.add_argument(
84*760c253cSXin Li        "--llvm-next",
85*760c253cSXin Li        action="store_true",
86*760c253cSXin Li        help="Also update for the llvm-next PGO profile.",
87*760c253cSXin Li    )
88*760c253cSXin Li    parser.add_argument(
89*760c253cSXin Li        "--chromiumos-overlay",
90*760c253cSXin Li        default=my_dir.parent.parent / "chromiumos-overlay",
91*760c253cSXin Li        type=Path,
92*760c253cSXin Li        help="The chromiumos-overlay directory to work in. Default %(default)s",
93*760c253cSXin Li    )
94*760c253cSXin Li    opts = parser.parse_args(argv)
95*760c253cSXin Li
96*760c253cSXin Li    llvm_9999 = opts.chromiumos_overlay / "sys-devel/llvm/llvm-9999.ebuild"
97*760c253cSXin Li    if opts.llvm_next:
98*760c253cSXin Li        with temporarily_add_llvm_next_pgo_to_src_uri(llvm_9999):
99*760c253cSXin Li            update_manifest(llvm_9999)
100*760c253cSXin Li    else:
101*760c253cSXin Li        update_manifest(llvm_9999)
102*760c253cSXin Li
103*760c253cSXin Li
104*760c253cSXin Liif __name__ == "__main__":
105*760c253cSXin Li    main(sys.argv[1:])
106