summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorPeter Scheibel <scheibel1@llnl.gov>2018-02-06 10:58:49 -0500
committerTodd Gamblin <tgamblin@llnl.gov>2018-03-20 00:29:54 -0700
commit6458b15bb1ff075a7c3a25c122c0bd4dde5dca0b (patch)
treefca5f85e44b85552b5055b0a16c59cb643b89b40 /lib
parent3501f2f4b5db871d8f2f63f05b29147b264c0920 (diff)
downloadspack-6458b15bb1ff075a7c3a25c122c0bd4dde5dca0b.tar.gz
spack-6458b15bb1ff075a7c3a25c122c0bd4dde5dca0b.tar.bz2
spack-6458b15bb1ff075a7c3a25c122c0bd4dde5dca0b.tar.xz
spack-6458b15bb1ff075a7c3a25c122c0bd4dde5dca0b.zip
spec: support "full" hashes
This hash includes the content of the package itself as well as the DAG for the package.
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/spack/spec.py27
-rw-r--r--lib/spack/spack/test/spec_yaml.py10
2 files changed, 34 insertions, 3 deletions
diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py
index 489e1135af..68fa632e9e 100644
--- a/lib/spack/spack/spec.py
+++ b/lib/spack/spack/spec.py
@@ -1085,6 +1085,8 @@ class Spec(object):
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
def external(self):
return bool(self.external_path) or bool(self.external_module)
@@ -1426,7 +1428,21 @@ class Spec(object):
"""Get the first <bits> bits of the DAG hash as an integer type."""
return base32_prefix_bits(self.dag_hash(), bits)
- def to_node_dict(self):
+ def full_hash(self, length=None):
+ if not self.concrete:
+ raise SpecError("Spec is not concrete: " + str(self))
+
+ if not self._full_hash:
+ yaml_text = syaml.dump(
+ self.to_node_dict(hash_function=lambda s: s.full_hash()),
+ default_flow_style=True, width=maxint)
+ package_hash = self.package.content_hash()
+ sha = hashlib.sha256(yaml_text.encode('utf-8') + package_hash)
+ self._full_hash = base64.b32encode(sha.digest()).lower()
+
+ return self._full_hash[:length]
+
+ def to_node_dict(self, hash_function=None):
d = syaml_dict()
if self.versions:
@@ -1460,10 +1476,12 @@ class Spec(object):
# TODO: concretization.
deps = self.dependencies_dict(deptype=('link', 'run'))
if deps:
+ if hash_function is None:
+ hash_function = lambda s: s.dag_hash()
d['dependencies'] = syaml_dict([
(name,
syaml_dict([
- ('hash', dspec.spec.dag_hash()),
+ ('hash', hash_function(dspec.spec)),
('type', sorted(str(s) for s in dspec.deptypes))])
) for name, dspec in sorted(deps.items())
])
@@ -1491,7 +1509,7 @@ class Spec(object):
name = next(iter(node))
node = node[name]
- spec = Spec(name)
+ spec = Spec(name, full_hash=node.get('full_hash', None))
spec.namespace = node.get('namespace', None)
spec._hash = node.get('hash', None)
@@ -2653,11 +2671,13 @@ class Spec(object):
self._cmp_key_cache = other._cmp_key_cache
self._normal = other._normal
self._concrete = other._concrete
+ self._full_hash = other._full_hash
else:
self._hash = None
self._cmp_key_cache = None
self._normal = False
self._concrete = False
+ self._full_hash = None
return changed
@@ -3383,6 +3403,7 @@ class SpecParser(spack.parse.Parser):
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.
diff --git a/lib/spack/spack/test/spec_yaml.py b/lib/spack/spack/test/spec_yaml.py
index cefb737cfb..0d1840a11c 100644
--- a/lib/spack/spack/test/spec_yaml.py
+++ b/lib/spack/spack/test/spec_yaml.py
@@ -195,6 +195,16 @@ def test_ordered_read_not_required_for_consistent_dag_hash(
assert spec.dag_hash() == round_trip_json_spec.dag_hash()
assert spec.dag_hash() == round_trip_reversed_yaml_spec.dag_hash()
assert spec.dag_hash() == round_trip_reversed_json_spec.dag_hash()
+ # full_hashes are equal
+ spec.concretize()
+ round_trip_yaml_spec.concretize()
+ round_trip_json_spec.concretize()
+ round_trip_reversed_yaml_spec.concretize()
+ round_trip_reversed_json_spec.concretize()
+ assert spec.full_hash() == round_trip_yaml_spec.full_hash()
+ assert spec.full_hash() == round_trip_json_spec.full_hash()
+ assert spec.full_hash() == round_trip_reversed_yaml_spec.full_hash()
+ assert spec.full_hash() == round_trip_reversed_json_spec.full_hash()
def reverse_all_dicts(data):