diff options
author | Massimiliano Culpo <massimiliano.culpo@gmail.com> | 2023-06-13 11:07:12 +0200 |
---|---|---|
committer | Todd Gamblin <tgamblin@llnl.gov> | 2023-08-15 15:54:37 -0700 |
commit | 6ad0dc3722c778afda37bcab8397ca6e703b5ee9 (patch) | |
tree | b72cc364a5a8bfa241f66d909df87df6b4f22809 /lib/spack | |
parent | 87d4bdaa025b624d3b891f4e2f0c4034b502496b (diff) | |
download | spack-6ad0dc3722c778afda37bcab8397ca6e703b5ee9.tar.gz spack-6ad0dc3722c778afda37bcab8397ca6e703b5ee9.tar.bz2 spack-6ad0dc3722c778afda37bcab8397ca6e703b5ee9.tar.xz spack-6ad0dc3722c778afda37bcab8397ca6e703b5ee9.zip |
Transform many package related facts to use a nested function
Each fact that is deduced from package rules, and start with
a bare package atom, is transformed into a "facts" atom containing
a nested function.
For instance we transformed
version_declared(Package, ...) -> facts(Package, version_declared(...))
This allows us to clearly mark facts that represent a rule on the package,
and will be of help later when we'll have to distinguish the cases where
the atom "Package" is being used referred to package rules and not to a
node in the DAG.
Diffstat (limited to 'lib/spack')
-rw-r--r-- | lib/spack/spack/solver/asp.py | 83 | ||||
-rw-r--r-- | lib/spack/spack/solver/concretize.lp | 166 | ||||
-rw-r--r-- | lib/spack/spack/test/concretize.py | 4 |
3 files changed, 141 insertions, 112 deletions
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 @@ class AspFunction(AspObject): 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 @@ class SpackSolverSetup: ) 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 @@ class SpackSolverSetup: 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 @@ class SpackSolverSetup: 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 @@ class SpackSolverSetup: 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 @@ class SpackSolverSetup: 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 @@ class SpackSolverSetup: 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 @@ class SpackSolverSetup: 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 @@ class SpackSolverSetup: 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 @@ class SpackSolverSetup: # 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 @@ class SpackSolverSetup: """ 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 @@ class SpackSolverSetup: 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 @@ class SpackSolverSetup: 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 @@ class SpackSolverSetup: 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 @@ class SpackSolverSetup: 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 @@ class SpackSolverSetup: 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 @@ class SpackSolverSetup: # 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 @@ class SpackSolverSetup: # 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 @@ class SpackSolverSetup: 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 @@ class TestConcretize: 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}) |