concretizer: added support for versioned virtual specs

This commit is contained in:
Massimiliano Culpo 2020-09-30 17:27:19 +02:00 committed by Todd Gamblin
parent 48eb50921a
commit 28afdb9530
2 changed files with 96 additions and 29 deletions

View File

@ -467,13 +467,19 @@ def _register_rule_for_cores(self, rule_str):
def fact(self, head):
"""ASP fact (a rule without a body)."""
sym = head.symbol()
self.out.write("%s.\n" % sym)
symbols = _normalize(head)
self.out.write("%s.\n" % ','.join(str(a) for a in symbols))
atom = self.backend.add_atom(sym)
self.backend.add_rule([atom], [], choice=self.cores)
atoms = {}
for s in symbols:
atoms[s] = self.backend.add_atom(s)
self.backend.add_rule(
[atoms[s] for s in symbols], [], choice=self.cores
)
if self.cores:
self.assumptions.append(atom)
for s in symbols:
self.assumptions.append(atoms[s])
def rule(self, head, body):
"""ASP rule (an implication)."""
@ -651,6 +657,8 @@ def __init__(self):
self.possible_virtuals = None
self.possible_compilers = []
self.version_constraints = set()
self.providers_by_vspec_name = collections.defaultdict(list)
self.virtual_constraints = set()
self.compiler_version_constraints = set()
self.post_facts = []
@ -838,21 +846,31 @@ def pkg_rules(self, pkg):
self.package_compiler_defaults(pkg)
# dependencies
self.package_dependencies_rules(pkg)
# virtual preferences
self.virtual_preferences(
pkg.name,
lambda v, p, i: self.gen.fact(
fn.pkg_provider_preference(pkg.name, v, p, i)
)
)
def package_dependencies_rules(self, pkg):
"""Translate 'depends_on' directives into ASP logic."""
for name, conditions in sorted(pkg.dependencies.items()):
for cond, dep in sorted(conditions.items()):
named_cond = cond.copy()
if not named_cond.name:
named_cond.name = pkg.name
named_cond.name = named_cond.name or pkg.name
if cond == spack.spec.Spec():
for t in sorted(dep.type):
for t in sorted(dep.type):
if cond == spack.spec.Spec():
self.gen.fact(
fn.declared_dependency(
dep.pkg.name, dep.spec.name, t
)
)
else:
for t in sorted(dep.type):
else:
self.gen.rule(
fn.declared_dependency(
dep.pkg.name, dep.spec.name, t
@ -863,27 +881,28 @@ def pkg_rules(self, pkg):
)
# add constraints on the dependency from dep spec.
clauses = self.spec_clauses(dep.spec)
if spack.repo.path.is_virtual(dep.spec.name):
clauses = []
for clause in clauses:
self.virtual_constraints.add(str(dep.spec))
self.gen.rule(
clause,
self.gen._and(
fn.depends_on(dep.pkg.name, dep.spec.name),
head=fn.single_provider_for(
str(dep.spec.name), str(dep.spec.versions)
),
body=self.gen._and(
*self.spec_clauses(named_cond, body=True)
)
)
else:
clauses = self.spec_clauses(dep.spec)
for clause in clauses:
self.gen.rule(
clause,
self.gen._and(
fn.depends_on(dep.pkg.name, dep.spec.name),
*self.spec_clauses(named_cond, body=True)
)
)
self.gen.newline()
# virtual preferences
self.virtual_preferences(
pkg.name,
lambda v, p, i: self.gen.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")
@ -1191,9 +1210,19 @@ def virtual_providers(self):
# what provides what
for vspec in sorted(self.possible_virtuals):
self.gen.fact(fn.virtual(vspec))
for provider in sorted(spack.repo.path.providers_for(vspec)):
# TODO: handle versioned and conditional virtuals
all_providers = sorted(spack.repo.path.providers_for(vspec))
for idx, provider in enumerate(all_providers):
self.gen.fact(fn.provides_virtual(provider.name, vspec))
possible_provider_fn = fn.possible_provider(
vspec, provider.name, idx
)
item = (idx, provider, possible_provider_fn)
self.providers_by_vspec_name[vspec].append(item)
clauses = self.spec_clauses(provider, body=True)
for clause in clauses:
self.gen.rule(clause, possible_provider_fn)
self.gen.newline()
self.gen.newline()
def generate_possible_compilers(self, specs):
compilers = compilers_for_default_arch()
@ -1240,6 +1269,27 @@ def define_version_constraints(self):
)
self.gen.newline()
def define_virtual_constraints(self):
for vspec_str in sorted(self.virtual_constraints):
vspec = spack.spec.Spec(vspec_str)
self.gen.h2("Virtual spec: {0}".format(vspec_str))
providers = spack.repo.path.providers_for(vspec_str)
candidates = self.providers_by_vspec_name[vspec.name]
possible_providers = [
func for idx, spec, func in candidates if spec in providers
]
self.gen.newline()
single_provider_for = fn.single_provider_for(
vspec.name, vspec.versions
)
one_of_the_possibles = self.gen.one_of(*possible_providers)
single_provider_rule = "{0} :- {1}.\n{1} :- {0}.\n".format(
single_provider_for, str(one_of_the_possibles)
)
self.gen.out.write(single_provider_rule)
self.gen.control.add("base", [], single_provider_rule)
def define_compiler_version_constraints(self):
compiler_list = spack.compilers.all_compiler_specs()
compiler_list = list(sorted(set(compiler_list)))
@ -1318,17 +1368,30 @@ def setup(self, driver, specs):
self.gen.h2('Spec: %s' % str(dep))
if dep.virtual:
self.gen.fact(fn.virtual_node(dep.name))
for clause in self.virtual_spec_clauses(dep):
self.gen.fact(clause)
else:
for clause in self.spec_clauses(dep):
self.gen.fact(clause)
self.gen.h1("Virtual Constraints")
self.define_virtual_constraints()
self.gen.h1("Version Constraints")
self.define_version_constraints()
self.gen.h1("Compiler Version Constraints")
self.define_compiler_version_constraints()
def virtual_spec_clauses(self, dep):
assert dep.virtual
self.virtual_constraints.add(str(dep))
clauses = [
fn.virtual_node(dep.name),
fn.single_provider_for(str(dep.name), str(dep.versions))
]
return clauses
class SpecBuilder(object):
"""Class with actions to rebuild a spec from ASP results."""

View File

@ -113,7 +113,11 @@ external(Package) :- external_only(Package), node(Package).
% if an external version is selected, the package is external and
% we are using the corresponding spec
external(Package), external_spec(Package, ID) :-
external(Package) :-
version(Package, Version), version_weight(Package, Weight),
external_version_declared(Package, Version, Weight, ID).
external_spec(Package, ID) :-
version(Package, Version), version_weight(Package, Weight),
external_version_declared(Package, Version, Weight, ID).