tests for variant concretization
This commit is contained in:
parent
535c1fac87
commit
793b842f99
2 changed files with 44 additions and 12 deletions
|
@ -294,8 +294,13 @@ def __str__(self):
|
||||||
|
|
||||||
|
|
||||||
class VariantMap(HashableMap):
|
class VariantMap(HashableMap):
|
||||||
def satisfies(self, other, self_is_concrete):
|
def __init__(self, spec):
|
||||||
if self_is_concrete:
|
super(VariantMap, self).__init__()
|
||||||
|
self.spec = spec
|
||||||
|
|
||||||
|
|
||||||
|
def satisfies(self, other):
|
||||||
|
if self.spec._concrete:
|
||||||
return all(k in self and self[k].enabled == other[k].enabled
|
return all(k in self and self[k].enabled == other[k].enabled
|
||||||
for k in other)
|
for k in other)
|
||||||
else:
|
else:
|
||||||
|
@ -303,8 +308,8 @@ def satisfies(self, other, self_is_concrete):
|
||||||
for k in other if k in self)
|
for k in other if k in self)
|
||||||
|
|
||||||
|
|
||||||
def constrain(self, other, other_is_concrete):
|
def constrain(self, other):
|
||||||
if other_is_concrete:
|
if other.spec._concrete:
|
||||||
for k in self:
|
for k in self:
|
||||||
if k not in other:
|
if k not in other:
|
||||||
raise UnsatisfiableVariantSpecError(self[k], '<absent>')
|
raise UnsatisfiableVariantSpecError(self[k], '<absent>')
|
||||||
|
@ -316,6 +321,18 @@ def constrain(self, other, other_is_concrete):
|
||||||
else:
|
else:
|
||||||
self[k] = other[k].copy()
|
self[k] = other[k].copy()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def concrete(self):
|
||||||
|
return self.spec._concrete or all(
|
||||||
|
v in self for v in self.spec.package.variants)
|
||||||
|
|
||||||
|
|
||||||
|
def copy(self):
|
||||||
|
clone = VariantMap(None)
|
||||||
|
for name, variant in self.items():
|
||||||
|
clone[name] = variant.copy()
|
||||||
|
return clone
|
||||||
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
sorted_keys = sorted(self.keys())
|
sorted_keys = sorted(self.keys())
|
||||||
|
@ -361,10 +378,11 @@ def __init__(self, spec_like, *dep_like, **kwargs):
|
||||||
self.name = other.name
|
self.name = other.name
|
||||||
self.dependents = other.dependents
|
self.dependents = other.dependents
|
||||||
self.versions = other.versions
|
self.versions = other.versions
|
||||||
self.variants = other.variants
|
|
||||||
self.architecture = other.architecture
|
self.architecture = other.architecture
|
||||||
self.compiler = other.compiler
|
self.compiler = other.compiler
|
||||||
self.dependencies = other.dependencies
|
self.dependencies = other.dependencies
|
||||||
|
self.variants = other.variants
|
||||||
|
self.variants.spec = self
|
||||||
|
|
||||||
# Specs are by default not assumed to be normal, but in some
|
# Specs are by default not assumed to be normal, but in some
|
||||||
# cases we've read them from a file want to assume normal.
|
# cases we've read them from a file want to assume normal.
|
||||||
|
@ -457,14 +475,15 @@ def virtual(self):
|
||||||
@property
|
@property
|
||||||
def concrete(self):
|
def concrete(self):
|
||||||
"""A spec is concrete if it can describe only ONE build of a package.
|
"""A spec is concrete if it can describe only ONE build of a package.
|
||||||
If any of the name, version, architecture, compiler, or depdenencies
|
If any of the name, version, architecture, compiler,
|
||||||
are ambiguous,then it is not concrete.
|
variants, or depdenencies are ambiguous,then it is not concrete.
|
||||||
"""
|
"""
|
||||||
if self._concrete:
|
if self._concrete:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
self._concrete = bool(not self.virtual
|
self._concrete = bool(not self.virtual
|
||||||
and self.versions.concrete
|
and self.versions.concrete
|
||||||
|
and self.variants.concrete
|
||||||
and self.architecture
|
and self.architecture
|
||||||
and self.compiler and self.compiler.concrete
|
and self.compiler and self.compiler.concrete
|
||||||
and self.dependencies.concrete)
|
and self.dependencies.concrete)
|
||||||
|
@ -947,7 +966,7 @@ def constrain(self, other, **kwargs):
|
||||||
self.compiler = other.compiler
|
self.compiler = other.compiler
|
||||||
|
|
||||||
self.versions.intersect(other.versions)
|
self.versions.intersect(other.versions)
|
||||||
self.variants.constrain(other.variants, other._concrete)
|
self.variants.constrain(other.variants)
|
||||||
self.architecture = self.architecture or other.architecture
|
self.architecture = self.architecture or other.architecture
|
||||||
|
|
||||||
if constrain_deps:
|
if constrain_deps:
|
||||||
|
@ -1020,7 +1039,7 @@ def satisfies(self, other, **kwargs):
|
||||||
if s and o and not s.satisfies(o):
|
if s and o and not s.satisfies(o):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if not self.variants.satisfies(other.variants, self._concrete):
|
if not self.variants.satisfies(other.variants):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Architecture satisfaction is currently just string equality.
|
# Architecture satisfaction is currently just string equality.
|
||||||
|
@ -1089,11 +1108,12 @@ def _dup(self, other, **kwargs):
|
||||||
# Local node attributes get copied first.
|
# Local node attributes get copied first.
|
||||||
self.name = other.name
|
self.name = other.name
|
||||||
self.versions = other.versions.copy()
|
self.versions = other.versions.copy()
|
||||||
self.variants = other.variants.copy()
|
|
||||||
self.architecture = other.architecture
|
self.architecture = other.architecture
|
||||||
self.compiler = other.compiler.copy() if other.compiler else None
|
self.compiler = other.compiler.copy() if other.compiler else None
|
||||||
self.dependents = DependencyMap()
|
self.dependents = DependencyMap()
|
||||||
self.dependencies = DependencyMap()
|
self.dependencies = DependencyMap()
|
||||||
|
self.variants = other.variants.copy()
|
||||||
|
self.variants.spec = self
|
||||||
|
|
||||||
# If we copy dependencies, preserve DAG structure in the new spec
|
# If we copy dependencies, preserve DAG structure in the new spec
|
||||||
if kwargs.get('deps', True):
|
if kwargs.get('deps', True):
|
||||||
|
@ -1429,7 +1449,7 @@ def spec(self):
|
||||||
spec = Spec.__new__(Spec)
|
spec = Spec.__new__(Spec)
|
||||||
spec.name = self.token.value
|
spec.name = self.token.value
|
||||||
spec.versions = VersionList()
|
spec.versions = VersionList()
|
||||||
spec.variants = VariantMap()
|
spec.variants = VariantMap(spec)
|
||||||
spec.architecture = None
|
spec.architecture = None
|
||||||
spec.compiler = None
|
spec.compiler = None
|
||||||
spec.dependents = DependencyMap()
|
spec.dependents = DependencyMap()
|
||||||
|
|
|
@ -35,7 +35,13 @@ def check_spec(self, abstract, concrete):
|
||||||
self.assertEqual(abstract.versions, concrete.versions)
|
self.assertEqual(abstract.versions, concrete.versions)
|
||||||
|
|
||||||
if abstract.variants:
|
if abstract.variants:
|
||||||
self.assertEqual(abstract.versions, concrete.versions)
|
for name in abstract.variants:
|
||||||
|
avariant = abstract.variants[name]
|
||||||
|
cvariant = concrete.variants[name]
|
||||||
|
self.assertEqual(avariant.enabled, cvariant.enabled)
|
||||||
|
|
||||||
|
for name in abstract.package.variants:
|
||||||
|
self.assertTrue(name in concrete.variants)
|
||||||
|
|
||||||
if abstract.compiler and abstract.compiler.concrete:
|
if abstract.compiler and abstract.compiler.concrete:
|
||||||
self.assertEqual(abstract.compiler, concrete.compiler)
|
self.assertEqual(abstract.compiler, concrete.compiler)
|
||||||
|
@ -66,6 +72,12 @@ def test_concretize_dag(self):
|
||||||
self.check_concretize('libelf')
|
self.check_concretize('libelf')
|
||||||
|
|
||||||
|
|
||||||
|
def test_concretize_variant(self):
|
||||||
|
self.check_concretize('mpich+debug')
|
||||||
|
self.check_concretize('mpich~debug')
|
||||||
|
self.check_concretize('mpich')
|
||||||
|
|
||||||
|
|
||||||
def test_concretize_with_virtual(self):
|
def test_concretize_with_virtual(self):
|
||||||
self.check_concretize('mpileaks ^mpi')
|
self.check_concretize('mpileaks ^mpi')
|
||||||
self.check_concretize('mpileaks ^mpi@:1.1')
|
self.check_concretize('mpileaks ^mpi@:1.1')
|
||||||
|
|
Loading…
Reference in a new issue