diff --git a/lib/spack/spack/solver/asp.py b/lib/spack/spack/solver/asp.py index e449b944ce..fe01be1bcf 100644 --- a/lib/spack/spack/solver/asp.py +++ b/lib/spack/spack/solver/asp.py @@ -302,6 +302,8 @@ def argify(arg): return clingo.String(str(arg)) elif isinstance(arg, int): return clingo.Number(arg) + elif isinstance(arg, AspFunction): + return clingo.Function(arg.name, [argify(x) for x in arg.args], positive=positive) else: return clingo.String(str(arg)) @@ -918,16 +920,20 @@ def key_fn(version): ) for weight, declared_version in enumerate(most_to_least_preferred): + # TODO: self.package_fact(pkg.name).version_declared(declared_version, weight=weight) self.gen.fact( - fn.version_declared( - pkg.name, declared_version.version, weight, str(declared_version.origin) + fn.facts( + pkg.name, + fn.version_declared( + declared_version.version, weight, str(declared_version.origin) + ), ) ) # Declare deprecated versions for this package, if any deprecated = self.deprecated_versions[pkg.name] for v in sorted(deprecated): - self.gen.fact(fn.deprecated_version(pkg.name, v)) + self.gen.fact(fn.facts(pkg.name, fn.deprecated_version(v))) def spec_versions(self, spec): """Return list of clauses expressing spec's version constraints.""" @@ -970,7 +976,9 @@ def conflict_rules(self, pkg): conflict_msg = default_msg.format(pkg.name, trigger, constraint) constraint_msg = "conflict constraint %s" % str(constraint) constraint_id = self.condition(constraint, name=pkg.name, msg=constraint_msg) - self.gen.fact(fn.conflict(pkg.name, trigger_id, constraint_id, conflict_msg)) + self.gen.fact( + fn.facts(pkg.name, fn.conflict(trigger_id, constraint_id, conflict_msg)) + ) self.gen.newline() def compiler_facts(self): @@ -1023,8 +1031,11 @@ def package_compiler_defaults(self, pkg): for i, compiler in enumerate(reversed(matches)): self.gen.fact( - fn.node_compiler_preference( - pkg.name, compiler.spec.name, compiler.spec.version, -i * 100 + fn.facts( + pkg.name, + fn.node_compiler_preference( + compiler.spec.name, compiler.spec.version, -i * 100 + ), ) ) @@ -1119,7 +1130,7 @@ def pkg_rules(self, pkg, tests): if spack.spec.Spec() in when: # unconditional variant - self.gen.fact(fn.variant(pkg.name, name)) + self.gen.fact(fn.facts(pkg.name, fn.variant(name))) else: # conditional variant for w in when: @@ -1128,19 +1139,23 @@ def pkg_rules(self, pkg, tests): msg += " when %s" % w cond_id = self.condition(w, name=pkg.name, msg=msg) - self.gen.fact(fn.variant_condition(cond_id, pkg.name, name)) + self.gen.fact(fn.facts(pkg.name, fn.conditional_variant(cond_id, name))) single_value = not variant.multi if single_value: - self.gen.fact(fn.variant_single_value(pkg.name, name)) + self.gen.fact(fn.facts(pkg.name, fn.variant_single_value(name))) self.gen.fact( - fn.variant_default_value_from_package_py(pkg.name, name, variant.default) + fn.facts( + pkg.name, fn.variant_default_value_from_package_py(name, variant.default) + ) ) else: spec_variant = variant.make_default() defaults = spec_variant.value for val in sorted(defaults): - self.gen.fact(fn.variant_default_value_from_package_py(pkg.name, name, val)) + self.gen.fact( + fn.facts(pkg.name, fn.variant_default_value_from_package_py(name, val)) + ) values = variant.values if values is None: @@ -1151,7 +1166,9 @@ def pkg_rules(self, pkg, tests): for sid, s in enumerate(values.sets): for value in s: self.gen.fact( - fn.variant_value_from_disjoint_sets(pkg.name, name, value, sid) + fn.facts( + pkg.name, fn.variant_value_from_disjoint_sets(name, value, sid) + ) ) union.update(s) values = union @@ -1178,7 +1195,9 @@ def pkg_rules(self, pkg, tests): msg="empty (total) conflict constraint", ) msg = "variant {0}={1} is conditionally disabled".format(name, value) - self.gen.fact(fn.conflict(pkg.name, trigger_id, constraint_id, msg)) + self.gen.fact( + fn.facts(pkg.name, fn.conflict(trigger_id, constraint_id, msg)) + ) else: imposed = spack.spec.Spec(value.when) imposed.name = pkg.name @@ -1189,10 +1208,10 @@ def pkg_rules(self, pkg, tests): name=pkg.name, msg="%s variant %s value %s when %s" % (pkg.name, name, value, when), ) - self.gen.fact(fn.variant_possible_value(pkg.name, name, value)) + self.gen.fact(fn.facts(pkg.name, fn.variant_possible_value(name, value))) if variant.sticky: - self.gen.fact(fn.variant_sticky(pkg.name, name)) + self.gen.fact(fn.facts(pkg.name, fn.variant_sticky(name))) self.gen.newline() @@ -1210,7 +1229,8 @@ def pkg_rules(self, pkg, tests): # virtual preferences self.virtual_preferences( - pkg.name, lambda v, p, i: self.gen.fact(fn.pkg_provider_preference(pkg.name, v, p, i)) + pkg.name, + lambda v, p, i: self.gen.fact(fn.facts(pkg.name, fn.provider_preference(v, p, i))), ) self.package_requirement_rules(pkg) @@ -1232,7 +1252,7 @@ def condition(self, required_spec, imposed_spec=None, name=None, msg=None, node= """ named_cond = required_spec.copy() named_cond.name = named_cond.name or name - assert named_cond.name, "must provide name for anonymous condtions!" + assert named_cond.name, "must provide name for anonymous conditions!" # Check if we can emit the requirements before updating the condition ID counter. # In this way, if a condition can't be emitted but the exception is handled in the caller, @@ -1240,7 +1260,8 @@ def condition(self, required_spec, imposed_spec=None, name=None, msg=None, node= requirements = self.spec_clauses(named_cond, body=True, required_from=name) condition_id = next(self._condition_id_counter) - self.gen.fact(fn.condition(condition_id, msg)) + self.gen.fact(fn.facts(named_cond.name, fn.condition(condition_id))) + self.gen.fact(fn.condition_reason(condition_id, msg)) for pred in requirements: self.gen.fact(fn.condition_requirement(condition_id, *pred.args)) @@ -1259,13 +1280,15 @@ def impose(self, condition_id, imposed_spec, node=True, name=None, body=False): def package_provider_rules(self, pkg): for provider_name in sorted(set(s.name for s in pkg.provided.keys())): - self.gen.fact(fn.possible_provider(pkg.name, provider_name)) + self.gen.fact(fn.facts(pkg.name, fn.possible_provider(provider_name))) for provided, whens in pkg.provided.items(): for when in whens: msg = "%s provides %s when %s" % (pkg.name, provided, when) condition_id = self.condition(when, provided, pkg.name, msg) - self.gen.fact(fn.provider_condition(condition_id, when.name, provided.name)) + self.gen.fact( + fn.facts(when.name, fn.provider_condition(condition_id, provided.name)) + ) self.gen.newline() def package_dependencies_rules(self, pkg): @@ -1291,7 +1314,9 @@ def package_dependencies_rules(self, pkg): msg += " when %s" % cond condition_id = self.condition(cond, dep.spec, pkg.name, msg) - self.gen.fact(fn.dependency_condition(condition_id, pkg.name, dep.spec.name)) + self.gen.fact( + fn.facts(pkg.name, fn.dependency_condition(condition_id, dep.spec.name)) + ) for t in sorted(deptypes): # there is a declared dependency of type t @@ -1449,7 +1474,7 @@ def external_packages(self): for local_idx, spec in enumerate(external_specs): msg = "%s available as external when satisfying %s" % (spec.name, spec) condition_id = self.condition(spec, msg=msg) - self.gen.fact(fn.possible_external(condition_id, pkg_name, local_idx)) + self.gen.fact(fn.facts(pkg_name, fn.possible_external(condition_id, local_idx))) self.possible_versions[spec.name].add(spec.version) self.gen.newline() @@ -1495,7 +1520,9 @@ def target_preferences(self, pkg_name): if str(preferred.architecture.target) == best_default and i != 0: offset = 100 self.gen.fact( - fn.target_weight(pkg_name, str(preferred.architecture.target), i + offset) + fn.facts( + pkg_name, fn.target_weight(str(preferred.architecture.target), i + offset) + ) ) def spec_clauses(self, *args, **kwargs): @@ -2041,11 +2068,11 @@ def define_version_constraints(self): # generate facts for each package constraint and the version # that satisfies it for v in sorted(v for v in self.possible_versions[pkg_name] if v.satisfies(versions)): - self.gen.fact(fn.version_satisfies(pkg_name, versions, v)) + self.gen.fact(fn.facts(pkg_name, fn.version_satisfies(versions, v))) self.gen.newline() - def define_virtual_constraints(self): + def collect_virtual_constraints(self): """Define versions for constraints on virtuals. Must be called before define_version_constraints(). @@ -2131,7 +2158,7 @@ def define_variant_values(self): # spec_clauses(). We might want to order these facts by pkg and name # if we are debugging. for pkg, variant, value in self.variant_values_from_specs: - self.gen.fact(fn.variant_possible_value(pkg, variant, value)) + self.gen.fact(fn.facts(pkg, fn.variant_possible_value(variant, value))) def _facts_from_concrete_spec(self, spec, possible): # tell the solver about any installed packages that could @@ -2280,10 +2307,8 @@ def setup(self, driver, specs, reuse=None): self.gen.h1("Variant Values defined in specs") self.define_variant_values() - self.gen.h1("Virtual Constraints") - self.define_virtual_constraints() - self.gen.h1("Version Constraints") + self.collect_virtual_constraints() self.define_version_constraints() self.gen.h1("Compiler Version Constraints") diff --git a/lib/spack/spack/solver/concretize.lp b/lib/spack/spack/solver/concretize.lp index f90aa872f8..7cf01e98b0 100644 --- a/lib/spack/spack/solver/concretize.lp +++ b/lib/spack/spack/solver/concretize.lp @@ -64,23 +64,23 @@ error(100, multiple_values_error, Attribute, Package) % Versions are declared with a weight and an origin, which indicates where the % version was declared (e.g. "package_py" or "external"). -version_declared(Package, Version, Weight) :- version_declared(Package, Version, Weight, _). +facts(Package, version_declared(Version, Weight)) :- facts(Package, version_declared(Version, Weight, _)). % We can't emit the same version **with the same weight** from two different sources -:- version_declared(Package, Version, Weight, Origin1), - version_declared(Package, Version, Weight, Origin2), +:- facts(Package, version_declared(Version, Weight, Origin1)), + facts(Package, version_declared(Version, Weight, Origin2)), Origin1 < Origin2, internal_error("Two versions with identical weights"). % We cannot use a version declared for an installed package if we end up building it -:- version_declared(Package, Version, Weight, "installed"), +:- facts(Package, version_declared(Version, Weight, "installed")), attr("version", Package, Version), version_weight(Package, Weight), not attr("hash", Package, _), internal_error("Reuse version weight used for built package"). % versions are declared w/priority -- declared with priority implies declared -version_declared(Package, Version) :- version_declared(Package, Version, _). +facts(Package, version_declared(Version)) :- facts(Package, version_declared(Version, _)). % a spec with a git hash version is equivalent to one with the same matched version version_satisfies(Package, Constraint, HashVersion) :- version_satisfies(Package, Constraint, EquivalentVersion), @@ -93,7 +93,7 @@ version_satisfies(Package, Constraint, HashVersion) :- version_satisfies(Package % is not precisely one version chosen. Error facts are heavily optimized % against to ensure they cannot be inferred when a non-error solution is % possible -{ attr("version", Package, Version) : version_declared(Package, Version) } +{ attr("version", Package, Version) : facts(Package, version_declared(Version)) } :- attr("node", Package). % A virtual package may or may not have a version, but never has more than one @@ -104,17 +104,17 @@ error(100, "Cannot select a single version for virtual '{0}'", Virtual) % If we select a deprecated version, mark the package as deprecated attr("deprecated", Package, Version) :- attr("version", Package, Version), - deprecated_version(Package, Version). + facts(Package, deprecated_version(Version)). possible_version_weight(Package, Weight) :- attr("version", Package, Version), - version_declared(Package, Version, Weight). + facts(Package, version_declared(Version, Weight)). % we can't use the weight for an external version if we don't use the % corresponding external spec. :- attr("version", Package, Version), version_weight(Package, Weight), - version_declared(Package, Version, Weight, "external"), + facts(Package, version_declared(Version, Weight, "external")), not external(Package), internal_error("External weight used for built package"). @@ -122,17 +122,17 @@ possible_version_weight(Package, Weight) % and vice-versa :- attr("version", Package, Version), version_weight(Package, Weight), - version_declared(Package, Version, Weight, "installed"), + facts(Package, version_declared(Version, Weight, "installed")), build(Package), internal_error("Reuse version weight used for build package"). :- attr("version", Package, Version), version_weight(Package, Weight), - not version_declared(Package, Version, Weight, "installed"), + not facts(Package, version_declared(Version, Weight, "installed")), not build(Package), internal_error("Build version weight used for reused package"). -1 { version_weight(Package, Weight) : version_declared(Package, Version, Weight) } 1 +1 { version_weight(Package, Weight) : facts(Package, version_declared(Version, Weight)) } 1 :- attr("version", Package, Version), attr("node", Package). @@ -141,24 +141,24 @@ possible_version_weight(Package, Weight) % While this choice rule appears redundant with the initial choice rule for % versions, virtual nodes with version constraints require this rule to be % able to choose versions -{ attr("version", Package, Version) : version_satisfies(Package, Constraint, Version) } +{ attr("version", Package, Version) : facts(Package, version_satisfies(Constraint, Version)) } :- attr("node_version_satisfies", Package, Constraint). % If there is at least a version that satisfy the constraint, impose a lower % bound on the choice rule to avoid false positives with the error below -1 { attr("version", Package, Version) : version_satisfies(Package, Constraint, Version) } +1 { attr("version", Package, Version) : facts(Package, version_satisfies(Constraint, Version)) } :- attr("node_version_satisfies", Package, Constraint), - version_satisfies(Package, Constraint, _). + facts(Package, version_satisfies(Constraint, _)). % More specific error message if the version cannot satisfy some constraint % Otherwise covered by `no_version_error` and `versions_conflict_error`. error(10, "Cannot satisfy '{0}@{1}'", Package, Constraint) :- attr("node_version_satisfies", Package, Constraint), attr("version", Package, Version), - not version_satisfies(Package, Constraint, Version). + not facts(Package, version_satisfies(Constraint, Version)). attr("node_version_satisfies", Package, Constraint) - :- attr("version", Package, Version), version_satisfies(Package, Constraint, Version). + :- attr("version", Package, Version), facts(Package, version_satisfies(Constraint, Version)). #defined version_satisfies/3. #defined deprecated_version/2. @@ -175,22 +175,22 @@ attr("node_version_satisfies", Package, Constraint) %----------------------------------------------------------------------------- % conditions are specified with `condition_requirement` and hold when % corresponding spec attributes hold. -condition_holds(ID) :- - condition(ID, _); +condition_holds(ID, Package) :- + facts(Package, condition(ID)); attr(Name, A1) : condition_requirement(ID, Name, A1); attr(Name, A1, A2) : condition_requirement(ID, Name, A1, A2); attr(Name, A1, A2, A3) : condition_requirement(ID, Name, A1, A2, A3); attr(Name, A1, A2, A3, A4) : condition_requirement(ID, Name, A1, A2, A3, A4). -% condition_holds(ID) implies all imposed_constraints, unless do_not_impose(ID) +% condition_holds(ID, Package) implies all imposed_constraints, unless do_not_impose(ID, Package) % is derived. This allows imposed constraints to be canceled in special cases. -impose(ID) :- condition_holds(ID), not do_not_impose(ID). +impose(ID, Package) :- condition_holds(ID, Package), not do_not_impose(ID, Package). % conditions that hold impose constraints on other specs -attr(Name, A1) :- impose(ID), imposed_constraint(ID, Name, A1). -attr(Name, A1, A2) :- impose(ID), imposed_constraint(ID, Name, A1, A2). -attr(Name, A1, A2, A3) :- impose(ID), imposed_constraint(ID, Name, A1, A2, A3). -attr(Name, A1, A2, A3, A4) :- impose(ID), imposed_constraint(ID, Name, A1, A2, A3, A4). +attr(Name, A1) :- impose(ID, Package), imposed_constraint(ID, Name, A1). +attr(Name, A1, A2) :- impose(ID, Package), imposed_constraint(ID, Name, A1, A2). +attr(Name, A1, A2, A3) :- impose(ID, Package), imposed_constraint(ID, Name, A1, A2, A3). +attr(Name, A1, A2, A3, A4) :- impose(ID, Package), imposed_constraint(ID, Name, A1, A2, A3, A4). % we cannot have additional variant values when we are working with concrete specs :- attr("node", Package), attr("hash", Package, Hash), @@ -231,17 +231,17 @@ depends_on(Package, Dependency) :- attr("depends_on", Package, Dependency, _). % concrete specs don't need to be resolved -- they arise from the concrete % specs themselves. dependency_holds(Package, Dependency, Type) :- - dependency_condition(ID, Package, Dependency), + facts(Package, dependency_condition(ID, Dependency)), dependency_type(ID, Type), build(Package), not external(Package), - condition_holds(ID). + condition_holds(ID, Package). % We cut off dependencies of externals (as we don't really know them). % Don't impose constraints on dependencies that don't exist. -do_not_impose(ID) :- +do_not_impose(ID, Package) :- not dependency_holds(Package, Dependency, _), - dependency_condition(ID, Package, Dependency). + facts(Package, dependency_condition(ID, Dependency)). % declared dependencies are real if they're not virtual AND % the package is not an external. @@ -281,9 +281,9 @@ error(100, "Cyclic dependency detected between '{0}' and '{1}' (consider changin % Conflicts %----------------------------------------------------------------------------- error(1, Msg) :- attr("node", Package), - conflict(Package, TriggerID, ConstraintID, Msg), - condition_holds(TriggerID), - condition_holds(ConstraintID), + facts(Package, conflict(TriggerID, ConstraintID, Msg)), + condition_holds(TriggerID, Package), + condition_holds(ConstraintID, Package), not external(Package), % ignore conflicts for externals not attr("hash", Package, _). % ignore conflicts for installed packages @@ -312,7 +312,7 @@ attr("virtual_node", Virtual) % If there's a virtual node, we must select one and only one provider. % The provider must be selected among the possible providers. -{ provider(Package, Virtual) : possible_provider(Package, Virtual) } +{ provider(Package, Virtual) : facts(Package, possible_provider(Virtual)) } :- attr("virtual_node", Virtual). error(100, "Cannot find valid provider for virtual {0}", Virtual) @@ -339,8 +339,8 @@ provider(Package, Virtual) :- attr("node", Package), virtual_condition_holds(Pac % The provider provides the virtual if some provider condition holds. virtual_condition_holds(Provider, Virtual) :- - provider_condition(ID, Provider, Virtual), - condition_holds(ID), + facts(Provider, provider_condition(ID, Virtual)), + condition_holds(ID, Provider), virtual(Virtual). % A package cannot be the actual provider for a virtual if it does not @@ -374,7 +374,7 @@ possible_provider_weight(Dependency, Virtual, 0, "external") possible_provider_weight(Dependency, Virtual, Weight, "packages_yaml") :- provider(Dependency, Virtual), depends_on(Package, Dependency), - pkg_provider_preference(Package, Virtual, Dependency, Weight). + facts(Package, provider_preference(Virtual, Dependency, Weight)). % A provider mentioned in the default configuration can use a weight % according to its priority in the list of providers @@ -408,7 +408,7 @@ possible_provider_weight(Dependency, Virtual, 100, "fallback") :- provider(Depen % if a package is external its version must be one of the external versions { external_version(Package, Version, Weight): - version_declared(Package, Version, Weight, "external") } + facts(Package, version_declared(Version, Weight, "external")) } :- external(Package). error(100, "Attempted to use external for '{0}' which does not satisfy any configured external spec", Package) :- external(Package), @@ -436,7 +436,7 @@ external(Package) :- attr("external_spec_selected", Package, _). % corresponding external spec. :- attr("version", Package, Version), version_weight(Package, Weight), - version_declared(Package, Version, Weight, "external"), + facts(Package, version_declared(Version, Weight, "external")), not external(Package), internal_error("External weight used for internal spec"). @@ -447,7 +447,7 @@ attr("external_spec_selected", Package, LocalIndex) :- not attr("hash", Package, _). external_conditions_hold(Package, LocalIndex) :- - possible_external(ID, Package, LocalIndex), condition_holds(ID). + facts(Package, possible_external(ID, LocalIndex)), condition_holds(ID, Package). % it cannot happen that a spec is external, but none of the external specs % conditions hold. @@ -477,24 +477,24 @@ activate_requirement(Package, X) :- activate_requirement(Package, X) :- package_in_dag(Package), requirement_group(Package, X), - condition_holds(Y), + condition_holds(Y, Package), requirement_conditional(Package, X, Y). requirement_group_satisfied(Package, X) :- - 1 { condition_holds(Y) : requirement_group_member(Y, Package, X) } 1, + 1 { condition_holds(Y, Package) : requirement_group_member(Y, Package, X) } 1, requirement_policy(Package, X, "one_of"), activate_requirement(Package, X), requirement_group(Package, X). requirement_weight(Package, Group, W) :- - condition_holds(Y), + condition_holds(Y, Package), requirement_has_weight(Y, W), requirement_group_member(Y, Package, Group), requirement_policy(Package, Group, "one_of"), requirement_group_satisfied(Package, Group). requirement_group_satisfied(Package, X) :- - 1 { condition_holds(Y) : requirement_group_member(Y, Package, X) } , + 1 { condition_holds(Y, Package) : requirement_group_member(Y, Package, X) } , requirement_policy(Package, X, "any_of"), activate_requirement(Package, X), requirement_group(Package, X). @@ -514,7 +514,7 @@ requirement_group_satisfied(Package, X) :- requirement_weight(Package, Group, W) :- W = #min { - Z : requirement_has_weight(Y, Z), condition_holds(Y), requirement_group_member(Y, Package, Group); + Z : requirement_has_weight(Y, Z), condition_holds(Y, Package), requirement_group_member(Y, Package, Group); % We need this to avoid an annoying warning during the solve % concretize.lp:1151:5-11: info: tuple ignored: % #sup@73 @@ -549,8 +549,12 @@ error(10, Message) :- %----------------------------------------------------------------------------- % a variant is a variant of a package if it is a variant under some condition % and that condition holds -variant(Package, Variant) :- variant_condition(ID, Package, Variant), - condition_holds(ID). +node_has_variant(Package, variant(Variant)) :- + facts(Package, conditional_variant(ID, Variant)), + condition_holds(ID, Package). + +node_has_variant(Package, variant(Variant)) :- facts(Package, variant(Variant)). + attr("variant_propagate", Package, Variant, Value, Source) :- attr("node", Package), @@ -560,56 +564,56 @@ attr("variant_propagate", Package, Variant, Value, Source) :- attr("variant_value", Package, Variant, Value) :- attr("node", Package), - variant(Package, Variant), + node_has_variant(Package, variant(Variant)), attr("variant_propagate", Package, Variant, Value, _), - variant_possible_value(Package, Variant, Value). + facts(Package, variant_possible_value(Variant, Value)). error(100, "{0} and {1} cannot both propagate variant '{2}' to package {3} with values '{4}' and '{5}'", Source1, Source2, Variant, Package, Value1, Value2) :- attr("variant_propagate", Package, Variant, Value1, Source1), attr("variant_propagate", Package, Variant, Value2, Source2), - variant(Package, Variant), + node_has_variant(Package, variant(Variant)), Value1 < Value2. % a variant cannot be set if it is not a variant on the package error(100, "Cannot set variant '{0}' for package '{1}' because the variant condition cannot be satisfied for the given spec", Variant, Package) :- attr("variant_set", Package, Variant), - not variant(Package, Variant), + not node_has_variant(Package, variant(Variant)), build(Package). % a variant cannot take on a value if it is not a variant of the package error(100, "Cannot set variant '{0}' for package '{1}' because the variant condition cannot be satisfied for the given spec", Variant, Package) :- attr("variant_value", Package, Variant, _), - not variant(Package, Variant), + not node_has_variant(Package, variant(Variant)), build(Package). % if a variant is sticky and not set its value is the default value attr("variant_value", Package, Variant, Value) :- - variant(Package, Variant), + node_has_variant(Package, variant(Variant)), not attr("variant_set", Package, Variant), - variant_sticky(Package, Variant), + facts(Package, variant_sticky(Variant)), variant_default_value(Package, Variant, Value), build(Package). % at most one variant value for single-valued variants. { attr("variant_value", Package, Variant, Value) - : variant_possible_value(Package, Variant, Value) + : facts(Package, variant_possible_value(Variant, Value)) } :- attr("node", Package), - variant(Package, Variant), + node_has_variant(Package, variant(Variant)), build(Package). error(100, "'{0}' required multiple values for single-valued variant '{1}'", Package, Variant) :- attr("node", Package), - variant(Package, Variant), - variant_single_value(Package, Variant), + node_has_variant(Package, variant(Variant)), + facts(Package, variant_single_value(Variant)), build(Package), 2 { attr("variant_value", Package, Variant, Value) }. error(100, "No valid value for variant '{1}' of package '{0}'", Package, Variant) :- attr("node", Package), - variant(Package, Variant), + node_has_variant(Package, variant(Variant)), build(Package), not attr("variant_value", Package, Variant, _). @@ -621,7 +625,7 @@ attr("variant_set", Package, Variant) :- attr("variant_set", Package, Variant, _ % have been built w/different variants from older/different package versions. error(10, "'Spec({1}={2})' is not a valid value for '{0}' variant '{1}'", Package, Variant, Value) :- attr("variant_value", Package, Variant, Value), - not variant_possible_value(Package, Variant, Value), + not facts(Package, variant_possible_value(Variant, Value)), build(Package). % Some multi valued variants accept multiple values from disjoint sets. @@ -630,8 +634,8 @@ error(10, "'Spec({1}={2})' is not a valid value for '{0}' variant '{1}'", Packag error(100, "{0} variant '{1}' cannot have values '{2}' and '{3}' as they come from disjoint value sets", Package, Variant, Value1, Value2) :- attr("variant_value", Package, Variant, Value1), attr("variant_value", Package, Variant, Value2), - variant_value_from_disjoint_sets(Package, Variant, Value1, Set1), - variant_value_from_disjoint_sets(Package, Variant, Value2, Set2), + facts(Package, variant_value_from_disjoint_sets(Variant, Value1, Set1)), + facts(Package, variant_value_from_disjoint_sets(Variant, Value2, Set2)), Set1 < Set2, % see[1] build(Package). @@ -639,7 +643,7 @@ error(100, "{0} variant '{1}' cannot have values '{2}' and '{3}' as they come fr % we revert to the default value. If it is set, we force the set value attr("variant_value", Package, Variant, Value) :- attr("node", Package), - variant(Package, Variant), + node_has_variant(Package, variant(Variant)), attr("variant_set", Package, Variant, Value). % The rules below allow us to prefer default values for variants @@ -662,7 +666,7 @@ variant_not_default(Package, Variant, Value) % A default variant value that is not used variant_default_not_used(Package, Variant, Value) :- variant_default_value(Package, Variant, Value), - variant(Package, Variant), + node_has_variant(Package, variant(Variant)), not attr("variant_value", Package, Variant, Value), attr("node", Package). @@ -670,7 +674,7 @@ variant_default_not_used(Package, Variant, Value) external_with_variant_set(Package, Variant, Value) :- attr("variant_value", Package, Variant, Value), condition_requirement(ID, "variant_value", Package, Variant, Value), - possible_external(ID, Package, _), + facts(Package, possible_external(ID, _)), external(Package), attr("node", Package). @@ -682,7 +686,7 @@ external_with_variant_set(Package, Variant, Value) % packages.yaml and the command line) % variant_default_value(Package, Variant, Value) - :- variant_default_value_from_package_py(Package, Variant, Value), + :- facts(Package, variant_default_value_from_package_py(Variant, Value)), not variant_default_value_from_packages_yaml(Package, Variant, _), not attr("variant_default_value_from_cli", Package, Variant, _). @@ -706,9 +710,11 @@ error(100, "{0} variant '{1}' cannot have values '{2}' and 'none'", Package, Var % when assigned a value. auto_variant("dev_path"). auto_variant("patches"). -variant(Package, Variant) + +node_has_variant(Package, variant(Variant)) :- attr("variant_set", Package, Variant, _), auto_variant(Variant). -variant_single_value(Package, "dev_path") + +facts(Package, variant_single_value("dev_path")) :- attr("variant_set", Package, "dev_path", _). % suppress warnings about this atom being unset. It's only set if some @@ -848,7 +854,7 @@ attr("node_target", Package, Target) node_target_weight(Package, Weight) :- attr("node", Package), attr("node_target", Package, Target), - target_weight(Package, Target, Weight). + facts(Package, target_weight(Target, Weight)). % compatibility rules for targets among nodes node_target_match(Parent, Dependency) @@ -866,8 +872,6 @@ error(100, "'{0} target={1}' is not compatible with this machine", Package, Targ attr("node_target", Package, Target), not target(Target). -#defined package_target_weight/3. - %----------------------------------------------------------------------------- % Compiler semantics %----------------------------------------------------------------------------- @@ -981,18 +985,18 @@ compiler_weight(Package, Weight) :- node_compiler(Package, CompilerID), compiler_name(CompilerID, Compiler), compiler_version(CompilerID, V), - node_compiler_preference(Package, Compiler, V, Weight). + facts(Package, node_compiler_preference(Compiler, V, Weight)). compiler_weight(Package, Weight) :- node_compiler(Package, CompilerID), compiler_name(CompilerID, Compiler), compiler_version(CompilerID, V), - not node_compiler_preference(Package, Compiler, V, _), + not facts(Package, node_compiler_preference(Compiler, V, _)), default_compiler_preference(CompilerID, Weight). compiler_weight(Package, 100) :- node_compiler(Package, CompilerID), compiler_name(CompilerID, Compiler), compiler_version(CompilerID, V), - not node_compiler_preference(Package, Compiler, V, _), + not facts(Package, node_compiler_preference(Compiler, V, _)), not default_compiler_preference(CompilerID, _). % For the time being, be strict and reuse only if the compiler match one we have on the system @@ -1085,7 +1089,7 @@ attr("no_flags", Package, FlagType) :- attr("node", Package), 2 { attr("hash", Package, Hash) }. % if a hash is selected, we impose all the constraints that implies -impose(Hash) :- attr("hash", Package, Hash). +impose(Hash, Package) :- attr("hash", Package, Hash). % if we haven't selected a hash for a package, we'll be building it build(Package) :- not attr("hash", Package, _), attr("node", Package). @@ -1124,7 +1128,7 @@ build_priority(Package, 0) :- attr("node", Package), not optimize_for_reuse(). % build deps in the solve, consider using them as a preference to resolve this. :- attr("version", Package, Version), version_weight(Package, Weight), - version_declared(Package, Version, Weight, "installed"), + facts(Package, version_declared(Version, Weight, "installed")), not optimize_for_reuse(). #defined installed_hash/2. @@ -1339,10 +1343,10 @@ opt_criterion(5, "non-preferred targets"). #heuristic literal_solved(ID) : literal(ID). [50, init] #heuristic attr("hash", Package, Hash) : attr("root", Package). [45, init] -#heuristic attr("version", Package, Version) : version_declared(Package, Version, 0), attr("root", Package). [40, true] -#heuristic version_weight(Package, 0) : version_declared(Package, Version, 0), attr("root", Package). [40, true] +#heuristic attr("version", Package, Version) : facts(Package, version_declared(Version, 0)), attr("root", Package). [40, true] +#heuristic version_weight(Package, 0) : facts(Package, version_declared(Version, 0)), attr("root", Package). [40, true] #heuristic attr("variant_value", Package, Variant, Value) : variant_default_value(Package, Variant, Value), attr("root", Package). [40, true] -#heuristic attr("node_target", Package, Target) : package_target_weight(Target, Package, 0), attr("root", Package). [40, true] +#heuristic attr("node_target", Package, Target) : facts(Package, target_weight(Target, 0)), attr("root", Package). [40, true] #heuristic node_target_weight(Package, 0) : attr("root", Package). [40, true] #heuristic node_compiler(Package, CompilerID) : default_compiler_preference(ID, 0), compiler_id(ID), attr("root", Package). [40, true] @@ -1350,10 +1354,10 @@ opt_criterion(5, "non-preferred targets"). #heuristic provider_weight(Package, Virtual, 0, R) : possible_provider_weight(Package, Virtual, 0, R), attr("virtual_node", Virtual). [30, true] #heuristic attr("node", Package) : possible_provider_weight(Package, Virtual, 0, _), attr("virtual_node", Virtual). [30, true] -#heuristic attr("version", Package, Version) : version_declared(Package, Version, 0), attr("node", Package). [20, true] -#heuristic version_weight(Package, 0) : version_declared(Package, Version, 0), attr("node", Package). [20, true] +#heuristic attr("version", Package, Version) : facts(Package, version_declared(Version, 0)), attr("node", Package). [20, true] +#heuristic version_weight(Package, 0) : facts(Package, version_declared(Version, 0)), attr("node", Package). [20, true] -#heuristic attr("node_target", Package, Target) : package_target_weight(Target, Package, 0), attr("node", Package). [20, true] +#heuristic attr("node_target", Package, Target) : facts(Package, target_weight(Target, 0)), attr("node", Package). [20, true] #heuristic node_target_weight(Package, 0) : attr("node", Package). [20, true] #heuristic node_compiler(Package, CompilerID) : default_compiler_preference(ID, 0), compiler_id(ID), attr("node", Package). [15, true] diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py index 465edfdb08..fad5812a2a 100644 --- a/lib/spack/spack/test/concretize.py +++ b/lib/spack/spack/test/concretize.py @@ -152,7 +152,7 @@ class Root(Package): version("1.0", sha256="abcde") depends_on("changing") - conflicts("changing~foo") + conflicts("^changing~foo") """ packages_dir.join("root", "package.py").write(root_pkg_str, ensure=True) @@ -1599,7 +1599,7 @@ def test_installed_version_is_selected_only_for_reuse( pytest.xfail("Known failure of the original concretizer") # Install a dependency that cannot be reused with "root" - # because of a conflict a variant, then delete its version + # because of a conflict in a variant, then delete its version dependency = Spec("changing@1.0~foo").concretized() dependency.package.do_install(fake=True, explicit=True) repo_with_changing_recipe.change({"delete_version": True})