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.py77
1 files changed, 51 insertions, 26 deletions
diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py
index f2c3d70f23..1657e2128b 100644
--- a/lib/spack/spack/spec.py
+++ b/lib/spack/spack/spec.py
@@ -739,6 +739,8 @@ class Spec(object):
def constrain(self, other, **kwargs):
+ other = self._autospec(other)
+
if not self.name == other.name:
raise UnsatisfiableSpecNameError(self.name, other.name)
@@ -766,10 +768,10 @@ class Spec(object):
self.architecture = self.architecture or other.architecture
if kwargs.get('deps', True):
- self.constrain_dependencies(other)
+ self._constrain_dependencies(other)
- def constrain_dependencies(self, other):
+ def _constrain_dependencies(self, other):
"""Apply constraints of other spec's dependencies to this spec."""
if not self.dependencies or not other.dependencies:
return
@@ -806,9 +808,22 @@ class Spec(object):
return mine
+ def _autospec(self, spec_like):
+ """Used to convert arguments to specs. If spec_like is a spec, returns it.
+ If it's a string, tries to parse a string. If that fails, tries to parse
+ a local spec from it (i.e. name is assumed to be self's name).
+ """
+ if isinstance(spec_like, spack.spec.Spec):
+ return spec_like
+
+ try:
+ return spack.spec.Spec(spec_like)
+ except SpecError:
+ return parse_anonymous_spec(spec_like, self.name)
+
+
def satisfies(self, other, **kwargs):
- if not isinstance(other, Spec):
- other = Spec(other)
+ other = self._autospec(other)
# First thing we care about is whether the name matches
if self.name != other.name:
@@ -934,9 +949,7 @@ class Spec(object):
def __contains__(self, spec):
"""True if this spec has any dependency that satisfies the supplied
spec."""
- if not isinstance(spec, Spec):
- spec = Spec(spec)
-
+ spec = self._autospec(spec)
for s in self.preorder_traversal():
if s.satisfies(spec):
return True
@@ -1104,18 +1117,22 @@ class SpecParser(spack.parse.Parser):
def do_parse(self):
specs = []
- while self.next:
- if self.accept(ID):
- specs.append(self.spec())
- elif self.accept(DEP):
- if not specs:
- self.last_token_error("Dependency has no package")
- self.expect(ID)
- specs[-1]._add_dependency(self.spec())
+ try:
+ while self.next:
+ if self.accept(ID):
+ specs.append(self.spec())
- else:
- self.unexpected_token()
+ elif self.accept(DEP):
+ if not specs:
+ self.last_token_error("Dependency has no package")
+ self.expect(ID)
+ specs[-1]._add_dependency(self.spec())
+
+ else:
+ self.unexpected_token()
+ except spack.parse.ParseError, e:
+ raise SpecParseError(e)
return specs
@@ -1238,7 +1255,7 @@ def parse(string):
return SpecParser().parse(string)
-def parse_local_spec(spec_like, pkg_name):
+def parse_anonymous_spec(spec_like, pkg_name):
"""Allow the user to omit the package name part of a spec if they
know what it has to be already.
@@ -1251,19 +1268,19 @@ def parse_local_spec(spec_like, pkg_name):
if isinstance(spec_like, str):
try:
- local_spec = Spec(spec_like)
- except spack.parse.ParseError:
- local_spec = Spec(pkg_name + spec_like)
- if local_spec.name != pkg_name: raise ValueError(
+ anon_spec = Spec(spec_like)
+ except SpecParseError:
+ anon_spec = Spec(pkg_name + spec_like)
+ if anon_spec.name != pkg_name: raise ValueError(
"Invalid spec for package %s: %s" % (pkg_name, spec_like))
else:
- local_spec = spec_like
+ anon_spec = spec_like.copy()
- if local_spec.name != pkg_name:
+ if anon_spec.name != pkg_name:
raise ValueError("Spec name '%s' must match package name '%s'"
- % (local_spec.name, pkg_name))
+ % (anon_spec.name, pkg_name))
- return local_spec
+ return anon_spec
class SpecError(spack.error.SpackError):
@@ -1272,6 +1289,14 @@ class SpecError(spack.error.SpackError):
super(SpecError, self).__init__(message)
+class SpecParseError(SpecError):
+ """Wrapper for ParseError for when we're parsing specs."""
+ def __init__(self, parse_error):
+ super(SpecParseError, self).__init__(parse_error.message)
+ self.string = parse_error.string
+ self.pos = parse_error.pos
+
+
class DuplicateDependencyError(SpecError):
"""Raised when the same dependency occurs in a spec twice."""
def __init__(self, message):