Make graph_ascii support deptypes.

- fix deptype support
- by default, graph command omits build depedencies
- update docs to use deptype args
This commit is contained in:
Todd Gamblin 2016-09-27 23:32:18 -04:00
parent f082d26ddd
commit 05d52752ff
6 changed files with 37 additions and 27 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
/db
/var/spack/stage /var/spack/stage
/var/spack/cache /var/spack/cache
/var/spack/repos/*/index.yaml /var/spack/repos/*/index.yaml

View File

@ -207,7 +207,7 @@ supply ``-p`` to Spack on the command line, before any subcommands.
``spack --profile`` output looks like this: ``spack --profile`` output looks like this:
.. command-output:: spack --profile graph dyninst .. command-output:: spack --profile graph --deptype=nobuild dyninst
:ellipsis: 25 :ellipsis: 25
The bottom of the output shows the top most time consuming functions, The bottom of the output shows the top most time consuming functions,

View File

@ -2888,9 +2888,22 @@ dependency graph. For example:
.. command-output:: spack graph mpileaks .. command-output:: spack graph mpileaks
At the top is the root package in the DAG, with dependency edges At the top is the root package in the DAG, with dependency edges emerging
emerging from it. On a color terminal, the edges are colored by which from it. On a color terminal, the edges are colored by which dependency
dependency they lead to. they lead to.
.. command-output:: spack graph --deptype=all mpileaks
The ``deptype`` argument tells Spack what types of dependencies to graph.
By default it includes link and run dependencies but not build
dependencies. Supplying ``--deptype=all`` will show the build
dependencies as well. This is equivalent to
``--deptype=build,link,run``. Options for ``deptype`` include:
* Any combination of ``build``, ``link``, and ``run`` separated by
commas.
* ``nobuild``, ``nolink``, ``norun`` to omit one type.
* ``all`` or ``alldeps`` for all types of dependencies.
You can also use ``spack graph`` to generate graphs in the widely used You can also use ``spack graph`` to generate graphs in the widely used
`Dot <http://www.graphviz.org/doc/info/lang.html>`_ format. For `Dot <http://www.graphviz.org/doc/info/lang.html>`_ format. For

View File

@ -83,7 +83,7 @@ def graph(parser, args):
setup_parser.parser.print_help() setup_parser.parser.print_help()
return 1 return 1
deptype = alldeps deptype = nobuild
if args.deptype: if args.deptype:
deptype = tuple(args.deptype.split(',')) deptype = tuple(args.deptype.split(','))
validate_deptype(deptype) validate_deptype(deptype)
@ -93,7 +93,7 @@ def graph(parser, args):
graph_dot(specs, static=args.static, deptype=deptype) graph_dot(specs, static=args.static, deptype=deptype)
elif specs: # ascii is default: user doesn't need to provide it explicitly elif specs: # ascii is default: user doesn't need to provide it explicitly
graph_ascii(specs[0], debug=spack.debug) graph_ascii(specs[0], debug=spack.debug, deptype=deptype)
for spec in specs[1:]: for spec in specs[1:]:
print # extra line bt/w independent graphs print # extra line bt/w independent graphs
graph_ascii(spec, debug=spack.debug) graph_ascii(spec, debug=spack.debug)

View File

@ -72,16 +72,15 @@
__all__ = ['topological_sort', 'graph_ascii', 'AsciiGraph', 'graph_dot'] __all__ = ['topological_sort', 'graph_ascii', 'AsciiGraph', 'graph_dot']
def topological_sort(spec, **kwargs): def topological_sort(spec, reverse=False, deptype=None):
"""Topological sort for specs. """Topological sort for specs.
Return a list of dependency specs sorted topologically. The spec Return a list of dependency specs sorted topologically. The spec
argument is not modified in the process. argument is not modified in the process.
""" """
reverse = kwargs.get('reverse', False) deptype = canonical_deptype(deptype)
# XXX(deptype): iterate over a certain kind of dependency. Maybe color
# edges based on the type of dependency?
if not reverse: if not reverse:
parents = lambda s: s.dependents() parents = lambda s: s.dependents()
children = lambda s: s.dependencies() children = lambda s: s.dependencies()
@ -90,7 +89,7 @@ def topological_sort(spec, **kwargs):
children = lambda s: s.dependents() children = lambda s: s.dependents()
# Work on a copy so this is nondestructive. # Work on a copy so this is nondestructive.
spec = spec.copy() spec = spec.copy(deps=deptype)
nodes = spec.index() nodes = spec.index()
topo_order = [] topo_order = []
@ -142,6 +141,7 @@ def __init__(self):
self.node_character = '*' self.node_character = '*'
self.debug = False self.debug = False
self.indent = 0 self.indent = 0
self.deptype = alldeps
# These are colors in the order they'll be used for edges. # These are colors in the order they'll be used for edges.
# See llnl.util.tty.color for details on color characters. # See llnl.util.tty.color for details on color characters.
@ -388,7 +388,7 @@ def write(self, spec, **kwargs):
self._out = ColorStream(sys.stdout, color=color) self._out = ColorStream(sys.stdout, color=color)
# We'll traverse the spec in topo order as we graph it. # We'll traverse the spec in topo order as we graph it.
topo_order = topological_sort(spec, reverse=True) topo_order = topological_sort(spec, reverse=True, deptype=self.deptype)
# Work on a copy to be nondestructive # Work on a copy to be nondestructive
spec = spec.copy() spec = spec.copy()
@ -484,27 +484,23 @@ def write(self, spec, **kwargs):
# Replace node with its dependencies # Replace node with its dependencies
self._frontier.pop(i) self._frontier.pop(i)
if node.dependencies(): deps = node.dependencies(self.deptype)
deps = sorted((d.name for d in node.dependencies()), if deps:
reverse=True) deps = sorted((d.name for d in deps), reverse=True)
self._connect_deps(i, deps, "new-deps") # anywhere. self._connect_deps(i, deps, "new-deps") # anywhere.
elif self._frontier: elif self._frontier:
self._collapse_line(i) self._collapse_line(i)
def graph_ascii(spec, **kwargs): def graph_ascii(spec, node='o', out=None, debug=False,
node_character = kwargs.get('node', 'o') indent=0, color=None, deptype=None):
out = kwargs.pop('out', None)
debug = kwargs.pop('debug', False)
indent = kwargs.pop('indent', 0)
color = kwargs.pop('color', None)
check_kwargs(kwargs, graph_ascii)
graph = AsciiGraph() graph = AsciiGraph()
graph.debug = debug graph.debug = debug
graph.indent = indent graph.indent = indent
graph.node_character = node_character graph.node_character = node
if deptype:
graph.deptype = canonical_deptype(deptype)
graph.write(spec, color=color, out=out) graph.write(spec, color=color, out=out)

View File

@ -194,6 +194,7 @@
norun = ('link', 'build') norun = ('link', 'build')
special_types = { special_types = {
'alldeps': alldeps, 'alldeps': alldeps,
'all': alldeps, # allow "all" as string but not symbol.
'nolink': nolink, 'nolink': nolink,
'nobuild': nobuild, 'nobuild': nobuild,
'norun': norun, 'norun': norun,
@ -1418,12 +1419,11 @@ def flat_dependencies_with_deptype(self, **kwargs):
# parser doesn't allow it. Spack must be broken! # parser doesn't allow it. Spack must be broken!
raise InconsistentSpecError("Invalid Spec DAG: %s" % e.message) raise InconsistentSpecError("Invalid Spec DAG: %s" % e.message)
def index(self): def index(self, deptype=None):
"""Return DependencyMap that points to all the dependencies in this """Return DependencyMap that points to all the dependencies in this
spec.""" spec."""
dm = DependencyMap() dm = DependencyMap()
# XXX(deptype): use a deptype kwarg. for spec in self.traverse(deptype=deptype):
for spec in self.traverse():
dm[spec.name] = spec dm[spec.name] = spec
return dm return dm