diff options
author | Massimiliano Culpo <massimiliano.culpo@gmail.com> | 2024-01-26 09:48:53 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-01-26 09:48:53 +0100 |
commit | 19df8e45ec887d8168fd98795b29cfcb1168f70a (patch) | |
tree | b5681c323e1a11bc88b99e50c3606ad652639b3a | |
parent | 4c7a1f541caee161584abfa965920eb27df575ab (diff) | |
download | spack-19df8e45ec887d8168fd98795b29cfcb1168f70a.tar.gz spack-19df8e45ec887d8168fd98795b29cfcb1168f70a.tar.bz2 spack-19df8e45ec887d8168fd98795b29cfcb1168f70a.tar.xz spack-19df8e45ec887d8168fd98795b29cfcb1168f70a.zip |
Merge `virtuals=` from duplicate dependencies (#42281)
Previously, for abstract specs like:
```
foo ^[virtuals=a] bar ^[virtuals=b] bar
```
the second requirement was silently discarded on concretization. Now they're merged, and the abstract spec is equivalent to:
```
foo ^[virtuals=a,b] bar
```
-rw-r--r-- | lib/spack/spack/spec.py | 16 | ||||
-rw-r--r-- | lib/spack/spack/test/spec_syntax.py | 17 |
2 files changed, 25 insertions, 8 deletions
diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py index 641ad1f5e9..eb6c81a9ae 100644 --- a/lib/spack/spack/spec.py +++ b/lib/spack/spack/spec.py @@ -1640,23 +1640,23 @@ class Spec: self.add_dependency_edge(spec, depflag=depflag, virtuals=virtuals) return - # Keep the intersection of constraints when a dependency is added - # multiple times. Currently, we only allow identical edge types. + # Keep the intersection of constraints when a dependency is added multiple times. + # The only restriction, currently, is keeping the same dependency type orig = self._dependencies[spec.name] try: dspec = next(dspec for dspec in orig if depflag == dspec.depflag) except StopIteration: - current_deps = ", ".join( - dt.flag_to_chars(x.depflag) + " " + x.spec.short_spec for x in orig - ) + edge_attrs = f"deptypes={dt.flag_to_chars(depflag).strip()}" + required_dep_str = f"^[{edge_attrs}] {str(spec)}" + raise DuplicateDependencyError( - f"{self.short_spec} cannot depend on '{spec.short_spec}' multiple times.\n" - f"\tRequired: {dt.flag_to_chars(depflag)}\n" - f"\tDependency: {current_deps}" + f"{spec.name} is a duplicate dependency, with conflicting dependency types\n" + f"\t'{str(self)}' cannot depend on '{required_dep_str}'" ) try: dspec.spec.constrain(spec) + dspec.update_virtuals(virtuals=virtuals) except spack.error.UnsatisfiableSpecError: raise DuplicateDependencyError( f"Cannot depend on incompatible specs '{dspec.spec}' and '{spec}'" diff --git a/lib/spack/spack/test/spec_syntax.py b/lib/spack/spack/test/spec_syntax.py index c421494ce8..49f6de3b65 100644 --- a/lib/spack/spack/test/spec_syntax.py +++ b/lib/spack/spack/test/spec_syntax.py @@ -523,6 +523,23 @@ def specfile_for(default_mock_concretization): ], "^[virtuals=mpi] openmpi", ), + # Allow merging attributes, if deptypes match + ( + "^[virtuals=mpi] openmpi+foo ^[virtuals=lapack] openmpi+bar", + [ + Token(TokenType.START_EDGE_PROPERTIES, value="^["), + Token(TokenType.KEY_VALUE_PAIR, value="virtuals=mpi"), + Token(TokenType.END_EDGE_PROPERTIES, value="]"), + Token(TokenType.UNQUALIFIED_PACKAGE_NAME, value="openmpi"), + Token(TokenType.BOOL_VARIANT, value="+foo"), + Token(TokenType.START_EDGE_PROPERTIES, value="^["), + Token(TokenType.KEY_VALUE_PAIR, value="virtuals=lapack"), + Token(TokenType.END_EDGE_PROPERTIES, value="]"), + Token(TokenType.UNQUALIFIED_PACKAGE_NAME, value="openmpi"), + Token(TokenType.BOOL_VARIANT, value="+bar"), + ], + "^[virtuals=lapack,mpi] openmpi+bar+foo", + ), ( "^[deptypes=link,build] zlib", [ |