Mercurial > hg-stable
view hgext/narrow/narrowrevlog.py @ 36121:9772ef9f6c04
narrow: assume addflagprocessor will always exist on revlog module
Differential Revision: https://phab.mercurial-scm.org/D1978
author | Augie Fackler <augie@google.com> |
---|---|
date | Mon, 29 Jan 2018 18:16:23 -0500 |
parents | adc8e1fe2f46 |
children | 9445a3141501 |
line wrap: on
line source
# narrowrevlog.py - revlog storing irrelevant nodes as "ellipsis" nodes # # Copyright 2017 Google, Inc. # # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. from __future__ import absolute_import from mercurial import ( manifest, revlog, util, ) ELLIPSIS_NODE_FLAG = 1 << 14 revlog.REVIDX_KNOWN_FLAGS |= ELLIPSIS_NODE_FLAG if ELLIPSIS_NODE_FLAG not in revlog.REVIDX_FLAGS_ORDER: revlog.REVIDX_FLAGS_ORDER.append(ELLIPSIS_NODE_FLAG) def readtransform(self, text): return text, False def writetransform(self, text): return text, False def rawtransform(self, text): return False revlog.addflagprocessor(ELLIPSIS_NODE_FLAG, (readtransform, writetransform, rawtransform)) def setup(): # We just wanted to add the flag processor, which is done at module # load time. pass class excludeddir(manifest.treemanifest): def __init__(self, dir, node): super(excludeddir, self).__init__(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/") self._files[''] = node self._flags[''] = 't' # Manifests outside the narrowspec should never be modified, so avoid # copying. This makes a noticeable difference when there are very many # directories outside the narrowspec. Also, it makes sense for the copy to # be of the same type as the original, which would not happen with the # super type's copy(). def copy(self): return self class excludeddirmanifestctx(manifest.treemanifestctx): def __init__(self, dir, node): self._dir = dir self._node = node def read(self): return excludeddir(self._dir, self._node) def write(self, *args): raise AssertionError('Attempt to write manifest from excluded dir %s' % self._dir) class excludedmanifestrevlog(manifest.manifestrevlog): def __init__(self, dir): self._dir = dir def __len__(self): raise AssertionError('Attempt to get length of excluded dir %s' % self._dir) def rev(self, node): raise AssertionError('Attempt to get rev from excluded dir %s' % self._dir) def linkrev(self, node): raise AssertionError('Attempt to get linkrev from excluded dir %s' % self._dir) def node(self, rev): raise AssertionError('Attempt to get node from excluded dir %s' % self._dir) def add(self, *args, **kwargs): # We should never write entries in dirlogs outside the narrow clone. # However, the method still gets called from writesubtree() in # _addtree(), so we need to handle it. We should possibly make that # avoid calling add() with a clean manifest (_dirty is always False # in excludeddir instances). pass def makenarrowmanifestrevlog(mfrevlog, repo): if util.safehasattr(mfrevlog, '_narrowed'): return class narrowmanifestrevlog(mfrevlog.__class__): # This function is called via debug{revlog,index,data}, but also during # at least some push operations. This will be used to wrap/exclude the # child directories when using treemanifests. def dirlog(self, dir): if dir and not dir.endswith('/'): dir = dir + '/' if not repo.narrowmatch().visitdir(dir[:-1] or '.'): return excludedmanifestrevlog(dir) result = super(narrowmanifestrevlog, self).dirlog(dir) makenarrowmanifestrevlog(result, repo) return result mfrevlog.__class__ = narrowmanifestrevlog mfrevlog._narrowed = True def makenarrowmanifestlog(mfl, repo): class narrowmanifestlog(mfl.__class__): def get(self, dir, node, verify=True): if not repo.narrowmatch().visitdir(dir[:-1] or '.'): return excludeddirmanifestctx(dir, node) return super(narrowmanifestlog, self).get(dir, node, verify=verify) mfl.__class__ = narrowmanifestlog def makenarrowfilelog(fl, narrowmatch): class narrowfilelog(fl.__class__): def renamed(self, node): m = super(narrowfilelog, self).renamed(node) if m and not narrowmatch(m[0]): return None return m def size(self, rev): # We take advantage of the fact that remotefilelog # lacks a node() method to just skip the # rename-checking logic when on remotefilelog. This # might be incorrect on other non-revlog-based storage # engines, but for now this seems to be fine. if util.safehasattr(self, 'node'): node = self.node(rev) # Because renamed() is overridden above to # sometimes return None even if there is metadata # in the revlog, size can be incorrect for # copies/renames, so we need to make sure we call # the super class's implementation of renamed() # for the purpose of size calculation. if super(narrowfilelog, self).renamed(node): return len(self.read(node)) return super(narrowfilelog, self).size(rev) def cmp(self, node, text): different = super(narrowfilelog, self).cmp(node, text) if different: # Similar to size() above, if the file was copied from # a file outside the narrowspec, the super class's # would have returned True because we tricked it into # thinking that the file was not renamed. if super(narrowfilelog, self).renamed(node): t2 = self.read(node) return t2 != text return different fl.__class__ = narrowfilelog