hgext/sparse.py
changeset 33297 ba5d89774db6
parent 33296 ee616196227c
child 33298 f41a99c45956
equal deleted inserted replaced
33296:ee616196227c 33297:ba5d89774db6
    90     hg,
    90     hg,
    91     localrepo,
    91     localrepo,
    92     match as matchmod,
    92     match as matchmod,
    93     merge as mergemod,
    93     merge as mergemod,
    94     registrar,
    94     registrar,
       
    95     sparse,
    95     util,
    96     util,
    96 )
    97 )
    97 
    98 
    98 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
    99 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
    99 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
   100 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
   405             return orig(self, *args)
   406             return orig(self, *args)
   406         extensions.wrapfunction(dirstate.dirstate, func, _wrapper)
   407         extensions.wrapfunction(dirstate.dirstate, func, _wrapper)
   407 
   408 
   408 def _wraprepo(ui, repo):
   409 def _wraprepo(ui, repo):
   409     class SparseRepo(repo.__class__):
   410     class SparseRepo(repo.__class__):
   410         def readsparseconfig(self, raw):
       
   411             """Takes a string sparse config and returns the includes,
       
   412             excludes, and profiles it specified.
       
   413             """
       
   414             includes = set()
       
   415             excludes = set()
       
   416             current = includes
       
   417             profiles = []
       
   418             for line in raw.split('\n'):
       
   419                 line = line.strip()
       
   420                 if not line or line.startswith('#'):
       
   421                     # empty or comment line, skip
       
   422                     continue
       
   423                 elif line.startswith('%include '):
       
   424                     line = line[9:].strip()
       
   425                     if line:
       
   426                         profiles.append(line)
       
   427                 elif line == '[include]':
       
   428                     if current != includes:
       
   429                         raise error.Abort(_('.hg/sparse cannot have includes ' +
       
   430                             'after excludes'))
       
   431                     continue
       
   432                 elif line == '[exclude]':
       
   433                     current = excludes
       
   434                 elif line:
       
   435                     if line.strip().startswith('/'):
       
   436                         self.ui.warn(_('warning: sparse profile cannot use' +
       
   437                                        ' paths starting with /, ignoring %s\n')
       
   438                                        % line)
       
   439                         continue
       
   440                     current.add(line)
       
   441 
       
   442             return includes, excludes, profiles
       
   443 
       
   444         def getsparsepatterns(self, rev):
   411         def getsparsepatterns(self, rev):
   445             """Returns the include/exclude patterns specified by the
   412             """Returns the include/exclude patterns specified by the
   446             given rev.
   413             given rev.
   447             """
   414             """
   448             raw = self.vfs.tryread('sparse')
   415             raw = self.vfs.tryread('sparse')
   450                 return set(), set(), []
   417                 return set(), set(), []
   451             if rev is None:
   418             if rev is None:
   452                 raise error.Abort(_("cannot parse sparse patterns from " +
   419                 raise error.Abort(_("cannot parse sparse patterns from " +
   453                     "working copy"))
   420                     "working copy"))
   454 
   421 
   455             includes, excludes, profiles = self.readsparseconfig(raw)
   422             includes, excludes, profiles = sparse.parseconfig(self.ui, raw)
   456 
   423 
   457             ctx = self[rev]
   424             ctx = self[rev]
   458             if profiles:
   425             if profiles:
   459                 visited = set()
   426                 visited = set()
   460                 while profiles:
   427                 while profiles:
   473                                 'sparse', 'missingwarning', True):
   440                                 'sparse', 'missingwarning', True):
   474                             self.ui.warn(msg)
   441                             self.ui.warn(msg)
   475                         else:
   442                         else:
   476                             self.ui.debug(msg)
   443                             self.ui.debug(msg)
   477                         continue
   444                         continue
   478                     pincludes, pexcludes, subprofs = \
   445                     pincludes, pexcludes, subprofs = sparse.parseconfig(
   479                         self.readsparseconfig(raw)
   446                         self.ui, raw)
   480                     includes.update(pincludes)
   447                     includes.update(pincludes)
   481                     excludes.update(pexcludes)
   448                     excludes.update(pexcludes)
   482                     for subprofile in subprofs:
   449                     for subprofile in subprofs:
   483                         profiles.append(subprofile)
   450                         profiles.append(subprofile)
   484 
   451 
   785         oldsparsematch = repo.sparsematch()
   752         oldsparsematch = repo.sparsematch()
   786 
   753 
   787         raw = repo.vfs.tryread('sparse')
   754         raw = repo.vfs.tryread('sparse')
   788         if raw:
   755         if raw:
   789             oldinclude, oldexclude, oldprofiles = map(
   756             oldinclude, oldexclude, oldprofiles = map(
   790                 set, repo.readsparseconfig(raw))
   757                 set, sparse.parseconfig(ui, raw))
   791         else:
   758         else:
   792             oldinclude = set()
   759             oldinclude = set()
   793             oldexclude = set()
   760             oldexclude = set()
   794             oldprofiles = set()
   761             oldprofiles = set()
   795 
   762 
   844         revs = [repo.changelog.rev(node) for node in
   811         revs = [repo.changelog.rev(node) for node in
   845                 repo.dirstate.parents() if node != nullid]
   812                 repo.dirstate.parents() if node != nullid]
   846 
   813 
   847         # read current configuration
   814         # read current configuration
   848         raw = repo.vfs.tryread('sparse')
   815         raw = repo.vfs.tryread('sparse')
   849         oincludes, oexcludes, oprofiles = repo.readsparseconfig(raw)
   816         oincludes, oexcludes, oprofiles = sparse.parseconfig(ui, raw)
   850         includes, excludes, profiles = map(
   817         includes, excludes, profiles = map(
   851                 set, (oincludes, oexcludes, oprofiles))
   818                 set, (oincludes, oexcludes, oprofiles))
   852 
   819 
   853         # all active rules
   820         # all active rules
   854         aincludes, aexcludes, aprofiles = set(), set(), set()
   821         aincludes, aexcludes, aprofiles = set(), set(), set()
   861         # import rules on top; only take in rules that are not yet
   828         # import rules on top; only take in rules that are not yet
   862         # part of the active rules.
   829         # part of the active rules.
   863         changed = False
   830         changed = False
   864         for file in files:
   831         for file in files:
   865             with util.posixfile(util.expandpath(file)) as importfile:
   832             with util.posixfile(util.expandpath(file)) as importfile:
   866                 iincludes, iexcludes, iprofiles = repo.readsparseconfig(
   833                 iincludes, iexcludes, iprofiles = sparse.parseconfig(
   867                     importfile.read())
   834                     ui, importfile.read())
   868                 oldsize = len(includes) + len(excludes) + len(profiles)
   835                 oldsize = len(includes) + len(excludes) + len(profiles)
   869                 includes.update(iincludes - aincludes)
   836                 includes.update(iincludes - aincludes)
   870                 excludes.update(iexcludes - aexcludes)
   837                 excludes.update(iexcludes - aexcludes)
   871                 profiles.update(set(iprofiles) - aprofiles)
   838                 profiles.update(set(iprofiles) - aprofiles)
   872                 if len(includes) + len(excludes) + len(profiles) > oldsize:
   839                 if len(includes) + len(excludes) + len(profiles) > oldsize:
   895                         *fcounts)
   862                         *fcounts)
   896 
   863 
   897 def _clear(ui, repo, files, force=False):
   864 def _clear(ui, repo, files, force=False):
   898     with repo.wlock():
   865     with repo.wlock():
   899         raw = repo.vfs.tryread('sparse')
   866         raw = repo.vfs.tryread('sparse')
   900         includes, excludes, profiles = repo.readsparseconfig(raw)
   867         includes, excludes, profiles = sparse.parseconfig(ui, raw)
   901 
   868 
   902         if includes or excludes:
   869         if includes or excludes:
   903             oldstatus = repo.status()
   870             oldstatus = repo.status()
   904             oldsparsematch = repo.sparsematch()
   871             oldsparsematch = repo.sparsematch()
   905             repo.writesparseconfig(set(), set(), profiles)
   872             repo.writesparseconfig(set(), set(), profiles)