hgkw/keyword.py
branchstable
changeset 810 0ae62443e644
parent 809 028b6584decb
child 811 31205612c018
equal deleted inserted replaced
805:b86b51448177 810:0ae62443e644
    90 
    90 
    91 commands.optionalrepo += ' kwdemo'
    91 commands.optionalrepo += ' kwdemo'
    92 
    92 
    93 # hg commands that do not act on keywords
    93 # hg commands that do not act on keywords
    94 nokwcommands = ('add addremove annotate bundle copy export grep incoming init'
    94 nokwcommands = ('add addremove annotate bundle copy export grep incoming init'
    95                 ' log outgoing push rename rollback tip verify'
    95                 ' log outgoing push rename tip verify convert email glog')
    96                 ' convert email glog')
       
    97 
    96 
    98 # hg commands that trigger expansion only when writing to working dir,
    97 # hg commands that trigger expansion only when writing to working dir,
    99 # not when reading filelog, and unexpand when reading from working dir
    98 # not when reading filelog, and unexpand when reading from working dir
   100 restricted = 'merge record qrecord resolve transplant'
    99 restricted = 'merge record qrecord resolve transplant'
   101 
   100 
   190         '''Returns true if path matches [keyword] pattern
   189         '''Returns true if path matches [keyword] pattern
   191         and is not a symbolic link.
   190         and is not a symbolic link.
   192         Caveat: localrepository._link fails on Windows.'''
   191         Caveat: localrepository._link fails on Windows.'''
   193         return self.match(path) and not 'l' in flagfunc(path)
   192         return self.match(path) and not 'l' in flagfunc(path)
   194 
   193 
   195     def overwrite(self, ctx, candidates, iswctx, expand):
   194     def overwrite(self, ctx, candidates, iswctx, expand, cfiles):
   196         '''Overwrites selected files expanding/shrinking keywords.'''
   195         '''Overwrites selected files expanding/shrinking keywords.'''
   197         if self.record:
   196         if cfiles is not None:
   198             candidates = [f for f in ctx.files() if f in ctx]
   197             candidates = [f for f in candidates if f in cfiles]
   199         candidates = [f for f in candidates if self.iskwfile(f, ctx.flags)]
   198         candidates = [f for f in candidates if self.iskwfile(f, ctx.flags)]
   200         if candidates:
   199         if candidates:
       
   200             restrict = self.restrict
   201             self.restrict = True        # do not expand when reading
   201             self.restrict = True        # do not expand when reading
       
   202             rollback = kwtools['hgcmd'] == 'rollback'
   202             mf = ctx.manifest()
   203             mf = ctx.manifest()
   203             msg = (expand and _('overwriting %s expanding keywords\n')
   204             msg = (expand and _('overwriting %s expanding keywords\n')
   204                    or _('overwriting %s shrinking keywords\n'))
   205                    or _('overwriting %s shrinking keywords\n'))
   205             for f in candidates:
   206             for f in candidates:
   206                 if not self.record:
   207                 if not self.record and not rollback:
   207                     data = self.repo.file(f).read(mf[f])
   208                     data = self.repo.file(f).read(mf[f])
   208                 else:
   209                 else:
   209                     data = self.repo.wread(f)
   210                     data = self.repo.wread(f)
   210                 if util.binary(data):
   211                 if util.binary(data):
   211                     continue
   212                     continue
   217                 else:
   218                 else:
   218                     found = self.re_kw.search(data)
   219                     found = self.re_kw.search(data)
   219                 if found:
   220                 if found:
   220                     self.ui.note(msg % f)
   221                     self.ui.note(msg % f)
   221                     self.repo.wwrite(f, data, mf.flags(f))
   222                     self.repo.wwrite(f, data, mf.flags(f))
   222                     if iswctx:
   223                     if iswctx and not rollback:
   223                         self.repo.dirstate.normal(f)
   224                         self.repo.dirstate.normal(f)
   224                     elif self.record:
   225                     elif self.record:
   225                         self.repo.dirstate.normallookup(f)
   226                         self.repo.dirstate.normallookup(f)
   226             self.restrict = False
   227             self.restrict = restrict
   227 
   228 
   228     def shrinktext(self, text):
   229     def shrinktext(self, text):
   229         '''Unconditionally removes all keyword substitutions from text.'''
   230         '''Unconditionally removes all keyword substitutions from text.'''
   230         return self.re_kw.sub(r'$\1$', text)
   231         return self.re_kw.sub(r'$\1$', text)
   231 
   232 
   296     try:
   297     try:
   297         status = _status(ui, repo, kwt, *pats, **opts)
   298         status = _status(ui, repo, kwt, *pats, **opts)
   298         modified, added, removed, deleted, unknown, ignored, clean = status
   299         modified, added, removed, deleted, unknown, ignored, clean = status
   299         if modified or added or removed or deleted:
   300         if modified or added or removed or deleted:
   300             raise util.Abort(_('outstanding uncommitted changes'))
   301             raise util.Abort(_('outstanding uncommitted changes'))
   301         kwt.overwrite(wctx, clean, True, expand)
   302         kwt.overwrite(wctx, clean, True, expand, None)
   302     finally:
   303     finally:
   303         wlock.release()
   304         wlock.release()
   304 
   305 
   305 def demo(ui, repo, *args, **opts):
   306 def demo(ui, repo, *args, **opts):
   306     '''print [keywordmaps] configuration and an expansion example
   307     '''print [keywordmaps] configuration and an expansion example
   500         def kwcommitctx(self, ctx, error=False):
   501         def kwcommitctx(self, ctx, error=False):
   501             n = super(kwrepo, self).commitctx(ctx, error)
   502             n = super(kwrepo, self).commitctx(ctx, error)
   502             # no lock needed, only called from repo.commit() which already locks
   503             # no lock needed, only called from repo.commit() which already locks
   503             if not kwt.record:
   504             if not kwt.record:
   504                 kwt.overwrite(self[n], sorted(ctx.added() + ctx.modified()),
   505                 kwt.overwrite(self[n], sorted(ctx.added() + ctx.modified()),
   505                               False, True)
   506                               False, True, None)
   506             return n
   507             return n
       
   508 
       
   509         def rollback(self, dryrun=False):
       
   510             wlock = repo.wlock()
       
   511             try:
       
   512                 if not dryrun:
       
   513                     cfiles = self['.'].files()
       
   514                 ret = super(kwrepo, self).rollback(dryrun)
       
   515                 if not dryrun:
       
   516                     ctx = self['.']
       
   517                     modified, added = super(kwrepo, self).status()[:2]
       
   518                     kwt.overwrite(ctx, added, True, False, cfiles)
       
   519                     kwt.overwrite(ctx, modified, True, True, cfiles)
       
   520                 return ret
       
   521             finally:
       
   522                 wlock.release()
   507 
   523 
   508     # monkeypatches
   524     # monkeypatches
   509     def kwpatchfile_init(orig, self, ui, fname, opener,
   525     def kwpatchfile_init(orig, self, ui, fname, opener,
   510                          missing=False, eolmode=None):
   526                          missing=False, eolmode=None):
   511         '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
   527         '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
   514         # shrink keywords read from working dir
   530         # shrink keywords read from working dir
   515         self.lines = kwt.shrinklines(self.fname, self.lines)
   531         self.lines = kwt.shrinklines(self.fname, self.lines)
   516 
   532 
   517     def kw_diff(orig, repo, node1=None, node2=None, match=None, changes=None,
   533     def kw_diff(orig, repo, node1=None, node2=None, match=None, changes=None,
   518                 opts=None, prefix=''):
   534                 opts=None, prefix=''):
   519         '''Monkeypatch patch.diff to avoid expansion except when
   535         '''Monkeypatch patch.diff to avoid expansion.'''
   520         comparing against working dir.'''
   536         kwt.restrict = True
   521         if node2 is not None:
       
   522             kwt.match = util.never
       
   523         elif node1 is not None and node1 != repo['.'].node():
       
   524             kwt.restrict = True
       
   525         return orig(repo, node1, node2, match, changes, opts, prefix)
   537         return orig(repo, node1, node2, match, changes, opts, prefix)
   526 
   538 
   527     def kwweb_skip(orig, web, req, tmpl):
   539     def kwweb_skip(orig, web, req, tmpl):
   528         '''Wraps webcommands.x turning off keyword expansion.'''
   540         '''Wraps webcommands.x turning off keyword expansion.'''
   529         kwt.match = util.never
   541         kwt.match = util.never
   537             # therefore compare nodes before and after
   549             # therefore compare nodes before and after
   538             ctx = repo['.']
   550             ctx = repo['.']
   539             ret = orig(ui, repo, commitfunc, *pats, **opts)
   551             ret = orig(ui, repo, commitfunc, *pats, **opts)
   540             recordctx = repo['.']
   552             recordctx = repo['.']
   541             if ctx != recordctx:
   553             if ctx != recordctx:
   542                 kwt.overwrite(recordctx, None, False, True)
   554                 kwt.overwrite(recordctx, recordctx.files(),
       
   555                               False, True, recordctx)
   543             return ret
   556             return ret
   544         finally:
   557         finally:
   545             wlock.release()
   558             wlock.release()
   546 
   559 
   547     repo.__class__ = kwrepo
   560     repo.__class__ = kwrepo
   548 
   561 
   549     extensions.wrapfunction(patch.patchfile, '__init__', kwpatchfile_init)
   562     extensions.wrapfunction(patch.patchfile, '__init__', kwpatchfile_init)
   550     if not kwt.restrict:
   563     extensions.wrapfunction(patch, 'diff', kw_diff)
   551         extensions.wrapfunction(patch, 'diff', kw_diff)
       
   552     for c in 'annotate changeset rev filediff diff'.split():
   564     for c in 'annotate changeset rev filediff diff'.split():
   553         extensions.wrapfunction(webcommands, c, kwweb_skip)
   565         extensions.wrapfunction(webcommands, c, kwweb_skip)
   554     for name in recordextensions.split():
   566     for name in recordextensions.split():
   555         try:
   567         try:
   556             record = extensions.find(name)
   568             record = extensions.find(name)