solver: first prototype of chained error messages for one message type
This commit is contained in:
parent
59acfe4f0b
commit
e9012c7781
@ -614,6 +614,23 @@ def multiple_values_error(self, attribute, pkg):
|
||||
def no_value_error(self, attribute, pkg):
|
||||
return f'Cannot select a single "{attribute}" for package "{pkg}"'
|
||||
|
||||
def _get_cause_tree(self, cause, conditions, condition_causes, literals, indent=""):
|
||||
parents = [c for e, c in condition_causes if e == cause]
|
||||
local = "required because %s " % conditions[cause]
|
||||
|
||||
return [indent + local] + [
|
||||
c
|
||||
for parent in parents
|
||||
for c in self._get_cause_tree(
|
||||
parent, conditions, condition_causes, literals, indent=indent + " "
|
||||
)
|
||||
]
|
||||
|
||||
def get_cause_tree(self, cause):
|
||||
conditions = dict(extract_args(self.model, "condition"))
|
||||
condition_causes = list(extract_args(self.model, "condition_cause"))
|
||||
return self._get_cause_tree(cause, conditions, condition_causes, [])
|
||||
|
||||
def handle_error(self, msg, *args):
|
||||
"""Handle an error state derived by the solver."""
|
||||
if msg == "multiple_values_error":
|
||||
@ -622,10 +639,24 @@ def handle_error(self, msg, *args):
|
||||
if msg == "no_value_error":
|
||||
return self.no_value_error(*args)
|
||||
|
||||
try:
|
||||
idx = args.index("startcauses")
|
||||
except ValueError:
|
||||
msg_args = args
|
||||
cause_args = []
|
||||
else:
|
||||
msg_args = args[:idx]
|
||||
cause_args = args[idx + 1 :]
|
||||
|
||||
msg = msg.format(*msg_args)
|
||||
|
||||
for cause in set(cause_args):
|
||||
for c in self.get_cause_tree(cause):
|
||||
msg += f"\n{c}"
|
||||
|
||||
# For variant formatting, we sometimes have to construct specs
|
||||
# to format values properly. Find/replace all occurances of
|
||||
# Spec(...) with the string representation of the spec mentioned
|
||||
msg = msg.format(*args)
|
||||
specs_to_construct = re.findall(r"Spec\(([^)]*)\)", msg)
|
||||
for spec_str in specs_to_construct:
|
||||
msg = msg.replace("Spec(%s)" % spec_str, str(spack.spec.Spec(spec_str)))
|
||||
@ -1266,9 +1297,11 @@ def package_provider_rules(self, pkg):
|
||||
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.imposed_constraint(
|
||||
condition_id, "virtual_condition_holds", pkg.name, provided.name
|
||||
))
|
||||
self.gen.fact(
|
||||
fn.imposed_constraint(
|
||||
condition_id, "virtual_condition_holds", pkg.name, provided.name
|
||||
)
|
||||
)
|
||||
self.gen.newline()
|
||||
|
||||
def package_dependencies_rules(self, pkg):
|
||||
@ -1298,9 +1331,11 @@ def package_dependencies_rules(self, pkg):
|
||||
|
||||
for t in sorted(deptypes):
|
||||
# there is a declared dependency of type t
|
||||
self.gen.fact(fn.imposed_constraint(
|
||||
condition_id, "dependency_holds", pkg.name, dep.spec.name, t
|
||||
))
|
||||
self.gen.fact(
|
||||
fn.imposed_constraint(
|
||||
condition_id, "dependency_holds", pkg.name, dep.spec.name, t
|
||||
)
|
||||
)
|
||||
|
||||
self.gen.newline()
|
||||
|
||||
@ -1454,9 +1489,11 @@ 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.imposed_constraint(
|
||||
condition_id, "external_conditions_hold", pkg_name, local_idx
|
||||
))
|
||||
self.gen.fact(
|
||||
fn.imposed_constraint(
|
||||
condition_id, "external_conditions_hold", pkg_name, local_idx
|
||||
)
|
||||
)
|
||||
self.possible_versions[spec.name].add(spec.version)
|
||||
self.gen.newline()
|
||||
|
||||
@ -2310,16 +2347,20 @@ def literal_specs(self, specs):
|
||||
|
||||
self.gen.fact(fn.condition_requirement(condition_id, "literal_solved", condition_id))
|
||||
|
||||
self.gen.fact(fn.imposed_constraint(
|
||||
condition_id, "virtual_root" if spec.virtual else "root", spec.name
|
||||
))
|
||||
self.gen.fact(
|
||||
fn.imposed_constraint(
|
||||
condition_id, "virtual_root" if spec.virtual else "root", spec.name
|
||||
)
|
||||
)
|
||||
|
||||
for clause in self.spec_clauses(spec):
|
||||
self.gen.fact(fn.imposed_constraint(condition_id, *clause.args))
|
||||
if clause.args[0] == "variant_set":
|
||||
self.gen.fact(fn.imposed_constraint(
|
||||
condition_id, "variant_default_value_from_cli", *clause.args[1:]
|
||||
))
|
||||
self.gen.fact(
|
||||
fn.imposed_constraint(
|
||||
condition_id, "variant_default_value_from_cli", *clause.args[1:]
|
||||
)
|
||||
)
|
||||
|
||||
if self.concretize_everything:
|
||||
self.gen.fact(fn.concretize_everything())
|
||||
|
@ -86,6 +86,27 @@ version_satisfies(Package, Constraint, HashVersion) :- version_satisfies(Package
|
||||
{ attr("version", Package, Version) : version_declared(Package, Version) }
|
||||
:- attr("node", Package).
|
||||
|
||||
% error we expect users to see
|
||||
error(0, "Version '{0}' of {1} does not satisfy '@{2}'", Version, Package, Constraint, startcauses, VersionCause, ConstraintCause)
|
||||
:- attr("node", Package),
|
||||
attr("version", Package, Version),
|
||||
imposed_constraint(VersionCause, "node_version_satisfies", Package, Version),
|
||||
condition_holds(VersionCause),
|
||||
attr("node_version_satisfies", Package, Constraint),
|
||||
imposed_constraint(ConstraintCause, "node_version_satisfies", Package, Constraint),
|
||||
condition_holds(ConstraintCause),
|
||||
not version_satisfies(Package, Constraint, Version).
|
||||
|
||||
% Error to ensure structure of the program is not violated
|
||||
error(2, "No version from '{0}' satisfies '@{1}' and '@{2}'", Package, Version1, Version2)
|
||||
:- attr("node", Package),
|
||||
attr("version", Package, Version1),
|
||||
attr("version", Package, Version2),
|
||||
Version1 < Version2. % see[1]
|
||||
|
||||
error(2, "No versions available for package '{0}'", Package)
|
||||
:- attr("node", Package), not attr("version", Package, _).
|
||||
|
||||
% A virtual package may or may not have a version, but never has more than one
|
||||
error(100, "Cannot select a single version for virtual '{0}'", Virtual)
|
||||
:- attr("virtual_node", Virtual),
|
||||
|
@ -23,6 +23,8 @@
|
||||
#show error/4.
|
||||
#show error/5.
|
||||
#show error/6.
|
||||
#show error/7.
|
||||
#show error/8.
|
||||
|
||||
% show cause -> effect data for errors
|
||||
#show condition_cause/2.
|
||||
|
Loading…
Reference in New Issue
Block a user