# Copyright 2013-2023 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 os
import pytest
import spack.config
import spack.environment as ev
import spack.package_base
import spack.repo
import spack.stage
import spack.traverse
from spack.main import SpackCommand, SpackCommandError
from spack.version import Version
stage = SpackCommand("stage")
env = SpackCommand("env")
pytestmark = pytest.mark.usefixtures("install_mockery", "mock_packages")
@pytest.mark.not_on_windows("not implemented on windows")
@pytest.mark.disable_clean_stage_check
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_base.PackageBase, "do_stage", fake_stage)
stage("trivial-install-test-package", "mpileaks")
assert len(expected) == 0
@pytest.fixture(scope="function")
def check_stage_path(monkeypatch, tmpdir):
expected_path = os.path.join(str(tmpdir), "x")
def fake_stage(pkg, mirror_only=False):
assert pkg.path == expected_path
monkeypatch.setattr(spack.package_base.PackageBase, "do_stage", fake_stage)
return expected_path
@pytest.mark.not_on_windows("PermissionError")
def test_stage_path(check_stage_path):
"""Verify that --path only works with single specs."""
stage("--path={0}".format(check_stage_path), "trivial-install-test-package")
def test_stage_path_errors_multiple_specs(check_stage_path):
"""Verify that --path only works with single specs."""
with pytest.raises(SpackCommandError):
stage(f"--path={check_stage_path}", "trivial-install-test-package", "mpileaks")
@pytest.mark.not_on_windows("not implemented on windows")
@pytest.mark.disable_clean_stage_check
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_base.PackageBase, "do_stage", fake_stage)
e = ev.create("test")
e.add("mpileaks")
e.concretize()
with e:
stage("trivial-install-test-package")
@pytest.mark.not_on_windows("not implemented on windows")
@pytest.mark.disable_clean_stage_check
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_base.PackageBase, "do_stage", fake_stage)
e = ev.create("test")
e.add("mpileaks@=100.100")
e.concretize()
with e:
stage("mpileaks")
@pytest.mark.not_on_windows("not implemented on windows")
@pytest.mark.disable_clean_stage_check
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(dep.name for dep in spack.traverse.traverse_nodes(e.concrete_roots()))
# 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_base.PackageBase, "do_stage", fake_stage)
with e:
stage()
# assert that all were staged
assert len(expected) == 0
@pytest.mark.disable_clean_stage_check
def test_concretizer_arguments(mock_packages, mock_fetch):
"""Make sure stage also has --reuse and --fresh flags."""
stage("--reuse", "trivial-install-test-package")
assert spack.config.get("concretizer:reuse", None) is True
stage("--fresh", "trivial-install-test-package")
assert spack.config.get("concretizer:reuse", None) is False