[PATCH] Add @unsatisfied-deps package set (bug 248026)

Zac Medico <[email protected]> Fri, 18 Jun 2021 16:48:44 -0700
Newsgroups gmane.linux.gentoo.portage.devel
Message-ID <[email protected]>
Bug: https://bugs.gentoo.org/248026
Signed-off-by: Zac Medico <[email protected]>
---
 cnf/sets/portage.conf      |  5 +++
 doc/config/sets.docbook    |  7 ++++
 lib/portage/_sets/dbapi.py | 73 +++++++++++++++++++++++++++++++++++++-
 3 files changed, 84 insertions(+), 1 deletion(-)

diff --git a/cnf/sets/portage.conf b/cnf/sets/portage.conf
index c4ad2efca..2bf38e414 100644
--- a/cnf/sets/portage.conf
+++ b/cnf/sets/portage.conf
@@ -115,3 +115,8 @@ class = portage.sets.dbapi.ChangedDepsSet
 class = portage.sets.dbapi.VariableSet
 variable = INHERITED
 includes = golang-base golang-build golang-vcs golang-vcs-snapshot go-module
+
+# Package set which contains all installed packages having one or more
+# unsatisfied runtime dependencies.
+[unsatisfied-deps]
+class = portage.sets.dbapi.UnsatisfiedDepsSet
diff --git a/doc/config/sets.docbook b/doc/config/sets.docbook
index eba98f468..1aa7e8aa1 100644
--- a/doc/config/sets.docbook
+++ b/doc/config/sets.docbook
@@ -610,6 +610,13 @@
 			</itemizedlist>
 			</sect3>
 		</sect2>
+		<sect2 id='config-set-classes-UnsatisfiedDepsSet'>
+		<title>portage.sets.dbapi.UnsatisfiedDepsSet</title>
+		<para>
+		Package set which contains all installed packages packages
+		having one or more unsatisfied runtime dependencies.
+		</para>
+		</sect2>
 	</sect1>
 	
 	<sect1 id='config-set-defaults'>
diff --git a/lib/portage/_sets/dbapi.py b/lib/portage/_sets/dbapi.py
index 8e1f19979..8e436980c 100644
--- a/lib/portage/_sets/dbapi.py
+++ b/lib/portage/_sets/dbapi.py
@@ -14,8 +14,16 @@ from portage._sets.base import PackageSet
 from portage._sets import SetConfigError, get_boolean
 import portage
 
+from _emerge.Package import Package
+from _emerge.RootConfig import RootConfig
+
 __all__ = ["CategorySet", "ChangedDepsSet", "DowngradeSet",
-	"EverythingSet", "OwnerSet", "SubslotChangedSet", "VariableSet"]
+	"EverythingSet",
+	"OwnerSet",
+	"SubslotChangedSet",
+	"UnsatisfiedDepsSet",
+	"VariableSet",
+]
 
 class EverythingSet(PackageSet):
 	_operations = ["merge"]
@@ -303,6 +311,69 @@ class UnavailableBinaries(EverythingSet):
 
 	singleBuilder = classmethod(singleBuilder)
 
+class UnsatisfiedDepsSet(PackageSet):
+
+	_operations = ["merge", "unmerge"]
+
+	description = (
+		"Package set which contains all installed packages packages "
+		"having one or more unsatisfied runtime dependencies."
+	)
+
+	def __init__(self, vardb=None):
+		super().__init__()
+		self._vardb = vardb
+
+	def load(self):
+		vardb = self._vardb
+		trees = {
+			vardb.settings["EROOT"]: {
+				"porttree": vardb.vartree,
+				"vartree": vardb.vartree,
+			}
+		}
+		root_config = RootConfig(vardb.settings, trees[vardb.settings["EROOT"]], None)
+		atoms = []
+		for pkg_str in vardb.cpv_all():
+			try:
+				metadata = dict(
+					zip(
+						vardb._aux_cache_keys,
+						vardb.aux_get(pkg_str, vardb._aux_cache_keys),
+					)
+				)
+			except KeyError:
+				continue
+			pkg = Package(
+				built=True,
+				cpv=pkg_str,
+				installed=True,
+				metadata=metadata,
+				root_config=root_config,
+				type_name="installed",
+			)
+
+			runtime_deps = " ".join(pkg._metadata[k] for k in Package._runtime_keys)
+
+			success, unsatisfied_deps = portage.dep_check(
+				runtime_deps,
+				None,
+				vardb.settings,
+				myuse=pkg.use.enabled,
+				myroot=vardb.settings["EROOT"],
+				trees=trees,
+			)
+
+			if not (success and not unsatisfied_deps):
+				atoms.append(pkg.slot_atom)
+
+		self._setAtoms(atoms)
+
+	def singleBuilder(cls, options, settings, trees):
+		return cls(vardb=trees["vartree"].dbapi)
+
+	singleBuilder = classmethod(singleBuilder)
+
 class CategorySet(PackageSet):
 	_operations = ["merge", "unmerge"]
 
-- 
2.26.2