diff --git a/lib/spack/spack/ci.py b/lib/spack/spack/ci.py index 56d1980a3ac..978065489f5 100644 --- a/lib/spack/spack/ci.py +++ b/lib/spack/spack/ci.py @@ -33,7 +33,6 @@ import spack import spack.binary_distribution as bindist import spack.builder -import spack.concretize import spack.config as cfg import spack.error import spack.main @@ -41,6 +40,7 @@ import spack.mirrors.utils import spack.paths import spack.repo +import spack.solver.asp import spack.spec import spack.util.git import spack.util.gpg as gpg_util @@ -707,7 +707,7 @@ def generate_gitlab_ci_yaml( files (spack.yaml, spack.lock), etc should be written. GitLab requires this to be within the project directory. """ - with spack.concretize.disable_compiler_existence_check(): + with spack.solver.asp.disable_compiler_existence_check(): with env.write_transaction(): env.concretize() env.write() diff --git a/lib/spack/spack/cmd/mirror.py b/lib/spack/spack/cmd/mirror.py index 309a82423c1..fc96ffdb862 100644 --- a/lib/spack/spack/cmd/mirror.py +++ b/lib/spack/spack/cmd/mirror.py @@ -17,6 +17,7 @@ import spack.mirrors.mirror import spack.mirrors.utils import spack.repo +import spack.solver.asp import spack.spec import spack.util.web as web_util from spack.cmd.common import arguments @@ -516,7 +517,7 @@ def extend_with_dependencies(specs): def concrete_specs_from_cli_or_file(args): tty.msg("Concretizing input specs") - with spack.concretize.disable_compiler_existence_check(): + with spack.solver.asp.disable_compiler_existence_check(): if args.specs: specs = spack.cmd.parse_specs(args.specs, concretize=True) if not specs: diff --git a/lib/spack/spack/concretize.py b/lib/spack/spack/concretize.py index 3a374658e0c..6faf5d7854a 100644 --- a/lib/spack/spack/concretize.py +++ b/lib/spack/spack/concretize.py @@ -5,8 +5,7 @@ """High-level functions to concretize list of specs""" import sys import time -from contextlib import contextmanager -from typing import Iterable, Optional, Sequence, Tuple, Union +from typing import Iterable, Sequence, Tuple, Union import llnl.util.tty as tty @@ -15,26 +14,7 @@ import spack.error import spack.repo import spack.util.parallel -from spack.spec import ArchSpec, CompilerSpec, Spec - -CHECK_COMPILER_EXISTENCE = True - - -@contextmanager -def disable_compiler_existence_check(): - global CHECK_COMPILER_EXISTENCE - CHECK_COMPILER_EXISTENCE, saved = False, CHECK_COMPILER_EXISTENCE - yield - CHECK_COMPILER_EXISTENCE = saved - - -@contextmanager -def enable_compiler_existence_check(): - global CHECK_COMPILER_EXISTENCE - CHECK_COMPILER_EXISTENCE, saved = True, CHECK_COMPILER_EXISTENCE - yield - CHECK_COMPILER_EXISTENCE = saved - +from spack.spec import Spec SpecPair = Tuple[Spec, Spec] SpecLike = Union[Spec, str] @@ -51,11 +31,10 @@ def concretize_specs_together( tests: list of package names for which to consider tests dependencies. If True, all nodes will have test dependencies. If False, test dependencies will be disregarded. """ - import spack.solver.asp + from spack.solver.asp import Solver allow_deprecated = spack.config.get("config:deprecated", False) - solver = spack.solver.asp.Solver() - result = solver.solve(abstract_specs, tests=tests, allow_deprecated=allow_deprecated) + result = Solver().solve(abstract_specs, tests=tests, allow_deprecated=allow_deprecated) return [s.copy() for s in result.specs] @@ -90,7 +69,7 @@ def concretize_together_when_possible( tests: list of package names for which to consider tests dependencies. If True, all nodes will have test dependencies. If False, test dependencies will be disregarded. """ - import spack.solver.asp + from spack.solver.asp import Solver to_concretize = [concrete if concrete else abstract for abstract, concrete in spec_list] old_concrete_to_abstract = { @@ -98,9 +77,8 @@ def concretize_together_when_possible( } result_by_user_spec = {} - solver = spack.solver.asp.Solver() allow_deprecated = spack.config.get("config:deprecated", False) - for result in solver.solve_in_rounds( + for result in Solver().solve_in_rounds( to_concretize, tests=tests, allow_deprecated=allow_deprecated ): result_by_user_spec.update(result.specs_by_input) @@ -124,7 +102,7 @@ def concretize_separately( tests: list of package names for which to consider tests dependencies. If True, all nodes will have test dependencies. If False, test dependencies will be disregarded. """ - import spack.bootstrap + from spack.bootstrap import ensure_bootstrap_configuration, ensure_clingo_importable_or_raise to_concretize = [abstract for abstract, concrete in spec_list if not concrete] args = [ @@ -134,8 +112,8 @@ def concretize_separately( ] ret = [(i, abstract) for i, abstract in enumerate(to_concretize) if abstract.concrete] # Ensure we don't try to bootstrap clingo in parallel - with spack.bootstrap.ensure_bootstrap_configuration(): - spack.bootstrap.ensure_clingo_importable_or_raise() + with ensure_bootstrap_configuration(): + ensure_clingo_importable_or_raise() # Ensure all the indexes have been built or updated, since # otherwise the processes in the pool may timeout on waiting @@ -201,6 +179,8 @@ def concretized(spec: Spec, tests: Union[bool, Iterable[str]] = False) -> Spec: tests: if False disregard 'test' dependencies, if a list of names activate them for the packages in the list, if True activate 'test' dependencies for all packages. """ + from spack.solver.asp import Solver, SpecBuilder + spec.replace_hash() for node in spec.traverse(): @@ -213,8 +193,7 @@ def concretized(spec: Spec, tests: Union[bool, Iterable[str]] = False) -> Spec: return spec.copy() allow_deprecated = spack.config.get("config:deprecated", False) - solver = spack.solver.asp.Solver() - result = solver.solve([spec], tests=tests, allow_deprecated=allow_deprecated) + result = Solver().solve([spec], tests=tests, allow_deprecated=allow_deprecated) # take the best answer opt, i, answer = min(result.answers) @@ -224,27 +203,10 @@ def concretized(spec: Spec, tests: Union[bool, Iterable[str]] = False) -> Spec: providers = [s.name for s in answer.values() if s.package.provides(name)] name = providers[0] - node = spack.solver.asp.SpecBuilder.make_node(pkg=name) + node = SpecBuilder.make_node(pkg=name) assert ( node in answer ), f"cannot find {name} in the list of specs {','.join([n.pkg for n in answer.keys()])}" concretized = answer[node] return concretized - - -class UnavailableCompilerVersionError(spack.error.SpackError): - """Raised when there is no available compiler that satisfies a - compiler spec.""" - - def __init__(self, compiler_spec: CompilerSpec, arch: Optional[ArchSpec] = None) -> None: - err_msg = f"No compilers with spec {compiler_spec} found" - if arch: - err_msg += f" for operating system {arch.os} and target {arch.target}." - - super().__init__( - err_msg, - "Run 'spack compiler find' to add compilers or " - "'spack compilers' to see which compilers are already recognized" - " by spack.", - ) diff --git a/lib/spack/spack/solver/asp.py b/lib/spack/spack/solver/asp.py index 436776e2721..61a494e974c 100644 --- a/lib/spack/spack/solver/asp.py +++ b/lib/spack/spack/solver/asp.py @@ -29,7 +29,6 @@ import spack.binary_distribution import spack.compiler import spack.compilers -import spack.concretize import spack.config import spack.deptypes as dt import spack.environment as ev @@ -48,6 +47,7 @@ import spack.version as vn import spack.version.git_ref_lookup from spack import traverse +from spack.spec import ArchSpec, CompilerSpec from .core import ( AspFunction, @@ -66,6 +66,8 @@ from .requirements import RequirementKind, RequirementParser, RequirementRule from .version_order import concretization_version_order +CHECK_COMPILER_EXISTENCE = True + GitOrStandardVersion = Union[spack.version.GitVersion, spack.version.StandardVersion] TransformFunction = Callable[["spack.spec.Spec", List[AspFunction]], List[AspFunction]] @@ -3103,7 +3105,6 @@ def with_input_specs(self, input_specs: List["spack.spec.Spec"]) -> "CompilerPar Args: input_specs: specs to be concretized """ - strict = spack.concretize.CHECK_COMPILER_EXISTENCE default_os = str(spack.platforms.host().default_os) default_target = str(archspec.cpu.host().family) for s in traverse.traverse_nodes(input_specs): @@ -3117,8 +3118,8 @@ def with_input_specs(self, input_specs: List["spack.spec.Spec"]) -> "CompilerPar continue # Error when a compiler is not found and strict mode is enabled - if strict: - raise spack.concretize.UnavailableCompilerVersionError(s.compiler) + if CHECK_COMPILER_EXISTENCE: + raise UnavailableCompilerVersionError(s.compiler) # Make up a compiler matching the input spec. This is for bootstrapping. compiler_cls = spack.compilers.class_for_compiler_name(s.compiler.name) @@ -4012,6 +4013,22 @@ def _specs_from_environment_included_concrete(env, included_concrete): return [] +@contextmanager +def disable_compiler_existence_check(): + global CHECK_COMPILER_EXISTENCE + CHECK_COMPILER_EXISTENCE, saved = False, CHECK_COMPILER_EXISTENCE + yield + CHECK_COMPILER_EXISTENCE = saved + + +@contextmanager +def enable_compiler_existence_check(): + global CHECK_COMPILER_EXISTENCE + CHECK_COMPILER_EXISTENCE, saved = True, CHECK_COMPILER_EXISTENCE + yield + CHECK_COMPILER_EXISTENCE = saved + + class ReuseStrategy(enum.Enum): ROOTS = enum.auto() DEPENDENCIES = enum.auto() @@ -4295,3 +4312,20 @@ def __init__(self, provided, conflicts): class InvalidSpliceError(spack.error.SpackError): """For cases in which the splice configuration is invalid.""" + + +class UnavailableCompilerVersionError(spack.error.SpackError): + """Raised when there is no available compiler that satisfies a + compiler spec.""" + + def __init__(self, compiler_spec: CompilerSpec, arch: Optional[ArchSpec] = None) -> None: + err_msg = f"No compilers with spec {compiler_spec} found" + if arch: + err_msg += f" for operating system {arch.os} and target {arch.target}." + + super().__init__( + err_msg, + "Run 'spack compiler find' to add compilers or " + "'spack compilers' to see which compilers are already recognized" + " by spack.", + ) diff --git a/lib/spack/spack/test/architecture.py b/lib/spack/spack/test/architecture.py index 7919589fa82..811827ad259 100644 --- a/lib/spack/spack/test/architecture.py +++ b/lib/spack/spack/test/architecture.py @@ -11,6 +11,7 @@ import spack.concretize import spack.operating_systems import spack.platforms +import spack.solver.asp from spack.spec import ArchSpec, Spec @@ -133,6 +134,6 @@ def test_concretize_target_ranges(root_target_range, dep_target_range, result, m spec = Spec( f"pkg-a %gcc@10 foobar=bar target={root_target_range} ^pkg-b target={dep_target_range}" ) - with spack.concretize.disable_compiler_existence_check(): + with spack.solver.asp.disable_compiler_existence_check(): spec = spack.concretize.concretized(spec) assert spec.target == spec["pkg-b"].target == result diff --git a/lib/spack/spack/test/concretization/core.py b/lib/spack/spack/test/concretization/core.py index 14f33682321..bb740d6d7c9 100644 --- a/lib/spack/spack/test/concretization/core.py +++ b/lib/spack/spack/test/concretization/core.py @@ -348,11 +348,11 @@ def test_concretize_with_restricted_virtual(self): assert concrete["mpich2"].satisfies("mpich2@1.3.1:1.4") def test_concretize_enable_disable_compiler_existence_check(self): - with spack.concretize.enable_compiler_existence_check(): - with pytest.raises(spack.concretize.UnavailableCompilerVersionError): + with spack.solver.asp.enable_compiler_existence_check(): + with pytest.raises(spack.solver.asp.UnavailableCompilerVersionError): check_concretize("dttop %gcc@=100.100") - with spack.concretize.disable_compiler_existence_check(): + with spack.solver.asp.disable_compiler_existence_check(): spec = check_concretize("dttop %gcc@=100.100") assert spec.satisfies("%gcc@100.100") assert spec["dtlink3"].satisfies("%gcc@100.100") @@ -723,9 +723,9 @@ def test_concretize_propagate_variant_second_level_dep_not_in_source(self): def test_no_matching_compiler_specs(self, mock_low_high_config): # only relevant when not building compilers as needed - with spack.concretize.enable_compiler_existence_check(): + with spack.solver.asp.enable_compiler_existence_check(): s = Spec("pkg-a %gcc@=0.0.0") - with pytest.raises(spack.concretize.UnavailableCompilerVersionError): + with pytest.raises(spack.solver.asp.UnavailableCompilerVersionError): s = spack.concretize.concretized(s) def test_no_compilers_for_arch(self): @@ -951,7 +951,7 @@ def test_adjusting_default_target_based_on_compiler( ): best_achievable = archspec.cpu.TARGETS[best_achievable] expected = best_achievable if best_achievable < current_host else current_host - with spack.concretize.disable_compiler_existence_check(): + with spack.solver.asp.disable_compiler_existence_check(): s = spack.concretize.concretized(Spec(spec)) assert str(s.architecture.target) == str(expected) @@ -966,7 +966,7 @@ def test_compiler_version_matches_any_entry_in_compilers_yaml(self): ) # This compiler does not exist - with pytest.raises(spack.concretize.UnavailableCompilerVersionError): + with pytest.raises(spack.solver.asp.UnavailableCompilerVersionError): spack.concretize.concretized(Spec("mpileaks %gcc@=10.2")) def test_concretize_anonymous(self): diff --git a/lib/spack/spack/test/solver/intermediate.py b/lib/spack/spack/test/solver/intermediate.py index f3d624cbd36..6215cac70f0 100644 --- a/lib/spack/spack/test/solver/intermediate.py +++ b/lib/spack/spack/test/solver/intermediate.py @@ -7,8 +7,8 @@ import spack.compilers import spack.spec -from spack.concretize import UnavailableCompilerVersionError from spack.solver import asp +from spack.solver.asp import UnavailableCompilerVersionError class TestCompilerParser: