Better spack spec (#2238)
* Add options for hashes, tree depth, and YAML to `spack spec`. - Can now display hashes with `spack spec`, like `spack find`. - Removed the old "ids" argument to `spack spec` (which printed numerical values)b - Can output YAML spec from `spack spec` with `-y` - Can control depth of DAG traversal with --cover=[nodes|edges|paths] - Can print install status (installed, missing, not installed) with -I * Don't use YAML aliases in specs. - Force Spack's YAML dumper to ignore aliases. - aliases cause non-canonical YAML to be used in DAG hash, and result in redundant hashes. - add a test to ensure this behavior stays
This commit is contained in:
parent
9a585e6c6a
commit
2536029ea9
@ -89,3 +89,11 @@ def _specs(self, **kwargs):
|
||||
_arguments['dirty'] = Args(
|
||||
'--dirty', action='store_true', dest='dirty',
|
||||
help='Do NOT clean environment before installing.')
|
||||
|
||||
_arguments['long'] = Args(
|
||||
'-l', '--long', action='store_true',
|
||||
help='Show dependency hashes as well as versions.')
|
||||
|
||||
_arguments['very_long'] = Args(
|
||||
'-L', '--very-long', action='store_true',
|
||||
help='Show full dependency hashes as well as versions.')
|
||||
|
@ -52,14 +52,8 @@ def setup_parser(subparser):
|
||||
const='deps',
|
||||
help='Show full dependency DAG of installed packages')
|
||||
|
||||
subparser.add_argument('-l', '--long',
|
||||
action='store_true',
|
||||
dest='long',
|
||||
help='Show dependency hashes as well as versions.')
|
||||
subparser.add_argument('-L', '--very-long',
|
||||
action='store_true',
|
||||
dest='very_long',
|
||||
help='Show dependency hashes as well as versions.')
|
||||
arguments.add_common_arguments(subparser, ['long', 'very_long'])
|
||||
|
||||
subparser.add_argument('-f', '--show-flags',
|
||||
action='store_true',
|
||||
dest='show_flags',
|
||||
|
@ -23,36 +23,57 @@
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
##############################################################################
|
||||
import argparse
|
||||
import spack.cmd
|
||||
|
||||
import spack
|
||||
import spack.cmd
|
||||
import spack.cmd.common.arguments as arguments
|
||||
|
||||
description = "print out abstract and concrete versions of a spec."
|
||||
|
||||
|
||||
def setup_parser(subparser):
|
||||
subparser.add_argument('-i', '--ids', action='store_true',
|
||||
help="show numerical ids for dependencies.")
|
||||
arguments.add_common_arguments(subparser, ['long', 'very_long'])
|
||||
subparser.add_argument(
|
||||
'-y', '--yaml', action='store_true', default=False,
|
||||
help='Print concrete spec as YAML.')
|
||||
subparser.add_argument(
|
||||
'-c', '--cover', action='store',
|
||||
default='nodes', choices=['nodes', 'edges', 'paths'],
|
||||
help='How extensively to traverse the DAG. (default: nodes).')
|
||||
subparser.add_argument(
|
||||
'-I', '--install-status', action='store_true', default=False,
|
||||
help='Show install status of packages. Packages can be: '
|
||||
'installed [+], missing and needed by an installed package [-], '
|
||||
'or not installed (no annotation).')
|
||||
subparser.add_argument(
|
||||
'specs', nargs=argparse.REMAINDER, help="specs of packages")
|
||||
|
||||
|
||||
def spec(parser, args):
|
||||
kwargs = {'ids': args.ids,
|
||||
'indent': 2,
|
||||
'color': True}
|
||||
kwargs = {'color': True,
|
||||
'cover': args.cover,
|
||||
'install_status': args.install_status,
|
||||
'hashes': args.long or args.very_long,
|
||||
'hashlen': None if args.very_long else 7}
|
||||
|
||||
for spec in spack.cmd.parse_specs(args.specs):
|
||||
# With -y, just print YAML to output.
|
||||
if args.yaml:
|
||||
spec.concretize()
|
||||
print spec.to_yaml()
|
||||
continue
|
||||
|
||||
# Print some diagnostic info by default.
|
||||
print "Input spec"
|
||||
print "------------------------------"
|
||||
print "--------------------------------"
|
||||
print spec.tree(**kwargs)
|
||||
|
||||
print "Normalized"
|
||||
print "------------------------------"
|
||||
print "--------------------------------"
|
||||
spec.normalize()
|
||||
print spec.tree(**kwargs)
|
||||
|
||||
print "Concretized"
|
||||
print "------------------------------"
|
||||
print "--------------------------------"
|
||||
spec.concretize()
|
||||
print spec.tree(**kwargs)
|
||||
|
@ -2396,12 +2396,24 @@ def __cmp__(self, other):
|
||||
def __str__(self):
|
||||
return self.format() + self.dep_string()
|
||||
|
||||
def _install_status(self):
|
||||
"""Helper for tree to print DB install status."""
|
||||
if not self.concrete:
|
||||
return None
|
||||
try:
|
||||
record = spack.store.db.get_record(self)
|
||||
return record.installed
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
def tree(self, **kwargs):
|
||||
"""Prints out this spec and its dependencies, tree-formatted
|
||||
with indentation."""
|
||||
color = kwargs.pop('color', False)
|
||||
depth = kwargs.pop('depth', False)
|
||||
showid = kwargs.pop('ids', False)
|
||||
hashes = kwargs.pop('hashes', True)
|
||||
hlen = kwargs.pop('hashlen', None)
|
||||
install_status = kwargs.pop('install_status', True)
|
||||
cover = kwargs.pop('cover', 'nodes')
|
||||
indent = kwargs.pop('indent', 0)
|
||||
fmt = kwargs.pop('format', '$_$@$%@+$+$=')
|
||||
@ -2410,8 +2422,6 @@ def tree(self, **kwargs):
|
||||
check_kwargs(kwargs, self.tree)
|
||||
|
||||
out = ""
|
||||
cur_id = 0
|
||||
ids = {}
|
||||
for d, node in self.traverse(
|
||||
order='pre', cover=cover, depth=True, deptypes=deptypes):
|
||||
if prefix is not None:
|
||||
@ -2419,11 +2429,17 @@ def tree(self, **kwargs):
|
||||
out += " " * indent
|
||||
if depth:
|
||||
out += "%-4d" % d
|
||||
if not id(node) in ids:
|
||||
cur_id += 1
|
||||
ids[id(node)] = cur_id
|
||||
if showid:
|
||||
out += "%-4d" % ids[id(node)]
|
||||
if install_status:
|
||||
status = node._install_status()
|
||||
if status is None:
|
||||
out += " " # Package isn't installed
|
||||
elif status:
|
||||
out += colorize("@g{[+]} ", color=color) # installed
|
||||
else:
|
||||
out += colorize("@r{[-]} ", color=color) # missing
|
||||
|
||||
if hashes:
|
||||
out += colorize('@K{%s} ', color=color) % node.dag_hash(hlen)
|
||||
out += (" " * d)
|
||||
if d > 0:
|
||||
out += "^"
|
||||
|
@ -90,3 +90,19 @@ def check(obj, start_line, end_line):
|
||||
check(self.data['config_file']['some_list'][2], 8, 8)
|
||||
check(self.data['config_file']['another_list'], 10, 10)
|
||||
check(self.data['config_file']['some_key'], 11, 11)
|
||||
|
||||
def test_yaml_aliases(self):
|
||||
aliased_list_1 = ['foo']
|
||||
aliased_list_2 = []
|
||||
dict_with_aliases = {
|
||||
'a': aliased_list_1,
|
||||
'b': aliased_list_1,
|
||||
'c': aliased_list_1,
|
||||
'd': aliased_list_2,
|
||||
'e': aliased_list_2,
|
||||
'f': aliased_list_2,
|
||||
}
|
||||
string = syaml.dump(dict_with_aliases)
|
||||
|
||||
# ensure no YAML aliases appear in syaml dumps.
|
||||
self.assertFalse('*id' in string)
|
||||
|
@ -202,6 +202,11 @@ def represent_mapping(self, tag, mapping, flow_style=None):
|
||||
node.flow_style = best_style
|
||||
return node
|
||||
|
||||
def ignore_aliases(self, _data):
|
||||
"""Make the dumper NEVER print YAML aliases."""
|
||||
return True
|
||||
|
||||
|
||||
# Make our special objects look like normal YAML ones.
|
||||
OrderedLineDumper.add_representer(syaml_dict, OrderedLineDumper.represent_dict)
|
||||
OrderedLineDumper.add_representer(syaml_list, OrderedLineDumper.represent_list)
|
||||
|
Loading…
Reference in New Issue
Block a user