spack edit: allow edit multiple files at once (#44416)

This commit is contained in:
Harmen Stoppels 2024-06-05 14:19:11 +02:00 committed by GitHub
parent 9b77502360
commit 3ffe02a2fe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 105 additions and 62 deletions

View File

@ -3,6 +3,7 @@
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import errno
import glob
import os
@ -11,43 +12,13 @@
import spack.cmd
import spack.paths
import spack.repo
from spack.spec import Spec
from spack.util.editor import editor
import spack.util.editor
description = "open package files in $EDITOR"
section = "packaging"
level = "short"
def edit_package(name, repo_path, namespace):
"""Opens the requested package file in your favorite $EDITOR.
Args:
name (str): The name of the package
repo_path (str): The path to the repository containing this package
namespace (str): A valid namespace registered with Spack
"""
# Find the location of the package
if repo_path:
repo = spack.repo.Repo(repo_path)
elif namespace:
repo = spack.repo.PATH.get_repo(namespace)
else:
repo = spack.repo.PATH
path = repo.filename_for_package_name(name)
spec = Spec(name)
if os.path.exists(path):
if not os.path.isfile(path):
tty.die("Something is wrong. '{0}' is not a file!".format(path))
if not os.access(path, os.R_OK):
tty.die("Insufficient permissions on '%s'!" % path)
else:
raise spack.repo.UnknownPackageError(spec.name)
editor(path)
def setup_parser(subparser):
excl_args = subparser.add_mutually_exclusive_group()
@ -98,41 +69,67 @@ def setup_parser(subparser):
excl_args.add_argument("-r", "--repo", default=None, help="path to repo to edit package in")
excl_args.add_argument("-N", "--namespace", default=None, help="namespace of package to edit")
subparser.add_argument("package", nargs="?", default=None, help="package name")
subparser.add_argument("package", nargs="*", default=None, help="package name")
def locate_package(name: str, repo: spack.repo.Repo) -> str:
path = repo.filename_for_package_name(name)
try:
with open(path, "r"):
return path
except OSError as e:
if e.errno == errno.ENOENT:
raise spack.repo.UnknownPackageError(name) from e
tty.die(f"Cannot edit package: {e}")
def locate_file(name: str, path: str) -> str:
# convert command names to python module name
if path == spack.paths.command_path:
name = spack.cmd.python_name(name)
file_path = os.path.join(path, name)
# Try to open direct match.
try:
with open(file_path, "r"):
return file_path
except OSError as e:
if e.errno != errno.ENOENT:
tty.die(f"Cannot edit file: {e}")
pass
# Otherwise try to find a file that starts with the name
candidates = glob.glob(file_path + "*")
exclude_list = [".pyc", "~"] # exclude binaries and backups
files = [f for f in candidates if not any(f.endswith(ext) for ext in exclude_list)]
if len(files) > 1:
tty.die(
f"Multiple files start with `{name}`:\n"
+ "\n".join(f" {os.path.basename(f)}" for f in files)
)
elif not files:
tty.die(f"No file for '{name}' was found in {path}")
return files[0]
def edit(parser, args):
name = args.package
# By default, edit package files
path = spack.paths.packages_path
names = args.package
# If `--command`, `--test`, or `--module` is chosen, edit those instead
if args.path:
path = args.path
if name:
# convert command names to python module name
if path == spack.paths.command_path:
name = spack.cmd.python_name(name)
path = os.path.join(path, name)
if not os.path.exists(path):
files = glob.glob(path + "*")
exclude_list = [".pyc", "~"] # exclude binaries and backups
files = list(filter(lambda x: all(s not in x for s in exclude_list), files))
if len(files) > 1:
m = "Multiple files exist with the name {0}.".format(name)
m += " Please specify a suffix. Files are:\n\n"
for f in files:
m += " " + os.path.basename(f) + "\n"
tty.die(m)
if not files:
tty.die("No file for '{0}' was found in {1}".format(name, path))
path = files[0] # already confirmed only one entry in files
editor(path)
elif name:
edit_package(name, args.repo, args.namespace)
paths = [locate_file(name, args.path) for name in names] if names else [args.path]
spack.util.editor.editor(*paths)
elif names:
if args.repo:
repo = spack.repo.Repo(args.repo)
elif args.namespace:
repo = spack.repo.PATH.get_repo(args.namespace)
else:
repo = spack.repo.PATH
paths = [locate_package(name, repo) for name in names]
spack.util.editor.editor(*paths)
else:
# By default open the directory where packages live
editor(path)
spack.util.editor.editor(spack.paths.packages_path)

View File

@ -0,0 +1,46 @@
# Copyright 2013-2024 Lawrence Livermore National Security, LLC and other
# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import os
import spack.paths
import spack.repo
import spack.util.editor
from spack.build_systems import autotools, cmake
from spack.main import SpackCommand
edit = SpackCommand("edit")
def test_edit_packages(monkeypatch, mock_packages: spack.repo.RepoPath):
"""Test spack edit a b"""
path_a = mock_packages.filename_for_package_name("a")
path_b = mock_packages.filename_for_package_name("b")
called = False
def editor(*args: str, **kwargs):
nonlocal called
called = True
assert args[0] == path_a
assert args[1] == path_b
monkeypatch.setattr(spack.util.editor, "editor", editor)
edit("a", "b")
assert called
def test_edit_files(monkeypatch):
"""Test spack edit --build-system autotools cmake"""
called = False
def editor(*args: str, **kwargs):
nonlocal called
called = True
assert os.path.samefile(args[0], autotools.__file__)
assert os.path.samefile(args[1], cmake.__file__)
monkeypatch.setattr(spack.util.editor, "editor", editor)
edit("--build-system", "autotools", "cmake")
assert called

View File

@ -1451,7 +1451,7 @@ complete -c spack -n '__fish_spack_using_command docs' -s h -l help -d 'show thi
# spack edit
set -g __fish_spack_optspecs_spack_edit h/help b/build-system c/command d/docs t/test m/module r/repo= N/namespace=
complete -c spack -n '__fish_spack_using_command_pos 0 edit' -f -a '(__fish_spack_packages)'
complete -c spack -n '__fish_spack_using_command_pos_remainder 0 edit' -f -a '(__fish_spack_packages)'
complete -c spack -n '__fish_spack_using_command edit' -s h -l help -f -a help
complete -c spack -n '__fish_spack_using_command edit' -s h -l help -d 'show this help message and exit'
complete -c spack -n '__fish_spack_using_command edit' -s b -l build-system -f -a path