Mike Frysinger | f1ba7ad | 2022-09-12 05:42:57 -0400 | [diff] [blame] | 1 | # Copyright 2020 The ChromiumOS Authors |
George Burgess IV | 85e6933 | 2020-01-16 17:33:16 -0800 | [diff] [blame] | 2 | # Use of this source code is governed by a BSD-style license that can be |
| 3 | # found in the LICENSE file. |
| 4 | |
George Burgess IV | 87c4dbf | 2022-03-21 12:05:11 -0700 | [diff] [blame] | 5 | """Determines all Chrome OS packages that are marked as `hot`. |
George Burgess IV | 85e6933 | 2020-01-16 17:33:16 -0800 | [diff] [blame] | 6 | |
| 7 | Dumps results as a list of package names to a JSON file. Hotness is |
| 8 | determined by statically analyzing an ebuild. |
| 9 | |
| 10 | Primarily intended for use by the Chrome OS toolchain team. |
| 11 | """ |
| 12 | |
George Burgess IV | 85e6933 | 2020-01-16 17:33:16 -0800 | [diff] [blame] | 13 | import json |
Chris McDonald | 59650c3 | 2021-07-20 15:29:28 -0600 | [diff] [blame] | 14 | import logging |
George Burgess IV | 87c4dbf | 2022-03-21 12:05:11 -0700 | [diff] [blame] | 15 | from pathlib import Path |
| 16 | from typing import Iterable, List, Tuple |
George Burgess IV | 85e6933 | 2020-01-16 17:33:16 -0800 | [diff] [blame] | 17 | |
| 18 | from chromite.lib import commandline |
George Burgess IV | 85e6933 | 2020-01-16 17:33:16 -0800 | [diff] [blame] | 19 | from chromite.lib import portage_util |
| 20 | |
| 21 | |
George Burgess IV | 1012e27 | 2023-09-21 15:07:03 -0600 | [diff] [blame] | 22 | def contains_hot_marker(file_path: Path): |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 23 | """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 IV | 85e6933 | 2020-01-16 17:33:16 -0800 | [diff] [blame] | 26 | |
| 27 | |
George Burgess IV | 87c4dbf | 2022-03-21 12:05:11 -0700 | [diff] [blame] | 28 | def locate_all_package_ebuilds( |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 29 | overlays: Iterable[Path], |
George Burgess IV | 1012e27 | 2023-09-21 15:07:03 -0600 | [diff] [blame] | 30 | ) -> Iterable[Tuple[Path, str, List[Path], List[Path]]]: |
| 31 | """Determines package -> (ebuild, bashrc) mappings for all packages. |
George Burgess IV | 85e6933 | 2020-01-16 17:33:16 -0800 | [diff] [blame] | 32 | |
George Burgess IV | 1012e27 | 2023-09-21 15:07:03 -0600 | [diff] [blame] | 33 | 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 Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 36 | """ |
| 37 | for overlay in overlays: |
Alex Klein | 68b270c | 2023-04-14 14:42:50 -0600 | [diff] [blame] | 38 | # 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 Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 41 | for package_dir in overlay.glob("*/*"): |
George Burgess IV | 1012e27 | 2023-09-21 15:07:03 -0600 | [diff] [blame] | 42 | 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 Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 56 | ebuilds = list(package_dir.glob("*.ebuild")) |
George Burgess IV | 1012e27 | 2023-09-21 15:07:03 -0600 | [diff] [blame] | 57 | 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 IV | 85e6933 | 2020-01-16 17:33:16 -0800 | [diff] [blame] | 62 | |
| 63 | |
George Burgess IV | 87c4dbf | 2022-03-21 12:05:11 -0700 | [diff] [blame] | 64 | def locate_all_hot_env_packages(overlays: Iterable[Path]) -> Iterable[str]: |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 65 | """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 IV | 1012e27 | 2023-09-21 15:07:03 -0600 | [diff] [blame] | 69 | if f.is_file() and contains_hot_marker(f): |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 70 | yield f"{f.parent.name}/{f.name}" |
George Burgess IV | 87c4dbf | 2022-03-21 12:05:11 -0700 | [diff] [blame] | 71 | |
| 72 | |
| 73 | def main(argv: List[str]): |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 74 | parser = commandline.ArgumentParser(description=__doc__) |
| 75 | parser.add_argument("--output", required=True, type=Path) |
| 76 | opts = parser.parse_args(argv) |
George Burgess IV | 85e6933 | 2020-01-16 17:33:16 -0800 | [diff] [blame] | 77 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 78 | ebuilds_found = 0 |
George Burgess IV | 1012e27 | 2023-09-21 15:07:03 -0600 | [diff] [blame] | 79 | bashrc_files_found = 0 |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 80 | packages_found = 0 |
| 81 | merged_packages = 0 |
George Burgess IV | 87c4dbf | 2022-03-21 12:05:11 -0700 | [diff] [blame] | 82 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 83 | overlays = portage_util.FindOverlays(overlay_type="both") |
| 84 | logging.debug("Found overlays %s", overlays) |
| 85 | overlays = [Path(x) for x in overlays] |
George Burgess IV | 87c4dbf | 2022-03-21 12:05:11 -0700 | [diff] [blame] | 86 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 87 | 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 IV | 1012e27 | 2023-09-21 15:07:03 -0600 | [diff] [blame] | 89 | for ( |
| 90 | package_dir, |
| 91 | package, |
| 92 | ebuilds, |
| 93 | bashrc_files, |
| 94 | ) in locate_all_package_ebuilds(overlays): |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 95 | packages_found += 1 |
| 96 | ebuilds_found += len(ebuilds) |
George Burgess IV | 1012e27 | 2023-09-21 15:07:03 -0600 | [diff] [blame] | 97 | bashrc_files_found += len(bashrc_files) |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 98 | logging.debug( |
George Burgess IV | 1012e27 | 2023-09-21 15:07:03 -0600 | [diff] [blame] | 99 | "Found package %r in %r with ebuilds %r and bashrc files %r", |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 100 | package, |
| 101 | package_dir, |
| 102 | ebuilds, |
George Burgess IV | 1012e27 | 2023-09-21 15:07:03 -0600 | [diff] [blame] | 103 | bashrc_files, |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 104 | ) |
George Burgess IV | 85e6933 | 2020-01-16 17:33:16 -0800 | [diff] [blame] | 105 | |
George Burgess IV | 1012e27 | 2023-09-21 15:07:03 -0600 | [diff] [blame] | 106 | 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 Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 111 | if is_marked_hot: |
George Burgess IV | 1012e27 | 2023-09-21 15:07:03 -0600 | [diff] [blame] | 112 | logging.debug("Package is marked as hot due to %s", first_hot_file) |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 113 | else: |
| 114 | logging.debug("Package is not marked as hot") |
George Burgess IV | 85e6933 | 2020-01-16 17:33:16 -0800 | [diff] [blame] | 115 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 116 | 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 IV | 85e6933 | 2020-01-16 17:33:16 -0800 | [diff] [blame] | 124 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 125 | hot_packages = sorted( |
| 126 | package for package, is_hot in mappings.items() if is_hot |
| 127 | ) |
George Burgess IV | 85e6933 | 2020-01-16 17:33:16 -0800 | [diff] [blame] | 128 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 129 | logging.info("%d ebuilds found", ebuilds_found) |
George Burgess IV | 1012e27 | 2023-09-21 15:07:03 -0600 | [diff] [blame] | 130 | logging.info("%d bashrc files found", bashrc_files_found) |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 131 | 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 IV | 85e6933 | 2020-01-16 17:33:16 -0800 | [diff] [blame] | 134 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 135 | opts.output.write_text(json.dumps(hot_packages), encoding="utf-8") |