mercurial/revlogutils/nodemap.py
changeset 47321 9a3aa54774ff
parent 47251 4f38ada3fc26
child 47322 5bc6d2fc1cfc
--- a/mercurial/revlogutils/nodemap.py	Thu May 06 19:39:19 2021 -0400
+++ b/mercurial/revlogutils/nodemap.py	Wed May 19 17:19:46 2021 +0200
@@ -10,13 +10,16 @@
 
 import errno
 import os
+import random
 import re
 import struct
 
 from ..node import hex
 
 from .. import (
+    encoding,
     error,
+    pycompat,
     util,
 )
 
@@ -288,6 +291,45 @@
     return hex(os.urandom(ID_SIZE))
 
 
+# some special test logic to avoid anoying random output in the test
+stable_docket_file = encoding.environ.get(b'HGTEST_DOCKETIDFILE')
+
+if stable_docket_file:
+
+    def _make_uid():
+        try:
+            with open(stable_docket_file, mode='rb') as f:
+                seed = f.read().strip()
+        except IOError as inst:
+            if inst.errno != errno.ENOENT:
+                raise
+            seed = b'4'  # chosen by a fair dice roll. garanteed to be random
+        if pycompat.ispy3:
+            iter_seed = iter(seed)
+        else:
+            iter_seed = (ord(c) for c in seed)
+        # some basic circular sum hashing on 64 bits
+        int_seed = 0
+        low_mask = int('1' * 35, 2)
+        for i in iter_seed:
+            high_part = int_seed >> 35
+            low_part = (int_seed & low_mask) << 28
+            int_seed = high_part + low_part + i
+        r = random.Random()
+        if pycompat.ispy3:
+            r.seed(int_seed, version=1)
+        else:
+            r.seed(int_seed)
+        # once we drop python 3.8 support we can simply use r.randbytes
+        raw = r.getrandbits(ID_SIZE * 8)
+        assert ID_SIZE == 8
+        p = struct.pack('>Q', raw)
+        new = hex(p)
+        with open(stable_docket_file, 'wb') as f:
+            f.write(new)
+        return new
+
+
 class NodeMapDocket(object):
     """metadata associated with persistent nodemap data