reclaimed the = sign. Architectures now specified by +arch= instead. Decided to prepend flag names with + for clarity in spec names and ease of parsing. Also generalized variants, although there is not yet a way to specify a generalized (name=value) variant.
This commit is contained in:
parent
7989a7f903
commit
db1b21b9aa
8 changed files with 104 additions and 60 deletions
|
@ -72,7 +72,7 @@
|
|||
dep_list = { ^ spec }
|
||||
spec = id [ options ]
|
||||
options = { @version-list | +variant | -variant | ~variant |
|
||||
%compiler | =architecture }
|
||||
%compiler | +arch=architecture | +flag=value}
|
||||
variant = id
|
||||
architecture = id
|
||||
compiler = id [ version-list ]
|
||||
|
@ -297,22 +297,25 @@ class VariantSpec(object):
|
|||
on the particular package being built, and each named variant can
|
||||
be enabled or disabled.
|
||||
"""
|
||||
def __init__(self, name, enabled):
|
||||
def __init__(self, name, value):
|
||||
self.name = name
|
||||
self.enabled = enabled
|
||||
self.value = value
|
||||
|
||||
|
||||
def _cmp_key(self):
|
||||
return (self.name, self.enabled)
|
||||
return (self.name, self.value)
|
||||
|
||||
|
||||
def copy(self):
|
||||
return VariantSpec(self.name, self.enabled)
|
||||
return VariantSpec(self.name, self.value)
|
||||
|
||||
|
||||
def __str__(self):
|
||||
out = '+' if self.enabled else '~'
|
||||
return out + self.name
|
||||
if self.value in [True,False]:
|
||||
out = '+' if self.value else '~'
|
||||
return out + self.name
|
||||
else:
|
||||
return '+' + self.name + "=" + self.value
|
||||
|
||||
|
||||
class VariantMap(HashableMap):
|
||||
|
@ -323,10 +326,10 @@ def __init__(self, spec):
|
|||
|
||||
def satisfies(self, other, strict=False):
|
||||
if strict or self.spec._concrete:
|
||||
return all(k in self and self[k].enabled == other[k].enabled
|
||||
return all(k in self and self[k].value == other[k].value
|
||||
for k in other)
|
||||
else:
|
||||
return all(self[k].enabled == other[k].enabled
|
||||
return all(self[k].value == other[k].value
|
||||
for k in other if k in self)
|
||||
|
||||
|
||||
|
@ -344,7 +347,7 @@ def constrain(self, other):
|
|||
changed = False
|
||||
for k in other:
|
||||
if k in self:
|
||||
if self[k].enabled != other[k].enabled:
|
||||
if self[k].value != other[k].value:
|
||||
raise UnsatisfiableVariantSpecError(self[k], other[k])
|
||||
else:
|
||||
self[k] = other[k].copy()
|
||||
|
@ -437,12 +440,20 @@ def _add_version(self, version):
|
|||
self.versions.add(version)
|
||||
|
||||
|
||||
def _add_variant(self, name, enabled):
|
||||
def _add_variant(self, name, value):
|
||||
"""Called by the parser to add a variant."""
|
||||
if name in self.variants: raise DuplicateVariantError(
|
||||
"Cannot specify variant '%s' twice" % name)
|
||||
self.variants[name] = VariantSpec(name, enabled)
|
||||
self.variants[name] = VariantSpec(name, value)
|
||||
|
||||
def _add_flag(self, name, value):
|
||||
"""Called by the parser to add a known flag.
|
||||
Known flags currently include "arch"
|
||||
"""
|
||||
if name == 'arch':
|
||||
self._set_architecture(value)
|
||||
else:
|
||||
raise SpecError("Invalid flag specified")
|
||||
|
||||
def _set_compiler(self, compiler):
|
||||
"""Called by the parser to set the compiler."""
|
||||
|
@ -653,7 +664,7 @@ def dag_hash(self, length=None):
|
|||
def to_node_dict(self):
|
||||
d = {
|
||||
'variants' : dict(
|
||||
(name,v.enabled) for name, v in self.variants.items()),
|
||||
(name,v.value) for name, v in self.variants.items()),
|
||||
'arch' : self.architecture,
|
||||
'dependencies' : dict((d, self.dependencies[d].dag_hash())
|
||||
for d in sorted(self.dependencies))
|
||||
|
@ -690,8 +701,8 @@ def from_node_dict(node):
|
|||
else:
|
||||
spec.compiler = CompilerSpec.from_dict(node)
|
||||
|
||||
for name, enabled in node['variants'].items():
|
||||
spec.variants[name] = VariantSpec(name, enabled)
|
||||
for name, value in node['variants'].items():
|
||||
spec.variants[name] = VariantSpec(name, value)
|
||||
|
||||
return spec
|
||||
|
||||
|
@ -804,6 +815,7 @@ def _expand_virtual_packages(self):
|
|||
spec._replace_with(concrete)
|
||||
changed = True
|
||||
|
||||
|
||||
# If there are duplicate providers or duplicate provider deps, this
|
||||
# consolidates them and merge constraints.
|
||||
changed |= self.normalize(force=True)
|
||||
|
@ -1138,7 +1150,7 @@ def constrain(self, other, deps=True):
|
|||
"""
|
||||
other = self._autospec(other)
|
||||
|
||||
if not self.name == other.name:
|
||||
if not (self.name == other.name or self.name == "any-pkg-name" or other.name == "any-pkg-name"):
|
||||
raise UnsatisfiableSpecNameError(self.name, other.name)
|
||||
|
||||
if not self.versions.overlaps(other.versions):
|
||||
|
@ -1146,7 +1158,7 @@ def constrain(self, other, deps=True):
|
|||
|
||||
for v in other.variants:
|
||||
if (v in self.variants and
|
||||
self.variants[v].enabled != other.variants[v].enabled):
|
||||
self.variants[v].value != other.variants[v].value):
|
||||
raise UnsatisfiableVariantSpecError(self.variants[v],
|
||||
other.variants[v])
|
||||
|
||||
|
@ -1228,7 +1240,10 @@ def _autospec(self, spec_like):
|
|||
return spec_like
|
||||
|
||||
try:
|
||||
return spack.spec.Spec(spec_like)
|
||||
spec = spack.spec.Spec(spec_like)
|
||||
if spec.name == "any-pkg-name":
|
||||
raise SpecError("anonymous package -- this will always be handled")
|
||||
return spec
|
||||
except SpecError:
|
||||
return parse_anonymous_spec(spec_like, self.name)
|
||||
|
||||
|
@ -1248,7 +1263,7 @@ def satisfies(self, other, deps=True, strict=False):
|
|||
"""
|
||||
other = self._autospec(other)
|
||||
|
||||
# A concrete provider can satisfy a virtual dependency.
|
||||
# A concrete provider can satisfy a virtual dependency.
|
||||
if not self.virtual and other.virtual:
|
||||
pkg = spack.db.get(self.name)
|
||||
if pkg.provides(other.name):
|
||||
|
@ -1622,7 +1637,7 @@ def tree(self, **kwargs):
|
|||
showid = kwargs.pop('ids', False)
|
||||
cover = kwargs.pop('cover', 'nodes')
|
||||
indent = kwargs.pop('indent', 0)
|
||||
fmt = kwargs.pop('format', '$_$@$%@$+$=')
|
||||
fmt = kwargs.pop('format', '$_$@$%@$+$+arch=')
|
||||
prefix = kwargs.pop('prefix', None)
|
||||
check_kwargs(kwargs, self.tree)
|
||||
|
||||
|
@ -1707,11 +1722,18 @@ def do_parse(self):
|
|||
|
||||
elif self.accept(ON):
|
||||
specs.append(self.empty_spec())
|
||||
specs[-1]._add_variant(self.variant(), True)
|
||||
self.expect(ID)
|
||||
self.check_identifier()
|
||||
name = self.token.value
|
||||
if self.accept(EQ):
|
||||
self.expect(ID)
|
||||
specs[-1]._add_flag(name,self.token.value)
|
||||
else:
|
||||
specs[-1]._add_variant(self.variant(name),True)
|
||||
|
||||
elif self.accept(OFF):
|
||||
specs.append(self.empty_spec())
|
||||
specs[-1]._add_variant(self.variant(), False)
|
||||
specs[-1]._add_variant(self.variant(),False)
|
||||
|
||||
else:
|
||||
self.unexpected_token()
|
||||
|
@ -1719,6 +1741,10 @@ def do_parse(self):
|
|||
except spack.parse.ParseError, e:
|
||||
raise SpecParseError(e)
|
||||
|
||||
for top_spec in specs:
|
||||
for spec in top_spec.traverse():
|
||||
if 'arch' in spec.variants:
|
||||
spec.architecture = spec.variants['arch']
|
||||
return specs
|
||||
|
||||
|
||||
|
@ -1763,10 +1789,17 @@ def empty_spec(self):
|
|||
#Should we be able to add cflags eventually?
|
||||
while self.next:
|
||||
if self.accept(ON):
|
||||
spec._add_variant(self.variant(), True)
|
||||
self.expect(ID)
|
||||
self.check_identifier()
|
||||
name = self.token.value
|
||||
if self.accept(EQ):
|
||||
self.expect(ID)
|
||||
spec._add_flag(name,self.token.value)
|
||||
else:
|
||||
spec._add_variant(self.variant(name),True)
|
||||
|
||||
elif self.accept(OFF):
|
||||
spec._add_variant(self.variant(), False)
|
||||
spec._add_variant(self.variant(),False)
|
||||
|
||||
elif self.accept(PCT):
|
||||
spec._set_compiler(self.compiler())
|
||||
|
@ -1805,18 +1838,23 @@ def spec(self):
|
|||
spec._add_version(version)
|
||||
added_version = True
|
||||
|
||||
|
||||
elif self.accept(ON):
|
||||
spec._add_variant(self.variant(), True)
|
||||
self.expect(ID)
|
||||
self.check_identifier()
|
||||
name = self.token.value
|
||||
if self.accept(EQ):
|
||||
self.expect(ID)
|
||||
spec._add_flag(name,self.token.value)
|
||||
else:
|
||||
spec._add_variant(self.variant(name),True)
|
||||
|
||||
elif self.accept(OFF):
|
||||
spec._add_variant(self.variant(), False)
|
||||
spec._add_variant(self.variant(),False)
|
||||
|
||||
elif self.accept(PCT):
|
||||
spec._set_compiler(self.compiler())
|
||||
|
||||
elif self.accept(EQ):
|
||||
spec._set_architecture(self.architecture())
|
||||
|
||||
else:
|
||||
break
|
||||
|
||||
|
@ -1827,13 +1865,17 @@ def spec(self):
|
|||
return spec
|
||||
|
||||
|
||||
def variant(self):
|
||||
self.expect(ID)
|
||||
self.check_identifier()
|
||||
return self.token.value
|
||||
|
||||
def variant(self,name=None):
|
||||
#TODO: Make generalized variants possible
|
||||
if name:
|
||||
return name
|
||||
else:
|
||||
self.expect(ID)
|
||||
self.check_identifier()
|
||||
return self.token.value
|
||||
|
||||
def architecture(self):
|
||||
#TODO: Make this work properly as a subcase of variant (includes adding names to grammar)
|
||||
self.expect(ID)
|
||||
return self.token.value
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ def check_spec(self, abstract, concrete):
|
|||
for name in abstract.variants:
|
||||
avariant = abstract.variants[name]
|
||||
cvariant = concrete.variants[name]
|
||||
self.assertEqual(avariant.enabled, cvariant.enabled)
|
||||
self.assertEqual(avariant.value, cvariant.value)
|
||||
|
||||
for name in abstract.package.variants:
|
||||
self.assertTrue(name in concrete.variants)
|
||||
|
|
|
@ -92,19 +92,19 @@ def test_default_works(self):
|
|||
|
||||
|
||||
def test_architecture_match(self):
|
||||
pkg = spack.db.get('multimethod=x86_64')
|
||||
pkg = spack.db.get('multimethod+arch=x86_64')
|
||||
self.assertEqual(pkg.different_by_architecture(), 'x86_64')
|
||||
|
||||
pkg = spack.db.get('multimethod=ppc64')
|
||||
pkg = spack.db.get('multimethod+arch=ppc64')
|
||||
self.assertEqual(pkg.different_by_architecture(), 'ppc64')
|
||||
|
||||
pkg = spack.db.get('multimethod=ppc32')
|
||||
pkg = spack.db.get('multimethod+arch=ppc32')
|
||||
self.assertEqual(pkg.different_by_architecture(), 'ppc32')
|
||||
|
||||
pkg = spack.db.get('multimethod=arm64')
|
||||
pkg = spack.db.get('multimethod+arch=arm64')
|
||||
self.assertEqual(pkg.different_by_architecture(), 'arm64')
|
||||
|
||||
pkg = spack.db.get('multimethod=macos')
|
||||
pkg = spack.db.get('multimethod+arch=macos')
|
||||
self.assertRaises(NoSuchMethodError, pkg.different_by_architecture)
|
||||
|
||||
|
||||
|
|
|
@ -241,8 +241,8 @@ def test_unsatisfiable_compiler_version(self):
|
|||
|
||||
|
||||
def test_unsatisfiable_architecture(self):
|
||||
set_pkg_dep('mpileaks', 'mpich=bgqos_0')
|
||||
spec = Spec('mpileaks ^mpich=sles_10_ppc64 ^callpath ^dyninst ^libelf ^libdwarf')
|
||||
set_pkg_dep('mpileaks', 'mpich+arch=bgqos_0')
|
||||
spec = Spec('mpileaks ^mpich+arch=sles_10_ppc64 ^callpath ^dyninst ^libelf ^libdwarf')
|
||||
self.assertRaises(spack.spec.UnsatisfiableArchitectureSpecError, spec.normalize)
|
||||
|
||||
|
||||
|
@ -426,6 +426,7 @@ def test_copy_concretized(self):
|
|||
orig.concretize()
|
||||
copy = orig.copy()
|
||||
|
||||
print orig
|
||||
self.check_links(copy)
|
||||
|
||||
self.assertEqual(orig, copy)
|
||||
|
|
|
@ -111,11 +111,11 @@ def test_satisfies_compiler_version(self):
|
|||
|
||||
|
||||
def test_satisfies_architecture(self):
|
||||
self.check_satisfies('foo=chaos_5_x86_64_ib', '=chaos_5_x86_64_ib')
|
||||
self.check_satisfies('foo=bgqos_0', '=bgqos_0')
|
||||
self.check_satisfies('foo+arch=chaos_5_x86_64_ib', '+arch=chaos_5_x86_64_ib')
|
||||
self.check_satisfies('foo+arch=bgqos_0', '+arch=bgqos_0')
|
||||
|
||||
self.check_unsatisfiable('foo=bgqos_0', '=chaos_5_x86_64_ib')
|
||||
self.check_unsatisfiable('foo=chaos_5_x86_64_ib', '=bgqos_0')
|
||||
self.check_unsatisfiable('foo+arch=bgqos_0', '+arch=chaos_5_x86_64_ib')
|
||||
self.check_unsatisfiable('foo+arch=chaos_5_x86_64_ib', '+arch=bgqos_0')
|
||||
|
||||
|
||||
def test_satisfies_dependencies(self):
|
||||
|
@ -267,13 +267,13 @@ def test_constrain_variants(self):
|
|||
|
||||
|
||||
def test_constrain_arch(self):
|
||||
self.check_constrain('libelf=bgqos_0', 'libelf=bgqos_0', 'libelf=bgqos_0')
|
||||
self.check_constrain('libelf=bgqos_0', 'libelf', 'libelf=bgqos_0')
|
||||
self.check_constrain('libelf+arch=bgqos_0', 'libelf+arch=bgqos_0', 'libelf+arch=bgqos_0')
|
||||
self.check_constrain('libelf+arch=bgqos_0', 'libelf', 'libelf+arch=bgqos_0')
|
||||
|
||||
|
||||
def test_constrain_compiler(self):
|
||||
self.check_constrain('libelf=bgqos_0', 'libelf=bgqos_0', 'libelf=bgqos_0')
|
||||
self.check_constrain('libelf=bgqos_0', 'libelf', 'libelf=bgqos_0')
|
||||
self.check_constrain('libelf+arch=bgqos_0', 'libelf+arch=bgqos_0', 'libelf+arch=bgqos_0')
|
||||
self.check_constrain('libelf+arch=bgqos_0', 'libelf', 'libelf+arch=bgqos_0')
|
||||
|
||||
|
||||
def test_invalid_constraint(self):
|
||||
|
@ -283,7 +283,7 @@ def test_invalid_constraint(self):
|
|||
self.check_invalid_constraint('libelf+debug', 'libelf~debug')
|
||||
self.check_invalid_constraint('libelf+debug~foo', 'libelf+debug+foo')
|
||||
|
||||
self.check_invalid_constraint('libelf=bgqos_0', 'libelf=x86_54')
|
||||
self.check_invalid_constraint('libelf+arch=bgqos_0', 'libelf+arch=x86_54')
|
||||
|
||||
|
||||
def test_constrain_changed(self):
|
||||
|
@ -293,7 +293,7 @@ def test_constrain_changed(self):
|
|||
self.check_constrain_changed('libelf%gcc', '%gcc@4.5')
|
||||
self.check_constrain_changed('libelf', '+debug')
|
||||
self.check_constrain_changed('libelf', '~debug')
|
||||
self.check_constrain_changed('libelf', '=bgqos_0')
|
||||
self.check_constrain_changed('libelf', '+arch=bgqos_0')
|
||||
|
||||
|
||||
def test_constrain_not_changed(self):
|
||||
|
@ -304,7 +304,7 @@ def test_constrain_not_changed(self):
|
|||
self.check_constrain_not_changed('libelf%gcc@4.5', '%gcc@4.5')
|
||||
self.check_constrain_not_changed('libelf+debug', '+debug')
|
||||
self.check_constrain_not_changed('libelf~debug', '~debug')
|
||||
self.check_constrain_not_changed('libelf=bgqos_0', '=bgqos_0')
|
||||
self.check_constrain_not_changed('libelf+arch=bgqos_0', '+arch=bgqos_0')
|
||||
self.check_constrain_not_changed('libelf^foo', 'libelf^foo')
|
||||
self.check_constrain_not_changed('libelf^foo^bar', 'libelf^foo^bar')
|
||||
|
||||
|
@ -316,7 +316,7 @@ def test_constrain_dependency_changed(self):
|
|||
self.check_constrain_changed('libelf^foo%gcc', 'libelf^foo%gcc@4.5')
|
||||
self.check_constrain_changed('libelf^foo', 'libelf^foo+debug')
|
||||
self.check_constrain_changed('libelf^foo', 'libelf^foo~debug')
|
||||
self.check_constrain_changed('libelf^foo', 'libelf^foo=bgqos_0')
|
||||
self.check_constrain_changed('libelf^foo', 'libelf^foo+arch=bgqos_0')
|
||||
|
||||
|
||||
def test_constrain_dependency_not_changed(self):
|
||||
|
@ -326,5 +326,5 @@ def test_constrain_dependency_not_changed(self):
|
|||
self.check_constrain_not_changed('libelf^foo%gcc@4.5', 'libelf^foo%gcc@4.5')
|
||||
self.check_constrain_not_changed('libelf^foo+debug', 'libelf^foo+debug')
|
||||
self.check_constrain_not_changed('libelf^foo~debug', 'libelf^foo~debug')
|
||||
self.check_constrain_not_changed('libelf^foo=bgqos_0', 'libelf^foo=bgqos_0')
|
||||
self.check_constrain_not_changed('libelf^foo+arch=bgqos_0', 'libelf^foo+arch=bgqos_0')
|
||||
|
||||
|
|
|
@ -70,6 +70,7 @@ def check_parse(self, expected, spec=None):
|
|||
spec = expected
|
||||
output = spack.spec.parse(spec)
|
||||
parsed = (" ".join(str(spec) for spec in output))
|
||||
print output, parsed
|
||||
self.assertEqual(expected, parsed)
|
||||
|
||||
|
||||
|
|
|
@ -32,5 +32,5 @@
|
|||
class Variant(object):
|
||||
"""Represents a variant on a build. Can be either on or off."""
|
||||
def __init__(self, default, description):
|
||||
self.default = bool(default)
|
||||
self.default = default
|
||||
self.description = str(description)
|
||||
|
|
|
@ -103,19 +103,19 @@ def has_a_default(self):
|
|||
#
|
||||
# Make sure we can switch methods on different architectures
|
||||
#
|
||||
@when('=x86_64')
|
||||
@when('+arch=x86_64')
|
||||
def different_by_architecture(self):
|
||||
return 'x86_64'
|
||||
|
||||
@when('=ppc64')
|
||||
@when('+arch=ppc64')
|
||||
def different_by_architecture(self):
|
||||
return 'ppc64'
|
||||
|
||||
@when('=ppc32')
|
||||
@when('+arch=ppc32')
|
||||
def different_by_architecture(self):
|
||||
return 'ppc32'
|
||||
|
||||
@when('=arm64')
|
||||
@when('+arch=arm64')
|
||||
def different_by_architecture(self):
|
||||
return 'arm64'
|
||||
|
||||
|
|
Loading…
Reference in a new issue