concretizer: handle virtual provider preferences from packages.yaml
This commit is contained in:
parent
36ec66d997
commit
b4e6d9d28e
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
import spack
|
import spack
|
||||||
import spack.cmd
|
import spack.cmd
|
||||||
|
import spack.config
|
||||||
import spack.spec
|
import spack.spec
|
||||||
import spack.package
|
import spack.package
|
||||||
import spack.package_prefs
|
import spack.package_prefs
|
||||||
@ -61,7 +62,14 @@ class AspObject(object):
|
|||||||
|
|
||||||
def _id(thing):
|
def _id(thing):
|
||||||
"""Quote string if needed for it to be a valid identifier."""
|
"""Quote string if needed for it to be a valid identifier."""
|
||||||
return thing if isinstance(thing, AspObject) else '"%s"' % str(thing)
|
if isinstance(thing, AspObject):
|
||||||
|
return thing
|
||||||
|
elif isinstance(thing, bool):
|
||||||
|
return '"%s"' % str(thing)
|
||||||
|
elif isinstance(thing, int):
|
||||||
|
return str(thing)
|
||||||
|
else:
|
||||||
|
return '"%s"' % str(thing)
|
||||||
|
|
||||||
|
|
||||||
class AspFunction(AspObject):
|
class AspFunction(AspObject):
|
||||||
@ -73,6 +81,10 @@ def __call__(self, *args):
|
|||||||
self.args[:] = args
|
self.args[:] = args
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
def __getitem___(self, *args):
|
||||||
|
self.args[:] = args
|
||||||
|
return self
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "%s(%s)" % (
|
return "%s(%s)" % (
|
||||||
self.name, ', '.join(_id(arg) for arg in self.args))
|
self.name, ', '.join(_id(arg) for arg in self.args))
|
||||||
@ -128,6 +140,7 @@ def __init__(self, out):
|
|||||||
self.out = out
|
self.out = out
|
||||||
self.func = AspFunctionBuilder()
|
self.func = AspFunctionBuilder()
|
||||||
self.possible_versions = {}
|
self.possible_versions = {}
|
||||||
|
self.possible_virtuals = None
|
||||||
|
|
||||||
def title(self, name, char):
|
def title(self, name, char):
|
||||||
self.out.write('\n')
|
self.out.write('\n')
|
||||||
@ -309,6 +322,33 @@ def pkg_rules(self, pkg):
|
|||||||
self._and(*self.spec_clauses(named_cond, body=True))
|
self._and(*self.spec_clauses(named_cond, body=True))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# virtual preferences
|
||||||
|
self.virtual_preferences(
|
||||||
|
pkg.name,
|
||||||
|
lambda v, p, i: self.fact(
|
||||||
|
fn.pkg_provider_preference(pkg.name, v, p, i)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def virtual_preferences(self, pkg_name, func):
|
||||||
|
"""Call func(vspec, provider, i) for each of pkg's provider prefs."""
|
||||||
|
config = spack.config.get("packages")
|
||||||
|
pkg_prefs = config.get(pkg_name, {}).get("providers", {})
|
||||||
|
for vspec, providers in pkg_prefs.items():
|
||||||
|
if vspec not in self.possible_virtuals:
|
||||||
|
continue
|
||||||
|
|
||||||
|
for i, provider in enumerate(providers):
|
||||||
|
func(vspec, provider, i)
|
||||||
|
|
||||||
|
def provider_defaults(self):
|
||||||
|
self.h2("Default virtual providers")
|
||||||
|
assert self.possible_virtuals is not None
|
||||||
|
self.virtual_preferences(
|
||||||
|
"all",
|
||||||
|
lambda v, p, i: self.fact(fn.default_provider_preference(v, p, i))
|
||||||
|
)
|
||||||
|
|
||||||
def spec_clauses(self, spec, body=False):
|
def spec_clauses(self, spec, body=False):
|
||||||
"""Return a list of clauses for a spec mandates are true.
|
"""Return a list of clauses for a spec mandates are true.
|
||||||
|
|
||||||
@ -358,6 +398,11 @@ class Body(object):
|
|||||||
|
|
||||||
# variants
|
# variants
|
||||||
for vname, variant in spec.variants.items():
|
for vname, variant in spec.variants.items():
|
||||||
|
value = variant.value
|
||||||
|
if isinstance(value, tuple):
|
||||||
|
for v in value:
|
||||||
|
clauses.append(f.variant(spec.name, vname, v))
|
||||||
|
else:
|
||||||
clauses.append(f.variant(spec.name, vname, variant.value))
|
clauses.append(f.variant(spec.name, vname, variant.value))
|
||||||
|
|
||||||
# compiler and compiler version
|
# compiler and compiler version
|
||||||
@ -397,9 +442,12 @@ def arch_defaults(self):
|
|||||||
self.fact(fn.arch_os_default(default_arch.os))
|
self.fact(fn.arch_os_default(default_arch.os))
|
||||||
self.fact(fn.arch_target_default(default_arch.target))
|
self.fact(fn.arch_target_default(default_arch.target))
|
||||||
|
|
||||||
def virtual_providers(self, virtuals):
|
def virtual_providers(self):
|
||||||
self.h2("Virtual providers")
|
self.h2("Virtual providers")
|
||||||
for vspec in virtuals:
|
assert self.possible_virtuals is not None
|
||||||
|
|
||||||
|
# what provides what
|
||||||
|
for vspec in self.possible_virtuals:
|
||||||
self.fact(fn.virtual(vspec))
|
self.fact(fn.virtual(vspec))
|
||||||
for provider in spack.repo.path.providers_for(vspec):
|
for provider in spack.repo.path.providers_for(vspec):
|
||||||
# TODO: handle versioned virtuals
|
# TODO: handle versioned virtuals
|
||||||
@ -417,10 +465,12 @@ def generate_asp_program(self, specs):
|
|||||||
pkg_names = set(spec.fullname for spec in specs)
|
pkg_names = set(spec.fullname for spec in specs)
|
||||||
|
|
||||||
possible = set()
|
possible = set()
|
||||||
virtuals = set()
|
self.possible_virtuals = set()
|
||||||
for name in pkg_names:
|
for name in pkg_names:
|
||||||
pkg = spack.repo.path.get_pkg_class(name)
|
pkg = spack.repo.path.get_pkg_class(name)
|
||||||
possible.update(pkg.possible_dependencies(virtuals=virtuals))
|
possible.update(
|
||||||
|
pkg.possible_dependencies(virtuals=self.possible_virtuals)
|
||||||
|
)
|
||||||
|
|
||||||
pkgs = set(possible) | set(pkg_names)
|
pkgs = set(possible) | set(pkg_names)
|
||||||
|
|
||||||
@ -433,7 +483,8 @@ def generate_asp_program(self, specs):
|
|||||||
self.h1('General Constraints')
|
self.h1('General Constraints')
|
||||||
self.compiler_defaults()
|
self.compiler_defaults()
|
||||||
self.arch_defaults()
|
self.arch_defaults()
|
||||||
self.virtual_providers(virtuals)
|
self.virtual_providers()
|
||||||
|
self.provider_defaults()
|
||||||
|
|
||||||
self.h1('Package Constraints')
|
self.h1('Package Constraints')
|
||||||
for pkg in pkgs:
|
for pkg in pkgs:
|
||||||
|
@ -28,12 +28,30 @@ depends_on(P, D) :- declared_dependency(P, D), not virtual(D), node(P).
|
|||||||
provider(P, V) :- node(P), provides_virtual(P, V).
|
provider(P, V) :- node(P), provides_virtual(P, V).
|
||||||
1 { provider(P, V) : node(P) } 1 :- virtual(V).
|
1 { provider(P, V) : node(P) } 1 :- virtual(V).
|
||||||
|
|
||||||
|
% give dependents the virtuals they want
|
||||||
|
provider_weight(D, N)
|
||||||
|
:- virtual(V), depends_on(P, D), provider(D, V),
|
||||||
|
pkg_provider_preference(P, V, D, N).
|
||||||
|
provider_weight(D, N)
|
||||||
|
:- virtual(V), depends_on(P, D), provider(D, V),
|
||||||
|
not pkg_provider_preference(P, V, D, _),
|
||||||
|
default_provider_preference(V, D, N).
|
||||||
|
|
||||||
|
% if there's no preference for something, it costs 100 to discourage its
|
||||||
|
% use with minimization
|
||||||
|
provider_weight(D, 100)
|
||||||
|
:- virtual(V), depends_on(P, D), provider(D, V),
|
||||||
|
not pkg_provider_preference(P, V, D, _),
|
||||||
|
not default_provider_preference(V, D, _).
|
||||||
|
|
||||||
|
% pick most preferred virtual providers
|
||||||
|
#minimize{ N@2,D : provider_weight(D, N) }.
|
||||||
|
|
||||||
% all nodes must be reachable from some root
|
% all nodes must be reachable from some root
|
||||||
% TODO: this doesn't seem to be working yet
|
needed(D) :- root(D), node(D).
|
||||||
needed(D) :- depends_on(_, D), node(D).
|
needed(D) :- root(P), depends_on(P, D).
|
||||||
needed(P) :- root(P).
|
needed(D) :- needed(P), depends_on(P, D), node(P).
|
||||||
:- node(P), not needed(P).
|
:- node(P), not needed(P).
|
||||||
#defined root/1.
|
|
||||||
|
|
||||||
% real dependencies imply new nodes.
|
% real dependencies imply new nodes.
|
||||||
node(D) :- node(P), depends_on(P, D).
|
node(D) :- node(P), depends_on(P, D).
|
||||||
@ -43,6 +61,9 @@ node(D) :- node(P), depends_on(P, D).
|
|||||||
#defined declared_dependency/2.
|
#defined declared_dependency/2.
|
||||||
#defined virtual/1.
|
#defined virtual/1.
|
||||||
#defined provides_virtual/2.
|
#defined provides_virtual/2.
|
||||||
|
#defined pkg_provider_preference/4.
|
||||||
|
#defined default_provider_preference/3.
|
||||||
|
#defined root/1.
|
||||||
|
|
||||||
%-----------------------------------------------------------------------------
|
%-----------------------------------------------------------------------------
|
||||||
% Variant semantics
|
% Variant semantics
|
||||||
|
Loading…
Reference in New Issue
Block a user