summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorTodd Gamblin <tgamblin@llnl.gov>2015-04-29 01:47:09 -0700
committerTodd Gamblin <tgamblin@llnl.gov>2015-04-29 01:47:09 -0700
commit278e70e533587f734a9ccaa2131291734883efbb (patch)
tree3ff8501f1533ce9eaa8e8ac50bc17cc63299c9c8 /lib
parent13132c6b9785859d4edf9ca1b11e61abc3ad4b51 (diff)
downloadspack-278e70e533587f734a9ccaa2131291734883efbb.tar.gz
spack-278e70e533587f734a9ccaa2131291734883efbb.tar.bz2
spack-278e70e533587f734a9ccaa2131291734883efbb.tar.xz
spack-278e70e533587f734a9ccaa2131291734883efbb.zip
Specs to/from YAML are working.
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/external/__init__.py9
-rw-r--r--lib/spack/spack/spec.py95
2 files changed, 102 insertions, 2 deletions
diff --git a/lib/spack/external/__init__.py b/lib/spack/external/__init__.py
index 1cc981930a..0578022210 100644
--- a/lib/spack/external/__init__.py
+++ b/lib/spack/external/__init__.py
@@ -28,6 +28,11 @@ packages that are included in spack.
So far:
argparse: We include our own version to be Python 2.6 compatible.
- pyqver2: External script to query required python version of python source code.
- Used for ensuring 2.6 compatibility.
+
+ pyqver2: External script to query required python version of
+ python source code. Used for ensuring 2.6 compatibility.
+
+ functools: Used for implementation of total_ordering.
+
+ yaml: Used for config files.
"""
diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py
index dffdccaddb..32970cdd33 100644
--- a/lib/spack/spack/spec.py
+++ b/lib/spack/spack/spec.py
@@ -95,6 +95,7 @@ import itertools
import hashlib
from StringIO import StringIO
from operator import attrgetter
+from external import yaml
import llnl.util.tty as tty
from llnl.util.lang import *
@@ -578,6 +579,100 @@ class Spec(object):
return full_hash[:length]
+ def dag_hash(self, length=None):
+ """Return a hash of the entire spec DAG, including connectivity."""
+ sha = hashlib.sha1()
+ sha.update(self.to_node_yaml(canonical=True))
+ full_hash = sha.hexdigest()
+ return full_hash[:length]
+
+
+ def to_node_dict(self):
+ return {
+ self.name : {
+ 'versions': [str(v) for v in self.versions],
+ 'compiler' : None if self.compiler is None else {
+ 'name' : self.compiler.name,
+ 'versions': [str(v) for v in self.compiler.versions],
+ },
+ 'variants' : dict(
+ (name,v.enabled) for name, v in self.variants.items()),
+ 'arch' : self.architecture,
+ 'dependencies' : dict((d, self.dependencies[d].dag_hash())
+ for d in sorted(self.dependencies))
+ }}
+
+
+ def to_node_yaml(self, **kwargs):
+ """Return spec's DAG in minimal YAML (only immediate descendents)."""
+ canonical = kwargs.pop('canonical', False)
+ check_kwargs(kwargs, self.to_yaml)
+ if canonical:
+ return yaml.dump(self.to_node_dict(),
+ default_flow_style=True, width=sys.maxint)
+ else:
+ return yaml.dump(self.to_node_dict(),
+ default_flow_style=False)
+
+
+ def to_dict(self):
+ return {
+ 'dag' : [s.to_node_dict() for s in self.traverse(order='pre')],
+ 'hash' : self.dag_hash()
+ }
+
+
+ def to_yaml(self):
+ return yaml.dump(self.to_dict(), default_flow_style=False)
+
+
+ @staticmethod
+ def from_node_dict(node):
+ name = next(iter(node))
+ node = node[name]
+
+ spec = Spec(name)
+ spec.versions = VersionList(node['versions'])
+ compiler = node['compiler']
+ spec.architecture = node['arch']
+
+ if compiler is None:
+ spec.compiler = None
+ else:
+ spec.compiler = CompilerSpec(compiler['name'], compiler['versions'])
+
+ for name, enabled in node['variants'].items():
+ spec.variants[name] = Variant(name, enabled)
+
+ return spec
+
+
+ @staticmethod
+ def from_yaml(string):
+ """Construct a spec from YAML.
+
+ TODO: currently discards hashes. Include hashes when they
+ represent more than the DAG does.
+
+ """
+ deps = {}
+ spec = None
+
+ yfile = yaml.load(string)
+ for node in yfile['dag']:
+ name = next(iter(node))
+ dep = Spec.from_node_dict(node)
+ if not spec:
+ spec = dep
+ deps[dep.name] = dep
+
+ for node in yfile['dag']:
+ name = next(iter(node))
+ for dep_name in node[name]['dependencies']:
+ deps[name].dependencies[dep_name] = deps[dep_name]
+ return spec
+
+
def _concretize_helper(self, presets=None, visited=None):
"""Recursive helper function for concretize().
This concretizes everything bottom-up. As things are