summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/spack/spack/cmd/solve.py14
-rw-r--r--lib/spack/spack/concretize.py11
-rw-r--r--lib/spack/spack/solver/asp.py110
-rw-r--r--lib/spack/spack/spec.py6
4 files changed, 95 insertions, 46 deletions
diff --git a/lib/spack/spack/cmd/solve.py b/lib/spack/spack/cmd/solve.py
index aaf631a1c5..b3207d7070 100644
--- a/lib/spack/spack/cmd/solve.py
+++ b/lib/spack/spack/cmd/solve.py
@@ -102,11 +102,15 @@ def solve(parser, args):
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,
- )
+ # set up solver parameters
+ solver = asp.Solver()
+ solver.reuse = args.reuse
+ solver.dump = dump
+ solver.models = models
+ solver.timers = args.timers
+ solver.stats = args.stats
+
+ result = solver.solve(specs)
if 'solutions' not in dump:
return
diff --git a/lib/spack/spack/concretize.py b/lib/spack/spack/concretize.py
index 35b4e82f30..de04fecffc 100644
--- a/lib/spack/spack/concretize.py
+++ b/lib/spack/spack/concretize.py
@@ -748,11 +748,12 @@ def concretize_specs_together(*abstract_specs, **kwargs):
def _concretize_specs_together_new(*abstract_specs, **kwargs):
import spack.solver.asp
- concretization_kwargs = {
- 'tests': kwargs.get('tests', False),
- 'reuse': kwargs.get('reuse', False)
- }
- result = spack.solver.asp.solve(abstract_specs, **concretization_kwargs)
+
+ solver = spack.solver.asp.Solver()
+ solver.tests = kwargs.get('tests', False)
+ solver.reuse = kwargs.get('reuse', False)
+
+ result = solver.solve(abstract_specs)
result.raise_if_unsat()
return [s.copy() for s in result.specs]
diff --git a/lib/spack/spack/solver/asp.py b/lib/spack/spack/solver/asp.py
index 6b656efba0..a87fa445f9 100644
--- a/lib/spack/spack/solver/asp.py
+++ b/lib/spack/spack/solver/asp.py
@@ -529,7 +529,7 @@ class PyclingoDriver(object):
def solve(
self, solver_setup, specs, dump=None, nmodels=0,
- timers=False, stats=False, tests=False, reuse=False,
+ timers=False, stats=False,
):
timer = spack.util.timer.Timer()
@@ -545,7 +545,7 @@ class PyclingoDriver(object):
self.assumptions = []
with self.control.backend() as backend:
self.backend = backend
- solver_setup.setup(self, specs, tests=tests, reuse=reuse)
+ solver_setup.setup(self, specs)
timer.phase("setup")
# read in the main ASP program and display logic -- these are
@@ -640,7 +640,7 @@ class PyclingoDriver(object):
class SpackSolverSetup(object):
"""Class to set up and run a Spack concretization solve."""
- def __init__(self):
+ def __init__(self, reuse=False, tests=False):
self.gen = None # set by setup()
self.declared_versions = {}
@@ -665,6 +665,12 @@ class SpackSolverSetup(object):
# Caches to optimize the setup phase of the solver
self.target_specs_cache = None
+ # whether to add installed/binary hashes to the solve
+ self.reuse = reuse
+
+ # whether to add installed/binary hashes to the solve
+ self.tests = tests
+
def pkg_version_rules(self, pkg):
"""Output declared versions of a package.
@@ -866,7 +872,7 @@ class SpackSolverSetup(object):
self.package_provider_rules(pkg)
# dependencies
- self.package_dependencies_rules(pkg, tests)
+ self.package_dependencies_rules(pkg)
# virtual preferences
self.virtual_preferences(
@@ -932,17 +938,17 @@ class SpackSolverSetup(object):
))
self.gen.newline()
- def package_dependencies_rules(self, pkg, tests):
+ def package_dependencies_rules(self, pkg):
"""Translate 'depends_on' directives into ASP logic."""
for _, conditions in sorted(pkg.dependencies.items()):
for cond, dep in sorted(conditions.items()):
deptypes = dep.type.copy()
# Skip test dependencies if they're not requested
- if not tests:
+ if not self.tests:
deptypes.discard("test")
# ... or if they are requested only for certain packages
- if not isinstance(tests, bool) and pkg.name not in tests:
+ if not isinstance(self.tests, bool) and pkg.name not in self.tests:
deptypes.discard("test")
# if there are no dependency types to be considered
@@ -1642,7 +1648,7 @@ class SpackSolverSetup(object):
# TODO: (or any mirror really) doesn't have binaries.
pass
- def setup(self, driver, specs, tests=False, reuse=False):
+ def setup(self, driver, specs):
"""Generate an ASP program with relevant constraints for specs.
This calls methods on the solve driver to set up the problem with
@@ -1689,7 +1695,7 @@ class SpackSolverSetup(object):
self.gen.h1("Concrete input spec definitions")
self.define_concrete_input_specs(specs, possible)
- if reuse:
+ if self.reuse:
self.gen.h1("Installed packages")
self.gen.fact(fn.optimize_for_reuse())
self.gen.newline()
@@ -1713,7 +1719,7 @@ class SpackSolverSetup(object):
self.gen.h1('Package Constraints')
for pkg in sorted(pkgs):
self.gen.h2('Package rules: %s' % pkg)
- self.pkg_rules(pkg, tests=tests)
+ self.pkg_rules(pkg, tests=self.tests)
self.gen.h2('Package preferences: %s' % pkg)
self.preferred_variants(pkg)
self.preferred_targets(pkg)
@@ -2016,33 +2022,67 @@ def _develop_specs_from_env(spec, env):
spec.constrain(dev_info['spec'])
-#
-# These are handwritten parts for the Spack ASP model.
-#
-def solve(specs, dump=(), models=0, timers=False, stats=False, tests=False,
- reuse=False):
- """Solve for a stable model of specs.
-
- Arguments:
- specs (list): list of Specs to solve.
- dump (tuple): what to dump
- models (int): number of models to search (default: 0)
+class Solver(object):
+ """This is the main external interface class for solving.
+
+ It manages solver configuration and preferences in once place. It sets up the solve
+ and passes the setup method to the driver, as well.
+
+ Properties of interest:
+
+ ``reuse (bool)``
+ Whether to try to reuse existing installs/binaries
+
+ ``show (tuple)``
+ What information to print to the console while running. Options are:
+ * asp: asp program text
+ * opt: optimization criteria for best model
+ * output: raw clingo output
+ * solutions: models found by asp program
+ * all: all of the above
+
+ ``models (int)``
+ Number of models to search (default: 0 for unlimited)
+
+ ``timers (bool)``
+ Print out coarse fimers for different solve phases.
+
+ ``stats (bool)``
+ Print out detailed stats from clingo
+
+ ``tests (bool or tuple)``
+ If ``True``, concretize test dependencies for all packages. If
+ a tuple of package names, concretize test dependencies for named
+ packages. If ``False``, do not concretize test dependencies.
+
"""
- driver = PyclingoDriver()
- if "asp" in dump:
- driver.out = sys.stdout
-
- # Check upfront that the variants are admissible
- for root in specs:
- for s in root.traverse():
- if s.virtual:
- continue
- spack.spec.Spec.ensure_valid_variants(s)
+ def __init__(self):
+ self.set_default_configuration()
+
+ def set_default_configuration(self):
+ self.reuse = False
+ self.dump = ()
+ self.models = 0
+ self.timers = False
+ self.stats = False
+ self.tests = False
+
+ def solve(self, specs):
+ driver = PyclingoDriver()
+ if "asp" in self.dump:
+ driver.out = sys.stdout
+
+ # Check upfront that the variants are admissible
+ for root in specs:
+ for s in root.traverse():
+ if s.virtual:
+ continue
+ spack.spec.Spec.ensure_valid_variants(s)
- setup = SpackSolverSetup()
- return driver.solve(
- setup, specs, dump, models, timers, stats, tests, reuse
- )
+ setup = SpackSolverSetup(reuse=self.reuse, tests=self.tests)
+ return driver.solve(
+ setup, specs, self.dump, self.models, self.timers, self.stats
+ )
class UnsatisfiableSpecError(spack.error.UnsatisfiableSpecError):
diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py
index 8b50b1fca3..4011bd10a7 100644
--- a/lib/spack/spack/spec.py
+++ b/lib/spack/spack/spec.py
@@ -2615,7 +2615,11 @@ class Spec(object):
if self._concrete:
return
- result = spack.solver.asp.solve([self], tests=tests, reuse=reuse)
+ solver = spack.solver.asp.Solver()
+ solver.reuse = reuse
+ solver.tests = tests
+
+ result = solver.solve([self])
result.raise_if_unsat()
# take the best answer