From 2c45c3c5b3d29319260d76ed489340f86463ee5f Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Sun, 29 Jul 2018 11:54:20 -0700 Subject: spec: `Spec.tree()` merges deptypes when only covering nodes (#8821) - previously, output could be confusing when deptypes were only shown for one dependent when a node had *multiple* dependents - also fix default coverage of `Spec.tree()`: it previously defaulted to cover only build and link dependencies, but this is a holdover from when those were the only types. --- lib/spack/spack/spec.py | 21 ++++++++++++++------ lib/spack/spack/test/cmd/spec.py | 43 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 56 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py index 33ca196ad9..cd12a46b60 100644 --- a/lib/spack/spack/spec.py +++ b/lib/spack/spack/spec.py @@ -3198,7 +3198,7 @@ class Spec(object): fmt = kwargs.pop('format', '$_$@$%@+$+$=') prefix = kwargs.pop('prefix', None) show_types = kwargs.pop('show_types', False) - deptypes = kwargs.pop('deptypes', ('build', 'link')) + deptypes = kwargs.pop('deptypes', 'all') check_kwargs(kwargs, self.tree) out = "" @@ -3226,12 +3226,21 @@ class Spec(object): out += colorize('@K{%s} ', color=color) % node.dag_hash(hlen) if show_types: + types = set() + if cover == 'nodes': + # when only covering nodes, we merge dependency types + # from all dependents before showing them. + for name, ds in node.dependents_dict().items(): + if ds.deptypes: + types.update(set(ds.deptypes)) + elif dep_spec.deptypes: + # when covering edges or paths, we show dependency + # types only for the edge through which we visited + types = set(dep_spec.deptypes) + out += '[' - if dep_spec.deptypes: - for t in all_deptypes: - out += ''.join(t[0] if t in dep_spec.deptypes else ' ') - else: - out += ' ' * len(all_deptypes) + for t in all_deptypes: + out += ''.join(t[0] if t in types else ' ') out += '] ' out += (" " * d) diff --git a/lib/spack/spack/test/cmd/spec.py b/lib/spack/spack/test/cmd/spec.py index 1f0501e530..75d91bcddf 100644 --- a/lib/spack/spack/test/cmd/spec.py +++ b/lib/spack/spack/test/cmd/spec.py @@ -22,13 +22,18 @@ # License along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ############################################################################## +import re +import pytest + import spack.spec from spack.main import SpackCommand +pytestmark = pytest.mark.usefixtures('config', 'mutable_mock_packages') + spec = SpackCommand('spec') -def test_spec(mock_packages, config): +def test_spec(): output = spec('mpileaks') assert 'mpileaks@2.3' in output @@ -39,7 +44,7 @@ def test_spec(mock_packages, config): assert 'mpich@3.0.4' in output -def test_spec_yaml(mock_packages, config): +def test_spec_yaml(): output = spec('--yaml', 'mpileaks') mpileaks = spack.spec.Spec.from_yaml(output) @@ -49,3 +54,37 @@ def test_spec_yaml(mock_packages, config): assert 'libdwarf' in mpileaks assert 'libelf' in mpileaks assert 'mpich' in mpileaks + + +def _parse_types(string): + """Parse deptypes for specs from `spack spec -t` output.""" + lines = string.strip().split('\n') + + result = {} + for line in lines: + match = re.match(r'\[([^]]*)\]\s*\^?([^@]*)@', line) + if match: + types, name = match.groups() + result.setdefault(name, []).append(types) + result[name] = sorted(result[name]) + return result + + +def test_spec_deptypes_nodes(): + output = spec('--types', '--cover', 'nodes', 'dt-diamond') + types = _parse_types(output) + + assert types['dt-diamond'] == [' '] + assert types['dt-diamond-left'] == ['bl '] + assert types['dt-diamond-right'] == ['bl '] + assert types['dt-diamond-bottom'] == ['blr '] + + +def test_spec_deptypes_edges(): + output = spec('--types', '--cover', 'edges', 'dt-diamond') + types = _parse_types(output) + + assert types['dt-diamond'] == [' '] + assert types['dt-diamond-left'] == ['bl '] + assert types['dt-diamond-right'] == ['bl '] + assert types['dt-diamond-bottom'] == ['b ', 'blr '] -- cgit v1.2.3-60-g2f50