diff options
author | Harmen Stoppels <me@harmenstoppels.nl> | 2024-09-19 23:25:36 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-09-19 23:25:36 +0200 |
commit | e4927b35d1d820545cb09c291bd3757131581a49 (patch) | |
tree | 81db5cf4a94f7aa243ccb74b9bb3c9fd0c2ceb79 | |
parent | 098ad7ffc0d0a5ac308741f3d85d3736446648e2 (diff) | |
download | spack-e4927b35d1d820545cb09c291bd3757131581a49.tar.gz spack-e4927b35d1d820545cb09c291bd3757131581a49.tar.bz2 spack-e4927b35d1d820545cb09c291bd3757131581a49.tar.xz spack-e4927b35d1d820545cb09c291bd3757131581a49.zip |
package_base: break dependency on installer (#46423)
Removes `spack.package_base.PackageBase.do_{install,deprecate}` in favor of
`spack.installer.PackageInstaller.install` and `spack.installer.deprecate` resp.
That drops a dependency of `spack.package_base` on `spack.installer`, which is
necessary to get rid of circular dependencies in Spack.
Also change the signature of `PackageInstaller.__init__` from taking a dict as
positional argument, to an explicit list of keyword arguments.
29 files changed, 249 insertions, 196 deletions
diff --git a/lib/spack/spack/bootstrap/core.py b/lib/spack/spack/bootstrap/core.py index 9713e2866a..6f1d9fdb9d 100644 --- a/lib/spack/spack/bootstrap/core.py +++ b/lib/spack/spack/bootstrap/core.py @@ -46,6 +46,7 @@ import spack.util.path import spack.util.spack_yaml import spack.util.url import spack.version +from spack.installer import PackageInstaller from ._common import _executables_in_store, _python_import, _root_spec, _try_import_from_store from .clingo import ClingoBootstrapConcretizer @@ -277,7 +278,7 @@ class SourceBootstrapper(Bootstrapper): # Install the spec that should make the module importable with spack.config.override(self.mirror_scope): - concrete_spec.package.do_install(fail_fast=True) + PackageInstaller([concrete_spec.package], fail_fast=True).install() if _try_import_from_store(module, query_spec=concrete_spec, query_info=info): self.last_search = info @@ -300,7 +301,7 @@ class SourceBootstrapper(Bootstrapper): msg = "[BOOTSTRAP] Try installing '{0}' from sources" tty.debug(msg.format(abstract_spec_str)) with spack.config.override(self.mirror_scope): - concrete_spec.package.do_install() + PackageInstaller([concrete_spec.package], fail_fast=True).install() if _executables_in_store(executables, concrete_spec, query_info=info): self.last_search = info return True diff --git a/lib/spack/spack/cmd/deprecate.py b/lib/spack/spack/cmd/deprecate.py index d7c6c49338..abca550cca 100644 --- a/lib/spack/spack/cmd/deprecate.py +++ b/lib/spack/spack/cmd/deprecate.py @@ -20,6 +20,7 @@ from llnl.util.symlink import symlink import spack.cmd import spack.environment as ev +import spack.installer import spack.store from spack.cmd.common import arguments from spack.database import InstallStatuses @@ -142,4 +143,4 @@ def deprecate(parser, args): tty.die("Will not deprecate any packages.") for dcate, dcator in zip(all_deprecate, all_deprecators): - dcate.package.do_deprecate(dcator, symlink) + spack.installer.deprecate(dcate, dcator, symlink) diff --git a/lib/spack/spack/cmd/dev_build.py b/lib/spack/spack/cmd/dev_build.py index b289d07dc9..696c16f4dc 100644 --- a/lib/spack/spack/cmd/dev_build.py +++ b/lib/spack/spack/cmd/dev_build.py @@ -14,6 +14,7 @@ import spack.cmd.common.arguments import spack.config import spack.repo from spack.cmd.common import arguments +from spack.installer import PackageInstaller description = "developer build: build from code in current working directory" section = "build" @@ -131,9 +132,9 @@ def dev_build(self, args): elif args.test == "root": tests = [spec.name for spec in specs] - spec.package.do_install( + PackageInstaller( + [spec.package], tests=tests, - make_jobs=args.jobs, keep_prefix=args.keep_prefix, install_deps=not args.ignore_deps, verbose=not args.quiet, @@ -141,7 +142,7 @@ def dev_build(self, args): stop_before=args.before, skip_patch=args.skip_patch, stop_at=args.until, - ) + ).install() # drop into the build environment of the package? if args.shell is not None: diff --git a/lib/spack/spack/cmd/install.py b/lib/spack/spack/cmd/install.py index 27b2ededcd..5040032f2b 100644 --- a/lib/spack/spack/cmd/install.py +++ b/lib/spack/spack/cmd/install.py @@ -474,5 +474,5 @@ def install_without_active_env(args, install_kwargs, reporter_factory): installs = [s.package for s in concrete_specs] install_kwargs["explicit"] = [s.dag_hash() for s in concrete_specs] - builder = PackageInstaller(installs, install_kwargs) + builder = PackageInstaller(installs, **install_kwargs) builder.install() diff --git a/lib/spack/spack/environment/environment.py b/lib/spack/spack/environment/environment.py index 2a22a76abe..900fd3f072 100644 --- a/lib/spack/spack/environment/environment.py +++ b/lib/spack/spack/environment/environment.py @@ -1967,7 +1967,7 @@ class Environment: ) install_args["explicit"] = explicit - PackageInstaller([spec.package for spec in specs], install_args).install() + PackageInstaller([spec.package for spec in specs], **install_args).install() def all_specs_generator(self) -> Iterable[Spec]: """Returns a generator for all concrete specs""" diff --git a/lib/spack/spack/installer.py b/lib/spack/spack/installer.py index fd46b9006d..e73fa1dc1f 100644 --- a/lib/spack/spack/installer.py +++ b/lib/spack/spack/installer.py @@ -37,7 +37,7 @@ import sys import time from collections import defaultdict from gzip import GzipFile -from typing import Dict, Iterator, List, Optional, Set, Tuple +from typing import Dict, Iterator, List, Optional, Set, Tuple, Union import llnl.util.filesystem as fs import llnl.util.lock as lk @@ -1053,8 +1053,87 @@ class PackageInstaller: """ def __init__( - self, packages: List["spack.package_base.PackageBase"], install_args: dict + self, + packages: List["spack.package_base.PackageBase"], + *, + cache_only: bool = False, + dependencies_cache_only: bool = False, + dependencies_use_cache: bool = True, + dirty: bool = False, + explicit: Union[Set[str], bool] = False, + overwrite: Optional[Union[List[str], Set[str]]] = None, + fail_fast: bool = False, + fake: bool = False, + include_build_deps: bool = False, + install_deps: bool = True, + install_package: bool = True, + install_source: bool = False, + keep_prefix: bool = False, + keep_stage: bool = False, + package_cache_only: bool = False, + package_use_cache: bool = True, + restage: bool = False, + skip_patch: bool = False, + stop_at: Optional[str] = None, + stop_before: Optional[str] = None, + tests: Union[bool, List[str], Set[str]] = False, + unsigned: Optional[bool] = None, + use_cache: bool = False, + verbose: bool = False, ) -> None: + """ + Arguments: + explicit: Set of package hashes to be marked as installed explicitly in the db. If + True, the specs from ``packages`` are marked explicit, while their dependencies are + not. + fail_fast: Fail if any dependency fails to install; otherwise, the default is to + install as many dependencies as possible (i.e., best effort installation). + fake: Don't really build; install fake stub files instead. + install_deps: Install dependencies before installing this package + install_source: By default, source is not installed, but for debugging it might be + useful to keep it around. + keep_prefix: Keep install prefix on failure. By default, destroys it. + keep_stage: By default, stage is destroyed only if there are no exceptions during + build. Set to True to keep the stage even with exceptions. + restage: Force spack to restage the package source. + skip_patch: Skip patch stage of build if True. + stop_before: stop execution before this installation phase (or None) + stop_at: last installation phase to be executed (or None) + tests: False to run no tests, True to test all packages, or a list of package names to + run tests for some + use_cache: Install from binary package, if available. + verbose: Display verbose build output (by default, suppresses it) + """ + if isinstance(explicit, bool): + explicit = {pkg.spec.dag_hash() for pkg in packages} if explicit else set() + + install_args = { + "cache_only": cache_only, + "dependencies_cache_only": dependencies_cache_only, + "dependencies_use_cache": dependencies_use_cache, + "dirty": dirty, + "explicit": explicit, + "fail_fast": fail_fast, + "fake": fake, + "include_build_deps": include_build_deps, + "install_deps": install_deps, + "install_package": install_package, + "install_source": install_source, + "keep_prefix": keep_prefix, + "keep_stage": keep_stage, + "overwrite": overwrite or [], + "package_cache_only": package_cache_only, + "package_use_cache": package_use_cache, + "restage": restage, + "skip_patch": skip_patch, + "stop_at": stop_at, + "stop_before": stop_before, + "tests": tests, + "unsigned": unsigned, + "use_cache": use_cache, + "verbose": verbose, + } + # List of build requests self.build_requests = [BuildRequest(pkg, install_args) for pkg in packages] @@ -1518,8 +1597,8 @@ class PackageInstaller: spack.store.STORE.db.add(pkg.spec, explicit=explicit) except spack.error.StopPhase as e: - # A StopPhase exception means that do_install was asked to - # stop early from clients, and is not an error at this point + # A StopPhase exception means that the installer was asked to stop early from clients, + # and is not an error at this point pid = f"{self.pid}: " if tty.show_pid() else "" tty.debug(f"{pid}{str(e)}") tty.debug(f"Package stage directory: {pkg.stage.source_path}") @@ -2070,7 +2149,7 @@ class BuildProcessInstaller: Arguments: pkg: the package being installed. - install_args: arguments to do_install() from parent process. + install_args: arguments to the installer from parent process. """ self.pkg = pkg @@ -2274,7 +2353,7 @@ def build_process(pkg: "spack.package_base.PackageBase", install_args: dict) -> Arguments: pkg: the package being installed. - install_args: arguments to do_install() from parent process. + install_args: arguments to installer from parent process. """ installer = BuildProcessInstaller(pkg, install_args) @@ -2284,6 +2363,33 @@ def build_process(pkg: "spack.package_base.PackageBase", install_args: dict) -> return installer.run() +def deprecate(spec: "spack.spec.Spec", deprecator: "spack.spec.Spec", link_fn) -> None: + """Deprecate this package in favor of deprecator spec""" + # Install deprecator if it isn't installed already + if not spack.store.STORE.db.query(deprecator): + PackageInstaller([deprecator.package], explicit=True).install() + + old_deprecator = spack.store.STORE.db.deprecator(spec) + if old_deprecator: + # Find this spec file from its old deprecation + specfile = spack.store.STORE.layout.deprecated_file_path(spec, old_deprecator) + else: + specfile = spack.store.STORE.layout.spec_file_path(spec) + + # copy spec metadata to "deprecated" dir of deprecator + depr_specfile = spack.store.STORE.layout.deprecated_file_path(spec, deprecator) + fs.mkdirp(os.path.dirname(depr_specfile)) + shutil.copy2(specfile, depr_specfile) + + # Any specs deprecated in favor of this spec are re-deprecated in favor of its new deprecator + for deprecated in spack.store.STORE.db.specs_deprecated_by(spec): + deprecate(deprecated, deprecator, link_fn) + + # Now that we've handled metadata, uninstall and replace with link + spack.package_base.PackageBase.uninstall_by_spec(spec, force=True, deprecator=deprecator) + link_fn(deprecator.prefix, spec.prefix) + + class OverwriteInstall: def __init__( self, diff --git a/lib/spack/spack/package_base.py b/lib/spack/spack/package_base.py index 5be23ff124..cc5f11cb72 100644 --- a/lib/spack/spack/package_base.py +++ b/lib/spack/spack/package_base.py @@ -19,7 +19,6 @@ import importlib import io import os import re -import shutil import sys import textwrap import time @@ -64,7 +63,6 @@ from spack.install_test import ( cache_extra_test_sources, install_test_root, ) -from spack.installer import PackageInstaller from spack.solver.version_order import concretization_version_order from spack.stage import DevelopStage, ResourceStage, Stage, StageComposite, compute_stage_name from spack.util.executable import ProcessError, which @@ -556,19 +554,16 @@ class PackageBase(WindowsRPath, PackageViewMixin, RedistributionMixin, metaclass There are two main parts of a Spack package: - 1. **The package class**. Classes contain ``directives``, which are - special functions, that add metadata (versions, patches, - dependencies, and other information) to packages (see - ``directives.py``). Directives provide the constraints that are - used as input to the concretizer. + 1. **The package class**. Classes contain ``directives``, which are special functions, that + add metadata (versions, patches, dependencies, and other information) to packages (see + ``directives.py``). Directives provide the constraints that are used as input to the + concretizer. - 2. **Package instances**. Once instantiated, a package is - essentially a software installer. Spack calls methods like - ``do_install()`` on the ``Package`` object, and it uses those to - drive user-implemented methods like ``patch()``, ``install()``, and - other build steps. To install software, an instantiated package - needs a *concrete* spec, which guides the behavior of the various - install methods. + 2. **Package instances**. Once instantiated, a package can be passed to the PackageInstaller. + It calls methods like ``do_stage()`` on the ``Package`` object, and it uses those to drive + user-implemented methods like ``patch()``, ``install()``, and other build steps. To + install software, an instantiated package needs a *concrete* spec, which guides the + behavior of the various install methods. Packages are imported from repos (see ``repo.py``). @@ -590,7 +585,6 @@ class PackageBase(WindowsRPath, PackageViewMixin, RedistributionMixin, metaclass p.do_fetch() # downloads tarball from a URL (or VCS) p.do_stage() # expands tarball in a temp directory p.do_patch() # applies patches to expanded source - p.do_install() # calls package's install() function p.do_uninstall() # removes install directory although packages that do not have code have nothing to fetch so omit @@ -1956,48 +1950,6 @@ class PackageBase(WindowsRPath, PackageViewMixin, RedistributionMixin, metaclass resource_stage_folder = "-".join(pieces) return resource_stage_folder - def do_install(self, **kwargs): - """Called by commands to install a package and or its dependencies. - - Package implementations should override install() to describe - their build process. - - Args: - cache_only (bool): Fail if binary package unavailable. - dirty (bool): Don't clean the build environment before installing. - explicit (bool): True if package was explicitly installed, False - if package was implicitly installed (as a dependency). - fail_fast (bool): Fail if any dependency fails to install; - otherwise, the default is to install as many dependencies as - possible (i.e., best effort installation). - fake (bool): Don't really build; install fake stub files instead. - force (bool): Install again, even if already installed. - install_deps (bool): Install dependencies before installing this - package - install_source (bool): By default, source is not installed, but - for debugging it might be useful to keep it around. - keep_prefix (bool): Keep install prefix on failure. By default, - destroys it. - keep_stage (bool): By default, stage is destroyed only if there - are no exceptions during build. Set to True to keep the stage - even with exceptions. - restage (bool): Force spack to restage the package source. - skip_patch (bool): Skip patch stage of build if True. - stop_before (str): stop execution before this - installation phase (or None) - stop_at (str): last installation phase to be executed - (or None) - tests (bool or list or set): False to run no tests, True to test - all packages, or a list of package names to run tests for some - use_cache (bool): Install from binary package, if available. - verbose (bool): Display verbose build output (by default, - suppresses it) - """ - explicit = kwargs.get("explicit", True) - if isinstance(explicit, bool): - kwargs["explicit"] = {self.spec.dag_hash()} if explicit else set() - PackageInstaller([self], kwargs).install() - # TODO (post-34236): Update tests and all packages that use this as a # TODO (post-34236): package method to the routine made available to # TODO (post-34236): packages. Once done, remove this method. @@ -2454,35 +2406,6 @@ class PackageBase(WindowsRPath, PackageViewMixin, RedistributionMixin, metaclass # delegate to instance-less method. PackageBase.uninstall_by_spec(self.spec, force) - def do_deprecate(self, deprecator, link_fn): - """Deprecate this package in favor of deprecator spec""" - spec = self.spec - - # Install deprecator if it isn't installed already - if not spack.store.STORE.db.query(deprecator): - deprecator.package.do_install() - - old_deprecator = spack.store.STORE.db.deprecator(spec) - if old_deprecator: - # Find this specs yaml file from its old deprecation - self_yaml = spack.store.STORE.layout.deprecated_file_path(spec, old_deprecator) - else: - self_yaml = spack.store.STORE.layout.spec_file_path(spec) - - # copy spec metadata to "deprecated" dir of deprecator - depr_yaml = spack.store.STORE.layout.deprecated_file_path(spec, deprecator) - fsys.mkdirp(os.path.dirname(depr_yaml)) - shutil.copy2(self_yaml, depr_yaml) - - # Any specs deprecated in favor of this spec are re-deprecated in - # favor of its new deprecator - for deprecated in spack.store.STORE.db.specs_deprecated_by(spec): - deprecated.package.do_deprecate(deprecator, link_fn) - - # Now that we've handled metadata, uninstall and replace with link - PackageBase.uninstall_by_spec(spec, force=True, deprecator=deprecator) - link_fn(deprecator.prefix, spec.prefix) - def view(self): """Create a view with the prefix of this package as the root. Extensions added to this view will modify the installation prefix of diff --git a/lib/spack/spack/test/build_distribution.py b/lib/spack/spack/test/build_distribution.py index dc1e763e2a..5edcbe5673 100644 --- a/lib/spack/spack/test/build_distribution.py +++ b/lib/spack/spack/test/build_distribution.py @@ -11,13 +11,14 @@ import pytest import spack.binary_distribution as bd import spack.mirror import spack.spec +from spack.installer import PackageInstaller pytestmark = pytest.mark.not_on_windows("does not run on windows") def test_build_tarball_overwrite(install_mockery, mock_fetch, monkeypatch, tmp_path): spec = spack.spec.Spec("trivial-install-test-package").concretized() - spec.package.do_install(fake=True) + PackageInstaller([spec.package], fake=True).install() specs = [spec] diff --git a/lib/spack/spack/test/build_environment.py b/lib/spack/spack/test/build_environment.py index 8d7a09ab7e..c3ccaee029 100644 --- a/lib/spack/spack/test/build_environment.py +++ b/lib/spack/spack/test/build_environment.py @@ -21,6 +21,7 @@ import spack.spec import spack.util.spack_yaml as syaml from spack.build_environment import UseMode, _static_to_shared_library, dso_suffix from spack.context import Context +from spack.installer import PackageInstaller from spack.paths import build_env_path from spack.util.environment import EnvironmentModifications from spack.util.executable import Executable @@ -181,7 +182,7 @@ def test_setup_dependent_package_inherited_modules( ): # This will raise on regression s = spack.spec.Spec("cmake-client-inheritor").concretized() - s.package.do_install() + PackageInstaller([s.package]).install() @pytest.mark.parametrize( diff --git a/lib/spack/spack/test/build_systems.py b/lib/spack/spack/test/build_systems.py index a28742488a..212ec412d3 100644 --- a/lib/spack/spack/test/build_systems.py +++ b/lib/spack/spack/test/build_systems.py @@ -21,6 +21,7 @@ import spack.paths import spack.platforms import spack.platforms.test from spack.build_environment import ChildError, setup_package +from spack.installer import PackageInstaller from spack.spec import Spec from spack.util.executable import which @@ -144,7 +145,7 @@ class TestAutotoolsPackage: def test_libtool_archive_files_are_deleted_by_default(self, mutable_database): # Install a package that creates a mock libtool archive s = Spec("libtool-deletion").concretized() - s.package.do_install(explicit=True) + PackageInstaller([s.package], explicit=True).install() # Assert the libtool archive is not there and we have # a log of removed files @@ -160,7 +161,7 @@ class TestAutotoolsPackage: # patch its package to preserve the installation s = Spec("libtool-deletion").concretized() monkeypatch.setattr(type(s.package.builder), "install_libtool_archives", True) - s.package.do_install(explicit=True) + PackageInstaller([s.package], explicit=True).install() # Assert libtool archives are installed assert os.path.exists(s.package.builder.libtool_archive_file) @@ -171,7 +172,7 @@ class TestAutotoolsPackage: files from working alternatives from the gnuconfig package. """ s = Spec("autotools-config-replacement +patch_config_files +gnuconfig").concretized() - s.package.do_install() + PackageInstaller([s.package]).install() with open(os.path.join(s.prefix.broken, "config.sub")) as f: assert "gnuconfig version of config.sub" in f.read() @@ -190,7 +191,7 @@ class TestAutotoolsPackage: Tests whether disabling patch_config_files """ s = Spec("autotools-config-replacement ~patch_config_files +gnuconfig").concretized() - s.package.do_install() + PackageInstaller([s.package]).install() with open(os.path.join(s.prefix.broken, "config.sub")) as f: assert "gnuconfig version of config.sub" not in f.read() @@ -219,7 +220,7 @@ class TestAutotoolsPackage: msg = "Cannot patch config files: missing dependencies: gnuconfig" with pytest.raises(ChildError, match=msg): - s.package.do_install() + PackageInstaller([s.package]).install() @pytest.mark.disable_clean_stage_check def test_broken_external_gnuconfig(self, mutable_database, tmpdir): diff --git a/lib/spack/spack/test/cmd/buildcache.py b/lib/spack/spack/test/cmd/buildcache.py index 30c779e705..840dd61f1a 100644 --- a/lib/spack/spack/test/cmd/buildcache.py +++ b/lib/spack/spack/test/cmd/buildcache.py @@ -19,6 +19,7 @@ import spack.main import spack.mirror import spack.spec import spack.util.url +from spack.installer import PackageInstaller from spack.spec import Spec buildcache = spack.main.SpackCommand("buildcache") @@ -178,7 +179,7 @@ def test_buildcache_autopush(tmp_path, install_mockery, mock_fetch): s = Spec("libdwarf").concretized() # Install and generate build cache index - s.package.do_install() + PackageInstaller([s.package], explicit=True).install() metadata_file = spack.binary_distribution.tarball_name(s, ".spec.json") @@ -379,7 +380,7 @@ def test_correct_specs_are_pushed( things_to_install, expected, tmpdir, monkeypatch, default_mock_concretization, temporary_store ): spec = default_mock_concretization("dttop") - spec.package.do_install(fake=True) + PackageInstaller([spec.package], explicit=True, fake=True).install() slash_hash = f"/{spec.dag_hash()}" class DontUpload(spack.binary_distribution.Uploader): @@ -438,13 +439,13 @@ def test_push_and_install_with_mirror_marked_unsigned_does_not_require_extra_fla # Install if signed: # Need to pass "--no-check-signature" to avoid install errors - kwargs = {"cache_only": True, "unsigned": True} + kwargs = {"explicit": True, "cache_only": True, "unsigned": True} else: # No need to pass "--no-check-signature" if the mirror is unsigned - kwargs = {"cache_only": True} + kwargs = {"explicit": True, "cache_only": True} spec.package.do_uninstall(force=True) - spec.package.do_install(**kwargs) + PackageInstaller([spec.package], **kwargs).install() def test_skip_no_redistribute(mock_packages, config): @@ -489,7 +490,7 @@ def test_push_without_build_deps(tmp_path, temporary_store, mock_packages, mutab mirror("add", "--unsigned", "my-mirror", str(tmp_path)) s = spack.spec.Spec("dtrun3").concretized() - s.package.do_install(fake=True) + PackageInstaller([s.package], explicit=True, fake=True).install() s["dtbuild3"].package.do_uninstall() # fails when build deps are required diff --git a/lib/spack/spack/test/cmd/extensions.py b/lib/spack/spack/test/cmd/extensions.py index b97bfa8b06..082628cc34 100644 --- a/lib/spack/spack/test/cmd/extensions.py +++ b/lib/spack/spack/test/cmd/extensions.py @@ -6,6 +6,7 @@ import pytest +from spack.installer import PackageInstaller from spack.main import SpackCommand, SpackCommandError from spack.spec import Spec @@ -15,10 +16,7 @@ extensions = SpackCommand("extensions") @pytest.fixture def python_database(mock_packages, mutable_database): specs = [Spec(s).concretized() for s in ["python", "py-extension1", "py-extension2"]] - - for spec in specs: - spec.package.do_install(fake=True, explicit=True) - + PackageInstaller([s.package for s in specs], explicit=True, fake=True).install() yield diff --git a/lib/spack/spack/test/cmd/gc.py b/lib/spack/spack/test/cmd/gc.py index 883d37ae33..2eab41a4fb 100644 --- a/lib/spack/spack/test/cmd/gc.py +++ b/lib/spack/spack/test/cmd/gc.py @@ -11,6 +11,7 @@ import spack.environment as ev import spack.main import spack.spec import spack.traverse +from spack.installer import PackageInstaller gc = spack.main.SpackCommand("gc") add = spack.main.SpackCommand("add") @@ -27,7 +28,7 @@ def test_gc_without_build_dependency(mutable_database): def test_gc_with_build_dependency(mutable_database): s = spack.spec.Spec("simple-inheritance") s.concretize() - s.package.do_install(fake=True, explicit=True) + PackageInstaller([s.package], explicit=True, fake=True).install() assert "There are no unused specs." in gc("-yb") assert "Successfully uninstalled cmake" in gc("-y") @@ -38,7 +39,7 @@ def test_gc_with_build_dependency(mutable_database): def test_gc_with_environment(mutable_database, mutable_mock_env_path): s = spack.spec.Spec("simple-inheritance") s.concretize() - s.package.do_install(fake=True, explicit=True) + PackageInstaller([s.package], explicit=True, fake=True).install() e = ev.create("test_gc") with e: @@ -54,7 +55,7 @@ def test_gc_with_environment(mutable_database, mutable_mock_env_path): def test_gc_with_build_dependency_in_environment(mutable_database, mutable_mock_env_path): s = spack.spec.Spec("simple-inheritance") s.concretize() - s.package.do_install(fake=True, explicit=True) + PackageInstaller([s.package], explicit=True, fake=True).install() e = ev.create("test_gc") with e: @@ -106,7 +107,7 @@ def test_gc_except_any_environments(mutable_database, mutable_mock_env_path): def test_gc_except_specific_environments(mutable_database, mutable_mock_env_path): s = spack.spec.Spec("simple-inheritance") s.concretize() - s.package.do_install(fake=True, explicit=True) + PackageInstaller([s.package], explicit=True, fake=True).install() assert mutable_database.query_local("zmpi") @@ -133,7 +134,7 @@ def test_gc_except_nonexisting_dir_env(mutable_database, mutable_mock_env_path, def test_gc_except_specific_dir_env(mutable_database, mutable_mock_env_path, tmpdir): s = spack.spec.Spec("simple-inheritance") s.concretize() - s.package.do_install(fake=True, explicit=True) + PackageInstaller([s.package], explicit=True, fake=True).install() assert mutable_database.query_local("zmpi") diff --git a/lib/spack/spack/test/cmd/install.py b/lib/spack/spack/test/cmd/install.py index da85366165..13721b2a0d 100644 --- a/lib/spack/spack/test/cmd/install.py +++ b/lib/spack/spack/test/cmd/install.py @@ -28,6 +28,7 @@ import spack.installer import spack.package_base import spack.store from spack.error import SpackError, SpecSyntaxError +from spack.installer import PackageInstaller from spack.main import SpackCommand from spack.spec import Spec @@ -136,7 +137,7 @@ def test_package_output(tmpdir, capsys, install_mockery, mock_fetch): # when nested AND in pytest spec = Spec("printing-package").concretized() pkg = spec.package - pkg.do_install(verbose=True) + PackageInstaller([pkg], explicit=True, verbose=True).install() with gzip.open(pkg.install_log_path, "rt") as f: out = f.read() @@ -261,7 +262,7 @@ def test_install_commit(mock_git_version_info, install_mockery, mock_packages, m # Use the earliest commit in the respository spec = Spec(f"git-test-commit@{commits[-1]}").concretized() - spec.package.do_install() + PackageInstaller([spec.package], explicit=True).install() # Ensure first commit file contents were written installed = os.listdir(spec.prefix.bin) diff --git a/lib/spack/spack/test/cmd/module.py b/lib/spack/spack/test/cmd/module.py index e16c8edecb..759d1391c9 100644 --- a/lib/spack/spack/test/cmd/module.py +++ b/lib/spack/spack/test/cmd/module.py @@ -15,6 +15,7 @@ import spack.modules.lmod import spack.repo import spack.spec import spack.store +from spack.installer import PackageInstaller module = spack.main.SpackCommand("module") @@ -184,8 +185,8 @@ def test_setdefault_command(mutable_database, mutable_config): # Install two different versions of pkg-a other_spec, preferred = "pkg-a@1.0", "pkg-a@2.0" - spack.spec.Spec(other_spec).concretized().package.do_install(fake=True) - spack.spec.Spec(preferred).concretized().package.do_install(fake=True) + specs = [spack.spec.Spec(other_spec).concretized(), spack.spec.Spec(preferred).concretized()] + PackageInstaller([s.package for s in specs], explicit=True, fake=True).install() writers = { preferred: writer_cls(spack.spec.Spec(preferred).concretized(), "default"), diff --git a/lib/spack/spack/test/cmd/tags.py b/lib/spack/spack/test/cmd/tags.py index 7de107c923..0e8e7f0165 100644 --- a/lib/spack/spack/test/cmd/tags.py +++ b/lib/spack/spack/test/cmd/tags.py @@ -6,6 +6,7 @@ import spack.main import spack.repo import spack.spec +from spack.installer import PackageInstaller tags = spack.main.SpackCommand("tags") @@ -48,7 +49,7 @@ def test_tags_no_tags(monkeypatch): def test_tags_installed(install_mockery, mock_fetch): s = spack.spec.Spec("mpich").concretized() - s.package.do_install() + PackageInstaller([s.package], explicit=True, fake=True).install() out = tags("-i") for tag in ["tag1", "tag2"]: diff --git a/lib/spack/spack/test/cmd/view.py b/lib/spack/spack/test/cmd/view.py index f385a69e85..6c349fe68c 100644 --- a/lib/spack/spack/test/cmd/view.py +++ b/lib/spack/spack/test/cmd/view.py @@ -8,6 +8,7 @@ import os.path import pytest import spack.util.spack_yaml as s_yaml +from spack.installer import PackageInstaller from spack.main import SpackCommand from spack.spec import Spec @@ -180,7 +181,7 @@ def test_view_files_not_ignored( ): spec = Spec("view-not-ignored").concretized() pkg = spec.package - pkg.do_install() + PackageInstaller([pkg], explicit=True).install() pkg.assert_installed(spec.prefix) install("view-file") # Arbitrary package to add noise diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py index ef004272a7..9f4d411aec 100644 --- a/lib/spack/spack/test/concretize.py +++ b/lib/spack/spack/test/concretize.py @@ -33,6 +33,7 @@ import spack.store import spack.util.file_cache import spack.variant as vt from spack.concretize import find_spec +from spack.installer import PackageInstaller from spack.spec import CompilerSpec, Spec from spack.version import Version, VersionList, ver @@ -1319,7 +1320,7 @@ class TestConcretize: # Install a spec root = Spec("root").concretized() dependency = root["changing"].copy() - root.package.do_install(fake=True, explicit=True) + PackageInstaller([root.package], fake=True, explicit=True).install() # Modify package.py repo_with_changing_recipe.change(context) @@ -1345,7 +1346,7 @@ class TestConcretize: # Install a spec for which the `version_based` variant condition does not hold old = Spec("conditional-variant-pkg @1").concretized() - old.package.do_install(fake=True, explicit=True) + PackageInstaller([old.package], fake=True, explicit=True).install() # Then explicitly require a spec with `+version_based`, which shouldn't reuse previous spec new1 = Spec("conditional-variant-pkg +version_based").concretized() @@ -1357,7 +1358,7 @@ class TestConcretize: def test_reuse_with_flags(self, mutable_database, mutable_config): spack.config.set("concretizer:reuse", True) spec = Spec("pkg-a cflags=-g cxxflags=-g").concretized() - spec.package.do_install(fake=True) + PackageInstaller([spec.package], fake=True, explicit=True).install() testspec = Spec("pkg-a cflags=-g") testspec.concretize() @@ -1658,7 +1659,7 @@ class TestConcretize: declared in package.py """ root = Spec("root").concretized() - root.package.do_install(fake=True, explicit=True) + PackageInstaller([root.package], fake=True, explicit=True).install() repo_with_changing_recipe.change({"delete_version": True}) with spack.config.override("concretizer:reuse", True): @@ -1676,7 +1677,7 @@ class TestConcretize: # Install a dependency that cannot be reused with "root" # because of a conflict in a variant, then delete its version dependency = Spec("changing@1.0~foo").concretized() - dependency.package.do_install(fake=True, explicit=True) + PackageInstaller([dependency.package], fake=True, explicit=True).install() repo_with_changing_recipe.change({"delete_version": True}) with spack.config.override("concretizer:reuse", True): @@ -1691,7 +1692,7 @@ class TestConcretize: with spack.repo.use_repositories(mock_custom_repository, override=False): s = Spec("pkg-c").concretized() assert s.namespace != "builtin.mock" - s.package.do_install(fake=True, explicit=True) + PackageInstaller([s.package], fake=True, explicit=True).install() with spack.config.override("concretizer:reuse", True): s = Spec("pkg-c").concretized() @@ -1703,7 +1704,7 @@ class TestConcretize: myrepo.add_package("zlib") builtin = Spec("zlib").concretized() - builtin.package.do_install(fake=True, explicit=True) + PackageInstaller([builtin.package], fake=True, explicit=True).install() with spack.repo.use_repositories(myrepo.root, override=False): with spack.config.override("concretizer:reuse", True): @@ -1718,7 +1719,7 @@ class TestConcretize: with spack.repo.use_repositories(builder.root, override=False): s = Spec("pkg-c").concretized() assert s.namespace == "myrepo" - s.package.do_install(fake=True, explicit=True) + PackageInstaller([s.package], fake=True, explicit=True).install() del sys.modules["spack.pkg.myrepo.pkg-c"] del sys.modules["spack.pkg.myrepo"] @@ -1936,7 +1937,7 @@ class TestConcretize: # Install the external spec external1 = Spec("changing@1.0").concretized() - external1.package.do_install(fake=True, explicit=True) + PackageInstaller([external1.package], fake=True, explicit=True).install() assert external1.external # Modify the package.py file @@ -2309,7 +2310,7 @@ class TestConcretize: """ s = Spec("py-extension1").concretized() python_hash = s["python"].dag_hash() - s.package.do_install(fake=True, explicit=True) + PackageInstaller([s.package], fake=True, explicit=True).install() with spack.config.override("concretizer:reuse", True): with_reuse = Spec(f"py-extension2 ^/{python_hash}").concretized() @@ -3023,7 +3024,7 @@ def test_spec_filters(specs, include, exclude, expected): @pytest.mark.regression("38484") def test_git_ref_version_can_be_reused(install_mockery, do_not_check_runtimes_on_reuse): first_spec = spack.spec.Spec("git-ref-package@git.2.1.5=2.1.5~opt").concretized() - first_spec.package.do_install(fake=True, explicit=True) + PackageInstaller([first_spec.package], fake=True, explicit=True).install() with spack.config.override("concretizer:reuse", True): # reproducer of the issue is that spack will solve when there is a change to the base spec @@ -3047,10 +3048,10 @@ def test_reuse_prefers_standard_over_git_versions( so install git ref last and ensure it is not picked up by reuse """ standard_spec = spack.spec.Spec(f"git-ref-package@{standard_version}").concretized() - standard_spec.package.do_install(fake=True, explicit=True) + PackageInstaller([standard_spec.package], fake=True, explicit=True).install() git_spec = spack.spec.Spec("git-ref-package@git.2.1.5=2.1.5").concretized() - git_spec.package.do_install(fake=True, explicit=True) + PackageInstaller([git_spec.package], fake=True, explicit=True).install() with spack.config.override("concretizer:reuse", True): test_spec = spack.spec.Spec("git-ref-package@2").concretized() diff --git a/lib/spack/spack/test/concretize_requirements.py b/lib/spack/spack/test/concretize_requirements.py index aef8d0ed5c..be66b2b0a8 100644 --- a/lib/spack/spack/test/concretize_requirements.py +++ b/lib/spack/spack/test/concretize_requirements.py @@ -14,6 +14,7 @@ import spack.repo import spack.solver.asp import spack.util.spack_yaml as syaml import spack.version +from spack.installer import PackageInstaller from spack.solver.asp import InternalConcretizerError, UnsatisfiableSpecError from spack.spec import Spec from spack.util.url import path_to_file_url @@ -436,7 +437,7 @@ packages: store_dir = tmp_path / "store" with spack.store.use_store(str(store_dir)): s1 = Spec("y@2.5 ~shared").concretized() - s1.package.do_install(fake=True, explicit=True) + PackageInstaller([s1.package], fake=True, explicit=True).install() update_packages_config(conf_str) diff --git a/lib/spack/spack/test/conftest.py b/lib/spack/spack/test/conftest.py index 2726061cb3..dc53f50688 100644 --- a/lib/spack/spack/test/conftest.py +++ b/lib/spack/spack/test/conftest.py @@ -61,6 +61,7 @@ import spack.util.url as url_util import spack.util.web import spack.version from spack.fetch_strategy import URLFetchStrategy +from spack.installer import PackageInstaller from spack.util.pattern import Bunch @@ -852,7 +853,7 @@ def _populate(mock_db): def _install(spec): s = spack.spec.Spec(spec).concretized() - s.package.do_install(fake=True, explicit=True) + PackageInstaller([s.package], fake=True, explicit=True).install() _install("mpileaks ^mpich") _install("mpileaks ^mpich2") diff --git a/lib/spack/spack/test/database.py b/lib/spack/spack/test/database.py index e34c85a788..6fd7575ffc 100644 --- a/lib/spack/spack/test/database.py +++ b/lib/spack/spack/test/database.py @@ -34,6 +34,7 @@ import spack.repo import spack.spec import spack.store import spack.version as vn +from spack.installer import PackageInstaller from spack.schema.database_index import schema from spack.util.executable import Executable @@ -385,7 +386,7 @@ def _check_remove_and_add_package(database: spack.database.Database, spec): def _mock_install(spec: str): s = spack.spec.Spec(spec).concretized() - s.package.do_install(fake=True) + PackageInstaller([s.package], fake=True, explicit=True).install() def _mock_remove(spec): @@ -713,7 +714,7 @@ def test_external_entries_in_db(mutable_database): assert not rec.spec.external_modules assert rec.explicit is False - rec.spec.package.do_install(fake=True, explicit=True) + PackageInstaller([rec.spec.package], fake=True, explicit=True).install() rec = mutable_database.get_record("externaltool") assert rec.spec.external_path == os.path.sep + os.path.join("path", "to", "external_tool") assert not rec.spec.external_modules @@ -731,7 +732,7 @@ def test_regression_issue_8036(mutable_database, usr_folder_exists): assert not s.installed # Now install the external package and check again the `installed` property - s.package.do_install(fake=True) + PackageInstaller([s.package], fake=True, explicit=True).install() assert s.installed @@ -774,7 +775,7 @@ def test_query_unused_specs(mutable_database): # This spec installs a fake cmake as a build only dependency s = spack.spec.Spec("simple-inheritance") s.concretize() - s.package.do_install(fake=True, explicit=True) + PackageInstaller([s.package], fake=True, explicit=True).install() si = s.dag_hash() ml_mpich = spack.store.STORE.db.query_one("mpileaks ^mpich").dag_hash() @@ -817,7 +818,7 @@ def test_query_spec_with_conditional_dependency(mutable_database): # conditional on a Boolean variant s = spack.spec.Spec("hdf5~mpi") s.concretize() - s.package.do_install(fake=True, explicit=True) + PackageInstaller([s.package], fake=True, explicit=True).install() results = spack.store.STORE.db.query_local("hdf5 ^mpich") assert not results @@ -1144,7 +1145,7 @@ def test_reindex_with_upstreams(tmp_path, monkeypatch, mock_packages, config): {"config": {"install_tree": {"root": str(tmp_path / "upstream")}}} ) monkeypatch.setattr(spack.store, "STORE", upstream_store) - callpath.package.do_install(fake=True) + PackageInstaller([callpath.package], fake=True, explicit=True).install() local_store = spack.store.create( { @@ -1153,7 +1154,7 @@ def test_reindex_with_upstreams(tmp_path, monkeypatch, mock_packages, config): } ) monkeypatch.setattr(spack.store, "STORE", local_store) - mpileaks.package.do_install(fake=True) + PackageInstaller([mpileaks.package], fake=True, explicit=True).install() # Sanity check that callpath is from upstream. assert not local_store.db.query_local("callpath") @@ -1163,7 +1164,7 @@ def test_reindex_with_upstreams(tmp_path, monkeypatch, mock_packages, config): # checks local installs before upstream databases, even when the local database is being # reindexed. monkeypatch.setattr(spack.store, "STORE", upstream_store) - mpileaks.package.do_install(fake=True) + PackageInstaller([mpileaks.package], fake=True, explicit=True).install() # Delete the local database shutil.rmtree(local_store.db.database_directory) diff --git a/lib/spack/spack/test/install.py b/lib/spack/spack/test/install.py index ba7084960a..efaa7cc171 100644 --- a/lib/spack/spack/test/install.py +++ b/lib/spack/spack/test/install.py @@ -24,6 +24,7 @@ import spack.store import spack.util.spack_json as sjson from spack import binary_distribution from spack.error import InstallError +from spack.installer import PackageInstaller from spack.package_base import ( PackageBase, PackageStillNeededError, @@ -42,7 +43,7 @@ def find_nothing(*args): def test_install_and_uninstall(install_mockery, mock_fetch, monkeypatch): spec = Spec("trivial-install-test-package").concretized() - spec.package.do_install() + PackageInstaller([spec.package], explicit=True).install() assert spec.installed spec.package.do_uninstall() @@ -54,7 +55,7 @@ def test_uninstall_non_existing_package(install_mockery, mock_fetch, monkeypatch """Ensure that we can uninstall a package that has been deleted from the repo""" spec = Spec("trivial-install-test-package").concretized() - spec.package.do_install() + PackageInstaller([spec.package], explicit=True).install() assert spec.installed # Mock deletion of the package @@ -75,7 +76,7 @@ def test_pkg_attributes(install_mockery, mock_fetch, monkeypatch): assert spec.concrete pkg = spec.package - pkg.do_install() + PackageInstaller([pkg], explicit=True).install() foo = "attributes-foo" assert spec["bar"].prefix == spec[foo].prefix assert spec["baz"].prefix == spec[foo].prefix @@ -132,7 +133,7 @@ def test_partial_install_delete_prefix_and_stage(install_mockery, mock_fetch, wo s.package.remove_prefix = mock_remove_prefix with pytest.raises(MockInstallError): - s.package.do_install() + PackageInstaller([s.package], explicit=True).install() assert os.path.isdir(s.package.prefix) rm_prefix_checker = RemovePrefixChecker(instance_rm_prefix) s.package.remove_prefix = rm_prefix_checker.remove_prefix @@ -141,7 +142,7 @@ def test_partial_install_delete_prefix_and_stage(install_mockery, mock_fetch, wo spack.store.STORE.failure_tracker.clear(s, True) s.package.set_install_succeed() - s.package.do_install(restage=True) + PackageInstaller([s.package], explicit=True, restage=True).install() assert rm_prefix_checker.removed assert s.package.spec.installed @@ -160,12 +161,12 @@ def test_failing_overwrite_install_should_keep_previous_installation( s.package.set_install_succeed() # Do a failing overwrite install - s.package.do_install() + PackageInstaller([s.package], explicit=True).install() s.package.set_install_fail() kwargs = {"overwrite": [s.dag_hash()]} with pytest.raises(Exception): - s.package.do_install(**kwargs) + PackageInstaller([s.package], explicit=True, **kwargs).install() assert s.package.spec.installed assert os.path.exists(s.prefix) @@ -174,7 +175,7 @@ def test_failing_overwrite_install_should_keep_previous_installation( def test_dont_add_patches_to_installed_package(install_mockery, mock_fetch, monkeypatch): dependency = Spec("dependency-install") dependency.concretize() - dependency.package.do_install() + PackageInstaller([dependency.package], explicit=True).install() dependency_hash = dependency.dag_hash() dependent = Spec("dependent-install ^/" + dependency_hash) @@ -192,7 +193,7 @@ def test_dont_add_patches_to_installed_package(install_mockery, mock_fetch, monk def test_installed_dependency_request_conflicts(install_mockery, mock_fetch, mutable_mock_repo): dependency = Spec("dependency-install") dependency.concretize() - dependency.package.do_install() + PackageInstaller([dependency.package], explicit=True).install() dependency_hash = dependency.dag_hash() dependent = Spec("conflicting-dependent ^/" + dependency_hash) @@ -205,7 +206,7 @@ def test_install_dependency_symlinks_pkg(install_mockery, mock_fetch, mutable_mo spec = Spec("flatten-deps") spec.concretize() pkg = spec.package - pkg.do_install() + PackageInstaller([pkg], explicit=True).install() # Ensure dependency directory exists after the installation. dependency_dir = os.path.join(pkg.prefix, "dependency-install") @@ -215,7 +216,7 @@ def test_install_dependency_symlinks_pkg(install_mockery, mock_fetch, mutable_mo def test_install_times(install_mockery, mock_fetch, mutable_mock_repo): """Test install times added.""" spec = Spec("dev-build-test-install-phases").concretized() - spec.package.do_install() + PackageInstaller([spec.package], explicit=True).install() # Ensure dependency directory exists after the installation. install_times = os.path.join(spec.package.prefix, ".spack", spack_times_log) @@ -238,7 +239,7 @@ def test_flatten_deps(install_mockery, mock_fetch, mutable_mock_repo): spec = Spec("dependent-install") spec.concretize() pkg = spec.package - pkg.do_install() + PackageInstaller([pkg], explicit=True).install() # Demonstrate that the directory does not appear under the spec # prior to the flatten operation. @@ -291,7 +292,7 @@ def test_installed_upstream_external(install_upstream, mock_fetch): assert new_dependency.external assert new_dependency.prefix == os.path.sep + os.path.join("path", "to", "external_tool") - dependent.package.do_install() + PackageInstaller([dependent.package], explicit=True).install() assert not os.path.exists(new_dependency.prefix) assert os.path.exists(dependent.prefix) @@ -310,7 +311,7 @@ def test_installed_upstream(install_upstream, mock_fetch): assert new_dependency.installed_upstream assert new_dependency.prefix == upstream_layout.path_for_spec(dependency) - dependent.package.do_install() + PackageInstaller([dependent.package], explicit=True).install() assert not os.path.exists(new_dependency.prefix) assert os.path.exists(dependent.prefix) @@ -323,14 +324,14 @@ def test_partial_install_keep_prefix(install_mockery, mock_fetch, monkeypatch, w # If remove_prefix is called at any point in this test, that is an error monkeypatch.setattr(spack.package_base.PackageBase, "remove_prefix", mock_remove_prefix) with pytest.raises(spack.build_environment.ChildError): - s.package.do_install(keep_prefix=True) + PackageInstaller([s.package], explicit=True, keep_prefix=True).install() assert os.path.exists(s.package.prefix) # must clear failure markings for the package before re-installing it spack.store.STORE.failure_tracker.clear(s, True) s.package.set_install_succeed() - s.package.do_install(keep_prefix=True) + PackageInstaller([s.package], explicit=True, keep_prefix=True).install() assert s.package.spec.installed @@ -339,12 +340,12 @@ def test_second_install_no_overwrite_first(install_mockery, mock_fetch, monkeypa monkeypatch.setattr(spack.package_base.PackageBase, "remove_prefix", mock_remove_prefix) s.package.set_install_succeed() - s.package.do_install() + PackageInstaller([s.package], explicit=True).install() assert s.package.spec.installed # If Package.install is called after this point, it will fail s.package.set_install_fail() - s.package.do_install() + PackageInstaller([s.package], explicit=True).install() def test_install_prefix_collision_fails(config, mock_fetch, mock_packages, tmpdir): @@ -357,16 +358,16 @@ def test_install_prefix_collision_fails(config, mock_fetch, mock_packages, tmpdi with spack.config.override("config:checksum", False): pkg_a = Spec("libelf@0.8.13").concretized().package pkg_b = Spec("libelf@0.8.12").concretized().package - pkg_a.do_install() + PackageInstaller([pkg_a], explicit=True).install() with pytest.raises(InstallError, match="Install prefix collision"): - pkg_b.do_install() + PackageInstaller([pkg_b], explicit=True).install() def test_store(install_mockery, mock_fetch): spec = Spec("cmake-client").concretized() pkg = spec.package - pkg.do_install() + PackageInstaller([pkg], explicit=True).install() @pytest.mark.disable_clean_stage_check @@ -375,7 +376,7 @@ def test_failing_build(install_mockery, mock_fetch, capfd): pkg = spec.package with pytest.raises(spack.build_environment.ChildError, match="Expected failure"): - pkg.do_install() + PackageInstaller([pkg], explicit=True).install() class MockInstallError(spack.error.SpackError): @@ -404,7 +405,7 @@ def test_nosource_pkg_install(install_mockery, mock_fetch, mock_packages, capfd, pkg = spec.package # Make sure install works even though there is no associated code. - pkg.do_install() + PackageInstaller([pkg], explicit=True).install() out = capfd.readouterr() assert "Installing dependency-install" in out[0] @@ -421,7 +422,7 @@ def test_nosource_bundle_pkg_install( pkg = spec.package # Make sure install works even though there is no associated code. - pkg.do_install() + PackageInstaller([pkg], explicit=True).install() out = capfd.readouterr() assert "Installing dependency-install" in out[0] @@ -435,7 +436,7 @@ def test_nosource_pkg_install_post_install(install_mockery, mock_fetch, mock_pac pkg = spec.package # Make sure both the install and post-install package methods work. - pkg.do_install() + PackageInstaller([pkg], explicit=True).install() # Ensure the file created in the package's `install` method exists. install_txt = os.path.join(spec.prefix, "install.txt") @@ -564,7 +565,7 @@ def test_unconcretized_install(install_mockery, mock_fetch, mock_packages): pkg_cls = spack.repo.PATH.get_pkg_class(spec.name) with pytest.raises(ValueError, match="must have a concrete spec"): - pkg_cls(spec).do_install() + PackageInstaller([pkg_cls(spec)], explicit=True).install() with pytest.raises(ValueError, match="only patch concrete packages"): pkg_cls(spec).do_patch() @@ -588,7 +589,7 @@ def test_empty_install_sanity_check_prefix( """Test empty install triggers sanity_check_prefix.""" spec = Spec("failing-empty-install").concretized() with pytest.raises(spack.build_environment.ChildError, match="Nothing was installed"): - spec.package.do_install() + PackageInstaller([spec.package], explicit=True).install() def test_install_from_binary_with_missing_patch_succeeds( @@ -624,10 +625,16 @@ def test_install_from_binary_with_missing_patch_succeeds( # Source install: fails, we don't have the patch. with pytest.raises(spack.error.SpecError, match="Couldn't find patch for package"): - s.package.do_install() + PackageInstaller([s.package], explicit=True).install() # Binary install: succeeds, we don't need the patch. spack.mirror.add(mirror) - s.package.do_install(package_cache_only=True, dependencies_cache_only=True, unsigned=True) + PackageInstaller( + [s.package], + explicit=True, + package_cache_only=True, + dependencies_cache_only=True, + unsigned=True, + ).install() assert temporary_store.db.query_local_by_spec_hash(s.dag_hash()) diff --git a/lib/spack/spack/test/installer.py b/lib/spack/spack/test/installer.py index 25dcafb64d..a95d151b50 100644 --- a/lib/spack/spack/test/installer.py +++ b/lib/spack/spack/test/installer.py @@ -28,6 +28,7 @@ import spack.repo import spack.spec import spack.store import spack.util.lock as lk +from spack.installer import PackageInstaller def _mock_repo(root, namespace): @@ -82,7 +83,7 @@ def create_installer( concretized.""" _specs = [spack.spec.Spec(s).concretized() if isinstance(s, str) else s for s in specs] _install_args = {} if install_args is None else install_args - return inst.PackageInstaller([spec.package for spec in _specs], _install_args) + return inst.PackageInstaller([spec.package for spec in _specs], **_install_args) @pytest.mark.parametrize( @@ -140,7 +141,9 @@ def test_install_from_cache_errors(install_mockery): with pytest.raises( spack.error.InstallError, match="No binary found when cache-only was specified" ): - spec.package.do_install(package_cache_only=True, dependencies_cache_only=True) + PackageInstaller( + [spec.package], package_cache_only=True, dependencies_cache_only=True + ).install() assert not spec.package.installed_from_binary_cache # Check when don't expect to install only from binary cache diff --git a/lib/spack/spack/test/modules/common.py b/lib/spack/spack/test/modules/common.py index 49f63f6c3b..f1430ecf6e 100644 --- a/lib/spack/spack/test/modules/common.py +++ b/lib/spack/spack/test/modules/common.py @@ -18,6 +18,7 @@ import spack.package_base import spack.package_prefs import spack.repo import spack.spec +from spack.installer import PackageInstaller from spack.modules.common import UpstreamModuleIndex from spack.spec import Spec @@ -180,7 +181,7 @@ module_index: def test_load_installed_package_not_in_repo(install_mockery, mock_fetch, monkeypatch): """Test that installed packages that have been removed are still loadable""" spec = Spec("trivial-install-test-package").concretized() - spec.package.do_install() + PackageInstaller([spec.package], explicit=True).install() spack.modules.module_types["tcl"](spec, "default", True).write() def find_nothing(*args): diff --git a/lib/spack/spack/test/package_class.py b/lib/spack/spack/test/package_class.py index 5a61d90d33..70955e9638 100644 --- a/lib/spack/spack/test/package_class.py +++ b/lib/spack/spack/test/package_class.py @@ -5,7 +5,7 @@ """Test class methods on Package objects. -This doesn't include methods on package *instances* (like do_install(), +This doesn't include methods on package *instances* (like do_patch(), etc.). Only methods like ``possible_dependencies()`` that deal with the static DSL metadata for packages. """ diff --git a/lib/spack/spack/test/packaging.py b/lib/spack/spack/test/packaging.py index f616cb47a7..d6ac1b190d 100644 --- a/lib/spack/spack/test/packaging.py +++ b/lib/spack/spack/test/packaging.py @@ -30,6 +30,7 @@ import spack.stage import spack.util.gpg import spack.util.url as url_util from spack.fetch_strategy import URLFetchStrategy +from spack.installer import PackageInstaller from spack.paths import mock_gpg_keys_path from spack.relocate import ( macho_find_paths, @@ -50,7 +51,7 @@ def test_buildcache(mock_archive, tmp_path, monkeypatch, mutable_config): # Install a test package spec = Spec("trivial-install-test-package").concretized() monkeypatch.setattr(spec.package, "fetcher", URLFetchStrategy(url=mock_archive.url)) - spec.package.do_install() + PackageInstaller([spec.package], explicit=True).install() pkghash = "/" + str(spec.dag_hash(7)) # Put some non-relocatable file in there diff --git a/lib/spack/spack/test/rewiring.py b/lib/spack/spack/test/rewiring.py index f082b1b153..523ae5325b 100644 --- a/lib/spack/spack/test/rewiring.py +++ b/lib/spack/spack/test/rewiring.py @@ -11,6 +11,7 @@ import pytest import spack.rewiring import spack.store +from spack.installer import PackageInstaller from spack.spec import Spec from spack.test.relocate import text_in_bin @@ -27,8 +28,7 @@ def test_rewire_db(mock_fetch, install_mockery, transitive): """Tests basic rewiring without binary executables.""" spec = Spec("splice-t^splice-h~foo").concretized() dep = Spec("splice-h+foo").concretized() - spec.package.do_install() - dep.package.do_install() + PackageInstaller([spec.package, dep.package], explicit=True).install() spliced_spec = spec.splice(dep, transitive=transitive) assert spec.dag_hash() != spliced_spec.dag_hash() @@ -57,8 +57,7 @@ def test_rewire_bin(mock_fetch, install_mockery, transitive): """Tests basic rewiring with binary executables.""" spec = Spec("quux").concretized() dep = Spec("garply cflags=-g").concretized() - spec.package.do_install() - dep.package.do_install() + PackageInstaller([spec.package, dep.package], explicit=True).install() spliced_spec = spec.splice(dep, transitive=transitive) assert spec.dag_hash() != spliced_spec.dag_hash() @@ -86,8 +85,7 @@ def test_rewire_writes_new_metadata(mock_fetch, install_mockery): Accuracy of metadata is left to other tests.""" spec = Spec("quux").concretized() dep = Spec("garply cflags=-g").concretized() - spec.package.do_install() - dep.package.do_install() + PackageInstaller([spec.package, dep.package], explicit=True).install() spliced_spec = spec.splice(dep, transitive=True) spack.rewiring.rewire(spliced_spec) @@ -129,8 +127,7 @@ def test_uninstall_rewired_spec(mock_fetch, install_mockery, transitive): """Test that rewired packages can be uninstalled as normal.""" spec = Spec("quux").concretized() dep = Spec("garply cflags=-g").concretized() - spec.package.do_install() - dep.package.do_install() + PackageInstaller([spec.package, dep.package], explicit=True).install() spliced_spec = spec.splice(dep, transitive=transitive) spack.rewiring.rewire(spliced_spec) spliced_spec.package.do_uninstall() diff --git a/lib/spack/spack/test/spec_list.py b/lib/spack/spack/test/spec_list.py index 98f0f8b312..295665ecfb 100644 --- a/lib/spack/spack/test/spec_list.py +++ b/lib/spack/spack/test/spec_list.py @@ -6,6 +6,7 @@ import itertools import pytest +from spack.installer import PackageInstaller from spack.spec import Spec from spack.spec_list import SpecList @@ -200,8 +201,7 @@ class TestSpecList: # Put mpich in the database so it can be referred to by hash. mpich_1 = Spec("mpich+debug").concretized() mpich_2 = Spec("mpich~debug").concretized() - mpich_1.package.do_install(fake=True) - mpich_2.package.do_install(fake=True) + PackageInstaller([mpich_1.package, mpich_2.package], explicit=True, fake=True).install() # Create matrix and exclude +debug, which excludes the first mpich after its abstract hash # is resolved. diff --git a/lib/spack/spack/test/views.py b/lib/spack/spack/test/views.py index c8ff50eeb9..2a62d04312 100644 --- a/lib/spack/spack/test/views.py +++ b/lib/spack/spack/test/views.py @@ -9,6 +9,7 @@ import pytest from spack.directory_layout import DirectoryLayout from spack.filesystem_view import SimpleFilesystemView, YamlFilesystemView +from spack.installer import PackageInstaller from spack.spec import Spec @@ -17,7 +18,7 @@ def test_remove_extensions_ordered(install_mockery, mock_fetch, tmpdir): layout = DirectoryLayout(view_dir) view = YamlFilesystemView(view_dir, layout) e2 = Spec("extension2").concretized() - e2.package.do_install() + PackageInstaller([e2.package], explicit=True).install() view.add_specs(e2) e1 = e2["extension1"] |