Propagate --test= for environments (#22040)
* Propagate --test= for environments * Improve help comment for spack concretize --test flag * Add tests for --test with environments
This commit is contained in:
@@ -14,11 +14,25 @@ def setup_parser(subparser):
|
|||||||
subparser.add_argument(
|
subparser.add_argument(
|
||||||
'-f', '--force', action='store_true',
|
'-f', '--force', action='store_true',
|
||||||
help="Re-concretize even if already concretized.")
|
help="Re-concretize even if already concretized.")
|
||||||
|
subparser.add_argument(
|
||||||
|
'--test', default=None,
|
||||||
|
choices=['root', 'all'],
|
||||||
|
help="""Concretize with test dependencies. When 'root' is chosen, test
|
||||||
|
dependencies are only added for the environment's root specs. When 'all' is
|
||||||
|
chosen, test dependencies are enabled for all packages in the environment.""")
|
||||||
|
|
||||||
|
|
||||||
def concretize(parser, args):
|
def concretize(parser, args):
|
||||||
env = ev.get_env(args, 'concretize', required=True)
|
env = ev.get_env(args, 'concretize', required=True)
|
||||||
|
|
||||||
|
if args.test == 'all':
|
||||||
|
tests = True
|
||||||
|
elif args.test == 'root':
|
||||||
|
tests = [spec.name for spec in env.user_specs]
|
||||||
|
else:
|
||||||
|
tests = False
|
||||||
|
|
||||||
with env.write_transaction():
|
with env.write_transaction():
|
||||||
concretized_specs = env.concretize(force=args.force)
|
concretized_specs = env.concretize(force=args.force, tests=tests)
|
||||||
ev.display_specs(concretized_specs)
|
ev.display_specs(concretized_specs)
|
||||||
env.write()
|
env.write()
|
||||||
|
|||||||
@@ -241,14 +241,28 @@ def install(parser, args, **kwargs):
|
|||||||
if args.log_file:
|
if args.log_file:
|
||||||
reporter.filename = args.log_file
|
reporter.filename = args.log_file
|
||||||
|
|
||||||
|
if args.run_tests:
|
||||||
|
tty.warn("Deprecated option: --run-tests: use --test=all instead")
|
||||||
|
|
||||||
|
def get_tests(specs):
|
||||||
|
if args.test == 'all' or args.run_tests:
|
||||||
|
return True
|
||||||
|
elif args.test == 'root':
|
||||||
|
return [spec.name for spec in specs]
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
if not args.spec and not args.specfiles:
|
if not args.spec and not args.specfiles:
|
||||||
# if there are no args but an active environment
|
# if there are no args but an active environment
|
||||||
# then install the packages from it.
|
# then install the packages from it.
|
||||||
env = ev.get_env(args, 'install')
|
env = ev.get_env(args, 'install')
|
||||||
if env:
|
if env:
|
||||||
|
tests = get_tests(env.user_specs)
|
||||||
|
kwargs['tests'] = tests
|
||||||
|
|
||||||
if not args.only_concrete:
|
if not args.only_concrete:
|
||||||
with env.write_transaction():
|
with env.write_transaction():
|
||||||
concretized_specs = env.concretize()
|
concretized_specs = env.concretize(tests=tests)
|
||||||
ev.display_specs(concretized_specs)
|
ev.display_specs(concretized_specs)
|
||||||
|
|
||||||
# save view regeneration for later, so that we only do it
|
# save view regeneration for later, so that we only do it
|
||||||
@@ -295,16 +309,9 @@ def install(parser, args, **kwargs):
|
|||||||
# that will be passed to the package installer
|
# that will be passed to the package installer
|
||||||
update_kwargs_from_args(args, kwargs)
|
update_kwargs_from_args(args, kwargs)
|
||||||
|
|
||||||
if args.run_tests:
|
|
||||||
tty.warn("Deprecated option: --run-tests: use --test=all instead")
|
|
||||||
|
|
||||||
# 1. Abstract specs from cli
|
# 1. Abstract specs from cli
|
||||||
abstract_specs = spack.cmd.parse_specs(args.spec)
|
abstract_specs = spack.cmd.parse_specs(args.spec)
|
||||||
tests = False
|
tests = get_tests(abstract_specs)
|
||||||
if args.test == 'all' or args.run_tests:
|
|
||||||
tests = True
|
|
||||||
elif args.test == 'root':
|
|
||||||
tests = [spec.name for spec in abstract_specs]
|
|
||||||
kwargs['tests'] = tests
|
kwargs['tests'] = tests
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -714,10 +714,12 @@ def _compiler_concretization_failure(compiler_spec, arch):
|
|||||||
raise UnavailableCompilerVersionError(compiler_spec, arch)
|
raise UnavailableCompilerVersionError(compiler_spec, arch)
|
||||||
|
|
||||||
|
|
||||||
def concretize_specs_together(*abstract_specs):
|
def concretize_specs_together(*abstract_specs, **kwargs):
|
||||||
"""Given a number of specs as input, tries to concretize them together.
|
"""Given a number of specs as input, tries to concretize them together.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
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
|
||||||
*abstract_specs: abstract specs to be concretized, given either
|
*abstract_specs: abstract specs to be concretized, given either
|
||||||
as Specs or strings
|
as Specs or strings
|
||||||
|
|
||||||
@@ -757,7 +759,7 @@ def make_concretization_repository(abstract_specs):
|
|||||||
with spack.repo.additional_repository(concretization_repository):
|
with spack.repo.additional_repository(concretization_repository):
|
||||||
# Spec from a helper package that depends on all the abstract_specs
|
# Spec from a helper package that depends on all the abstract_specs
|
||||||
concretization_root = spack.spec.Spec('concretizationroot')
|
concretization_root = spack.spec.Spec('concretizationroot')
|
||||||
concretization_root.concretize()
|
concretization_root.concretize(tests=kwargs.get('tests', False))
|
||||||
# Retrieve the direct dependencies
|
# Retrieve the direct dependencies
|
||||||
concrete_specs = [
|
concrete_specs = [
|
||||||
concretization_root[spec.name].copy() for spec in abstract_specs
|
concretization_root[spec.name].copy() for spec in abstract_specs
|
||||||
|
|||||||
@@ -1064,7 +1064,7 @@ def undevelop(self, spec):
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def concretize(self, force=False):
|
def concretize(self, force=False, tests=False):
|
||||||
"""Concretize user_specs in this environment.
|
"""Concretize user_specs in this environment.
|
||||||
|
|
||||||
Only concretizes specs that haven't been concretized yet unless
|
Only concretizes specs that haven't been concretized yet unless
|
||||||
@@ -1076,6 +1076,8 @@ def concretize(self, force=False):
|
|||||||
Arguments:
|
Arguments:
|
||||||
force (bool): re-concretize ALL specs, even those that were
|
force (bool): re-concretize ALL specs, even those that were
|
||||||
already concretized
|
already concretized
|
||||||
|
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
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List of specs that have been concretized. Each entry is a tuple of
|
List of specs that have been concretized. Each entry is a tuple of
|
||||||
@@ -1089,14 +1091,14 @@ def concretize(self, force=False):
|
|||||||
|
|
||||||
# Pick the right concretization strategy
|
# Pick the right concretization strategy
|
||||||
if self.concretization == 'together':
|
if self.concretization == 'together':
|
||||||
return self._concretize_together()
|
return self._concretize_together(tests=tests)
|
||||||
if self.concretization == 'separately':
|
if self.concretization == 'separately':
|
||||||
return self._concretize_separately()
|
return self._concretize_separately(tests=tests)
|
||||||
|
|
||||||
msg = 'concretization strategy not implemented [{0}]'
|
msg = 'concretization strategy not implemented [{0}]'
|
||||||
raise SpackEnvironmentError(msg.format(self.concretization))
|
raise SpackEnvironmentError(msg.format(self.concretization))
|
||||||
|
|
||||||
def _concretize_together(self):
|
def _concretize_together(self, tests=False):
|
||||||
"""Concretization strategy that concretizes all the specs
|
"""Concretization strategy that concretizes all the specs
|
||||||
in the same DAG.
|
in the same DAG.
|
||||||
"""
|
"""
|
||||||
@@ -1129,14 +1131,13 @@ def _concretize_together(self):
|
|||||||
self.specs_by_hash = {}
|
self.specs_by_hash = {}
|
||||||
|
|
||||||
concrete_specs = spack.concretize.concretize_specs_together(
|
concrete_specs = spack.concretize.concretize_specs_together(
|
||||||
*self.user_specs
|
*self.user_specs, tests=tests)
|
||||||
)
|
|
||||||
concretized_specs = [x for x in zip(self.user_specs, concrete_specs)]
|
concretized_specs = [x for x in zip(self.user_specs, concrete_specs)]
|
||||||
for abstract, concrete in concretized_specs:
|
for abstract, concrete in concretized_specs:
|
||||||
self._add_concrete_spec(abstract, concrete)
|
self._add_concrete_spec(abstract, concrete)
|
||||||
return concretized_specs
|
return concretized_specs
|
||||||
|
|
||||||
def _concretize_separately(self):
|
def _concretize_separately(self, tests=False):
|
||||||
"""Concretization strategy that concretizes separately one
|
"""Concretization strategy that concretizes separately one
|
||||||
user spec after the other.
|
user spec after the other.
|
||||||
"""
|
"""
|
||||||
@@ -1159,12 +1160,12 @@ def _concretize_separately(self):
|
|||||||
for uspec, uspec_constraints in zip(
|
for uspec, uspec_constraints in zip(
|
||||||
self.user_specs, self.user_specs.specs_as_constraints):
|
self.user_specs, self.user_specs.specs_as_constraints):
|
||||||
if uspec not in old_concretized_user_specs:
|
if uspec not in old_concretized_user_specs:
|
||||||
concrete = _concretize_from_constraints(uspec_constraints)
|
concrete = _concretize_from_constraints(uspec_constraints, tests=tests)
|
||||||
self._add_concrete_spec(uspec, concrete)
|
self._add_concrete_spec(uspec, concrete)
|
||||||
concretized_specs.append((uspec, concrete))
|
concretized_specs.append((uspec, concrete))
|
||||||
return concretized_specs
|
return concretized_specs
|
||||||
|
|
||||||
def concretize_and_add(self, user_spec, concrete_spec=None):
|
def concretize_and_add(self, user_spec, concrete_spec=None, tests=False):
|
||||||
"""Concretize and add a single spec to the environment.
|
"""Concretize and add a single spec to the environment.
|
||||||
|
|
||||||
Concretize the provided ``user_spec`` and add it along with the
|
Concretize the provided ``user_spec`` and add it along with the
|
||||||
@@ -1187,7 +1188,7 @@ def concretize_and_add(self, user_spec, concrete_spec=None):
|
|||||||
spec = Spec(user_spec)
|
spec = Spec(user_spec)
|
||||||
|
|
||||||
if self.add(spec):
|
if self.add(spec):
|
||||||
concrete = concrete_spec or spec.concretized()
|
concrete = concrete_spec or spec.concretized(tests=tests)
|
||||||
self._add_concrete_spec(spec, concrete)
|
self._add_concrete_spec(spec, concrete)
|
||||||
else:
|
else:
|
||||||
# spec might be in the user_specs, but not installed.
|
# spec might be in the user_specs, but not installed.
|
||||||
@@ -1197,7 +1198,7 @@ def concretize_and_add(self, user_spec, concrete_spec=None):
|
|||||||
)
|
)
|
||||||
concrete = self.specs_by_hash.get(spec.build_hash())
|
concrete = self.specs_by_hash.get(spec.build_hash())
|
||||||
if not concrete:
|
if not concrete:
|
||||||
concrete = spec.concretized()
|
concrete = spec.concretized(tests=tests)
|
||||||
self._add_concrete_spec(spec, concrete)
|
self._add_concrete_spec(spec, concrete)
|
||||||
|
|
||||||
return concrete
|
return concrete
|
||||||
@@ -1904,7 +1905,7 @@ def _tree_to_display(spec):
|
|||||||
print('')
|
print('')
|
||||||
|
|
||||||
|
|
||||||
def _concretize_from_constraints(spec_constraints):
|
def _concretize_from_constraints(spec_constraints, tests=False):
|
||||||
# Accept only valid constraints from list and concretize spec
|
# Accept only valid constraints from list and concretize spec
|
||||||
# Get the named spec even if out of order
|
# Get the named spec even if out of order
|
||||||
root_spec = [s for s in spec_constraints if s.name]
|
root_spec = [s for s in spec_constraints if s.name]
|
||||||
@@ -1923,7 +1924,7 @@ def _concretize_from_constraints(spec_constraints):
|
|||||||
if c not in invalid_constraints:
|
if c not in invalid_constraints:
|
||||||
s.constrain(c)
|
s.constrain(c)
|
||||||
try:
|
try:
|
||||||
return s.concretized()
|
return s.concretized(tests=tests)
|
||||||
except spack.spec.InvalidDependencyError as e:
|
except spack.spec.InvalidDependencyError as e:
|
||||||
invalid_deps_string = ['^' + d for d in e.invalid_deps]
|
invalid_deps_string = ['^' + d for d in e.invalid_deps]
|
||||||
invalid_deps = [c for c in spec_constraints
|
invalid_deps = [c for c in spec_constraints
|
||||||
|
|||||||
55
lib/spack/spack/test/cmd/concretize.py
Normal file
55
lib/spack/spack/test/cmd/concretize.py
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
# Copyright 2013-2021 Lawrence Livermore National Security, LLC and other
|
||||||
|
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||||
|
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
import spack.environment as ev
|
||||||
|
from spack.main import SpackCommand
|
||||||
|
|
||||||
|
|
||||||
|
# everything here uses the mock_env_path
|
||||||
|
pytestmark = pytest.mark.usefixtures(
|
||||||
|
'mutable_mock_env_path', 'config', 'mutable_mock_repo')
|
||||||
|
|
||||||
|
env = SpackCommand('env')
|
||||||
|
add = SpackCommand('add')
|
||||||
|
concretize = SpackCommand('concretize')
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('concretization', ['separately', 'together'])
|
||||||
|
def test_concretize_all_test_dependencies(concretization):
|
||||||
|
"""Check all test dependencies are concretized."""
|
||||||
|
env('create', 'test')
|
||||||
|
|
||||||
|
with ev.read('test') as e:
|
||||||
|
e.concretization = concretization
|
||||||
|
add('depb')
|
||||||
|
concretize('--test', 'all')
|
||||||
|
assert e.matching_spec('test-dependency')
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('concretization', ['separately', 'together'])
|
||||||
|
def test_concretize_root_test_dependencies_not_recursive(concretization):
|
||||||
|
"""Check that test dependencies are not concretized recursively."""
|
||||||
|
env('create', 'test')
|
||||||
|
|
||||||
|
with ev.read('test') as e:
|
||||||
|
e.concretization = concretization
|
||||||
|
add('depb')
|
||||||
|
concretize('--test', 'root')
|
||||||
|
assert e.matching_spec('test-dependency') is None
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('concretization', ['separately', 'together'])
|
||||||
|
def test_concretize_root_test_dependencies_are_concretized(concretization):
|
||||||
|
"""Check that root test dependencies are concretized."""
|
||||||
|
env('create', 'test')
|
||||||
|
|
||||||
|
with ev.read('test') as e:
|
||||||
|
e.concretization = concretization
|
||||||
|
add('a')
|
||||||
|
add('b')
|
||||||
|
concretize('--test', 'root')
|
||||||
|
assert e.matching_spec('test-dependency')
|
||||||
@@ -885,3 +885,23 @@ def test_cache_install_full_hash_match(
|
|||||||
|
|
||||||
uninstall('-y', s.name)
|
uninstall('-y', s.name)
|
||||||
mirror('rm', 'test-mirror')
|
mirror('rm', 'test-mirror')
|
||||||
|
|
||||||
|
|
||||||
|
def test_install_env_with_tests_all(tmpdir, mock_packages, mock_fetch,
|
||||||
|
install_mockery, mutable_mock_env_path):
|
||||||
|
env('create', 'test')
|
||||||
|
with ev.read('test'):
|
||||||
|
test_dep = Spec('test-dependency').concretized()
|
||||||
|
add('depb')
|
||||||
|
install('--test', 'all')
|
||||||
|
assert os.path.exists(test_dep.prefix)
|
||||||
|
|
||||||
|
|
||||||
|
def test_install_env_with_tests_root(tmpdir, mock_packages, mock_fetch,
|
||||||
|
install_mockery, mutable_mock_env_path):
|
||||||
|
env('create', 'test')
|
||||||
|
with ev.read('test'):
|
||||||
|
test_dep = Spec('test-dependency').concretized()
|
||||||
|
add('depb')
|
||||||
|
install('--test', 'root')
|
||||||
|
assert not os.path.exists(test_dep.prefix)
|
||||||
|
|||||||
@@ -660,8 +660,7 @@ def test_simultaneous_concretization_of_specs(self, abstract_specs):
|
|||||||
|
|
||||||
abstract_specs = [Spec(x) for x in abstract_specs]
|
abstract_specs = [Spec(x) for x in abstract_specs]
|
||||||
concrete_specs = spack.concretize.concretize_specs_together(
|
concrete_specs = spack.concretize.concretize_specs_together(
|
||||||
*abstract_specs
|
*abstract_specs)
|
||||||
)
|
|
||||||
|
|
||||||
# Check there's only one configuration of each package in the DAG
|
# Check there's only one configuration of each package in the DAG
|
||||||
names = set(
|
names = set(
|
||||||
|
|||||||
@@ -579,7 +579,7 @@ _spack_compilers() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_spack_concretize() {
|
_spack_concretize() {
|
||||||
SPACK_COMPREPLY="-h --help -f --force"
|
SPACK_COMPREPLY="-h --help -f --force --test"
|
||||||
}
|
}
|
||||||
|
|
||||||
_spack_config() {
|
_spack_config() {
|
||||||
|
|||||||
Reference in New Issue
Block a user