diff options
author | Harmen Stoppels <harmenstoppels@gmail.com> | 2021-03-29 20:10:44 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-29 11:10:44 -0700 |
commit | e89c9ec0823d914845aaa5587d8ee1e89f4568fa (patch) | |
tree | 72679687604de2cfe9c6b0d73eab237896334d72 | |
parent | f9cc073be0bf706adfb2a8ffd20f380bbfa7a1be (diff) | |
download | spack-e89c9ec0823d914845aaa5587d8ee1e89f4568fa.tar.gz spack-e89c9ec0823d914845aaa5587d8ee1e89f4568fa.tar.bz2 spack-e89c9ec0823d914845aaa5587d8ee1e89f4568fa.tar.xz spack-e89c9ec0823d914845aaa5587d8ee1e89f4568fa.zip |
Make stage use concrete specs from environment (#22320)
* Make stage use concrete specs from environment
Same as in https://github.com/spack/spack/pull/21642, the idea is that
we want to easily stage a package that fails to build in a complex
environment. Instead of making the user create a spec by hand (basically
transforming all the rules in the environment manifest into a spec,
defying the purpose of the environment...), use the provided spec as a
filter for the already concretized specs. This also speeds up things,
cause we don't have to reconcretize.
-rw-r--r-- | lib/spack/spack/cmd/stage.py | 8 | ||||
-rw-r--r-- | lib/spack/spack/test/cmd/stage.py | 114 |
2 files changed, 121 insertions, 1 deletions
diff --git a/lib/spack/spack/cmd/stage.py b/lib/spack/spack/cmd/stage.py index 62073f10bd..639f32f28a 100644 --- a/lib/spack/spack/cmd/stage.py +++ b/lib/spack/spack/cmd/stage.py @@ -41,8 +41,14 @@ def stage(parser, args): if args.deprecated: spack.config.set('config:deprecated', True, scope='command_line') - specs = spack.cmd.parse_specs(args.specs, concretize=True) + specs = spack.cmd.parse_specs(args.specs, concretize=False) + + # prevent multiple specs from extracting in the same folder + if len(specs) > 1 and args.path: + tty.die("`--path` requires a single spec, but multiple were provided") + for spec in specs: + spec = spack.cmd.matching_spec_from_env(spec) package = spack.repo.get(spec) if args.path: package.path = args.path diff --git a/lib/spack/spack/test/cmd/stage.py b/lib/spack/spack/test/cmd/stage.py new file mode 100644 index 0000000000..481694dc6e --- /dev/null +++ b/lib/spack/spack/test/cmd/stage.py @@ -0,0 +1,114 @@ +# 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 +from spack.main import SpackCommand +import spack.environment as ev +import spack.repo +from spack.version import Version + + +stage = SpackCommand('stage') +env = SpackCommand('env') + +pytestmark = pytest.mark.usefixtures('install_mockery', 'mock_packages') + + +def test_stage_spec(monkeypatch): + """Verify that staging specs works.""" + + expected = set(['trivial-install-test-package', 'mpileaks']) + + def fake_stage(pkg, mirror_only=False): + expected.remove(pkg.name) + + monkeypatch.setattr(spack.package.PackageBase, 'do_stage', fake_stage) + + stage('trivial-install-test-package', 'mpileaks') + + assert len(expected) == 0 + + +def test_stage_path(monkeypatch): + """Verify that --path only works with single specs.""" + + def fake_stage(pkg, mirror_only=False): + assert pkg.path == 'x' + + monkeypatch.setattr(spack.package.PackageBase, 'do_stage', fake_stage) + + stage('--path=x', 'trivial-install-test-package') + + +def test_stage_path_errors_multiple_specs(monkeypatch): + """Verify that --path only works with single specs.""" + + def fake_stage(pkg, mirror_only=False): + pass + + monkeypatch.setattr(spack.package.PackageBase, 'do_stage', fake_stage) + + with pytest.raises(spack.main.SpackCommandError): + stage('--path=x', 'trivial-install-test-package', 'mpileaks') + + +def test_stage_with_env_outside_env(mutable_mock_env_path, monkeypatch): + """Verify that stage concretizes specs not in environment instead of erroring.""" + + def fake_stage(pkg, mirror_only=False): + assert pkg.name == 'trivial-install-test-package' + assert pkg.path is None + + monkeypatch.setattr(spack.package.PackageBase, 'do_stage', fake_stage) + + e = ev.create('test') + e.add('mpileaks') + e.concretize() + + with e: + stage('trivial-install-test-package') + + +def test_stage_with_env_inside_env(mutable_mock_env_path, monkeypatch): + """Verify that stage filters specs in environment instead of reconcretizing.""" + + def fake_stage(pkg, mirror_only=False): + assert pkg.name == 'mpileaks' + assert pkg.version == Version('100.100') + + monkeypatch.setattr(spack.package.PackageBase, 'do_stage', fake_stage) + + e = ev.create('test') + e.add('mpileaks@100.100') + e.concretize() + + with e: + stage('mpileaks') + + +def test_stage_full_env(mutable_mock_env_path, monkeypatch): + """Verify that stage filters specs in environment.""" + + e = ev.create('test') + e.add('mpileaks@100.100') + e.concretize() + + # list all the package names that should be staged + expected = set() + for spec in e.specs_by_hash.values(): + for dep in spec.traverse(): + expected.add(dep.name) + + # pop the package name from the list instead of actually staging + def fake_stage(pkg, mirror_only=False): + expected.remove(pkg.name) + + monkeypatch.setattr(spack.package.PackageBase, 'do_stage', fake_stage) + + with e: + stage() + + # assert that all were staged + assert len(expected) == 0 |