From c3e41153ac92f6ef92414024a8386d4ceec2615c Mon Sep 17 00:00:00 2001 From: Peter Scheibel Date: Mon, 20 Mar 2023 12:30:33 -0700 Subject: Package requirements: allow single specs in requirement lists (#36258) If you have a "require:" section in your packages config, and you use it to specify a list of requirements, the list elements can now include strings (before this, each element in the list had to be a `one_of` or `any_of` specification, which is awkward if you wanted to apply just one spec with no alternatives). --- lib/spack/spack/schema/packages.py | 15 ++++++++++----- lib/spack/spack/solver/asp.py | 11 ++++++++--- lib/spack/spack/test/concretize_requirements.py | 18 +++++++++++++++++- 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/lib/spack/spack/schema/packages.py b/lib/spack/spack/schema/packages.py index 1f7c16e2d7..fe27557e68 100644 --- a/lib/spack/spack/schema/packages.py +++ b/lib/spack/spack/schema/packages.py @@ -32,11 +32,16 @@ properties = { { "type": "array", "items": { - "type": "object", - "properties": { - "one_of": {"type": "array"}, - "any_of": {"type": "array"}, - }, + "oneOf": [ + { + "type": "object", + "properties": { + "one_of": {"type": "array"}, + "any_of": {"type": "array"}, + }, + }, + {"type": "string"}, + ] }, }, # Shorthand for a single requirement group with diff --git a/lib/spack/spack/solver/asp.py b/lib/spack/spack/solver/asp.py index 42ce486233..8b9acd8b5e 100644 --- a/lib/spack/spack/solver/asp.py +++ b/lib/spack/spack/solver/asp.py @@ -1017,9 +1017,14 @@ class SpackSolverSetup(object): else: rules = [] for requirement in requirements: - for policy in ("one_of", "any_of"): - if policy in requirement: - rules.append((pkg_name, policy, requirement[policy])) + if isinstance(requirement, str): + # A string represents a spec that must be satisfied. It is + # equivalent to a one_of group with a single element + rules.append((pkg_name, "one_of", [requirement])) + else: + for policy in ("one_of", "any_of"): + if policy in requirement: + rules.append((pkg_name, policy, requirement[policy])) return rules def pkg_rules(self, pkg, tests): diff --git a/lib/spack/spack/test/concretize_requirements.py b/lib/spack/spack/test/concretize_requirements.py index 965d85e93d..f58cd87694 100644 --- a/lib/spack/spack/test/concretize_requirements.py +++ b/lib/spack/spack/test/concretize_requirements.py @@ -107,12 +107,28 @@ def fake_installs(monkeypatch, tmpdir): ) +def test_one_package_multiple_reqs(concretize_scope, test_repo): + if spack.config.get("config:concretizer") == "original": + pytest.skip("Original concretizer does not support configuration requirements") + + conf_str = """\ +packages: + y: + require: + - "@2.4" + - "~shared" +""" + update_packages_config(conf_str) + y_spec = Spec("y").concretized() + assert y_spec.satisfies("@2.4~shared") + + def test_requirement_isnt_optional(concretize_scope, test_repo): """If a user spec requests something that directly conflicts with a requirement, make sure we get an error. """ if spack.config.get("config:concretizer") == "original": - pytest.skip("Original concretizer does not support configuration" " requirements") + pytest.skip("Original concretizer does not support configuration requirements") conf_str = """\ packages: -- cgit v1.2.3-60-g2f50