scripts: make enumerate_hot_packages look for local bashrc files

Some packages (e.g., openssl) have configuration in a bashrc file.
Respect that here.

BUG=b:301436810
TEST=./enumerate_hot_packages reports that openssl is marked hot.

Change-Id: I1f6395eb2a6c6e08bc3fe6c3389b54e08947dcc0
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/chromite/+/4884051
Tested-by: George Burgess <gbiv@chromium.org>
Reviewed-by: Ryan Beltran <ryanbeltran@chromium.org>
Reviewed-by: Lee Presland <zland@google.com>
Commit-Queue: George Burgess <gbiv@chromium.org>
diff --git a/scripts/enumerate_hot_packages.py b/scripts/enumerate_hot_packages.py
index 9385128..776593b 100644
--- a/scripts/enumerate_hot_packages.py
+++ b/scripts/enumerate_hot_packages.py
@@ -19,7 +19,7 @@
 from chromite.lib import portage_util
 
 
-def contains_ebuild_hot_marker(file_path: Path):
+def contains_hot_marker(file_path: Path):
     """Returns whether a file seems to be marked as hot."""
     ebuild_contents = file_path.read_text(encoding="utf-8")
     return "cros_optimize_package_for_speed" in ebuild_contents
@@ -27,22 +27,38 @@
 
 def locate_all_package_ebuilds(
     overlays: Iterable[Path],
-) -> Iterable[Tuple[Path, str, List[Path]]]:
-    """Determines package -> ebuild mappings for all packages.
+) -> Iterable[Tuple[Path, str, List[Path], List[Path]]]:
+    """Determines package -> (ebuild, bashrc) mappings for all packages.
 
-    Yields a series of (package_path, package_name, [path_to_ebuilds]). This may
-    yield the same package name multiple times if it's available in multiple
-    overlays.
+    Yields a series of (package_path, package_name, [path_to_ebuilds],
+    [path_to_bashrc_files]). This may yield the same package name multiple
+    times if it's available in multiple overlays.
     """
     for overlay in overlays:
         # Note that portage_util.GetOverlayEBuilds can't be used here, since
         # that specifically only searches for cros_workon candidates. We care
         # about everything we can possibly build.
         for package_dir in overlay.glob("*/*"):
+            resolved_bashrc_files = []
+            # `*.bashrc` files can either be a single file, or a directory
+            # containing a series of files.
+            for bashrc in package_dir.glob("*.bashrc"):
+                if bashrc.is_file():
+                    resolved_bashrc_files.append(bashrc)
+                    continue
+
+                # Ignore nested subdirectories. Those aren't observed in any
+                # CrOS overlays at the moment.
+                resolved_bashrc_files.extend(
+                    x for x in bashrc.iterdir() if x.is_file()
+                )
+
             ebuilds = list(package_dir.glob("*.ebuild"))
-            if ebuilds:
-                package_name = f"{package_dir.parent.name}/{package_dir.name}"
-                yield package_dir, package_name, ebuilds
+            if not (ebuilds or resolved_bashrc_files):
+                continue
+
+            package_name = f"{package_dir.parent.name}/{package_dir.name}"
+            yield package_dir, package_name, ebuilds, resolved_bashrc_files
 
 
 def locate_all_hot_env_packages(overlays: Iterable[Path]) -> Iterable[str]:
@@ -50,7 +66,7 @@
     for overlay in overlays:
         env_dir = overlay / "chromeos" / "config" / "env"
         for f in env_dir.glob("*/*"):
-            if f.is_file() and contains_ebuild_hot_marker(f):
+            if f.is_file() and contains_hot_marker(f):
                 yield f"{f.parent.name}/{f.name}"
 
 
@@ -60,6 +76,7 @@
     opts = parser.parse_args(argv)
 
     ebuilds_found = 0
+    bashrc_files_found = 0
     packages_found = 0
     merged_packages = 0
 
@@ -69,19 +86,30 @@
 
     mappings = {x: True for x in locate_all_hot_env_packages(overlays)}
     logging.debug("Found hot packages %r from env search", sorted(mappings))
-    for package_dir, package, ebuilds in locate_all_package_ebuilds(overlays):
+    for (
+        package_dir,
+        package,
+        ebuilds,
+        bashrc_files,
+    ) in locate_all_package_ebuilds(overlays):
         packages_found += 1
         ebuilds_found += len(ebuilds)
+        bashrc_files_found += len(bashrc_files)
         logging.debug(
-            "Found package %r in %r with ebuilds %r",
+            "Found package %r in %r with ebuilds %r and bashrc files %r",
             package,
             package_dir,
             ebuilds,
+            bashrc_files,
         )
 
-        is_marked_hot = any(contains_ebuild_hot_marker(x) for x in ebuilds)
+        files_with_hot_marker = (
+            x for x in bashrc_files + ebuilds if contains_hot_marker(x)
+        )
+        first_hot_file = next(files_with_hot_marker, None)
+        is_marked_hot = first_hot_file is not None
         if is_marked_hot:
-            logging.debug("Package is marked as hot")
+            logging.debug("Package is marked as hot due to %s", first_hot_file)
         else:
             logging.debug("Package is not marked as hot")
 
@@ -99,6 +127,7 @@
     )
 
     logging.info("%d ebuilds found", ebuilds_found)
+    logging.info("%d bashrc files found", bashrc_files_found)
     logging.info("%d packages found", packages_found)
     logging.info("%d packages merged", merged_packages)
     logging.info("%d hot packages found, total", len(hot_packages))