Source code for spack.cmd.tags
# Copyright Spack Project Developers. See COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import argparse
import io
import sys
from typing import Dict, Iterable, List
import spack.environment
import spack.repo
import spack.util.string
from spack.util import tty
from spack.util.tty import colify
description = "show package tags and associated packages"
section = "query"
level = "long"
[docs]
def report_tags(category, tags):
buffer = io.StringIO()
isatty = sys.stdout.isatty()
if isatty:
num = len(tags)
fmt = "{0} package tag".format(category)
buffer.write("{0}:\n".format(spack.util.string.plural(num, fmt)))
if tags:
colify.colify(tags, output=buffer, tty=isatty, indent=4)
else:
buffer.write(" None\n")
print(buffer.getvalue())
[docs]
def setup_parser(subparser: argparse.ArgumentParser) -> None:
subparser.epilog = (
"Tags from known packages will be used if no tags are provided on "
"the command\nline. If tags are provided, packages with at least one "
"will be reported.\n\nYou are not allowed to provide tags and use "
"'--all' at the same time."
)
subparser.add_argument(
"-i",
"--installed",
action="store_true",
default=False,
help="show information for installed packages only",
)
subparser.add_argument(
"-a",
"--all",
action="store_true",
default=False,
help="show packages for all available tags",
)
subparser.add_argument("tag", nargs="*", help="show packages with the specified tag")
[docs]
def tags(parser, args):
# Disallow combining all option with (positional) tags to avoid confusion
if args.all and args.tag:
args.subparser.error("use the '--all' option OR provide tag(s) on the command line")
# Provide a nice, simple message if database is empty
if args.installed and not spack.environment.installed_specs():
tty.msg("No installed packages")
return
# unique list of available tags
available_tags = sorted(spack.repo.PATH.tag_index.tags)
if not available_tags:
tty.msg("No tagged packages")
return
show_packages = args.tag or args.all
# Only report relevant, available tags if no packages are to be shown
if not show_packages:
if not args.installed:
report_tags("available", available_tags)
else:
tag_pkgs = packages_with_tags(available_tags, True, True)
tags = tag_pkgs.keys() if tag_pkgs else []
report_tags("installed", tags)
return
# Report packages associated with tags
buffer = io.StringIO()
isatty = sys.stdout.isatty()
tags = args.tag if args.tag else available_tags
tag_pkgs = packages_with_tags(tags, args.installed, False)
missing = "No installed packages" if args.installed else "None"
for tag in sorted(tag_pkgs):
# TODO: Remove the sorting once we're sure no one has an old
# TODO: tag cache since it can accumulate duplicates.
packages = sorted(list(set(tag_pkgs[tag])))
if isatty:
buffer.write("{0}:\n".format(tag))
if packages:
colify.colify(packages, output=buffer, tty=isatty, indent=4)
else:
buffer.write(" {0}\n".format(missing))
buffer.write("\n")
print(buffer.getvalue())
[docs]
def packages_with_tags(
tags: Iterable[str], installed: bool, skip_empty: bool
) -> Dict[str, List[str]]:
"""
Returns a dict, indexed by tag, containing lists of names of packages
containing the tag or, if no tags, for all available tags.
Arguments:
tags: list of tags of interest or None for all
installed: True if want names of packages that are installed;
otherwise, False if want all packages with the tag
skip_empty: True if exclude tags with no associated packages;
otherwise, False if want entries for all tags even when no such
tagged packages
"""
tag_pkgs: Dict[str, List[str]] = {}
name_filter = {x.name for x in spack.environment.installed_specs()} if installed else None
for tag in tags:
packages = spack.repo.PATH.tag_index.get_packages(tag)
if name_filter is not None:
packages = [p for p in packages if p in name_filter]
if packages or not skip_empty:
tag_pkgs[tag] = packages
return tag_pkgs