Skip to content

Commit affda79

Browse files
authored
Merge pull request #569 from FNALssi/maintenance/merge-from-upstream-2025-08-06
Merge from upstream/develop 2025-08-06
2 parents b1a8f3f + 8940ffb commit affda79

File tree

144 files changed

+3967
-4664
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

144 files changed

+3967
-4664
lines changed
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
#!/usr/bin/env python3
2+
# Copyright Spack Project Developers. See COPYRIGHT file for details.
3+
#
4+
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
5+
import argparse
6+
import ast
7+
import os
8+
import subprocess
9+
import sys
10+
from itertools import product
11+
from typing import List
12+
13+
14+
def run_git_command(*args: str, dir: str) -> None:
15+
"""Run a git command in the output directory."""
16+
subprocess.run(
17+
[
18+
"git",
19+
"-c",
20+
21+
"-c",
22+
"user.name=Example",
23+
"-c",
24+
"init.defaultBranch=main",
25+
"-c",
26+
"color.ui=always",
27+
"-C",
28+
dir,
29+
*args,
30+
],
31+
check=True,
32+
stdout=sys.stdout,
33+
stderr=sys.stderr,
34+
)
35+
36+
37+
def run(root: str, output_dir: str) -> None:
38+
"""Recurse over a directory and canonicalize all Python files."""
39+
from spack.util.package_hash import RemoveDocstrings, unparse
40+
41+
count = 0
42+
stack = [root]
43+
44+
while stack:
45+
current = stack.pop()
46+
for entry in os.scandir(current):
47+
if entry.is_dir(follow_symlinks=False):
48+
stack.append(entry.path)
49+
elif entry.is_file(follow_symlinks=False) and entry.name.endswith(".py"):
50+
try:
51+
with open(entry.path, "r") as f:
52+
src = f.read()
53+
except OSError:
54+
continue
55+
56+
canonical_dir = os.path.join(output_dir, os.path.relpath(current, root))
57+
os.makedirs(canonical_dir, exist_ok=True)
58+
with open(os.path.join(canonical_dir, entry.name), "w") as f:
59+
f.write(
60+
unparse(RemoveDocstrings().visit(ast.parse(src)), py_ver_consistent=True)
61+
)
62+
count += 1
63+
64+
assert count > 0, "No Python files found in the specified directory."
65+
66+
67+
def compare(
68+
input_dir: str, output_dir: str, python_versions: List[str], spack_versions: List[str]
69+
) -> None:
70+
"""Compare canonicalized files across different Python versions and error if they differ."""
71+
# Create a git repo in output_dir to track changes
72+
os.makedirs(output_dir, exist_ok=True)
73+
run_git_command("init", dir=output_dir)
74+
75+
pairs = list(product(spack_versions, python_versions))
76+
77+
if len(pairs) < 2:
78+
raise ValueError("At least two Python or two Spack versions must be given for comparison.")
79+
80+
changes_with_previous: List[int] = []
81+
82+
for i, (spack_dir, python_exe) in enumerate(pairs):
83+
print(f"\033[1;97mCanonicalizing with {python_exe} and {spack_dir}...\033[0m", flush=True)
84+
85+
# Point PYTHONPATH to the given Spack library for the subprocess
86+
if not os.path.isdir(spack_dir):
87+
raise ValueError(f"Invalid Spack dir: {spack_dir}")
88+
env = os.environ.copy()
89+
spack_pythonpath = os.path.join(spack_dir, "lib", "spack")
90+
if "PYTHONPATH" in env and env["PYTHONPATH"]:
91+
env["PYTHONPATH"] = f"{spack_pythonpath}{os.pathsep}{env['PYTHONPATH']}"
92+
else:
93+
env["PYTHONPATH"] = spack_pythonpath
94+
95+
subprocess.run(
96+
[python_exe, __file__, "--run", "--input-dir", input_dir, "--output-dir", output_dir],
97+
check=True,
98+
stdout=sys.stdout,
99+
stderr=sys.stderr,
100+
env=env,
101+
)
102+
if i > 0:
103+
try:
104+
run_git_command("diff", "--exit-code", "HEAD", dir=output_dir)
105+
except subprocess.CalledProcessError:
106+
changes_with_previous.append(i)
107+
108+
# The first run creates a commit for reference
109+
run_git_command("add", ".", dir=output_dir)
110+
run_git_command(
111+
"commit",
112+
"--quiet",
113+
"--allow-empty", # makes this idempotent when running locally
114+
"-m",
115+
f"Canonicalized with {python_exe} and {spack_dir}",
116+
dir=output_dir,
117+
)
118+
119+
for i in changes_with_previous:
120+
previous_spack, previous_python = pairs[i - 1]
121+
current_spack, current_python = pairs[i]
122+
print(
123+
f"\033[1;31mChanges detected between {previous_python} ({previous_spack}) and "
124+
f"{current_python} ({current_spack})\033[0m"
125+
)
126+
127+
if changes_with_previous:
128+
exit(1)
129+
130+
131+
if __name__ == "__main__":
132+
parser = argparse.ArgumentParser(description="Canonicalize Spack package files.")
133+
parser.add_argument("--run", action="store_true", help="Generate canonicalized sources.")
134+
parser.add_argument("--spack", nargs="+", help="Specify one or more Spack versions.")
135+
parser.add_argument("--python", nargs="+", help="Specify one or more Python versions.")
136+
parser.add_argument("--input-dir", type=str, required=True, help="A repo's packages dir.")
137+
parser.add_argument(
138+
"--output-dir",
139+
type=str,
140+
required=True,
141+
help="The output directory for canonicalized package files.",
142+
)
143+
args = parser.parse_args()
144+
145+
if args.run:
146+
run(args.input_dir, args.output_dir)
147+
else:
148+
compare(args.input_dir, args.output_dir, args.python, args.spack)

.github/workflows/ci.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ jobs:
5050
- '.github/workflows/ci.yaml'
5151
core:
5252
- './!(var/**)/**'
53+
- 'var/spack/test_repos/**'
5354
packages:
5455
- 'var/**'
5556
# Some links for easier reference:

.github/workflows/prechecks.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,31 @@ jobs:
8585
spack -d bootstrap now --dev
8686
spack -d style -t black
8787
spack unit-test -V
88+
89+
canonicalization:
90+
name: package.py canonicalization
91+
runs-on: ubuntu-latest
92+
container:
93+
image: ghcr.io/spack/all-pythons:2025-07-25
94+
95+
steps:
96+
- name: Checkout Spack (current)
97+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
98+
with:
99+
path: spack-current
100+
- name: Checkout Spack (previous)
101+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
102+
with:
103+
path: spack-previous
104+
ref: ${{ github.event.pull_request.base.sha || github.event.before }}
105+
- name: Checkout Spack Packages
106+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
107+
with:
108+
repository: spack/spack-packages
109+
path: spack-packages
110+
- name: Test package.py canonicalization
111+
run: spack-current/.github/workflows/bin/canonicalize.py
112+
--spack $PWD/spack-previous $PWD/spack-current
113+
--python python3.6 python3.7 python3.8 python3.9 python3.10 python3.11 python3.12 python3.13
114+
--input-dir spack-packages/repos/spack_repo/builtin/packages/
115+
--output-dir canonicalized

.github/workflows/requirements/style/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ black==25.1.0
22
clingo==5.8.0
33
flake8==7.3.0
44
isort==6.0.1
5-
mypy==1.17.0
5+
mypy==1.17.1
66
types-six==1.17.0.20250515
77
vermin==1.6.0
88
pylint==3.3.7

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
<h2>
44
<picture>
5-
<source media="(prefers-color-scheme: dark)" srcset="https://cdn.rawgit.com/spack/spack/develop/share/spack/logo/spack-logo-white-text.svg" width="250">
6-
<source media="(prefers-color-scheme: light)" srcset="https://cdn.rawgit.com/spack/spack/develop/share/spack/logo/spack-logo-text.svg" width="250">
7-
<img alt="Spack" src="https://cdn.rawgit.com/spack/spack/develop/share/spack/logo/spack-logo-text.svg" width="250">
5+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/spack/spack/refs/heads/develop/share/spack/logo/spack-logo-white-text.svg" width="250">
6+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/spack/spack/refs/heads/develop/share/spack/logo/spack-logo-text.svg" width="250">
7+
<img alt="Spack" src="https://raw.githubusercontent.com/spack/spack/refs/heads/develop/share/spack/logo/spack-logo-text.svg" width="250">
88
</picture>
99

1010
<br>

lib/spack/docs/_pygments/style.py

Lines changed: 0 additions & 15 deletions
This file was deleted.
Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,57 @@
11
div.versionadded {
2-
border-left: 3px solid #0c731f;
3-
color: #0c731f;
4-
padding-left: 1rem;
2+
border-left: 3px solid #0c731f;
3+
color: #0c731f;
4+
padding-left: 1rem;
55
}
66

77
.py.property {
88
display: block !important;
9+
}
10+
11+
div.version-switch {
12+
text-align: center;
13+
min-height: 2em;
14+
}
15+
16+
div.version-switch>select {
17+
display: inline-block;
18+
text-align-last: center;
19+
background: none;
20+
border: none;
21+
border-radius: 0.5em;
22+
box-shadow: none;
23+
color: var(--color-foreground-primary);
24+
cursor: pointer;
25+
appearance: none;
26+
padding: 0.2em;
27+
-webkit-appearance: none;
28+
-moz-appearance: none;
29+
}
30+
31+
div.version-switch select:active,
32+
div.version-switch select:focus,
33+
div.version-switch select:hover {
34+
color: var(--color-foreground-secondary);
35+
background: var(--color-background-hover);
36+
}
37+
38+
.toc-tree li.scroll-current>.reference {
39+
font-weight: normal;
40+
}
41+
42+
.search-results span {
43+
background-color: #fff3cd;
44+
padding: 0.1rem 0.2rem;
45+
border-radius: 2px;
46+
}
47+
48+
@media (prefers-color-scheme: dark) {
49+
body:not([data-theme="light"]) .search-results span {
50+
background-color: #664d03;
51+
color: #fff3cd;
52+
}
53+
}
54+
55+
.highlight .go {
56+
color: #333;
957
}

0 commit comments

Comments
 (0)