Source code for spack.cmd.solve

# Copyright 2013-2022 Lawrence Livermore National Security, LLC and other
# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)

from __future__ import print_function

import argparse
import re
import sys

import llnl.util.tty as tty
import llnl.util.tty.color as color

import spack
import spack.cmd
import spack.cmd.common.arguments as arguments
import spack.config
import spack.environment
import spack.hash_types as ht
import spack.package
import spack.solver.asp as asp

description = "concretize a specs using an ASP solver"
section = 'developer'
level = 'long'

#: output options
show_options = ('asp', 'opt', 'output', 'solutions')


[docs]def setup_parser(subparser): # Solver arguments subparser.add_argument( '--show', action='store', default='opt,solutions', help="select outputs: comma-separated list of: \n" " asp asp program text\n" " opt optimization criteria for best model\n" " output raw clingo output\n" " solutions models found by asp program\n" " all all of the above" ) subparser.add_argument( '--models', action='store', type=int, default=0, help="number of solutions to search (default 0 for all)") # Below are arguments w.r.t. spec display (like spack spec) arguments.add_common_arguments( subparser, ['long', 'very_long', 'install_status'] ) subparser.add_argument( '-y', '--yaml', action='store_const', dest='format', default=None, const='yaml', help='print concrete spec as yaml') subparser.add_argument( '-j', '--json', action='store_const', dest='format', default=None, const='json', help='print concrete spec as json') subparser.add_argument( '-c', '--cover', action='store', default='nodes', choices=['nodes', 'edges', 'paths'], help='how extensively to traverse the DAG (default: nodes)') subparser.add_argument( '-N', '--namespaces', action='store_true', default=False, help='show fully qualified package names') subparser.add_argument( '-t', '--types', action='store_true', default=False, help='show dependency types') subparser.add_argument( '--timers', action='store_true', default=False, help='print out timers for different solve phases') subparser.add_argument( '--stats', action='store_true', default=False, help='print out statistics from clingo') subparser.add_argument( 'specs', nargs=argparse.REMAINDER, help="specs of packages") spack.cmd.common.arguments.add_concretizer_args(subparser)
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()
[docs]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 output options show = re.split(r'\s*,\s*', args.show) if 'all' in show: show = show_options for d in show: 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") # Format required for the output (JSON, YAML or None) required_format = args.format # If we have an active environment, pick the specs from there env = spack.environment.active_environment() if env and args.specs: msg = "cannot give explicit specs when an environment is active" raise RuntimeError(msg) specs = list(env.user_specs) if env else spack.cmd.parse_specs(args.specs) solver = asp.Solver() output = sys.stdout if "asp" in show else None setup_only = set(show) == {'asp'} unify = spack.config.get('concretizer:unify') if unify != 'when_possible': # set up solver parameters # Note: reuse and other concretizer prefs are passed as configuration result = solver.solve( specs, out=output, models=models, timers=args.timers, stats=args.stats, setup_only=setup_only ) if not setup_only: _process_result(result, show, required_format, kwargs) else: for idx, result in enumerate(solver.solve_in_rounds( specs, out=output, models=models, timers=args.timers, stats=args.stats )): if "solutions" in show: tty.msg("ROUND {0}".format(idx)) tty.msg("") else: print("% END ROUND {0}\n".format(idx)) if not setup_only: _process_result(result, show, required_format, kwargs)