summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/spack/spack/cmd/__init__.py16
-rw-r--r--lib/spack/spack/cmd/find.py18
-rw-r--r--lib/spack/spack/test/cmd/find.py183
-rw-r--r--lib/spack/spack/test/spec_yaml.py14
-rwxr-xr-xshare/spack/spack-completion.bash5
5 files changed, 217 insertions, 19 deletions
diff --git a/lib/spack/spack/cmd/__init__.py b/lib/spack/spack/cmd/__init__.py
index f47a4602ce..54496dc32d 100644
--- a/lib/spack/spack/cmd/__init__.py
+++ b/lib/spack/spack/cmd/__init__.py
@@ -221,8 +221,8 @@ def display_specs_as_json(specs, deps=False):
sjson.dump(records, sys.stdout)
-def iter_sections(specs, indent, all_headers):
- """Break a list of specs into sections indexed by arch/compiler."""
+def iter_groups(specs, indent, all_headers):
+ """Break a list of specs into groups indexed by arch/compiler."""
# Make a dict with specs keyed by architecture and compiler.
index = index_by(specs, ('architecture', 'compiler'))
ispace = indent * ' '
@@ -278,9 +278,9 @@ def display_specs(specs, args=None, **kwargs):
show_flags (bool): Show compiler flags with specs
variants (bool): Show variants with specs
indent (int): indent each line this much
- sections (bool): display specs grouped by arch/compiler (default True)
+ groups (bool): display specs grouped by arch/compiler (default True)
decorators (dict): dictionary mappng specs to decorators
- header_callback (function): called at start of arch/compiler sections
+ header_callback (function): called at start of arch/compiler groups
all_headers (bool): show headers even when arch/compiler aren't defined
"""
@@ -300,7 +300,7 @@ def display_specs(specs, args=None, **kwargs):
flags = get_arg('show_flags', False)
full_compiler = get_arg('show_full_compiler', False)
variants = get_arg('variants', False)
- sections = get_arg('sections', True)
+ groups = get_arg('groups', True)
all_headers = get_arg('all_headers', False)
decorator = get_arg('decorator', None)
@@ -338,7 +338,7 @@ def display_specs(specs, args=None, **kwargs):
return string
def format_list(specs):
- """Display a single list of specs, with no sections"""
+ """Display a single list of specs, with no groups"""
# create the final, formatted versions of all specs
formatted = []
for spec in specs:
@@ -367,8 +367,8 @@ def display_specs(specs, args=None, **kwargs):
else:
print(string)
- if sections:
- for specs in iter_sections(specs, indent, all_headers):
+ if groups:
+ for specs in iter_groups(specs, indent, all_headers):
format_list(specs)
else:
format_list(sorted(specs))
diff --git a/lib/spack/spack/cmd/find.py b/lib/spack/spack/cmd/find.py
index 6376ef6d88..5d6b07f45f 100644
--- a/lib/spack/spack/cmd/find.py
+++ b/lib/spack/spack/cmd/find.py
@@ -35,10 +35,10 @@ def setup_parser(subparser):
subparser.add_argument('-p', '--paths', action='store_true',
help='show paths to package install directories')
subparser.add_argument(
- '--sections', action='store_true', default=None, dest='sections',
- help='group specs in arch/compiler sections (default on)')
+ '--groups', action='store_true', default=None, dest='groups',
+ help='display specs in arch/compiler groups (default on)')
subparser.add_argument(
- '--no-sections', action='store_false', default=None, dest='sections',
+ '--no-groups', action='store_false', default=None, dest='groups',
help='do not group specs by arch/compiler')
arguments.add_common_arguments(
@@ -177,16 +177,16 @@ def find(parser, args):
if env:
decorator, added, roots, removed = setup_env(env)
- # use sections by default except with format.
- if args.sections is None:
- args.sections = not args.format
+ # use groups by default except with format.
+ if args.groups is None:
+ args.groups = not args.format
- # Exit early if no package matches the constraint
+ # Exit early with an error code if no package matches the constraint
if not results and args.constraint:
msg = "No package matches the query: {0}"
msg = msg.format(' '.join(args.constraint))
tty.msg(msg)
- return
+ return 1
# If tags have been specified on the command line, filter by tags
if args.tags:
@@ -199,7 +199,7 @@ def find(parser, args):
else:
if env:
display_env(env, args, decorator)
- if args.sections:
+ if args.groups:
tty.msg("%s" % plural(len(results), 'installed package'))
cmd.display_specs(
results, args, decorator=decorator, all_headers=True)
diff --git a/lib/spack/spack/test/cmd/find.py b/lib/spack/spack/test/cmd/find.py
index 7abe63cd4f..c457b8ffac 100644
--- a/lib/spack/spack/test/cmd/find.py
+++ b/lib/spack/spack/test/cmd/find.py
@@ -4,15 +4,20 @@
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import argparse
+import json
import pytest
+import spack.cmd as cmd
import spack.cmd.find
from spack.main import SpackCommand
+from spack.spec import Spec
from spack.util.pattern import Bunch
find = SpackCommand('find')
+base32_alphabet = 'abcdefghijklmnopqrstuvwxyz234567'
+
@pytest.fixture(scope='module')
def parser():
@@ -111,3 +116,181 @@ def test_namespaces_shown_correctly(database):
out = find('--namespace')
assert 'builtin.mock.zmpi' in out
+
+
+def _check_json_output(spec_list):
+ assert len(spec_list) == 3
+ assert all(spec["name"] == "mpileaks" for spec in spec_list)
+
+ deps = [spec["dependencies"] for spec in spec_list]
+ assert sum(["zmpi" in d for d in deps]) == 1
+ assert sum(["mpich" in d for d in deps]) == 1
+ assert sum(["mpich2" in d for d in deps]) == 1
+
+
+def _check_json_output_deps(spec_list):
+ assert len(spec_list) == 13
+
+ names = [spec["name"] for spec in spec_list]
+ assert names.count("mpileaks") == 3
+ assert names.count("callpath") == 3
+ assert names.count("zmpi") == 1
+ assert names.count("mpich") == 1
+ assert names.count("mpich2") == 1
+ assert names.count("fake") == 1
+ assert names.count("dyninst") == 1
+ assert names.count("libdwarf") == 1
+ assert names.count("libelf") == 1
+
+
+@pytest.mark.db
+def test_find_json(database):
+ output = find('--json', 'mpileaks')
+ spec_list = json.loads(output)
+ _check_json_output(spec_list)
+
+
+@pytest.mark.db
+def test_find_json_deps(database):
+ output = find('-d', '--json', 'mpileaks')
+ spec_list = json.loads(output)
+ _check_json_output_deps(spec_list)
+
+
+@pytest.mark.db
+def test_display_json(database, capsys):
+ specs = [Spec(s).concretized() for s in [
+ "mpileaks ^zmpi",
+ "mpileaks ^mpich",
+ "mpileaks ^mpich2",
+ ]]
+
+ cmd.display_specs_as_json(specs)
+ spec_list = json.loads(capsys.readouterr()[0])
+ _check_json_output(spec_list)
+
+ cmd.display_specs_as_json(specs + specs + specs)
+ spec_list = json.loads(capsys.readouterr()[0])
+ _check_json_output(spec_list)
+
+
+@pytest.mark.db
+def test_display_json_deps(database, capsys):
+ specs = [Spec(s).concretized() for s in [
+ "mpileaks ^zmpi",
+ "mpileaks ^mpich",
+ "mpileaks ^mpich2",
+ ]]
+
+ cmd.display_specs_as_json(specs, deps=True)
+ spec_list = json.loads(capsys.readouterr()[0])
+ _check_json_output_deps(spec_list)
+
+ cmd.display_specs_as_json(specs + specs + specs, deps=True)
+ spec_list = json.loads(capsys.readouterr()[0])
+ _check_json_output_deps(spec_list)
+
+
+@pytest.mark.db
+def test_find_format(database, config):
+ output = find('--format', '{name}-{^mpi.name}', 'mpileaks')
+ assert set(output.strip().split('\n')) == set([
+ "mpileaks-zmpi",
+ "mpileaks-mpich",
+ "mpileaks-mpich2",
+ ])
+
+ output = find('--format', '{name}-{version}-{compiler.name}-{^mpi.name}',
+ 'mpileaks')
+ assert set(output.strip().split('\n')) == set([
+ "mpileaks-2.3-gcc-zmpi",
+ "mpileaks-2.3-gcc-mpich",
+ "mpileaks-2.3-gcc-mpich2",
+ ])
+
+ output = find('--format', '{name}-{^mpi.name}-{hash:7}',
+ 'mpileaks')
+ elements = output.strip().split('\n')
+ assert set(e[:-7] for e in elements) == set([
+ "mpileaks-zmpi-",
+ "mpileaks-mpich-",
+ "mpileaks-mpich2-",
+ ])
+
+ # hashes are in base32
+ for e in elements:
+ for c in e[-7:]:
+ assert c in base32_alphabet
+
+
+@pytest.mark.db
+def test_find_format_deps(database, config):
+ output = find('-d', '--format', '{name}-{version}', 'mpileaks', '^zmpi')
+ assert output == """\
+mpileaks-2.3
+ callpath-1.0
+ dyninst-8.2
+ libdwarf-20130729
+ libelf-0.8.13
+ zmpi-1.0
+ fake-1.0
+
+"""
+
+
+@pytest.mark.db
+def test_find_format_deps_paths(database, config):
+ output = find('-dp', '--format', '{name}-{version}', 'mpileaks', '^zmpi')
+
+ spec = Spec("mpileaks ^zmpi").concretized()
+ prefixes = [s.prefix for s in spec.traverse()]
+
+ assert output == """\
+mpileaks-2.3 {0}
+ callpath-1.0 {1}
+ dyninst-8.2 {2}
+ libdwarf-20130729 {3}
+ libelf-0.8.13 {4}
+ zmpi-1.0 {5}
+ fake-1.0 {6}
+
+""".format(*prefixes)
+
+
+@pytest.mark.db
+def test_find_very_long(database, config):
+ output = find('-L', '--no-groups', "mpileaks")
+
+ specs = [Spec(s).concretized() for s in [
+ "mpileaks ^zmpi",
+ "mpileaks ^mpich",
+ "mpileaks ^mpich2",
+ ]]
+
+ assert set(output.strip().split("\n")) == set([
+ ("%s mpileaks@2.3" % s.dag_hash()) for s in specs
+ ])
+
+
+@pytest.mark.db
+def test_find_show_compiler(database, config):
+ output = find('--no-groups', '--show-full-compiler', "mpileaks")
+ assert "mpileaks@2.3%gcc@4.5.0" in output
+
+
+@pytest.mark.db
+def test_find_not_found(database, config, capsys):
+ with capsys.disabled():
+ output = find("foobarbaz", fail_on_error=False)
+ assert "No package matches the query: foobarbaz" in output
+ assert find.returncode == 1
+
+
+@pytest.mark.db
+def test_find_no_sections(database, config):
+ output = find()
+ assert "-----------" in output
+
+ output = find("--no-groups")
+ assert "-----------" not in output
+ assert "==>" not in output
diff --git a/lib/spack/spack/test/spec_yaml.py b/lib/spack/spack/test/spec_yaml.py
index 9943084951..7fd2a36469 100644
--- a/lib/spack/spack/test/spec_yaml.py
+++ b/lib/spack/spack/test/spec_yaml.py
@@ -104,6 +104,20 @@ def test_using_ordered_dict(mock_packages):
assert level >= 5
+def test_to_record_dict(mock_packages, config):
+ specs = ['mpileaks', 'zmpi', 'dttop']
+ for name in specs:
+ spec = Spec(name).concretized()
+ record = spec.to_record_dict()
+ assert record["name"] == name
+ assert "hash" in record
+
+ node = spec.to_node_dict()
+ for key, value in node[name].items():
+ assert key in record
+ assert record[key] == value
+
+
def test_ordered_read_not_required_for_consistent_dag_hash(
config, mock_packages
):
diff --git a/share/spack/spack-completion.bash b/share/spack/spack-completion.bash
index 1edc262d0a..45dae0e171 100755
--- a/share/spack/spack-completion.bash
+++ b/share/spack/spack-completion.bash
@@ -521,7 +521,8 @@ function _spack_fetch {
function _spack_find {
if $list_options
then
- compgen -W "-h --help -s --short -p --paths -d --deps -l --long
+ compgen -W "-h --help -s --short -d --deps -p --paths
+ --format --json --groups --no-groups -l --long
-L --very-long -t --tags -c --show-concretized
-f --show-flags --show-full-compiler -x --explicit
-X --implicit -u --unknown -m --missing -v --variants
@@ -1282,7 +1283,7 @@ function _all_resource_hashes {
}
function _installed_packages {
- spack --color=never find | grep -v "^--"
+ spack --color=never find --no-groups
}
function _installed_compilers {