Install: Add use-buildcache option to install (#32537)
Install: Add use-buildcache option to install * Allow differentiating between top level packages and dependencies when determining whether to install from the cache or not. * Add unit test for --use-buildcache * Use metavar to display use-buildcache options. * Update spack-completion
This commit is contained in:
parent
7a25f416b8
commit
a01c36da45
4 changed files with 167 additions and 9 deletions
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
import textwrap
|
import textwrap
|
||||||
|
@ -31,10 +32,50 @@
|
||||||
level = "short"
|
level = "short"
|
||||||
|
|
||||||
|
|
||||||
|
# Pass in the value string passed to use-buildcache and get back
|
||||||
|
# the package and dependencies values.
|
||||||
|
def parse_use_buildcache(opt):
|
||||||
|
bc_keys = ["package:", "dependencies:", ""]
|
||||||
|
bc_values = ["only", "never", "auto"]
|
||||||
|
kv_list = re.findall("([a-z]+:)?([a-z]+)", opt)
|
||||||
|
|
||||||
|
# Verify keys and values
|
||||||
|
bc_map = {k: v for k, v in kv_list if k in bc_keys and v in bc_values}
|
||||||
|
if not len(kv_list) == len(bc_map):
|
||||||
|
tty.error("Unrecognized arguments passed to use-buildcache")
|
||||||
|
tty.error(
|
||||||
|
"Expected: --use-buildcache "
|
||||||
|
"[[auto|only|never],[package:[auto|only|never]],[dependencies:[auto|only|never]]]"
|
||||||
|
)
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
for _group in ["package:", "dependencies:"]:
|
||||||
|
if _group not in bc_map:
|
||||||
|
if "" in bc_map:
|
||||||
|
bc_map[_group] = bc_map[""]
|
||||||
|
else:
|
||||||
|
bc_map[_group] = "auto"
|
||||||
|
|
||||||
|
return bc_map["package:"], bc_map["dependencies:"]
|
||||||
|
|
||||||
|
|
||||||
|
# Determine value of cache flag
|
||||||
|
def cache_opt(default_opt, use_buildcache):
|
||||||
|
if use_buildcache == "auto":
|
||||||
|
return default_opt
|
||||||
|
elif use_buildcache == "only":
|
||||||
|
return True
|
||||||
|
elif use_buildcache == "never":
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def install_kwargs_from_args(args):
|
def install_kwargs_from_args(args):
|
||||||
"""Translate command line arguments into a dictionary that will be passed
|
"""Translate command line arguments into a dictionary that will be passed
|
||||||
to the package installer.
|
to the package installer.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
pkg_use_bc, dep_use_bc = parse_use_buildcache(args.use_buildcache)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"fail_fast": args.fail_fast,
|
"fail_fast": args.fail_fast,
|
||||||
"keep_prefix": args.keep_prefix,
|
"keep_prefix": args.keep_prefix,
|
||||||
|
@ -44,8 +85,10 @@ def install_kwargs_from_args(args):
|
||||||
"verbose": args.verbose or args.install_verbose,
|
"verbose": args.verbose or args.install_verbose,
|
||||||
"fake": args.fake,
|
"fake": args.fake,
|
||||||
"dirty": args.dirty,
|
"dirty": args.dirty,
|
||||||
"use_cache": args.use_cache,
|
"package_use_cache": cache_opt(args.use_cache, pkg_use_bc),
|
||||||
"cache_only": args.cache_only,
|
"package_cache_only": cache_opt(args.cache_only, pkg_use_bc),
|
||||||
|
"dependencies_use_cache": cache_opt(args.use_cache, dep_use_bc),
|
||||||
|
"dependencies_cache_only": cache_opt(args.cache_only, dep_use_bc),
|
||||||
"include_build_deps": args.include_build_deps,
|
"include_build_deps": args.include_build_deps,
|
||||||
"explicit": True, # Use true as a default for install command
|
"explicit": True, # Use true as a default for install command
|
||||||
"stop_at": args.until,
|
"stop_at": args.until,
|
||||||
|
@ -123,6 +166,18 @@ def setup_parser(subparser):
|
||||||
default=False,
|
default=False,
|
||||||
help="only install package from binary mirrors",
|
help="only install package from binary mirrors",
|
||||||
)
|
)
|
||||||
|
cache_group.add_argument(
|
||||||
|
"--use-buildcache",
|
||||||
|
dest="use_buildcache",
|
||||||
|
default="package:auto,dependencies:auto",
|
||||||
|
metavar="[{auto,only,never},][package:{auto,only,never},][dependencies:{auto,only,never}]",
|
||||||
|
help="""select the mode of buildcache for the 'package' and 'dependencies'.
|
||||||
|
Default: package:auto,dependencies:auto
|
||||||
|
- `auto` behaves like --use-cache
|
||||||
|
- `only` behaves like --cache-only
|
||||||
|
- `never` behaves like --no-cache
|
||||||
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
subparser.add_argument(
|
subparser.add_argument(
|
||||||
"--include-build-deps",
|
"--include-build-deps",
|
||||||
|
|
|
@ -1182,12 +1182,12 @@ def _install_task(self, task):
|
||||||
Args:
|
Args:
|
||||||
task (BuildTask): the installation build task for a package"""
|
task (BuildTask): the installation build task for a package"""
|
||||||
|
|
||||||
install_args = task.request.install_args
|
|
||||||
cache_only = install_args.get("cache_only")
|
|
||||||
explicit = task.explicit
|
explicit = task.explicit
|
||||||
|
install_args = task.request.install_args
|
||||||
|
cache_only = task.cache_only
|
||||||
|
use_cache = task.use_cache
|
||||||
tests = install_args.get("tests")
|
tests = install_args.get("tests")
|
||||||
unsigned = install_args.get("unsigned")
|
unsigned = install_args.get("unsigned")
|
||||||
use_cache = install_args.get("use_cache")
|
|
||||||
|
|
||||||
pkg, pkg_id = task.pkg, task.pkg_id
|
pkg, pkg_id = task.pkg, task.pkg_id
|
||||||
|
|
||||||
|
@ -2220,7 +2220,29 @@ def flag_installed(self, installed):
|
||||||
@property
|
@property
|
||||||
def explicit(self):
|
def explicit(self):
|
||||||
"""The package was explicitly requested by the user."""
|
"""The package was explicitly requested by the user."""
|
||||||
return self.pkg == self.request.pkg and self.request.install_args.get("explicit", True)
|
return self.is_root and self.request.install_args.get("explicit", True)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_root(self):
|
||||||
|
"""The package was requested directly, but may or may not be explicit
|
||||||
|
in an environment."""
|
||||||
|
return self.pkg == self.request.pkg
|
||||||
|
|
||||||
|
@property
|
||||||
|
def use_cache(self):
|
||||||
|
_use_cache = True
|
||||||
|
if self.is_root:
|
||||||
|
return self.request.install_args.get("package_use_cache", _use_cache)
|
||||||
|
else:
|
||||||
|
return self.request.install_args.get("dependencies_use_cache", _use_cache)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cache_only(self):
|
||||||
|
_cache_only = False
|
||||||
|
if self.is_root:
|
||||||
|
return self.request.install_args.get("package_cache_only", _cache_only)
|
||||||
|
else:
|
||||||
|
return self.request.install_args.get("dependencies_cache_only", _cache_only)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def key(self):
|
def key(self):
|
||||||
|
@ -2302,21 +2324,23 @@ def __str__(self):
|
||||||
def _add_default_args(self):
|
def _add_default_args(self):
|
||||||
"""Ensure standard install options are set to at least the default."""
|
"""Ensure standard install options are set to at least the default."""
|
||||||
for arg, default in [
|
for arg, default in [
|
||||||
("cache_only", False),
|
|
||||||
("context", "build"), # installs *always* build
|
("context", "build"), # installs *always* build
|
||||||
|
("dependencies_cache_only", False),
|
||||||
|
("dependencies_use_cache", True),
|
||||||
("dirty", False),
|
("dirty", False),
|
||||||
("fail_fast", False),
|
("fail_fast", False),
|
||||||
("fake", False),
|
("fake", False),
|
||||||
("install_deps", True),
|
("install_deps", True),
|
||||||
("install_package", True),
|
("install_package", True),
|
||||||
("install_source", False),
|
("install_source", False),
|
||||||
|
("package_cache_only", False),
|
||||||
|
("package_use_cache", True),
|
||||||
("keep_prefix", False),
|
("keep_prefix", False),
|
||||||
("keep_stage", False),
|
("keep_stage", False),
|
||||||
("restage", False),
|
("restage", False),
|
||||||
("skip_patch", False),
|
("skip_patch", False),
|
||||||
("tests", False),
|
("tests", False),
|
||||||
("unsigned", False),
|
("unsigned", False),
|
||||||
("use_cache", True),
|
|
||||||
("verbose", False),
|
("verbose", False),
|
||||||
]:
|
]:
|
||||||
_ = self.install_args.setdefault(arg, default)
|
_ = self.install_args.setdefault(arg, default)
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import filecmp
|
import filecmp
|
||||||
|
import itertools
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
@ -14,6 +15,7 @@
|
||||||
from six.moves import builtins
|
from six.moves import builtins
|
||||||
|
|
||||||
import llnl.util.filesystem as fs
|
import llnl.util.filesystem as fs
|
||||||
|
import llnl.util.tty as tty
|
||||||
|
|
||||||
import spack.cmd.install
|
import spack.cmd.install
|
||||||
import spack.compilers as compilers
|
import spack.compilers as compilers
|
||||||
|
@ -1090,3 +1092,80 @@ def test_install_callbacks_fail(install_mockery, mock_fetch, name, method):
|
||||||
assert output.count(method) == 2
|
assert output.count(method) == 2
|
||||||
assert output.count("method not implemented") == 1
|
assert output.count("method not implemented") == 1
|
||||||
assert output.count("TestFailure: 1 tests failed") == 1
|
assert output.count("TestFailure: 1 tests failed") == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_install_use_buildcache(
|
||||||
|
capsys,
|
||||||
|
mock_packages,
|
||||||
|
mock_fetch,
|
||||||
|
mock_archive,
|
||||||
|
mock_binary_index,
|
||||||
|
tmpdir,
|
||||||
|
install_mockery_mutable_config,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Make sure installing with use-buildcache behaves correctly.
|
||||||
|
"""
|
||||||
|
|
||||||
|
package_name = "dependent-install"
|
||||||
|
dependency_name = "dependency-install"
|
||||||
|
|
||||||
|
def validate(mode, out, pkg):
|
||||||
|
def assert_auto(pkg, out):
|
||||||
|
assert "==> Extracting {0}".format(pkg) in out
|
||||||
|
|
||||||
|
def assert_only(pkg, out):
|
||||||
|
assert "==> Extracting {0}".format(pkg) in out
|
||||||
|
|
||||||
|
def assert_never(pkg, out):
|
||||||
|
assert "==> {0}: Executing phase: 'install'".format(pkg) in out
|
||||||
|
|
||||||
|
if mode == "auto":
|
||||||
|
assert_auto(pkg, out)
|
||||||
|
elif mode == "only":
|
||||||
|
assert_only(pkg, out)
|
||||||
|
else:
|
||||||
|
assert_never(pkg, out)
|
||||||
|
|
||||||
|
def install_use_buildcache(opt):
|
||||||
|
out = install(
|
||||||
|
"--no-check-signature", "--use-buildcache", opt, package_name, fail_on_error=True
|
||||||
|
)
|
||||||
|
|
||||||
|
pkg_opt, dep_opt = spack.cmd.install.parse_use_buildcache(opt)
|
||||||
|
validate(dep_opt, out, dependency_name)
|
||||||
|
validate(pkg_opt, out, package_name)
|
||||||
|
|
||||||
|
# Clean up installed packages
|
||||||
|
uninstall("-y", "-a")
|
||||||
|
|
||||||
|
# Setup the mirror
|
||||||
|
# Create a temp mirror directory for buildcache usage
|
||||||
|
mirror_dir = tmpdir.join("mirror_dir")
|
||||||
|
mirror_url = "file://{0}".format(mirror_dir.strpath)
|
||||||
|
|
||||||
|
# Populate the buildcache
|
||||||
|
install(package_name)
|
||||||
|
buildcache("create", "-u", "-a", "-f", "-d", mirror_dir.strpath, package_name, dependency_name)
|
||||||
|
|
||||||
|
# Uninstall the all of the packages for clean slate
|
||||||
|
uninstall("-y", "-a")
|
||||||
|
|
||||||
|
# Configure the mirror where we put that buildcache w/ the compiler
|
||||||
|
mirror("add", "test-mirror", mirror_url)
|
||||||
|
|
||||||
|
with capsys.disabled():
|
||||||
|
# Install using the matrix of possible combinations with --use-buildcache
|
||||||
|
for pkg, deps in itertools.product(["auto", "only", "never"], repeat=2):
|
||||||
|
tty.debug(
|
||||||
|
"Testing `spack install --use-buildcache package:{0},dependencies:{1}`".format(
|
||||||
|
pkg, deps
|
||||||
|
)
|
||||||
|
)
|
||||||
|
install_use_buildcache("package:{0},dependencies:{1}".format(pkg, deps))
|
||||||
|
install_use_buildcache("dependencies:{0},package:{1}".format(deps, pkg))
|
||||||
|
|
||||||
|
# Install using a default override option
|
||||||
|
# Alternative to --cache-only (always) or --no-cache (never)
|
||||||
|
for opt in ["auto", "only", "never"]:
|
||||||
|
install_use_buildcache(opt)
|
||||||
|
|
|
@ -1188,7 +1188,7 @@ _spack_info() {
|
||||||
_spack_install() {
|
_spack_install() {
|
||||||
if $list_options
|
if $list_options
|
||||||
then
|
then
|
||||||
SPACK_COMPREPLY="-h --help --only -u --until -j --jobs --overwrite --fail-fast --keep-prefix --keep-stage --dont-restage --use-cache --no-cache --cache-only --include-build-deps --no-check-signature --show-log-on-error --source -n --no-checksum --deprecated -v --verbose --fake --only-concrete --no-add -f --file --clean --dirty --test --log-format --log-file --help-cdash --cdash-upload-url --cdash-build --cdash-site --cdash-track --cdash-buildstamp -y --yes-to-all -U --fresh --reuse"
|
SPACK_COMPREPLY="-h --help --only -u --until -j --jobs --overwrite --fail-fast --keep-prefix --keep-stage --dont-restage --use-cache --no-cache --cache-only --use-buildcache --include-build-deps --no-check-signature --show-log-on-error --source -n --no-checksum --deprecated -v --verbose --fake --only-concrete --no-add -f --file --clean --dirty --test --log-format --log-file --help-cdash --cdash-upload-url --cdash-build --cdash-site --cdash-track --cdash-buildstamp -y --yes-to-all -U --fresh --reuse"
|
||||||
else
|
else
|
||||||
_all_packages
|
_all_packages
|
||||||
fi
|
fi
|
||||||
|
|
Loading…
Reference in a new issue