Compare commits

...

3 Commits

Author SHA1 Message Date
Gregory Becker
a542b0cfc0 flake 2023-02-16 19:29:35 -08:00
Gregory Becker
0d02262bbc docs 2023-02-16 19:13:04 -08:00
Gregory Becker
9beac03142 SpecList: enforce ordering of matrices on constructed specs 2023-02-16 19:12:52 -08:00
5 changed files with 58 additions and 36 deletions

View File

@@ -630,6 +630,35 @@ The following two Environment manifests are identical:
Spec matrices can be used to install swaths of software across various
toolchains.
Note that ordering of matrices is important. For example, the
following environments are identical:
.. code-block:: yaml
spack:
specs:
- matrix:
- [hdf5@1.10.2+mpi]
- [^mpich, ^openmpi]
- ['%gcc']
- matrix:
- [hdf5@1.12.1+mpi]
- ['%gcc']
- [^mpich, ^openmpi]
spack:
specs:
- hdf5@1.10.2+mpi ^mpich%gcc
- hdf5@1.10.2+mpi ^openmpi%gcc
- hdf5@1.12.1+mpi %gcc ^mpich
- hdf5@1.12.1+mpi %gcc ^openmpi
Notice how the first matrix applies the compiler constraints to the
mpi dependencies, whereas the second matrix applies the compiler
constraints directly to the root hdf5 node. This gives users the full
breadth of expressiveness of the spec syntax through the matrix
interface.
^^^^^^^^^^^^^^^^^^^^
Spec List References
^^^^^^^^^^^^^^^^^^^^

View File

@@ -2265,15 +2265,12 @@ def _concretize_from_constraints(spec_constraints, tests=False):
m += "concretization target. all specs must have a single name "
m += "constraint for concretization."
raise InvalidSpecConstraintError(m)
spec_constraints.remove(root_spec[0])
invalid_constraints = []
while True:
# Attach all anonymous constraints to one named spec
s = root_spec[0].copy()
for c in spec_constraints:
if c not in invalid_constraints:
s.constrain(c)
# Combine constraints into a single spec
s = Spec(" ".join([str(c) for c in spec_constraints if c not in invalid_constraints]))
try:
return s.concretized(tests=tests)
except spack.spec.InvalidDependencyError as e:

View File

@@ -51,7 +51,9 @@ def specs_as_constraints(self):
constraints = []
for item in self.specs_as_yaml_list:
if isinstance(item, dict): # matrix of specs
constraints.extend(_expand_matrix_constraints(item))
expanded = _expand_matrix_constraints(item)
for e in expanded:
constraints.append([Spec(x) for x in e])
else: # individual spec
constraints.append([Spec(item)])
self._constraints = constraints
@@ -62,13 +64,11 @@ def specs_as_constraints(self):
def specs(self):
if self._specs is None:
specs = []
# This could be slightly faster done directly from yaml_list,
# but this way is easier to maintain.
for constraint_list in self.specs_as_constraints:
spec = constraint_list[0].copy()
for const in constraint_list[1:]:
spec.constrain(const)
specs.append(spec)
for item in self.specs_as_yaml_list:
if isinstance(item, dict): # matrix of specs
specs.extend([Spec(" ".join(x)) for x in _expand_matrix_constraints(item)])
else: # individual spec
specs.append(Spec(item))
self._specs = specs
return self._specs
@@ -193,11 +193,7 @@ def _expand_matrix_constraints(matrix_config):
for combo in itertools.product(*expanded_rows):
# Construct a combined spec to test against excludes
flat_combo = [constraint for constraint_list in combo for constraint in constraint_list]
flat_combo = [Spec(x) for x in flat_combo]
test_spec = flat_combo[0].copy()
for constraint in flat_combo[1:]:
test_spec.constrain(constraint)
test_spec = Spec(" ".join(flat_combo))
# Abstract variants don't have normal satisfaction semantics
# Convert all variants to concrete types.
@@ -213,7 +209,7 @@ def _expand_matrix_constraints(matrix_config):
continue
if sigil:
flat_combo[0] = Spec(sigil + str(flat_combo[0]))
flat_combo[0] = sigil + flat_combo[0]
# Add to list of constraints
results.append(flat_combo)

View File

@@ -75,8 +75,8 @@ def test_env_change_spec(tmpdir, mock_packages, config):
- desired_specs: ["mpileaks@2.1"]
specs:
- matrix:
- [$compilers]
- [$desired_specs]
- [$compilers]
"""

View File

@@ -61,25 +61,25 @@ def test_spec_list_expansions(self):
@pytest.mark.parametrize(
"specs,expected",
[
# Constraints are ordered randomly
# Constraints are ordered carefully to apply to appropriate node
(
[
{
"matrix": [
["^zmpi"],
["%gcc@4.5.0"],
["hypre", "libelf"],
["~shared"],
["cflags=-O3", 'cflags="-g -O0"'],
["^foo"],
["^zmpi"],
["%gcc@4.5.0"],
["cflags=-O3", 'cflags="-g -O0"'],
]
}
],
[
"hypre cflags=-O3 ~shared %gcc@4.5.0 ^foo ^zmpi",
'hypre cflags="-g -O0" ~shared %gcc@4.5.0 ^foo ^zmpi',
"libelf cflags=-O3 ~shared %gcc@4.5.0 ^foo ^zmpi",
'libelf cflags="-g -O0" ~shared %gcc@4.5.0 ^foo ^zmpi',
"hypre ~shared ^foo ^zmpi cflags=-O3 %gcc@4.5.0",
'hypre ~shared ^foo ^zmpi cflags="-g -O0" %gcc@4.5.0',
"libelf ~shared ^foo ^zmpi cflags=-O3 %gcc@4.5.0",
'libelf ~shared ^foo ^zmpi cflags="-g -O0" %gcc@4.5.0',
],
),
# A constraint affects both the root and a dependency