spack spec: simplify and unify output (#47574)

`spack spec` output has looked like this for a while:

```console
> spack spec /v5fn6xo /wd2p2v7
Input spec
--------------------------------
 -   /v5fn6xo

Concretized
--------------------------------
[+]  openssl@3.3.1%apple-clang@16.0.0~docs+shared build_system=generic certs=mozilla arch=darwin-sequoia-m1
[+]      ^ca-certificates-mozilla@2023-05-30%apple-clang@16.0.0 build_system=generic arch=darwin-sequoia-m1
...

Input spec
--------------------------------
 -   /wd2p2v7

Concretized
--------------------------------
[+]  py-six@1.16.0%apple-clang@16.0.0 build_system=python_pip arch=darwin-sequoia-m1
[+]      ^py-pip@23.1.2%apple-clang@16.0.0 build_system=generic arch=darwin-sequoia-m1
```

But the input spec is right there on the CLI, and it doesn't add anything to the output.
Also, since #44843, specs concretized in the CLI line can be unified, so it makes sense
to display them as we did in #44489 -- as one multi-root tree instead of as multiple
single-root trees.

With this PR, concretize output now looks like this:

```console
> spack spec /v5fn6xo /wd2p2v7
[+]  openssl@3.3.1%apple-clang@16.0.0~docs+shared build_system=generic certs=mozilla arch=darwin-sequoia-m1
[+]      ^ca-certificates-mozilla@2023-05-30%apple-clang@16.0.0 build_system=generic arch=darwin-sequoia-m1
[+]      ^gmake@4.4.1%apple-clang@16.0.0~guile build_system=generic arch=darwin-sequoia-m1
[+]      ^perl@5.40.0%apple-clang@16.0.0+cpanm+opcode+open+shared+threads build_system=generic arch=darwin-sequoia-m1
[+]          ^berkeley-db@18.1.40%apple-clang@16.0.0+cxx~docs+stl build_system=autotools patches=26090f4,b231fcc arch=darwin-sequoia-m1
[+]          ^bzip2@1.0.8%apple-clang@16.0.0~debug~pic+shared build_system=generic arch=darwin-sequoia-m1
[+]              ^diffutils@3.10%apple-clang@16.0.0 build_system=autotools arch=darwin-sequoia-m1
[+]                  ^libiconv@1.17%apple-clang@16.0.0 build_system=autotools libs=shared,static arch=darwin-sequoia-m1
[+]          ^gdbm@1.23%apple-clang@16.0.0 build_system=autotools arch=darwin-sequoia-m1
[+]              ^readline@8.2%apple-clang@16.0.0 build_system=autotools patches=bbf97f1 arch=darwin-sequoia-m1
[+]                  ^ncurses@6.5%apple-clang@16.0.0~symlinks+termlib abi=none build_system=autotools patches=7a351bc arch=darwin-sequoia-m1
[+]                      ^pkgconf@2.2.0%apple-clang@16.0.0 build_system=autotools arch=darwin-sequoia-m1
[+]      ^zlib-ng@2.2.1%apple-clang@16.0.0+compat+new_strategies+opt+pic+shared build_system=autotools arch=darwin-sequoia-m1
[+]          ^gnuconfig@2022-09-17%apple-clang@16.0.0 build_system=generic arch=darwin-sequoia-m1
[+]  py-six@1.16.0%apple-clang@16.0.0 build_system=python_pip arch=darwin-sequoia-m1
[+]      ^py-pip@23.1.2%apple-clang@16.0.0 build_system=generic arch=darwin-sequoia-m1
[+]      ^py-setuptools@69.2.0%apple-clang@16.0.0 build_system=generic arch=darwin-sequoia-m1
[-]      ^py-wheel@0.41.2%apple-clang@16.0.0 build_system=generic arch=darwin-sequoia-m1
...
```

With no input spec displayed -- just the concretization output shown as one consolidated
tree and multiple roots.

- [x] remove "Input Spec" section and "Concretized" header from `spack spec` output
- [x] print concretized specs as one BFS tree instead of multiple

---------

Signed-off-by: Todd Gamblin <tgamblin@llnl.gov>
Co-authored-by: Harmen Stoppels <harmenstoppels@gmail.com>
This commit is contained in:
Todd Gamblin 2024-11-13 07:21:16 -08:00 committed by Harmen Stoppels
parent 020e30f3e6
commit e5c411d8f0

View File

@ -82,14 +82,6 @@ def spec(parser, args):
if args.namespaces: if args.namespaces:
fmt = "{namespace}." + fmt fmt = "{namespace}." + fmt
tree_kwargs = {
"cover": args.cover,
"format": fmt,
"hashlen": None if args.very_long else 7,
"show_types": args.types,
"status_fn": install_status_fn if args.install_status else None,
}
# use a read transaction if we are getting install status for every # use a read transaction if we are getting install status for every
# spec in the DAG. This avoids repeatedly querying the DB. # spec in the DAG. This avoids repeatedly querying the DB.
tree_context = lang.nullcontext tree_context = lang.nullcontext
@ -99,46 +91,35 @@ def spec(parser, args):
env = ev.active_environment() env = ev.active_environment()
if args.specs: if args.specs:
input_specs = spack.cmd.parse_specs(args.specs) concrete_specs = spack.cmd.parse_specs(args.specs, concretize=True)
concretized_specs = spack.cmd.parse_specs(args.specs, concretize=True)
specs = list(zip(input_specs, concretized_specs))
elif env: elif env:
env.concretize() env.concretize()
specs = env.concretized_specs() concrete_specs = env.concrete_roots()
if not args.format:
# environments are printed together in a combined tree() invocation,
# except when using --yaml or --json, which we print spec by spec below.
tree_kwargs["key"] = spack.traverse.by_dag_hash
tree_kwargs["hashes"] = args.long or args.very_long
print(spack.spec.tree([concrete for _, concrete in specs], **tree_kwargs))
return
else: else:
tty.die("spack spec requires at least one spec or an active environment") tty.die("spack spec requires at least one spec or an active environment")
for input, output in specs: # With --yaml, --json, or --format, just print the raw specs to output
# With --yaml or --json, just print the raw specs to output
if args.format: if args.format:
for spec in concrete_specs:
if args.format == "yaml": if args.format == "yaml":
# use write because to_yaml already has a newline. # use write because to_yaml already has a newline.
sys.stdout.write(output.to_yaml(hash=ht.dag_hash)) sys.stdout.write(spec.to_yaml(hash=ht.dag_hash))
elif args.format == "json": elif args.format == "json":
print(output.to_json(hash=ht.dag_hash)) print(spec.to_json(hash=ht.dag_hash))
else: else:
print(output.format(args.format)) print(spec.format(args.format))
continue return
with tree_context(): with tree_context():
# Only show the headers for input specs that are not concrete to avoid print(
# repeated output. This happens because parse_specs outputs concrete spack.spec.tree(
# specs for `/hash` inputs. concrete_specs,
if not input.concrete: cover=args.cover,
tree_kwargs["hashes"] = False # Always False for input spec format=fmt,
print("Input spec") hashlen=None if args.very_long else 7,
print("--------------------------------") show_types=args.types,
print(input.tree(**tree_kwargs)) status_fn=install_status_fn if args.install_status else None,
print("Concretized") hashes=args.long or args.very_long,
print("--------------------------------") key=spack.traverse.by_dag_hash,
)
tree_kwargs["hashes"] = args.long or args.very_long )
print(output.tree(**tree_kwargs))