summaryrefslogtreecommitdiff
path: root/lib/spack/spack/spec.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/spack/spack/spec.py')
-rw-r--r--lib/spack/spack/spec.py52
1 files changed, 30 insertions, 22 deletions
diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py
index b7a819cc46..fa88698ea9 100644
--- a/lib/spack/spack/spec.py
+++ b/lib/spack/spack/spec.py
@@ -581,8 +581,11 @@ class DependencySpec(object):
self.deptypes = tuple(sorted(set(deptypes)))
def update_deptypes(self, deptypes):
- deptypes = tuple(sorted(set(deptypes)))
+ deptypes = set(deptypes)
+ deptypes.update(self.deptypes)
+ deptypes = tuple(sorted(deptypes))
changed = self.deptypes != deptypes
+
self.deptypes = deptypes
return changed
@@ -1801,6 +1804,8 @@ class Spec(object):
dependency already in this spec.
"""
assert(vdep.virtual)
+
+ # note that this defensively copies.
providers = provider_index.providers_for(vdep)
# If there is a provider for the vpkg, then use that instead of
@@ -1830,6 +1835,10 @@ class Spec(object):
provider_index):
"""Merge the dependency into this spec.
+ Caller should assume that this routine can owns the dep parameter
+ (i.e. it needs to be a copy of any internal structures like
+ dependencies on Package class objects).
+
This is the core of normalize(). There are some basic steps:
* If dep is virtual, evaluate whether it corresponds to an
@@ -1842,6 +1851,7 @@ class Spec(object):
constraints into this spec.
This method returns True if the spec was changed, False otherwise.
+
"""
changed = False
@@ -1854,7 +1864,8 @@ class Spec(object):
dep = provider
else:
index = ProviderIndex([dep], restrict=True)
- for vspec in (v for v in spec_deps.values() if v.virtual):
+ items = list(spec_deps.items())
+ for name, vspec in items:
if index.providers_for(vspec):
vspec._replace_with(dep)
del spec_deps[vspec.name]
@@ -1865,29 +1876,23 @@ class Spec(object):
raise UnsatisfiableProviderSpecError(required[0], dep)
provider_index.update(dep)
- # If the spec isn't already in the set of dependencies, clone
- # it from the package description.
+ # If the spec isn't already in the set of dependencies, add it.
+ # Note: dep is always owned by this method. If it's from the
+ # caller, it's a copy from _evaluate_dependency_conditions. If it
+ # comes from a vdep, it's a defensive copy from _find_provider.
if dep.name not in spec_deps:
- spec_deps[dep.name] = dep.copy()
+ spec_deps[dep.name] = dep
changed = True
else:
- dspec = spec_deps[dep.name]
- if self.name not in dspec._dependents:
- self._add_dependency(dspec, deptypes)
- else:
- dependent = dspec._dependents[self.name]
- changed = dependent.update_deptypes(deptypes)
-
- # Constrain package information with spec info
- try:
- changed |= spec_deps[dep.name].constrain(dep)
-
- except UnsatisfiableSpecError as e:
- e.message = "Invalid spec: '%s'. "
- e.message += "Package %s requires %s %s, but spec asked for %s"
- e.message %= (spec_deps[dep.name], dep.name,
- e.constraint_type, e.required, e.provided)
- raise e
+ # merge package/vdep information into spec
+ try:
+ changed |= spec_deps[dep.name].constrain(dep)
+ except UnsatisfiableSpecError as e:
+ e.message = "Invalid spec: '%s'. "
+ e.message += "Package %s requires %s %s, but spec asked for %s"
+ e.message %= (spec_deps[dep.name], dep.name,
+ e.constraint_type, e.required, e.provided)
+ raise e
# Add merged spec to my deps and recurse
dependency = spec_deps[dep.name]
@@ -2097,6 +2102,9 @@ class Spec(object):
changed = False
for name in self.common_dependencies(other):
changed |= self[name].constrain(other[name], deps=False)
+ if name in self._dependencies:
+ changed |= self._dependencies[name].update_deptypes(
+ other._dependencies[name].deptypes)
# Update with additional constraints from other spec
for name in other.dep_difference(self):