Source code for spack.cmd.info

# Copyright 2013-2023 Lawrence Livermore National Security, LLC and other
# 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 textwrap
from itertools import zip_longest

import llnl.util.tty as tty
import llnl.util.tty.color as color
from llnl.util.tty.colify import colify

import spack.cmd.common.arguments as arguments
import spack.fetch_strategy as fs
import spack.install_test
import spack.repo
import spack.spec
from spack.package_base import preferred_version

description = "get detailed information on a particular package"
section = "basic"
level = "short"

header_color = "@*b"
plain_format = "@."


[docs]def padder(str_list, extra=0): """Return a function to pad elements of a list.""" length = max(len(str(s)) for s in str_list) + extra def pad(string): string = str(string) padding = max(0, length - len(string)) return string + (padding * " ") return pad
[docs]def setup_parser(subparser): subparser.add_argument( "-a", "--all", action="store_true", default=False, help="output all package information" ) options = [ ("--detectable", print_detectable.__doc__), ("--maintainers", print_maintainers.__doc__), ("--no-dependencies", "do not " + print_dependencies.__doc__), ("--no-variants", "do not " + print_variants.__doc__), ("--no-versions", "do not " + print_versions.__doc__), ("--phases", print_phases.__doc__), ("--tags", print_tags.__doc__), ("--tests", print_tests.__doc__), ("--virtuals", print_virtuals.__doc__), ] for opt, help_comment in options: subparser.add_argument(opt, action="store_true", help=help_comment) arguments.add_common_arguments(subparser, ["package"])
[docs]def section_title(s): return header_color + s + plain_format
[docs]def version(s): return spack.spec.version_color + s + plain_format
[docs]def variant(s): return spack.spec.enabled_variant_color + s + plain_format
[docs]class VariantFormatter(object): def __init__(self, variants): self.variants = variants self.headers = ("Name [Default]", "When", "Allowed values", "Description") # Formats fmt_name = "{0} [{1}]" # Initialize column widths with the length of the # corresponding headers, as they cannot be shorter # than that self.column_widths = [len(x) for x in self.headers] # Expand columns based on max line lengths for k, e in variants.items(): v, w = e candidate_max_widths = ( len(fmt_name.format(k, self.default(v))), # Name [Default] len(str(w)), len(v.allowed_values), # Allowed values len(v.description), # Description ) self.column_widths = ( max(self.column_widths[0], candidate_max_widths[0]), max(self.column_widths[1], candidate_max_widths[1]), max(self.column_widths[2], candidate_max_widths[2]), max(self.column_widths[3], candidate_max_widths[3]), ) # Don't let name or possible values be less than max widths _, cols = tty.terminal_size() max_name = min(self.column_widths[0], 30) max_when = min(self.column_widths[1], 30) max_vals = min(self.column_widths[2], 20) # allow the description column to extend as wide as the terminal. max_description = min( self.column_widths[3], # min width 70 cols, 14 cols of margins and column spacing max(cols, 70) - max_name - max_vals - 14, ) self.column_widths = (max_name, max_when, max_vals, max_description) # Compute the format self.fmt = "%%-%ss%%-%ss%%-%ss%%s" % ( self.column_widths[0] + 4, self.column_widths[1] + 4, self.column_widths[2] + 4, )
[docs] def default(self, v): s = "on" if v.default is True else "off" if not isinstance(v.default, bool): s = v.default return s
@property def lines(self): if not self.variants: yield " None" else: yield " " + self.fmt % self.headers underline = tuple([w * "=" for w in self.column_widths]) yield " " + self.fmt % underline yield "" for k, e in sorted(self.variants.items()): v, w = e name = textwrap.wrap( "{0} [{1}]".format(k, self.default(v)), width=self.column_widths[0] ) if all(spec == spack.spec.Spec() for spec in w): w = "--" when = textwrap.wrap(str(w), width=self.column_widths[1]) allowed = v.allowed_values.replace("True, False", "on, off") allowed = textwrap.wrap(allowed, width=self.column_widths[2]) description = [] for d_line in v.description.split("\n"): description += textwrap.wrap(d_line, width=self.column_widths[3]) for t in zip_longest(name, when, allowed, description, fillvalue=""): yield " " + self.fmt % t
[docs]def info(parser, args): spec = spack.spec.Spec(args.package) pkg_cls = spack.repo.path.get_pkg_class(spec.name) pkg = pkg_cls(spec) # Output core package information header = section_title("{0}: ").format(pkg.build_system_class) + pkg.name color.cprint(header) color.cprint("") color.cprint(section_title("Description:")) if pkg.__doc__: color.cprint(color.cescape(pkg.format_doc(indent=4))) else: color.cprint(" None") color.cprint(section_title("Homepage: ") + pkg.homepage) # Now output optional information in expected order sections = [ (args.all or args.maintainers, print_maintainers), (args.all or args.detectable, print_detectable), (args.all or args.tags, print_tags), (args.all or not args.no_versions, print_versions), (args.all or not args.no_variants, print_variants), (args.all or args.phases, print_phases), (args.all or not args.no_dependencies, print_dependencies), (args.all or args.virtuals, print_virtuals), (args.all or args.tests, print_tests), ] for print_it, func in sections: if print_it: func(pkg) color.cprint("")