commit:     9fefb10f2b5ca6dc3e595e1d318956252f396ed0
Author:     Arthur Zamarin <arthurzam <AT> gentoo <DOT> org>
AuthorDate: Thu Oct 27 19:07:12 2022 +0000
Commit:     Arthur Zamarin <arthurzam <AT> gentoo <DOT> org>
CommitDate: Fri Nov  4 12:57:44 2022 +0000
URL:        
https://gitweb.gentoo.org/proj/pkgcore/pkgcheck.git/commit/?id=9fefb10f

VirtualProvidersCheck: new check for providers issues

- check for virtual package defining DEPEND or BDEPEND
- check for virtual package with a single provider across versions

Closes: https://bugs.gentoo.org/744784
Signed-off-by: Arthur Zamarin <arthurzam <AT> gentoo.org>

 src/pkgcheck/checks/metadata.py                    | 80 +++++++++++++++++++++-
 .../VirtualWithBdepend/expected.json               |  2 +
 .../VirtualWithDepend/expected.json                |  2 +
 .../VirtualWithSingleProvider/expected.json        |  1 +
 testdata/repos/standalone/profiles/desc/elibc.desc |  1 +
 .../repos/standalone/profiles/package.deprecated   |  1 +
 .../VirtualWithBdepend/VirtualWithBdepend-0.ebuild |  6 ++
 .../VirtualWithBdepend/VirtualWithBdepend-1.ebuild | 11 +++
 .../VirtualWithDepend/VirtualWithDepend-0.ebuild   |  6 ++
 .../VirtualWithDepend/VirtualWithDepend-1.ebuild   | 11 +++
 .../VirtualWithSingleProvider1-0.ebuild            | 10 +++
 .../VirtualWithSingleProvider2-0.ebuild            | 10 +++
 .../VirtualWithSingleProvider3-0.ebuild            |  8 +++
 .../VirtualWithSingleProvider3-1.ebuild            |  8 +++
 .../VirtualWithSingleProvider4-0.ebuild            |  8 +++
 .../VirtualWithSingleProvider4-1.ebuild            |  8 +++
 .../VirtualWithSingleProvider5-0.ebuild            |  8 +++
 .../VirtualWithSingleProvider6-0.ebuild            |  9 +++
 18 files changed, 189 insertions(+), 1 deletion(-)

diff --git a/src/pkgcheck/checks/metadata.py b/src/pkgcheck/checks/metadata.py
index 7980942d..6e087c5f 100644
--- a/src/pkgcheck/checks/metadata.py
+++ b/src/pkgcheck/checks/metadata.py
@@ -7,7 +7,7 @@ from difflib import SequenceMatcher
 from functools import partial
 from operator import attrgetter
 
-from pkgcore.ebuild import atom as atom_mod
+from pkgcore.ebuild import atom as atom_mod, restricts
 from pkgcore.ebuild.atom import atom as atom_cls
 from pkgcore.ebuild.eapi import get_eapi
 from pkgcore.ebuild.misc import sort_keywords
@@ -1627,3 +1627,81 @@ class MissingUnpackerDepCheck(Check):
         for unpackers, filenames in missing_unpackers.items():
             yield MissingUnpackerDep(
                 str(pkg.eapi), sorted(filenames), sorted(unpackers), pkg=pkg)
+
+
+class VirtualWithSingleProvider(results.PackageResult, results.Warning):
+    """Virtual package with a single remaining provider.
+
+    Virtual packages are used to provide a common interface for multiple
+    implementations of a given functionality. However, if there is only a
+    single implementation, there is no need for a virtual package. In such
+    case, consider adding the package to package.deprecated and removing the
+    virtual package.
+    """
+
+    def __init__(self, provider, **kwargs):
+        super().__init__(**kwargs)
+        self.provider = str(provider)
+
+    @property
+    def desc(self):
+        return f'virtual package with a single provider: {self.provider}'
+
+
+class VirtualWithBdepend(results.VersionResult, results.Warning):
+    """Virtual package with a BDEPEND defined."""
+
+    desc = 'virtual package with a BDEPEND defined'
+
+
+class VirtualWithDepend(results.VersionResult, results.Warning):
+    """Virtual package with a BDEPEND defined."""
+
+    desc = 'virtual package with a DEPEND defined'
+
+
+class VirtualProvidersCheck(Check):
+    """Check providers of virtual packages."""
+
+    _restricted_source = (sources.RestrictionRepoSource, 
(restricts.CategoryDep('virtual'), ))
+    _source = (sources.PackageRepoSource, (), (('source', 
_restricted_source),))
+    known_results = frozenset([VirtualWithSingleProvider,
+        VirtualWithBdepend, VirtualWithDepend])
+
+    useless_depends = (
+        ('depend', VirtualWithDepend),
+        ('bdepend', VirtualWithBdepend),
+    )
+
+    def __init__(self, options, **kwargs):
+        super().__init__(options, **kwargs)
+
+        self.deprecated = self.options.target_repo.deprecated
+
+    def pkg_has_conditional_exception(self, pkgs):
+        return any(use.startswith(('elibc', 'kernel'))
+            for pkg in pkgs
+            for dep in iflatten_instance(pkg.rdepend, (atom_cls, 
packages.Conditional))
+            if isinstance(dep, packages.Conditional) and dep.attr == 'use' and 
isinstance(dep.restriction, values.ContainmentMatch)
+            for use in dep.restriction.vals
+        )
+
+    def feed(self, pkgs):
+        for pkg in pkgs:
+            for attr, cls in self.useless_depends:
+                if getattr(pkg, attr):
+                    yield cls(pkg=pkg)
+
+        if not any(self.deprecated.match(pkg) for pkg in pkgs):
+            pkgs_rdepends = tuple(
+                tuple(iflatten_instance(pkg.rdepend, atom_cls))
+                for pkg in pkgs
+            )
+            if max(map(len, pkgs_rdepends)) == 1:
+                unversioned_rdepends = {
+                    deps[0].unversioned_atom
+                    for deps in pkgs_rdepends
+                    if len(deps) == 1
+                }
+                if len(unversioned_rdepends) == 1 and not 
self.pkg_has_conditional_exception(pkgs):
+                    yield 
VirtualWithSingleProvider(unversioned_rdepends.pop(), pkg=pkgs[0])

diff --git 
a/testdata/data/repos/standalone/VirtualProvidersCheck/VirtualWithBdepend/expected.json
 
b/testdata/data/repos/standalone/VirtualProvidersCheck/VirtualWithBdepend/expected.json
new file mode 100644
index 00000000..67f8c375
--- /dev/null
+++ 
b/testdata/data/repos/standalone/VirtualProvidersCheck/VirtualWithBdepend/expected.json
@@ -0,0 +1,2 @@
+{"__class__": "VirtualWithBdepend", "category": "virtual", "package": 
"VirtualWithBdepend", "version": "0"}
+{"__class__": "VirtualWithBdepend", "category": "virtual", "package": 
"VirtualWithBdepend", "version": "1"}

diff --git 
a/testdata/data/repos/standalone/VirtualProvidersCheck/VirtualWithDepend/expected.json
 
b/testdata/data/repos/standalone/VirtualProvidersCheck/VirtualWithDepend/expected.json
new file mode 100644
index 00000000..05edb413
--- /dev/null
+++ 
b/testdata/data/repos/standalone/VirtualProvidersCheck/VirtualWithDepend/expected.json
@@ -0,0 +1,2 @@
+{"__class__": "VirtualWithDepend", "category": "virtual", "package": 
"VirtualWithDepend", "version": "0"}
+{"__class__": "VirtualWithDepend", "category": "virtual", "package": 
"VirtualWithDepend", "version": "1"}

diff --git 
a/testdata/data/repos/standalone/VirtualProvidersCheck/VirtualWithSingleProvider/expected.json
 
b/testdata/data/repos/standalone/VirtualProvidersCheck/VirtualWithSingleProvider/expected.json
new file mode 100644
index 00000000..898cdb35
--- /dev/null
+++ 
b/testdata/data/repos/standalone/VirtualProvidersCheck/VirtualWithSingleProvider/expected.json
@@ -0,0 +1 @@
+{"__class__": "VirtualWithSingleProvider", "category": "virtual", "package": 
"VirtualWithSingleProvider4", "provider": "stub/slotted"}

diff --git a/testdata/repos/standalone/profiles/desc/elibc.desc 
b/testdata/repos/standalone/profiles/desc/elibc.desc
new file mode 100644
index 00000000..82a26e2b
--- /dev/null
+++ b/testdata/repos/standalone/profiles/desc/elibc.desc
@@ -0,0 +1 @@
+glibc - ELIBC setting for systems that use the GNU C library

diff --git a/testdata/repos/standalone/profiles/package.deprecated 
b/testdata/repos/standalone/profiles/package.deprecated
new file mode 100644
index 00000000..f3b49d01
--- /dev/null
+++ b/testdata/repos/standalone/profiles/package.deprecated
@@ -0,0 +1 @@
+virtual/VirtualWithSingleProvider5

diff --git 
a/testdata/repos/standalone/virtual/VirtualWithBdepend/VirtualWithBdepend-0.ebuild
 
b/testdata/repos/standalone/virtual/VirtualWithBdepend/VirtualWithBdepend-0.ebuild
new file mode 100644
index 00000000..a34781c9
--- /dev/null
+++ 
b/testdata/repos/standalone/virtual/VirtualWithBdepend/VirtualWithBdepend-0.ebuild
@@ -0,0 +1,6 @@
+EAPI=7
+
+DESCRIPTION="Ebuild with unnecessary DEPEND"
+SLOT="0"
+
+BDEPEND="stub/stub1"

diff --git 
a/testdata/repos/standalone/virtual/VirtualWithBdepend/VirtualWithBdepend-1.ebuild
 
b/testdata/repos/standalone/virtual/VirtualWithBdepend/VirtualWithBdepend-1.ebuild
new file mode 100644
index 00000000..f9f7f891
--- /dev/null
+++ 
b/testdata/repos/standalone/virtual/VirtualWithBdepend/VirtualWithBdepend-1.ebuild
@@ -0,0 +1,11 @@
+EAPI=7
+
+DESCRIPTION="Ebuild with unnecessary DEPEND"
+SLOT="0"
+
+RDEPEND="|| (
+       stub/stub1
+       stub/stub2
+)
+"
+BDEPEND="${RDEPEND}"

diff --git 
a/testdata/repos/standalone/virtual/VirtualWithDepend/VirtualWithDepend-0.ebuild
 
b/testdata/repos/standalone/virtual/VirtualWithDepend/VirtualWithDepend-0.ebuild
new file mode 100644
index 00000000..bc9f2162
--- /dev/null
+++ 
b/testdata/repos/standalone/virtual/VirtualWithDepend/VirtualWithDepend-0.ebuild
@@ -0,0 +1,6 @@
+EAPI=7
+
+DESCRIPTION="Ebuild with unnecessary DEPEND"
+SLOT="0"
+
+DEPEND="stub/stub1"

diff --git 
a/testdata/repos/standalone/virtual/VirtualWithDepend/VirtualWithDepend-1.ebuild
 
b/testdata/repos/standalone/virtual/VirtualWithDepend/VirtualWithDepend-1.ebuild
new file mode 100644
index 00000000..d29f3b42
--- /dev/null
+++ 
b/testdata/repos/standalone/virtual/VirtualWithDepend/VirtualWithDepend-1.ebuild
@@ -0,0 +1,11 @@
+EAPI=7
+
+DESCRIPTION="Ebuild with unnecessary DEPEND"
+SLOT="0"
+
+RDEPEND="|| (
+       stub/stub1
+       stub/stub2
+)
+"
+DEPEND="${RDEPEND}"

diff --git 
a/testdata/repos/standalone/virtual/VirtualWithSingleProvider1/VirtualWithSingleProvider1-0.ebuild
 
b/testdata/repos/standalone/virtual/VirtualWithSingleProvider1/VirtualWithSingleProvider1-0.ebuild
new file mode 100644
index 00000000..7a9a8f34
--- /dev/null
+++ 
b/testdata/repos/standalone/virtual/VirtualWithSingleProvider1/VirtualWithSingleProvider1-0.ebuild
@@ -0,0 +1,10 @@
+EAPI=7
+
+DESCRIPTION="Good virtual with 2 providers"
+SLOT="0"
+
+RDEPEND="|| (
+       stub/stub1
+       stub/stub2
+)
+"

diff --git 
a/testdata/repos/standalone/virtual/VirtualWithSingleProvider2/VirtualWithSingleProvider2-0.ebuild
 
b/testdata/repos/standalone/virtual/VirtualWithSingleProvider2/VirtualWithSingleProvider2-0.ebuild
new file mode 100644
index 00000000..2891a52e
--- /dev/null
+++ 
b/testdata/repos/standalone/virtual/VirtualWithSingleProvider2/VirtualWithSingleProvider2-0.ebuild
@@ -0,0 +1,10 @@
+EAPI=7
+
+DESCRIPTION="Good virtual with 1 provider but different use combinations"
+SLOT="0"
+
+RDEPEND="|| (
+       stub/stub1[matching]
+       stub/stub1[probable]
+)
+"

diff --git 
a/testdata/repos/standalone/virtual/VirtualWithSingleProvider3/VirtualWithSingleProvider3-0.ebuild
 
b/testdata/repos/standalone/virtual/VirtualWithSingleProvider3/VirtualWithSingleProvider3-0.ebuild
new file mode 100644
index 00000000..85b8d702
--- /dev/null
+++ 
b/testdata/repos/standalone/virtual/VirtualWithSingleProvider3/VirtualWithSingleProvider3-0.ebuild
@@ -0,0 +1,8 @@
+EAPI=7
+
+DESCRIPTION="Good virtual with 1 different provider across versions"
+SLOT="0"
+
+RDEPEND="
+       stub/stub1
+"

diff --git 
a/testdata/repos/standalone/virtual/VirtualWithSingleProvider3/VirtualWithSingleProvider3-1.ebuild
 
b/testdata/repos/standalone/virtual/VirtualWithSingleProvider3/VirtualWithSingleProvider3-1.ebuild
new file mode 100644
index 00000000..5655b1ff
--- /dev/null
+++ 
b/testdata/repos/standalone/virtual/VirtualWithSingleProvider3/VirtualWithSingleProvider3-1.ebuild
@@ -0,0 +1,8 @@
+EAPI=7
+
+DESCRIPTION="Good virtual with 1 different provider across versions"
+SLOT="0"
+
+RDEPEND="
+       stub/stub2
+"

diff --git 
a/testdata/repos/standalone/virtual/VirtualWithSingleProvider4/VirtualWithSingleProvider4-0.ebuild
 
b/testdata/repos/standalone/virtual/VirtualWithSingleProvider4/VirtualWithSingleProvider4-0.ebuild
new file mode 100644
index 00000000..e3469bf8
--- /dev/null
+++ 
b/testdata/repos/standalone/virtual/VirtualWithSingleProvider4/VirtualWithSingleProvider4-0.ebuild
@@ -0,0 +1,8 @@
+EAPI=7
+
+DESCRIPTION="Redundant virtual with 1 provider"
+SLOT="1"
+
+RDEPEND="
+       stub/slotted:${SLOT}
+"

diff --git 
a/testdata/repos/standalone/virtual/VirtualWithSingleProvider4/VirtualWithSingleProvider4-1.ebuild
 
b/testdata/repos/standalone/virtual/VirtualWithSingleProvider4/VirtualWithSingleProvider4-1.ebuild
new file mode 100644
index 00000000..e3469bf8
--- /dev/null
+++ 
b/testdata/repos/standalone/virtual/VirtualWithSingleProvider4/VirtualWithSingleProvider4-1.ebuild
@@ -0,0 +1,8 @@
+EAPI=7
+
+DESCRIPTION="Redundant virtual with 1 provider"
+SLOT="1"
+
+RDEPEND="
+       stub/slotted:${SLOT}
+"

diff --git 
a/testdata/repos/standalone/virtual/VirtualWithSingleProvider5/VirtualWithSingleProvider5-0.ebuild
 
b/testdata/repos/standalone/virtual/VirtualWithSingleProvider5/VirtualWithSingleProvider5-0.ebuild
new file mode 100644
index 00000000..e7c2db6b
--- /dev/null
+++ 
b/testdata/repos/standalone/virtual/VirtualWithSingleProvider5/VirtualWithSingleProvider5-0.ebuild
@@ -0,0 +1,8 @@
+EAPI=7
+
+DESCRIPTION="Good virtual with 2 providers"
+SLOT="0"
+
+RDEPEND="
+       stub/stub1
+"

diff --git 
a/testdata/repos/standalone/virtual/VirtualWithSingleProvider6/VirtualWithSingleProvider6-0.ebuild
 
b/testdata/repos/standalone/virtual/VirtualWithSingleProvider6/VirtualWithSingleProvider6-0.ebuild
new file mode 100644
index 00000000..0f874ab4
--- /dev/null
+++ 
b/testdata/repos/standalone/virtual/VirtualWithSingleProvider6/VirtualWithSingleProvider6-0.ebuild
@@ -0,0 +1,9 @@
+EAPI=7
+
+DESCRIPTION="virtual with 1 provider, but behind special use flags"
+SLOT="0"
+IUSE="elibc_glibc"
+
+RDEPEND="
+       !elibc_glibc? ( stub/stub1 )
+"

Reply via email to