diff --git a/mercurial/revlogutils/docket.py b/mercurial/revlogutils/docket.py --- a/mercurial/revlogutils/docket.py +++ b/mercurial/revlogutils/docket.py @@ -17,10 +17,16 @@ from __future__ import absolute_import +import errno +import os +import random import struct from .. import ( + encoding, error, + node, + pycompat, util, ) @@ -28,6 +34,55 @@ constants, ) + +def make_uid(id_size=8): + """return a new unique identifier. + + The identifier is random and composed of ascii characters.""" + # size we "hex" the result we need half the number of bits to have a final + # uuid of size ID_SIZE + return node.hex(os.urandom(id_size // 2)) + + +# some special test logic to avoid anoying random output in the test +stable_docket_file = encoding.environ.get(b'HGTEST_UUIDFILE') + +if stable_docket_file: + + def make_uid(id_size=8): + 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'04' # 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 * 4) + assert id_size == 8 + p = struct.pack('>L', raw) + new = node.hex(p) + with open(stable_docket_file, 'wb') as f: + f.write(new) + return new + + # Docket format # # * 4 bytes: revlog version diff --git a/mercurial/revlogutils/nodemap.py b/mercurial/revlogutils/nodemap.py --- a/mercurial/revlogutils/nodemap.py +++ b/mercurial/revlogutils/nodemap.py @@ -9,19 +9,16 @@ from __future__ import absolute_import import errno -import os -import random import re import struct from ..node import hex from .. import ( - encoding, error, - pycompat, util, ) +from . import docket as docket_mod class NodeMap(dict): @@ -281,56 +278,6 @@ S_VERSION = struct.Struct(">B") S_HEADER = struct.Struct(">BQQQQ") -ID_SIZE = 8 - - -def _make_uid(): - """return a new unique identifier. - - The identifier is random and composed of ascii characters.""" - # size we "hex" the result we need half the number of bits to have a final - # uuid of size ID_SIZE - return hex(os.urandom(ID_SIZE // 2)) - - -# 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 * 4) - assert ID_SIZE == 8 - p = struct.pack('>L', 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 @@ -340,7 +287,7 @@ def __init__(self, uid=None): if uid is None: - uid = _make_uid() + uid = docket_mod.make_uid() # a unique identifier for the data file: # - When new data are appended, it is preserved. # - When a new data file is created, a new identifier is generated. diff --git a/tests/run-tests.py b/tests/run-tests.py --- a/tests/run-tests.py +++ b/tests/run-tests.py @@ -1386,8 +1386,8 @@ env['PYTHONUSERBASE'] = sysconfig.get_config_var('userbase') or '' env['HGEMITWARNINGS'] = '1' env['TESTTMP'] = _bytes2sys(self._testtmp) - docket_id_file = os.path.join(_bytes2sys(self._testtmp), 'DOCKETID') - env['HGTEST_DOCKETIDFILE'] = docket_id_file + uid_file = os.path.join(_bytes2sys(self._testtmp), 'UID') + env['HGTEST_UUIDFILE'] = uid_file env['TESTNAME'] = self.name env['HOME'] = _bytes2sys(self._testtmp) if os.name == 'nt':