summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd Gamblin <tgamblin@llnl.gov>2019-09-01 16:42:53 -0700
committerTodd Gamblin <tgamblin@llnl.gov>2019-09-02 19:24:48 -0700
commit1a1f5674dfbabf6a9b91933b15304acd7f3e64f0 (patch)
tree83d8608e10f6ae720aa52f535e49834e534e300b
parent64af0a9874f64e058f885cac16b403868d981dc4 (diff)
downloadspack-1a1f5674dfbabf6a9b91933b15304acd7f3e64f0.tar.gz
spack-1a1f5674dfbabf6a9b91933b15304acd7f3e64f0.tar.bz2
spack-1a1f5674dfbabf6a9b91933b15304acd7f3e64f0.tar.xz
spack-1a1f5674dfbabf6a9b91933b15304acd7f3e64f0.zip
command: add `spack find --json`
This is another machine-readable version of `spack find`. Supplying the `--json` argument causes specs to be written out as json records, easily filered with tools like jq. e.g.: $ spack find --json python | jq -C ".[] | { name, version } " [ { "name": "python", "version": "2.7.16" }, { "name": "bzip2", "version": "1.0.8" } ]
-rw-r--r--lib/spack/spack/cmd/__init__.py19
-rw-r--r--lib/spack/spack/cmd/find.py11
-rw-r--r--lib/spack/spack/environment.py1
-rw-r--r--lib/spack/spack/spec.py25
4 files changed, 52 insertions, 4 deletions
diff --git a/lib/spack/spack/cmd/__init__.py b/lib/spack/spack/cmd/__init__.py
index b4de2a88c3..4c80025e05 100644
--- a/lib/spack/spack/cmd/__init__.py
+++ b/lib/spack/spack/cmd/__init__.py
@@ -21,6 +21,7 @@ import spack.extensions
import spack.paths
import spack.spec
import spack.store
+import spack.util.spack_json as sjson
from spack.error import SpackError
@@ -214,6 +215,24 @@ def display_formatted_specs(specs, format_string, deps=False):
print(" " * depth, dep.format(format_string))
+def display_specs_as_json(specs, deps=False):
+ """Convert specs to a list of json records."""
+ seen = set()
+ records = []
+ for spec in specs:
+ if spec.dag_hash() not in seen:
+ seen.add(spec.dag_hash())
+ records.append(spec.to_record_dict())
+
+ if deps:
+ for dep in spec.traverse():
+ if dep.dag_hash() not in seen:
+ seen.add(spec.dag_hash())
+ records.append(dep.to_record_dict())
+
+ sjson.dump(records, sys.stdout)
+
+
def display_specs(specs, args=None, **kwargs):
"""Display human readable specs with customizable formatting.
diff --git a/lib/spack/spack/cmd/find.py b/lib/spack/spack/cmd/find.py
index ef300a83cd..afe8cf9b7c 100644
--- a/lib/spack/spack/cmd/find.py
+++ b/lib/spack/spack/cmd/find.py
@@ -2,6 +2,7 @@
# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
from __future__ import print_function
import llnl.util.tty as tty
@@ -12,7 +13,6 @@ import spack.environment as ev
import spack.repo
import spack.cmd as cmd
import spack.cmd.common.arguments as arguments
-from spack.cmd import display_specs
from spack.util.string import plural
description = "list and search installed packages"
@@ -36,6 +36,9 @@ def setup_parser(subparser):
format_group.add_argument(
"--format", action="store", default=None,
help="output specs with the specified format string")
+ format_group.add_argument(
+ "--json", action="store_true", default=False,
+ help="output specs as machine-readable json records")
# TODO: separate this entirely from the "mode" option -- it's
# TODO: orthogonal, but changing it for all commands that use it with
@@ -159,14 +162,14 @@ def display_env(env, args, decorator):
else:
tty.msg('Root specs')
# TODO: Change this to not print extraneous deps and variants
- display_specs(
+ cmd.display_specs(
env.user_specs, args,
decorator=lambda s, f: color.colorize('@*{%s}' % f))
print()
if args.show_concretized:
tty.msg('Concretized roots')
- display_specs(
+ cmd.display_specs(
env.specs_by_hash.values(), args, decorator=decorator)
print()
@@ -205,4 +208,4 @@ def find(parser, args):
if env:
display_env(env, args, decorator)
tty.msg("%s" % plural(len(results), 'installed package'))
- display_specs(results, args, decorator=decorator, all_headers=True)
+ cmd.display_specs(results, args, decorator=decorator, all_headers=True)
diff --git a/lib/spack/spack/environment.py b/lib/spack/spack/environment.py
index 1a279e4ea9..56b6fde6f3 100644
--- a/lib/spack/spack/environment.py
+++ b/lib/spack/spack/environment.py
@@ -952,6 +952,7 @@ class Environment(object):
('PKG_CONFIG_PATH', ['lib/pkgconfig', 'lib64/pkgconfig']),
('CMAKE_PREFIX_PATH', ['']),
]
+
path_updates = list()
if default_view_name in self.views:
for var, subdirs in updates:
diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py
index d6cdc59924..3586cb2aae 100644
--- a/lib/spack/spack/spec.py
+++ b/lib/spack/spack/spec.py
@@ -1540,6 +1540,31 @@ class Spec(object):
return syaml_dict([('spec', node_list)])
+ def to_record_dict(self):
+ """Return a "flat" dictionary with name and hash as top-level keys.
+
+ This is similar to ``to_node_dict()``, but the name and the hash
+ are "flattened" into the dictionary for easiler parsing by tools
+ like ``jq``. Instead of being keyed by name or hash, the
+ dictionary "name" and "hash" fields, e.g.::
+
+ {
+ "name": "openssl"
+ "hash": "3ws7bsihwbn44ghf6ep4s6h4y2o6eznv"
+ "version": "3.28.0",
+ "arch": {
+ ...
+ }
+
+ But is otherwise the same as ``to_node_dict()``.
+
+ """
+ dictionary = syaml_dict()
+ dictionary["name"] = self.name
+ dictionary["hash"] = self.dag_hash()
+ dictionary.update(self.to_node_dict()[self.name])
+ return dictionary
+
def to_yaml(self, stream=None, hash=ht.dag_hash):
return syaml.dump(
self.to_dict(hash), stream=stream, default_flow_style=False)