hgkw/keyword.py
branchstable
changeset 738 abd249e1db3c
parent 736 38ef84cc9dd1
child 745 a72c2895fc26
equal deleted inserted replaced
732:0ff5881bc04b 738:abd249e1db3c
    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 '''
    90                 ' log outgoing push rename rollback tip verify'
    85                 ' log outgoing push rename rollback tip verify'
    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 resolve qfold qimport qnew qpush qrefresh qrecord'
    90 restricted = 'merge record qrecord resolve transplant'
    96               ' transplant')
    91 
       
    92 # commands using dorecord
       
    93 recordcommands = 'record qrecord'
    97 
    94 
    98 # provide cvs-like UTC date filter
    95 # provide cvs-like UTC date filter
    99 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')
   100 
    97 
   101 # make keyword tools accessible
    98 # make keyword tools accessible
   123         self.ui = ui
   120         self.ui = ui
   124         self.repo = repo
   121         self.repo = repo
   125         self.match = match.match(repo.root, '', [],
   122         self.match = match.match(repo.root, '', [],
   126                                  kwtools['inc'], kwtools['exc'])
   123                                  kwtools['inc'], kwtools['exc'])
   127         self.restrict = kwtools['hgcmd'] in restricted.split()
   124         self.restrict = kwtools['hgcmd'] in restricted.split()
       
   125         self.record = kwtools['hgcmd'] in recordcommands.split()
   128 
   126 
   129         kwmaps = self.ui.configitems('keywordmaps')
   127         kwmaps = self.ui.configitems('keywordmaps')
   130         if kwmaps: # override default templates
   128         if kwmaps: # override default templates
   131             self.templates = dict((k, templater.parsestring(v, False))
   129             self.templates = dict((k, templater.parsestring(v, False))
   132                                   for k, v in kwmaps)
   130                                   for k, v in kwmaps)
   160         '''Returns true if path matches [keyword] pattern
   158         '''Returns true if path matches [keyword] pattern
   161         and is not a symbolic link.
   159         and is not a symbolic link.
   162         Caveat: localrepository._link fails on Windows.'''
   160         Caveat: localrepository._link fails on Windows.'''
   163         return self.match(path) and not 'l' in flagfunc(path)
   161         return self.match(path) and not 'l' in flagfunc(path)
   164 
   162 
   165     def overwrite(self, node, expand, candidates):
   163     def overwrite(self, node, expand, candidates, recctx=None):
   166         '''Overwrites selected files expanding/shrinking keywords.'''
   164         '''Overwrites selected files expanding/shrinking keywords.'''
   167         ctx = self.repo[node]
   165         if recctx is None:
       
   166             ctx = self.repo[node]
       
   167         else:
       
   168             ctx = recctx
   168         mf = ctx.manifest()
   169         mf = ctx.manifest()
   169         if node is not None:     # commit
   170         if node is not None:     # commit, record
   170             candidates = [f for f in ctx.files() if f in mf]
   171             candidates = [f for f in ctx.files() if f in mf]
   171         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)]
   172         if candidates:
   173         if candidates:
   173             self.restrict = True # do not expand when reading
   174             self.restrict = True # do not expand when reading
   174             msg = (expand and _('overwriting %s expanding keywords\n')
   175             msg = (expand and _('overwriting %s expanding keywords\n')
   175                    or _('overwriting %s shrinking keywords\n'))
   176                    or _('overwriting %s shrinking keywords\n'))
   176             for f in candidates:
   177             for f in candidates:
   177                 fp = self.repo.file(f)
   178                 if recctx is None:
   178                 data = fp.read(mf[f])
   179                     data = self.repo.file(f).read(mf[f])
       
   180                 else:
       
   181                     data = self.repo.wread(f)
   179                 if util.binary(data):
   182                 if util.binary(data):
   180                     continue
   183                     continue
   181                 if expand:
   184                 if expand:
   182                     if node is None:
   185                     if node is None:
   183                         ctx = self.repo.filectx(f, fileid=mf[f]).changectx()
   186                         ctx = self.repo.filectx(f, fileid=mf[f]).changectx()
   464                 del self.commitctx
   467                 del self.commitctx
   465 
   468 
   466         def kwcommitctx(self, ctx, error=False):
   469         def kwcommitctx(self, ctx, error=False):
   467             n = super(kwrepo, self).commitctx(ctx, error)
   470             n = super(kwrepo, self).commitctx(ctx, error)
   468             # no lock needed, only called from repo.commit() which already locks
   471             # no lock needed, only called from repo.commit() which already locks
   469             kwt.overwrite(n, True, None)
   472             if not kwt.record:
       
   473                 kwt.overwrite(n, True, None)
   470             return n
   474             return n
   471 
   475 
   472     # monkeypatches
   476     # monkeypatches
   473     def kwpatchfile_init(orig, self, ui, fname, opener,
   477     def kwpatchfile_init(orig, self, ui, fname, opener,
   474                          missing=False, eolmode=None):
   478                          missing=False, eolmode=None):
   491     def kwweb_skip(orig, web, req, tmpl):
   495     def kwweb_skip(orig, web, req, tmpl):
   492         '''Wraps webcommands.x turning off keyword expansion.'''
   496         '''Wraps webcommands.x turning off keyword expansion.'''
   493         kwt.match = util.never
   497         kwt.match = util.never
   494         return orig(web, req, tmpl)
   498         return orig(web, req, tmpl)
   495 
   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 
   496     repo.__class__ = kwrepo
   515     repo.__class__ = kwrepo
   497 
   516 
   498     extensions.wrapfunction(patch.patchfile, '__init__', kwpatchfile_init)
   517     extensions.wrapfunction(patch.patchfile, '__init__', kwpatchfile_init)
   499     if not kwt.restrict:
   518     if not kwt.restrict:
   500         extensions.wrapfunction(patch, 'diff', kw_diff)
   519         extensions.wrapfunction(patch, 'diff', kw_diff)
   501     for c in 'annotate changeset rev filediff diff'.split():
   520     for c in 'annotate changeset rev filediff diff'.split():
   502         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
   503 
   527 
   504 cmdtable = {
   528 cmdtable = {
   505     'kwdemo':
   529     'kwdemo':
   506         (demo,
   530         (demo,
   507          [('d', 'default', None, _('show default keyword template maps')),
   531          [('d', 'default', None, _('show default keyword template maps')),