summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHarmen Stoppels <me@harmenstoppels.nl>2024-09-19 23:25:36 +0200
committerGitHub <noreply@github.com>2024-09-19 23:25:36 +0200
commite4927b35d1d820545cb09c291bd3757131581a49 (patch)
tree81db5cf4a94f7aa243ccb74b9bb3c9fd0c2ceb79
parent098ad7ffc0d0a5ac308741f3d85d3736446648e2 (diff)
downloadspack-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.
-rw-r--r--lib/spack/spack/bootstrap/core.py5
-rw-r--r--lib/spack/spack/cmd/deprecate.py3
-rw-r--r--lib/spack/spack/cmd/dev_build.py7
-rw-r--r--lib/spack/spack/cmd/install.py2
-rw-r--r--lib/spack/spack/environment/environment.py2
-rw-r--r--lib/spack/spack/installer.py118
-rw-r--r--lib/spack/spack/package_base.py95
-rw-r--r--lib/spack/spack/test/build_distribution.py3
-rw-r--r--lib/spack/spack/test/build_environment.py3
-rw-r--r--lib/spack/spack/test/build_systems.py11
-rw-r--r--lib/spack/spack/test/cmd/buildcache.py13
-rw-r--r--lib/spack/spack/test/cmd/extensions.py6
-rw-r--r--lib/spack/spack/test/cmd/gc.py11
-rw-r--r--lib/spack/spack/test/cmd/install.py5
-rw-r--r--lib/spack/spack/test/cmd/module.py5
-rw-r--r--lib/spack/spack/test/cmd/tags.py3
-rw-r--r--lib/spack/spack/test/cmd/view.py3
-rw-r--r--lib/spack/spack/test/concretize.py27
-rw-r--r--lib/spack/spack/test/concretize_requirements.py3
-rw-r--r--lib/spack/spack/test/conftest.py3
-rw-r--r--lib/spack/spack/test/database.py17
-rw-r--r--lib/spack/spack/test/install.py65
-rw-r--r--lib/spack/spack/test/installer.py7
-rw-r--r--lib/spack/spack/test/modules/common.py3
-rw-r--r--lib/spack/spack/test/package_class.py2
-rw-r--r--lib/spack/spack/test/packaging.py3
-rw-r--r--lib/spack/spack/test/rewiring.py13
-rw-r--r--lib/spack/spack/test/spec_list.py4
-rw-r--r--lib/spack/spack/test/views.py3
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"]