blob: 776593bd1afbbec11f1c4b474f1acf20c0690a5a [file] [log] [blame]
Mike Frysingerf1ba7ad2022-09-12 05:42:57 -04001# Copyright 2020 The ChromiumOS Authors
George Burgess IV85e69332020-01-16 17:33:16 -08002# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
George Burgess IV87c4dbf2022-03-21 12:05:11 -07005"""Determines all Chrome OS packages that are marked as `hot`.
George Burgess IV85e69332020-01-16 17:33:16 -08006
7Dumps results as a list of package names to a JSON file. Hotness is
8determined by statically analyzing an ebuild.
9
10Primarily intended for use by the Chrome OS toolchain team.
11"""
12
George Burgess IV85e69332020-01-16 17:33:16 -080013import json
Chris McDonald59650c32021-07-20 15:29:28 -060014import logging
George Burgess IV87c4dbf2022-03-21 12:05:11 -070015from pathlib import Path
16from typing import Iterable, List, Tuple
George Burgess IV85e69332020-01-16 17:33:16 -080017
18from chromite.lib import commandline
George Burgess IV85e69332020-01-16 17:33:16 -080019from chromite.lib import portage_util
20
21
George Burgess IV1012e272023-09-21 15:07:03 -060022def contains_hot_marker(file_path: Path):
Alex Klein1699fab2022-09-08 08:46:06 -060023 """Returns whether a file seems to be marked as hot."""
24 ebuild_contents = file_path.read_text(encoding="utf-8")
25 return "cros_optimize_package_for_speed" in ebuild_contents
George Burgess IV85e69332020-01-16 17:33:16 -080026
27
George Burgess IV87c4dbf2022-03-21 12:05:11 -070028def locate_all_package_ebuilds(
Alex Klein1699fab2022-09-08 08:46:06 -060029 overlays: Iterable[Path],
George Burgess IV1012e272023-09-21 15:07:03 -060030) -> Iterable[Tuple[Path, str, List[Path], List[Path]]]:
31 """Determines package -> (ebuild, bashrc) mappings for all packages.
George Burgess IV85e69332020-01-16 17:33:16 -080032
George Burgess IV1012e272023-09-21 15:07:03 -060033 Yields a series of (package_path, package_name, [path_to_ebuilds],
34 [path_to_bashrc_files]). This may yield the same package name multiple
35 times if it's available in multiple overlays.
Alex Klein1699fab2022-09-08 08:46:06 -060036 """
37 for overlay in overlays:
Alex Klein68b270c2023-04-14 14:42:50 -060038 # Note that portage_util.GetOverlayEBuilds can't be used here, since
39 # that specifically only searches for cros_workon candidates. We care
40 # about everything we can possibly build.
Alex Klein1699fab2022-09-08 08:46:06 -060041 for package_dir in overlay.glob("*/*"):
George Burgess IV1012e272023-09-21 15:07:03 -060042 resolved_bashrc_files = []
43 # `*.bashrc` files can either be a single file, or a directory
44 # containing a series of files.
45 for bashrc in package_dir.glob("*.bashrc"):
46 if bashrc.is_file():
47 resolved_bashrc_files.append(bashrc)
48 continue
49
50 # Ignore nested subdirectories. Those aren't observed in any
51 # CrOS overlays at the moment.
52 resolved_bashrc_files.extend(
53 x for x in bashrc.iterdir() if x.is_file()
54 )
55
Alex Klein1699fab2022-09-08 08:46:06 -060056 ebuilds = list(package_dir.glob("*.ebuild"))
George Burgess IV1012e272023-09-21 15:07:03 -060057 if not (ebuilds or resolved_bashrc_files):
58 continue
59
60 package_name = f"{package_dir.parent.name}/{package_dir.name}"
61 yield package_dir, package_name, ebuilds, resolved_bashrc_files
George Burgess IV85e69332020-01-16 17:33:16 -080062
63
George Burgess IV87c4dbf2022-03-21 12:05:11 -070064def locate_all_hot_env_packages(overlays: Iterable[Path]) -> Iterable[str]:
Alex Klein1699fab2022-09-08 08:46:06 -060065 """Yields packages marked hot by files in chromeos/config/env."""
66 for overlay in overlays:
67 env_dir = overlay / "chromeos" / "config" / "env"
68 for f in env_dir.glob("*/*"):
George Burgess IV1012e272023-09-21 15:07:03 -060069 if f.is_file() and contains_hot_marker(f):
Alex Klein1699fab2022-09-08 08:46:06 -060070 yield f"{f.parent.name}/{f.name}"
George Burgess IV87c4dbf2022-03-21 12:05:11 -070071
72
73def main(argv: List[str]):
Alex Klein1699fab2022-09-08 08:46:06 -060074 parser = commandline.ArgumentParser(description=__doc__)
75 parser.add_argument("--output", required=True, type=Path)
76 opts = parser.parse_args(argv)
George Burgess IV85e69332020-01-16 17:33:16 -080077
Alex Klein1699fab2022-09-08 08:46:06 -060078 ebuilds_found = 0
George Burgess IV1012e272023-09-21 15:07:03 -060079 bashrc_files_found = 0
Alex Klein1699fab2022-09-08 08:46:06 -060080 packages_found = 0
81 merged_packages = 0
George Burgess IV87c4dbf2022-03-21 12:05:11 -070082
Alex Klein1699fab2022-09-08 08:46:06 -060083 overlays = portage_util.FindOverlays(overlay_type="both")
84 logging.debug("Found overlays %s", overlays)
85 overlays = [Path(x) for x in overlays]
George Burgess IV87c4dbf2022-03-21 12:05:11 -070086
Alex Klein1699fab2022-09-08 08:46:06 -060087 mappings = {x: True for x in locate_all_hot_env_packages(overlays)}
88 logging.debug("Found hot packages %r from env search", sorted(mappings))
George Burgess IV1012e272023-09-21 15:07:03 -060089 for (
90 package_dir,
91 package,
92 ebuilds,
93 bashrc_files,
94 ) in locate_all_package_ebuilds(overlays):
Alex Klein1699fab2022-09-08 08:46:06 -060095 packages_found += 1
96 ebuilds_found += len(ebuilds)
George Burgess IV1012e272023-09-21 15:07:03 -060097 bashrc_files_found += len(bashrc_files)
Alex Klein1699fab2022-09-08 08:46:06 -060098 logging.debug(
George Burgess IV1012e272023-09-21 15:07:03 -060099 "Found package %r in %r with ebuilds %r and bashrc files %r",
Alex Klein1699fab2022-09-08 08:46:06 -0600100 package,
101 package_dir,
102 ebuilds,
George Burgess IV1012e272023-09-21 15:07:03 -0600103 bashrc_files,
Alex Klein1699fab2022-09-08 08:46:06 -0600104 )
George Burgess IV85e69332020-01-16 17:33:16 -0800105
George Burgess IV1012e272023-09-21 15:07:03 -0600106 files_with_hot_marker = (
107 x for x in bashrc_files + ebuilds if contains_hot_marker(x)
108 )
109 first_hot_file = next(files_with_hot_marker, None)
110 is_marked_hot = first_hot_file is not None
Alex Klein1699fab2022-09-08 08:46:06 -0600111 if is_marked_hot:
George Burgess IV1012e272023-09-21 15:07:03 -0600112 logging.debug("Package is marked as hot due to %s", first_hot_file)
Alex Klein1699fab2022-09-08 08:46:06 -0600113 else:
114 logging.debug("Package is not marked as hot")
George Burgess IV85e69332020-01-16 17:33:16 -0800115
Alex Klein1699fab2022-09-08 08:46:06 -0600116 if package in mappings:
117 logging.warning(
118 "Multiple entries found for package %r; merging", package
119 )
120 merged_packages += 1
121 mappings[package] = is_marked_hot or mappings[package]
122 else:
123 mappings[package] = is_marked_hot
George Burgess IV85e69332020-01-16 17:33:16 -0800124
Alex Klein1699fab2022-09-08 08:46:06 -0600125 hot_packages = sorted(
126 package for package, is_hot in mappings.items() if is_hot
127 )
George Burgess IV85e69332020-01-16 17:33:16 -0800128
Alex Klein1699fab2022-09-08 08:46:06 -0600129 logging.info("%d ebuilds found", ebuilds_found)
George Burgess IV1012e272023-09-21 15:07:03 -0600130 logging.info("%d bashrc files found", bashrc_files_found)
Alex Klein1699fab2022-09-08 08:46:06 -0600131 logging.info("%d packages found", packages_found)
132 logging.info("%d packages merged", merged_packages)
133 logging.info("%d hot packages found, total", len(hot_packages))
George Burgess IV85e69332020-01-16 17:33:16 -0800134
Alex Klein1699fab2022-09-08 08:46:06 -0600135 opts.output.write_text(json.dumps(hot_packages), encoding="utf-8")