spec: support "full" hashes
This hash includes the content of the package itself as well as the DAG for the package.
This commit is contained in:
parent
3501f2f4b5
commit
6458b15bb1
@ -1085,6 +1085,8 @@ def __init__(self, spec_like, **kwargs):
|
|||||||
self.external_path = kwargs.get('external_path', None)
|
self.external_path = kwargs.get('external_path', None)
|
||||||
self.external_module = kwargs.get('external_module', None)
|
self.external_module = kwargs.get('external_module', None)
|
||||||
|
|
||||||
|
self._full_hash = kwargs.get('full_hash', None)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def external(self):
|
def external(self):
|
||||||
return bool(self.external_path) or bool(self.external_module)
|
return bool(self.external_path) or bool(self.external_module)
|
||||||
@ -1426,7 +1428,21 @@ def dag_hash_bit_prefix(self, bits):
|
|||||||
"""Get the first <bits> bits of the DAG hash as an integer type."""
|
"""Get the first <bits> bits of the DAG hash as an integer type."""
|
||||||
return base32_prefix_bits(self.dag_hash(), bits)
|
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()
|
d = syaml_dict()
|
||||||
|
|
||||||
if self.versions:
|
if self.versions:
|
||||||
@ -1460,10 +1476,12 @@ def to_node_dict(self):
|
|||||||
# TODO: concretization.
|
# TODO: concretization.
|
||||||
deps = self.dependencies_dict(deptype=('link', 'run'))
|
deps = self.dependencies_dict(deptype=('link', 'run'))
|
||||||
if deps:
|
if deps:
|
||||||
|
if hash_function is None:
|
||||||
|
hash_function = lambda s: s.dag_hash()
|
||||||
d['dependencies'] = syaml_dict([
|
d['dependencies'] = syaml_dict([
|
||||||
(name,
|
(name,
|
||||||
syaml_dict([
|
syaml_dict([
|
||||||
('hash', dspec.spec.dag_hash()),
|
('hash', hash_function(dspec.spec)),
|
||||||
('type', sorted(str(s) for s in dspec.deptypes))])
|
('type', sorted(str(s) for s in dspec.deptypes))])
|
||||||
) for name, dspec in sorted(deps.items())
|
) for name, dspec in sorted(deps.items())
|
||||||
])
|
])
|
||||||
@ -1491,7 +1509,7 @@ def from_node_dict(node):
|
|||||||
name = next(iter(node))
|
name = next(iter(node))
|
||||||
node = node[name]
|
node = node[name]
|
||||||
|
|
||||||
spec = Spec(name)
|
spec = Spec(name, full_hash=node.get('full_hash', None))
|
||||||
spec.namespace = node.get('namespace', None)
|
spec.namespace = node.get('namespace', None)
|
||||||
spec._hash = node.get('hash', None)
|
spec._hash = node.get('hash', None)
|
||||||
|
|
||||||
@ -2653,11 +2671,13 @@ def _dup(self, other, deps=True, cleardeps=True, caches=None):
|
|||||||
self._cmp_key_cache = other._cmp_key_cache
|
self._cmp_key_cache = other._cmp_key_cache
|
||||||
self._normal = other._normal
|
self._normal = other._normal
|
||||||
self._concrete = other._concrete
|
self._concrete = other._concrete
|
||||||
|
self._full_hash = other._full_hash
|
||||||
else:
|
else:
|
||||||
self._hash = None
|
self._hash = None
|
||||||
self._cmp_key_cache = None
|
self._cmp_key_cache = None
|
||||||
self._normal = False
|
self._normal = False
|
||||||
self._concrete = False
|
self._concrete = False
|
||||||
|
self._full_hash = None
|
||||||
|
|
||||||
return changed
|
return changed
|
||||||
|
|
||||||
@ -3383,6 +3403,7 @@ def spec(self, name):
|
|||||||
spec._package = None
|
spec._package = None
|
||||||
spec._normal = False
|
spec._normal = False
|
||||||
spec._concrete = False
|
spec._concrete = False
|
||||||
|
spec._full_hash = None
|
||||||
|
|
||||||
# record this so that we know whether version is
|
# record this so that we know whether version is
|
||||||
# unspecified or not.
|
# unspecified or not.
|
||||||
|
@ -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_json_spec.dag_hash()
|
||||||
assert spec.dag_hash() == round_trip_reversed_yaml_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()
|
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):
|
def reverse_all_dicts(data):
|
||||||
|
Loading…
Reference in New Issue
Block a user