Mercurial > hg
changeset 46780:6266d19556ad
node: introduce nodeconstants class
In preparing for moving from SHA1 hashes to a modern hash function,
place nullid and other constant magic vules in a class. Provide the
active set of constants in the repository and push it down. Provide
nullid directly in strategic places like the repository as it is
accessed very often. This changeset introduces the API change, but not
the mechanical replacement of the node.py attributes itself.
Differential Revision: https://phab.mercurial-scm.org/D9750
author | Joerg Sonnenberger <joerg@bec.de> |
---|---|
date | Wed, 13 Jan 2021 16:14:58 +0100 |
parents | 49fd21f32695 |
children | 1099ca176ba1 |
files | contrib/perf.py hgext/absorb.py hgext/git/gitlog.py hgext/largefiles/lfutil.py hgext/sqlitestore.py mercurial/bookmarks.py mercurial/branchmap.py mercurial/bundle2.py mercurial/bundlerepo.py mercurial/changegroup.py mercurial/changelog.py mercurial/dirstate.py mercurial/discovery.py mercurial/exchange.py mercurial/filelog.py mercurial/interfaces/dirstate.py mercurial/interfaces/repository.py mercurial/localrepo.py mercurial/manifest.py mercurial/node.py mercurial/obsolete.py mercurial/revlog.py mercurial/statichttprepo.py mercurial/store.py mercurial/unionrepo.py mercurial/upgrade_utils/engine.py relnotes/next tests/simplestorerepo.py tests/test-check-interfaces.py tests/test-manifest.py |
diffstat | 30 files changed, 215 insertions(+), 86 deletions(-) [+] |
line wrap: on
line diff
--- a/contrib/perf.py Wed Mar 10 18:09:21 2021 +0100 +++ b/contrib/perf.py Wed Jan 13 16:14:58 2021 +0100 @@ -3672,7 +3672,7 @@ Result is the number of markers in the repo.""" timer, fm = gettimer(ui) svfs = getsvfs(repo) - timer(lambda: len(obsolete.obsstore(svfs))) + timer(lambda: len(obsolete.obsstore(repo, svfs))) fm.end()
--- a/hgext/absorb.py Wed Mar 10 18:09:21 2021 +0100 +++ b/hgext/absorb.py Wed Jan 13 16:14:58 2021 +0100 @@ -102,6 +102,9 @@ class emptyfilecontext(object): """minimal filecontext representing an empty file""" + def __init__(self, repo): + self._repo = repo + def data(self): return b'' @@ -212,7 +215,7 @@ if path in pctx: fctxs.append(pctx[path]) else: - fctxs.append(emptyfilecontext()) + fctxs.append(emptyfilecontext(pctx.repo())) fctxs.reverse() # note: we rely on a property of hg: filerev is not reused for linear
--- a/hgext/git/gitlog.py Wed Mar 10 18:09:21 2021 +0100 +++ b/hgext/git/gitlog.py Wed Jan 13 16:14:58 2021 +0100 @@ -8,6 +8,7 @@ nullhex, nullid, nullrev, + sha1nodeconstants, wdirhex, ) from mercurial import ( @@ -422,6 +423,8 @@ class manifestlog(baselog): + nodeconstants = sha1nodeconstants + def __getitem__(self, node): return self.get(b'', node)
--- a/hgext/largefiles/lfutil.py Wed Mar 10 18:09:21 2021 +0100 +++ b/hgext/largefiles/lfutil.py Wed Jan 13 16:14:58 2021 +0100 @@ -206,6 +206,7 @@ repo.root, repo.dirstate._validate, lambda: sparse.matcher(repo), + repo.nodeconstants, ) # If the largefiles dirstate does not exist, populate and create
--- a/hgext/sqlitestore.py Wed Mar 10 18:09:21 2021 +0100 +++ b/hgext/sqlitestore.py Wed Jan 13 16:14:58 2021 +0100 @@ -54,6 +54,7 @@ from mercurial.node import ( nullid, nullrev, + sha1nodeconstants, short, ) from mercurial.thirdparty import attr @@ -305,6 +306,7 @@ """Implements storage for an individual tracked path.""" def __init__(self, db, path, compression): + self.nullid = sha1nodeconstants.nullid self._db = db self._path = path
--- a/mercurial/bookmarks.py Wed Mar 10 18:09:21 2021 +0100 +++ b/mercurial/bookmarks.py Wed Jan 13 16:14:58 2021 +0100 @@ -623,7 +623,7 @@ _binaryentry = struct.Struct(b'>20sH') -def binaryencode(bookmarks): +def binaryencode(repo, bookmarks): """encode a '(bookmark, node)' iterable into a binary stream the binary format is: @@ -645,7 +645,7 @@ return b''.join(binarydata) -def binarydecode(stream): +def binarydecode(repo, stream): """decode a binary stream into an '(bookmark, node)' iterable the binary format is:
--- a/mercurial/branchmap.py Wed Mar 10 18:09:21 2021 +0100 +++ b/mercurial/branchmap.py Wed Jan 13 16:14:58 2021 +0100 @@ -97,7 +97,7 @@ revs.extend(r for r in extrarevs if r <= bcache.tiprev) else: # nothing to fall back on, start empty. - bcache = branchcache() + bcache = branchcache(repo) revs.extend(cl.revs(start=bcache.tiprev + 1)) if revs: @@ -129,6 +129,7 @@ if rbheads: rtiprev = max((int(clrev(node)) for node in rbheads)) cache = branchcache( + repo, remotebranchmap, repo[rtiprev].node(), rtiprev, @@ -184,6 +185,7 @@ def __init__( self, + repo, entries=(), tipnode=nullid, tiprev=nullrev, @@ -195,6 +197,7 @@ """hasnode is a function which can be used to verify whether changelog has a given node or not. If it's not provided, we assume that every node we have exists in changelog""" + self._repo = repo self.tipnode = tipnode self.tiprev = tiprev self.filteredhash = filteredhash @@ -280,6 +283,7 @@ if len(cachekey) > 2: filteredhash = bin(cachekey[2]) bcache = cls( + repo, tipnode=last, tiprev=lrev, filteredhash=filteredhash, @@ -388,6 +392,7 @@ def copy(self): """return an deep copy of the branchcache object""" return type(self)( + self._repo, self._entries, self.tipnode, self.tiprev,
--- a/mercurial/bundle2.py Wed Mar 10 18:09:21 2021 +0100 +++ b/mercurial/bundle2.py Wed Jan 13 16:14:58 2021 +0100 @@ -2146,7 +2146,7 @@ contains binary encoded (bookmark, node) tuple. If the local state does not marks the one in the part, a PushRaced exception is raised """ - bookdata = bookmarks.binarydecode(inpart) + bookdata = bookmarks.binarydecode(op.repo, inpart) msgstandard = ( b'remote repository changed while pushing - please try again ' @@ -2376,7 +2376,7 @@ When mode is 'records', the information is recorded into the 'bookmarks' records of the bundle operation. This behavior is suitable for pulling. """ - changes = bookmarks.binarydecode(inpart) + changes = bookmarks.binarydecode(op.repo, inpart) pushkeycompat = op.repo.ui.configbool( b'server', b'bookmarks-pushkey-compat'
--- a/mercurial/bundlerepo.py Wed Mar 10 18:09:21 2021 +0100 +++ b/mercurial/bundlerepo.py Wed Jan 13 16:14:58 2021 +0100 @@ -175,9 +175,15 @@ class bundlemanifest(bundlerevlog, manifest.manifestrevlog): def __init__( - self, opener, cgunpacker, linkmapper, dirlogstarts=None, dir=b'' + self, + nodeconstants, + opener, + cgunpacker, + linkmapper, + dirlogstarts=None, + dir=b'', ): - manifest.manifestrevlog.__init__(self, opener, tree=dir) + manifest.manifestrevlog.__init__(self, nodeconstants, opener, tree=dir) bundlerevlog.__init__( self, opener, self.indexfile, cgunpacker, linkmapper ) @@ -192,6 +198,7 @@ if d in self._dirlogstarts: self.bundle.seek(self._dirlogstarts[d]) return bundlemanifest( + self.nodeconstants, self.opener, self.bundle, self._linkmapper, @@ -368,7 +375,9 @@ # consume the header if it exists self._cgunpacker.manifestheader() linkmapper = self.unfiltered().changelog.rev - rootstore = bundlemanifest(self.svfs, self._cgunpacker, linkmapper) + rootstore = bundlemanifest( + self.nodeconstants, self.svfs, self._cgunpacker, linkmapper + ) self.filestart = self._cgunpacker.tell() return manifest.manifestlog(
--- a/mercurial/changegroup.py Wed Mar 10 18:09:21 2021 +0100 +++ b/mercurial/changegroup.py Wed Jan 13 16:14:58 2021 +0100 @@ -662,7 +662,7 @@ return readexactly(self._fh, n) -def _revisiondeltatochunks(delta, headerfn): +def _revisiondeltatochunks(repo, delta, headerfn): """Serialize a revisiondelta to changegroup chunks.""" # The captured revision delta may be encoded as a delta against @@ -1065,7 +1065,9 @@ sidedata_helpers=sidedata_helpers, ) for delta in deltas: - for chunk in _revisiondeltatochunks(delta, self._builddeltaheader): + for chunk in _revisiondeltatochunks( + self._repo, delta, self._builddeltaheader + ): size += len(chunk) yield chunk @@ -1121,7 +1123,9 @@ yield chunk for delta in deltas: - chunks = _revisiondeltatochunks(delta, self._builddeltaheader) + chunks = _revisiondeltatochunks( + self._repo, delta, self._builddeltaheader + ) for chunk in chunks: size += len(chunk) yield chunk @@ -1160,7 +1164,9 @@ yield h for delta in deltas: - chunks = _revisiondeltatochunks(delta, self._builddeltaheader) + chunks = _revisiondeltatochunks( + self._repo, delta, self._builddeltaheader + ) for chunk in chunks: size += len(chunk) yield chunk
--- a/mercurial/changelog.py Wed Mar 10 18:09:21 2021 +0100 +++ b/mercurial/changelog.py Wed Jan 13 16:14:58 2021 +0100 @@ -191,7 +191,7 @@ # Extensions might modify _defaultextra, so let the constructor below pass # it in extra = attr.ib() - manifest = attr.ib(default=nullid) + manifest = attr.ib() user = attr.ib(default=b'') date = attr.ib(default=(0, 0)) files = attr.ib(default=attr.Factory(list)) @@ -219,9 +219,9 @@ '_changes', ) - def __new__(cls, text, sidedata, cpsd): + def __new__(cls, cl, text, sidedata, cpsd): if not text: - return _changelogrevision(extra=_defaultextra) + return _changelogrevision(extra=_defaultextra, manifest=nullid) self = super(changelogrevision, cls).__new__(cls) # We could return here and implement the following as an __init__. @@ -526,7 +526,7 @@ """ d, s = self._revisiondata(nodeorrev) c = changelogrevision( - d, s, self._copiesstorage == b'changeset-sidedata' + self, d, s, self._copiesstorage == b'changeset-sidedata' ) return (c.manifest, c.user, c.date, c.files, c.description, c.extra) @@ -534,7 +534,7 @@ """Obtain a ``changelogrevision`` for a node or revision.""" text, sidedata = self._revisiondata(nodeorrev) return changelogrevision( - text, sidedata, self._copiesstorage == b'changeset-sidedata' + self, text, sidedata, self._copiesstorage == b'changeset-sidedata' ) def readfiles(self, nodeorrev):
--- a/mercurial/dirstate.py Wed Mar 10 18:09:21 2021 +0100 +++ b/mercurial/dirstate.py Wed Jan 13 16:14:58 2021 +0100 @@ -73,13 +73,16 @@ @interfaceutil.implementer(intdirstate.idirstate) class dirstate(object): - def __init__(self, opener, ui, root, validate, sparsematchfn): + def __init__( + self, opener, ui, root, validate, sparsematchfn, nodeconstants + ): """Create a new dirstate object. opener is an open()-like callable that can be used to open the dirstate file; root is the root of the directory tracked by the dirstate. """ + self._nodeconstants = nodeconstants self._opener = opener self._validate = validate self._root = root @@ -136,7 +139,9 @@ @propertycache def _map(self): """Return the dirstate contents (see documentation for dirstatemap).""" - self._map = self._mapcls(self._ui, self._opener, self._root) + self._map = self._mapcls( + self._ui, self._opener, self._root, self._nodeconstants + ) return self._map @property @@ -1420,12 +1425,13 @@ denormalized form that they appear as in the dirstate. """ - def __init__(self, ui, opener, root): + def __init__(self, ui, opener, root, nodeconstants): self._ui = ui self._opener = opener self._root = root self._filename = b'dirstate' self._nodelen = 20 + self._nodeconstants = nodeconstants self._parents = None self._dirtyparents = False @@ -1724,7 +1730,8 @@ if rustmod is not None: class dirstatemap(object): - def __init__(self, ui, opener, root): + def __init__(self, ui, opener, root, nodeconstants): + self._nodeconstants = nodeconstants self._ui = ui self._opener = opener self._root = root
--- a/mercurial/discovery.py Wed Mar 10 18:09:21 2021 +0100 +++ b/mercurial/discovery.py Wed Jan 13 16:14:58 2021 +0100 @@ -270,9 +270,12 @@ # C. Update newmap with outgoing changes. # This will possibly add new heads and remove existing ones. newmap = branchmap.remotebranchcache( - (branch, heads[1]) - for branch, heads in pycompat.iteritems(headssum) - if heads[0] is not None + repo, + ( + (branch, heads[1]) + for branch, heads in pycompat.iteritems(headssum) + if heads[0] is not None + ), ) newmap.update(repo, (ctx.rev() for ctx in missingctx)) for branch, newheads in pycompat.iteritems(newmap):
--- a/mercurial/exchange.py Wed Mar 10 18:09:21 2021 +0100 +++ b/mercurial/exchange.py Wed Jan 13 16:14:58 2021 +0100 @@ -827,7 +827,7 @@ data = [] for book, old, new in pushop.outbookmarks: data.append((book, old)) - checkdata = bookmod.binaryencode(data) + checkdata = bookmod.binaryencode(pushop.repo, data) bundler.newpart(b'check:bookmarks', data=checkdata) @@ -1027,7 +1027,7 @@ _abortonsecretctx(pushop, new, book) data.append((book, new)) allactions.append((book, _bmaction(old, new))) - checkdata = bookmod.binaryencode(data) + checkdata = bookmod.binaryencode(pushop.repo, data) bundler.newpart(b'bookmarks', data=checkdata) def handlereply(op): @@ -2455,7 +2455,7 @@ if not b2caps or b'bookmarks' not in b2caps: raise error.Abort(_(b'no common bookmarks exchange method')) books = bookmod.listbinbookmarks(repo) - data = bookmod.binaryencode(books) + data = bookmod.binaryencode(repo, books) if data: bundler.newpart(b'bookmarks', data=data)
--- a/mercurial/filelog.py Wed Mar 10 18:09:21 2021 +0100 +++ b/mercurial/filelog.py Wed Jan 13 16:14:58 2021 +0100 @@ -33,6 +33,7 @@ # Used by LFS. self._revlog.filename = path self._revlog.revlog_kind = b'filelog' + self.nullid = self._revlog.nullid def __len__(self): return len(self._revlog)
--- a/mercurial/interfaces/dirstate.py Wed Mar 10 18:09:21 2021 +0100 +++ b/mercurial/interfaces/dirstate.py Wed Jan 13 16:14:58 2021 +0100 @@ -8,7 +8,7 @@ class idirstate(interfaceutil.Interface): - def __init__(opener, ui, root, validate, sparsematchfn): + def __init__(opener, ui, root, validate, sparsematchfn, nodeconstants): """Create a new dirstate object. opener is an open()-like callable that can be used to open the
--- a/mercurial/interfaces/repository.py Wed Mar 10 18:09:21 2021 +0100 +++ b/mercurial/interfaces/repository.py Wed Jan 13 16:14:58 2021 +0100 @@ -523,6 +523,10 @@ * Metadata to facilitate storage. """ + nullid = interfaceutil.Attribute( + """node for the null revision for use as delta base.""" + ) + def __len__(): """Obtain the number of revisions stored for this file.""" @@ -1143,6 +1147,10 @@ class imanifeststorage(interfaceutil.Interface): """Storage interface for manifest data.""" + nodeconstants = interfaceutil.Attribute( + """nodeconstants used by the current repository.""" + ) + tree = interfaceutil.Attribute( """The path to the directory this manifest tracks. @@ -1366,6 +1374,10 @@ tree manifests. """ + nodeconstants = interfaceutil.Attribute( + """nodeconstants used by the current repository.""" + ) + def __getitem__(node): """Obtain a manifest instance for a given binary node. @@ -1434,6 +1446,13 @@ This currently captures the reality of things - not how things should be. """ + nodeconstants = interfaceutil.Attribute( + """Constant nodes matching the hash function used by the repository.""" + ) + nullid = interfaceutil.Attribute( + """null revision for the hash function used by the repository.""" + ) + supportedformats = interfaceutil.Attribute( """Set of requirements that apply to stream clone.
--- a/mercurial/localrepo.py Wed Mar 10 18:09:21 2021 +0100 +++ b/mercurial/localrepo.py Wed Jan 13 16:14:58 2021 +0100 @@ -21,6 +21,7 @@ hex, nullid, nullrev, + sha1nodeconstants, short, ) from .pycompat import ( @@ -1330,6 +1331,8 @@ self.vfs = hgvfs self.path = hgvfs.base self.requirements = requirements + self.nodeconstants = sha1nodeconstants + self.nullid = self.nodeconstants.nullid self.supported = supportedrequirements self.sharedpath = sharedpath self.store = store @@ -1676,7 +1679,12 @@ sparsematchfn = lambda: sparse.matcher(self) return dirstate.dirstate( - self.vfs, self.ui, self.root, self._dirstatevalidate, sparsematchfn + self.vfs, + self.ui, + self.root, + self._dirstatevalidate, + sparsematchfn, + self.nodeconstants, ) def _dirstatevalidate(self, node):
--- a/mercurial/manifest.py Wed Mar 10 18:09:21 2021 +0100 +++ b/mercurial/manifest.py Wed Jan 13 16:14:58 2021 +0100 @@ -792,8 +792,9 @@ @interfaceutil.implementer(repository.imanifestdict) class treemanifest(object): - def __init__(self, dir=b'', text=b''): + def __init__(self, nodeconstants, dir=b'', text=b''): self._dir = dir + self.nodeconstants = nodeconstants self._node = nullid self._loadfunc = _noop self._copyfunc = _noop @@ -1051,7 +1052,9 @@ if dir: self._loadlazy(dir) if dir not in self._dirs: - self._dirs[dir] = treemanifest(self._subpath(dir)) + self._dirs[dir] = treemanifest( + self.nodeconstants, self._subpath(dir) + ) self._dirs[dir].__setitem__(subpath, n) else: # manifest nodes are either 20 bytes or 32 bytes, @@ -1078,14 +1081,16 @@ if dir: self._loadlazy(dir) if dir not in self._dirs: - self._dirs[dir] = treemanifest(self._subpath(dir)) + self._dirs[dir] = treemanifest( + self.nodeconstants, self._subpath(dir) + ) self._dirs[dir].setflag(subpath, flags) else: self._flags[f] = flags self._dirty = True def copy(self): - copy = treemanifest(self._dir) + copy = treemanifest(self.nodeconstants, self._dir) copy._node = self._node copy._dirty = self._dirty if self._copyfunc is _noop: @@ -1215,7 +1220,7 @@ visit = match.visitchildrenset(self._dir[:-1]) if visit == b'all': return self.copy() - ret = treemanifest(self._dir) + ret = treemanifest(self.nodeconstants, self._dir) if not visit: return ret @@ -1272,7 +1277,7 @@ m2 = m2._matches(match) return m1.diff(m2, clean=clean) result = {} - emptytree = treemanifest() + emptytree = treemanifest(self.nodeconstants) def _iterativediff(t1, t2, stack): """compares two tree manifests and append new tree-manifests which @@ -1368,7 +1373,7 @@ self._load() # for consistency; should never have any effect here m1._load() m2._load() - emptytree = treemanifest() + emptytree = treemanifest(self.nodeconstants) def getnode(m, d): ld = m._lazydirs.get(d) @@ -1551,6 +1556,7 @@ def __init__( self, + nodeconstants, opener, tree=b'', dirlogcache=None, @@ -1567,6 +1573,7 @@ option takes precedence, so if it is set to True, we ignore whatever value is passed in to the constructor. """ + self.nodeconstants = nodeconstants # During normal operations, we expect to deal with not more than four # revs at a time (such as during commit --amend). When rebasing large # stacks of commits, the number can go up, hence the config knob below. @@ -1654,7 +1661,11 @@ assert self._treeondisk if d not in self._dirlogcache: mfrevlog = manifestrevlog( - self.opener, d, self._dirlogcache, treemanifest=self._treeondisk + self.nodeconstants, + self.opener, + d, + self._dirlogcache, + treemanifest=self._treeondisk, ) self._dirlogcache[d] = mfrevlog return self._dirlogcache[d] @@ -1917,6 +1928,7 @@ they receive (i.e. tree or flat or lazily loaded, etc).""" def __init__(self, opener, repo, rootstore, narrowmatch): + self.nodeconstants = repo.nodeconstants usetreemanifest = False cachesize = 4 @@ -1955,7 +1967,7 @@ if not self._narrowmatch.always(): if not self._narrowmatch.visitdir(tree[:-1]): - return excludeddirmanifestctx(tree, node) + return excludeddirmanifestctx(self.nodeconstants, tree, node) if tree: if self._rootstore._treeondisk: if verify: @@ -2118,7 +2130,7 @@ def __init__(self, manifestlog, dir=b''): self._manifestlog = manifestlog self._dir = dir - self._treemanifest = treemanifest() + self._treemanifest = treemanifest(manifestlog.nodeconstants) def _storage(self): return self._manifestlog.getstorage(b'') @@ -2168,17 +2180,19 @@ narrowmatch = self._manifestlog._narrowmatch if not narrowmatch.always(): if not narrowmatch.visitdir(self._dir[:-1]): - return excludedmanifestrevlog(self._dir) + return excludedmanifestrevlog( + self._manifestlog.nodeconstants, self._dir + ) return self._manifestlog.getstorage(self._dir) def read(self): if self._data is None: store = self._storage() if self._node == nullid: - self._data = treemanifest() + self._data = treemanifest(self._manifestlog.nodeconstants) # TODO accessing non-public API elif store._treeondisk: - m = treemanifest(dir=self._dir) + m = treemanifest(self._manifestlog.nodeconstants, dir=self._dir) def gettext(): return store.revision(self._node) @@ -2198,7 +2212,9 @@ text = store.revision(self._node) arraytext = bytearray(text) store.fulltextcache[self._node] = arraytext - self._data = treemanifest(dir=self._dir, text=text) + self._data = treemanifest( + self._manifestlog.nodeconstants, dir=self._dir, text=text + ) return self._data @@ -2235,7 +2251,7 @@ r0 = store.deltaparent(store.rev(self._node)) m0 = self._manifestlog.get(self._dir, store.node(r0)).read() m1 = self.read() - md = treemanifest(dir=self._dir) + md = treemanifest(self._manifestlog.nodeconstants, dir=self._dir) for f, ((n0, fl0), (n1, fl1)) in pycompat.iteritems(m0.diff(m1)): if n1: md[f] = n1 @@ -2278,8 +2294,8 @@ whose contents are unknown. """ - def __init__(self, dir, node): - super(excludeddir, self).__init__(dir) + def __init__(self, nodeconstants, dir, node): + super(excludeddir, self).__init__(nodeconstants, dir) self._node = node # Add an empty file, which will be included by iterators and such, # appearing as the directory itself (i.e. something like "dir/") @@ -2298,12 +2314,13 @@ class excludeddirmanifestctx(treemanifestctx): """context wrapper for excludeddir - see that docstring for rationale""" - def __init__(self, dir, node): + def __init__(self, nodeconstants, dir, node): + self.nodeconstants = nodeconstants self._dir = dir self._node = node def read(self): - return excludeddir(self._dir, self._node) + return excludeddir(self.nodeconstants, self._dir, self._node) def readfast(self, shallow=False): # special version of readfast since we don't have underlying storage @@ -2325,7 +2342,8 @@ outside the narrowspec. """ - def __init__(self, dir): + def __init__(self, nodeconstants, dir): + self.nodeconstants = nodeconstants self._dir = dir def __len__(self):
--- a/mercurial/node.py Wed Mar 10 18:09:21 2021 +0100 +++ b/mercurial/node.py Wed Jan 13 16:14:58 2021 +0100 @@ -21,29 +21,48 @@ raise TypeError(e) -nullrev = -1 -# In hex, this is '0000000000000000000000000000000000000000' -nullid = b"\0" * 20 -nullhex = hex(nullid) +def short(node): + return hex(node[:6]) + -# Phony node value to stand-in for new files in some uses of -# manifests. -# In hex, this is '2121212121212121212121212121212121212121' -newnodeid = b'!!!!!!!!!!!!!!!!!!!!' -# In hex, this is '3030303030303030303030303030306164646564' -addednodeid = b'000000000000000added' -# In hex, this is '3030303030303030303030306d6f646966696564' -modifiednodeid = b'000000000000modified' +nullrev = -1 -wdirfilenodeids = {newnodeid, addednodeid, modifiednodeid} - -# pseudo identifiers for working directory -# (they are experimental, so don't add too many dependencies on them) +# pseudo identifier for working directory +# (experimental, so don't add too many dependencies on it) wdirrev = 0x7FFFFFFF -# In hex, this is 'ffffffffffffffffffffffffffffffffffffffff' -wdirid = b"\xff" * 20 -wdirhex = hex(wdirid) -def short(node): - return hex(node[:6]) +class sha1nodeconstants(object): + nodelen = 20 + + # In hex, this is '0000000000000000000000000000000000000000' + nullid = b"\0" * nodelen + nullhex = hex(nullid) + + # Phony node value to stand-in for new files in some uses of + # manifests. + # In hex, this is '2121212121212121212121212121212121212121' + newnodeid = b'!!!!!!!!!!!!!!!!!!!!' + # In hex, this is '3030303030303030303030303030306164646564' + addednodeid = b'000000000000000added' + # In hex, this is '3030303030303030303030306d6f646966696564' + modifiednodeid = b'000000000000modified' + + wdirfilenodeids = {newnodeid, addednodeid, modifiednodeid} + + # pseudo identifier for working directory + # (experimental, so don't add too many dependencies on it) + # In hex, this is 'ffffffffffffffffffffffffffffffffffffffff' + wdirid = b"\xff" * nodelen + wdirhex = hex(wdirid) + + +# legacy starting point for porting modules +nullid = sha1nodeconstants.nullid +nullhex = sha1nodeconstants.nullhex +newnodeid = sha1nodeconstants.newnodeid +addednodeid = sha1nodeconstants.addednodeid +modifiednodeid = sha1nodeconstants.modifiednodeid +wdirfilenodeids = sha1nodeconstants.wdirfilenodeids +wdirid = sha1nodeconstants.wdirid +wdirhex = sha1nodeconstants.wdirhex
--- a/mercurial/obsolete.py Wed Mar 10 18:09:21 2021 +0100 +++ b/mercurial/obsolete.py Wed Jan 13 16:14:58 2021 +0100 @@ -560,10 +560,11 @@ # parents: (tuple of nodeid) or None, parents of predecessors # None is used when no data has been recorded - def __init__(self, svfs, defaultformat=_fm1version, readonly=False): + def __init__(self, repo, svfs, defaultformat=_fm1version, readonly=False): # caches for various obsolescence related cache self.caches = {} self.svfs = svfs + self.repo = repo self._defaultformat = defaultformat self._readonly = readonly @@ -806,7 +807,7 @@ if defaultformat is not None: kwargs['defaultformat'] = defaultformat readonly = not isenabled(repo, createmarkersopt) - store = obsstore(repo.svfs, readonly=readonly, **kwargs) + store = obsstore(repo, repo.svfs, readonly=readonly, **kwargs) if store and readonly: ui.warn( _(b'obsolete feature not enabled but %i markers found!\n')
--- a/mercurial/revlog.py Wed Mar 10 18:09:21 2021 +0100 +++ b/mercurial/revlog.py Wed Jan 13 16:14:58 2021 +0100 @@ -28,6 +28,7 @@ nullhex, nullid, nullrev, + sha1nodeconstants, short, wdirfilenodeids, wdirhex, @@ -651,6 +652,10 @@ raise error.RevlogError( _(b'unknown version (%d) in revlog %s') % (fmt, self.indexfile) ) + + self.nodeconstants = sha1nodeconstants + self.nullid = self.nodeconstants.nullid + # sparse-revlog can't be on without general-delta (issue6056) if not self._generaldelta: self._sparserevlog = False
--- a/mercurial/statichttprepo.py Wed Mar 10 18:09:21 2021 +0100 +++ b/mercurial/statichttprepo.py Wed Jan 13 16:14:58 2021 +0100 @@ -12,6 +12,7 @@ import errno from .i18n import _ +from .node import sha1nodeconstants from . import ( branchmap, changelog, @@ -198,6 +199,8 @@ requirements, supportedrequirements ) localrepo.ensurerequirementscompatible(ui, requirements) + self.nodeconstants = sha1nodeconstants + self.nullid = self.nodeconstants.nullid # setup store self.store = localrepo.makestore(requirements, self.path, vfsclass) @@ -207,7 +210,7 @@ self._filecache = {} self.requirements = requirements - rootmanifest = manifest.manifestrevlog(self.svfs) + rootmanifest = manifest.manifestrevlog(self.nodeconstants, self.svfs) self.manifestlog = manifest.manifestlog( self.svfs, self, rootmanifest, self.narrowmatch() )
--- a/mercurial/store.py Wed Mar 10 18:09:21 2021 +0100 +++ b/mercurial/store.py Wed Jan 13 16:14:58 2021 +0100 @@ -441,7 +441,7 @@ ) def manifestlog(self, repo, storenarrowmatch): - rootstore = manifest.manifestrevlog(self.vfs) + rootstore = manifest.manifestrevlog(repo.nodeconstants, self.vfs) return manifest.manifestlog(self.vfs, repo, rootstore, storenarrowmatch) def datafiles(self, matcher=None):
--- a/mercurial/unionrepo.py Wed Mar 10 18:09:21 2021 +0100 +++ b/mercurial/unionrepo.py Wed Jan 13 16:14:58 2021 +0100 @@ -153,9 +153,9 @@ class unionmanifest(unionrevlog, manifest.manifestrevlog): - def __init__(self, opener, opener2, linkmapper): - manifest.manifestrevlog.__init__(self, opener) - manifest2 = manifest.manifestrevlog(opener2) + def __init__(self, nodeconstants, opener, opener2, linkmapper): + manifest.manifestrevlog.__init__(self, nodeconstants, opener) + manifest2 = manifest.manifestrevlog(nodeconstants, opener2) unionrevlog.__init__( self, opener, self.indexfile, manifest2, linkmapper ) @@ -205,7 +205,10 @@ @localrepo.unfilteredpropertycache def manifestlog(self): rootstore = unionmanifest( - self.svfs, self.repo2.svfs, self.unfiltered()._clrev + self.nodeconstants, + self.svfs, + self.repo2.svfs, + self.unfiltered()._clrev, ) return manifest.manifestlog( self.svfs, self, rootstore, self.narrowmatch()
--- a/mercurial/upgrade_utils/engine.py Wed Mar 10 18:09:21 2021 +0100 +++ b/mercurial/upgrade_utils/engine.py Wed Jan 13 16:14:58 2021 +0100 @@ -36,7 +36,9 @@ return changelog.changelog(repo.svfs) elif path.endswith(b'00manifest.i'): mandir = path[: -len(b'00manifest.i')] - return manifest.manifestrevlog(repo.svfs, tree=mandir) + return manifest.manifestrevlog( + repo.nodeconstants, repo.svfs, tree=mandir + ) else: # reverse of "/".join(("data", path + ".i")) return filelog.filelog(repo.svfs, path[5:-2])
--- a/relnotes/next Wed Mar 10 18:09:21 2021 +0100 +++ b/relnotes/next Wed Jan 13 16:14:58 2021 +0100 @@ -43,3 +43,7 @@ now get a revision number as argument instead of a node. * revlog.addrevision returns the revision number instead of the node. + + * `nodes.nullid` and related constants are being phased out as part of + the deprecation of SHA1. Repository instances and related classes + provide access via `nodeconstants` and in some cases `nullid` attributes.
--- a/tests/simplestorerepo.py Wed Mar 10 18:09:21 2021 +0100 +++ b/tests/simplestorerepo.py Wed Jan 13 16:14:58 2021 +0100 @@ -106,7 +106,9 @@ _flagserrorclass = simplestoreerror - def __init__(self, svfs, path): + def __init__(self, repo, svfs, path): + self.nullid = repo.nullid + self._repo = repo self._svfs = svfs self._path = path @@ -689,7 +691,7 @@ class simplestorerepo(repo.__class__): def file(self, f): - return filestorage(self.svfs, f) + return filestorage(repo, self.svfs, f) repo.__class__ = simplestorerepo
--- a/tests/test-check-interfaces.py Wed Mar 10 18:09:21 2021 +0100 +++ b/tests/test-check-interfaces.py Wed Jan 13 16:14:58 2021 +0100 @@ -248,7 +248,10 @@ # Conforms to imanifestlog. ml = manifest.manifestlog( - vfs, repo, manifest.manifestrevlog(repo.svfs), repo.narrowmatch() + vfs, + repo, + manifest.manifestrevlog(repo.nodeconstants, repo.svfs), + repo.narrowmatch(), ) checkzobject(ml) checkzobject(repo.manifestlog) @@ -263,7 +266,7 @@ # Conforms to imanifestdict. checkzobject(mctx.read()) - mrl = manifest.manifestrevlog(vfs) + mrl = manifest.manifestrevlog(repo.nodeconstants, vfs) checkzobject(mrl) ziverify.verifyClass(repository.irevisiondelta, revlog.revlogrevisiondelta)
--- a/tests/test-manifest.py Wed Mar 10 18:09:21 2021 +0100 +++ b/tests/test-manifest.py Wed Jan 13 16:14:58 2021 +0100 @@ -6,6 +6,8 @@ import unittest import zlib +from mercurial.node import sha1nodeconstants + from mercurial import ( manifest as manifestmod, match as matchmod, @@ -436,7 +438,7 @@ class testtreemanifest(unittest.TestCase, basemanifesttests): def parsemanifest(self, text): - return manifestmod.treemanifest(b'', text) + return manifestmod.treemanifest(sha1nodeconstants, b'', text) def testWalkSubtrees(self): m = self.parsemanifest(A_DEEPER_MANIFEST)