mercurial/sparse.py
changeset 33320 153456f02426
parent 33318 526255fe7899
child 33321 d09e948dc303
equal deleted inserted replaced
33319:3c84591e7321 33320:153456f02426
     6 # GNU General Public License version 2 or any later version.
     6 # GNU General Public License version 2 or any later version.
     7 
     7 
     8 from __future__ import absolute_import
     8 from __future__ import absolute_import
     9 
     9 
    10 import hashlib
    10 import hashlib
       
    11 import os
    11 
    12 
    12 from .i18n import _
    13 from .i18n import _
    13 from .node import nullid
    14 from .node import nullid
    14 from . import (
    15 from . import (
    15     error,
    16     error,
       
    17     match as matchmod,
       
    18     pycompat,
    16 )
    19 )
    17 
    20 
    18 # Whether sparse features are enabled. This variable is intended to be
    21 # Whether sparse features are enabled. This variable is intended to be
    19 # temporary to facilitate porting sparse to core. It should eventually be
    22 # temporary to facilitate porting sparse to core. It should eventually be
    20 # a per-repo option, possibly a repo requirement.
    23 # a per-repo option, possibly a repo requirement.
   191 def addtemporaryincludes(repo, additional):
   194 def addtemporaryincludes(repo, additional):
   192     includes = readtemporaryincludes(repo)
   195     includes = readtemporaryincludes(repo)
   193     for i in additional:
   196     for i in additional:
   194         includes.add(i)
   197         includes.add(i)
   195     writetemporaryincludes(repo, includes)
   198     writetemporaryincludes(repo, includes)
       
   199 
       
   200 def matcher(repo, revs=None, includetemp=True):
       
   201     """Obtain a matcher for sparse working directories for the given revs.
       
   202 
       
   203     If multiple revisions are specified, the matcher is the union of all
       
   204     revs.
       
   205 
       
   206     ``includetemp`` indicates whether to use the temporary sparse profile.
       
   207     """
       
   208     # If sparse isn't enabled, sparse matcher matches everything.
       
   209     if not enabled:
       
   210         return matchmod.always(repo.root, '')
       
   211 
       
   212     if not revs or revs == [None]:
       
   213         revs = [repo.changelog.rev(node)
       
   214                 for node in repo.dirstate.parents() if node != nullid]
       
   215 
       
   216     signature = configsignature(repo, includetemp=includetemp)
       
   217 
       
   218     key = '%s %s' % (signature, ' '.join(map(pycompat.bytestr, revs)))
       
   219 
       
   220     result = repo._sparsematchercache.get(key)
       
   221     if result:
       
   222         return result
       
   223 
       
   224     matchers = []
       
   225     for rev in revs:
       
   226         try:
       
   227             includes, excludes, profiles = patternsforrev(repo, rev)
       
   228 
       
   229             if includes or excludes:
       
   230                 # Explicitly include subdirectories of includes so
       
   231                 # status will walk them down to the actual include.
       
   232                 subdirs = set()
       
   233                 for include in includes:
       
   234                     # TODO consider using posix path functions here so Windows
       
   235                     # \ directory separators don't come into play.
       
   236                     dirname = os.path.dirname(include)
       
   237                     # basename is used to avoid issues with absolute
       
   238                     # paths (which on Windows can include the drive).
       
   239                     while os.path.basename(dirname):
       
   240                         subdirs.add(dirname)
       
   241                         dirname = os.path.dirname(dirname)
       
   242 
       
   243                 matcher = matchmod.match(repo.root, '', [],
       
   244                                          include=includes, exclude=excludes,
       
   245                                          default='relpath')
       
   246                 if subdirs:
       
   247                     matcher = matchmod.forceincludematcher(matcher, subdirs)
       
   248                 matchers.append(matcher)
       
   249         except IOError:
       
   250             pass
       
   251 
       
   252     if not matchers:
       
   253         result = matchmod.always(repo.root, '')
       
   254     elif len(matchers) == 1:
       
   255         result = matchers[0]
       
   256     else:
       
   257         result = matchmod.unionmatcher(matchers)
       
   258 
       
   259     if includetemp:
       
   260         tempincludes = readtemporaryincludes(repo)
       
   261         result = matchmod.forceincludematcher(result, tempincludes)
       
   262 
       
   263     repo._sparsematchercache[key] = result
       
   264 
       
   265     return result