From f1900f6a7b080a6b45392d356749e2a98de46398 Mon Sep 17 00:00:00 2001
From: Brett Viren <brett.viren@gmail.com>
Date: Sun, 8 May 2016 10:25:21 -0400
Subject: [PATCH] Add a 'print' view allowing genreation of arbitrary strings
 based on format using package/spec parameters.

---
 lib/spack/spack/cmd/view.py | 64 +++++++++++++++++++++++++++++++++++--
 1 file changed, 61 insertions(+), 3 deletions(-)

diff --git a/lib/spack/spack/cmd/view.py b/lib/spack/spack/cmd/view.py
index 31937b39a2..b504dfd2b1 100644
--- a/lib/spack/spack/cmd/view.py
+++ b/lib/spack/spack/cmd/view.py
@@ -38,11 +38,12 @@
   the union of the hierarchies of the installed packages in the DAG
   where installed files are referenced via symlinks.  
 
-- hardlink :: like the symlink view but hardlinks are used
+- hardlink :: like the symlink view but hardlinks are used.
 
 - statlink :: a view producing a status report of a symlink or
   hardlink view.
 
+- format :: a view printing one string per spec following a given format.
 
 The file system view concept is imspired by Nix, implemented by
 brett.viren@gmail.com ca 2016.
@@ -64,6 +65,7 @@
 
 import os
 import re
+import sys
 import argparse
 
 import spack
@@ -86,6 +88,9 @@ def setup_parser(sp):
 
     ssp = sp.add_subparsers(metavar='ACTION', dest='action')
 
+    specs_opts = dict(metavar='spec', nargs='+', 
+                      help="Seed specs of the packages to view.")
+
     # The action parameterizes the command but in keeping with Spack
     # patterns we make it a subcommand.
     file_system_view_actions = [
@@ -102,9 +107,15 @@ def setup_parser(sp):
     for act in file_system_view_actions:
         act.add_argument('path', nargs=1,
                          help="Path to file system view directory.")
-        act.add_argument('specs', metavar='spec', nargs='+', 
-                         help="Seed specs of the packages to view.")
+        act.add_argument('specs', **specs_opts)
         
+    # The formatted print action.
+    act = ssp.add_parser('print',
+                         help="Print a string to stdout based on given format")
+    act.add_argument('format', nargs=1, 
+                     help="Format describing per-package printout.")
+    act.add_argument('specs', **specs_opts)
+
     ## Other VIEW ACTIONS might be added here.
     ## Some ideas are the following (and some are redundant with existing cmds)
     ## A JSON view that dumps a DAG to a JSON file
@@ -170,6 +181,39 @@ def flatten(seeds, descend=True):
         flat.update(spec.normalized().traverse())
     return flat
 
+def spec2dict(spec):
+    'Convert info in a spec into a simple dictionary.'
+
+    # Expclitly convert instead of just returning spec.__dict__ as
+    # some things need processing or are properties.
+    #
+    pkg = spec.package
+    ret = dict(name = spec.name,
+               short = spec.short_spec,
+               cshort = spec.cshort_spec, # color
+               root = spec.root,
+               prefix = spec.prefix,
+               version = spec.version,
+               variants = spec.variants,
+               namespace = spec.namespace,
+               compiler = spec.compiler,
+               architecture = spec.architecture,
+               dependencies = ','.join(spec.dependencies.keys()),
+               dependents = ','.join(spec.dependents.keys()),
+               external = spec.external or "False",
+               hash = spec.dag_hash(),
+
+               # package related:
+               url = pkg.url,
+               stage = pkg.stage.path,
+               installed = pkg.installed,
+               installed_dependents = ','.join([s.name for s in pkg.installed_dependents]),
+               build_log = pkg.build_log_path,
+               rpath = ':'.join(pkg.rpath),
+
+               # ...
+               )
+    return ret
 
 ### Action-specific helpers
 
@@ -270,6 +314,20 @@ def visitor_statlink(specs, args):
 visitor_status = visitor_statlink
 visitor_check = visitor_statlink
 
+def visitor_print(specs, args):
+    'Print a string for each spec using args.format.'
+    fmt = args.format[0]
+    for spec in specs:
+        kwds = spec2dict(spec)
+        try:
+            string = fmt.format(**kwds)
+        except KeyError:
+            tty.error("Format error, use keywords: %s" % (', '.join(kwds.keys()), ))
+            raise
+        # argparser escapes these
+        string = string.replace(r'\n', '\n').replace(r'\t', '\t')
+        sys.stdout.write(string)
+
 
 # Finally, the actual "view" command.  There should be no need to
 # modify anything below when new actions are added.
-- 
GitLab