Allow default requirements in packages.yaml (#32260)
Allow users to express default requirements in packages.yaml. These requirements are overridden if more specific requirements are present for a given package.
This commit is contained in:
parent
b4df535e8d
commit
e2468c8928
3 changed files with 81 additions and 3 deletions
|
@ -396,10 +396,34 @@ choose between a set of options using ``any_of`` or ``one_of``:
|
||||||
``mpich`` already includes a conflict, so this is redundant but
|
``mpich`` already includes a conflict, so this is redundant but
|
||||||
still demonstrates the concept).
|
still demonstrates the concept).
|
||||||
|
|
||||||
|
You can also set default requirements for all packages under ``all``
|
||||||
|
like this:
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
packages:
|
||||||
|
all:
|
||||||
|
require: '%clang'
|
||||||
|
|
||||||
|
which means every spec will be required to use ``clang`` as a compiler.
|
||||||
|
|
||||||
|
Note that in this case ``all`` represents a *default set of requirements* -
|
||||||
|
if there are specific package requirements, then the default requirements
|
||||||
|
under ``all`` are disregarded. For example, with a configuration like this:
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
packages:
|
||||||
|
all:
|
||||||
|
require: '%clang'
|
||||||
|
cmake:
|
||||||
|
require: '%gcc'
|
||||||
|
|
||||||
|
Spack requires ``cmake`` to use ``gcc`` and all other nodes (including cmake dependencies)
|
||||||
|
to use ``clang``.
|
||||||
|
|
||||||
Other notes about ``requires``:
|
Other notes about ``requires``:
|
||||||
|
|
||||||
* You can only specify requirements for specific packages: you cannot
|
|
||||||
add ``requires`` under ``all``.
|
|
||||||
* You cannot specify requirements for virtual packages (e.g. you can
|
* You cannot specify requirements for virtual packages (e.g. you can
|
||||||
specify requirements for ``openmpi`` but not ``mpi``).
|
specify requirements for ``openmpi`` but not ``mpi``).
|
||||||
* For ``any_of`` and ``one_of``, the order of specs indicates a
|
* For ``any_of`` and ``one_of``, the order of specs indicates a
|
||||||
|
|
|
@ -942,7 +942,9 @@ def package_compiler_defaults(self, pkg):
|
||||||
def package_requirement_rules(self, pkg):
|
def package_requirement_rules(self, pkg):
|
||||||
pkg_name = pkg.name
|
pkg_name = pkg.name
|
||||||
config = spack.config.get("packages")
|
config = spack.config.get("packages")
|
||||||
requirements = config.get(pkg_name, {}).get("require", [])
|
requirements = config.get(pkg_name, {}).get("require", []) or config.get("all", {}).get(
|
||||||
|
"require", []
|
||||||
|
)
|
||||||
if isinstance(requirements, string_types):
|
if isinstance(requirements, string_types):
|
||||||
rules = [(pkg_name, "one_of", [requirements])]
|
rules = [(pkg_name, "one_of", [requirements])]
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -297,3 +297,55 @@ def test_requirements_are_higher_priority_than_deprecation(concretize_scope, tes
|
||||||
s1 = Spec("y").concretized()
|
s1 = Spec("y").concretized()
|
||||||
assert s1.satisfies("@2.3")
|
assert s1.satisfies("@2.3")
|
||||||
assert s1.satisfies("%gcc")
|
assert s1.satisfies("%gcc")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("spec_str,requirement_str", [("x", "%gcc"), ("x", "%clang")])
|
||||||
|
def test_default_requirements_with_all(spec_str, requirement_str, concretize_scope, test_repo):
|
||||||
|
"""Test that default requirements are applied to all packages."""
|
||||||
|
if spack.config.get("config:concretizer") == "original":
|
||||||
|
pytest.skip("Original concretizer does not support configuration" " requirements")
|
||||||
|
|
||||||
|
conf_str = """\
|
||||||
|
packages:
|
||||||
|
all:
|
||||||
|
require: "{}"
|
||||||
|
""".format(
|
||||||
|
requirement_str
|
||||||
|
)
|
||||||
|
update_packages_config(conf_str)
|
||||||
|
|
||||||
|
spec = Spec(spec_str).concretized()
|
||||||
|
for s in spec.traverse():
|
||||||
|
assert s.satisfies(requirement_str)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"requirements,expectations",
|
||||||
|
[
|
||||||
|
(("%gcc", "%clang"), ("%gcc", "%clang")),
|
||||||
|
(("%gcc ~shared", "@1.0"), ("%gcc ~shared", "@1.0 +shared")),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_default_and_package_specific_requirements(
|
||||||
|
concretize_scope, requirements, expectations, test_repo
|
||||||
|
):
|
||||||
|
"""Test that specific package requirements override default package requirements."""
|
||||||
|
if spack.config.get("config:concretizer") == "original":
|
||||||
|
pytest.skip("Original concretizer does not support configuration" " requirements")
|
||||||
|
generic_req, specific_req = requirements
|
||||||
|
generic_exp, specific_exp = expectations
|
||||||
|
conf_str = """\
|
||||||
|
packages:
|
||||||
|
all:
|
||||||
|
require: "{}"
|
||||||
|
x:
|
||||||
|
require: "{}"
|
||||||
|
""".format(
|
||||||
|
generic_req, specific_req
|
||||||
|
)
|
||||||
|
update_packages_config(conf_str)
|
||||||
|
|
||||||
|
spec = Spec("x").concretized()
|
||||||
|
assert spec.satisfies(specific_exp)
|
||||||
|
for s in spec.traverse(root=False):
|
||||||
|
assert s.satisfies(generic_exp)
|
||||||
|
|
Loading…
Reference in a new issue