blob: 91522ecdfea9712d68f642ef68757c3d9a4108fc [file] [log] [blame]
George Burgess IV85e69332020-01-16 17:33:16 -08001# Copyright 2020 The Chromium OS Authors. All rights reserved.
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 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 IV87c4dbf2022-03-21 12:05:11 -070022def contains_ebuild_hot_marker(file_path: Path):
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 IV85e69332020-01-16 17:33:16 -080026
27
George Burgess IV87c4dbf2022-03-21 12:05:11 -070028def locate_all_package_ebuilds(
29 overlays: Iterable[Path]) -> Iterable[Tuple[Path, str, List[Path]]]:
George Burgess IV85e69332020-01-16 17:33:16 -080030 """Determines package -> ebuild mappings for all packages.
31
32 Yields a series of (package_path, package_name, [path_to_ebuilds]). This may
33 yield the same package name multiple times if it's available in multiple
34 overlays.
35 """
George Burgess IV87c4dbf2022-03-21 12:05:11 -070036 for overlay in overlays:
George Burgess IV85e69332020-01-16 17:33:16 -080037 # Note that portage_util.GetOverlayEBuilds can't be used here, since that
38 # specifically only searches for cros_workon candidates. We care about
39 # everything we can possibly build.
George Burgess IV87c4dbf2022-03-21 12:05:11 -070040 for package_dir in overlay.glob('*/*'):
41 ebuilds = list(package_dir.glob('*.ebuild'))
42 if ebuilds:
43 package_name = f'{package_dir.parent.name}/{package_dir.name}'
44 yield package_dir, package_name, ebuilds
George Burgess IV85e69332020-01-16 17:33:16 -080045
46
George Burgess IV87c4dbf2022-03-21 12:05:11 -070047def locate_all_hot_env_packages(overlays: Iterable[Path]) -> Iterable[str]:
48 """Yields packages marked hot by files in chromeos/config/env."""
49 for overlay in overlays:
50 env_dir = overlay / 'chromeos' / 'config' / 'env'
51 for f in env_dir.glob('*/*'):
52 if f.is_file() and contains_ebuild_hot_marker(f):
53 yield f'{f.parent.name}/{f.name}'
54
55
56def main(argv: List[str]):
George Burgess IV85e69332020-01-16 17:33:16 -080057 parser = commandline.ArgumentParser(description=__doc__)
George Burgess IV87c4dbf2022-03-21 12:05:11 -070058 parser.add_argument('--output', required=True, type=Path)
George Burgess IV85e69332020-01-16 17:33:16 -080059 opts = parser.parse_args(argv)
60
61 ebuilds_found = 0
62 packages_found = 0
63 merged_packages = 0
George Burgess IV87c4dbf2022-03-21 12:05:11 -070064
65 overlays = portage_util.FindOverlays(overlay_type='both')
66 logging.debug('Found overlays %s', overlays)
67 overlays = [Path(x) for x in overlays]
68
69 mappings = {x: True for x in locate_all_hot_env_packages(overlays)}
70 logging.debug('Found hot packages %r from env search', sorted(mappings))
71 for package_dir, package, ebuilds in locate_all_package_ebuilds(overlays):
George Burgess IV85e69332020-01-16 17:33:16 -080072 packages_found += 1
73 ebuilds_found += len(ebuilds)
74 logging.debug('Found package %r in %r with ebuilds %r', package,
75 package_dir, ebuilds)
76
George Burgess IV87c4dbf2022-03-21 12:05:11 -070077 is_marked_hot = any(contains_ebuild_hot_marker(x) for x in ebuilds)
George Burgess IV85e69332020-01-16 17:33:16 -080078 if is_marked_hot:
79 logging.debug('Package is marked as hot')
80 else:
81 logging.debug('Package is not marked as hot')
82
83 if package in mappings:
84 logging.warning('Multiple entries found for package %r; merging', package)
85 merged_packages += 1
86 mappings[package] = is_marked_hot or mappings[package]
87 else:
88 mappings[package] = is_marked_hot
89
90 hot_packages = sorted(
91 package for package, is_hot in mappings.items() if is_hot)
92
93 logging.info('%d ebuilds found', ebuilds_found)
94 logging.info('%d packages found', packages_found)
95 logging.info('%d packages merged', merged_packages)
96 logging.info('%d hot packages found, total', len(hot_packages))
97
George Burgess IV87c4dbf2022-03-21 12:05:11 -070098 opts.output.write_text(json.dumps(hot_packages), encoding='utf-8')