spec: refactor and clean up Spec initialization
- Since early Spack versions, the SpecParser has (weirdly) been responsible for initializing Spec fields. - This refactors initialization to take place in Spec.__init__, as it probably should have originally. - This makes the code easier to read, the parser easier to understand, and removes the use of __new__ in the parser to initialize the Spec. - This also makes it possible to make a completely empty Spec with `Spec()` -- this is an abstract Spec that will match anything.
This commit is contained in:
parent
e0d22519cd
commit
88cb11758b
@ -889,188 +889,71 @@ class Spec(object):
|
|||||||
#: Cache for spec's prefix, computed lazily in the corresponding property
|
#: Cache for spec's prefix, computed lazily in the corresponding property
|
||||||
_prefix = None
|
_prefix = None
|
||||||
|
|
||||||
@staticmethod
|
def __init__(self, spec_like=None,
|
||||||
def from_literal(spec_dict, normal=True):
|
normal=False, concrete=False, external_path=None,
|
||||||
"""Builds a Spec from a dictionary containing the spec literal.
|
external_module=None, full_hash=None):
|
||||||
|
"""Create a new Spec.
|
||||||
|
|
||||||
The dictionary must have a single top level key, representing the root,
|
Arguments:
|
||||||
and as many secondary level keys as needed in the spec.
|
spec_like (optional string): if not provided, we initialize
|
||||||
|
an anonymous Spec that matches any Spec object; if
|
||||||
|
provided we parse this as a Spec string.
|
||||||
|
|
||||||
The keys can be either a string or a Spec or a tuple containing the
|
Keyword arguments:
|
||||||
Spec and the dependency types.
|
# assign special fields from constructor
|
||||||
|
self._normal = normal
|
||||||
Args:
|
self._concrete = concrete
|
||||||
spec_dict (dict): the dictionary containing the spec literal
|
self.external_path = external_path
|
||||||
normal (bool): if True the same key appearing at different levels
|
self.external_module = external_module
|
||||||
of the ``spec_dict`` will map to the same object in memory.
|
self._full_hash = full_hash
|
||||||
|
|
||||||
Examples:
|
|
||||||
A simple spec ``foo`` with no dependencies:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
{'foo': None}
|
|
||||||
|
|
||||||
A spec ``foo`` with a ``(build, link)`` dependency ``bar``:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
{'foo':
|
|
||||||
{'bar:build,link': None}}
|
|
||||||
|
|
||||||
A spec with a diamond dependency and various build types:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
{'dt-diamond': {
|
|
||||||
'dt-diamond-left:build,link': {
|
|
||||||
'dt-diamond-bottom:build': None
|
|
||||||
},
|
|
||||||
'dt-diamond-right:build,link': {
|
|
||||||
'dt-diamond-bottom:build,link,run': None
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
|
|
||||||
The same spec with a double copy of ``dt-diamond-bottom`` and
|
|
||||||
no diamond structure:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
{'dt-diamond': {
|
|
||||||
'dt-diamond-left:build,link': {
|
|
||||||
'dt-diamond-bottom:build': None
|
|
||||||
},
|
|
||||||
'dt-diamond-right:build,link': {
|
|
||||||
'dt-diamond-bottom:build,link,run': None
|
|
||||||
}
|
|
||||||
}, normal=False}
|
|
||||||
|
|
||||||
Constructing a spec using a Spec object as key:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
mpich = Spec('mpich')
|
|
||||||
libelf = Spec('libelf@1.8.11')
|
|
||||||
expected_normalized = Spec.from_literal({
|
|
||||||
'mpileaks': {
|
|
||||||
'callpath': {
|
|
||||||
'dyninst': {
|
|
||||||
'libdwarf': {libelf: None},
|
|
||||||
libelf: None
|
|
||||||
},
|
|
||||||
mpich: None
|
|
||||||
},
|
|
||||||
mpich: None
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Maps a literal to a Spec, to be sure we are reusing the same object
|
|
||||||
spec_cache = LazySpecCache()
|
|
||||||
|
|
||||||
def spec_builder(d):
|
|
||||||
# The invariant is that the top level dictionary must have
|
|
||||||
# only one key
|
|
||||||
assert len(d) == 1
|
|
||||||
|
|
||||||
# Construct the top-level spec
|
|
||||||
spec_like, dep_like = next(iter(d.items()))
|
|
||||||
|
|
||||||
# If the requirements was for unique nodes (default)
|
|
||||||
# then re-use keys from the local cache. Otherwise build
|
|
||||||
# a new node every time.
|
|
||||||
if not isinstance(spec_like, Spec):
|
|
||||||
spec = spec_cache[spec_like] if normal else Spec(spec_like)
|
|
||||||
else:
|
|
||||||
spec = spec_like
|
|
||||||
|
|
||||||
if dep_like is None:
|
|
||||||
return spec
|
|
||||||
|
|
||||||
def name_and_dependency_types(s):
|
|
||||||
"""Given a key in the dictionary containing the literal,
|
|
||||||
extracts the name of the spec and its dependency types.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
s (str): key in the dictionary containing the literal
|
|
||||||
|
|
||||||
"""
|
|
||||||
t = s.split(':')
|
|
||||||
|
|
||||||
if len(t) > 2:
|
|
||||||
msg = 'more than one ":" separator in key "{0}"'
|
|
||||||
raise KeyError(msg.format(s))
|
|
||||||
|
|
||||||
n = t[0]
|
|
||||||
if len(t) == 2:
|
|
||||||
dtypes = tuple(dt.strip() for dt in t[1].split(','))
|
|
||||||
else:
|
|
||||||
dtypes = ()
|
|
||||||
|
|
||||||
return n, dtypes
|
|
||||||
|
|
||||||
def spec_and_dependency_types(s):
|
|
||||||
"""Given a non-string key in the literal, extracts the spec
|
|
||||||
and its dependency types.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
s (spec or tuple): either a Spec object or a tuple
|
|
||||||
composed of a Spec object and a string with the
|
|
||||||
dependency types
|
|
||||||
|
|
||||||
"""
|
|
||||||
if isinstance(s, Spec):
|
|
||||||
return s, ()
|
|
||||||
|
|
||||||
spec_obj, dtypes = s
|
|
||||||
return spec_obj, tuple(dt.strip() for dt in dtypes.split(','))
|
|
||||||
|
|
||||||
# Recurse on dependencies
|
|
||||||
for s, s_dependencies in dep_like.items():
|
|
||||||
|
|
||||||
if isinstance(s, string_types):
|
|
||||||
dag_node, dependency_types = name_and_dependency_types(s)
|
|
||||||
else:
|
|
||||||
dag_node, dependency_types = spec_and_dependency_types(s)
|
|
||||||
|
|
||||||
dependency_spec = spec_builder({dag_node: s_dependencies})
|
|
||||||
spec._add_dependency(dependency_spec, dependency_types)
|
|
||||||
|
|
||||||
return spec
|
|
||||||
|
|
||||||
return spec_builder(spec_dict)
|
|
||||||
|
|
||||||
def __init__(self, spec_like, **kwargs):
|
|
||||||
# Copy if spec_like is a Spec.
|
# Copy if spec_like is a Spec.
|
||||||
if isinstance(spec_like, Spec):
|
if isinstance(spec_like, Spec):
|
||||||
self._dup(spec_like)
|
self._dup(spec_like)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Parse if the spec_like is a string.
|
# init an empty spec that matches anything.
|
||||||
if not isinstance(spec_like, string_types):
|
self.name = None
|
||||||
|
self.versions = VersionList(':')
|
||||||
|
self.variants = VariantMap(self)
|
||||||
|
self.architecture = None
|
||||||
|
self.compiler = None
|
||||||
|
self.external_path = None
|
||||||
|
self.external_module = None
|
||||||
|
self.compiler_flags = FlagMap(self)
|
||||||
|
self._dependents = DependencyMap()
|
||||||
|
self._dependencies = DependencyMap()
|
||||||
|
self.namespace = None
|
||||||
|
|
||||||
|
self._hash = None
|
||||||
|
self._cmp_key_cache = None
|
||||||
|
self._package = None
|
||||||
|
|
||||||
|
# Most of these are internal implementation details that can be
|
||||||
|
# set by internal Spack calls in the constructor.
|
||||||
|
#
|
||||||
|
# For example, Specs are by default not assumed to be normal, but
|
||||||
|
# in some cases we've read them from a file want to assume
|
||||||
|
# normal. This allows us to manipulate specs that Spack doesn't
|
||||||
|
# have package.py files for.
|
||||||
|
self._normal = normal
|
||||||
|
self._concrete = concrete
|
||||||
|
self.external_path = external_path
|
||||||
|
self.external_module = external_module
|
||||||
|
self._full_hash = full_hash
|
||||||
|
|
||||||
|
if isinstance(spec_like, string_types):
|
||||||
|
spec_list = SpecParser(self).parse(spec_like)
|
||||||
|
if len(spec_list) > 1:
|
||||||
|
raise ValueError("More than one spec in string: " + spec_like)
|
||||||
|
if len(spec_list) < 1:
|
||||||
|
raise ValueError("String contains no specs: " + spec_like)
|
||||||
|
|
||||||
|
elif spec_like is not None:
|
||||||
raise TypeError("Can't make spec out of %s" % type(spec_like))
|
raise TypeError("Can't make spec out of %s" % type(spec_like))
|
||||||
|
|
||||||
# parse string types *into* this spec
|
|
||||||
spec_list = SpecParser(self).parse(spec_like)
|
|
||||||
if len(spec_list) > 1:
|
|
||||||
raise ValueError("More than one spec in string: " + spec_like)
|
|
||||||
if len(spec_list) < 1:
|
|
||||||
raise ValueError("String contains no specs: " + spec_like)
|
|
||||||
|
|
||||||
# Specs are by default not assumed to be normal, but in some
|
|
||||||
# cases we've read them from a file want to assume normal.
|
|
||||||
# This allows us to manipulate specs that Spack doesn't have
|
|
||||||
# package.py files for.
|
|
||||||
self._normal = kwargs.get('normal', False)
|
|
||||||
self._concrete = kwargs.get('concrete', False)
|
|
||||||
|
|
||||||
# Allow a spec to be constructed with an external path.
|
|
||||||
self.external_path = kwargs.get('external_path', None)
|
|
||||||
self.external_module = kwargs.get('external_module', None)
|
|
||||||
|
|
||||||
self._full_hash = kwargs.get('full_hash', None)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def external(self):
|
def external(self):
|
||||||
return bool(self.external_path) or bool(self.external_module)
|
return bool(self.external_path) or bool(self.external_module)
|
||||||
@ -1610,6 +1493,158 @@ def read_yaml_dep_specs(dependency_dict):
|
|||||||
|
|
||||||
yield dep_name, dag_hash, list(deptypes)
|
yield dep_name, dag_hash, list(deptypes)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_literal(spec_dict, normal=True):
|
||||||
|
"""Builds a Spec from a dictionary containing the spec literal.
|
||||||
|
|
||||||
|
The dictionary must have a single top level key, representing the root,
|
||||||
|
and as many secondary level keys as needed in the spec.
|
||||||
|
|
||||||
|
The keys can be either a string or a Spec or a tuple containing the
|
||||||
|
Spec and the dependency types.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
spec_dict (dict): the dictionary containing the spec literal
|
||||||
|
normal (bool): if True the same key appearing at different levels
|
||||||
|
of the ``spec_dict`` will map to the same object in memory.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
A simple spec ``foo`` with no dependencies:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
{'foo': None}
|
||||||
|
|
||||||
|
A spec ``foo`` with a ``(build, link)`` dependency ``bar``:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
{'foo':
|
||||||
|
{'bar:build,link': None}}
|
||||||
|
|
||||||
|
A spec with a diamond dependency and various build types:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
{'dt-diamond': {
|
||||||
|
'dt-diamond-left:build,link': {
|
||||||
|
'dt-diamond-bottom:build': None
|
||||||
|
},
|
||||||
|
'dt-diamond-right:build,link': {
|
||||||
|
'dt-diamond-bottom:build,link,run': None
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
|
The same spec with a double copy of ``dt-diamond-bottom`` and
|
||||||
|
no diamond structure:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
{'dt-diamond': {
|
||||||
|
'dt-diamond-left:build,link': {
|
||||||
|
'dt-diamond-bottom:build': None
|
||||||
|
},
|
||||||
|
'dt-diamond-right:build,link': {
|
||||||
|
'dt-diamond-bottom:build,link,run': None
|
||||||
|
}
|
||||||
|
}, normal=False}
|
||||||
|
|
||||||
|
Constructing a spec using a Spec object as key:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
mpich = Spec('mpich')
|
||||||
|
libelf = Spec('libelf@1.8.11')
|
||||||
|
expected_normalized = Spec.from_literal({
|
||||||
|
'mpileaks': {
|
||||||
|
'callpath': {
|
||||||
|
'dyninst': {
|
||||||
|
'libdwarf': {libelf: None},
|
||||||
|
libelf: None
|
||||||
|
},
|
||||||
|
mpich: None
|
||||||
|
},
|
||||||
|
mpich: None
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Maps a literal to a Spec, to be sure we are reusing the same object
|
||||||
|
spec_cache = LazySpecCache()
|
||||||
|
|
||||||
|
def spec_builder(d):
|
||||||
|
# The invariant is that the top level dictionary must have
|
||||||
|
# only one key
|
||||||
|
assert len(d) == 1
|
||||||
|
|
||||||
|
# Construct the top-level spec
|
||||||
|
spec_like, dep_like = next(iter(d.items()))
|
||||||
|
|
||||||
|
# If the requirements was for unique nodes (default)
|
||||||
|
# then re-use keys from the local cache. Otherwise build
|
||||||
|
# a new node every time.
|
||||||
|
if not isinstance(spec_like, Spec):
|
||||||
|
spec = spec_cache[spec_like] if normal else Spec(spec_like)
|
||||||
|
else:
|
||||||
|
spec = spec_like
|
||||||
|
|
||||||
|
if dep_like is None:
|
||||||
|
return spec
|
||||||
|
|
||||||
|
def name_and_dependency_types(s):
|
||||||
|
"""Given a key in the dictionary containing the literal,
|
||||||
|
extracts the name of the spec and its dependency types.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
s (str): key in the dictionary containing the literal
|
||||||
|
|
||||||
|
"""
|
||||||
|
t = s.split(':')
|
||||||
|
|
||||||
|
if len(t) > 2:
|
||||||
|
msg = 'more than one ":" separator in key "{0}"'
|
||||||
|
raise KeyError(msg.format(s))
|
||||||
|
|
||||||
|
n = t[0]
|
||||||
|
if len(t) == 2:
|
||||||
|
dtypes = tuple(dt.strip() for dt in t[1].split(','))
|
||||||
|
else:
|
||||||
|
dtypes = ()
|
||||||
|
|
||||||
|
return n, dtypes
|
||||||
|
|
||||||
|
def spec_and_dependency_types(s):
|
||||||
|
"""Given a non-string key in the literal, extracts the spec
|
||||||
|
and its dependency types.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
s (spec or tuple): either a Spec object or a tuple
|
||||||
|
composed of a Spec object and a string with the
|
||||||
|
dependency types
|
||||||
|
|
||||||
|
"""
|
||||||
|
if isinstance(s, Spec):
|
||||||
|
return s, ()
|
||||||
|
|
||||||
|
spec_obj, dtypes = s
|
||||||
|
return spec_obj, tuple(dt.strip() for dt in dtypes.split(','))
|
||||||
|
|
||||||
|
# Recurse on dependencies
|
||||||
|
for s, s_dependencies in dep_like.items():
|
||||||
|
|
||||||
|
if isinstance(s, string_types):
|
||||||
|
dag_node, dependency_types = name_and_dependency_types(s)
|
||||||
|
else:
|
||||||
|
dag_node, dependency_types = spec_and_dependency_types(s)
|
||||||
|
|
||||||
|
dependency_spec = spec_builder({dag_node: s_dependencies})
|
||||||
|
spec._add_dependency(dependency_spec, dependency_types)
|
||||||
|
|
||||||
|
return spec
|
||||||
|
|
||||||
|
return spec_builder(spec_dict)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_dict(data):
|
def from_dict(data):
|
||||||
"""Construct a spec from YAML.
|
"""Construct a spec from YAML.
|
||||||
@ -3484,52 +3519,31 @@ def spec_by_hash(self):
|
|||||||
def spec(self, name):
|
def spec(self, name):
|
||||||
"""Parse a spec out of the input. If a spec is supplied, initialize
|
"""Parse a spec out of the input. If a spec is supplied, initialize
|
||||||
and return it instead of creating a new one."""
|
and return it instead of creating a new one."""
|
||||||
|
spec_namespace = None
|
||||||
|
spec_name = None
|
||||||
if name:
|
if name:
|
||||||
spec_namespace, dot, spec_name = name.rpartition('.')
|
spec_namespace, dot, spec_name = name.rpartition('.')
|
||||||
if not spec_namespace:
|
if not spec_namespace:
|
||||||
spec_namespace = None
|
spec_namespace = None
|
||||||
self.check_identifier(spec_name)
|
self.check_identifier(spec_name)
|
||||||
else:
|
|
||||||
spec_namespace = None
|
|
||||||
spec_name = None
|
|
||||||
|
|
||||||
if self._initial is None:
|
if self._initial is None:
|
||||||
# This will init the spec without calling Spec.__init__
|
# This will init the spec without calling Spec.__init__
|
||||||
spec = Spec.__new__(Spec)
|
spec = Spec()
|
||||||
else:
|
else:
|
||||||
# this is used by Spec.__init__
|
# this is used by Spec.__init__
|
||||||
spec = self._initial
|
spec = self._initial
|
||||||
self._initial = None
|
self._initial = None
|
||||||
|
|
||||||
spec.name = spec_name
|
|
||||||
spec.versions = VersionList()
|
|
||||||
spec.variants = VariantMap(spec)
|
|
||||||
spec.architecture = None
|
|
||||||
spec.compiler = None
|
|
||||||
spec.external_path = None
|
|
||||||
spec.external_module = None
|
|
||||||
spec.compiler_flags = FlagMap(spec)
|
|
||||||
spec._dependents = DependencyMap()
|
|
||||||
spec._dependencies = DependencyMap()
|
|
||||||
spec.namespace = spec_namespace
|
spec.namespace = spec_namespace
|
||||||
spec._hash = None
|
spec.name = spec_name
|
||||||
spec._cmp_key_cache = None
|
|
||||||
|
|
||||||
spec._package = None
|
|
||||||
spec._normal = False
|
|
||||||
spec._concrete = False
|
|
||||||
spec._full_hash = None
|
|
||||||
|
|
||||||
# record this so that we know whether version is
|
|
||||||
# unspecified or not.
|
|
||||||
added_version = False
|
|
||||||
|
|
||||||
while self.next:
|
while self.next:
|
||||||
if self.accept(AT):
|
if self.accept(AT):
|
||||||
vlist = self.version_list()
|
vlist = self.version_list()
|
||||||
|
spec.versions = VersionList()
|
||||||
for version in vlist:
|
for version in vlist:
|
||||||
spec._add_version(version)
|
spec._add_version(version)
|
||||||
added_version = True
|
|
||||||
|
|
||||||
elif self.accept(ON):
|
elif self.accept(ON):
|
||||||
name = self.variant()
|
name = self.variant()
|
||||||
@ -3568,10 +3582,6 @@ def spec(self, name):
|
|||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
|
||||||
# If there was no version in the spec, consier it an open range
|
|
||||||
if not added_version and not spec._hash:
|
|
||||||
spec.versions = VersionList(':')
|
|
||||||
|
|
||||||
return spec
|
return spec
|
||||||
|
|
||||||
def variant(self, name=None):
|
def variant(self, name=None):
|
||||||
|
@ -13,8 +13,8 @@
|
|||||||
|
|
||||||
|
|
||||||
def target_factory(spec_string, target_concrete):
|
def target_factory(spec_string, target_concrete):
|
||||||
spec = Spec(spec_string)
|
spec = Spec(spec_string) if spec_string else Spec()
|
||||||
|
print spec, spec_string, "AAAAA"
|
||||||
if target_concrete:
|
if target_concrete:
|
||||||
spec._mark_concrete()
|
spec._mark_concrete()
|
||||||
substitute_abstract_variants(spec)
|
substitute_abstract_variants(spec)
|
||||||
@ -27,6 +27,7 @@ def argument_factory(argument_spec, left):
|
|||||||
# If it's not anonymous, allow it
|
# If it's not anonymous, allow it
|
||||||
right = target_factory(argument_spec, False)
|
right = target_factory(argument_spec, False)
|
||||||
except Exception:
|
except Exception:
|
||||||
|
print "HAHA"
|
||||||
right = parse_anonymous_spec(argument_spec, left.name)
|
right = parse_anonymous_spec(argument_spec, left.name)
|
||||||
return right
|
return right
|
||||||
|
|
||||||
@ -36,9 +37,12 @@ def check_satisfies(target_spec, argument_spec, target_concrete=False):
|
|||||||
left = target_factory(target_spec, target_concrete)
|
left = target_factory(target_spec, target_concrete)
|
||||||
right = argument_factory(argument_spec, left)
|
right = argument_factory(argument_spec, left)
|
||||||
|
|
||||||
|
print left, 'left', left.name
|
||||||
|
print right, right.name
|
||||||
# Satisfies is one-directional.
|
# Satisfies is one-directional.
|
||||||
assert left.satisfies(right)
|
assert left.satisfies(right)
|
||||||
assert left.satisfies(argument_spec)
|
if argument_spec:
|
||||||
|
assert left.satisfies(argument_spec)
|
||||||
|
|
||||||
# If left satisfies right, then we should be able to constrain
|
# If left satisfies right, then we should be able to constrain
|
||||||
# right by left. Reverse is not always true.
|
# right by left. Reverse is not always true.
|
||||||
@ -91,6 +95,34 @@ def test_satisfies(self):
|
|||||||
check_satisfies('libelf@0.8.13', '@0:1')
|
check_satisfies('libelf@0.8.13', '@0:1')
|
||||||
check_satisfies('libdwarf^libelf@0.8.13', '^libelf@0:1')
|
check_satisfies('libdwarf^libelf@0.8.13', '^libelf@0:1')
|
||||||
|
|
||||||
|
def test_empty_satisfies(self):
|
||||||
|
# Basic satisfaction
|
||||||
|
check_satisfies('libelf', '')
|
||||||
|
check_satisfies('libdwarf', '')
|
||||||
|
check_satisfies('%intel', '')
|
||||||
|
check_satisfies('^mpi', '')
|
||||||
|
check_satisfies('+debug', '')
|
||||||
|
check_satisfies('@3:', '')
|
||||||
|
|
||||||
|
# Concrete (strict) satisfaction
|
||||||
|
check_satisfies('libelf', '', True)
|
||||||
|
check_satisfies('libdwarf', '', True)
|
||||||
|
check_satisfies('%intel', '', True)
|
||||||
|
check_satisfies('^mpi', '', True)
|
||||||
|
# TODO: Variants can't be called concrete while anonymous
|
||||||
|
# check_satisfies('+debug', '', True)
|
||||||
|
check_satisfies('@3:', '', True)
|
||||||
|
|
||||||
|
# Reverse (non-strict) satisfaction
|
||||||
|
check_satisfies('', 'libelf')
|
||||||
|
check_satisfies('', 'libdwarf')
|
||||||
|
check_satisfies('', '%intel')
|
||||||
|
check_satisfies('', '^mpi')
|
||||||
|
# TODO: Variant matching is auto-strict
|
||||||
|
# we should rethink this
|
||||||
|
# check_satisfies('', '+debug')
|
||||||
|
check_satisfies('', '@3:')
|
||||||
|
|
||||||
def test_satisfies_namespace(self):
|
def test_satisfies_namespace(self):
|
||||||
check_satisfies('builtin.mpich', 'mpich')
|
check_satisfies('builtin.mpich', 'mpich')
|
||||||
check_satisfies('builtin.mock.mpich', 'mpich')
|
check_satisfies('builtin.mock.mpich', 'mpich')
|
||||||
|
Loading…
Reference in New Issue
Block a user