diff --git a/lib/spack/spack/audit.py b/lib/spack/spack/audit.py index ac05919f025..a93e151636e 100644 --- a/lib/spack/spack/audit.py +++ b/lib/spack/spack/audit.py @@ -1010,7 +1010,7 @@ def _issues_in_depends_on_directive(pkgs, error_cls): for dep_name, dep in deps_by_name.items(): 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 error = error_cls( f"{pkg_name}: {msg}", diff --git a/lib/spack/spack/binary_distribution.py b/lib/spack/spack/binary_distribution.py index 1135f9bd007..28e339f611f 100644 --- a/lib/spack/spack/binary_distribution.py +++ b/lib/spack/spack/binary_distribution.py @@ -2529,10 +2529,10 @@ def install_root_node( allow_missing: when true, allows installing a node with missing dependencies """ # Early termination - if spec.external or spec.virtual: - warnings.warn("Skipping external or virtual package {0}".format(spec.format())) + if spec.external or not spec.concrete: + warnings.warn("Skipping external or abstract spec {0}".format(spec.format())) 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())) return diff --git a/lib/spack/spack/cmd/providers.py b/lib/spack/spack/cmd/providers.py index 8ae3cd40af7..80ece18e8d8 100644 --- a/lib/spack/spack/cmd/providers.py +++ b/lib/spack/spack/cmd/providers.py @@ -41,7 +41,11 @@ def providers(parser, args): specs = spack.cmd.parse_specs(args.virtual_package) # 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: msg = "non-virtual specs cannot be part of the query " msg += "[{0}]\n".format(", ".join(non_virtual)) diff --git a/lib/spack/spack/concretize.py b/lib/spack/spack/concretize.py index 78a46a33ab8..ae7cd7cd939 100644 --- a/lib/spack/spack/concretize.py +++ b/lib/spack/spack/concretize.py @@ -220,7 +220,7 @@ def concretize_one(spec: Union[str, Spec], tests: TestsType = False) -> Spec: opt, i, answer = min(result.answers) name = spec.name # 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)] name = providers[0] diff --git a/lib/spack/spack/database.py b/lib/spack/spack/database.py index 6b20e09fe39..76596e3c771 100644 --- a/lib/spack/spack/database.py +++ b/lib/spack/spack/database.py @@ -41,6 +41,8 @@ Union, ) +import spack.repo + try: 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 # package installation, so skip the virtual check entirely. If we *didn't* find anything, # 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)] return results diff --git a/lib/spack/spack/relocate.py b/lib/spack/spack/relocate.py index f2d0089eba0..045995169ed 100644 --- a/lib/spack/spack/relocate.py +++ b/lib/spack/spack/relocate.py @@ -406,8 +406,8 @@ def fixup_macos_rpaths(spec): entries which makes it harder to adjust with ``install_name_tool -delete_rpath``. """ - if spec.external or spec.virtual: - tty.warn("external or virtual package cannot be fixed up: {0!s}".format(spec)) + if spec.external or not spec.concrete: + tty.warn("external/abstract spec cannot be fixed up: {0!s}".format(spec)) return False if "platform=darwin" not in spec: diff --git a/lib/spack/spack/solver/asp.py b/lib/spack/spack/solver/asp.py index 91cea4d1a24..fc568770748 100644 --- a/lib/spack/spack/solver/asp.py +++ b/lib/spack/spack/solver/asp.py @@ -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 # with the input. Multiple inputs may be matched to the same concrete spec node = SpecBuilder.make_node(pkg=input_spec.name) - if input_spec.virtual: + if spack.repo.PATH.is_virtual(input_spec.name): providers = [ 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 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: clauses.append(f.namespace(spec.name, spec.namespace)) @@ -2107,7 +2111,7 @@ def _spec_clauses( for value in variant.value_as_tuple: # 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( self.pkg_class(spec.name), variant, spec ) @@ -2667,7 +2671,9 @@ def setup( # Fail if we already know an unreachable node is requested for spec in specs: 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: raise spack.spec.InvalidDependencyError(spec.name, missing_deps) @@ -2884,7 +2890,11 @@ def literal_specs(self, specs): pkg_name = clause.args[1] 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) 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 = [] for root in specs: for s in root.traverse(): - if s.virtual: - continue if s.concrete: reusable.append(s) + elif spack.repo.PATH.is_virtual(s.name): + continue spack.spec.Spec.ensure_valid_variants(s) return reusable diff --git a/lib/spack/spack/solver/input_analysis.py b/lib/spack/spack/solver/input_analysis.py index 16ecaea4495..61c45b2c8f1 100644 --- a/lib/spack/spack/solver/input_analysis.py +++ b/lib/spack/spack/solver/input_analysis.py @@ -381,7 +381,9 @@ def __init__( self.all_types = dt.LINK | dt.RUN | dt.BUILD 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]: """Returns the list of possible dependencies""" diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py index d78246daa46..9dba2cbdff1 100644 --- a/lib/spack/spack/spec.py +++ b/lib/spack/spack/spec.py @@ -1915,6 +1915,12 @@ def package_class(self): @property 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) @property @@ -3090,7 +3096,7 @@ def validate_or_raise(self): # FIXME: raise just the first one encountered for spec in self.traverse(): # 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) # validate compiler in addition to the package name. @@ -3099,7 +3105,7 @@ def validate_or_raise(self): raise UnsupportedCompilerError(spec.compiler.name) # 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) 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 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 lhs = spack.repo.PATH.providers_for(str(self)) 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) # A provider can satisfy a virtual dependency. - elif self.virtual or other.virtual: - virtual_spec, non_virtual_spec = (self, other) if self.virtual else (other, self) + elif self_virtual or other_virtual: + virtual_spec, non_virtual_spec = (self, other) if self_virtual else (other, self) try: # Here we might get an abstract spec 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 self.name != other.name and self.name and other.name: # 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: # Here we might get an abstract spec 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) 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: + if spack.repo.PATH.is_virtual(rhs_edge.spec.name): rhs_edge.update_virtuals(virtuals=(rhs_edge.spec.name,)) if not rhs_edge.virtuals: @@ -3562,7 +3572,7 @@ def satisfies(self, other: Union[str, "Spec"], deps: bool = True) -> bool: def virtual_dependencies(self): """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 def patches(self): @@ -4850,7 +4860,9 @@ def reconstruct_virtuals_on_edges(spec): possible_virtuals = set() for node in spec.traverse(): 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: warnings.warn(f"cannot reconstruct virtual dependencies on package {node.name}: {e}") continue