summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd Gamblin <tgamblin@llnl.gov>2017-08-29 00:02:25 -0700
committerGitHub <noreply@github.com>2017-08-29 00:02:25 -0700
commitee93993b07d774bf1b2cee09960bbafe8ccfac8e (patch)
treeb320161fe61056f174ad2183bc02d33c0ffb4f96
parent6036a5a113220764e32b50a89a45f24d6b305cb4 (diff)
downloadspack-ee93993b07d774bf1b2cee09960bbafe8ccfac8e.tar.gz
spack-ee93993b07d774bf1b2cee09960bbafe8ccfac8e.tar.bz2
spack-ee93993b07d774bf1b2cee09960bbafe8ccfac8e.tar.xz
spack-ee93993b07d774bf1b2cee09960bbafe8ccfac8e.zip
Make Spec construction simpler (#5227)
-rw-r--r--lib/spack/spack/spec.py53
1 files changed, 26 insertions, 27 deletions
diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py
index aa22978217..2e61e88ddb 100644
--- a/lib/spack/spack/spec.py
+++ b/lib/spack/spack/spec.py
@@ -1133,34 +1133,19 @@ class Spec(object):
if not isinstance(spec_like, string_types):
raise TypeError("Can't make spec out of %s" % type(spec_like))
- spec_list = SpecParser().parse(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)
- # Take all the attributes from the first parsed spec without copying.
- # This is safe b/c we throw out the parsed spec. It's a bit nasty,
- # but it's nastier to implement the constructor so that the parser
- # writes directly into this Spec object.
- other = spec_list[0]
- self.name = other.name
- self.versions = other.versions
- self.architecture = other.architecture
- self.compiler = other.compiler
- self.compiler_flags = other.compiler_flags
- self.compiler_flags.spec = self
- self._dependencies = other._dependencies
- self._dependents = other._dependents
- self.variants = other.variants
- self.variants.spec = self
- self.namespace = other.namespace
- self._hash = other._hash
- self._cmp_key_cache = other._cmp_key_cache
-
- # Specs are by default not assumed to be normal or concrete.
- self._normal = False
- self._concrete = False
+ # 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)
@@ -3131,9 +3116,17 @@ _lexer = SpecLexer()
class SpecParser(spack.parse.Parser):
- def __init__(self):
+ def __init__(self, initial_spec=None):
+ """Construct a new SpecParser.
+
+ Args:
+ initial_spec (Spec, optional): provide a Spec that we'll parse
+ directly into. This is used to avoid construction of a
+ superfluous Spec object in the Spec constructor.
+ """
super(SpecParser, self).__init__(_lexer)
self.previous = None
+ self._initial = initial_spec
def do_parse(self):
specs = []
@@ -3257,8 +3250,14 @@ class SpecParser(spack.parse.Parser):
spec_namespace = None
spec_name = None
- # This will init the spec without calling __init__.
- spec = Spec.__new__(Spec)
+ if self._initial is None:
+ # This will init the spec without calling Spec.__init__
+ spec = Spec.__new__(Spec)
+ else:
+ # this is used by Spec.__init__
+ spec = self._initial
+ self._initial = None
+
spec.name = spec_name
spec.versions = VersionList()
spec.variants = VariantMap(spec)
@@ -3316,7 +3315,7 @@ class SpecParser(spack.parse.Parser):
# Get spec by hash and confirm it matches what we already have
hash_spec = self.spec_by_hash()
if hash_spec.satisfies(spec):
- spec = hash_spec
+ spec._dup(hash_spec)
break
else:
raise InvalidHashError(spec, hash_spec.dag_hash())