summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorHarmen Stoppels <harmenstoppels@gmail.com>2021-03-29 20:10:44 +0200
committerGitHub <noreply@github.com>2021-03-29 11:10:44 -0700
commite89c9ec0823d914845aaa5587d8ee1e89f4568fa (patch)
tree72679687604de2cfe9c6b0d73eab237896334d72 /lib
parentf9cc073be0bf706adfb2a8ffd20f380bbfa7a1be (diff)
downloadspack-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.
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/spack/cmd/stage.py8
-rw-r--r--lib/spack/spack/test/cmd/stage.py114
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