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" } ]
This commit is contained in:
parent
64af0a9874
commit
1a1f5674df
4 changed files with 52 additions and 4 deletions
|
@ -21,6 +21,7 @@
|
||||||
import spack.paths
|
import spack.paths
|
||||||
import spack.spec
|
import spack.spec
|
||||||
import spack.store
|
import spack.store
|
||||||
|
import spack.util.spack_json as sjson
|
||||||
from spack.error import SpackError
|
from spack.error import SpackError
|
||||||
|
|
||||||
|
|
||||||
|
@ -214,6 +215,24 @@ def display_formatted_specs(specs, format_string, deps=False):
|
||||||
print(" " * depth, dep.format(format_string))
|
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):
|
def display_specs(specs, args=None, **kwargs):
|
||||||
"""Display human readable specs with customizable formatting.
|
"""Display human readable specs with customizable formatting.
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||||
|
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
import llnl.util.tty as tty
|
import llnl.util.tty as tty
|
||||||
|
@ -12,7 +13,6 @@
|
||||||
import spack.repo
|
import spack.repo
|
||||||
import spack.cmd as cmd
|
import spack.cmd as cmd
|
||||||
import spack.cmd.common.arguments as arguments
|
import spack.cmd.common.arguments as arguments
|
||||||
from spack.cmd import display_specs
|
|
||||||
from spack.util.string import plural
|
from spack.util.string import plural
|
||||||
|
|
||||||
description = "list and search installed packages"
|
description = "list and search installed packages"
|
||||||
|
@ -36,6 +36,9 @@ def setup_parser(subparser):
|
||||||
format_group.add_argument(
|
format_group.add_argument(
|
||||||
"--format", action="store", default=None,
|
"--format", action="store", default=None,
|
||||||
help="output specs with the specified format string")
|
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: separate this entirely from the "mode" option -- it's
|
||||||
# TODO: orthogonal, but changing it for all commands that use it with
|
# TODO: orthogonal, but changing it for all commands that use it with
|
||||||
|
@ -159,14 +162,14 @@ def display_env(env, args, decorator):
|
||||||
else:
|
else:
|
||||||
tty.msg('Root specs')
|
tty.msg('Root specs')
|
||||||
# TODO: Change this to not print extraneous deps and variants
|
# TODO: Change this to not print extraneous deps and variants
|
||||||
display_specs(
|
cmd.display_specs(
|
||||||
env.user_specs, args,
|
env.user_specs, args,
|
||||||
decorator=lambda s, f: color.colorize('@*{%s}' % f))
|
decorator=lambda s, f: color.colorize('@*{%s}' % f))
|
||||||
print()
|
print()
|
||||||
|
|
||||||
if args.show_concretized:
|
if args.show_concretized:
|
||||||
tty.msg('Concretized roots')
|
tty.msg('Concretized roots')
|
||||||
display_specs(
|
cmd.display_specs(
|
||||||
env.specs_by_hash.values(), args, decorator=decorator)
|
env.specs_by_hash.values(), args, decorator=decorator)
|
||||||
print()
|
print()
|
||||||
|
|
||||||
|
@ -205,4 +208,4 @@ def find(parser, args):
|
||||||
if env:
|
if env:
|
||||||
display_env(env, args, decorator)
|
display_env(env, args, decorator)
|
||||||
tty.msg("%s" % plural(len(results), 'installed package'))
|
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)
|
||||||
|
|
|
@ -952,6 +952,7 @@ def _shell_vars(self):
|
||||||
('PKG_CONFIG_PATH', ['lib/pkgconfig', 'lib64/pkgconfig']),
|
('PKG_CONFIG_PATH', ['lib/pkgconfig', 'lib64/pkgconfig']),
|
||||||
('CMAKE_PREFIX_PATH', ['']),
|
('CMAKE_PREFIX_PATH', ['']),
|
||||||
]
|
]
|
||||||
|
|
||||||
path_updates = list()
|
path_updates = list()
|
||||||
if default_view_name in self.views:
|
if default_view_name in self.views:
|
||||||
for var, subdirs in updates:
|
for var, subdirs in updates:
|
||||||
|
|
|
@ -1540,6 +1540,31 @@ def to_dict(self, hash=ht.dag_hash):
|
||||||
|
|
||||||
return syaml_dict([('spec', node_list)])
|
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):
|
def to_yaml(self, stream=None, hash=ht.dag_hash):
|
||||||
return syaml.dump(
|
return syaml.dump(
|
||||||
self.to_dict(hash), stream=stream, default_flow_style=False)
|
self.to_dict(hash), stream=stream, default_flow_style=False)
|
||||||
|
|
Loading…
Reference in a new issue