summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorHarmen Stoppels <me@harmenstoppels.nl>2024-09-13 13:21:58 +0200
committerGitHub <noreply@github.com>2024-09-13 13:21:58 +0200
commit7573ea2ae5d0e772b82263d5543ab0f9551dfb35 (patch)
tree2b41175c3f0c48d5a34c1f5585c01058c9e1d1b1 /lib
parentef35811f39e85774d644472795f0af982c09a8ac (diff)
downloadspack-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.py88
-rw-r--r--lib/spack/spack/cmd/audit.py14
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}}"))