From 05d52752fff1a6435f9173a2e1a6c6ab45232c3c Mon Sep 17 00:00:00 2001
From: Todd Gamblin <tgamblin@llnl.gov>
Date: Tue, 27 Sep 2016 23:32:18 -0400
Subject: Make graph_ascii support deptypes.

- fix deptype support
- by default, graph command omits build depedencies
- update docs to use deptype args
---
 .gitignore                         |  1 +
 lib/spack/docs/configuration.rst   |  2 +-
 lib/spack/docs/packaging_guide.rst | 19 ++++++++++++++++---
 lib/spack/spack/cmd/graph.py       |  4 ++--
 lib/spack/spack/graph.py           | 32 ++++++++++++++------------------
 lib/spack/spack/spec.py            |  6 +++---
 6 files changed, 37 insertions(+), 27 deletions(-)

diff --git a/.gitignore b/.gitignore
index 072bf30c07..e6200a0676 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+/db
 /var/spack/stage
 /var/spack/cache
 /var/spack/repos/*/index.yaml
diff --git a/lib/spack/docs/configuration.rst b/lib/spack/docs/configuration.rst
index ba534d1e62..6de823c845 100644
--- a/lib/spack/docs/configuration.rst
+++ b/lib/spack/docs/configuration.rst
@@ -207,7 +207,7 @@ supply ``-p`` to Spack on the command line, before any subcommands.
 
 ``spack --profile`` output looks like this:
 
-.. command-output:: spack --profile graph dyninst
+.. command-output:: spack --profile graph --deptype=nobuild dyninst
    :ellipsis: 25
 
 The bottom of the output shows the top most time consuming functions,
diff --git a/lib/spack/docs/packaging_guide.rst b/lib/spack/docs/packaging_guide.rst
index 0294f32748..70cd58f6c1 100644
--- a/lib/spack/docs/packaging_guide.rst
+++ b/lib/spack/docs/packaging_guide.rst
@@ -2888,9 +2888,22 @@ dependency graph.  For example:
 
 .. command-output:: spack graph mpileaks
 
-At the top is the root package in the DAG, with dependency edges
-emerging from it.  On a color terminal, the edges are colored by which
-dependency they lead to.
+At the top is the root package in the DAG, with dependency edges emerging
+from it.  On a color terminal, the edges are colored by which dependency
+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
 `Dot <http://www.graphviz.org/doc/info/lang.html>`_ format.  For
diff --git a/lib/spack/spack/cmd/graph.py b/lib/spack/spack/cmd/graph.py
index 6de1ed974b..3f7ab8bc2f 100644
--- a/lib/spack/spack/cmd/graph.py
+++ b/lib/spack/spack/cmd/graph.py
@@ -83,7 +83,7 @@ def graph(parser, args):
         setup_parser.parser.print_help()
         return 1
 
-    deptype = alldeps
+    deptype = nobuild
     if args.deptype:
         deptype = tuple(args.deptype.split(','))
         validate_deptype(deptype)
@@ -93,7 +93,7 @@ def graph(parser, args):
         graph_dot(specs, static=args.static, deptype=deptype)
 
     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:]:
             print  # extra line bt/w independent graphs
             graph_ascii(spec, debug=spack.debug)
diff --git a/lib/spack/spack/graph.py b/lib/spack/spack/graph.py
index acb6ee50de..f474799275 100644
--- a/lib/spack/spack/graph.py
+++ b/lib/spack/spack/graph.py
@@ -72,16 +72,15 @@ from spack.spec import *
 __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.
 
     Return a list of dependency specs sorted topologically.  The spec
     argument is not modified in the process.
 
     """
-    reverse = kwargs.get('reverse', False)
-    # XXX(deptype): iterate over a certain kind of dependency. Maybe color
-    #               edges based on the type of dependency?
+    deptype = canonical_deptype(deptype)
+
     if not reverse:
         parents = lambda s: s.dependents()
         children = lambda s: s.dependencies()
@@ -90,7 +89,7 @@ def topological_sort(spec, **kwargs):
         children = lambda s: s.dependents()
 
     # Work on a copy so this is nondestructive.
-    spec = spec.copy()
+    spec = spec.copy(deps=deptype)
     nodes = spec.index()
 
     topo_order = []
@@ -142,6 +141,7 @@ class AsciiGraph(object):
         self.node_character = '*'
         self.debug = False
         self.indent = 0
+        self.deptype = alldeps
 
         # These are colors in the order they'll be used for edges.
         # See llnl.util.tty.color for details on color characters.
@@ -388,7 +388,7 @@ class AsciiGraph(object):
         self._out = ColorStream(sys.stdout, color=color)
 
         # 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
         spec = spec.copy()
@@ -484,27 +484,23 @@ class AsciiGraph(object):
 
                 # Replace node with its dependencies
                 self._frontier.pop(i)
-                if node.dependencies():
-                    deps = sorted((d.name for d in node.dependencies()),
-                                  reverse=True)
+                deps = node.dependencies(self.deptype)
+                if deps:
+                    deps = sorted((d.name for d in deps), reverse=True)
                     self._connect_deps(i, deps, "new-deps")  # anywhere.
 
                 elif self._frontier:
                     self._collapse_line(i)
 
 
-def graph_ascii(spec, **kwargs):
-    node_character = kwargs.get('node', 'o')
-    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)
-
+def graph_ascii(spec, node='o', out=None, debug=False,
+                indent=0, color=None, deptype=None):
     graph = AsciiGraph()
     graph.debug = debug
     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)
 
diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py
index 108e771748..ba9cea876d 100644
--- a/lib/spack/spack/spec.py
+++ b/lib/spack/spack/spec.py
@@ -194,6 +194,7 @@ nobuild = ('link', 'run')
 norun   = ('link', 'build')
 special_types = {
     'alldeps': alldeps,
+    'all': alldeps,  # allow "all" as string but not symbol.
     'nolink': nolink,
     'nobuild': nobuild,
     'norun': norun,
@@ -1418,12 +1419,11 @@ class Spec(object):
             # parser doesn't allow it. Spack must be broken!
             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
            spec."""
         dm = DependencyMap()
-        # XXX(deptype): use a deptype kwarg.
-        for spec in self.traverse():
+        for spec in self.traverse(deptype=deptype):
             dm[spec.name] = spec
         return dm
 
-- 
cgit v1.2.3-70-g09d2