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.py45
1 files changed, 38 insertions, 7 deletions
diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py
index 1e2da10dcc..45c3402617 100644
--- a/lib/spack/spack/spec.py
+++ b/lib/spack/spack/spec.py
@@ -345,6 +345,17 @@ class Spec(object):
self.compiler = other.compiler
self.dependencies = other.dependencies
+ # 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)
+
+ # Specs cannot be concrete and non-normal.
+ if self._concrete:
+ self._normal = True
+
# This allows users to construct a spec DAG with literals.
# Note that given two specs a and b, Spec(a) copies a, but
# Spec(a, b) will copy a but just add b as a dep.
@@ -432,11 +443,15 @@ class Spec(object):
If any of the name, version, architecture, compiler, or depdenencies
are ambiguous,then it is not concrete.
"""
- return bool(not self.virtual
- and self.versions.concrete
- and self.architecture
- and self.compiler and self.compiler.concrete
- and self.dependencies.concrete)
+ if self._concrete:
+ return True
+
+ self._concrete = bool(not self.virtual
+ and self.versions.concrete
+ and self.architecture
+ and self.compiler and self.compiler.concrete
+ and self.dependencies.concrete)
+ return self._concrete
def preorder_traversal(self, visited=None, d=0, **kwargs):
@@ -606,7 +621,7 @@ class Spec(object):
# If there are duplicate providers or duplicate provider deps, this
# consolidates them and merges constraints.
- self.normalize()
+ self.normalize(force=True)
def concretize(self):
@@ -621,9 +636,13 @@ class Spec(object):
with requirements of its pacakges. See flatten() and normalize() for
more details on this.
"""
+ if self._concrete:
+ return
+
self.normalize()
self._expand_virtual_packages()
self._concretize_helper()
+ self._concrete = True
def concretized(self):
@@ -754,7 +773,7 @@ class Spec(object):
dependency._normalize_helper(visited, spec_deps, provider_index)
- def normalize(self):
+ def normalize(self, **kwargs):
"""When specs are parsed, any dependencies specified are hanging off
the root, and ONLY the ones that were explicitly provided are there.
Normalization turns a partial flat spec into a DAG, where:
@@ -772,6 +791,9 @@ class Spec(object):
TODO: normalize should probably implement some form of cycle detection,
to ensure that the spec is actually a DAG.
"""
+ if self._normal and not kwargs.get('force', False):
+ return
+
# Ensure first that all packages & compilers in the DAG exist.
self.validate_names()
@@ -805,6 +827,9 @@ class Spec(object):
raise InvalidDependencyException(
self.name + " does not depend on " + comma_or(extra))
+ # Mark the spec as normal once done.
+ self._normal = True
+
def normalized(self):
"""Return a normalized copy of this spec without modifying this spec."""
@@ -1009,6 +1034,9 @@ class Spec(object):
else:
self.dependencies = DependencyMap()
+ self._normal = other._normal
+ self._concrete = other._concrete
+
def copy(self, **kwargs):
"""Return a copy of this spec.
@@ -1261,6 +1289,9 @@ class SpecParser(spack.parse.Parser):
spec.dependents = DependencyMap()
spec.dependencies = DependencyMap()
+ spec._normal = False
+ spec._concrete = False
+
# record this so that we know whether version is
# unspecified or not.
added_version = False