hgkw/keyword.py
changeset 736 38ef84cc9dd1
parent 735 cbb80aee425c
child 745 a72c2895fc26
equal deleted inserted replaced
735:cbb80aee425c 736:38ef84cc9dd1
    63 the risk of inadvertently storing expanded keywords in the change
    63 the risk of inadvertently storing expanded keywords in the change
    64 history.
    64 history.
    65 
    65 
    66 To force expansion after enabling it, or a configuration change, run
    66 To force expansion after enabling it, or a configuration change, run
    67 :hg:`kwexpand`.
    67 :hg:`kwexpand`.
    68 
       
    69 Also, when committing with the record extension or using mq's qrecord,
       
    70 be aware that keywords cannot be updated. Again, run :hg:`kwexpand` on
       
    71 the files in question to update keyword expansions after all changes
       
    72 have been checked in.
       
    73 
    68 
    74 Expansions spanning more than one line and incremental expansions,
    69 Expansions spanning more than one line and incremental expansions,
    75 like CVS' $Log$, are not supported. A keyword template map "Log =
    70 like CVS' $Log$, are not supported. A keyword template map "Log =
    76 {desc}" expands to the first line of the changeset description.
    71 {desc}" expands to the first line of the changeset description.
    77 '''
    72 '''
    91                 ' convert email glog')
    86                 ' convert email glog')
    92 
    87 
    93 # hg commands that trigger expansion only when writing to working dir,
    88 # hg commands that trigger expansion only when writing to working dir,
    94 # not when reading filelog, and unexpand when reading from working dir
    89 # not when reading filelog, and unexpand when reading from working dir
    95 restricted = 'merge record qrecord resolve transplant'
    90 restricted = 'merge record qrecord resolve transplant'
       
    91 
       
    92 # commands using dorecord
       
    93 recordcommands = 'record qrecord'
    96 
    94 
    97 # provide cvs-like UTC date filter
    95 # provide cvs-like UTC date filter
    98 utcdate = lambda x: util.datestr((x[0], 0), '%Y/%m/%d %H:%M:%S')
    96 utcdate = lambda x: util.datestr((x[0], 0), '%Y/%m/%d %H:%M:%S')
    99 
    97 
   100 # make keyword tools accessible
    98 # make keyword tools accessible
   122         self.ui = ui
   120         self.ui = ui
   123         self.repo = repo
   121         self.repo = repo
   124         self.match = match.match(repo.root, '', [],
   122         self.match = match.match(repo.root, '', [],
   125                                  kwtools['inc'], kwtools['exc'])
   123                                  kwtools['inc'], kwtools['exc'])
   126         self.restrict = kwtools['hgcmd'] in restricted.split()
   124         self.restrict = kwtools['hgcmd'] in restricted.split()
       
   125         self.record = kwtools['hgcmd'] in recordcommands.split()
   127 
   126 
   128         kwmaps = self.ui.configitems('keywordmaps')
   127         kwmaps = self.ui.configitems('keywordmaps')
   129         if kwmaps: # override default templates
   128         if kwmaps: # override default templates
   130             self.templates = dict((k, templater.parsestring(v, False))
   129             self.templates = dict((k, templater.parsestring(v, False))
   131                                   for k, v in kwmaps)
   130                                   for k, v in kwmaps)
   159         '''Returns true if path matches [keyword] pattern
   158         '''Returns true if path matches [keyword] pattern
   160         and is not a symbolic link.
   159         and is not a symbolic link.
   161         Caveat: localrepository._link fails on Windows.'''
   160         Caveat: localrepository._link fails on Windows.'''
   162         return self.match(path) and not 'l' in flagfunc(path)
   161         return self.match(path) and not 'l' in flagfunc(path)
   163 
   162 
   164     def overwrite(self, node, expand, candidates):
   163     def overwrite(self, node, expand, candidates, recctx=None):
   165         '''Overwrites selected files expanding/shrinking keywords.'''
   164         '''Overwrites selected files expanding/shrinking keywords.'''
   166         ctx = self.repo[node]
   165         if recctx is None:
       
   166             ctx = self.repo[node]
       
   167         else:
       
   168             ctx = recctx
   167         mf = ctx.manifest()
   169         mf = ctx.manifest()
   168         if node is not None:     # commit
   170         if node is not None:     # commit, record
   169             candidates = [f for f in ctx.files() if f in mf]
   171             candidates = [f for f in ctx.files() if f in mf]
   170         candidates = [f for f in candidates if self.iskwfile(f, ctx.flags)]
   172         candidates = [f for f in candidates if self.iskwfile(f, ctx.flags)]
   171         if candidates:
   173         if candidates:
   172             self.restrict = True # do not expand when reading
   174             self.restrict = True # do not expand when reading
   173             msg = (expand and _('overwriting %s expanding keywords\n')
   175             msg = (expand and _('overwriting %s expanding keywords\n')
   174                    or _('overwriting %s shrinking keywords\n'))
   176                    or _('overwriting %s shrinking keywords\n'))
   175             for f in candidates:
   177             for f in candidates:
   176                 fp = self.repo.file(f)
   178                 if recctx is None:
   177                 data = fp.read(mf[f])
   179                     data = self.repo.file(f).read(mf[f])
       
   180                 else:
       
   181                     data = self.repo.wread(f)
   178                 if util.binary(data):
   182                 if util.binary(data):
   179                     continue
   183                     continue
   180                 if expand:
   184                 if expand:
   181                     if node is None:
   185                     if node is None:
   182                         ctx = self.repo.filectx(f, fileid=mf[f]).changectx()
   186                         ctx = self.repo.filectx(f, fileid=mf[f]).changectx()
   463                 del self.commitctx
   467                 del self.commitctx
   464 
   468 
   465         def kwcommitctx(self, ctx, error=False):
   469         def kwcommitctx(self, ctx, error=False):
   466             n = super(kwrepo, self).commitctx(ctx, error)
   470             n = super(kwrepo, self).commitctx(ctx, error)
   467             # no lock needed, only called from repo.commit() which already locks
   471             # no lock needed, only called from repo.commit() which already locks
   468             kwt.overwrite(n, True, None)
   472             if not kwt.record:
       
   473                 kwt.overwrite(n, True, None)
   469             return n
   474             return n
   470 
   475 
   471     # monkeypatches
   476     # monkeypatches
   472     def kwpatchfile_init(orig, self, ui, fname, opener,
   477     def kwpatchfile_init(orig, self, ui, fname, opener,
   473                          missing=False, eolmode=None):
   478                          missing=False, eolmode=None):
   490     def kwweb_skip(orig, web, req, tmpl):
   495     def kwweb_skip(orig, web, req, tmpl):
   491         '''Wraps webcommands.x turning off keyword expansion.'''
   496         '''Wraps webcommands.x turning off keyword expansion.'''
   492         kwt.match = util.never
   497         kwt.match = util.never
   493         return orig(web, req, tmpl)
   498         return orig(web, req, tmpl)
   494 
   499 
       
   500     def kw_dorecord(orig, ui, repo, commitfunc, *pats, **opts):
       
   501         '''Wraps record.dorecord expanding keywords after recording.'''
       
   502         wlock = repo.wlock()
       
   503         try:
       
   504             # record returns 0 even when nothing has changed
       
   505             # therefore compare nodes before and after
       
   506             ctx = repo['.']
       
   507             ret = orig(ui, repo, commitfunc, *pats, **opts)
       
   508             recctx = repo['.']
       
   509             if ctx != recctx:
       
   510                 kwt.overwrite('.',  True, None, recctx)
       
   511             return ret
       
   512         finally:
       
   513             wlock.release()
       
   514 
   495     repo.__class__ = kwrepo
   515     repo.__class__ = kwrepo
   496 
   516 
   497     extensions.wrapfunction(patch.patchfile, '__init__', kwpatchfile_init)
   517     extensions.wrapfunction(patch.patchfile, '__init__', kwpatchfile_init)
   498     if not kwt.restrict:
   518     if not kwt.restrict:
   499         extensions.wrapfunction(patch, 'diff', kw_diff)
   519         extensions.wrapfunction(patch, 'diff', kw_diff)
   500     for c in 'annotate changeset rev filediff diff'.split():
   520     for c in 'annotate changeset rev filediff diff'.split():
   501         extensions.wrapfunction(webcommands, c, kwweb_skip)
   521         extensions.wrapfunction(webcommands, c, kwweb_skip)
       
   522     try:
       
   523         record = extensions.find('record')
       
   524         extensions.wrapfunction(record, 'dorecord', kw_dorecord)
       
   525     except KeyError:
       
   526         pass
   502 
   527 
   503 cmdtable = {
   528 cmdtable = {
   504     'kwdemo':
   529     'kwdemo':
   505         (demo,
   530         (demo,
   506          [('d', 'default', None, _('show default keyword template maps')),
   531          [('d', 'default', None, _('show default keyword template maps')),