hgext/narrow/narrowdirstate.py
changeset 36079 a2a6e724d61a
child 36160 9fd8c2a3db5a
equal deleted inserted replaced
36078:7f68235f23ff 36079:a2a6e724d61a
       
     1 # narrowdirstate.py - extensions to mercurial dirstate to support narrow clones
       
     2 #
       
     3 # Copyright 2017 Google, Inc.
       
     4 #
       
     5 # This software may be used and distributed according to the terms of the
       
     6 # GNU General Public License version 2 or any later version.
       
     7 
       
     8 from __future__ import absolute_import
       
     9 
       
    10 from mercurial.i18n import _
       
    11 from mercurial import (
       
    12     dirstate,
       
    13     error,
       
    14     extensions,
       
    15     match as matchmod,
       
    16     util as hgutil,
       
    17 )
       
    18 
       
    19 from . import narrowspec
       
    20 
       
    21 def setup(repo):
       
    22     """Add narrow spec dirstate ignore, block changes outside narrow spec."""
       
    23 
       
    24     def walk(orig, self, match, subrepos, unknown, ignored, full=True,
       
    25              narrowonly=True):
       
    26         if narrowonly:
       
    27             narrowmatch = repo.narrowmatch()
       
    28             match = matchmod.intersectmatchers(match, narrowmatch)
       
    29         return orig(self, match, subrepos, unknown, ignored, full)
       
    30 
       
    31     extensions.wrapfunction(dirstate.dirstate, 'walk', walk)
       
    32 
       
    33     # Prevent adding files that are outside the sparse checkout
       
    34     editfuncs = ['normal', 'add', 'normallookup', 'copy', 'remove', 'merge']
       
    35     for func in editfuncs:
       
    36         def _wrapper(orig, self, *args):
       
    37             dirstate = repo.dirstate
       
    38             narrowmatch = repo.narrowmatch()
       
    39             for f in args:
       
    40                 if f is not None and not narrowmatch(f) and f not in dirstate:
       
    41                     raise error.Abort(_("cannot track '%s' - it is outside " +
       
    42                         "the narrow clone") % f)
       
    43             return orig(self, *args)
       
    44         extensions.wrapfunction(dirstate.dirstate, func, _wrapper)
       
    45 
       
    46     def filterrebuild(orig, self, parent, allfiles, changedfiles=None):
       
    47         if changedfiles is None:
       
    48             # Rebuilding entire dirstate, let's filter allfiles to match the
       
    49             # narrowspec.
       
    50             allfiles = [f for f in allfiles if repo.narrowmatch()(f)]
       
    51         orig(self, parent, allfiles, changedfiles)
       
    52 
       
    53     extensions.wrapfunction(dirstate.dirstate, 'rebuild', filterrebuild)
       
    54 
       
    55     def _narrowbackupname(backupname):
       
    56         assert 'dirstate' in backupname
       
    57         return backupname.replace('dirstate', narrowspec.FILENAME)
       
    58 
       
    59     def restorebackup(orig, self, tr, backupname):
       
    60         self._opener.rename(_narrowbackupname(backupname), narrowspec.FILENAME,
       
    61                             checkambig=True)
       
    62         orig(self, tr, backupname)
       
    63 
       
    64     extensions.wrapfunction(dirstate.dirstate, 'restorebackup', restorebackup)
       
    65 
       
    66     def savebackup(orig, self, tr, backupname):
       
    67         orig(self, tr, backupname)
       
    68 
       
    69         narrowbackupname = _narrowbackupname(backupname)
       
    70         self._opener.tryunlink(narrowbackupname)
       
    71         hgutil.copyfile(self._opener.join(narrowspec.FILENAME),
       
    72                         self._opener.join(narrowbackupname), hardlink=True)
       
    73 
       
    74     extensions.wrapfunction(dirstate.dirstate, 'savebackup', savebackup)
       
    75 
       
    76     def clearbackup(orig, self, tr, backupname):
       
    77         orig(self, tr, backupname)
       
    78         self._opener.unlink(_narrowbackupname(backupname))
       
    79 
       
    80     extensions.wrapfunction(dirstate.dirstate, 'clearbackup', clearbackup)