From d3a7a73a00836b9c0c90c55e01a288ec36f70071 Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Wed, 23 Oct 2024 11:47:41 +0200 Subject: [PATCH] Improve error messages for statically checked specs Signed-off-by: Massimiliano Culpo --- lib/spack/spack/solver/asp.py | 23 +++++++++++++++++++++++ lib/spack/spack/spec.py | 16 +++++++++++++--- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/lib/spack/spack/solver/asp.py b/lib/spack/spack/solver/asp.py index 3d9c4daa4c5..c4be74a0bcb 100644 --- a/lib/spack/spack/solver/asp.py +++ b/lib/spack/spack/solver/asp.py @@ -4452,6 +4452,29 @@ def _check_input_and_extract_concrete_specs(specs): reusable = [] for root in specs: for s in root.traverse(): + candidates = s.edges_to_dependencies(depflag=dt.BUILD) + if candidates: + virtuals = set() + non_virtuals = spack.package_base.possible_dependencies( + s, transitive=False, virtuals=virtuals + ) + possible_direct_deps = set(non_virtuals) | virtuals + not_possible = set( + [ + x.spec.name + for x in candidates + if x.direct and x.spec.name not in possible_direct_deps + ] + ) + if not_possible: + start_str = f"'{s}' in '{root}'" + if s == root: + start_str = f"'{root}'" + raise UnsatisfiableSpecError( + f"{start_str} cannot have a dependency on {', '.join(not_possible)}, " + f"according to its recipe" + ) + if s.concrete: reusable.append(s) elif spack.repo.PATH.is_virtual(s.name): diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py index dd8b90a1f89..6bf8bb6d6ff 100644 --- a/lib/spack/spack/spec.py +++ b/lib/spack/spack/spec.py @@ -758,7 +758,13 @@ def update_virtuals(self, virtuals: Iterable[str]) -> bool: def copy(self) -> "DependencySpec": """Return a copy of this edge""" - return DependencySpec(self.parent, self.spec, depflag=self.depflag, virtuals=self.virtuals) + return DependencySpec( + self.parent, + self.spec, + depflag=self.depflag, + virtuals=self.virtuals, + direct=self.direct, + ) def _cmp_iter(self): yield self.parent.name if self.parent else None @@ -1789,7 +1795,7 @@ def _add_dependency( f"\t'{str(self)}' cannot depend on '{required_dep_str}'" ) - self.add_dependency_edge(spec, depflag=depflag, virtuals=virtuals) + self.add_dependency_edge(spec, depflag=depflag, virtuals=virtuals, direct=direct) return try: @@ -3175,6 +3181,7 @@ def _constrain_dependencies(self, other: "Spec") -> bool: dep_spec_copy.spec.copy(), depflag=dep_spec_copy.depflag, virtuals=dep_spec_copy.virtuals, + direct=dep_spec_copy.direct, ) changed = True @@ -3618,7 +3625,10 @@ def spid(spec): new_specs[spid(edge.spec)] = edge.spec.copy(deps=False) new_specs[spid(edge.parent)].add_dependency_edge( - new_specs[spid(edge.spec)], depflag=edge.depflag, virtuals=edge.virtuals + new_specs[spid(edge.spec)], + depflag=edge.depflag, + virtuals=edge.virtuals, + direct=edge.direct, ) def copy(self, deps: Union[bool, dt.DepTypes, dt.DepFlag] = True, **kwargs):