aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArthur Zamarin <arthurzam@gentoo.org>2022-12-30 21:27:23 +0200
committerArthur Zamarin <arthurzam@gentoo.org>2023-01-02 22:11:43 +0200
commit4247e10d9c266ac1f6aac48b0c67f1092dde1d78 (patch)
tree4be9e3e3905f5b8f3747072cafd4f4e30f1a59f3
parenttest_pkgcheck_replay: fix test_replay_pipe_stdin from sdist (diff)
downloadpkgcheck-4247e10d.tar.gz
pkgcheck-4247e10d.tar.bz2
pkgcheck-4247e10d.zip
ProvidedEclassInherit: new check for inheriting provided eclases
Resolves: https://github.com/pkgcore/pkgcheck/issues/504 Signed-off-by: Arthur Zamarin <arthurzam@gentoo.org>
-rw-r--r--src/pkgcheck/checks/eclass.py103
-rw-r--r--testdata/data/repos/eclass/EclassUsageCheck/ProvidedEclassInherit/expected.json1
-rw-r--r--testdata/data/repos/eclass/EclassUsageCheck/ProvidedEclassInherit/fix.patch10
-rw-r--r--testdata/repos/eclass/EclassUsageCheck/ProvidedEclassInherit/ProvidedEclassInherit-0.ebuild11
4 files changed, 93 insertions, 32 deletions
diff --git a/src/pkgcheck/checks/eclass.py b/src/pkgcheck/checks/eclass.py
index 5c4f205f..862dbb91 100644
--- a/src/pkgcheck/checks/eclass.py
+++ b/src/pkgcheck/checks/eclass.py
@@ -98,18 +98,36 @@ class MisplacedEclassVar(results.LineResult, results.Error):
return f"invalid pre-inherit placement, line {self.lineno}: {self.line!r}"
+class ProvidedEclassInherit(results.LineResult, results.Style):
+ """Ebuild inherits an eclass which is already provided by another eclass.
+
+ When inheriting an eclass which declares ``@PROVIDES``, those referenced
+ eclasses are guaranteed to be provided by the eclass. Therefore, inheriting
+ them in ebuilds is redundant and should be removed.
+ """
+
+ def __init__(self, provider, **kwargs):
+ super().__init__(**kwargs)
+ self.provider = provider
+
+ @property
+ def desc(self):
+ return f"line {self.lineno}: redundant eclass inherit {self.line!r}, provided by {self.provider!r}"
+
+
class EclassUsageCheck(Check):
"""Scan packages for various eclass-related issues."""
_source = sources.EbuildParseRepoSource
known_results = frozenset(
- [
+ {
DeprecatedEclass,
DeprecatedEclassVariable,
DeprecatedEclassFunction,
DuplicateEclassInherit,
MisplacedEclassVar,
- ]
+ ProvidedEclassInherit,
+ }
)
required_addons = (addons.eclass.EclassAddon,)
@@ -118,15 +136,16 @@ class EclassUsageCheck(Check):
self.deprecated_eclasses = eclass_addon.deprecated
self.eclass_cache = eclass_addon.eclasses
- def check_pre_inherits(self, pkg, inherits):
+ def check_pre_inherits(self, pkg, inherits: list[tuple[list[str], int]]):
"""Check for invalid @PRE_INHERIT variable placement."""
- pre_inherits = {}
# determine if any inherited eclasses have @PRE_INHERIT variables
- for eclasses, lineno in inherits:
- for eclass in eclasses:
- for var in self.eclass_cache[eclass].variables:
- if var.pre_inherit:
- pre_inherits[var.name] = lineno
+ pre_inherits = {
+ var.name: lineno
+ for eclasses, lineno in inherits
+ for eclass in eclasses
+ for var in self.eclass_cache[eclass].variables
+ if var.pre_inherit
+ }
# scan for any misplaced @PRE_INHERIT variables
if pre_inherits:
@@ -137,22 +156,23 @@ class EclassUsageCheck(Check):
line = pkg.node_str(node)
yield MisplacedEclassVar(var_name, line=line, lineno=lineno + 1, pkg=pkg)
- def check_deprecated_variables(self, pkg, inherits):
- """Check for usage of @DEPRECATED variables or functions."""
- deprecated = {}
+ def check_deprecated_variables(self, pkg, inherits: list[tuple[list[str], int]]):
+ """Check for usage of @DEPRECATED variables."""
# determine if any inherited eclasses have @DEPRECATED variables
- for eclasses, _ in inherits:
- for eclass in eclasses:
- for var in self.eclass_cache[eclass].variables:
- if var.deprecated:
- deprecated[var.name] = var.deprecated
+ deprecated = {
+ var.name: var.deprecated
+ for eclasses, _ in inherits
+ for eclass in eclasses
+ for var in self.eclass_cache[eclass].variables
+ if var.deprecated
+ }
# scan for usage of @DEPRECATED variables
if deprecated:
for node, _ in bash.var_query.captures(pkg.tree.root_node):
var_name = pkg.node_str(node)
- lineno, _colno = node.start_point
if var_name in deprecated:
+ lineno, _colno = node.start_point
line = pkg.node_str(node)
replacement = deprecated[var_name]
if not isinstance(replacement, str):
@@ -161,22 +181,23 @@ class EclassUsageCheck(Check):
var_name, replacement, line=line, lineno=lineno + 1, pkg=pkg
)
- def check_deprecated_functions(self, pkg, inherits):
- """Check for usage of @DEPRECATED variables or functions."""
- deprecated = {}
- # determine if any inherited eclasses have @DEPRECATED variables or functions
- for eclasses, _ in inherits:
- for eclass in eclasses:
- for func in self.eclass_cache[eclass].functions:
- if func.deprecated:
- deprecated[func.name] = func.deprecated
+ def check_deprecated_functions(self, pkg, inherits: list[tuple[list[str], int]]):
+ """Check for usage of @DEPRECATED functions."""
+ # determine if any inherited eclasses have @DEPRECATED functions
+ deprecated = {
+ func.name: func.deprecated
+ for eclasses, _ in inherits
+ for eclass in eclasses
+ for func in self.eclass_cache[eclass].functions
+ if func.deprecated
+ }
# scan for usage of @DEPRECATED functions
if deprecated:
for node, _ in bash.cmd_query.captures(pkg.tree.root_node):
func_name = pkg.node_str(node.child_by_field_name("name"))
- lineno, _colno = node.start_point
if func_name in deprecated:
+ lineno, _colno = node.start_point
line = pkg.node_str(node)
replacement = deprecated[func_name]
if not isinstance(replacement, str):
@@ -185,10 +206,22 @@ class EclassUsageCheck(Check):
func_name, replacement, line=line, lineno=lineno + 1, pkg=pkg
)
+ def check_provided_eclasses(self, pkg, inherits: list[tuple[list[str], int]]):
+ """Check for usage of eclasses (i.e. redundant inherits) that are
+ provided by another inherited eclass."""
+ provided_eclasses = {
+ provided: (eclass, lineno + 1)
+ for eclasses, lineno in inherits
+ for eclass in eclasses
+ for provided in pkg.inherit.intersection(self.eclass_cache[eclass].provides)
+ }
+ for provided, (eclass, lineno) in provided_eclasses.items():
+ yield ProvidedEclassInherit(eclass, pkg=pkg, line=provided, lineno=lineno)
+
def feed(self, pkg):
if pkg.inherit:
inherited = set()
- inherits = []
+ inherits: list[tuple[list[str], int]] = []
for node, _ in bash.cmd_query.captures(pkg.tree.root_node):
name = pkg.node_str(node.child_by_field_name("name"))
if name == "inherit":
@@ -207,6 +240,7 @@ class EclassUsageCheck(Check):
eclass, line=call, lineno=lineno + 1, pkg=pkg
)
+ yield from self.check_provided_eclasses(pkg, inherits)
# verify @PRE_INHERIT variable placement
yield from self.check_pre_inherits(pkg, inherits)
# verify @DEPRECATED variables or functions
@@ -281,7 +315,7 @@ class EclassParseCheck(Check):
for var_node, _ in bash.var_query.captures(func_node):
var_name = eclass.node_str(var_node)
if var_name in variables:
- lineno, colno = var_node.start_point
+ lineno, _colno = var_node.start_point
usage[var_name].add(lineno + 1)
for var, lines in sorted(usage.items()):
yield EclassVariableScope(
@@ -369,7 +403,12 @@ class EclassCheck(Check):
_source = sources.EclassRepoSource
known_results = frozenset(
- [EclassBashSyntaxError, EclassDocError, EclassDocMissingFunc, EclassDocMissingVar]
+ [
+ EclassBashSyntaxError,
+ EclassDocError,
+ EclassDocMissingFunc,
+ EclassDocMissingVar,
+ ]
)
def __init__(self, *args):
@@ -393,7 +432,7 @@ class EclassCheck(Check):
lineno = 0
error = []
for line in p.stderr.splitlines():
- path, line, msg = line.split(": ", 2)
+ _path, line, msg = line.split(": ", 2)
lineno = line[5:]
error.append(msg.strip("\n"))
error = ": ".join(error)
diff --git a/testdata/data/repos/eclass/EclassUsageCheck/ProvidedEclassInherit/expected.json b/testdata/data/repos/eclass/EclassUsageCheck/ProvidedEclassInherit/expected.json
new file mode 100644
index 00000000..397c0644
--- /dev/null
+++ b/testdata/data/repos/eclass/EclassUsageCheck/ProvidedEclassInherit/expected.json
@@ -0,0 +1 @@
+{"__class__": "ProvidedEclassInherit", "category": "EclassUsageCheck", "package": "ProvidedEclassInherit", "version": "0", "line": "inherit", "lineno": 2, "provider": "deep-provided-inherit"}
diff --git a/testdata/data/repos/eclass/EclassUsageCheck/ProvidedEclassInherit/fix.patch b/testdata/data/repos/eclass/EclassUsageCheck/ProvidedEclassInherit/fix.patch
new file mode 100644
index 00000000..607e8caf
--- /dev/null
+++ b/testdata/data/repos/eclass/EclassUsageCheck/ProvidedEclassInherit/fix.patch
@@ -0,0 +1,10 @@
+diff -Naur eclass/EclassUsageCheck/ProvidedEclassInherit/ProvidedEclassInherit-0.ebuild fixed/EclassUsageCheck/ProvidedEclassInherit/ProvidedEclassInherit-0.ebuild
+--- eclass/EclassUsageCheck/ProvidedEclassInherit/ProvidedEclassInherit-0.ebuild 2021-05-23 20:23:16.423009026 -0600
++++ fixed/EclassUsageCheck/ProvidedEclassInherit/ProvidedEclassInherit-0.ebuild 2021-05-23 20:23:43.734588313 -0600
+@@ -1,5 +1,5 @@
+ EAPI=7
+-inherit inherit deep-provided-inherit
++inherit deep-provided-inherit
+ DESCRIPTION="Ebuild inheriting provided eclass"
+ HOMEPAGE="https://github.com/pkgcore/pkgcheck"
+ SLOT="0"
diff --git a/testdata/repos/eclass/EclassUsageCheck/ProvidedEclassInherit/ProvidedEclassInherit-0.ebuild b/testdata/repos/eclass/EclassUsageCheck/ProvidedEclassInherit/ProvidedEclassInherit-0.ebuild
new file mode 100644
index 00000000..cd8585ea
--- /dev/null
+++ b/testdata/repos/eclass/EclassUsageCheck/ProvidedEclassInherit/ProvidedEclassInherit-0.ebuild
@@ -0,0 +1,11 @@
+EAPI=7
+inherit inherit deep-provided-inherit
+DESCRIPTION="Ebuild inheriting provided eclass"
+HOMEPAGE="https://github.com/pkgcore/pkgcheck"
+SLOT="0"
+LICENSE="BSD"
+
+src_prepare() {
+ inherit_public_func
+ deep-provided-inherit_public_func
+}