summaryrefslogtreecommitdiff
path: root/lib/spack/spack/spec.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/spack/spack/spec.py')
-rw-r--r--lib/spack/spack/spec.py108
1 files changed, 92 insertions, 16 deletions
diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py
index 6030ff2681..20e5c3ffa3 100644
--- a/lib/spack/spack/spec.py
+++ b/lib/spack/spack/spec.py
@@ -59,7 +59,7 @@ import platform
import re
import socket
import warnings
-from typing import Any, Callable, Dict, List, Optional, Tuple, Union
+from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
import llnl.path
import llnl.string
@@ -1464,6 +1464,26 @@ class Spec:
"""
return [d for d in self._dependencies.select(child=name, depflag=depflag)]
+ @property
+ def edge_attributes(self) -> str:
+ """Helper method to print edge attributes in spec literals"""
+ edges = self.edges_from_dependents()
+ if not edges:
+ return ""
+
+ union = DependencySpec(parent=Spec(), spec=self, depflag=0, virtuals=())
+ for edge in edges:
+ union.update_deptypes(edge.depflag)
+ union.update_virtuals(edge.virtuals)
+ deptypes_str = (
+ f"deptypes={','.join(dt.flag_to_tuple(union.depflag))}" if union.depflag else ""
+ )
+ virtuals_str = f"virtuals={','.join(union.virtuals)}" if union.virtuals else ""
+ if not deptypes_str and not virtuals_str:
+ return ""
+ result = f"{deptypes_str} {virtuals_str}".strip()
+ return f"[{result}]"
+
def dependencies(self, name=None, deptype: Union[dt.DepTypes, dt.DepFlag] = dt.ALL):
"""Return a list of direct dependencies (nodes in the DAG).
@@ -3688,8 +3708,15 @@ class Spec:
if other.concrete and self.concrete:
return self.dag_hash() == other.dag_hash()
- self_hash = self.dag_hash() if self.concrete else self.abstract_hash
- other_hash = other.dag_hash() if other.concrete else other.abstract_hash
+ elif self.concrete:
+ return self.satisfies(other)
+
+ elif other.concrete:
+ return other.satisfies(self)
+
+ # From here we know both self and other are not concrete
+ self_hash = self.abstract_hash
+ other_hash = other.abstract_hash
if (
self_hash
@@ -3778,10 +3805,6 @@ class Spec:
repository=spack.repo.PATH, specs=other.traverse(), restrict=True
)
- # This handles cases where there are already providers for both vpkgs
- if not self_index.satisfies(other_index):
- return False
-
# These two loops handle cases where there is an overly restrictive
# vpkg in one spec for a provider in the other (e.g., mpi@3: is not
# compatible with mpich2)
@@ -3879,7 +3902,46 @@ class Spec:
return False
# If we arrived here, then rhs is abstract. At the moment we don't care about the edge
- # structure of an abstract DAG - hence the deps=False parameter.
+ # structure of an abstract DAG, so we check if any edge could satisfy the properties
+ # we ask for.
+ lhs_edges: Dict[str, Set[DependencySpec]] = collections.defaultdict(set)
+ for rhs_edge in other.traverse_edges(root=False, cover="edges"):
+ # If we are checking for ^mpi we need to verify if there is any edge
+ if rhs_edge.spec.virtual:
+ rhs_edge.update_virtuals(virtuals=(rhs_edge.spec.name,))
+
+ if not rhs_edge.virtuals:
+ continue
+
+ if not lhs_edges:
+ # Construct a map of the link/run subDAG + direct "build" edges,
+ # keyed by dependency name
+ for lhs_edge in self.traverse_edges(
+ root=False, cover="edges", deptype=("link", "run")
+ ):
+ lhs_edges[lhs_edge.spec.name].add(lhs_edge)
+ for virtual_name in lhs_edge.virtuals:
+ lhs_edges[virtual_name].add(lhs_edge)
+
+ build_edges = self.edges_to_dependencies(depflag=dt.BUILD)
+ for lhs_edge in build_edges:
+ lhs_edges[lhs_edge.spec.name].add(lhs_edge)
+ for virtual_name in lhs_edge.virtuals:
+ lhs_edges[virtual_name].add(lhs_edge)
+
+ # We don't have edges to this dependency
+ current_dependency_name = rhs_edge.spec.name
+ if current_dependency_name not in lhs_edges:
+ return False
+
+ for virtual in rhs_edge.virtuals:
+ has_virtual = any(
+ virtual in edge.virtuals for edge in lhs_edges[current_dependency_name]
+ )
+ if not has_virtual:
+ return False
+
+ # Edges have been checked above already, hence deps=False
return all(
any(lhs.satisfies(rhs, deps=False) for lhs in self.traverse(root=False))
for rhs in other.traverse(root=False)
@@ -4081,9 +4143,7 @@ class Spec:
"""
query_parameters = name.split(":")
if len(query_parameters) > 2:
- msg = "key has more than one ':' symbol."
- msg += " At most one is admitted."
- raise KeyError(msg)
+ raise KeyError("key has more than one ':' symbol. At most one is admitted.")
name, query_parameters = query_parameters[0], query_parameters[1:]
if query_parameters:
@@ -4108,11 +4168,17 @@ class Spec:
itertools.chain(
# Regular specs
(x for x in order() if x.name == name),
+ (
+ x
+ for x in order()
+ if (not x.virtual)
+ and any(name in edge.virtuals for edge in x.edges_from_dependents())
+ ),
(x for x in order() if (not x.virtual) and x.package.provides(name)),
)
)
except StopIteration:
- raise KeyError("No spec with name %s in %s" % (name, self))
+ raise KeyError(f"No spec with name {name} in {self}")
if self._concrete:
return SpecBuildInterface(value, name, query_parameters)
@@ -4490,17 +4556,27 @@ class Spec:
return str(path_ctor(*output_path_components))
def __str__(self):
- sorted_nodes = [self] + sorted(
+ root_str = [self.format()]
+ sorted_dependencies = sorted(
self.traverse(root=False), key=lambda x: (x.name, x.abstract_hash)
)
- return " ^".join(d.format() for d in sorted_nodes).strip()
+ sorted_dependencies = [
+ d.format("{edge_attributes} " + DEFAULT_FORMAT) for d in sorted_dependencies
+ ]
+ spec_str = " ^".join(root_str + sorted_dependencies)
+ return spec_str.strip()
@property
def colored_str(self):
- sorted_nodes = [self] + sorted(
+ root_str = [self.cformat()]
+ sorted_dependencies = sorted(
self.traverse(root=False), key=lambda x: (x.name, x.abstract_hash)
)
- return " ^".join(d.cformat() for d in sorted_nodes).strip()
+ sorted_dependencies = [
+ d.cformat("{edge_attributes} " + DISPLAY_FORMAT) for d in sorted_dependencies
+ ]
+ spec_str = " ^".join(root_str + sorted_dependencies)
+ return spec_str.strip()
def install_status(self):
"""Helper for tree to print DB install status."""