commands: add simple spack commands --update-completion
argument (#14607)
Instead of another script, this adds a simple argument to `spack commands` that updates the completion script. Developers can now just run: spack commands --update-completion This should make it simpler for developers to remember to run this *before* the tests fail. Also, this version tab-completes.
This commit is contained in:
parent
031fdfd7ca
commit
04a6a55cf8
@ -11,6 +11,7 @@
|
|||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import llnl.util.filesystem as fs
|
||||||
import llnl.util.tty as tty
|
import llnl.util.tty as tty
|
||||||
from llnl.util.argparsewriter import (
|
from llnl.util.argparsewriter import (
|
||||||
ArgparseWriter, ArgparseRstWriter, ArgparseCompletionWriter
|
ArgparseWriter, ArgparseRstWriter, ArgparseCompletionWriter
|
||||||
@ -19,6 +20,7 @@
|
|||||||
|
|
||||||
import spack.cmd
|
import spack.cmd
|
||||||
import spack.main
|
import spack.main
|
||||||
|
import spack.paths
|
||||||
from spack.main import section_descriptions
|
from spack.main import section_descriptions
|
||||||
|
|
||||||
|
|
||||||
@ -31,6 +33,20 @@
|
|||||||
formatters = {}
|
formatters = {}
|
||||||
|
|
||||||
|
|
||||||
|
#: standard arguments for updating completion scripts
|
||||||
|
#: we iterate through these when called with --update-completion
|
||||||
|
update_completion_args = {
|
||||||
|
"bash": {
|
||||||
|
"aliases": True,
|
||||||
|
"format": "bash",
|
||||||
|
"header": os.path.join(
|
||||||
|
spack.paths.share_path, "bash", "spack-completion.in"),
|
||||||
|
"update": os.path.join(
|
||||||
|
spack.paths.share_path, "spack-completion.bash"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def formatter(func):
|
def formatter(func):
|
||||||
"""Decorator used to register formatters"""
|
"""Decorator used to register formatters"""
|
||||||
formatters[func.__name__] = func
|
formatters[func.__name__] = func
|
||||||
@ -39,7 +55,12 @@ def formatter(func):
|
|||||||
|
|
||||||
def setup_parser(subparser):
|
def setup_parser(subparser):
|
||||||
subparser.add_argument(
|
subparser.add_argument(
|
||||||
'-a', '--aliases', action='store_true', help='include command aliases')
|
"--update-completion", action='store_true', default=False,
|
||||||
|
help="regenerate spack's tab completion scripts")
|
||||||
|
|
||||||
|
subparser.add_argument(
|
||||||
|
'-a', '--aliases', action='store_true', default=False,
|
||||||
|
help='include command aliases')
|
||||||
subparser.add_argument(
|
subparser.add_argument(
|
||||||
'--format', default='names', choices=formatters,
|
'--format', default='names', choices=formatters,
|
||||||
help='format to be used to print the output (default: names)')
|
help='format to be used to print the output (default: names)')
|
||||||
@ -229,7 +250,11 @@ def prepend_header(args, out):
|
|||||||
out.write(header.read())
|
out.write(header.read())
|
||||||
|
|
||||||
|
|
||||||
def commands(parser, args):
|
def _commands(parser, args):
|
||||||
|
"""This is the 'regular' command, which can be called multiple times.
|
||||||
|
|
||||||
|
See ``commands()`` below for ``--update-completion`` handling.
|
||||||
|
"""
|
||||||
formatter = formatters[args.format]
|
formatter = formatters[args.format]
|
||||||
|
|
||||||
# check header first so we don't open out files unnecessarily
|
# check header first so we don't open out files unnecessarily
|
||||||
@ -255,6 +280,37 @@ def commands(parser, args):
|
|||||||
prepend_header(args, f)
|
prepend_header(args, f)
|
||||||
formatter(args, f)
|
formatter(args, f)
|
||||||
|
|
||||||
|
if args.update_completion:
|
||||||
|
fs.set_executable(args.update)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
prepend_header(args, sys.stdout)
|
prepend_header(args, sys.stdout)
|
||||||
formatter(args, sys.stdout)
|
formatter(args, sys.stdout)
|
||||||
|
|
||||||
|
|
||||||
|
def update_completion(parser, args):
|
||||||
|
"""Iterate through the shells and update the standard completion files.
|
||||||
|
|
||||||
|
This is a convenience method to avoid calling this command many
|
||||||
|
times, and to simplify completion update for developers.
|
||||||
|
|
||||||
|
"""
|
||||||
|
for shell, shell_args in update_completion_args.items():
|
||||||
|
for attr, value in shell_args.items():
|
||||||
|
setattr(args, attr, value)
|
||||||
|
_commands(parser, args)
|
||||||
|
|
||||||
|
|
||||||
|
def commands(parser, args):
|
||||||
|
if args.update_completion:
|
||||||
|
if args.format != 'names' or any([
|
||||||
|
args.aliases, args.update, args.header
|
||||||
|
]):
|
||||||
|
tty.die("--update-completion can only be specified alone.")
|
||||||
|
|
||||||
|
# this runs the command multiple times with different arguments
|
||||||
|
return update_completion(parser, args)
|
||||||
|
|
||||||
|
else:
|
||||||
|
# run commands normally
|
||||||
|
return _commands(parser, args)
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
import filecmp
|
import filecmp
|
||||||
import os
|
import os
|
||||||
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
@ -208,12 +209,47 @@ def test_bash_completion():
|
|||||||
assert '_spack_compiler_add() {' in out2
|
assert '_spack_compiler_add() {' in out2
|
||||||
|
|
||||||
|
|
||||||
|
def test_update_completion_arg(tmpdir, monkeypatch):
|
||||||
|
mock_infile = tmpdir.join("spack-completion.in")
|
||||||
|
mock_bashfile = tmpdir.join("spack-completion.bash")
|
||||||
|
|
||||||
|
mock_args = {
|
||||||
|
"bash": {
|
||||||
|
"aliases": True,
|
||||||
|
"format": "bash",
|
||||||
|
"header": str(mock_infile),
|
||||||
|
"update": str(mock_bashfile),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
# make a mock completion file missing the --update-completion argument
|
||||||
|
real_args = spack.cmd.commands.update_completion_args
|
||||||
|
shutil.copy(real_args['bash']['header'], mock_args['bash']['header'])
|
||||||
|
with open(real_args['bash']['update']) as old:
|
||||||
|
old_file = old.read()
|
||||||
|
with open(mock_args['bash']['update'], 'w') as mock:
|
||||||
|
mock.write(old_file.replace("--update-completion", ""))
|
||||||
|
mock_bashfile.setmtime(0) # ensure mtime triggers update
|
||||||
|
|
||||||
|
monkeypatch.setattr(
|
||||||
|
spack.cmd.commands, 'update_completion_args', mock_args)
|
||||||
|
|
||||||
|
# ensure things fail if --update-completion isn't specified alone
|
||||||
|
with pytest.raises(spack.main.SpackCommandError):
|
||||||
|
commands("--update-completion", "-a")
|
||||||
|
|
||||||
|
# ensure arg is restored
|
||||||
|
assert "--update-completion" not in mock_bashfile.read()
|
||||||
|
commands("--update-completion")
|
||||||
|
assert "--update-completion" in mock_bashfile.read()
|
||||||
|
|
||||||
|
|
||||||
def test_updated_completion_scripts(tmpdir):
|
def test_updated_completion_scripts(tmpdir):
|
||||||
"""Make sure our shell tab completion scripts remain up-to-date."""
|
"""Make sure our shell tab completion scripts remain up-to-date."""
|
||||||
|
|
||||||
msg = ("It looks like Spack's command-line interface has been modified. "
|
msg = ("It looks like Spack's command-line interface has been modified. "
|
||||||
"Please update Spack's shell tab completion scripts by running:\n\n"
|
"Please update Spack's shell tab completion scripts by running:\n\n"
|
||||||
" share/spack/qa/update-completion-scripts.sh\n\n"
|
" spack commands --update-completion\n\n"
|
||||||
"and adding the changed files to your pull request.")
|
"and adding the changed files to your pull request.")
|
||||||
|
|
||||||
for shell in ['bash']: # 'zsh', 'fish']:
|
for shell in ['bash']: # 'zsh', 'fish']:
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
#
|
|
||||||
# Copyright 2013-2020 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)
|
|
||||||
|
|
||||||
# Updates Spack's shell tab completion scripts
|
|
||||||
|
|
||||||
# Switch to parent directory
|
|
||||||
QA_DIR="$(dirname "${BASH_SOURCE[0]}")"
|
|
||||||
cd "$QA_DIR/.."
|
|
||||||
|
|
||||||
# Update each shell
|
|
||||||
for shell in bash # zsh fish
|
|
||||||
do
|
|
||||||
header=$shell/spack-completion.in
|
|
||||||
script=spack-completion.$shell
|
|
||||||
|
|
||||||
rm -f $script
|
|
||||||
spack commands --aliases --format=$shell --header=$header --update=$script
|
|
||||||
chmod +x $script
|
|
||||||
done
|
|
@ -507,7 +507,7 @@ _spack_clone() {
|
|||||||
_spack_commands() {
|
_spack_commands() {
|
||||||
if $list_options
|
if $list_options
|
||||||
then
|
then
|
||||||
SPACK_COMPREPLY="-h --help -a --aliases --format --header --update"
|
SPACK_COMPREPLY="-h --help --update-completion -a --aliases --format --header --update"
|
||||||
else
|
else
|
||||||
SPACK_COMPREPLY=""
|
SPACK_COMPREPLY=""
|
||||||
fi
|
fi
|
||||||
|
Loading…
Reference in New Issue
Block a user