scripts: package_has_missing_deps: match multiple slots

The get_packages logic returns the first match.  This is OK if
the query includes a version and that matches, but if the query
is just for a CATEGORY/PACKAGE_NAME (e.g. dev-libs/openssl), we
end up matching only one of them.  Instead, match both.  This
improves the --match behavior, and the implicit lookups, and the
virtual expansion.  In practice, none of these really expand into
more than one (other than --match), so this isn't that useful by
itself.  But the next CL will rely on this new behavior ...

BUG=None
TEST=`./scripts/package_has_missing_deps --board=betty --match dev-libs/openssl` checks both SLOTs

Change-Id: Ib8a53569ad5d2cfbcf22fd3785d958ad09cccc12
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/chromite/+/4879813
Tested-by: Mike Frysinger <vapier@chromium.org>
Auto-Submit: Mike Frysinger <vapier@chromium.org>
Reviewed-by: Allen Webb <allenwebb@google.com>
Commit-Queue: Mike Frysinger <vapier@chromium.org>
Commit-Queue: Allen Webb <allenwebb@google.com>
diff --git a/scripts/package_has_missing_deps.py b/scripts/package_has_missing_deps.py
index aba02c8..f72f7cc 100644
--- a/scripts/package_has_missing_deps.py
+++ b/scripts/package_has_missing_deps.py
@@ -18,7 +18,7 @@
 from pathlib import Path
 import pprint
 import sys
-from typing import List, Optional, Set, Union
+from typing import Iterable, List, Optional, Set, Union
 
 from chromite.lib import build_target_lib
 from chromite.lib import chroot_lib
@@ -156,10 +156,10 @@
             self._db_packges = self.db.InstalledPackages()
         return self._db_packges
 
-    def get_package(
+    def get_packages(
         self, query: str, from_sdk=False
-    ) -> Optional[portage_util.InstalledPackage]:
-        """Try to find an InstalledPackage for the provided package string"""
+    ) -> Iterable[portage_util.InstalledPackage]:
+        """Find matching InstalledPackage(s) for the |query|."""
         packages = self.sdk_db_packages if from_sdk else self.db_packages
         info = package_info.parse(query)
         for package in packages:
@@ -172,8 +172,7 @@
                 continue
             if info.pv and info.pv != dep_info.pv:
                 continue
-            return package
-        return None
+            yield package
 
     def get_required_libs(self, package) -> Set[str]:
         """Return a set of required .so files."""
@@ -213,9 +212,7 @@
                 deps.append(pkg)
 
         for dep in expanded:
-            pkg = self.get_package(dep)
-            if pkg:
-                deps.append(pkg)
+            deps.extend(self.get_packages(dep))
 
         return deps
 
@@ -232,10 +229,8 @@
             ("sys-libs/libcxx", False),
             ("sys-libs/llvm-libunwind", False),
         ):
-            pkg = self.get_package(dep, from_sdk)
-            if not pkg:
-                continue
-            implicit_libs.update(self.provided_libs(pkg))
+            for pkg in self.get_packages(dep, from_sdk):
+                implicit_libs.update(self.provided_libs(pkg))
         return implicit_libs
 
     def provided_libs(self, package: portage_util.InstalledPackage) -> Set[str]:
@@ -450,7 +445,9 @@
         else:
             packages = resolver.db.InstalledPackages()
     else:
-        packages = [resolver.get_package(p) for p in opts.package]
+        packages = []
+        for pkg in opts.package:
+            packages.extend(resolver.get_packages(pkg))
 
     implicit = resolver.get_implicit_libs()
     if opts.debug: