diff --git a/contrib/perf.py b/contrib/perf.py --- a/contrib/perf.py +++ b/contrib/perf.py @@ -3672,7 +3672,7 @@ def perfloadmarkers(ui, repo): 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() diff --git a/hgext/absorb.py b/hgext/absorb.py --- a/hgext/absorb.py +++ b/hgext/absorb.py @@ -102,6 +102,9 @@ class nullui(object): 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 @@ def getfilestack(stack, path, seenfctxs= 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 diff --git a/hgext/git/gitlog.py b/hgext/git/gitlog.py --- a/hgext/git/gitlog.py +++ b/hgext/git/gitlog.py @@ -8,6 +8,7 @@ from mercurial.node import ( nullhex, nullid, nullrev, + sha1nodeconstants, wdirhex, ) from mercurial import ( @@ -422,6 +423,8 @@ class changelog(baselog): class manifestlog(baselog): + nodeconstants = sha1nodeconstants + def __getitem__(self, node): return self.get(b'', node) diff --git a/hgext/largefiles/lfutil.py b/hgext/largefiles/lfutil.py --- a/hgext/largefiles/lfutil.py +++ b/hgext/largefiles/lfutil.py @@ -206,6 +206,7 @@ def openlfdirstate(ui, repo, create=True repo.root, repo.dirstate._validate, lambda: sparse.matcher(repo), + repo.nodeconstants, ) # If the largefiles dirstate does not exist, populate and create diff --git a/hgext/sqlitestore.py b/hgext/sqlitestore.py --- a/hgext/sqlitestore.py +++ b/hgext/sqlitestore.py @@ -54,6 +54,7 @@ from mercurial.i18n import _ from mercurial.node import ( nullid, nullrev, + sha1nodeconstants, short, ) from mercurial.thirdparty import attr @@ -305,6 +306,7 @@ class sqlitefilestore(object): """Implements storage for an individual tracked path.""" def __init__(self, db, path, compression): + self.nullid = sha1nodeconstants.nullid self._db = db self._path = path diff --git a/mercurial/bookmarks.py b/mercurial/bookmarks.py --- a/mercurial/bookmarks.py +++ b/mercurial/bookmarks.py @@ -623,7 +623,7 @@ def unhexlifybookmarks(marks): _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 @@ def binaryencode(bookmarks): return b''.join(binarydata) -def binarydecode(stream): +def binarydecode(repo, stream): """decode a binary stream into an '(bookmark, node)' iterable the binary format is: diff --git a/mercurial/branchmap.py b/mercurial/branchmap.py --- a/mercurial/branchmap.py +++ b/mercurial/branchmap.py @@ -97,7 +97,7 @@ class BranchMapCache(object): 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 @@ class BranchMapCache(object): if rbheads: rtiprev = max((int(clrev(node)) for node in rbheads)) cache = branchcache( + repo, remotebranchmap, repo[rtiprev].node(), rtiprev, @@ -184,6 +185,7 @@ class branchcache(object): def __init__( self, + repo, entries=(), tipnode=nullid, tiprev=nullrev, @@ -195,6 +197,7 @@ class branchcache(object): """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 @@ class branchcache(object): if len(cachekey) > 2: filteredhash = bin(cachekey[2]) bcache = cls( + repo, tipnode=last, tiprev=lrev, filteredhash=filteredhash, @@ -388,6 +392,7 @@ class branchcache(object): def copy(self): """return an deep copy of the branchcache object""" return type(self)( + self._repo, self._entries, self.tipnode, self.tiprev, diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py --- a/mercurial/bundle2.py +++ b/mercurial/bundle2.py @@ -2146,7 +2146,7 @@ def handlecheckbookmarks(op, inpart): 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 @@ def handlebookmark(op, inpart): 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' diff --git a/mercurial/bundlerepo.py b/mercurial/bundlerepo.py --- a/mercurial/bundlerepo.py +++ b/mercurial/bundlerepo.py @@ -175,9 +175,15 @@ class bundlechangelog(bundlerevlog, chan 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 @@ class bundlemanifest(bundlerevlog, manif 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 @@ class bundlerepository(object): # 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( diff --git a/mercurial/changegroup.py b/mercurial/changegroup.py --- a/mercurial/changegroup.py +++ b/mercurial/changegroup.py @@ -662,7 +662,7 @@ class headerlessfixup(object): 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 @@ class cgpacker(object): 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 @@ class cgpacker(object): 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 @@ class cgpacker(object): 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 diff --git a/mercurial/changelog.py b/mercurial/changelog.py --- a/mercurial/changelog.py +++ b/mercurial/changelog.py @@ -191,7 +191,7 @@ class _changelogrevision(object): # 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 @@ class changelogrevision(object): '_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 @@ class changelog(revlog.revlog): """ 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 @@ class changelog(revlog.revlog): """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): diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py --- a/mercurial/dirstate.py +++ b/mercurial/dirstate.py @@ -73,13 +73,16 @@ def _getfsnow(vfs): @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 @@ class dirstate(object): @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 @@ class dirstatemap(object): 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 @@ class dirstatemap(object): 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 diff --git a/mercurial/discovery.py b/mercurial/discovery.py --- a/mercurial/discovery.py +++ b/mercurial/discovery.py @@ -270,9 +270,12 @@ def _headssummary(pushop): # 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): diff --git a/mercurial/exchange.py b/mercurial/exchange.py --- a/mercurial/exchange.py +++ b/mercurial/exchange.py @@ -827,7 +827,7 @@ def _pushb2checkbookmarks(pushop, bundle 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 @@ def _pushb2bookmarkspart(pushop, bundler _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 @@ def _getbundlebookmarkpart( 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) diff --git a/mercurial/filelog.py b/mercurial/filelog.py --- a/mercurial/filelog.py +++ b/mercurial/filelog.py @@ -33,6 +33,7 @@ class filelog(object): # 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) diff --git a/mercurial/interfaces/dirstate.py b/mercurial/interfaces/dirstate.py --- a/mercurial/interfaces/dirstate.py +++ b/mercurial/interfaces/dirstate.py @@ -8,7 +8,7 @@ from . import util as interfaceutil 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 diff --git a/mercurial/interfaces/repository.py b/mercurial/interfaces/repository.py --- a/mercurial/interfaces/repository.py +++ b/mercurial/interfaces/repository.py @@ -523,6 +523,10 @@ class ifileindex(interfaceutil.Interface * 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 imanifestrevisionwritable(imanifes 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 @@ class imanifestlog(interfaceutil.Interfa 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 @@ class ilocalrepositorymain(interfaceutil 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. diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py --- a/mercurial/localrepo.py +++ b/mercurial/localrepo.py @@ -21,6 +21,7 @@ from .node import ( hex, nullid, nullrev, + sha1nodeconstants, short, ) from .pycompat import ( @@ -1330,6 +1331,8 @@ class localrepository(object): 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 @@ class localrepository(object): 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): diff --git a/mercurial/manifest.py b/mercurial/manifest.py --- a/mercurial/manifest.py +++ b/mercurial/manifest.py @@ -792,8 +792,9 @@ def _splittopdir(f): @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 @@ class treemanifest(object): 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 @@ class treemanifest(object): 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 @@ class treemanifest(object): 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 @@ class treemanifest(object): 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 @@ class treemanifest(object): 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 @@ class manifestrevlog(object): def __init__( self, + nodeconstants, opener, tree=b'', dirlogcache=None, @@ -1567,6 +1573,7 @@ class manifestrevlog(object): 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 @@ class manifestrevlog(object): 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 @@ class manifestlog(object): 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 @@ class manifestlog(object): 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 @@ class memtreemanifestctx(object): 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 @@ class treemanifestctx(object): 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 @@ class treemanifestctx(object): 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 @@ class treemanifestctx(object): 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 @@ class excludeddir(treemanifest): 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 excludeddir(treemanifest): 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 @@ class excludedmanifestrevlog(manifestrev outside the narrowspec. """ - def __init__(self, dir): + def __init__(self, nodeconstants, dir): + self.nodeconstants = nodeconstants self._dir = dir def __len__(self): diff --git a/mercurial/node.py b/mercurial/node.py --- a/mercurial/node.py +++ b/mercurial/node.py @@ -21,29 +21,48 @@ def bin(s): 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 diff --git a/mercurial/obsolete.py b/mercurial/obsolete.py --- a/mercurial/obsolete.py +++ b/mercurial/obsolete.py @@ -560,10 +560,11 @@ class obsstore(object): # 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 @@ def makestore(ui, repo): 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') diff --git a/mercurial/revlog.py b/mercurial/revlog.py --- a/mercurial/revlog.py +++ b/mercurial/revlog.py @@ -28,6 +28,7 @@ from .node import ( nullhex, nullid, nullrev, + sha1nodeconstants, short, wdirfilenodeids, wdirhex, @@ -651,6 +652,10 @@ class revlog(object): 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 diff --git a/mercurial/statichttprepo.py b/mercurial/statichttprepo.py --- a/mercurial/statichttprepo.py +++ b/mercurial/statichttprepo.py @@ -12,6 +12,7 @@ from __future__ import absolute_import import errno from .i18n import _ +from .node import sha1nodeconstants from . import ( branchmap, changelog, @@ -198,6 +199,8 @@ class statichttprepository( 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 @@ class statichttprepository( 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() ) diff --git a/mercurial/store.py b/mercurial/store.py --- a/mercurial/store.py +++ b/mercurial/store.py @@ -441,7 +441,7 @@ class basicstore(object): ) 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): diff --git a/mercurial/unionrepo.py b/mercurial/unionrepo.py --- a/mercurial/unionrepo.py +++ b/mercurial/unionrepo.py @@ -153,9 +153,9 @@ class unionchangelog(unionrevlog, change 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 @@ class unionrepository(object): @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() diff --git a/mercurial/upgrade_utils/engine.py b/mercurial/upgrade_utils/engine.py --- a/mercurial/upgrade_utils/engine.py +++ b/mercurial/upgrade_utils/engine.py @@ -36,7 +36,9 @@ def _revlogfrompath(repo, path): 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]) diff --git a/relnotes/next b/relnotes/next --- a/relnotes/next +++ b/relnotes/next @@ -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. diff --git a/tests/simplestorerepo.py b/tests/simplestorerepo.py --- a/tests/simplestorerepo.py +++ b/tests/simplestorerepo.py @@ -106,7 +106,9 @@ class filestorage(object): _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 @@ def reposetup(ui, repo): class simplestorerepo(repo.__class__): def file(self, f): - return filestorage(self.svfs, f) + return filestorage(repo, self.svfs, f) repo.__class__ = simplestorerepo diff --git a/tests/test-check-interfaces.py b/tests/test-check-interfaces.py --- a/tests/test-check-interfaces.py +++ b/tests/test-check-interfaces.py @@ -248,7 +248,10 @@ def main(): # 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 @@ def main(): # Conforms to imanifestdict. checkzobject(mctx.read()) - mrl = manifest.manifestrevlog(vfs) + mrl = manifest.manifestrevlog(repo.nodeconstants, vfs) checkzobject(mrl) ziverify.verifyClass(repository.irevisiondelta, revlog.revlogrevisiondelta) diff --git a/tests/test-manifest.py b/tests/test-manifest.py --- a/tests/test-manifest.py +++ b/tests/test-manifest.py @@ -6,6 +6,8 @@ import silenttestrunner import unittest import zlib +from mercurial.node import sha1nodeconstants + from mercurial import ( manifest as manifestmod, match as matchmod, @@ -436,7 +438,7 @@ class testmanifestdict(unittest.TestCase 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)