Add --color=[always|never|auto] argument; fix color when piping (#3013)
* Disable spec colorization when redirecting stdout and add command line flag to re-enable * Add command line `--color` flag to control output colorization * Add options to `llnl.util.tty.color` to allow color to be auto/always/never * Add `Spec.cformat()` function to be used when `format()` should have auto-coloring
This commit is contained in:
		 paulhopkins
					paulhopkins
				
			
				
					committed by
					
						 Todd Gamblin
						Todd Gamblin
					
				
			
			
				
	
			
			
			 Todd Gamblin
						Todd Gamblin
					
				
			
						parent
						
							f3c70c235c
						
					
				
				
					commit
					1c7e5724d9
				
			| @@ -80,6 +80,7 @@ | |||||||
| """ | """ | ||||||
| import re | import re | ||||||
| import sys | import sys | ||||||
|  | from contextlib import contextmanager | ||||||
|  |  | ||||||
|  |  | ||||||
| class ColorParseError(Exception): | class ColorParseError(Exception): | ||||||
| @@ -107,15 +108,62 @@ def __init__(self, message): | |||||||
| # Regex to be used for color formatting | # Regex to be used for color formatting | ||||||
| color_re = r'@(?:@|\.|([*_])?([a-zA-Z])?(?:{((?:[^}]|}})*)})?)' | color_re = r'@(?:@|\.|([*_])?([a-zA-Z])?(?:{((?:[^}]|}})*)})?)' | ||||||
|  |  | ||||||
|  | # Mapping from color arguments to values for tty.set_color | ||||||
|  | color_when_values = { | ||||||
|  |     'always': True, | ||||||
|  |     'auto': None, | ||||||
|  |     'never': False | ||||||
|  | } | ||||||
|  |  | ||||||
| # Force color even if stdout is not a tty. | # Force color; None: Only color if stdout is a tty | ||||||
| _force_color = False | # True: Always colorize output, False: Never colorize output | ||||||
|  | _force_color = None | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def _color_when_value(when): | ||||||
|  |     """Raise a ValueError for an invalid color setting. | ||||||
|  |  | ||||||
|  |     Valid values are 'always', 'never', and 'auto', or equivalently, | ||||||
|  |     True, False, and None. | ||||||
|  |     """ | ||||||
|  |     if when in color_when_values: | ||||||
|  |         return color_when_values[when] | ||||||
|  |     elif when not in color_when_values.values(): | ||||||
|  |         raise ValueError('Invalid color setting: %s' % when) | ||||||
|  |     return when | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def get_color_when(): | ||||||
|  |     """Return whether commands should print color or not.""" | ||||||
|  |     if _force_color is not None: | ||||||
|  |         return _force_color | ||||||
|  |     return sys.stdout.isatty() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def set_color_when(when): | ||||||
|  |     """Set when color should be applied.  Options are: | ||||||
|  |  | ||||||
|  |     * True or 'always': always print color | ||||||
|  |     * False or 'never': never print color | ||||||
|  |     * None or 'auto': only print color if sys.stdout is a tty. | ||||||
|  |     """ | ||||||
|  |     global _force_color | ||||||
|  |     _force_color = _color_when_value(when) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @contextmanager | ||||||
|  | def color_when(value): | ||||||
|  |     """Context manager to temporarily use a particular color setting.""" | ||||||
|  |     old_value = value | ||||||
|  |     set_color(value) | ||||||
|  |     yield | ||||||
|  |     set_color(old_value) | ||||||
|  |  | ||||||
|  |  | ||||||
| class match_to_ansi(object): | class match_to_ansi(object): | ||||||
|  |  | ||||||
|     def __init__(self, color=True): |     def __init__(self, color=True): | ||||||
|         self.color = color |         self.color = _color_when_value(color) | ||||||
|  |  | ||||||
|     def escape(self, s): |     def escape(self, s): | ||||||
|         """Returns a TTY escape sequence for a color""" |         """Returns a TTY escape sequence for a color""" | ||||||
| @@ -166,7 +214,7 @@ def colorize(string, **kwargs): | |||||||
|         color (bool): If False, output will be plain text without control |         color (bool): If False, output will be plain text without control | ||||||
|             codes, for output to non-console devices. |             codes, for output to non-console devices. | ||||||
|     """ |     """ | ||||||
|     color = kwargs.get('color', True) |     color = _color_when_value(kwargs.get('color', get_color_when())) | ||||||
|     return re.sub(color_re, match_to_ansi(color), string) |     return re.sub(color_re, match_to_ansi(color), string) | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -188,7 +236,7 @@ def cwrite(string, stream=sys.stdout, color=None): | |||||||
|        then it will be set based on stream.isatty(). |        then it will be set based on stream.isatty(). | ||||||
|     """ |     """ | ||||||
|     if color is None: |     if color is None: | ||||||
|         color = stream.isatty() or _force_color |         color = get_color_when() | ||||||
|     stream.write(colorize(string, color=color)) |     stream.write(colorize(string, color=color)) | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -217,7 +265,7 @@ def write(self, string, **kwargs): | |||||||
|             if raw: |             if raw: | ||||||
|                 color = True |                 color = True | ||||||
|             else: |             else: | ||||||
|                 color = self._stream.isatty() or _force_color |                 color = get_color_when() | ||||||
|         raw_write(colorize(string, color=color)) |         raw_write(colorize(string, color=color)) | ||||||
|  |  | ||||||
|     def writelines(self, sequence, **kwargs): |     def writelines(self, sequence, **kwargs): | ||||||
|   | |||||||
| @@ -154,9 +154,8 @@ def disambiguate_spec(spec): | |||||||
|     elif len(matching_specs) > 1: |     elif len(matching_specs) > 1: | ||||||
|         args = ["%s matches multiple packages." % spec, |         args = ["%s matches multiple packages." % spec, | ||||||
|                 "Matching packages:"] |                 "Matching packages:"] | ||||||
|         color = sys.stdout.isatty() |         args += [colorize("  @K{%s} " % s.dag_hash(7)) + | ||||||
|         args += [colorize("  @K{%s} " % s.dag_hash(7), color=color) + |                  s.cformat('$_$@$%@$=') for s in matching_specs] | ||||||
|                  s.format('$_$@$%@$=', color=color) for s in matching_specs] |  | ||||||
|         args += ["Use a more specific spec."] |         args += ["Use a more specific spec."] | ||||||
|         tty.die(*args) |         tty.die(*args) | ||||||
|  |  | ||||||
| @@ -200,7 +199,7 @@ def display_specs(specs, **kwargs): | |||||||
|         specs = index[(architecture, compiler)] |         specs = index[(architecture, compiler)] | ||||||
|         specs.sort() |         specs.sort() | ||||||
|  |  | ||||||
|         abbreviated = [s.format(format_string, color=True) for s in specs] |         abbreviated = [s.cformat(format_string) for s in specs] | ||||||
|         if mode == 'paths': |         if mode == 'paths': | ||||||
|             # Print one spec per line along with prefix path |             # Print one spec per line along with prefix path | ||||||
|             width = max(len(s) for s in abbreviated) |             width = max(len(s) for s in abbreviated) | ||||||
| @@ -215,7 +214,6 @@ def display_specs(specs, **kwargs): | |||||||
|             for spec in specs: |             for spec in specs: | ||||||
|                 print(spec.tree( |                 print(spec.tree( | ||||||
|                     format=format_string, |                     format=format_string, | ||||||
|                     color=True, |  | ||||||
|                     indent=4, |                     indent=4, | ||||||
|                     prefix=(lambda s: gray_hash(s, hlen)) if hashes else None)) |                     prefix=(lambda s: gray_hash(s, hlen)) if hashes else None)) | ||||||
|  |  | ||||||
| @@ -227,7 +225,7 @@ def fmt(s): | |||||||
|                     string = "" |                     string = "" | ||||||
|                     if hashes: |                     if hashes: | ||||||
|                         string += gray_hash(s, hlen) + ' ' |                         string += gray_hash(s, hlen) + ' ' | ||||||
|                     string += s.format('$-%s$@%s' % (nfmt, vfmt), color=True) |                     string += s.cformat('$-%s$@%s' % (nfmt, vfmt)) | ||||||
|  |  | ||||||
|                     return string |                     return string | ||||||
|  |  | ||||||
| @@ -237,7 +235,7 @@ def fmt(s): | |||||||
|                 for spec in specs: |                 for spec in specs: | ||||||
|                     # Print the hash if necessary |                     # Print the hash if necessary | ||||||
|                     hsh = gray_hash(spec, hlen) + ' ' if hashes else '' |                     hsh = gray_hash(spec, hlen) + ' ' if hashes else '' | ||||||
|                     print(hsh + spec.format(format_string, color=True) + '\n') |                     print(hsh + spec.cformat(format_string) + '\n') | ||||||
|  |  | ||||||
|         else: |         else: | ||||||
|             raise ValueError( |             raise ValueError( | ||||||
|   | |||||||
| @@ -47,7 +47,7 @@ def dependents(parser, args): | |||||||
|         tty.die("spack dependents takes only one spec.") |         tty.die("spack dependents takes only one spec.") | ||||||
|     spec = spack.cmd.disambiguate_spec(specs[0]) |     spec = spack.cmd.disambiguate_spec(specs[0]) | ||||||
|  |  | ||||||
|     tty.msg("Dependents of %s" % spec.format('$_$@$%@$/', color=True)) |     tty.msg("Dependents of %s" % spec.cformat('$_$@$%@$/')) | ||||||
|     deps = spack.store.db.installed_dependents(spec) |     deps = spack.store.db.installed_dependents(spec) | ||||||
|     if deps: |     if deps: | ||||||
|         spack.cmd.display_specs(deps) |         spack.cmd.display_specs(deps) | ||||||
|   | |||||||
| @@ -213,7 +213,7 @@ def mirror_create(args): | |||||||
|         "  %-4d failed to fetch." % e) |         "  %-4d failed to fetch." % e) | ||||||
|     if error: |     if error: | ||||||
|         tty.error("Failed downloads:") |         tty.error("Failed downloads:") | ||||||
|         colify(s.format("$_$@") for s in error) |         colify(s.cformat("$_$@") for s in error) | ||||||
|  |  | ||||||
|  |  | ||||||
| def mirror(parser, args): | def mirror(parser, args): | ||||||
|   | |||||||
| @@ -236,7 +236,8 @@ def refresh(mtype, specs, args): | |||||||
|             if len(writer_list) > 1: |             if len(writer_list) > 1: | ||||||
|                 message += '\nfile: {0}\n'.format(filename) |                 message += '\nfile: {0}\n'.format(filename) | ||||||
|                 for x in writer_list: |                 for x in writer_list: | ||||||
|                     message += 'spec: {0}\n'.format(x.spec.format(color=True)) |                     message += 'spec: {0}\n'.format(x.spec.format()) | ||||||
|  |  | ||||||
|         tty.error(message) |         tty.error(message) | ||||||
|         tty.error('Operation aborted') |         tty.error('Operation aborted') | ||||||
|         raise SystemExit(1) |         raise SystemExit(1) | ||||||
| @@ -269,7 +270,7 @@ def module(parser, args): | |||||||
|                    "and this is not allowed in this context") |                    "and this is not allowed in this context") | ||||||
|         tty.error(message.format(query=constraint)) |         tty.error(message.format(query=constraint)) | ||||||
|         for s in specs: |         for s in specs: | ||||||
|             sys.stderr.write(s.format(color=True) + '\n') |             sys.stderr.write(s.cformat() + '\n') | ||||||
|         raise SystemExit(1) |         raise SystemExit(1) | ||||||
|     except NoMatch: |     except NoMatch: | ||||||
|         message = ("the constraint '{query}' matches no package, " |         message = ("the constraint '{query}' matches no package, " | ||||||
|   | |||||||
| @@ -60,8 +60,7 @@ def setup_parser(subparser): | |||||||
|  |  | ||||||
| def spec(parser, args): | def spec(parser, args): | ||||||
|     name_fmt = '$.' if args.namespaces else '$_' |     name_fmt = '$.' if args.namespaces else '$_' | ||||||
|     kwargs = {'color': True, |     kwargs = {'cover': args.cover, | ||||||
|               'cover': args.cover, |  | ||||||
|               'format': name_fmt + '$@$%@+$+$=', |               'format': name_fmt + '$@$%@+$+$=', | ||||||
|               'hashes': args.long or args.very_long, |               'hashes': args.long or args.very_long, | ||||||
|               'hashlen': None if args.very_long else 7, |               'hashlen': None if args.very_long else 7, | ||||||
|   | |||||||
| @@ -180,8 +180,7 @@ def get_uninstall_list(args): | |||||||
|     has_error = False |     has_error = False | ||||||
|     if dependent_list and not args.dependents and not args.force: |     if dependent_list and not args.dependents and not args.force: | ||||||
|         for spec, lst in dependent_list.items(): |         for spec, lst in dependent_list.items(): | ||||||
|             tty.error('Will not uninstall {0}'.format( |             tty.error("Will not uninstall %s" % spec.cformat("$_$@$%@$/")) | ||||||
|                       spec.format("$_$@$%@$/", color=True))) |  | ||||||
|             print('') |             print('') | ||||||
|             print('The following packages depend on it:') |             print('The following packages depend on it:') | ||||||
|             spack.cmd.display_specs(lst, **display_args) |             spack.cmd.display_specs(lst, **display_args) | ||||||
|   | |||||||
| @@ -288,7 +288,7 @@ def _assign_dependencies(self, hash_key, installs, data): | |||||||
|                 if dhash not in data: |                 if dhash not in data: | ||||||
|                     tty.warn("Missing dependency not in database: ", |                     tty.warn("Missing dependency not in database: ", | ||||||
|                              "%s needs %s-%s" % ( |                              "%s needs %s-%s" % ( | ||||||
|                                  spec.format('$_$/'), dname, dhash[:7])) |                                  spec.cformat('$_$/'), dname, dhash[:7])) | ||||||
|                     continue |                     continue | ||||||
|  |  | ||||||
|                 child = data[dhash].spec |                 child = data[dhash].spec | ||||||
| @@ -440,8 +440,7 @@ def _read_suppress_error(): | |||||||
|                     # just to be conservative in case a command like |                     # just to be conservative in case a command like | ||||||
|                     # "autoremove" is run by the user after a reindex. |                     # "autoremove" is run by the user after a reindex. | ||||||
|                     tty.debug( |                     tty.debug( | ||||||
|                         'RECONSTRUCTING FROM SPEC.YAML: {0}'.format(spec) |                         'RECONSTRUCTING FROM SPEC.YAML: {0}'.format(spec)) | ||||||
|                     ) |  | ||||||
|                     explicit = True |                     explicit = True | ||||||
|                     if old_data is not None: |                     if old_data is not None: | ||||||
|                         old_info = old_data.get(spec.dag_hash()) |                         old_info = old_data.get(spec.dag_hash()) | ||||||
| @@ -467,8 +466,7 @@ def _read_suppress_error(): | |||||||
|                     # installed compilers or externally installed |                     # installed compilers or externally installed | ||||||
|                     # applications. |                     # applications. | ||||||
|                     tty.debug( |                     tty.debug( | ||||||
|                         'RECONSTRUCTING FROM OLD DB: {0}'.format(entry.spec) |                         'RECONSTRUCTING FROM OLD DB: {0}'.format(entry.spec)) | ||||||
|                     ) |  | ||||||
|                     try: |                     try: | ||||||
|                         layout = spack.store.layout |                         layout = spack.store.layout | ||||||
|                         if entry.spec.external: |                         if entry.spec.external: | ||||||
|   | |||||||
| @@ -168,7 +168,9 @@ def __init__(self, root, **kwargs): | |||||||
|         self.metadata_dir   = kwargs.get('metadata_dir', '.spack') |         self.metadata_dir   = kwargs.get('metadata_dir', '.spack') | ||||||
|         self.hash_len       = kwargs.get('hash_len') |         self.hash_len       = kwargs.get('hash_len') | ||||||
|         self.path_scheme    = kwargs.get('path_scheme') or ( |         self.path_scheme    = kwargs.get('path_scheme') or ( | ||||||
|             "${ARCHITECTURE}/${COMPILERNAME}-${COMPILERVER}/${PACKAGE}-${VERSION}-${HASH}")  # NOQA: E501 |             "${ARCHITECTURE}/" | ||||||
|  |             "${COMPILERNAME}-${COMPILERVER}/" | ||||||
|  |             "${PACKAGE}-${VERSION}-${HASH}") | ||||||
|         if self.hash_len is not None: |         if self.hash_len is not None: | ||||||
|             if re.search('\${HASH:\d+}', self.path_scheme): |             if re.search('\${HASH:\d+}', self.path_scheme): | ||||||
|                 raise InvalidDirectoryLayoutParametersError( |                 raise InvalidDirectoryLayoutParametersError( | ||||||
|   | |||||||
| @@ -58,7 +58,7 @@ | |||||||
|  |  | ||||||
| # control top-level spack options shown in basic vs. advanced help | # control top-level spack options shown in basic vs. advanced help | ||||||
| options_by_level = { | options_by_level = { | ||||||
|     'short': 'hkV', |     'short': ['h', 'k', 'V', 'color'], | ||||||
|     'long': 'all' |     'long': 'all' | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -280,6 +280,9 @@ def make_argument_parser(): | |||||||
|  |  | ||||||
|     parser.add_argument('-h', '--help', action='store_true', |     parser.add_argument('-h', '--help', action='store_true', | ||||||
|                         help="show this help message and exit") |                         help="show this help message and exit") | ||||||
|  |     parser.add_argument('--color', action='store', default='auto', | ||||||
|  |                         choices=('always', 'never', 'auto'), | ||||||
|  |                         help="when to colorize output; default is auto") | ||||||
|     parser.add_argument('-d', '--debug', action='store_true', |     parser.add_argument('-d', '--debug', action='store_true', | ||||||
|                         help="write out debug logs during compile") |                         help="write out debug logs during compile") | ||||||
|     parser.add_argument('-D', '--pdb', action='store_true', |     parser.add_argument('-D', '--pdb', action='store_true', | ||||||
| @@ -325,6 +328,9 @@ def setup_main_options(args): | |||||||
|         tty.warn("You asked for --insecure. Will NOT check SSL certificates.") |         tty.warn("You asked for --insecure. Will NOT check SSL certificates.") | ||||||
|         spack.insecure = True |         spack.insecure = True | ||||||
|  |  | ||||||
|  |     # when to use color (takes always, auto, or never) | ||||||
|  |     tty.color.set_color_when(args.color) | ||||||
|  |  | ||||||
|  |  | ||||||
| def allows_unknown_args(command): | def allows_unknown_args(command): | ||||||
|     """Implements really simple argument injection for unknown arguments. |     """Implements really simple argument injection for unknown arguments. | ||||||
|   | |||||||
| @@ -224,14 +224,14 @@ def add_single_spec(spec, mirror_root, categories, **kwargs): | |||||||
|                     # create a subdirectory for the current package@version |                     # create a subdirectory for the current package@version | ||||||
|                     archive_path = os.path.abspath(join_path( |                     archive_path = os.path.abspath(join_path( | ||||||
|                         mirror_root, mirror_archive_path(spec, fetcher))) |                         mirror_root, mirror_archive_path(spec, fetcher))) | ||||||
|                     name = spec.format("$_$@") |                     name = spec.cformat("$_$@") | ||||||
|                 else: |                 else: | ||||||
|                     resource = stage.resource |                     resource = stage.resource | ||||||
|                     archive_path = os.path.abspath(join_path( |                     archive_path = os.path.abspath(join_path( | ||||||
|                         mirror_root, |                         mirror_root, | ||||||
|                         mirror_archive_path(spec, fetcher, resource.name))) |                         mirror_archive_path(spec, fetcher, resource.name))) | ||||||
|                     name = "{resource} ({pkg}).".format( |                     name = "{resource} ({pkg}).".format( | ||||||
|                         resource=resource.name, pkg=spec.format("$_$@")) |                         resource=resource.name, pkg=spec.cformat("$_$@")) | ||||||
|                 subdir = os.path.dirname(archive_path) |                 subdir = os.path.dirname(archive_path) | ||||||
|                 mkdirp(subdir) |                 mkdirp(subdir) | ||||||
|  |  | ||||||
| @@ -258,8 +258,8 @@ def add_single_spec(spec, mirror_root, categories, **kwargs): | |||||||
|         if spack.debug: |         if spack.debug: | ||||||
|             sys.excepthook(*sys.exc_info()) |             sys.excepthook(*sys.exc_info()) | ||||||
|         else: |         else: | ||||||
|             tty.warn("Error while fetching %s" |             tty.warn( | ||||||
|                      % spec.format('$_$@'), e.message) |                 "Error while fetching %s" % spec.cformat('$_$@'), e.message) | ||||||
|         categories['error'].append(spec) |         categories['error'].append(spec) | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -905,7 +905,7 @@ def do_fetch(self, mirror_only=False): | |||||||
|         start_time = time.time() |         start_time = time.time() | ||||||
|         if spack.do_checksum and self.version not in self.versions: |         if spack.do_checksum and self.version not in self.versions: | ||||||
|             tty.warn("There is no checksum on file to fetch %s safely." % |             tty.warn("There is no checksum on file to fetch %s safely." % | ||||||
|                      self.spec.format('$_$@')) |                      self.spec.cformat('$_$@')) | ||||||
|  |  | ||||||
|             # Ask the user whether to skip the checksum if we're |             # Ask the user whether to skip the checksum if we're | ||||||
|             # interactive, but just fail if non-interactive. |             # interactive, but just fail if non-interactive. | ||||||
| @@ -1649,8 +1649,9 @@ def do_activate(self, force=False): | |||||||
|         self.extendee_spec.package.activate(self, **self.extendee_args) |         self.extendee_spec.package.activate(self, **self.extendee_args) | ||||||
|  |  | ||||||
|         spack.store.layout.add_extension(self.extendee_spec, self.spec) |         spack.store.layout.add_extension(self.extendee_spec, self.spec) | ||||||
|         tty.msg("Activated extension %s for %s" % |         tty.msg( | ||||||
|                 (self.spec.short_spec, self.extendee_spec.format("$_$@$+$%@"))) |             "Activated extension %s for %s" % | ||||||
|  |             (self.spec.short_spec, self.extendee_spec.cformat("$_$@$+$%@"))) | ||||||
|  |  | ||||||
|     def dependency_activations(self): |     def dependency_activations(self): | ||||||
|         return (spec for spec in self.spec.traverse(root=False, deptype='run') |         return (spec for spec in self.spec.traverse(root=False, deptype='run') | ||||||
| @@ -1708,8 +1709,9 @@ def do_deactivate(self, **kwargs): | |||||||
|             spack.store.layout.remove_extension( |             spack.store.layout.remove_extension( | ||||||
|                 self.extendee_spec, self.spec) |                 self.extendee_spec, self.spec) | ||||||
|  |  | ||||||
|         tty.msg("Deactivated extension %s for %s" % |         tty.msg( | ||||||
|                 (self.spec.short_spec, self.extendee_spec.format("$_$@$+$%@"))) |             "Deactivated extension %s for %s" % | ||||||
|  |             (self.spec.short_spec, self.extendee_spec.cformat("$_$@$+$%@"))) | ||||||
|  |  | ||||||
|     def deactivate(self, extension, **kwargs): |     def deactivate(self, extension, **kwargs): | ||||||
|         """Unlinks all files from extension out of this package's install dir. |         """Unlinks all files from extension out of this package's install dir. | ||||||
|   | |||||||
| @@ -108,6 +108,10 @@ | |||||||
| from six import string_types | from six import string_types | ||||||
| from six import iteritems | from six import iteritems | ||||||
|  |  | ||||||
|  | from llnl.util.filesystem import find_headers, find_libraries, is_exe | ||||||
|  | from llnl.util.lang import * | ||||||
|  | from llnl.util.tty.color import * | ||||||
|  |  | ||||||
| import spack | import spack | ||||||
| import spack.architecture | import spack.architecture | ||||||
| import spack.compilers as compilers | import spack.compilers as compilers | ||||||
| @@ -117,9 +121,6 @@ | |||||||
| import spack.util.spack_json as sjson | import spack.util.spack_json as sjson | ||||||
| import spack.util.spack_yaml as syaml | import spack.util.spack_yaml as syaml | ||||||
|  |  | ||||||
| from llnl.util.filesystem import find_headers, find_libraries, is_exe |  | ||||||
| from llnl.util.lang import * |  | ||||||
| from llnl.util.tty.color import * |  | ||||||
| from spack.util.module_cmd import get_path_from_module, load_module | from spack.util.module_cmd import get_path_from_module, load_module | ||||||
| from spack.error import SpecError, UnsatisfiableSpecError | from spack.error import SpecError, UnsatisfiableSpecError | ||||||
| from spack.provider_index import ProviderIndex | from spack.provider_index import ProviderIndex | ||||||
| @@ -1363,9 +1364,8 @@ def short_spec(self): | |||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def cshort_spec(self): |     def cshort_spec(self): | ||||||
|         """Returns a version of the spec with the dependencies hashed |         """Returns an auto-colorized version of ``self.short_spec``.""" | ||||||
|            instead of completely enumerated.""" |         return self.cformat('$_$@$%@$+$=$/') | ||||||
|         return self.format('$_$@$%@$+$=$/', color=True) |  | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def prefix(self): |     def prefix(self): | ||||||
| @@ -2852,6 +2852,12 @@ def write(s, c): | |||||||
|         result = out.getvalue() |         result = out.getvalue() | ||||||
|         return result |         return result | ||||||
|  |  | ||||||
|  |     def cformat(self, *args, **kwargs): | ||||||
|  |         """Same as format, but color defaults to auto instead of False.""" | ||||||
|  |         kwargs = kwargs.copy() | ||||||
|  |         kwargs.setdefault('color', None) | ||||||
|  |         return self.format(*args, **kwargs) | ||||||
|  |  | ||||||
|     def dep_string(self): |     def dep_string(self): | ||||||
|         return ''.join("^" + dep.format() for dep in self.sorted_deps()) |         return ''.join("^" + dep.format() for dep in self.sorted_deps()) | ||||||
|  |  | ||||||
| @@ -2882,7 +2888,7 @@ def _installed_explicitly(self): | |||||||
|     def tree(self, **kwargs): |     def tree(self, **kwargs): | ||||||
|         """Prints out this spec and its dependencies, tree-formatted |         """Prints out this spec and its dependencies, tree-formatted | ||||||
|            with indentation.""" |            with indentation.""" | ||||||
|         color = kwargs.pop('color', False) |         color = kwargs.pop('color', get_color_when()) | ||||||
|         depth = kwargs.pop('depth', False) |         depth = kwargs.pop('depth', False) | ||||||
|         hashes = kwargs.pop('hashes', False) |         hashes = kwargs.pop('hashes', False) | ||||||
|         hlen = kwargs.pop('hashlen', None) |         hlen = kwargs.pop('hashlen', None) | ||||||
|   | |||||||
| @@ -115,7 +115,8 @@ function _spack { | |||||||
|     if $list_options |     if $list_options | ||||||
|     then |     then | ||||||
|         compgen -W "-h --help -d --debug -D --pdb -k --insecure -m --mock -p |         compgen -W "-h --help -d --debug -D --pdb -k --insecure -m --mock -p | ||||||
|                     --profile -v --verbose -s --stacktrace -V --version" -- "$cur" |                     --profile -v --verbose -s --stacktrace -V --version | ||||||
|  |                     --color --color=always --color=auto --color=never" -- "$cur" | ||||||
|     else |     else | ||||||
|         compgen -W "$(_subcommands)" -- "$cur" |         compgen -W "$(_subcommands)" -- "$cur" | ||||||
|     fi |     fi | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user