diff options
author | Harmen Stoppels <me@harmenstoppels.nl> | 2024-09-13 13:21:58 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-09-13 13:21:58 +0200 |
commit | 7573ea2ae5d0e772b82263d5543ab0f9551dfb35 (patch) | |
tree | 2b41175c3f0c48d5a34c1f5585c01058c9e1d1b1 /lib | |
parent | ef35811f39e85774d644472795f0af982c09a8ac (diff) | |
download | spack-7573ea2ae5d0e772b82263d5543ab0f9551dfb35.tar.gz spack-7573ea2ae5d0e772b82263d5543ab0f9551dfb35.tar.bz2 spack-7573ea2ae5d0e772b82263d5543ab0f9551dfb35.tar.xz spack-7573ea2ae5d0e772b82263d5543ab0f9551dfb35.zip |
audit: deprecate certain globals (#44895)
Diffstat (limited to 'lib')
-rw-r--r-- | lib/spack/spack/audit.py | 88 | ||||
-rw-r--r-- | lib/spack/spack/cmd/audit.py | 14 |
2 files changed, 92 insertions, 10 deletions
diff --git a/lib/spack/spack/audit.py b/lib/spack/spack/audit.py index 28b7727e5e..14fe7a5f33 100644 --- a/lib/spack/spack/audit.py +++ b/lib/spack/spack/audit.py @@ -46,12 +46,14 @@ import pathlib import pickle import re import warnings +from typing import Iterable, List, Set, Tuple from urllib.request import urlopen import llnl.util.lang import spack.config import spack.patch +import spack.paths import spack.repo import spack.spec import spack.util.crypto @@ -73,7 +75,9 @@ class Error: self.details = tuple(details) def __str__(self): - return self.summary + "\n" + "\n".join([" " + detail for detail in self.details]) + if self.details: + return f"{self.summary}\n" + "\n".join(f" {detail}" for detail in self.details) + return self.summary def __eq__(self, other): if self.summary != other.summary or self.details != other.details: @@ -679,6 +683,88 @@ def _ensure_env_methods_are_ported_to_builders(pkgs, error_cls): return errors +class DeprecatedMagicGlobals(ast.NodeVisitor): + def __init__(self, magic_globals: Iterable[str]): + super().__init__() + + self.magic_globals: Set[str] = set(magic_globals) + + # State to track whether we're in a class function + self.depth: int = 0 + self.in_function: bool = False + self.path = (ast.Module, ast.ClassDef, ast.FunctionDef) + + # Defined locals in the current function (heuristically at least) + self.locals: Set[str] = set() + + # List of (name, lineno) tuples for references to magic globals + self.references_to_globals: List[Tuple[str, int]] = [] + + def descend_in_function_def(self, node: ast.AST) -> None: + if not isinstance(node, self.path[self.depth]): + return + self.depth += 1 + if self.depth == len(self.path): + self.in_function = True + super().generic_visit(node) + if self.depth == len(self.path): + self.in_function = False + self.locals.clear() + self.depth -= 1 + + def generic_visit(self, node: ast.AST) -> None: + # Recurse into function definitions + if self.depth < len(self.path): + return self.descend_in_function_def(node) + elif not self.in_function: + return + elif isinstance(node, ast.Global): + for name in node.names: + if name in self.magic_globals: + self.references_to_globals.append((name, node.lineno)) + elif isinstance(node, ast.Assign): + # visit the rhs before lhs + super().visit(node.value) + for target in node.targets: + super().visit(target) + elif isinstance(node, ast.Name) and node.id in self.magic_globals: + if isinstance(node.ctx, ast.Load) and node.id not in self.locals: + self.references_to_globals.append((node.id, node.lineno)) + elif isinstance(node.ctx, ast.Store): + self.locals.add(node.id) + else: + super().generic_visit(node) + + +@package_properties +def _uses_deprecated_globals(pkgs, error_cls): + """Ensure that packages do not use deprecated globals""" + errors = [] + + for pkg_name in pkgs: + # some packages scheduled to be removed in v0.23 are not worth fixing. + pkg_cls = spack.repo.PATH.get_pkg_class(pkg_name) + if all(v.get("deprecated", False) for v in pkg_cls.versions.values()): + continue + + file = spack.repo.PATH.filename_for_package_name(pkg_name) + tree = ast.parse(open(file).read()) + visitor = DeprecatedMagicGlobals(("std_cmake_args",)) + visitor.visit(tree) + if visitor.references_to_globals: + errors.append( + error_cls( + f"Package '{pkg_name}' uses deprecated globals", + [ + f"{file}:{line} references '{name}'" + for name, line in visitor.references_to_globals + ], + ) + ) + + return errors + + @package_https_directives def _linting_package_file(pkgs, error_cls): """Check for correctness of links""" diff --git a/lib/spack/spack/cmd/audit.py b/lib/spack/spack/cmd/audit.py index 77bbbc5d82..e5512d9a90 100644 --- a/lib/spack/spack/cmd/audit.py +++ b/lib/spack/spack/cmd/audit.py @@ -115,15 +115,11 @@ def audit(parser, args): def _process_reports(reports): for check, errors in reports: if errors: - msg = "{0}: {1} issue{2} found".format( - check, len(errors), "" if len(errors) == 1 else "s" - ) - header = "@*b{" + msg + "}" - print(cl.colorize(header)) + status = f"{len(errors)} issue{'' if len(errors) == 1 else 's'} found" + print(cl.colorize(f"{check}: @*r{{{status}}}")) + numdigits = len(str(len(errors))) for idx, error in enumerate(errors): - print(str(idx + 1) + ". " + str(error)) + print(f"{idx + 1:>{numdigits}}. {error}") raise SystemExit(1) else: - msg = "{0}: 0 issues found.".format(check) - header = "@*b{" + msg + "}" - print(cl.colorize(header)) + print(cl.colorize(f"{check}: @*g{{passed}}")) |