diff --git a/src/pkgcheck/checks/rust.py b/src/pkgcheck/checks/rust.py new file mode 100644 index 000000000..1a5e67701 --- /dev/null +++ b/src/pkgcheck/checks/rust.py @@ -0,0 +1,86 @@ +from .. import bash, results, sources +from . import Check + + +class SuboptimalCratesSeparator(results.LineResult, results.Warning): + """Using ``-`` as name-version separator in ``CRATES`` is suboptimal. + + The ``CRATES`` variable is a space separated list of crates. The eclass + supports specifying the crate name and version as ``name@version`` and as + ``name-version``. The latter is suboptimal as it's slower. + + It is recommended to use ``pycargoebuild`` 0.7+ to generate new ``CRATES``. + """ + + @property + def desc(self): + return f"line: {self.lineno}: using - as name-version separator in CRATES is suboptimal, use name@version instead" + + +class SuboptimalCratesURICall(results.LineResult, results.Warning): + """Calling ``cargo_crate_uris`` with ``CRATES`` is suboptimal, use + ``${CARGO_CRATE_URIS}``. + + Calls to ``$(cargo_crate_uris)`` and ``$(cargo_crate_uris ${CRATES})`` are + suboptimal, and can be replaces with ``${CARGO_CRATE_URIS}`` which is + pre-computed, faster and doesn't require sub-shell in global-scope. + """ + + @property + def desc(self): + return f"line: {self.lineno}: calling {self.line!r} is suboptimal, use '${{CARGO_CRATE_URIS}}' for global CRATES instead" + + +class RustCheck(Check): + """Checks for rust related issues.""" + + _source = sources.EbuildParseRepoSource + known_results = frozenset( + { + SuboptimalCratesSeparator, + SuboptimalCratesURICall, + } + ) + + def _verify_crates(self, pkg: bash.ParseTree): + for node in pkg.global_query(bash.var_assign_query): + name = pkg.node_str(node.child_by_field_name("name")) + if name == "CRATES": + val_node = node.children[-1] + row, _ = val_node.start_point + val_str = pkg.node_str(val_node).strip("'\"") + for lineno, line in enumerate(val_str.splitlines(), start=row + 1): + for token in line.split(): + if "@" not in token: + yield SuboptimalCratesSeparator( + lineno=lineno, + line=token, + pkg=pkg, + ) + return + + def _verify_cargo_crate_uris(self, pkg: bash.ParseTree): + for node, _ in bash.cmd_query.captures(pkg.tree.root_node): + call_name = pkg.node_str(node.child_by_field_name("name")) + if call_name == "cargo_crate_uris": + row, _ = node.start_point + line = pkg.node_str(node.parent) + if node.child_count == 1 or ( + node.child_count == 2 + and any( + pkg.node_str(var_node) == "CRATES" + for var_node, _ in bash.var_query.captures(node.children[1]) + ) + ): + yield SuboptimalCratesURICall( + lineno=row + 1, + line=line, + pkg=pkg, + ) + break + + def feed(self, pkg: bash.ParseTree): + if "cargo" not in pkg.inherited: + return + yield from self._verify_crates(pkg) + yield from self._verify_cargo_crate_uris(pkg) diff --git a/testdata/data/repos/standalone/RustCheck/SuboptimalCratesSeparator/expected.json b/testdata/data/repos/standalone/RustCheck/SuboptimalCratesSeparator/expected.json new file mode 100644 index 000000000..8e5796574 --- /dev/null +++ b/testdata/data/repos/standalone/RustCheck/SuboptimalCratesSeparator/expected.json @@ -0,0 +1 @@ +{"__class__": "SuboptimalCratesSeparator", "category": "RustCheck", "package": "SuboptimalCratesSeparator", "version": "0", "line": "snakeoil-0.10.0", "lineno": 2} diff --git a/testdata/data/repos/standalone/RustCheck/SuboptimalCratesSeparator/fix.patch b/testdata/data/repos/standalone/RustCheck/SuboptimalCratesSeparator/fix.patch new file mode 100644 index 000000000..e400178cc --- /dev/null +++ b/testdata/data/repos/standalone/RustCheck/SuboptimalCratesSeparator/fix.patch @@ -0,0 +1,14 @@ +diff -Naur standalone/RustCheck/SuboptimalCratesSeparator/SuboptimalCratesSeparator-0.ebuild fixed/RustCheck/SuboptimalCratesSeparator/SuboptimalCratesSeparator-0.ebuild +--- standalone/RustCheck/SuboptimalCratesSeparator/SuboptimalCratesSeparator-0.ebuild ++++ fixed/RustCheck/SuboptimalCratesSeparator/SuboptimalCratesSeparator-0.ebuild +@@ -1,7 +1,7 @@ + CRATES=" +- random@0.10.0 snakeoil-0.10.0 +- pkgcore-0.10.0 +- pkgcheck-0.10.0 ++ random@0.10.0 snakeoil@0.10.0 ++ pkgcore@0.10.0 ++ pkgcheck@0.10.0 + " + + inherit cargo diff --git a/testdata/data/repos/standalone/RustCheck/SuboptimalCratesURICall/expected.json b/testdata/data/repos/standalone/RustCheck/SuboptimalCratesURICall/expected.json new file mode 100644 index 000000000..a5b216187 --- /dev/null +++ b/testdata/data/repos/standalone/RustCheck/SuboptimalCratesURICall/expected.json @@ -0,0 +1,2 @@ +{"__class__": "SuboptimalCratesURICall", "category": "RustCheck", "package": "SuboptimalCratesURICall", "version": "0", "line": "$(cargo_crate_uris)", "lineno": 13} +{"__class__": "SuboptimalCratesURICall", "category": "RustCheck", "package": "SuboptimalCratesURICall", "version": "1", "line": "$(cargo_crate_uris ${CRATES})", "lineno": 13} diff --git a/testdata/data/repos/standalone/RustCheck/SuboptimalCratesURICall/fix.patch b/testdata/data/repos/standalone/RustCheck/SuboptimalCratesURICall/fix.patch new file mode 100644 index 000000000..6e200a511 --- /dev/null +++ b/testdata/data/repos/standalone/RustCheck/SuboptimalCratesURICall/fix.patch @@ -0,0 +1,18 @@ +diff -Naur standalone/RustCheck/SuboptimalCratesURICall/SuboptimalCratesURICall-0.ebuild fixed/RustCheck/SuboptimalCratesURICall/SuboptimalCratesURICall-0.ebuild +--- standalone/RustCheck/SuboptimalCratesURICall/SuboptimalCratesURICall-0.ebuild ++++ fixed/RustCheck/SuboptimalCratesURICall/SuboptimalCratesURICall-0.ebuild +@@ -10,4 +10,4 @@ DESCRIPTION="Ebuild with suboptimal cargo_crate_uris" + HOMEPAGE="https://github.com/pkgcore/pkgcheck" + SLOT="0" + LICENSE="BSD" +-SRC_URI="$(cargo_crate_uris)" ++SRC_URI="${CARGO_CRATE_URIS}" +diff -Naur standalone/RustCheck/SuboptimalCratesURICall/SuboptimalCratesURICall-1.ebuild fixed/RustCheck/SuboptimalCratesURICall/SuboptimalCratesURICall-1.ebuild +--- standalone/RustCheck/SuboptimalCratesURICall/SuboptimalCratesURICall-1.ebuild ++++ fixed/RustCheck/SuboptimalCratesURICall/SuboptimalCratesURICall-1.ebuild +@@ -10,4 +10,4 @@ DESCRIPTION="Ebuild with suboptimal cargo_crate_uris" + HOMEPAGE="https://github.com/pkgcore/pkgcheck" + SLOT="0" + LICENSE="BSD" +-SRC_URI="$(cargo_crate_uris ${CRATES})" ++SRC_URI="${CARGO_CRATE_URIS}" diff --git a/testdata/repos/standalone/RustCheck/SuboptimalCratesSeparator/SuboptimalCratesSeparator-0.ebuild b/testdata/repos/standalone/RustCheck/SuboptimalCratesSeparator/SuboptimalCratesSeparator-0.ebuild new file mode 100644 index 000000000..d1da3ecc8 --- /dev/null +++ b/testdata/repos/standalone/RustCheck/SuboptimalCratesSeparator/SuboptimalCratesSeparator-0.ebuild @@ -0,0 +1,12 @@ +CRATES=" + random@0.10.0 snakeoil-0.10.0 + pkgcore-0.10.0 + pkgcheck-0.10.0 +" + +inherit cargo + +DESCRIPTION="Ebuild with suboptimal CRATES separator" +HOMEPAGE="https://github.com/pkgcore/pkgcheck" +SLOT="0" +LICENSE="BSD" diff --git a/testdata/repos/standalone/RustCheck/SuboptimalCratesURICall/SuboptimalCratesURICall-0.ebuild b/testdata/repos/standalone/RustCheck/SuboptimalCratesURICall/SuboptimalCratesURICall-0.ebuild new file mode 100644 index 000000000..8a8b79d0d --- /dev/null +++ b/testdata/repos/standalone/RustCheck/SuboptimalCratesURICall/SuboptimalCratesURICall-0.ebuild @@ -0,0 +1,13 @@ +CRATES=" + snakeoil@0.10.0 + pkgcore@0.10.0 + pkgcheck@0.10.0 +" + +inherit cargo + +DESCRIPTION="Ebuild with suboptimal cargo_crate_uris" +HOMEPAGE="https://github.com/pkgcore/pkgcheck" +SLOT="0" +LICENSE="BSD" +SRC_URI="$(cargo_crate_uris)" diff --git a/testdata/repos/standalone/RustCheck/SuboptimalCratesURICall/SuboptimalCratesURICall-1.ebuild b/testdata/repos/standalone/RustCheck/SuboptimalCratesURICall/SuboptimalCratesURICall-1.ebuild new file mode 100644 index 000000000..1aa95b8f4 --- /dev/null +++ b/testdata/repos/standalone/RustCheck/SuboptimalCratesURICall/SuboptimalCratesURICall-1.ebuild @@ -0,0 +1,13 @@ +CRATES=" + snakeoil@0.10.0 + pkgcore@0.10.0 + pkgcheck@0.10.0 +" + +inherit cargo + +DESCRIPTION="Ebuild with suboptimal cargo_crate_uris" +HOMEPAGE="https://github.com/pkgcore/pkgcheck" +SLOT="0" +LICENSE="BSD" +SRC_URI="$(cargo_crate_uris ${CRATES})" diff --git a/testdata/repos/standalone/RustCheck/SuboptimalCratesURICall/SuboptimalCratesURICall-2.ebuild b/testdata/repos/standalone/RustCheck/SuboptimalCratesURICall/SuboptimalCratesURICall-2.ebuild new file mode 100644 index 000000000..72ef8a24f --- /dev/null +++ b/testdata/repos/standalone/RustCheck/SuboptimalCratesURICall/SuboptimalCratesURICall-2.ebuild @@ -0,0 +1,13 @@ +CRATES=" + snakeoil@0.10.0 + pkgcore@0.10.0 + pkgcheck@0.10.0 +" + +inherit cargo + +DESCRIPTION="Ebuild with suboptimal cargo_crate_uris" +HOMEPAGE="https://github.com/pkgcore/pkgcheck" +SLOT="0" +LICENSE="BSD" +SRC_URI="$(cargo_crate_uris ${CRATES} something)" diff --git a/testdata/repos/standalone/eclass/cargo.eclass b/testdata/repos/standalone/eclass/cargo.eclass new file mode 100644 index 000000000..217dc8e8d --- /dev/null +++ b/testdata/repos/standalone/eclass/cargo.eclass @@ -0,0 +1,5 @@ +# cargo eclass + +CARGO_CRATE_URIS=${CRATES} + +cargo_crate_uris() { :; }