commit:     e9a8c4094584ae23fd5921098105a94a1a81d60e
Author:     Arthur Zamarin <arthurzam <AT> gentoo <DOT> org>
AuthorDate: Wed Aug 30 17:23:06 2023 +0000
Commit:     Arthur Zamarin <arthurzam <AT> gentoo <DOT> org>
CommitDate: Fri Sep  1 08:18:36 2023 +0000
URL:        
https://gitweb.gentoo.org/proj/pkgcore/pkgcheck.git/commit/?id=e9a8c409

EclassManualDepsCheck: add check for missing manual deps

When in special modes of eclasses (for example CARGO_OPTIONAL=1), verify
specific dependencies are listed somehow in one of the dependencies var.

Resolves: https://github.com/pkgcore/pkgcheck/issues/615
Signed-off-by: Arthur Zamarin <arthurzam <AT> gentoo.org>

 src/pkgcheck/checks/eclass.py                      | 92 ++++++++++++++++++++++
 .../GoMissingDeps/expected.json                    |  1 +
 .../RubyMissingDeps/expected.json                  |  1 +
 .../RubyMissingDeps/fix.patch                      |  9 +++
 .../RustMissingDeps/expected.json                  |  1 +
 .../RustMissingDeps/fix.patch                      |  9 +++
 .../RubyMissingDeps/RubyMissingDeps-0.ebuild       | 12 +++
 .../RubyMissingDeps/RubyMissingDeps-1.ebuild       |  8 ++
 .../RubyMissingDeps/RubyMissingDeps-2.ebuild       | 14 ++++
 .../RustMissingDeps/RustMissingDeps-0.ebuild       |  6 ++
 .../RustMissingDeps/RustMissingDeps-1.ebuild       | 10 +++
 .../repos/standalone/dev-lang/ruby/ruby-0.ebuild   |  4 +
 .../repos/standalone/dev-ruby/stub/stub-0.ebuild   |  4 +
 testdata/repos/standalone/eclass/ruby-ng.eclass    |  1 +
 .../standalone/virtual/rubygems/rubygems-0.ebuild  |  2 +
 .../repos/standalone/virtual/rust/rust-0.ebuild    |  2 +
 16 files changed, 176 insertions(+)

diff --git a/src/pkgcheck/checks/eclass.py b/src/pkgcheck/checks/eclass.py
index 935ed960..394ef192 100644
--- a/src/pkgcheck/checks/eclass.py
+++ b/src/pkgcheck/checks/eclass.py
@@ -3,8 +3,10 @@ import subprocess
 from collections import defaultdict
 from functools import partial
 
+from pkgcore.ebuild.atom import atom as atom_cls
 from pkgcore.ebuild.eapi import EAPI
 from pkgcore.ebuild.eclass import EclassDoc
+from snakeoil.sequences import iflatten_instance
 from snakeoil.strings import pluralism
 
 from .. import addons, bash, results, sources
@@ -498,3 +500,93 @@ class EclassCheck(Check):
         )
         if vars_missing_docs:
             yield EclassDocMissingVar(sorted(vars_missing_docs), eclass=eclass)
+
+
+class GoMissingDeps(results.VersionResult, results.Warning):
+    """Package sets ``GO_OPTIONAL`` but does not depend on ``dev-lang/go``."""
+
+    desc = "sets GO_OPTIONAL but does not depend on dev-lang/go"
+
+
+class RubyMissingDeps(results.VersionResult, results.Warning):
+    """Package sets ``RUBY_OPTIONAL`` but does not depend on ``dev-lang/ruby``
+    or ``virtual/rubygems``."""
+
+    desc = "sets RUBY_OPTIONAL but does not depend on dev-lang/ruby or 
virtual/rubygems"
+
+
+class RustMissingDeps(results.VersionResult, results.Warning):
+    """Package sets ``CARGO_OPTIONAL`` but does not depend on 
``virtual/rust``."""
+
+    desc = "sets CARGO_OPTIONAL but does not depend on virtual/rust"
+
+
+class TmpfilesMissingDeps(results.VersionResult, results.Warning):
+    """Package sets ``TMPFILES_OPTIONAL`` but does not depend on 
``virtual/tmpfiles``."""
+
+    desc = "sets TMPFILES_OPTIONAL but does not depend on virtual/tmpfiles"
+
+
+class EclassManualDepsCheck(Check):
+    """Check for missing deps when inheriting eclasses in special mode."""
+
+    _source = sources.EbuildParseRepoSource
+    known_results = frozenset(
+        {
+            GoMissingDeps,
+            RustMissingDeps,
+            RubyMissingDeps,
+            TmpfilesMissingDeps,
+        }
+    )
+
+    dependencies = (
+        # eclass, variable, one of deps, class
+        ("cargo", "CARGO_OPTIONAL", {"virtual/rust"}, RustMissingDeps),
+        ("go-module", "GO_OPTIONAL", {"dev-lang/go"}, GoMissingDeps),
+        (
+            "ruby-ng",
+            "RUBY_OPTIONAL",
+            {"dev-lang/ruby", "virtual/rubygems", "dev-ruby"},
+            RubyMissingDeps,
+        ),
+        ("tmpfiles", "TMPFILES_OPTIONAL", {"virtual/tmpfiles"}, 
TmpfilesMissingDeps),
+    )
+
+    def __init__(self, options, **kwargs):
+        super().__init__(options, **kwargs)
+
+        self.queries_by_eclass = defaultdict(list)
+        for eclass, variable, deps, cls in self.dependencies:
+            pkgs = frozenset({x for x in deps if "/" in x})
+            categories = frozenset({x for x in deps if "/" not in x})
+            self.queries_by_eclass[eclass].append(
+                (
+                    bash.query(
+                        # has variable assignment to a variable named
+                        f'(variable_assignment name: (variable_name) @name 
(.eq? @name "{variable}"))'
+                    ),
+                    pkgs,
+                    categories,
+                    cls,
+                )
+            )
+
+    def feed(self, pkg: bash.ParseTree):
+        for eclass, queries in self.queries_by_eclass.items():
+            if eclass not in pkg.inherited:
+                continue
+            for query, pkgs, categories, cls in queries:
+                # is the variable assigned in global scope
+                try:
+                    next(pkg.global_query(query))
+                except StopIteration:
+                    continue
+
+                # does any dep attr have any of the deps
+                if all(
+                    atom.key not in pkgs and atom.category not in categories
+                    for attr in pkg.eapi.dep_keys
+                    for atom in iflatten_instance(getattr(pkg, attr.lower()), 
atom_cls)
+                ):
+                    yield cls(pkg)

diff --git 
a/testdata/data/repos/standalone/EclassManualDepsCheck/GoMissingDeps/expected.json
 
b/testdata/data/repos/standalone/EclassManualDepsCheck/GoMissingDeps/expected.json
new file mode 100644
index 00000000..a2e61bca
--- /dev/null
+++ 
b/testdata/data/repos/standalone/EclassManualDepsCheck/GoMissingDeps/expected.json
@@ -0,0 +1 @@
+{"__class__": "GoMissingDeps", "category": "EclassUsageCheck", "package": 
"DeprecatedEclassVariable", "version": "0"}

diff --git 
a/testdata/data/repos/standalone/EclassManualDepsCheck/RubyMissingDeps/expected.json
 
b/testdata/data/repos/standalone/EclassManualDepsCheck/RubyMissingDeps/expected.json
new file mode 100644
index 00000000..94c44a0e
--- /dev/null
+++ 
b/testdata/data/repos/standalone/EclassManualDepsCheck/RubyMissingDeps/expected.json
@@ -0,0 +1 @@
+{"__class__": "RubyMissingDeps", "category": "EclassManualDepsCheck", 
"package": "RubyMissingDeps", "version": "1"}

diff --git 
a/testdata/data/repos/standalone/EclassManualDepsCheck/RubyMissingDeps/fix.patch
 
b/testdata/data/repos/standalone/EclassManualDepsCheck/RubyMissingDeps/fix.patch
new file mode 100644
index 00000000..40c816d3
--- /dev/null
+++ 
b/testdata/data/repos/standalone/EclassManualDepsCheck/RubyMissingDeps/fix.patch
@@ -0,0 +1,9 @@
+diff -Naur 
standalone/EclassManualDepsCheck/RubyMissingDeps/RubyMissingDeps-1.ebuild 
fixed/EclassManualDepsCheck/RubyMissingDeps/RubyMissingDeps-1.ebuild
+--- standalone/EclassManualDepsCheck/RubyMissingDeps/RubyMissingDeps-1.ebuild
++++ fixed/EclassManualDepsCheck/RubyMissingDeps/RubyMissingDeps-1.ebuild
+@@ -6,3 +6,5 @@ DESCRIPTION="Optional inherit without dep"
+ HOMEPAGE="https://github.com/pkgcore/pkgcheck";
+ SLOT="0"
+ LICENSE="BSD"
++
++DEPEND="virtual/rubygems"

diff --git 
a/testdata/data/repos/standalone/EclassManualDepsCheck/RustMissingDeps/expected.json
 
b/testdata/data/repos/standalone/EclassManualDepsCheck/RustMissingDeps/expected.json
new file mode 100644
index 00000000..43be8d93
--- /dev/null
+++ 
b/testdata/data/repos/standalone/EclassManualDepsCheck/RustMissingDeps/expected.json
@@ -0,0 +1 @@
+{"__class__": "RustMissingDeps", "category": "EclassManualDepsCheck", 
"package": "RustMissingDeps", "version": "1"}

diff --git 
a/testdata/data/repos/standalone/EclassManualDepsCheck/RustMissingDeps/fix.patch
 
b/testdata/data/repos/standalone/EclassManualDepsCheck/RustMissingDeps/fix.patch
new file mode 100644
index 00000000..a62eb390
--- /dev/null
+++ 
b/testdata/data/repos/standalone/EclassManualDepsCheck/RustMissingDeps/fix.patch
@@ -0,0 +1,9 @@
+diff -Naur 
standalone/EclassManualDepsCheck/RustMissingDeps/RustMissingDeps-1.ebuild 
fixed/EclassManualDepsCheck/RustMissingDeps/RustMissingDeps-1.ebuild
+--- standalone/EclassManualDepsCheck/RustMissingDeps/RustMissingDeps-1.ebuild
++++ fixed/EclassManualDepsCheck/RustMissingDeps/RustMissingDeps-1.ebuild
+@@ -8,3 +8,5 @@ DESCRIPTION="Optional inherit without deps"
+ HOMEPAGE="https://github.com/pkgcore/pkgcheck";
+ SLOT="0"
+ LICENSE="BSD"
++
++BDEPEND="virtual/rust"

diff --git 
a/testdata/repos/standalone/EclassManualDepsCheck/RubyMissingDeps/RubyMissingDeps-0.ebuild
 
b/testdata/repos/standalone/EclassManualDepsCheck/RubyMissingDeps/RubyMissingDeps-0.ebuild
new file mode 100644
index 00000000..aaf1acd0
--- /dev/null
+++ 
b/testdata/repos/standalone/EclassManualDepsCheck/RubyMissingDeps/RubyMissingDeps-0.ebuild
@@ -0,0 +1,12 @@
+EAPI=8
+
+RUBY_OPTIONAL=1
+
+inherit ruby-ng
+
+DESCRIPTION="Optional inherit with one dep"
+HOMEPAGE="https://github.com/pkgcore/pkgcheck";
+SLOT="0"
+LICENSE="BSD"
+
+IDEPEND="dev-lang/ruby"

diff --git 
a/testdata/repos/standalone/EclassManualDepsCheck/RubyMissingDeps/RubyMissingDeps-1.ebuild
 
b/testdata/repos/standalone/EclassManualDepsCheck/RubyMissingDeps/RubyMissingDeps-1.ebuild
new file mode 100644
index 00000000..aba69b0b
--- /dev/null
+++ 
b/testdata/repos/standalone/EclassManualDepsCheck/RubyMissingDeps/RubyMissingDeps-1.ebuild
@@ -0,0 +1,8 @@
+RUBY_OPTIONAL=1
+
+inherit ruby-ng
+
+DESCRIPTION="Optional inherit without dep"
+HOMEPAGE="https://github.com/pkgcore/pkgcheck";
+SLOT="0"
+LICENSE="BSD"

diff --git 
a/testdata/repos/standalone/EclassManualDepsCheck/RubyMissingDeps/RubyMissingDeps-2.ebuild
 
b/testdata/repos/standalone/EclassManualDepsCheck/RubyMissingDeps/RubyMissingDeps-2.ebuild
new file mode 100644
index 00000000..04bab5d8
--- /dev/null
+++ 
b/testdata/repos/standalone/EclassManualDepsCheck/RubyMissingDeps/RubyMissingDeps-2.ebuild
@@ -0,0 +1,14 @@
+EAPI=8
+
+RUBY_OPTIONAL=1
+
+inherit ruby-ng
+
+DESCRIPTION="Optional inherit with category whitelist"
+HOMEPAGE="https://github.com/pkgcore/pkgcheck";
+SLOT="0"
+LICENSE="BSD"
+
+IUSE="test"
+RESTRICT="!test? ( test )"
+BDEPEND="test? ( dev-ruby/stub )"

diff --git 
a/testdata/repos/standalone/EclassManualDepsCheck/RustMissingDeps/RustMissingDeps-0.ebuild
 
b/testdata/repos/standalone/EclassManualDepsCheck/RustMissingDeps/RustMissingDeps-0.ebuild
new file mode 100644
index 00000000..2b453030
--- /dev/null
+++ 
b/testdata/repos/standalone/EclassManualDepsCheck/RustMissingDeps/RustMissingDeps-0.ebuild
@@ -0,0 +1,6 @@
+inherit cargo
+
+DESCRIPTION="Normal non-optional inherit"
+HOMEPAGE="https://github.com/pkgcore/pkgcheck";
+SLOT="0"
+LICENSE="BSD"

diff --git 
a/testdata/repos/standalone/EclassManualDepsCheck/RustMissingDeps/RustMissingDeps-1.ebuild
 
b/testdata/repos/standalone/EclassManualDepsCheck/RustMissingDeps/RustMissingDeps-1.ebuild
new file mode 100644
index 00000000..b43ff1b4
--- /dev/null
+++ 
b/testdata/repos/standalone/EclassManualDepsCheck/RustMissingDeps/RustMissingDeps-1.ebuild
@@ -0,0 +1,10 @@
+EAPI=7
+
+CARGO_OPTIONAL=1
+
+inherit cargo
+
+DESCRIPTION="Optional inherit without deps"
+HOMEPAGE="https://github.com/pkgcore/pkgcheck";
+SLOT="0"
+LICENSE="BSD"

diff --git a/testdata/repos/standalone/dev-lang/ruby/ruby-0.ebuild 
b/testdata/repos/standalone/dev-lang/ruby/ruby-0.ebuild
new file mode 100644
index 00000000..ba6aebb4
--- /dev/null
+++ b/testdata/repos/standalone/dev-lang/ruby/ruby-0.ebuild
@@ -0,0 +1,4 @@
+DESCRIPTION="Stub ebuild"
+HOMEPAGE="https://github.com/pkgcore/pkgcheck";
+SLOT="0"
+LICENSE="BSD"

diff --git a/testdata/repos/standalone/dev-ruby/stub/stub-0.ebuild 
b/testdata/repos/standalone/dev-ruby/stub/stub-0.ebuild
new file mode 100644
index 00000000..ba6aebb4
--- /dev/null
+++ b/testdata/repos/standalone/dev-ruby/stub/stub-0.ebuild
@@ -0,0 +1,4 @@
+DESCRIPTION="Stub ebuild"
+HOMEPAGE="https://github.com/pkgcore/pkgcheck";
+SLOT="0"
+LICENSE="BSD"

diff --git a/testdata/repos/standalone/eclass/ruby-ng.eclass 
b/testdata/repos/standalone/eclass/ruby-ng.eclass
new file mode 100644
index 00000000..5b2b9973
--- /dev/null
+++ b/testdata/repos/standalone/eclass/ruby-ng.eclass
@@ -0,0 +1 @@
+# ruby-ng eclass

diff --git a/testdata/repos/standalone/virtual/rubygems/rubygems-0.ebuild 
b/testdata/repos/standalone/virtual/rubygems/rubygems-0.ebuild
new file mode 100644
index 00000000..9c2ce2e9
--- /dev/null
+++ b/testdata/repos/standalone/virtual/rubygems/rubygems-0.ebuild
@@ -0,0 +1,2 @@
+DESCRIPTION="Stub ebuild"
+SLOT="0"

diff --git a/testdata/repos/standalone/virtual/rust/rust-0.ebuild 
b/testdata/repos/standalone/virtual/rust/rust-0.ebuild
new file mode 100644
index 00000000..9c2ce2e9
--- /dev/null
+++ b/testdata/repos/standalone/virtual/rust/rust-0.ebuild
@@ -0,0 +1,2 @@
+DESCRIPTION="Stub ebuild"
+SLOT="0"

Reply via email to