def print_maintainers(pkg): """output package maintainers""" if len(pkg.maintainers) > 0: mnt = " ".join(['@@' + m for m in pkg.maintainers]) color.cprint('') color.cprint(section_title('Maintainers: ') + mnt)
def info(message, *args, **kwargs): if isinstance(message, Exception): message = "%s: %s" % (message.__class__.__name__, str(message)) format = kwargs.get('format', '*b') stream = kwargs.get('stream', sys.stdout) wrap = kwargs.get('wrap', False) break_long_words = kwargs.get('break_long_words', False) st_countback = kwargs.get('countback', 3) st_text = "" if _stacktrace: st_text = process_stacktrace(st_countback) cprint("@%s{%s==>} %s%s" % ( format, st_text, get_timestamp(), cescape(six.text_type(message)) ), stream=stream) for arg in args: if wrap: lines = textwrap.wrap( six.text_type(arg), initial_indent=indent, subsequent_indent=indent, break_long_words=break_long_words) for line in lines: stream.write(line + '\n') else: stream.write(indent + six.text_type(arg) + '\n')
def _show_patch(sha256): """Show a record from the patch index.""" patches = spack.repo.path.patch_index.index data = patches.get(sha256) if not data: candidates = [k for k in patches if k.startswith(sha256)] if not candidates: tty.die('no such resource: %s' % sha256) elif len(candidates) > 1: tty.die('%s: ambiguous hash prefix. Options are:', *candidates) sha256 = candidates[0] data = patches.get(sha256) color.cprint('@c{%s}' % sha256) for package, rec in data.items(): owner = rec['owner'] if 'relative_path' in rec: pkg_dir = spack.repo.get(owner).package_dir path = os.path.join(pkg_dir, rec['relative_path']) print(" path: %s" % path) else: print(" url: %s" % rec['url']) print(" applies to: %s" % package) if owner != package: print(" patched by: %s" % owner)
def info(message, *args, **kwargs): format = kwargs.get('format', '*b') stream = kwargs.get('stream', sys.stderr) wrap = kwargs.get('wrap', False) break_long_words = kwargs.get('break_long_words', False) st_countback = kwargs.get('countback', 3) reported_by = kwargs.get('reported_by') if reported_by is not None: message += ' (reported by {0})'.format(reported_by) st_text = "" if _stacktrace: st_text = process_stacktrace(st_countback) cprint("@%s{%s==>} %s%s" % (format, st_text, get_timestamp(), cescape(str(message))), stream=stream) for arg in args: if wrap: lines = textwrap.wrap(str(arg), initial_indent=indent, subsequent_indent=indent, break_long_words=break_long_words) for line in lines: stream.write(line + '\n') else: stream.write(indent + str(arg) + '\n')
def msg(message, *args, **kwargs): newline = kwargs.get('newline', True) st_text = "" if _stacktrace: st_text = process_stacktrace(2) if newline: cprint("@*b{%s==>} %s" % (st_text, cescape(message))) else: cwrite("@*b{%s==>} %s" % (st_text, cescape(message))) for arg in args: print(indent + str(arg))
def msg(message, *args, **kwargs): if not msg_enabled(): return newline = kwargs.get('newline', True) st_text = "" if _stacktrace: st_text = process_stacktrace(2) if newline: cprint("@*b{%s==>} %s%s" % (st_text, get_timestamp(), cescape(message))) else: cwrite("@*b{%s==>} %s%s" % (st_text, get_timestamp(), cescape(message))) for arg in args: print(indent + str(arg))
def msg(message, *args, **kwargs): if not msg_enabled(): return if isinstance(message, Exception): message = "%s: %s" % (message.__class__.__name__, str(message)) newline = kwargs.get('newline', True) st_text = "" if _stacktrace: st_text = process_stacktrace(2) if newline: cprint("@*b{%s==>} %s%s" % ( st_text, get_timestamp(), cescape(message))) else: cwrite("@*b{%s==>} %s%s" % ( st_text, get_timestamp(), cescape(message))) for arg in args: print(indent + six.text_type(arg))
def _process_result(result, show, required_format, kwargs): result.raise_if_unsat() opt, _, _ = min(result.answers) if ("opt" in show) and (not required_format): tty.msg("Best of %d considered solutions." % result.nmodels) tty.msg("Optimization Criteria:") maxlen = max(len(s[2]) for s in result.criteria) color.cprint("@*{ Priority Criterion %sInstalled ToBuild}" % ((maxlen - 10) * " ")) fmt = " @K{%%-8d} %%-%ds%%9s %%7s" % maxlen for i, (installed_cost, build_cost, name) in enumerate(result.criteria, 1): color.cprint(fmt % ( i, name, "-" if build_cost is None else installed_cost, installed_cost if build_cost is None else build_cost, )) print() # dump the solutions as concretized specs if 'solutions' in show: for spec in result.specs: # With -y, just print YAML to output. if required_format == 'yaml': # use write because to_yaml already has a newline. sys.stdout.write(spec.to_yaml(hash=ht.dag_hash)) elif required_format == 'json': sys.stdout.write(spec.to_json(hash=ht.dag_hash)) else: sys.stdout.write(spec.tree(color=sys.stdout.isatty(), **kwargs)) print() if result.unsolved_specs and "solutions" in show: tty.msg("Unsolved specs") for spec in result.unsolved_specs: print(spec) print()
def info(message, *args, **kwargs): format = kwargs.get('format', '*b') stream = kwargs.get('stream', sys.stdout) wrap = kwargs.get('wrap', False) break_long_words = kwargs.get('break_long_words', False) st_countback = kwargs.get('countback', 3) st_text = "" if _stacktrace: st_text = process_stacktrace(st_countback) cprint("@%s{%s==>} %s" % (format, st_text, cescape(str(message))), stream=stream) for arg in args: if wrap: lines = textwrap.wrap( str(arg), initial_indent=indent, subsequent_indent=indent, break_long_words=break_long_words) for line in lines: stream.write(line + '\n') else: stream.write(indent + str(arg) + '\n')
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 print_variants(pkg): """output variants""" color.cprint('') color.cprint(section_title('Variants:')) formatter = VariantFormatter(pkg.variants) for line in formatter.lines: color.cprint(color.cescape(line))
def maintainers(parser, args): if args.maintained or args.unmaintained: maintained, unmaintained = maintained_packages() pkgs = maintained if args.maintained else unmaintained colify(pkgs) return 0 if pkgs else 1 if args.all: if args.by_user: maintainers = maintainers_to_packages(args.package_or_user) for user, packages in sorted(maintainers.items()): color.cprint('@c{%s}: %s' % (user, ', '.join(sorted(packages)))) return 0 if maintainers else 1 else: packages = packages_to_maintainers(args.package_or_user) for pkg, maintainers in sorted(packages.items()): color.cprint('@c{%s}: %s' % (pkg, ', '.join(sorted(maintainers)))) return 0 if packages else 1 if args.by_user: if not args.package_or_user: tty.die('spack maintainers --by-user requires a user or --all') packages = union_values(maintainers_to_packages(args.package_or_user)) colify(packages) return 0 if packages else 1 else: if not args.package_or_user: tty.die('spack maintainers requires a package or --all') users = union_values(packages_to_maintainers(args.package_or_user)) colify(users) return 0 if users else 1
def print_tags(pkg): """output package tags""" color.cprint('') color.cprint(section_title("Tags: ")) if hasattr(pkg, 'tags'): tags = sorted(pkg.tags) colify(tags, indent=4) else: color.cprint(" None")
def print_phases(pkg): """output installation phases""" if hasattr(pkg, 'phases') and pkg.phases: color.cprint('') color.cprint(section_title('Installation Phases:')) phase_str = '' for phase in pkg.phases: phase_str += " {0}".format(phase) color.cprint(phase_str)
def print_dependencies(pkg): """output build, link, and run package dependencies""" for deptype in ('build', 'link', 'run'): color.cprint('') color.cprint(section_title('%s Dependencies:' % deptype.capitalize())) deps = sorted(pkg.dependencies_of_type(deptype)) if deps: colify(deps, indent=4) else: color.cprint(' None')
def print_detectable(pkg): """output information on external detection""" color.cprint('') color.cprint(section_title('Externally Detectable: ')) # If the package has an 'executables' field, it can detect an installation if hasattr(pkg, 'executables'): find_attributes = [] if hasattr(pkg, 'determine_version'): find_attributes.append('version') if hasattr(pkg, 'determine_variants'): find_attributes.append('variants') # If the package does not define 'determine_version' nor # 'determine_variants', then it must use some custom detection # mechanism. In this case, just inform the user it's detectable somehow. color.cprint(' True{0}'.format(' (' + ', '.join(find_attributes) + ')' if find_attributes else '')) else: color.cprint(' False')
def print_virtuals(pkg): """output virtual packages""" color.cprint('') color.cprint(section_title('Virtual Packages: ')) if pkg.provided: inverse_map = {} for spec, whens in pkg.provided.items(): for when in whens: if when not in inverse_map: inverse_map[when] = set() inverse_map[when].add(spec) for when, specs in reversed(sorted(inverse_map.items())): line = " %s provides %s" % (when.colorized(), ', '.join( s.colorized() for s in specs)) print(line) else: color.cprint(" None")
def fmt(header, content): header_fmt = "@*b{{{0}:}} {1}" color.cprint(header_fmt.format(header, content))
def do_list(args, extra_args): """Print a lists of tests than what pytest offers.""" 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)) # To list the files we just need to inspect the filesystem, # which doesn't need to wait for pytest collection and doesn't # require parsing pytest output files = llnl.util.filesystem.find(root=spack.paths.test_path, files='*.py', recursive=True) files = [ os.path.relpath(f, start=spack.paths.spack_root) for f in files if not f.endswith(('conftest.py', '__init__.py')) ] old_output = sys.stdout try: sys.stdout = output = StringIO() pytest.main(['--collect-only'] + extra_args) finally: sys.stdout = old_output lines = output.getvalue().split('\n') tests = collections.defaultdict(set) # collect tests into sections node_regexp = re.compile(r"(\s*)<([^ ]*) ['\"]?([^']*)['\"]?>") key_parts, name_parts = [], [] for line in lines: match = node_regexp.match(line) if not match: continue indent, nodetype, name = match.groups() # strip parametrized tests if "[" in name: name = name[:name.index("[")] len_indent = len(indent) if os.path.isabs(name): name = os.path.relpath(name, start=spack.paths.spack_root) item = (len_indent, name, nodetype) # Reduce the parts to the scopes that are of interest name_parts = [x for x in name_parts if x[0] < len_indent] key_parts = [x for x in key_parts if x[0] < len_indent] # From version 3.X to version 6.X the output format # changed a lot in pytest, and probably will change # in the future - so this manipulation might be fragile if nodetype.lower() == 'function': name_parts.append(item) key_end = os.path.join(*[x[1] for x in key_parts]) key = next(f for f in files if f.endswith(key_end)) tests[key].add(tuple(x[1] for x in name_parts)) elif nodetype.lower() == 'class': name_parts.append(item) elif nodetype.lower() in ('package', 'module'): key_parts.append(item) if args.list == "list": files = set(tests.keys()) color_files = [colorize("B", file) for file in sorted(files)] colify(color_files) elif args.list == "long": for prefix, functions in sorted(tests.items()): path = colorize("*B", prefix) + "::" functions = [colorize("c", f) for f in sorted(functions)] color.cprint(path) colify(functions, indent=4) print() else: # args.list == "names" all_functions = [ colorize("*B", prefix) + "::" + colorize("c", f) for prefix, functions in sorted(tests.items()) for f in sorted(functions) ] colify(all_functions)
def print_text_info(pkg): """Print out a plain text description of a package.""" 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) if len(pkg.maintainers) > 0: mnt = " ".join(['@@' + m for m in pkg.maintainers]) color.cprint('') color.cprint(section_title('Maintainers: ') + mnt) color.cprint('') color.cprint(section_title("Tags: ")) if hasattr(pkg, 'tags'): tags = sorted(pkg.tags) colify(tags, indent=4) else: color.cprint(" None") color.cprint('') color.cprint(section_title('Preferred version: ')) if not pkg.versions: color.cprint(version(' None')) color.cprint('') color.cprint(section_title('Safe versions: ')) color.cprint(version(' None')) else: pad = padder(pkg.versions, 4) # Here we sort first on the fact that a version is marked # as preferred in the package, then on the fact that the # version is not develop, then lexicographically key_fn = lambda v: (pkg.versions[v].get('preferred', False), not v.isdevelop(), v) preferred = sorted(pkg.versions, key=key_fn).pop() f = fs.for_package_version(pkg, preferred) line = version(' {0}'.format(pad(preferred))) + color.cescape(f) color.cprint(line) color.cprint('') color.cprint(section_title('Safe versions: ')) for v in reversed(sorted(pkg.versions)): f = fs.for_package_version(pkg, v) line = version(' {0}'.format(pad(v))) + color.cescape(f) color.cprint(line) color.cprint('') color.cprint(section_title('Variants:')) formatter = VariantFormatter(pkg.variants) for line in formatter.lines: color.cprint(line) color.cprint('') color.cprint(section_title('Installation Phases:')) phase_str = '' for phase in pkg.phases: phase_str += " {0}".format(phase) color.cprint(phase_str) for deptype in ('build', 'link', 'run'): color.cprint('') color.cprint(section_title('%s Dependencies:' % deptype.capitalize())) deps = sorted(pkg.dependencies_of_type(deptype)) if deps: colify(deps, indent=4) else: color.cprint(' None') color.cprint('') color.cprint(section_title('Virtual Packages: ')) if pkg.provided: inverse_map = {} for spec, whens in pkg.provided.items(): for when in whens: if when not in inverse_map: inverse_map[when] = set() inverse_map[when].add(spec) for when, specs in reversed(sorted(inverse_map.items())): line = " %s provides %s" % ( when.colorized(), ', '.join(s.colorized() for s in specs) ) print(line) else: color.cprint(" None") color.cprint('')
def url_stats(args): # dictionary of issue type -> package -> descriptions issues = defaultdict(lambda: defaultdict(lambda: [])) class UrlStats(object): def __init__(self): self.total = 0 self.schemes = defaultdict(lambda: 0) self.checksums = defaultdict(lambda: 0) self.url_type = defaultdict(lambda: 0) self.git_type = defaultdict(lambda: 0) def add(self, pkg_name, fetcher): self.total += 1 url_type = fetcher.url_attr self.url_type[url_type or 'no code'] += 1 if url_type == 'url': digest = getattr(fetcher, 'digest', None) if digest: algo = crypto.hash_algo_for_digest(digest) else: algo = 'no checksum' self.checksums[algo] += 1 if algo == "md5": md5_hashes = issues["md5 hashes"] md5_hashes[pkg_name].append(fetcher.url) # parse out the URL scheme (https/http/ftp/etc.) urlinfo = urllib_parse.urlparse(fetcher.url) self.schemes[urlinfo.scheme] += 1 if urlinfo.scheme == "http": http_urls = issues["http urls"] http_urls[pkg_name].append(fetcher.url) elif url_type == 'git': if getattr(fetcher, 'commit', None): self.git_type['commit'] += 1 elif getattr(fetcher, 'branch', None): self.git_type['branch'] += 1 elif getattr(fetcher, 'tag', None): self.git_type['tag'] += 1 else: self.git_type['no ref'] += 1 npkgs = 0 version_stats = UrlStats() resource_stats = UrlStats() for pkg_cls in spack.repo.path.all_package_classes(): npkgs += 1 for v in pkg_cls.versions: try: pkg = pkg_cls(spack.spec.Spec(pkg_cls.name)) fetcher = fs.for_package_version(pkg, v) except (fs.InvalidArgsError, fs.FetcherConflict): continue version_stats.add(pkg_cls.name, fetcher) for _, resources in pkg_cls.resources.items(): for resource in resources: resource_stats.add(pkg_cls.name, resource.fetcher) # print a nice summary table tty.msg("URL stats for %d packages:" % npkgs) def print_line(): print("-" * 62) def print_stat(indent, name, stat_name=None): width = 20 - indent fmt = " " * indent fmt += "%%-%ds" % width if stat_name is None: print(fmt % name) else: fmt += "%12d%8.1f%%%12d%8.1f%%" v = getattr(version_stats, stat_name).get(name, 0) r = getattr(resource_stats, stat_name).get(name, 0) print(fmt % (name, v, v / version_stats.total * 100, r, r / resource_stats.total * 100)) print_line() print("%-20s%12s%9s%12s%9s" % ("stat", "versions", "%", "resources", "%")) print_line() print_stat(0, "url", "url_type") print_stat(4, "schemes") schemes = set(version_stats.schemes) | set(resource_stats.schemes) for scheme in schemes: print_stat(8, scheme, "schemes") print_stat(4, "checksums") checksums = set(version_stats.checksums) | set(resource_stats.checksums) for checksum in checksums: print_stat(8, checksum, "checksums") print_line() types = set(version_stats.url_type) | set(resource_stats.url_type) types -= set(["url", "git"]) for url_type in sorted(types): print_stat(0, url_type, "url_type") print_line() print_stat(0, "git", "url_type") git_types = set(version_stats.git_type) | set(resource_stats.git_type) for git_type in sorted(git_types): print_stat(4, git_type, "git_type") print_line() if args.show_issues: total_issues = sum( len(issues) for _, pkg_issues in issues.items() for _, issues in pkg_issues.items()) print() tty.msg("Found %d issues." % total_issues) for issue_type, pkgs in issues.items(): tty.msg("Package URLs with %s" % issue_type) for pkg_cls, pkg_issues in pkgs.items(): color.cprint(" @*C{%s}" % pkg_cls) for issue in pkg_issues: print(" %s" % issue)
def do_list(args, extra_args): """Print a lists of tests than what pytest offers.""" # Run test collection and get the tree out. old_output = sys.stdout try: sys.stdout = output = StringIO() pytest.main(['--collect-only'] + extra_args) finally: sys.stdout = old_output lines = output.getvalue().split('\n') tests = collections.defaultdict(lambda: set()) prefix = [] # collect tests into sections for line in lines: match = re.match(r"(\s*)<([^ ]*) '([^']*)'", line) if not match: continue indent, nodetype, name = match.groups() # strip parametrized tests if "[" in name: name = name[:name.index("[")] depth = len(indent) // 2 if nodetype.endswith("Function"): key = tuple(prefix) tests[key].add(name) else: prefix = prefix[:depth] prefix.append(name) 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)) if args.list == "list": files = set(prefix[0] for prefix in tests) color_files = [colorize("B", file) for file in sorted(files)] colify(color_files) elif args.list == "long": for prefix, functions in sorted(tests.items()): path = colorize("*B", prefix) + "::" functions = [colorize("c", f) for f in sorted(functions)] color.cprint(path) colify(functions, indent=4) print() else: # args.list == "names" all_functions = [ colorize("*B", prefix) + "::" + colorize("c", f) for prefix, functions in sorted(tests.items()) for f in sorted(functions) ] colify(all_functions)
def print_tool_result(tool, returncode): if returncode == 0: color.cprint(" @g{%s checks were clean}" % tool) else: color.cprint(" @r{%s found errors}" % tool)
def print_text_info(pkg): """Print out a plain text description of a package.""" 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) if len(pkg.maintainers) > 0: mnt = " ".join(['@@' + m for m in pkg.maintainers]) color.cprint('') color.cprint(section_title('Maintainers: ') + mnt) color.cprint('') color.cprint(section_title('Externally Detectable: ')) # If the package has an 'executables' field, it can detect an installation if hasattr(pkg, 'executables'): find_attributes = [] if hasattr(pkg, 'determine_version'): find_attributes.append('version') if hasattr(pkg, 'determine_variants'): find_attributes.append('variants') # If the package does not define 'determine_version' nor # 'determine_variants', then it must use some custom detection # mechanism. In this case, just inform the user it's detectable somehow. color.cprint(' True{0}'.format(' (' + ', '.join(find_attributes) + ')' if find_attributes else '')) else: color.cprint(' False') color.cprint('') color.cprint(section_title("Tags: ")) if hasattr(pkg, 'tags'): tags = sorted(pkg.tags) colify(tags, indent=4) else: color.cprint(" None") color.cprint('') color.cprint(section_title('Preferred version: ')) if not pkg.versions: color.cprint(version(' None')) color.cprint('') color.cprint(section_title('Safe versions: ')) color.cprint(version(' None')) color.cprint('') color.cprint(section_title('Deprecated versions: ')) color.cprint(version(' None')) else: pad = padder(pkg.versions, 4) preferred = preferred_version(pkg) url = '' if pkg.has_code: url = fs.for_package_version(pkg, preferred) line = version(' {0}'.format(pad(preferred))) + color.cescape(url) color.cprint(line) safe = [] deprecated = [] for v in reversed(sorted(pkg.versions)): if pkg.has_code: url = fs.for_package_version(pkg, v) if pkg.versions[v].get('deprecated', False): deprecated.append((v, url)) else: safe.append((v, url)) for title, vers in [('Safe', safe), ('Deprecated', deprecated)]: color.cprint('') color.cprint(section_title('{0} versions: '.format(title))) if not vers: color.cprint(version(' None')) continue for v, url in vers: line = version(' {0}'.format(pad(v))) + color.cescape(url) color.cprint(line) color.cprint('') color.cprint(section_title('Variants:')) formatter = VariantFormatter(pkg.variants) for line in formatter.lines: color.cprint(color.cescape(line)) if hasattr(pkg, 'phases') and pkg.phases: color.cprint('') color.cprint(section_title('Installation Phases:')) phase_str = '' for phase in pkg.phases: phase_str += " {0}".format(phase) color.cprint(phase_str) for deptype in ('build', 'link', 'run'): color.cprint('') color.cprint(section_title('%s Dependencies:' % deptype.capitalize())) deps = sorted(pkg.dependencies_of_type(deptype)) if deps: colify(deps, indent=4) else: color.cprint(' None') color.cprint('') color.cprint(section_title('Virtual Packages: ')) if pkg.provided: inverse_map = {} for spec, whens in pkg.provided.items(): for when in whens: if when not in inverse_map: inverse_map[when] = set() inverse_map[when].add(spec) for when, specs in reversed(sorted(inverse_map.items())): line = " %s provides %s" % (when.colorized(), ', '.join( s.colorized() for s in specs)) print(line) else: color.cprint(" None") color.cprint('')
def print_difference(c, attributes="all", out=None): """ Print the difference. Given a diffset for A and a diffset for B, print red/green diffs to show the differences. """ # Default to standard out unless another stream is provided out = out or sys.stdout A = c['b_not_a'] B = c['a_not_b'] cprint("@R{--- %s}" % c["a_name"]) # bright red cprint("@G{+++ %s}" % c["b_name"]) # bright green # Cut out early if we don't have any differences! if not A and not B: print("No differences\n") return def group_by_type(diffset): grouped = {} for entry in diffset: if entry[0] not in grouped: grouped[entry[0]] = [] grouped[entry[0]].append(entry[1]) # Sort by second value to make comparison slightly closer for key, values in grouped.items(): values.sort() return grouped A = group_by_type(A) B = group_by_type(B) # print a directionally relevant diff keys = list(A) + list(B) category = None for key in keys: if "all" not in attributes and key not in attributes: continue # Write the attribute, B is subtraction A is addition subtraction = [] if key not in B else B[key] addition = [] if key not in A else A[key] # Bail out early if we don't have any entries if not subtraction and not addition: continue # If we have a new category, create a new section if category != key: category = key # print category in bold, colorized cprint("@*b{@@ %s @@}" % category) # bold blue # Print subtractions first while subtraction: cprint("@R{- %s}" % subtraction.pop(0)) # bright red if addition: cprint("@G{+ %s}" % addition.pop(0)) # bright green # Any additions left? while addition: cprint("@G{+ %s}" % addition.pop(0))
def print_versions(pkg): """output versions""" color.cprint('') color.cprint(section_title('Preferred version: ')) if not pkg.versions: color.cprint(version(' None')) color.cprint('') color.cprint(section_title('Safe versions: ')) color.cprint(version(' None')) color.cprint('') color.cprint(section_title('Deprecated versions: ')) color.cprint(version(' None')) else: pad = padder(pkg.versions, 4) preferred = preferred_version(pkg) url = '' if pkg.has_code: url = fs.for_package_version(pkg, preferred) line = version(' {0}'.format(pad(preferred))) + color.cescape(url) color.cprint(line) safe = [] deprecated = [] for v in reversed(sorted(pkg.versions)): if pkg.has_code: url = fs.for_package_version(pkg, v) if pkg.versions[v].get('deprecated', False): deprecated.append((v, url)) else: safe.append((v, url)) for title, vers in [('Safe', safe), ('Deprecated', deprecated)]: color.cprint('') color.cprint(section_title('{0} versions: '.format(title))) if not vers: color.cprint(version(' None')) continue for v, url in vers: line = version(' {0}'.format(pad(v))) + color.cescape(url) color.cprint(line)
def print_tests(pkg): """output relevant build-time and stand-alone tests""" # Some built-in base packages (e.g., Autotools) define callback (e.g., # check) inherited by descendant packages. These checks may not result # in build-time testing if the package's build does not implement the # expected functionality (e.g., a 'check' or 'test' targets). # # So the presence of a callback in Spack does not necessarily correspond # to the actual presence of built-time tests for a package. for callbacks, phase in [(pkg.build_time_test_callbacks, 'Build'), (pkg.install_time_test_callbacks, 'Install')]: color.cprint('') color.cprint(section_title('Available {0} Phase Test Methods:' .format(phase))) names = [] if callbacks: for name in callbacks: if getattr(pkg, name, False): names.append(name) if names: colify(sorted(names), indent=4) else: color.cprint(' None') # PackageBase defines an empty install/smoke test but we want to know # if it has been overridden and, therefore, assumed to be implemented. color.cprint('') color.cprint(section_title('Stand-Alone/Smoke Test Methods:')) names = [] pkg_cls = pkg if inspect.isclass(pkg) else pkg.__class__ if has_test_method(pkg_cls): pkg_base = spack.package_base.PackageBase test_pkgs = [str(cls.test) for cls in inspect.getmro(pkg_cls) if issubclass(cls, pkg_base) and cls.test != pkg_base.test] test_pkgs = list(set(test_pkgs)) names.extend([(test.split()[1]).lower() for test in test_pkgs]) # TODO Refactor START # Use code from package_base.py's test_process IF this functionality is # accepted. v_names = list(set([vspec.name for vspec in pkg.virtuals_provided])) # hack for compilers that are not dependencies (yet) # TODO: this all eventually goes away c_names = ('gcc', 'intel', 'intel-parallel-studio', 'pgi') if pkg.name in c_names: v_names.extend(['c', 'cxx', 'fortran']) if pkg.spec.satisfies('llvm+clang'): v_names.extend(['c', 'cxx']) # TODO Refactor END v_specs = [spack.spec.Spec(v_name) for v_name in v_names] for v_spec in v_specs: try: pkg = v_spec.package pkg_cls = pkg if inspect.isclass(pkg) else pkg.__class__ if has_test_method(pkg_cls): names.append('{0}.test'.format(pkg.name.lower())) except spack.repo.UnknownPackageError: pass if names: colify(sorted(names), indent=4) else: color.cprint(' None')
def solve(parser, args): # these are the same options as `spack spec` name_fmt = '{namespace}.{name}' if args.namespaces else '{name}' fmt = '{@version}{%compiler}{compiler_flags}{variants}{arch=architecture}' install_status_fn = spack.spec.Spec.install_status kwargs = { 'cover': args.cover, 'format': name_fmt + fmt, 'hashlen': None if args.very_long else 7, 'show_types': args.types, 'status_fn': install_status_fn if args.install_status else None, 'hashes': args.long or args.very_long } # process dump options dump = re.split(r'\s*,\s*', args.show) if 'all' in dump: dump = show_options for d in dump: if d not in show_options: raise ValueError( "Invalid option for '--show': '%s'\nchoose from: (%s)" % (d, ', '.join(show_options + ('all', )))) models = args.models if models < 0: tty.die("model count must be non-negative: %d") specs = spack.cmd.parse_specs(args.specs) # dump generated ASP program result = asp.solve( specs, dump=dump, models=models, timers=args.timers, stats=args.stats, reuse=args.reuse, ) if 'solutions' not in dump: return # die if no solution was found result.raise_if_unsat() # dump the solutions as concretized specs if 'solutions' in dump: opt, _, _ = min(result.answers) if ("opt" in dump) and (not args.format): tty.msg("Best of %d considered solutions." % result.nmodels) tty.msg("Optimization Criteria:") maxlen = max(len(s[2]) for s in result.criteria) color.cprint("@*{ Priority Criterion %sInstalled ToBuild}" % ((maxlen - 10) * " ")) fmt = " @K{%%-8d} %%-%ds%%9s %%7s" % maxlen for i, (idx, build_idx, name) in enumerate(result.criteria, 1): color.cprint(fmt % ( i, name, "-" if build_idx is None else opt[idx], opt[idx] if build_idx is None else opt[build_idx], )) print() for spec in result.specs: # With -y, just print YAML to output. if args.format == 'yaml': # use write because to_yaml already has a newline. sys.stdout.write(spec.to_yaml(hash=ht.build_hash)) elif args.format == 'json': sys.stdout.write(spec.to_json(hash=ht.build_hash)) else: sys.stdout.write(spec.tree(color=sys.stdout.isatty(), **kwargs))
def info(parser, args): pkg = spack.repo.get(args.package) # 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('')
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] returncode = 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) # run tools in order defined in tool_order returncode = 0 for tool_name, tool_spec in tool_order: if getattr(args, tool_name): run_function, required = tools[tool_name] print_tool_header(tool_name) try: # Bootstrap tools so we don't need to require install with spack.bootstrap.ensure_bootstrap_configuration(): spec = spack.spec.Spec(tool_spec) cmd = None cmd = spack.bootstrap.get_executable(tool_name, spec=spec, install=True) if not cmd: color.cprint(" @y{%s not in PATH, skipped}" % tool_name) continue returncode |= run_function(cmd, file_list, args) except Exception as e: raise spack.error.SpackError( "Couldn't bootstrap %s:" % tool_name, str(e)) if returncode == 0: tty.msg(color.colorize("@*{spack style checks were clean}")) else: tty.error(color.colorize("@*{spack style found errors}")) return returncode