cmd/checksum: allow adding new versions to package (#24532)
This adds super-lazy maintainer mode to `spack checksum`: Instead of only printing the new checksums to the terminal, `-a` and `--add-to-package` will add the new checksums to the `package.py` file and open it in the editor afterwards for final checks.
This commit is contained in:
@@ -6,6 +6,7 @@
|
|||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import sys
|
||||||
|
|
||||||
import llnl.util.tty as tty
|
import llnl.util.tty as tty
|
||||||
|
|
||||||
@@ -16,6 +17,7 @@
|
|||||||
import spack.stage
|
import spack.stage
|
||||||
import spack.util.crypto
|
import spack.util.crypto
|
||||||
from spack.package_base import deprecated_version, preferred_version
|
from spack.package_base import deprecated_version, preferred_version
|
||||||
|
from spack.util.editor import editor
|
||||||
from spack.util.naming import valid_fully_qualified_module_name
|
from spack.util.naming import valid_fully_qualified_module_name
|
||||||
from spack.version import VersionBase, ver
|
from spack.version import VersionBase, ver
|
||||||
|
|
||||||
@@ -53,6 +55,13 @@ def setup_parser(subparser):
|
|||||||
default=False,
|
default=False,
|
||||||
help="checksum the preferred version only",
|
help="checksum the preferred version only",
|
||||||
)
|
)
|
||||||
|
subparser.add_argument(
|
||||||
|
"-a",
|
||||||
|
"--add-to-package",
|
||||||
|
action="store_true",
|
||||||
|
default=False,
|
||||||
|
help="add new versions to package",
|
||||||
|
)
|
||||||
arguments.add_common_arguments(subparser, ["package"])
|
arguments.add_common_arguments(subparser, ["package"])
|
||||||
subparser.add_argument(
|
subparser.add_argument(
|
||||||
"versions", nargs=argparse.REMAINDER, help="versions to generate checksums for"
|
"versions", nargs=argparse.REMAINDER, help="versions to generate checksums for"
|
||||||
@@ -118,3 +127,46 @@ def checksum(parser, args):
|
|||||||
print()
|
print()
|
||||||
print(version_lines)
|
print(version_lines)
|
||||||
print()
|
print()
|
||||||
|
|
||||||
|
if args.add_to_package:
|
||||||
|
filename = spack.repo.path.filename_for_package_name(pkg.name)
|
||||||
|
# Make sure we also have a newline after the last version
|
||||||
|
versions = [v + "\n" for v in version_lines.splitlines()]
|
||||||
|
versions.append("\n")
|
||||||
|
# We need to insert the versions in reversed order
|
||||||
|
versions.reverse()
|
||||||
|
versions.append(" # FIXME: Added by `spack checksum`\n")
|
||||||
|
version_line = None
|
||||||
|
|
||||||
|
with open(filename, "r") as f:
|
||||||
|
lines = f.readlines()
|
||||||
|
for i in range(len(lines)):
|
||||||
|
# Black is drunk, so this is what it looks like for now
|
||||||
|
# See https://github.com/psf/black/issues/2156 for more information
|
||||||
|
if lines[i].startswith(" # FIXME: Added by `spack checksum`") or lines[
|
||||||
|
i
|
||||||
|
].startswith(" version("):
|
||||||
|
version_line = i
|
||||||
|
break
|
||||||
|
|
||||||
|
if version_line is not None:
|
||||||
|
for v in versions:
|
||||||
|
lines.insert(version_line, v)
|
||||||
|
|
||||||
|
with open(filename, "w") as f:
|
||||||
|
f.writelines(lines)
|
||||||
|
|
||||||
|
msg = "opening editor to verify"
|
||||||
|
|
||||||
|
if not sys.stdout.isatty():
|
||||||
|
msg = "please verify"
|
||||||
|
|
||||||
|
tty.info(
|
||||||
|
"Added {0} new versions to {1}, "
|
||||||
|
"{2}.".format(len(versions) - 2, args.package, msg)
|
||||||
|
)
|
||||||
|
|
||||||
|
if sys.stdout.isatty():
|
||||||
|
editor(filename)
|
||||||
|
else:
|
||||||
|
tty.warn("Could not add new versions to {0}.".format(args.package))
|
||||||
|
@@ -20,16 +20,17 @@
|
|||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"arguments,expected",
|
"arguments,expected",
|
||||||
[
|
[
|
||||||
(["--batch", "patch"], (True, False, False)),
|
(["--batch", "patch"], (True, False, False, False)),
|
||||||
(["--latest", "patch"], (False, True, False)),
|
(["--latest", "patch"], (False, True, False, False)),
|
||||||
(["--preferred", "patch"], (False, False, True)),
|
(["--preferred", "patch"], (False, False, True, False)),
|
||||||
|
(["--add-to-package", "patch"], (False, False, False, True)),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_checksum_args(arguments, expected):
|
def test_checksum_args(arguments, expected):
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
spack.cmd.checksum.setup_parser(parser)
|
spack.cmd.checksum.setup_parser(parser)
|
||||||
args = parser.parse_args(arguments)
|
args = parser.parse_args(arguments)
|
||||||
check = args.batch, args.latest, args.preferred
|
check = args.batch, args.latest, args.preferred, args.add_to_package
|
||||||
assert check == expected
|
assert check == expected
|
||||||
|
|
||||||
|
|
||||||
@@ -40,9 +41,10 @@ def test_checksum_args(arguments, expected):
|
|||||||
(["--batch", "preferred-test"], "version of preferred-test"),
|
(["--batch", "preferred-test"], "version of preferred-test"),
|
||||||
(["--latest", "preferred-test"], "Found 1 version"),
|
(["--latest", "preferred-test"], "Found 1 version"),
|
||||||
(["--preferred", "preferred-test"], "Found 1 version"),
|
(["--preferred", "preferred-test"], "Found 1 version"),
|
||||||
|
(["--add-to-package", "preferred-test"], "Added 1 new versions to"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_checksum(arguments, expected, mock_packages, mock_stage):
|
def test_checksum(arguments, expected, mock_packages, mock_clone_repo, mock_stage):
|
||||||
output = spack_checksum(*arguments)
|
output = spack_checksum(*arguments)
|
||||||
assert expected in output
|
assert expected in output
|
||||||
assert "version(" in output
|
assert "version(" in output
|
||||||
@@ -62,19 +64,31 @@ def _get_number(*args, **kwargs):
|
|||||||
assert "version(" in output
|
assert "version(" in output
|
||||||
|
|
||||||
|
|
||||||
def test_checksum_versions(mock_packages, mock_fetch, mock_stage):
|
def test_checksum_versions(mock_packages, mock_clone_repo, mock_fetch, mock_stage):
|
||||||
pkg_cls = spack.repo.path.get_pkg_class("preferred-test")
|
pkg_cls = spack.repo.path.get_pkg_class("preferred-test")
|
||||||
versions = [str(v) for v in pkg_cls.versions if not v.isdevelop()]
|
versions = [str(v) for v in pkg_cls.versions if not v.isdevelop()]
|
||||||
output = spack_checksum("preferred-test", versions[0])
|
output = spack_checksum("preferred-test", versions[0])
|
||||||
assert "Found 1 version" in output
|
assert "Found 1 version" in output
|
||||||
assert "version(" in output
|
assert "version(" in output
|
||||||
|
output = spack_checksum("--add-to-package", "preferred-test", versions[0])
|
||||||
|
assert "Found 1 version" in output
|
||||||
|
assert "version(" in output
|
||||||
|
assert "Added 1 new versions to" in output
|
||||||
|
|
||||||
|
|
||||||
def test_checksum_missing_version(mock_packages, mock_fetch, mock_stage):
|
def test_checksum_missing_version(mock_packages, mock_clone_repo, mock_fetch, mock_stage):
|
||||||
output = spack_checksum("preferred-test", "99.99.99", fail_on_error=False)
|
output = spack_checksum("preferred-test", "99.99.99", fail_on_error=False)
|
||||||
assert "Could not find any remote versions" in output
|
assert "Could not find any remote versions" in output
|
||||||
|
output = spack_checksum("--add-to-package", "preferred-test", "99.99.99", fail_on_error=False)
|
||||||
|
assert "Could not find any remote versions" in output
|
||||||
|
assert "Added 1 new versions to" not in output
|
||||||
|
|
||||||
|
|
||||||
def test_checksum_deprecated_version(mock_packages, mock_fetch, mock_stage):
|
def test_checksum_deprecated_version(mock_packages, mock_clone_repo, mock_fetch, mock_stage):
|
||||||
output = spack_checksum("deprecated-versions", "1.1.0", fail_on_error=False)
|
output = spack_checksum("deprecated-versions", "1.1.0", fail_on_error=False)
|
||||||
assert "Version 1.1.0 is deprecated" in output
|
assert "Version 1.1.0 is deprecated" in output
|
||||||
|
output = spack_checksum(
|
||||||
|
"--add-to-package", "deprecated-versions", "1.1.0", fail_on_error=False
|
||||||
|
)
|
||||||
|
assert "Version 1.1.0 is deprecated" in output
|
||||||
|
assert "Added 1 new versions to" not in output
|
||||||
|
@@ -1604,6 +1604,30 @@ def mock_test_repo(tmpdir_factory):
|
|||||||
shutil.rmtree(str(repodir))
|
shutil.rmtree(str(repodir))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="function")
|
||||||
|
def mock_clone_repo(tmpdir_factory):
|
||||||
|
"""Create a cloned repository."""
|
||||||
|
repo_namespace = "mock_clone_repo"
|
||||||
|
repodir = tmpdir_factory.mktemp(repo_namespace)
|
||||||
|
yaml = repodir.join("repo.yaml")
|
||||||
|
yaml.write(
|
||||||
|
"""
|
||||||
|
repo:
|
||||||
|
namespace: mock_clone_repo
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
shutil.copytree(
|
||||||
|
os.path.join(spack.paths.mock_packages_path, spack.repo.packages_dir_name),
|
||||||
|
os.path.join(str(repodir), spack.repo.packages_dir_name),
|
||||||
|
)
|
||||||
|
|
||||||
|
with spack.repo.use_repositories(str(repodir)) as repo:
|
||||||
|
yield repo, repodir
|
||||||
|
|
||||||
|
shutil.rmtree(str(repodir))
|
||||||
|
|
||||||
|
|
||||||
##########
|
##########
|
||||||
# Class and fixture to work around problems raising exceptions in directives,
|
# Class and fixture to work around problems raising exceptions in directives,
|
||||||
# which cause tests like test_from_list_url to hang for Python 2.x metaclass
|
# which cause tests like test_from_list_url to hang for Python 2.x metaclass
|
||||||
|
@@ -580,7 +580,7 @@ _spack_change() {
|
|||||||
_spack_checksum() {
|
_spack_checksum() {
|
||||||
if $list_options
|
if $list_options
|
||||||
then
|
then
|
||||||
SPACK_COMPREPLY="-h --help --keep-stage -b --batch -l --latest -p --preferred"
|
SPACK_COMPREPLY="-h --help --keep-stage -b --batch -l --latest -p --preferred -a --add-to-package"
|
||||||
else
|
else
|
||||||
_all_packages
|
_all_packages
|
||||||
fi
|
fi
|
||||||
|
Reference in New Issue
Block a user