Spec.is_virtual -> spack.repo.PATH.is_virtual (#48986)

This commit is contained in:
Harmen Stoppels 2025-02-12 16:57:27 +01:00 committed by GitHub
parent cd98781fb4
commit 76f00a3659
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 61 additions and 26 deletions

View File

@ -1010,7 +1010,7 @@ def _issues_in_depends_on_directive(pkgs, error_cls):
for dep_name, dep in deps_by_name.items(): for dep_name, dep in deps_by_name.items():
def check_virtual_with_variants(spec, msg): def check_virtual_with_variants(spec, msg):
if not spec.virtual or not spec.variants: if not spack.repo.PATH.is_virtual(spec.name) or not spec.variants:
return return
error = error_cls( error = error_cls(
f"{pkg_name}: {msg}", f"{pkg_name}: {msg}",

View File

@ -2529,10 +2529,10 @@ def install_root_node(
allow_missing: when true, allows installing a node with missing dependencies allow_missing: when true, allows installing a node with missing dependencies
""" """
# Early termination # Early termination
if spec.external or spec.virtual: if spec.external or not spec.concrete:
warnings.warn("Skipping external or virtual package {0}".format(spec.format())) warnings.warn("Skipping external or abstract spec {0}".format(spec.format()))
return return
elif spec.concrete and spec.installed and not force: elif spec.installed and not force:
warnings.warn("Package for spec {0} already installed.".format(spec.format())) warnings.warn("Package for spec {0} already installed.".format(spec.format()))
return return

View File

@ -41,7 +41,11 @@ def providers(parser, args):
specs = spack.cmd.parse_specs(args.virtual_package) specs = spack.cmd.parse_specs(args.virtual_package)
# Check prerequisites # Check prerequisites
non_virtual = [str(s) for s in specs if not s.virtual or s.name not in valid_virtuals] non_virtual = [
str(s)
for s in specs
if not spack.repo.PATH.is_virtual(s.name) or s.name not in valid_virtuals
]
if non_virtual: if non_virtual:
msg = "non-virtual specs cannot be part of the query " msg = "non-virtual specs cannot be part of the query "
msg += "[{0}]\n".format(", ".join(non_virtual)) msg += "[{0}]\n".format(", ".join(non_virtual))

View File

@ -220,7 +220,7 @@ def concretize_one(spec: Union[str, Spec], tests: TestsType = False) -> Spec:
opt, i, answer = min(result.answers) opt, i, answer = min(result.answers)
name = spec.name name = spec.name
# TODO: Consolidate this code with similar code in solve.py # TODO: Consolidate this code with similar code in solve.py
if spec.virtual: if spack.repo.PATH.is_virtual(spec.name):
providers = [s.name for s in answer.values() if s.package.provides(name)] providers = [s.name for s in answer.values() if s.package.provides(name)]
name = providers[0] name = providers[0]

View File

@ -41,6 +41,8 @@
Union, Union,
) )
import spack.repo
try: try:
import uuid import uuid
@ -1556,7 +1558,12 @@ def _query(
# If we did fine something, the query spec can't be virtual b/c we matched an actual # If we did fine something, the query spec can't be virtual b/c we matched an actual
# package installation, so skip the virtual check entirely. If we *didn't* find anything, # package installation, so skip the virtual check entirely. If we *didn't* find anything,
# check all the deferred specs *if* the query is virtual. # check all the deferred specs *if* the query is virtual.
if not results and query_spec is not None and deferred and query_spec.virtual: if (
not results
and query_spec is not None
and deferred
and spack.repo.PATH.is_virtual(query_spec.name)
):
results = [spec for spec in deferred if spec.satisfies(query_spec)] results = [spec for spec in deferred if spec.satisfies(query_spec)]
return results return results

View File

@ -406,8 +406,8 @@ def fixup_macos_rpaths(spec):
entries which makes it harder to adjust with ``install_name_tool entries which makes it harder to adjust with ``install_name_tool
-delete_rpath``. -delete_rpath``.
""" """
if spec.external or spec.virtual: if spec.external or not spec.concrete:
tty.warn("external or virtual package cannot be fixed up: {0!s}".format(spec)) tty.warn("external/abstract spec cannot be fixed up: {0!s}".format(spec))
return False return False
if "platform=darwin" not in spec: if "platform=darwin" not in spec:

View File

@ -498,7 +498,7 @@ def _compute_specs_from_answer_set(self):
# The specs must be unified to get here, so it is safe to associate any satisfying spec # The specs must be unified to get here, so it is safe to associate any satisfying spec
# with the input. Multiple inputs may be matched to the same concrete spec # with the input. Multiple inputs may be matched to the same concrete spec
node = SpecBuilder.make_node(pkg=input_spec.name) node = SpecBuilder.make_node(pkg=input_spec.name)
if input_spec.virtual: if spack.repo.PATH.is_virtual(input_spec.name):
providers = [ providers = [
spec.name for spec in answer.values() if spec.package.provides(input_spec.name) spec.name for spec in answer.values() if spec.package.provides(input_spec.name)
] ]
@ -2080,7 +2080,11 @@ def _spec_clauses(
f: Union[Type[_Head], Type[_Body]] = _Body if body else _Head f: Union[Type[_Head], Type[_Body]] = _Body if body else _Head
if spec.name: if spec.name:
clauses.append(f.node(spec.name) if not spec.virtual else f.virtual_node(spec.name)) clauses.append(
f.node(spec.name)
if not spack.repo.PATH.is_virtual(spec.name)
else f.virtual_node(spec.name)
)
if spec.namespace: if spec.namespace:
clauses.append(f.namespace(spec.name, spec.namespace)) clauses.append(f.namespace(spec.name, spec.namespace))
@ -2107,7 +2111,7 @@ def _spec_clauses(
for value in variant.value_as_tuple: for value in variant.value_as_tuple:
# ensure that the value *can* be valid for the spec # ensure that the value *can* be valid for the spec
if spec.name and not spec.concrete and not spec.virtual: if spec.name and not spec.concrete and not spack.repo.PATH.is_virtual(spec.name):
variant_defs = vt.prevalidate_variant_value( variant_defs = vt.prevalidate_variant_value(
self.pkg_class(spec.name), variant, spec self.pkg_class(spec.name), variant, spec
) )
@ -2667,7 +2671,9 @@ def setup(
# Fail if we already know an unreachable node is requested # Fail if we already know an unreachable node is requested
for spec in specs: for spec in specs:
missing_deps = [ missing_deps = [
str(d) for d in spec.traverse() if d.name not in self.pkgs and not d.virtual str(d)
for d in spec.traverse()
if d.name not in self.pkgs and not spack.repo.PATH.is_virtual(d.name)
] ]
if missing_deps: if missing_deps:
raise spack.spec.InvalidDependencyError(spec.name, missing_deps) raise spack.spec.InvalidDependencyError(spec.name, missing_deps)
@ -2884,7 +2890,11 @@ def literal_specs(self, specs):
pkg_name = clause.args[1] pkg_name = clause.args[1]
self.gen.fact(fn.mentioned_in_literal(trigger_id, root_name, pkg_name)) self.gen.fact(fn.mentioned_in_literal(trigger_id, root_name, pkg_name))
requirements.append(fn.attr("virtual_root" if spec.virtual else "root", spec.name)) requirements.append(
fn.attr(
"virtual_root" if spack.repo.PATH.is_virtual(spec.name) else "root", spec.name
)
)
cache[imposed_spec_key] = (effect_id, requirements) cache[imposed_spec_key] = (effect_id, requirements)
self.gen.fact(fn.pkg_fact(spec.name, fn.condition_effect(condition_id, effect_id))) self.gen.fact(fn.pkg_fact(spec.name, fn.condition_effect(condition_id, effect_id)))
@ -4085,10 +4095,10 @@ def _check_input_and_extract_concrete_specs(specs):
reusable = [] reusable = []
for root in specs: for root in specs:
for s in root.traverse(): for s in root.traverse():
if s.virtual:
continue
if s.concrete: if s.concrete:
reusable.append(s) reusable.append(s)
elif spack.repo.PATH.is_virtual(s.name):
continue
spack.spec.Spec.ensure_valid_variants(s) spack.spec.Spec.ensure_valid_variants(s)
return reusable return reusable

View File

@ -381,7 +381,9 @@ def __init__(
self.all_types = dt.LINK | dt.RUN | dt.BUILD self.all_types = dt.LINK | dt.RUN | dt.BUILD
self._possible_dependencies: Set[str] = set() self._possible_dependencies: Set[str] = set()
self._possible_virtuals: Set[str] = set(x.name for x in specs if x.virtual) self._possible_virtuals: Set[str] = {
x.name for x in specs if spack.repo.PATH.is_virtual(x.name)
}
def possible_dependencies(self) -> Set[str]: def possible_dependencies(self) -> Set[str]:
"""Returns the list of possible dependencies""" """Returns the list of possible dependencies"""

View File

@ -1915,6 +1915,12 @@ def package_class(self):
@property @property
def virtual(self): def virtual(self):
warnings.warn(
"`Spec.virtual` is deprecated and will be removed in version 1.0.0. Use "
"`spack.repo.PATH.is_virtual(spec.name)` instead.",
category=spack.error.SpackAPIWarning,
stacklevel=2,
)
return spack.repo.PATH.is_virtual(self.name) return spack.repo.PATH.is_virtual(self.name)
@property @property
@ -3090,7 +3096,7 @@ def validate_or_raise(self):
# FIXME: raise just the first one encountered # FIXME: raise just the first one encountered
for spec in self.traverse(): for spec in self.traverse():
# raise an UnknownPackageError if the spec's package isn't real. # raise an UnknownPackageError if the spec's package isn't real.
if (not spec.virtual) and spec.name: if spec.name and not spack.repo.PATH.is_virtual(spec.name):
spack.repo.PATH.get_pkg_class(spec.fullname) spack.repo.PATH.get_pkg_class(spec.fullname)
# validate compiler in addition to the package name. # validate compiler in addition to the package name.
@ -3099,7 +3105,7 @@ def validate_or_raise(self):
raise UnsupportedCompilerError(spec.compiler.name) raise UnsupportedCompilerError(spec.compiler.name)
# Ensure correctness of variants (if the spec is not virtual) # Ensure correctness of variants (if the spec is not virtual)
if not spec.virtual: if not spack.repo.PATH.is_virtual(spec.name):
Spec.ensure_valid_variants(spec) Spec.ensure_valid_variants(spec)
substitute_abstract_variants(spec) substitute_abstract_variants(spec)
@ -3334,7 +3340,9 @@ def intersects(self, other: Union[str, "Spec"], deps: bool = True) -> bool:
# If the names are different, we need to consider virtuals # If the names are different, we need to consider virtuals
if self.name != other.name and self.name and other.name: if self.name != other.name and self.name and other.name:
if self.virtual and other.virtual: self_virtual = spack.repo.PATH.is_virtual(self.name)
other_virtual = spack.repo.PATH.is_virtual(other.name)
if self_virtual and other_virtual:
# Two virtual specs intersect only if there are providers for both # Two virtual specs intersect only if there are providers for both
lhs = spack.repo.PATH.providers_for(str(self)) lhs = spack.repo.PATH.providers_for(str(self))
rhs = spack.repo.PATH.providers_for(str(other)) rhs = spack.repo.PATH.providers_for(str(other))
@ -3342,8 +3350,8 @@ def intersects(self, other: Union[str, "Spec"], deps: bool = True) -> bool:
return bool(intersection) return bool(intersection)
# A provider can satisfy a virtual dependency. # A provider can satisfy a virtual dependency.
elif self.virtual or other.virtual: elif self_virtual or other_virtual:
virtual_spec, non_virtual_spec = (self, other) if self.virtual else (other, self) virtual_spec, non_virtual_spec = (self, other) if self_virtual else (other, self)
try: try:
# Here we might get an abstract spec # Here we might get an abstract spec
pkg_cls = spack.repo.PATH.get_pkg_class(non_virtual_spec.fullname) pkg_cls = spack.repo.PATH.get_pkg_class(non_virtual_spec.fullname)
@ -3448,7 +3456,9 @@ def satisfies(self, other: Union[str, "Spec"], deps: bool = True) -> bool:
# If the names are different, we need to consider virtuals # If the names are different, we need to consider virtuals
if self.name != other.name and self.name and other.name: if self.name != other.name and self.name and other.name:
# A concrete provider can satisfy a virtual dependency. # A concrete provider can satisfy a virtual dependency.
if not self.virtual and other.virtual: if not spack.repo.PATH.is_virtual(self.name) and spack.repo.PATH.is_virtual(
other.name
):
try: try:
# Here we might get an abstract spec # Here we might get an abstract spec
pkg_cls = spack.repo.PATH.get_pkg_class(self.fullname) pkg_cls = spack.repo.PATH.get_pkg_class(self.fullname)
@ -3516,7 +3526,7 @@ def satisfies(self, other: Union[str, "Spec"], deps: bool = True) -> bool:
lhs_edges: Dict[str, Set[DependencySpec]] = collections.defaultdict(set) lhs_edges: Dict[str, Set[DependencySpec]] = collections.defaultdict(set)
for rhs_edge in other.traverse_edges(root=False, cover="edges"): 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 we are checking for ^mpi we need to verify if there is any edge
if rhs_edge.spec.virtual: if spack.repo.PATH.is_virtual(rhs_edge.spec.name):
rhs_edge.update_virtuals(virtuals=(rhs_edge.spec.name,)) rhs_edge.update_virtuals(virtuals=(rhs_edge.spec.name,))
if not rhs_edge.virtuals: if not rhs_edge.virtuals:
@ -3562,7 +3572,7 @@ def satisfies(self, other: Union[str, "Spec"], deps: bool = True) -> bool:
def virtual_dependencies(self): def virtual_dependencies(self):
"""Return list of any virtual deps in this spec.""" """Return list of any virtual deps in this spec."""
return [spec for spec in self.traverse() if spec.virtual] return [spec for spec in self.traverse() if spack.repo.PATH.is_virtual(spec.name)]
@property # type: ignore[misc] # decorated prop not supported in mypy @property # type: ignore[misc] # decorated prop not supported in mypy
def patches(self): def patches(self):
@ -4850,7 +4860,9 @@ def reconstruct_virtuals_on_edges(spec):
possible_virtuals = set() possible_virtuals = set()
for node in spec.traverse(): for node in spec.traverse():
try: try:
possible_virtuals.update({x for x in node.package.dependencies if Spec(x).virtual}) possible_virtuals.update(
{x for x in node.package.dependencies if spack.repo.PATH.is_virtual(x)}
)
except Exception as e: except Exception as e:
warnings.warn(f"cannot reconstruct virtual dependencies on package {node.name}: {e}") warnings.warn(f"cannot reconstruct virtual dependencies on package {node.name}: {e}")
continue continue