def colorize(c, prefix): if isinstance(prefix, tuple): return "::".join( color.colorize("@%s{%s}" % (c, p)) for p in prefix if p != "()" ) return color.colorize("@%s{%s}" % (c, prefix))
def display_targets(targets): """Prints a human readable list of the targets passed as argument.""" by_vendor = collections.defaultdict(list) for _, target in targets.items(): by_vendor[target.vendor].append(target) def display_target_group(header, target_group): print(header) colify.colify(target_group, indent=4) print('') generic_architectures = by_vendor.pop('generic', None) if generic_architectures: header = color.colorize(r'@*B{Generic architectures (families)}') group = sorted(generic_architectures, key=lambda x: str(x)) display_target_group(header, group) for vendor, vendor_targets in by_vendor.items(): by_family = collections.defaultdict(list) for t in vendor_targets: by_family[str(t.family)].append(t) for family, group in by_family.items(): vendor = color.colorize(r'@*B{' + vendor + r'}') family = color.colorize(r'@*B{' + family + r'}') header = ' - '.join([vendor, family]) group = sorted(group, key=lambda x: len(x.ancestors)) display_target_group(header, group)
def avail_full(self, regex=None, long_format=False): sio = StringIO() sio.write("\n") _, width = tty.terminal_size() # head = lambda x: (" " + x + " ").center(width, "-") for path in self: directory = path.path modules = sorted([m for m in path.modules if m.is_enabled], key=self.sort_key) modules = self.filter_modules_by_regex(modules, regex) if not os.path.isdir(directory): # pragma: no cover s = colorize("@r{(Directory not readable)}".center(width)) elif not modules: # pragma: no cover if regex: continue s = colorize("@r{(None)}".center(width)) else: modules = [ self.colorize(m.format_dl_status()) for m in modules ] aliases = pymod.alias.get(directory) if aliases: # pragma: no cover for (alias, target) in aliases: i = bisect.bisect_left(modules, alias) insert_key = colorize("@M{%s}@@" % (alias)) if long_format: # pragma: no cover insert_key += " -> %s" % (target) modules.insert(i, insert_key) s = colified(modules, width=width) directory = directory.replace(os.path.expanduser("~/"), "~/") # sio.write(head(directory) + '\n') sio.write(colorize("@G{%s}:\n" % (directory))) sio.write(s + "\n") return sio.getvalue()
def style(parser, args): # ensure python version is new enough if sys.version_info < (3, 6): tty.die("spack style requires Python 3.6 or later.") # save initial working directory for relativizing paths later args.initial_working_dir = os.getcwd() # ensure that the config files we need actually exist in the spack prefix. # assertions b/c users should not ever see these errors -- they're checked in CI. assert os.path.isfile(os.path.join(spack.paths.prefix, "pyproject.toml")) assert os.path.isfile(os.path.join(spack.paths.prefix, ".flake8")) # validate spack root if the user provided one args.root = os.path.realpath(args.root) if args.root else spack.paths.prefix spack_script = os.path.join(args.root, "bin", "spack") if not os.path.exists(spack_script): tty.die( "This does not look like a valid spack root.", "No such file: '%s'" % spack_script ) file_list = args.files if file_list: def prefix_relative(path): return os.path.relpath(os.path.abspath(os.path.realpath(path)), args.root) file_list = [prefix_relative(p) for p in file_list] return_code = 0 with working_dir(args.root): if not file_list: file_list = changed_files(args.base, args.untracked, args.all) print_style_header(file_list, args) commands = {} with spack.bootstrap.ensure_bootstrap_configuration(): for tool_name, bootstrap_fn in tool_order: # Skip the tool if it was not requested if not getattr(args, tool_name): continue commands[tool_name] = bootstrap_fn() for tool_name, bootstrap_fn in tool_order: # Skip the tool if it was not requested if not getattr(args, tool_name): continue run_function, required = tools[tool_name] print_tool_header(tool_name) return_code |= run_function(commands[tool_name], file_list, args) if return_code == 0: tty.msg(color.colorize("@*{spack style checks were clean}")) else: tty.error(color.colorize("@*{spack style found errors}")) return return_code
def decorator(spec, fmt): # add +/-/* to show added/removed/root specs if any(spec.dag_hash() == r.dag_hash() for r in roots): return color.colorize('@*{%s}' % fmt) elif spec in removed: return color.colorize('@K{%s}' % fmt) else: return '%s' % fmt
def colorize(self, string): """Colorize item for output to console""" D = "(%s)" % colorize("@R{D}") L = "(%s)" % colorize("@G{L}") DL = "(%s,%s)" % (colorize("@R{D}"), colorize("@G{L}")) colorized = string.replace("(D)", D) colorized = colorized.replace("(L)", L) colorized = colorized.replace("(D,L)", DL) return colorized
def print_status(self, *specs, **kwargs): if kwargs.get("with_dependencies", False): specs = set(get_dependencies(specs)) specs = sorted(specs, key=lambda s: s.name) in_view = list(map(self.get_spec, specs)) for s, v in zip(specs, in_view): if not v: tty.error(self._croot + 'Package not linked: %s' % s.name) elif s != v: self.print_conflict(v, s, level="warn") in_view = list(filter(None, in_view)) if len(specs) > 0: tty.msg("Packages linked in %s:" % self._croot[:-1]) # Make a dict with specs keyed by architecture and compiler. index = index_by(specs, ('architecture', 'compiler')) # Traverse the index and print out each package for i, (architecture, compiler) in enumerate(sorted(index)): if i > 0: print() header = "%s{%s} / %s{%s}" % (spack.spec.architecture_color, architecture, spack.spec.compiler_color, compiler) tty.hline(colorize(header), char='-') specs = index[(architecture, compiler)] specs.sort() format_string = '{name}{@version}' format_string += '{%compiler}{compiler_flags}{variants}' abbreviated = [s.cformat(format_string) for s in specs] # Print one spec per line along with prefix path width = max(len(s) for s in abbreviated) width += 2 format = " %%-%ds%%s" % width for abbrv, s in zip(abbreviated, specs): prefix = '' if self.verbose: prefix = colorize('@K{%s}' % s.dag_hash(7)) print( prefix + (format % (abbrv, self.get_projection_for_spec(s))) ) else: tty.warn(self._croot + "No packages found.")
def shell_init_instructions(cmd, equivalent): """Print out instructions for users to initialize shell support. Arguments: cmd (str): the command the user tried to run that requires shell support in order to work equivalent (str): a command they can run instead, without enabling shell support """ shell_specific = "{sh_arg}" in equivalent msg = [ "`%s` requires Spack's shell support." % cmd, "", "To set up shell support, run the command below for your shell.", "", color.colorize("@*c{For bash/zsh/sh:}"), " . %s/setup-env.sh" % spack.paths.share_path, "", color.colorize("@*c{For csh/tcsh:}"), " source %s/setup-env.csh" % spack.paths.share_path, "", color.colorize("@*c{For fish:}"), " source %s/setup-env.fish" % spack.paths.share_path, "", color.colorize("@*c{For Windows batch:}"), " source %s/spack_cmd.bat" % spack.paths.share_path, "", "Or, if you do not want to use shell support, run " + ("one of these" if shell_specific else "this") + " instead:", "", ] if shell_specific: msg += [ equivalent.format(sh_arg="--sh ") + " # bash/zsh/sh", equivalent.format(sh_arg="--csh ") + " # csh/tcsh", equivalent.format(sh_arg="--fish") + " # fish", equivalent.format(sh_arg="--bat ") + " # batch" ] else: msg += [" " + equivalent] msg += [ "", "If you have already set up Spack's shell support but still receive", "this message, please make sure to call Spack via the `spack` command", "without any path components (such as `bin/spack`).", ] msg += [''] tty.error(*msg)
def _process_reports(reports): for check, errors in reports: if errors: msg = '{0}: {1} issue{2} found'.format( check, len(errors), '' if len(errors) == 1 else 's') header = '@*b{' + msg + '}' print(cl.colorize(header)) for idx, error in enumerate(errors): print(str(idx + 1) + '. ' + str(error)) raise SystemExit(1) else: msg = '{0}: 0 issues found.'.format(check) header = '@*b{' + msg + '}' print(cl.colorize(header))
def iter_groups(specs, indent, all_headers): """Break a list of specs into groups indexed by arch/compiler.""" # Make a dict with specs keyed by architecture and compiler. index = index_by(specs, ('architecture', 'compiler')) ispace = indent * ' ' # Traverse the index and print out each package for i, (architecture, compiler) in enumerate(sorted(index)): if i > 0: print() header = "%s{%s} / %s{%s}" % (spack.spec.architecture_color, architecture if architecture else 'no arch', spack.spec.compiler_color, compiler if compiler else 'no compiler') # Sometimes we want to display specs that are not yet concretized. # If they don't have a compiler / architecture attached to them, # then skip the header if all_headers or (architecture is not None or compiler is not None): sys.stdout.write(ispace) tty.hline(colorize(header), char='-') specs = index[(architecture, compiler)] specs.sort() yield specs
def compiler_list(args): tty.msg("Available compilers") index = index_by(spack.compilers.all_compilers(scope=args.scope), lambda c: (c.spec.name, c.operating_system, c.target)) # For a container, take each element which does not evaluate to false and # convert it to a string. For elements which evaluate to False (e.g. None) # convert them to '' (in which case it still evaluates to False but is a # string type). Tuples produced by this are guaranteed to be comparable in # Python 3 convert_str = (lambda tuple_container: tuple( str(x) if x else '' for x in tuple_container)) index_str_keys = list((convert_str(x), y) for x, y in index.items()) ordered_sections = sorted(index_str_keys, key=lambda item: item[0]) for i, (key, compilers) in enumerate(ordered_sections): if i >= 1: print() name, os, target = key os_str = os if target: os_str += "-%s" % target cname = "%s{%s} %s" % (spack.spec.compiler_color, name, os_str) tty.hline(colorize(cname), char='-') colify(reversed(sorted(c.spec for c in compilers)))
def info(names): for name in names: modules = pymod.modulepath.candidates(name) if not modules: raise ModuleNotFoundError(name) for module in modules: s = "@B{Module:} @*{%s}\n" % module.fullname s += " @C{Name:} %s\n" % module.name if module.version: # pragma: no cover s += " @C{Version:} %s\n" % module.version if module.family: # pragma: no cover s += " @C{Family:} %s\n" % module.family s += " @C{Loaded:} %s\n" % module.is_loaded s += " @C{Filename:} %s\n" % module.filename s += " @C{Modulepath:} %s" % module.modulepath unlocked_by = module.unlocked_by() if unlocked_by: # pragma: no cover s += " @C{Unlocked by:} %s\n" for m in unlocked_by: s += " %s\n" % m.fullname unlocks = module.unlocks() if unlocks: # pragma: no cover s += " @C{Unlocks:} %s\n" for dirname in unlocks: s += " %s\n" % dirname sys.stderr.write(colorize(s) + "\n")
def disambiguate_spec(spec, env, local=False, installed=True): """Given a spec, figure out which installed package it refers to. Arguments: spec (spack.spec.Spec): a spec to disambiguate env (spack.environment.Environment): a spack environment, if one is active, or None if no environment is active local (boolean, default False): do not search chained spack instances installed (boolean or any, or spack.database.InstallStatus or iterable of spack.database.InstallStatus): install status argument passed to database query. See ``spack.database.Database._query`` for details. """ hashes = env.all_hashes() if env else None if local: matching_specs = spack.store.db.query_local(spec, hashes=hashes, installed=installed) else: matching_specs = spack.store.db.query(spec, hashes=hashes, installed=installed) if not matching_specs: tty.die("Spec '%s' matches no installed packages." % spec) elif len(matching_specs) > 1: format_string = '{name}{@version}{%compiler}{arch=architecture}' args = ["%s matches multiple packages." % spec, "Matching packages:"] args += [ colorize(" @K{%s} " % s.dag_hash(7)) + s.cformat(format_string) for s in matching_specs ] args += ["Use a more specific spec."] tty.die(*args) return matching_specs[0]
def disambiguate_spec_from_hashes(spec, hashes, local=False, installed=True, first=False): """Given a spec and a list of hashes, get concrete spec the spec refers to. Arguments: spec (spack.spec.Spec): a spec to disambiguate hashes (typing.Iterable): a set of hashes of specs among which to disambiguate local (bool): do not search chained spack instances installed (bool or spack.database.InstallStatus or typing.Iterable): install status argument passed to database query. See ``spack.database.Database._query`` for details. """ if local: matching_specs = spack.store.db.query_local(spec, hashes=hashes, installed=installed) else: matching_specs = spack.store.db.query(spec, hashes=hashes, installed=installed) if not matching_specs: tty.die("Spec '%s' matches no installed packages." % spec) elif first: return matching_specs[0] elif len(matching_specs) > 1: format_string = '{name}{@version}{%compiler}{arch=architecture}' args = ["%s matches multiple packages." % spec, "Matching packages:"] args += [colorize(" @K{%s} " % s.dag_hash(7)) + s.cformat(format_string) for s in matching_specs] args += ["Use a more specific spec."] tty.die(*args) return matching_specs[0]
def display_env(env, args, decorator): tty.msg('In environment %s' % env.name) if not env.user_specs: tty.msg('No root specs') else: tty.msg('Root specs') # Root specs cannot be displayed with prefixes, since those are not # set for abstract specs. Same for hashes root_args = copy.copy(args) root_args.paths = False # Roots are displayed with variants, etc. so that we can see # specifically what the user asked for. cmd.display_specs( env.user_specs, root_args, decorator=lambda s, f: color.colorize('@*{%s}' % f), namespace=True, show_flags=True, show_full_compiler=True, variants=True ) print() if args.show_concretized: tty.msg('Concretized roots') cmd.display_specs( env.specs_by_hash.values(), args, decorator=decorator) print()
def display_env(env, args, decorator): tty.msg('In environment %s' % env.name) if not env.user_specs: tty.msg('No root specs') else: tty.msg('Root specs') # Roots are displayed with variants, etc. so that we can see # specifically what the user asked for. cmd.display_specs(env.user_specs, args, decorator=lambda s, f: color.colorize('@*{%s}' % f), namespace=True, show_flags=True, show_full_compiler=True, variants=True) print() if args.show_concretized: tty.msg('Concretized roots') cmd.display_specs(env.specs_by_hash.values(), args, decorator=decorator) print()
def activate( env, use_env_repo=False, add_view=True, shell='sh', prompt=None ): """Activate an environment. To activate an environment, we add its configuration scope to the existing Spack configuration, and we set active to the current environment. Arguments: env (Environment): the environment to activate use_env_repo (bool): use the packages exactly as they appear in the environment's repository add_view (bool): generate commands to add view to path variables shell (string): One of `sh`, `csh`. prompt (string): string to add to the users prompt, or None Returns: cmds: Shell commands to activate environment. TODO: environment to use the activated spack environment. """ global _active_environment _active_environment = env prepare_config_scope(_active_environment) if use_env_repo: spack.repo.path.put_first(_active_environment.repo) tty.debug("Using environmennt '%s'" % _active_environment.name) # Construct the commands to run cmds = '' if shell == 'csh': # TODO: figure out how to make color work for csh cmds += 'setenv SPACK_ENV %s;\n' % env.path cmds += 'alias despacktivate "spack env deactivate";\n' if prompt: cmds += 'if (! $?SPACK_OLD_PROMPT ) ' cmds += 'setenv SPACK_OLD_PROMPT "${prompt}";\n' cmds += 'set prompt="%s ${prompt}";\n' % prompt else: if os.getenv('TERM') and 'color' in os.getenv('TERM') and prompt: prompt = colorize('@G{%s} ' % prompt, color=True) cmds += 'export SPACK_ENV=%s;\n' % env.path cmds += "alias despacktivate='spack env deactivate';\n" if prompt: cmds += 'if [ -z ${SPACK_OLD_PS1+x} ]; then\n' cmds += ' if [ -z ${PS1+x} ]; then\n' cmds += " PS1='$$$$';\n" cmds += ' fi;\n' cmds += ' export SPACK_OLD_PS1="${PS1}";\n' cmds += 'fi;\n' cmds += 'export PS1="%s ${PS1}";\n' % prompt if add_view and default_view_name in env.views: cmds += env.add_default_view_to_shell(shell) return cmds
def activate_header(env, shell, prompt=None): # Construct the commands to run cmds = '' if shell == 'csh': # TODO: figure out how to make color work for csh cmds += 'setenv SPACK_ENV %s;\n' % env.path cmds += 'alias despacktivate "spack env deactivate";\n' if prompt: cmds += 'if (! $?SPACK_OLD_PROMPT ) ' cmds += 'setenv SPACK_OLD_PROMPT "${prompt}";\n' cmds += 'set prompt="%s ${prompt}";\n' % prompt elif shell == 'fish': if 'color' in os.getenv('TERM', '') and prompt: prompt = colorize('@G{%s} ' % prompt, color=True) cmds += 'set -gx SPACK_ENV %s;\n' % env.path cmds += 'function despacktivate;\n' cmds += ' spack env deactivate;\n' cmds += 'end;\n' # # NOTE: We're not changing the fish_prompt function (which is fish's # solution to the PS1 variable) here. This is a bit fiddly, and easy to # screw up => spend time reasearching a solution. Feedback welcome. # elif shell == 'bat': # TODO: Color cmds += 'set "SPACK_ENV=%s"\n' % env.path # TODO: despacktivate # TODO: prompt else: if 'color' in os.getenv('TERM', '') and prompt: prompt = colorize('@G{%s}' % prompt, color=True) cmds += 'export SPACK_ENV=%s;\n' % env.path cmds += "alias despacktivate='spack env deactivate';\n" if prompt: cmds += 'if [ -z ${SPACK_OLD_PS1+x} ]; then\n' cmds += ' if [ -z ${PS1+x} ]; then\n' cmds += " PS1='$$$$';\n" cmds += ' fi;\n' cmds += ' export SPACK_OLD_PS1="${PS1}";\n' cmds += 'fi;\n' cmds += 'export PS1="%s ${PS1}";\n' % prompt return cmds
def compiler_list(args): tty.msg("Available compilers") index = index_by(spack.compilers.all_compilers(scope=args.scope), 'name') for i, (name, compilers) in enumerate(index.items()): if i >= 1: print cname = "%s{%s}" % (spack.spec.compiler_color, name) tty.hline(colorize(cname), char='-') colify(reversed(sorted(compilers)))
def dump(stream=None): # pragma: no cover """Dump the final results to the shell to be evaluated""" output = format_output() stream = sys.stderr if pymod.config.get("dryrun") else stream or sys.stdout stream.write(output) output = pymod.mc._mc.format_changed_module_state() if output.split(): sys.stderr.write(colorize(output))
def compiler_list(args): tty.msg("Available compilers") index = index_by(spack.compilers.all_compilers(), 'name') for i, (name, compilers) in enumerate(index.items()): if i >= 1: print cname = "%s{%s}" % (spack.spec.compiler_color, name) tty.hline(colorize(cname), char='-') colify(reversed(sorted(compilers)))
def find(names): for name in names: s = None candidates = pymod.modulepath.candidates(name) if not candidates: raise ModuleNotFoundError(name) for module in candidates: s = "@*{%s}\n @C{%s}" % (module.fullname, module.filename) sys.stderr.write(colorize(s) + "\n")
def get_package_context(traceback, context=3): """Return some context for an error message when the build fails. Args: traceback (traceback): A traceback from some exception raised during install context (int): Lines of context to show before and after the line where the error happened This function inspects the stack to find where we failed in the package file, and it adds detailed context to the long_message from there. """ def make_stack(tb, stack=None): """Tracebacks come out of the system in caller -> callee order. Return an array in callee -> caller order so we can traverse it.""" if stack is None: stack = [] if tb is not None: make_stack(tb.tb_next, stack) stack.append(tb) return stack stack = make_stack(traceback) for tb in stack: frame = tb.tb_frame if 'self' in frame.f_locals: # Find the first proper subclass of PackageBase. obj = frame.f_locals['self'] if isinstance(obj, spack.package.PackageBase): break # we found obj, the Package implementation we care about. # point out the location in the install method where we failed. lines = [] lines.append("%s:%d, in %s:" % ( inspect.getfile(frame.f_code), frame.f_lineno, frame.f_code.co_name )) # Build a message showing context in the install method. sourcelines, start = inspect.getsourcelines(frame) fl = frame.f_lineno - start start_ctx = max(0, fl - context) sourcelines = sourcelines[start_ctx:fl + context + 1] for i, line in enumerate(sourcelines): is_error = start_ctx + i == fl mark = ">> " if is_error else " " marked = " %s%-6d%s" % (mark, start_ctx + i, line.rstrip()) if is_error: marked = colorize('@R{%s}' % marked) lines.append(marked) return lines
def help(parser, args): if args.guide: print(colorize(guides[args.guide])) return 0 if args.help_command: parser.add_command(args.help_command) parser.parse_args([args.help_command, '-h']) else: sys.stdout.write(parser.format_help(level=args.all))
def shell_init_instructions(cmd, equivalent): """Print out instructions for users to initialize shell support. Arguments: cmd (str): the command the user tried to run that requires shell support in order to work equivalent (str): a command they can run instead, without enabling shell support """ shell_specific = "{sh_arg}" in equivalent msg = [ "`%s` requires spack's shell support." % cmd, "", "To set up shell support, run the command below for your shell.", "", color.colorize("@*c{For bash/zsh/sh:}"), " . %s/setup-env.sh" % spack.paths.share_path, "", color.colorize("@*c{For csh/tcsh:}"), " source %s/setup-env.csh" % spack.paths.share_path, "", color.colorize("@*c{For fish:}"), " source %s/setup-env.fish" % spack.paths.share_path, "", "Or, if you do not want to use shell support, run " + ("one of these" if shell_specific else "this") + " instead:", "", ] if shell_specific: msg += [ equivalent.format(sh_arg="--sh ") + " # bash/zsh/sh", equivalent.format(sh_arg="--csh ") + " # csh/tcsh", equivalent.format(sh_arg="--fish") + " # fish", ] else: msg += [" " + equivalent] msg += [''] tty.error(*msg)
def list(parser, args): for subcommand, check_tags in spack.audit.GROUPS.items(): print(cl.colorize('@*b{' + subcommand + '}:')) for tag in check_tags: audit_obj = spack.audit.CALLBACKS[tag] print(' ' + audit_obj.description) if args.verbose: for idx, fn in enumerate(audit_obj.callbacks): print(' {0}. '.format(idx + 1) + fn.__doc__) print() print()
def style(parser, args): # save initial working directory for relativizing paths later global initial_working_dir initial_working_dir = os.getcwd() file_list = args.files if file_list: def prefix_relative(path): return os.path.relpath(os.path.abspath(os.path.realpath(path)), spack.paths.prefix) file_list = [prefix_relative(p) for p in file_list] returncode = 0 with working_dir(spack.paths.prefix): if not file_list: file_list = changed_files(args.base, args.untracked, args.all) print_style_header(file_list, args) # run tools in order defined in tool_order returncode = 0 for tool_name in tool_order: if getattr(args, tool_name): run_function, required = tools[tool_name] print_tool_header(tool_name) cmd = which(tool_name, required=required) if not cmd: color.cprint(" @y{%s not in PATH, skipped}" % tool_name) continue returncode |= run_function(cmd, file_list, args) if returncode == 0: tty.msg(color.colorize("@*{spack style checks were clean}")) else: tty.error(color.colorize("@*{spack style found errors}")) return returncode
def env_activate(args): env = args.activate_env if not args.shell: msg = [ "This command works best with Spack's shell support", "" ] + spack.cmd.common.shell_init_instructions + [ 'Or, if you want to use `spack env activate` without initializing', 'shell support, you can run one of these:', '', ' eval `spack env activate --sh %s` # for bash/sh' % env, ' eval `spack env activate --csh %s` # for csh/tcsh' % env, ] tty.msg(*msg) return 1 if ev.exists(env) and not args.dir: spack_env = ev.root(env) short_name = env env_prompt = '[%s]' % env elif ev.is_env_dir(env): spack_env = os.path.abspath(env) short_name = os.path.basename(os.path.abspath(env)) env_prompt = '[%s]' % short_name else: tty.die("No such environment: '%s'" % env) if spack_env == os.environ.get('SPACK_ENV'): tty.die("Environment %s is already active" % args.activate_env) if args.shell == 'csh': # TODO: figure out how to make color work for csh sys.stdout.write('setenv SPACK_ENV %s;\n' % spack_env) sys.stdout.write('alias despacktivate "spack env deactivate";\n') if args.prompt: sys.stdout.write('if (! $?SPACK_OLD_PROMPT ) ' 'setenv SPACK_OLD_PROMPT "${prompt}";\n') sys.stdout.write('set prompt="%s ${prompt}";\n' % env_prompt) else: if 'color' in os.environ['TERM']: env_prompt = colorize('@G{%s} ' % env_prompt, color=True) sys.stdout.write('export SPACK_ENV=%s;\n' % spack_env) sys.stdout.write("alias despacktivate='spack env deactivate';\n") if args.prompt: sys.stdout.write('if [ -z "${SPACK_OLD_PS1}" ]; then\n') sys.stdout.write('export SPACK_OLD_PS1="${PS1}"; fi;\n') sys.stdout.write('export PS1="%s ${PS1}";\n' % env_prompt)
def write_line_break(self): super(LineAnnotationDumper, self).write_line_break() if self.saved is None: _annotations.append(colorize('@K{---}')) return # append annotations at the end of each line if self.saved: mark = self.saved._start_mark color = self.filename_colors.get(mark.name) if not color: ncolors = len(self.colors) color = self.colors[len(self.filename_colors) % ncolors] self.filename_colors[mark.name] = color fmt = '@%s{%%s}' % color ann = fmt % mark.name if mark.line is not None: ann += ':@c{%s}' % (mark.line + 1) _annotations.append(colorize(ann)) else: _annotations.append('')
def write_line_break(self): super(LineAnnotationDumper, self).write_line_break() if not self.saved: return # append annotations at the end of each line if self.saved: mark = self.saved._start_mark ann = '@K{%s}' % mark.name if mark.line is not None: ann += ':@c{%s}' % (mark.line + 1) _annotations.append(colorize(ann)) else: _annotations.append('')
def disambiguate_spec(spec): matching_specs = spack.store.db.query(spec) if not matching_specs: tty.die("Spec '%s' matches no installed packages." % spec) elif len(matching_specs) > 1: args = ["%s matches multiple packages." % spec, "Matching packages:"] args += [colorize(" @K{%s} " % s.dag_hash(7)) + s.cformat('$_$@$%@$=') for s in matching_specs] args += ["Use a more specific spec."] tty.die(*args) return matching_specs[0]
def compiler_list(args): tty.msg("Available compilers") index = index_by(spack.compilers.all_compilers(scope=args.scope), lambda c: (c.spec.name, c.operating_system, c.target)) ordered_sections = sorted(index.items(), key=lambda item: item[0]) for i, (key, compilers) in enumerate(ordered_sections): if i >= 1: print() name, os, target = key os_str = os if target: os_str += "-%s" % target cname = "%s{%s} %s" % (spack.spec.compiler_color, name, os_str) tty.hline(colorize(cname), char='-') colify(reversed(sorted(c.spec for c in compilers)))
def env_list(args): names = ev.all_environment_names() color_names = [] for name in names: if ev.active(name): name = colorize('@*g{%s}' % name) color_names.append(name) # say how many there are if writing to a tty if sys.stdout.isatty(): if not names: tty.msg('No environments') else: tty.msg('%d environments' % len(names)) colify(color_names, indent=4)
def find(parser, args): q_args = query_arguments(args) results = args.specs(**q_args) decorator = lambda s, f: f added = set() removed = set() env = ev.get_env(args, 'find', required=False) if env: decorator, added, roots, removed = setup_env(env) # Exit early if no package matches the constraint if not results and args.constraint: msg = "No package matches the query: {0}" msg = msg.format(' '.join(args.constraint)) tty.msg(msg) return # If tags have been specified on the command line, filter by tags if args.tags: packages_with_tags = spack.repo.path.packages_with_tags(*args.tags) results = [x for x in results if x.name in packages_with_tags] # Display the result if env: tty.msg('In environment %s' % env.name) if not env.user_specs: tty.msg('No root specs') else: tty.msg('Root specs') display_specs( env.user_specs, args, decorator=lambda s, f: color.colorize('@*{%s}' % f)) print() if args.show_concretized: tty.msg('Concretized roots') display_specs( env.specs_by_hash.values(), args, decorator=decorator) print() tty.msg("%s" % plural(len(results), 'installed package')) display_specs(results, args, decorator=decorator, all_headers=True)
def write_line_break(self): super(LineAnnotationDumper, self).write_line_break() if not self.saved: return # append annotations at the end of each line if self.saved: mark = self.saved._start_mark color = self.filename_colors.get(mark.name) if not color: ncolors = len(self.colors) color = self.colors[len(self.filename_colors) % ncolors] self.filename_colors[mark.name] = color fmt = '@%s{%%s}' % color ann = fmt % mark.name if mark.line is not None: ann += ':@c{%s}' % (mark.line + 1) _annotations.append(colorize(ann)) else: _annotations.append('')
def display_specs(specs, args=None, **kwargs): """Display human readable specs with customizable formatting. Prints the supplied specs to the screen, formatted according to the arguments provided. Specs are grouped by architecture and compiler, and columnized if possible. There are three possible "modes": * ``short`` (default): short specs with name and version, columnized * ``paths``: Two columns: one for specs, one for paths * ``deps``: Dependency-tree style, like ``spack spec``; can get long Options can add more information to the default display. Options can be provided either as keyword arguments or as an argparse namespace. Keyword arguments take precedence over settings in the argparse namespace. Args: specs (list of spack.spec.Spec): the specs to display args (optional argparse.Namespace): namespace containing formatting arguments Keyword Args: mode (str): Either 'short', 'paths', or 'deps' long (bool): Display short hashes with specs very_long (bool): Display full hashes with specs (supersedes ``long``) namespace (bool): Print namespaces along with names show_flags (bool): Show compiler flags with specs variants (bool): Show variants with specs """ def get_arg(name, default=None): """Prefer kwargs, then args, then default.""" if name in kwargs: return kwargs.get(name) elif args is not None: return getattr(args, name, default) else: return default mode = get_arg('mode', 'short') hashes = get_arg('long', False) namespace = get_arg('namespace', False) flags = get_arg('show_flags', False) full_compiler = get_arg('show_full_compiler', False) variants = get_arg('variants', False) hlen = 7 if get_arg('very_long', False): hashes = True hlen = None nfmt = '.' if namespace else '_' ffmt = '' if full_compiler or flags: ffmt += '$%' if full_compiler: ffmt += '@' ffmt += '+' vfmt = '$+' if variants else '' format_string = '$%s$@%s%s' % (nfmt, ffmt, vfmt) # Make a dict with specs keyed by architecture and compiler. index = index_by(specs, ('architecture', 'compiler')) # Traverse the index and print out each package for i, (architecture, compiler) in enumerate(sorted(index)): if i > 0: print() header = "%s{%s} / %s{%s}" % (spack.spec.architecture_color, architecture, spack.spec.compiler_color, compiler) # Sometimes we want to display specs that are not yet concretized. # If they don't have a compiler / architecture attached to them, # then skip the header if architecture is not None or compiler is not None: tty.hline(colorize(header), char='-') specs = index[(architecture, compiler)] specs.sort() abbreviated = [s.cformat(format_string) for s in specs] if mode == 'paths': # Print one spec per line along with prefix path width = max(len(s) for s in abbreviated) width += 2 format = " %%-%ds%%s" % width for abbrv, spec in zip(abbreviated, specs): prefix = gray_hash(spec, hlen) if hashes else '' print(prefix + (format % (abbrv, spec.prefix))) elif mode == 'deps': for spec in specs: print(spec.tree( format=format_string, indent=4, prefix=(lambda s: gray_hash(s, hlen)) if hashes else None)) elif mode == 'short': # Print columns of output if not printing flags if not flags and not full_compiler: def fmt(s): string = "" if hashes: string += gray_hash(s, hlen) + ' ' string += s.cformat('$-%s$@%s' % (nfmt, vfmt)) return string colify(fmt(s) for s in specs) # Print one entry per line if including flags else: for spec in specs: # Print the hash if necessary hsh = gray_hash(spec, hlen) + ' ' if hashes else '' print(hsh + spec.cformat(format_string) + '\n') else: raise ValueError( "Invalid mode for display_specs: %s. Must be one of (paths," "deps, short)." % mode)
def write_stream_start(self): super(LineAnnotationDumper, self).write_stream_start() _annotations.append(colorize('@K{---}'))
def gray_hash(spec, length): return colorize('@K{%s}' % spec.dag_hash(length))
def make_log_context(log_events, width=None): """Get error context from a log file. Args: log_events (list of LogEvent): list of events created by ``ctest_log_parser.parse()`` width (int or None): wrap width; ``0`` for no limit; ``None`` to auto-size for terminal Returns: str: context from the build log with errors highlighted Parses the log file for lines containing errors, and prints them out with line numbers and context. Errors are highlighted with '>>' and with red highlighting (if color is enabled). Events are sorted by line number before they are displayed. """ error_lines = set(e.line_no for e in log_events) log_events = sorted(log_events, key=lambda e: e.line_no) num_width = len(str(max(error_lines))) + 4 line_fmt = '%%-%dd%%s' % num_width indent = ' ' * (5 + num_width) if width is None: _, width = tty.terminal_size() if width <= 0: width = sys.maxsize wrap_width = width - num_width - 6 out = StringIO() next_line = 1 for event in log_events: start = event.start if isinstance(event, BuildError): color = 'R' elif isinstance(event, BuildWarning): color = 'Y' else: color = 'W' if next_line != 1 and start > next_line: out.write('\n ...\n\n') if start < next_line: start = next_line for i in range(start, event.end): # wrap to width lines = _wrap(event[i], wrap_width) lines[1:] = [indent + l for l in lines[1:]] wrapped_line = line_fmt % (i, '\n'.join(lines)) if i in error_lines: out.write(colorize( ' @%s{>> %s}\n' % (color, cescape(wrapped_line)))) else: out.write(' %s\n' % wrapped_line) next_line = event.end return out.getvalue()
def get_package_context(traceback, context=3): """Return some context for an error message when the build fails. Args: traceback (traceback): A traceback from some exception raised during install context (int): Lines of context to show before and after the line where the error happened This function inspects the stack to find where we failed in the package file, and it adds detailed context to the long_message from there. """ def make_stack(tb, stack=None): """Tracebacks come out of the system in caller -> callee order. Return an array in callee -> caller order so we can traverse it.""" if stack is None: stack = [] if tb is not None: make_stack(tb.tb_next, stack) stack.append(tb) return stack stack = make_stack(traceback) for tb in stack: frame = tb.tb_frame if 'self' in frame.f_locals: # Find the first proper subclass of PackageBase. obj = frame.f_locals['self'] if isinstance(obj, spack.package.PackageBase): break # We found obj, the Package implementation we care about. # Point out the location in the install method where we failed. lines = [ '{0}:{1:d}, in {2}:'.format( inspect.getfile(frame.f_code), frame.f_lineno - 1, # subtract 1 because f_lineno is 0-indexed frame.f_code.co_name ) ] # Build a message showing context in the install method. sourcelines, start = inspect.getsourcelines(frame) # Calculate lineno of the error relative to the start of the function. # Subtract 1 because f_lineno is 0-indexed. fun_lineno = frame.f_lineno - start - 1 start_ctx = max(0, fun_lineno - context) sourcelines = sourcelines[start_ctx:fun_lineno + context + 1] for i, line in enumerate(sourcelines): is_error = start_ctx + i == fun_lineno mark = '>> ' if is_error else ' ' # Add start to get lineno relative to start of file, not function. marked = ' {0}{1:-6d}{2}'.format( mark, start + start_ctx + i, line.rstrip()) if is_error: marked = colorize('@R{%s}' % cescape(marked)) lines.append(marked) return lines
def color_url(path, **kwargs): """Color the parts of the url according to Spack's parsing. Colors are: | Cyan: The version found by :func:`parse_version_offset`. | Red: The name found by :func:`parse_name_offset`. | Green: Instances of version string from :func:`substitute_version`. | Magenta: Instances of the name (protected from substitution). Args: path (str): The filename or URL for the package errors (bool): Append parse errors at end of string. subs (bool): Color substitutions as well as parsed name/version. """ errors = kwargs.get('errors', False) subs = kwargs.get('subs', False) (name, ns, nl, noffs, ver, vs, vl, voffs) = substitution_offsets(path) nends = [no + nl - 1 for no in noffs] vends = [vo + vl - 1 for vo in voffs] nerr = verr = 0 out = StringIO() for i in range(len(path)): if i == vs: out.write('@c') verr += 1 elif i == ns: out.write('@r') nerr += 1 elif subs: if i in voffs: out.write('@g') elif i in noffs: out.write('@m') out.write(path[i]) if i == vs + vl - 1: out.write('@.') verr += 1 elif i == ns + nl - 1: out.write('@.') nerr += 1 elif subs: if i in vends or i in nends: out.write('@.') if errors: if nerr == 0: out.write(" @r{[no name]}") if verr == 0: out.write(" @r{[no version]}") if nerr == 1: out.write(" @r{[incomplete name]}") if verr == 1: out.write(" @r{[incomplete version]}") return colorize(out.getvalue())
def gray_hash(spec, length): h = spec.dag_hash(length) if spec.concrete else '-' * length return colorize('@K{%s}' % h)