# Copyright 2013-2024 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 argparse
import pytest
import spack.cmd
import spack.cmd.common.arguments as arguments
import spack.config
import spack.environment as ev
import spack.main
@pytest.fixture()
def job_parser():
# --jobs needs to write to a command_line config scope, so this is the only
# scope we create.
p = argparse.ArgumentParser()
arguments.add_common_arguments(p, ["jobs"])
scopes = [spack.config.InternalConfigScope("command_line", {"config": {}})]
with spack.config.use_configuration(*scopes):
yield p
def test_setting_jobs_flag(job_parser):
namespace = job_parser.parse_args(["-j", "24"])
assert namespace.jobs == 24
assert spack.config.get("config:build_jobs", scope="command_line") == 24
def test_omitted_job_flag(job_parser):
namespace = job_parser.parse_args([])
assert namespace.jobs is None
assert spack.config.get("config:build_jobs") is None
def test_negative_integers_not_allowed_for_parallel_jobs(job_parser):
with pytest.raises(ValueError) as exc_info:
job_parser.parse_args(["-j", "-2"])
assert "expected a positive integer" in str(exc_info.value)
@pytest.mark.parametrize(
"specs,cflags,propagation,negated_variants",
[
(['coreutils cflags="-O3 -g"'], ["-O3", "-g"], [False, False], []),
(['coreutils cflags=="-O3 -g"'], ["-O3", "-g"], [True, True], []),
(["coreutils", "cflags=-O3 -g"], ["-O3", "-g"], [False, False], []),
(["coreutils", "cflags==-O3 -g"], ["-O3", "-g"], [True, True], []),
(["coreutils", "cflags=-O3", "-g"], ["-O3"], [False], ["g"]),
],
)
@pytest.mark.regression("12951")
def test_parse_spec_flags_with_spaces(specs, cflags, propagation, negated_variants):
spec_list = spack.cmd.parse_specs(specs)
assert len(spec_list) == 1
s = spec_list.pop()
compiler_flags = [flag for flag in s.compiler_flags["cflags"]]
flag_propagation = [flag.propagate for flag in s.compiler_flags["cflags"]]
assert compiler_flags == cflags
assert flag_propagation == propagation
assert list(s.variants.keys()) == negated_variants
for v in negated_variants:
assert "~{0}".format(v) in s
@pytest.mark.usefixtures("config")
def test_match_spec_env(mock_packages, mutable_mock_env_path):
"""
Concretize a spec with non-default options in an environment. Make
sure that when we ask for a matching spec when the environment is
active that we get the instance concretized in the environment.
"""
# Initial sanity check: we are planning on choosing a non-default
# value, so make sure that is in fact not the default.
check_defaults = spack.cmd.parse_specs(["a"], concretize=True)[0]
assert not check_defaults.satisfies("foobar=baz")
e = ev.create("test")
e.add("a foobar=baz")
e.concretize()
with e:
env_spec = spack.cmd.matching_spec_from_env(spack.cmd.parse_specs(["a"])[0])
assert env_spec.satisfies("foobar=baz")
assert env_spec.concrete
@pytest.mark.usefixtures("config")
def test_multiple_env_match_raises_error(mock_packages, mutable_mock_env_path):
e = ev.create("test")
e.add("a foobar=baz")
e.add("a foobar=fee")
e.concretize()
with e:
with pytest.raises(ev.SpackEnvironmentError) as exc_info:
spack.cmd.matching_spec_from_env(spack.cmd.parse_specs(["a"])[0])
assert "matches multiple specs" in exc_info.value.message
@pytest.mark.usefixtures("config")
def test_root_and_dep_match_returns_root(mock_packages, mutable_mock_env_path):
e = ev.create("test")
e.add("b@0.9")
e.add("a foobar=bar") # Depends on b, should choose b@1.0
e.concretize()
with e:
# This query matches the root b and b as a dependency of a. In that
# case the root instance should be preferred.
env_spec1 = spack.cmd.matching_spec_from_env(spack.cmd.parse_specs(["b"])[0])
assert env_spec1.satisfies("@0.9")
env_spec2 = spack.cmd.matching_spec_from_env(spack.cmd.parse_specs(["b@1.0"])[0])
assert env_spec2
@pytest.mark.parametrize(
"arg,config", [("--reuse", True), ("--fresh", False), ("--reuse-deps", "dependencies")]
)
def test_concretizer_arguments(mutable_config, mock_packages, arg, config):
"""Ensure that ConfigSetAction is doing the right thing."""
spec = spack.main.SpackCommand("spec")
assert spack.config.get("concretizer:reuse", None) is None
spec(arg, "zlib")
assert spack.config.get("concretizer:reuse", None) == config
def test_use_buildcache_type():
assert arguments.use_buildcache("only") == ("only", "only")
assert arguments.use_buildcache("never") == ("never", "never")
assert arguments.use_buildcache("auto") == ("auto", "auto")
assert arguments.use_buildcache("package:never,dependencies:only") == ("never", "only")
assert arguments.use_buildcache("only,package:never") == ("never", "only")
assert arguments.use_buildcache("package:only,package:never") == ("never", "auto")
assert arguments.use_buildcache("auto , package: only") == ("only", "auto")
with pytest.raises(argparse.ArgumentTypeError):
assert arguments.use_buildcache("pkg:only,deps:never")
with pytest.raises(argparse.ArgumentTypeError):
assert arguments.use_buildcache("sometimes")