summaryrefslogtreecommitdiff
path: root/share/spack/qa
diff options
context:
space:
mode:
authorAdam J. Stewart <ajstewart426@gmail.com>2020-01-05 23:35:23 -0800
committerTodd Gamblin <tgamblin@llnl.gov>2020-01-22 21:31:12 -0800
commit11f2b612612748ee57728693c7745e3af92e9d54 (patch)
tree656c2ba1de69064c62af1fbd4f43469f7c36cac9 /share/spack/qa
parent8011fedd9ca47578e8da37a9060407c6784d7015 (diff)
downloadspack-11f2b612612748ee57728693c7745e3af92e9d54.tar.gz
spack-11f2b612612748ee57728693c7745e3af92e9d54.tar.bz2
spack-11f2b612612748ee57728693c7745e3af92e9d54.tar.xz
spack-11f2b612612748ee57728693c7745e3af92e9d54.zip
Use `spack commands --format=bash` to generate shell completion (#14393)
This PR adds a `--format=bash` option to `spack commands` to auto-generate the Bash programmable tab completion script. It can be extended to work for other shells. Progress: - [x] Fix bug in superclass initialization in `ArgparseWriter` - [x] Refactor `ArgparseWriter` (see below) - [x] Ensure that output of old `--format` options remains the same - [x] Add `ArgparseCompletionWriter` and `BashCompletionWriter` - [x] Add `--aliases` option to add command aliases - [x] Standardize positional argument names - [x] Tests for `spack commands --format=bash` coverage - [x] Tests to make sure `spack-completion.bash` stays up-to-date - [x] Tests for `spack-completion.bash` coverage - [x] Speed up `spack-completion.bash` by caching subroutine calls This PR also necessitates a significant refactoring of `ArgparseWriter`. Previously, `ArgparseWriter` was mostly a single `_write` method which handled everything from extracting the information we care about from the parser to formatting the output. Now, `_write` only handles recursion, while the information extraction is split into a separate `parse` method, and the formatting is handled by `format`. This allows subclasses to completely redefine how the format will appear without overriding all of `_write`. Co-Authored-by: Todd Gamblin <tgamblin@llnl.gov>
Diffstat (limited to 'share/spack/qa')
-rwxr-xr-xshare/spack/qa/completion-test.sh89
-rwxr-xr-xshare/spack/qa/run-unit-tests17
-rwxr-xr-xshare/spack/qa/setup-env-test.sh195
-rwxr-xr-xshare/spack/qa/test-framework.sh195
-rwxr-xr-xshare/spack/qa/update-completion-scripts.sh23
5 files changed, 329 insertions, 190 deletions
diff --git a/share/spack/qa/completion-test.sh b/share/spack/qa/completion-test.sh
new file mode 100755
index 0000000000..5b326b4a6d
--- /dev/null
+++ b/share/spack/qa/completion-test.sh
@@ -0,0 +1,89 @@
+#!/bin/sh
+#
+# 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)
+
+#
+# This script tests that Spack's tab completion scripts work.
+#
+# The tests are portable to bash, zsh, and bourne shell, and can be run
+# in any of these shells.
+#
+
+export QA_DIR=$(dirname "$0")
+export SHARE_DIR=$(cd "$QA_DIR/.." && pwd)
+export SPACK_ROOT=$(cd "$QA_DIR/../../.." && pwd)
+
+. "$QA_DIR/test-framework.sh"
+
+# Fail on undefined variables
+set -u
+
+# Source setup-env.sh before tests
+. "$SHARE_DIR/setup-env.sh"
+. "$SHARE_DIR/spack-completion.$_sp_shell"
+
+title "Testing spack-completion.$_sp_shell with $_sp_shell"
+
+# Spack command is now available
+succeeds which spack
+
+title 'Testing all subcommands'
+while IFS= read -r line
+do
+ # Test that completion with no args works
+ succeeds _spack_completions ${line[*]} ''
+
+ # Test that completion with flags works
+ contains '-h --help' _spack_completions ${line[*]} -
+done <<- EOF
+ $(spack commands --aliases --format=subcommands)
+EOF
+
+title 'Testing for correct output'
+contains 'compiler' _spack_completions spack ''
+contains 'install' _spack_completions spack inst
+contains 'find' _spack_completions spack help ''
+contains 'hdf5' _spack_completions spack list ''
+contains 'py-numpy' _spack_completions spack list py-
+contains 'mpi' _spack_completions spack providers ''
+contains 'builtin' _spack_completions spack repo remove ''
+contains 'packages' _spack_completions spack config edit ''
+contains 'python' _spack_completions spack extensions ''
+contains 'hdf5' _spack_completions spack -d install --jobs 8 ''
+contains 'hdf5' _spack_completions spack install -v ''
+
+# XFAIL: Fails for Python 2.6 because pkg_resources not found?
+#contains 'compilers.py' _spack_completions spack test ''
+
+title 'Testing debugging functions'
+
+# This is a particularly tricky case that involves the following situation:
+# `spack -d [] install `
+# Here, [] represents the cursor, which is in the middle of the line.
+# We should tab-complete optional flags for `spack`, not optional flags for
+# `spack install` or package names.
+COMP_LINE='spack -d install '
+COMP_POINT=9
+COMP_WORDS=(spack -d install)
+COMP_CWORD=2
+COMP_KEY=9
+COMP_TYPE=64
+
+_bash_completion_spack
+contains "--all-help" echo "${COMPREPLY[@]}"
+
+contains "['spack', '-d', 'install', '']" _pretty_print COMP_WORDS[@]
+
+# Set the rest of the intermediate variables manually
+COMP_WORDS_NO_FLAGS=(spack install)
+COMP_CWORD_NO_FLAGS=1
+subfunction=_spack
+cur=
+
+list_options=true
+contains "'True'" _test_vars
+list_options=false
+contains "'False'" _test_vars
diff --git a/share/spack/qa/run-unit-tests b/share/spack/qa/run-unit-tests
index 8ba6eed350..52748dacdf 100755
--- a/share/spack/qa/run-unit-tests
+++ b/share/spack/qa/run-unit-tests
@@ -23,7 +23,7 @@
ORIGINAL_PATH="$PATH"
. "$(dirname $0)/setup.sh"
-check_dependencies ${coverage} git hg svn
+check_dependencies $coverage git hg svn
# Move to root directory of Spack
# Allows script to be run from anywhere
@@ -46,7 +46,7 @@ extra_args=""
if [[ -n "$@" ]]; then
extra_args="-k $@"
fi
-${coverage_run} bin/spack test -x --verbose "$extra_args"
+$coverage_run bin/spack test -x --verbose "$extra_args"
#-----------------------------------------------------------
# Run tests for setup-env.sh
@@ -57,15 +57,18 @@ export PATH="$ORIGINAL_PATH"
unset spack
# start in the spack root directory
-cd $SPACK_ROOT
+cd "$SPACK_ROOT"
# Run bash tests with coverage enabled, but pipe output to /dev/null
# because it seems that kcov seems to undo the script's redirection
if [ "$BASH_COVERAGE" = true ]; then
- ${QA_DIR}/bashcov ${QA_DIR}/setup-env-test.sh &> /dev/null
+ "$QA_DIR/bashcov" "$QA_DIR/setup-env-test.sh" &> /dev/null
+ "$QA_DIR/bashcov" "$QA_DIR/completion-test.sh" &> /dev/null
fi
# run the test scripts for their output (these will print nicely)
-bash ${QA_DIR}/setup-env-test.sh
-zsh ${QA_DIR}/setup-env-test.sh
-dash ${QA_DIR}/setup-env-test.sh
+bash "$QA_DIR/setup-env-test.sh"
+zsh "$QA_DIR/setup-env-test.sh"
+dash "$QA_DIR/setup-env-test.sh"
+
+bash "$QA_DIR/completion-test.sh"
diff --git a/share/spack/qa/setup-env-test.sh b/share/spack/qa/setup-env-test.sh
index 7613637984..66284d1a96 100755
--- a/share/spack/qa/setup-env-test.sh
+++ b/share/spack/qa/setup-env-test.sh
@@ -12,159 +12,11 @@
# in any of these shells.
#
-# ------------------------------------------------------------------------
-# Functions for color output.
-# ------------------------------------------------------------------------
-
-# Colors for output
-red='\033[1;31m'
-cyan='\033[1;36m'
-green='\033[1;32m'
-reset='\033[0m'
-
-echo_red() {
- printf "${red}$*${reset}\n"
-}
-
-echo_green() {
- printf "${green}$*${reset}\n"
-}
-
-echo_msg() {
- printf "${cyan}$*${reset}\n"
-}
-
-# ------------------------------------------------------------------------
-# Generic functions for testing shell code.
-# ------------------------------------------------------------------------
-
-# counts of test successes and failures.
-success=0
-errors=0
-
-# Print out a header for a group of tests.
-title() {
- echo
- echo_msg "$@"
- echo_msg "---------------------------------"
-}
-
-# echo FAIL in red text; increment failures
-fail() {
- echo_red FAIL
- errors=$((errors+1))
-}
-
-#
-# Echo SUCCESS in green; increment successes
-#
-pass() {
- echo_green SUCCESS
- success=$((success+1))
-}
-
-#
-# Run a command and suppress output unless it fails.
-# On failure, echo the exit code and output.
-#
-succeeds() {
- printf "'%s' succeeds ... " "$*"
- output=$($* 2>&1)
- err="$?"
-
- if [ "$err" != 0 ]; then
- fail
- echo_red "Command failed with error $err."
- if [ -n "$output" ]; then
- echo_msg "Output:"
- echo "$output"
- else
- echo_msg "No output."
- fi
- else
- pass
- fi
-}
-
-#
-# Run a command and suppress output unless it succeeds.
-# If the command succeeds, echo the output.
-#
-fails() {
- printf "'%s' fails ... " "$*"
- output=$("$@" 2>&1)
- err="$?"
-
- if [ "$err" = 0 ]; then
- fail
- echo_red "Command failed with error $err."
- if [ -n "$output" ]; then
- echo_msg "Output:"
- echo "$output"
- else
- echo_msg "No output."
- fi
- else
- pass
- fi
-}
-
-#
-# Ensure that a string is in the output of a command.
-# Suppresses output on success.
-# On failure, echo the exit code and output.
-#
-contains() {
- string="$1"
- shift
-
- printf "'%s' output contains '$string' ... " "$*"
- output=$("$@" 2>&1)
- err="$?"
-
- if [ "${output#*$string}" = "${output}" ]; then
- fail
- echo_red "Command exited with error $err."
- echo_red "'$string' was not in output."
- if [ -n "$output" ]; then
- echo_msg "Output:"
- echo "$output"
- else
- echo_msg "No output."
- fi
- else
- pass
- fi
-}
-
-#
-# Ensure that a variable is set.
-#
-is_set() {
- printf "'%s' is set ... " "$1"
- if eval "[ -z \${${1:-}+x} ]"; then
- fail
- echo_msg "$1 was not set!"
- else
- pass
- fi
-}
-
-#
-# Ensure that a variable is not set.
-# Fails and prints the value of the variable if it is set.
-#
-is_not_set() {
- printf "'%s' is not set ... " "$1"
- if eval "[ ! -z \${${1:-}+x} ]"; then
- fail
- echo_msg "$1 was set:"
- echo " $1"
- else
- pass
- fi
-}
+export QA_DIR=$(dirname "$0")
+export SHARE_DIR=$(cd "$QA_DIR/.." && pwd)
+export SPACK_ROOT=$(cd "$QA_DIR/../../.." && pwd)
+. "$QA_DIR/test-framework.sh"
# -----------------------------------------------------------------------
# Instead of invoking the module commands, we print the
@@ -184,28 +36,28 @@ module() {
# Make sure no environment is active
unset SPACK_ENV
-# fail on undefined variables
+# Fail on undefined variables
set -u
# Source setup-env.sh before tests
-. share/spack/setup-env.sh
+. "$SHARE_DIR/setup-env.sh"
-# bash should expand aliases even when non-interactive
+# Bash should expand aliases even when non-interactive
if [ -n "${BASH:-}" ]; then
shopt -s expand_aliases
fi
title "Testing setup-env.sh with $_sp_shell"
-# spack command is now avaialble
+# Spack command is now available
succeeds which spack
-# mock cd command (intentionally define only AFTER setup-env.sh)
+# Mock cd command (intentionally define only AFTER setup-env.sh)
cd() {
echo cd "$@"
}
-# create a fake mock package install and store its location for later
+# Create a fake mock package install and store its location for later
title "Setup"
echo "Creating a mock package installation"
spack -m install --fake a
@@ -215,19 +67,13 @@ a_module=$(spack -m module tcl find a)
b_install=$(spack location -i b)
b_module=$(spack -m module tcl find b)
-# create a test environment for tesitng environment commands
+# Create a test environment for testing environment commands
echo "Creating a mock environment"
spack env create spack_test_env
test_env_location=$(spack location -e spack_test_env)
-# ensure that we uninstall b on exit
+# Ensure that we uninstall b on exit
cleanup() {
- if [ "$?" != 0 ]; then
- trapped_error=true
- else
- trapped_error=false
- fi
-
echo "Removing test environment before exiting."
spack env deactivate 2>&1 > /dev/null
spack env rm -y spack_test_env
@@ -235,24 +81,7 @@ cleanup() {
title "Cleanup"
echo "Removing test packages before exiting."
spack -m uninstall -yf b a
-
- echo
- echo "$success tests succeeded."
- echo "$errors tests failed."
-
- if [ "$trapped_error" = true ]; then
- echo "Exited due to an error."
- fi
-
- if [ "$errors" = 0 ] && [ "$trapped_error" = false ]; then
- pass
- exit 0
- else
- fail
- exit 1
- fi
}
-trap cleanup EXIT
# -----------------------------------------------------------------------
# Test all spack commands with special env support
diff --git a/share/spack/qa/test-framework.sh b/share/spack/qa/test-framework.sh
new file mode 100755
index 0000000000..14b58bbecf
--- /dev/null
+++ b/share/spack/qa/test-framework.sh
@@ -0,0 +1,195 @@
+# 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)
+
+#
+# A testing framework for any POSIX-compatible shell.
+#
+
+# ------------------------------------------------------------------------
+# Functions for color output.
+# ------------------------------------------------------------------------
+
+# Colors for output
+red='\033[1;31m'
+cyan='\033[1;36m'
+green='\033[1;32m'
+reset='\033[0m'
+
+echo_red() {
+ printf "${red}$*${reset}\n"
+}
+
+echo_green() {
+ printf "${green}$*${reset}\n"
+}
+
+echo_msg() {
+ printf "${cyan}$*${reset}\n"
+}
+
+# ------------------------------------------------------------------------
+# Generic functions for testing shell code.
+# ------------------------------------------------------------------------
+
+# counts of test successes and failures.
+success=0
+errors=0
+
+# Print out a header for a group of tests.
+title() {
+ echo
+ echo_msg "$@"
+ echo_msg "---------------------------------"
+}
+
+# echo FAIL in red text; increment failures
+fail() {
+ echo_red FAIL
+ errors=$((errors+1))
+}
+
+#
+# Echo SUCCESS in green; increment successes
+#
+pass() {
+ echo_green SUCCESS
+ success=$((success+1))
+}
+
+#
+# Run a command and suppress output unless it fails.
+# On failure, echo the exit code and output.
+#
+succeeds() {
+ printf "'%s' succeeds ... " "$*"
+ output=$("$@" 2>&1)
+ err="$?"
+
+ if [ "$err" != 0 ]; then
+ fail
+ echo_red "Command failed with error $err."
+ if [ -n "$output" ]; then
+ echo_msg "Output:"
+ echo "$output"
+ else
+ echo_msg "No output."
+ fi
+ else
+ pass
+ fi
+}
+
+#
+# Run a command and suppress output unless it succeeds.
+# If the command succeeds, echo the output.
+#
+fails() {
+ printf "'%s' fails ... " "$*"
+ output=$("$@" 2>&1)
+ err="$?"
+
+ if [ "$err" = 0 ]; then
+ fail
+ echo_red "Command failed with error $err."
+ if [ -n "$output" ]; then
+ echo_msg "Output:"
+ echo "$output"
+ else
+ echo_msg "No output."
+ fi
+ else
+ pass
+ fi
+}
+
+#
+# Ensure that a string is in the output of a command.
+# Suppresses output on success.
+# On failure, echo the exit code and output.
+#
+contains() {
+ string="$1"
+ shift
+
+ printf "'%s' output contains '$string' ... " "$*"
+ output=$("$@" 2>&1)
+ err="$?"
+
+ if [ "${output#*$string}" = "${output}" ]; then
+ fail
+ echo_red "Command exited with error $err."
+ echo_red "'$string' was not in output."
+ if [ -n "$output" ]; then
+ echo_msg "Output:"
+ echo "$output"
+ else
+ echo_msg "No output."
+ fi
+ else
+ pass
+ fi
+}
+
+#
+# Ensure that a variable is set.
+#
+is_set() {
+ printf "'%s' is set ... " "$1"
+ if eval "[ -z \${${1:-}+x} ]"; then
+ fail
+ echo_msg "$1 was not set!"
+ else
+ pass
+ fi
+}
+
+#
+# Ensure that a variable is not set.
+# Fails and prints the value of the variable if it is set.
+#
+is_not_set() {
+ printf "'%s' is not set ... " "$1"
+ if eval "[ ! -z \${${1:-}+x} ]"; then
+ fail
+ echo_msg "$1 was set:"
+ echo " $1"
+ else
+ pass
+ fi
+}
+
+#
+# Report the number of tests that succeeded and failed on exit.
+#
+teardown() {
+ if [ "$?" != 0 ]; then
+ trapped_error=true
+ else
+ trapped_error=false
+ fi
+
+ if type cleanup &> /dev/null
+ then
+ cleanup
+ fi
+
+ echo
+ echo "$success tests succeeded."
+ echo "$errors tests failed."
+
+ if [ "$trapped_error" = true ]; then
+ echo "Exited due to an error."
+ fi
+
+ if [ "$errors" = 0 ] && [ "$trapped_error" = false ]; then
+ pass
+ exit 0
+ else
+ fail
+ exit 1
+ fi
+}
+
+trap teardown EXIT
diff --git a/share/spack/qa/update-completion-scripts.sh b/share/spack/qa/update-completion-scripts.sh
new file mode 100755
index 0000000000..8fcd321457
--- /dev/null
+++ b/share/spack/qa/update-completion-scripts.sh
@@ -0,0 +1,23 @@
+#!/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