diff -r b7e5c53a779e -r 1cba497491be hgext/narrow/narrowdirstate.py --- a/hgext/narrow/narrowdirstate.py Tue May 22 00:25:18 2018 +0530 +++ b/hgext/narrow/narrowdirstate.py Wed May 16 14:59:32 2018 -0700 @@ -9,74 +9,91 @@ from mercurial.i18n import _ from mercurial import ( - dirstate, error, - extensions, match as matchmod, narrowspec, util as hgutil, ) -def setup(repo): +def wrapdirstate(repo, dirstate): """Add narrow spec dirstate ignore, block changes outside narrow spec.""" - def walk(orig, self, match, subrepos, unknown, ignored, full=True, - narrowonly=True): - if narrowonly: - # hack to not exclude explicitly-specified paths so that they can - # be warned later on e.g. dirstate.add() - em = matchmod.exact(match._root, match._cwd, match.files()) - nm = matchmod.unionmatcher([repo.narrowmatch(), em]) - match = matchmod.intersectmatchers(match, nm) - return orig(self, match, subrepos, unknown, ignored, full) - - extensions.wrapfunction(dirstate.dirstate, 'walk', walk) - - # Prevent adding files that are outside the sparse checkout - editfuncs = ['normal', 'add', 'normallookup', 'copy', 'remove', 'merge'] - for func in editfuncs: - def _wrapper(orig, self, *args): + def _editfunc(fn): + def _wrapper(self, *args): dirstate = repo.dirstate narrowmatch = repo.narrowmatch() for f in args: if f is not None and not narrowmatch(f) and f not in dirstate: raise error.Abort(_("cannot track '%s' - it is outside " + "the narrow clone") % f) - return orig(self, *args) - extensions.wrapfunction(dirstate.dirstate, func, _wrapper) - - def filterrebuild(orig, self, parent, allfiles, changedfiles=None): - if changedfiles is None: - # Rebuilding entire dirstate, let's filter allfiles to match the - # narrowspec. - allfiles = [f for f in allfiles if repo.narrowmatch()(f)] - orig(self, parent, allfiles, changedfiles) - - extensions.wrapfunction(dirstate.dirstate, 'rebuild', filterrebuild) + return fn(self, *args) + return _wrapper def _narrowbackupname(backupname): assert 'dirstate' in backupname return backupname.replace('dirstate', narrowspec.FILENAME) - def restorebackup(orig, self, tr, backupname): - self._opener.rename(_narrowbackupname(backupname), narrowspec.FILENAME, - checkambig=True) - orig(self, tr, backupname) + class narrowdirstate(dirstate.__class__): + def walk(self, match, subrepos, unknown, ignored, full=True, + narrowonly=True): + if narrowonly: + # hack to not exclude explicitly-specified paths so that they + # can be warned later on e.g. dirstate.add() + em = matchmod.exact(match._root, match._cwd, match.files()) + nm = matchmod.unionmatcher([repo.narrowmatch(), em]) + match = matchmod.intersectmatchers(match, nm) + return super(narrowdirstate, self).walk(match, subrepos, unknown, + ignored, full) - extensions.wrapfunction(dirstate.dirstate, 'restorebackup', restorebackup) + # Prevent adding/editing/copying/deleting files that are outside the + # sparse checkout + @_editfunc + def normal(self, *args): + return super(narrowdirstate, self).normal(*args) - def savebackup(orig, self, tr, backupname): - orig(self, tr, backupname) + @_editfunc + def add(self, *args): + return super(narrowdirstate, self).add(*args) + + @_editfunc + def normallookup(self, *args): + return super(narrowdirstate, self).normallookup(*args) + + @_editfunc + def copy(self, *args): + return super(narrowdirstate, self).copy(*args) - narrowbackupname = _narrowbackupname(backupname) - self._opener.tryunlink(narrowbackupname) - hgutil.copyfile(self._opener.join(narrowspec.FILENAME), - self._opener.join(narrowbackupname), hardlink=True) + @_editfunc + def remove(self, *args): + return super(narrowdirstate, self).remove(*args) + + @_editfunc + def merge(self, *args): + return super(narrowdirstate, self).merge(*args) + + def rebuild(self, parent, allfiles, changedfiles=None): + if changedfiles is None: + # Rebuilding entire dirstate, let's filter allfiles to match the + # narrowspec. + allfiles = [f for f in allfiles if repo.narrowmatch()(f)] + super(narrowdirstate, self).rebuild(parent, allfiles, changedfiles) - extensions.wrapfunction(dirstate.dirstate, 'savebackup', savebackup) + def restorebackup(self, tr, backupname): + self._opener.rename(_narrowbackupname(backupname), + narrowspec.FILENAME, checkambig=True) + super(narrowdirstate, self).restorebackup(tr, backupname) + + def savebackup(self, tr, backupname): + super(narrowdirstate, self).savebackup(tr, backupname) - def clearbackup(orig, self, tr, backupname): - orig(self, tr, backupname) - self._opener.unlink(_narrowbackupname(backupname)) + narrowbackupname = _narrowbackupname(backupname) + self._opener.tryunlink(narrowbackupname) + hgutil.copyfile(self._opener.join(narrowspec.FILENAME), + self._opener.join(narrowbackupname), hardlink=True) - extensions.wrapfunction(dirstate.dirstate, 'clearbackup', clearbackup) + def clearbackup(self, tr, backupname): + super(narrowdirstate, self).clearbackup(tr, backupname) + self._opener.unlink(_narrowbackupname(backupname)) + + dirstate.__class__ = narrowdirstate + return dirstate