hgext/sparse.py
branchstable
changeset 49366 288de6f5d724
parent 49360 bd3519dc6741
child 49862 b1147450c55c
equal deleted inserted replaced
49364:e8ea403b1c46 49366:288de6f5d724
    69 
    69 
    70   [exclude]
    70   [exclude]
    71   tools/tests/**
    71   tools/tests/**
    72 """
    72 """
    73 
    73 
    74 from __future__ import absolute_import
       
    75 
    74 
    76 from mercurial.i18n import _
    75 from mercurial.i18n import _
    77 from mercurial.pycompat import setattr
    76 from mercurial.pycompat import setattr
    78 from mercurial import (
    77 from mercurial import (
    79     cmdutil,
    78     cmdutil,
    80     commands,
    79     commands,
    81     dirstate,
       
    82     error,
    80     error,
    83     extensions,
    81     extensions,
    84     logcmdutil,
    82     logcmdutil,
    85     match as matchmod,
       
    86     merge as mergemod,
    83     merge as mergemod,
    87     pycompat,
    84     pycompat,
    88     registrar,
    85     registrar,
    89     sparse,
    86     sparse,
    90     util,
    87     util,
   104     sparse.enabled = True
   101     sparse.enabled = True
   105 
   102 
   106     _setupclone(ui)
   103     _setupclone(ui)
   107     _setuplog(ui)
   104     _setuplog(ui)
   108     _setupadd(ui)
   105     _setupadd(ui)
   109     _setupdirstate(ui)
       
   110 
   106 
   111 
   107 
   112 def replacefilecache(cls, propname, replacement):
   108 def replacefilecache(cls, propname, replacement):
   113     """Replace a filecache property with a new class. This allows changing the
   109     """Replace a filecache property with a new class. This allows changing the
   114     cache invalidation condition."""
   110     cache invalidation condition."""
   205                 dirs.add(dirname)
   201                 dirs.add(dirname)
   206             sparse.updateconfig(repo, opts, include=list(dirs))
   202             sparse.updateconfig(repo, opts, include=list(dirs))
   207         return orig(ui, repo, *pats, **opts)
   203         return orig(ui, repo, *pats, **opts)
   208 
   204 
   209     extensions.wrapcommand(commands.table, b'add', _add)
   205     extensions.wrapcommand(commands.table, b'add', _add)
   210 
       
   211 
       
   212 def _setupdirstate(ui):
       
   213     """Modify the dirstate to prevent stat'ing excluded files,
       
   214     and to prevent modifications to files outside the checkout.
       
   215     """
       
   216 
       
   217     def walk(orig, self, match, subrepos, unknown, ignored, full=True):
       
   218         # hack to not exclude explicitly-specified paths so that they can
       
   219         # be warned later on e.g. dirstate.add()
       
   220         em = matchmod.exact(match.files())
       
   221         sm = matchmod.unionmatcher([self._sparsematcher, em])
       
   222         match = matchmod.intersectmatchers(match, sm)
       
   223         return orig(self, match, subrepos, unknown, ignored, full)
       
   224 
       
   225     extensions.wrapfunction(dirstate.dirstate, b'walk', walk)
       
   226 
       
   227     # dirstate.rebuild should not add non-matching files
       
   228     def _rebuild(orig, self, parent, allfiles, changedfiles=None):
       
   229         matcher = self._sparsematcher
       
   230         if not matcher.always():
       
   231             allfiles = [f for f in allfiles if matcher(f)]
       
   232             if changedfiles:
       
   233                 changedfiles = [f for f in changedfiles if matcher(f)]
       
   234 
       
   235             if changedfiles is not None:
       
   236                 # In _rebuild, these files will be deleted from the dirstate
       
   237                 # when they are not found to be in allfiles
       
   238                 dirstatefilestoremove = {f for f in self if not matcher(f)}
       
   239                 changedfiles = dirstatefilestoremove.union(changedfiles)
       
   240 
       
   241         return orig(self, parent, allfiles, changedfiles)
       
   242 
       
   243     extensions.wrapfunction(dirstate.dirstate, b'rebuild', _rebuild)
       
   244 
       
   245     # Prevent adding files that are outside the sparse checkout
       
   246     editfuncs = [
       
   247         b'set_tracked',
       
   248         b'set_untracked',
       
   249         b'copy',
       
   250     ]
       
   251     hint = _(
       
   252         b'include file with `hg debugsparse --include <pattern>` or use '
       
   253         + b'`hg add -s <file>` to include file directory while adding'
       
   254     )
       
   255     for func in editfuncs:
       
   256 
       
   257         def _wrapper(orig, self, *args, **kwargs):
       
   258             sparsematch = self._sparsematcher
       
   259             if not sparsematch.always():
       
   260                 for f in args:
       
   261                     if f is not None and not sparsematch(f) and f not in self:
       
   262                         raise error.Abort(
       
   263                             _(
       
   264                                 b"cannot add '%s' - it is outside "
       
   265                                 b"the sparse checkout"
       
   266                             )
       
   267                             % f,
       
   268                             hint=hint,
       
   269                         )
       
   270             return orig(self, *args, **kwargs)
       
   271 
       
   272         extensions.wrapfunction(dirstate.dirstate, func, _wrapper)
       
   273 
   206 
   274 
   207 
   275 @command(
   208 @command(
   276     b'debugsparse',
   209     b'debugsparse',
   277     [
   210     [
   396     )
   329     )
   397     count = sum([updateconfig, bool(action)])
   330     count = sum([updateconfig, bool(action)])
   398     if count > 1:
   331     if count > 1:
   399         raise error.Abort(_(b"too many flags specified"))
   332         raise error.Abort(_(b"too many flags specified"))
   400 
   333 
       
   334     # enable sparse on repo even if the requirements is missing.
       
   335     repo._has_sparse = True
       
   336 
   401     if count == 0:
   337     if count == 0:
   402         if repo.vfs.exists(b'sparse'):
   338         if repo.vfs.exists(b'sparse'):
   403             ui.status(repo.vfs.read(b"sparse") + b"\n")
   339             ui.status(repo.vfs.read(b"sparse") + b"\n")
   404             temporaryincludes = sparse.readtemporaryincludes(repo)
   340             temporaryincludes = sparse.readtemporaryincludes(repo)
   405             if temporaryincludes:
   341             if temporaryincludes:
   451                 dropped=fcounts[1],
   387                 dropped=fcounts[1],
   452                 conflicting=fcounts[2],
   388                 conflicting=fcounts[2],
   453             )
   389             )
   454         finally:
   390         finally:
   455             wlock.release()
   391             wlock.release()
       
   392 
       
   393     del repo._has_sparse