From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lists.gentoo.org (pigeon.gentoo.org [208.92.234.80]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by finch.gentoo.org (Postfix) with ESMTPS id 6162515800F for ; Mon, 2 Jan 2023 20:19:07 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id 7D48EE0858; Mon, 2 Jan 2023 20:19:06 +0000 (UTC) Received: from smtp.gentoo.org (woodpecker.gentoo.org [140.211.166.183]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id 5974FE0858 for ; Mon, 2 Jan 2023 20:19:06 +0000 (UTC) Received: from oystercatcher.gentoo.org (oystercatcher.gentoo.org [148.251.78.52]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id 0DE7F340CF1 for ; Mon, 2 Jan 2023 20:19:05 +0000 (UTC) Received: from localhost.localdomain (localhost [IPv6:::1]) by oystercatcher.gentoo.org (Postfix) with ESMTP id 31A3772B for ; Mon, 2 Jan 2023 20:19:03 +0000 (UTC) From: "Arthur Zamarin" To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "Arthur Zamarin" Message-ID: <1672690303.4247e10d9c266ac1f6aac48b0c67f1092dde1d78.arthurzam@gentoo> Subject: [gentoo-commits] proj/pkgcore/pkgcheck:master commit in: src/pkgcheck/checks/, ... X-VCS-Repository: proj/pkgcore/pkgcheck X-VCS-Files: src/pkgcheck/checks/eclass.py testdata/data/repos/eclass/EclassUsageCheck/ProvidedEclassInherit/expected.json testdata/data/repos/eclass/EclassUsageCheck/ProvidedEclassInherit/fix.patch testdata/repos/eclass/EclassUsageCheck/ProvidedEclassInherit/ProvidedEclassInherit-0.ebuild X-VCS-Directories: testdata/data/repos/eclass/EclassUsageCheck/ProvidedEclassInherit/ testdata/repos/eclass/EclassUsageCheck/ProvidedEclassInherit/ src/pkgcheck/checks/ X-VCS-Committer: arthurzam X-VCS-Committer-Name: Arthur Zamarin X-VCS-Revision: 4247e10d9c266ac1f6aac48b0c67f1092dde1d78 X-VCS-Branch: master Date: Mon, 2 Jan 2023 20:19:03 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org X-Auto-Response-Suppress: DR, RN, NRN, OOF, AutoReply X-Archives-Salt: 74e3192f-0874-4974-b970-4e722bcaed63 X-Archives-Hash: 82396f578b2bf703e162cd38239cf00e commit: 4247e10d9c266ac1f6aac48b0c67f1092dde1d78 Author: Arthur Zamarin gentoo org> AuthorDate: Fri Dec 30 19:27:23 2022 +0000 Commit: Arthur Zamarin gentoo org> CommitDate: Mon Jan 2 20:11:43 2023 +0000 URL: https://gitweb.gentoo.org/proj/pkgcore/pkgcheck.git/commit/?id=4247e10d ProvidedEclassInherit: new check for inheriting provided eclases Resolves: https://github.com/pkgcore/pkgcheck/issues/504 Signed-off-by: Arthur Zamarin gentoo.org> src/pkgcheck/checks/eclass.py | 103 ++++++++++++++------- .../ProvidedEclassInherit/expected.json | 1 + .../ProvidedEclassInherit/fix.patch | 10 ++ .../ProvidedEclassInherit-0.ebuild | 11 +++ 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 +}