tests and completions for spack find --json
and spack find --format
This commit is contained in:
parent
2dc7467760
commit
1b877e8e0f
@ -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 get_arg(name, default=None):
|
||||
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 fmt(s, depth=0):
|
||||
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 format_list(specs):
|
||||
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))
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -104,6 +104,20 @@ def descend_and_check(iterable, level=0):
|
||||
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
|
||||
):
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user