scripts: package_has_missing_deps: Support running as install hook
When running as an install hook, NEEDED is available but REQUIRES is
not and CONTENTS isn't available, but ${D} contains the files.
* Adds --image for --build-info, which defaults to ${D} when not set,
to correctly handle libraries provided by the package when CONTENTS
is not available.
* Adds a fallback from REQUIRES to NEEDED if REQUIRES is not available
and NEEDED is.
BUG=b:299471320
TEST=emerge-${BOARD} a cros-workoned package
Change-Id: Ie331af8048e5961bcb712c314fd5aaa2877e7341
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/chromite/+/4856741
Commit-Queue: Allen Webb <allenwebb@google.com>
Reviewed-by: Mike Frysinger <vapier@chromium.org>
Tested-by: Allen Webb <allenwebb@google.com>
diff --git a/scripts/package_has_missing_deps.py b/scripts/package_has_missing_deps.py
index b4e8598..b34b8e6 100644
--- a/scripts/package_has_missing_deps.py
+++ b/scripts/package_has_missing_deps.py
@@ -80,7 +80,16 @@
def get_required_libs(self, package) -> Set[str]:
"""Return a set of required .so files."""
- return set(env_to_libs(package.requires or ""))
+ requires = package.requires
+ if requires is not None:
+ return set(env_to_libs(package.requires))
+ # Fallback to needed if requires is not available.
+ aggregate = set()
+ needed = package.needed
+ if needed is not None:
+ for libs in needed.values():
+ aggregate.update(libs)
+ return aggregate
def get_deps(self, package):
"""Return a list of dependencies."""
@@ -125,11 +134,31 @@
self.provided_libs_cache[cpvr] = libs
return libs
+ def cache_libs_from_build(
+ self, package: portage_util.InstalledPackage, image_dir: Path
+ ):
+ """Populate the provided_libs_cache for the package from the image dir.
+
+ When using build-info, CONTENTS might not be available yet. so provide
+ alternative using the destination directory of the ebuild.
+ """
+
+ cpvr = f"{package.category}/{package.pf}"
+ libs = set()
+ for _, _, files in os.walk(image_dir):
+ for file in files:
+ if file.endswith(".so") or ".so." in file:
+ libs.add(os.path.basename(file))
+ self.provided_libs_cache[cpvr] = libs
+
def get_provided_from_all_deps(
self, package: portage_util.InstalledPackage
) -> Set[str]:
"""Return a set of .so files provided by the immediate dependencies."""
provided_libs = set()
+ # |package| may not actually be installed yet so manually add it to the
+ # since a package can depend on its own libs.
+ provided_libs.update(self.provided_libs(package))
deps = self.get_deps(package)
for dep in deps:
info = package_info.parse(dep)
@@ -190,6 +219,14 @@
)
parser.add_argument(
+ "-x",
+ "--image",
+ default=None,
+ type=Path,
+ help="Path to image folder post src_install (${D} if unspecified)",
+ )
+
+ parser.add_argument(
"--match",
default=False,
action="store_true",
@@ -212,7 +249,9 @@
parser = get_parser()
opts = parser.parse_args(argv)
if opts.build_info and opts.package:
- raise Exception("Do not specify a package when setting --board-info")
+ parser.error("Do not specify a package when setting --board-info")
+ if opts.image and not opts.build_info:
+ parser.error("--image requires --board-info")
if opts.build_info or len(opts.package) == 1:
opts.jobs = 1
return opts
@@ -273,9 +312,11 @@
if not opts.package:
if opts.build_info:
- packages = [
- portage_util.InstalledPackage(resolver.db, opts.build_info)
- ]
+ pkg = portage_util.InstalledPackage(resolver.db, opts.build_info)
+ image_path = opts.image or os.environ.get("D")
+ if image_path:
+ resolver.cache_libs_from_build(pkg, Path(image_path))
+ packages = [pkg]
else:
packages = resolver.db.InstalledPackages()
else: