hgkw/keyword.py
changeset 204 2d089b691b31
parent 203 20eaa6147391
child 205 f2d2e36053f9
equal deleted inserted replaced
203:20eaa6147391 204:2d089b691b31
    92     findcmd = commands.findcmd
    92     findcmd = commands.findcmd
    93     bail_if_changed = commands.bail_if_changed
    93     bail_if_changed = commands.bail_if_changed
    94 
    94 
    95 commands.optionalrepo += ' kwdemo'
    95 commands.optionalrepo += ' kwdemo'
    96 
    96 
    97 deftemplates = {
       
    98     'Revision': '{node|short}',
       
    99     'Author': '{author|user}',
       
   100     'Date': '{date|utcdate}',
       
   101     'RCSFile': '{file|basename},v',
       
   102     'Source': '{root}/{file},v',
       
   103     'Id': '{file|basename},v {node|short} {date|utcdate} {author|user}',
       
   104     'Header': '{root}/{file},v {node|short} {date|utcdate} {author|user}',
       
   105 }
       
   106 
       
   107 nokwcommands = ('add', 'addremove', 'bundle', 'clone', 'copy', 'export',
       
   108                 'incoming', 'outgoing', 'push', 'remove', 'rename', 'rollback')
       
   109 
       
   110 keyword_raw = r'\$(%s)[^$\n\r]*?\$'
       
   111 
       
   112 def utcdate(date):
    97 def utcdate(date):
   113     '''Returns hgdate in cvs-like UTC format.'''
    98     '''Returns hgdate in cvs-like UTC format.'''
   114     return time.strftime('%Y/%m/%d %H:%M:%S', time.gmtime(date[0]))
    99     return time.strftime('%Y/%m/%d %H:%M:%S', time.gmtime(date[0]))
   115 
       
   116 def getcmd(ui):
       
   117     '''Returns current hg command.'''
       
   118     # commands.parse(ui, sys.argv[1:])[0] breaks "hg diff -r"
       
   119     try:
       
   120         args = fancyopts.fancyopts(sys.argv[1:], commands.globalopts, {})
       
   121     except fancyopts.getopt.GetoptError, inst:
       
   122         raise commands.ParseError(None, inst)
       
   123     if args:
       
   124         cmd = args[0]
       
   125         aliases, i = findcmd(ui, cmd)
       
   126         return aliases[0]
       
   127 
   100 
   128 def keywordmatcher(ui, repo):
   101 def keywordmatcher(ui, repo):
   129     '''Collects include/exclude filename patterns for expansion
   102     '''Collects include/exclude filename patterns for expansion
   130     candidates of current configuration. Returns filename matching
   103     candidates of current configuration. Returns filename matching
   131     function if include patterns exist, None otherwise.'''
   104     function if include patterns exist, None otherwise.'''
   142 class kwtemplater(object):
   115 class kwtemplater(object):
   143     '''
   116     '''
   144     Sets up keyword templates, corresponding keyword regex, and
   117     Sets up keyword templates, corresponding keyword regex, and
   145     provides keyword substitution functions.
   118     provides keyword substitution functions.
   146     '''
   119     '''
       
   120     deftemplates = {
       
   121         'Revision': '{node|short}',
       
   122         'Author': '{author|user}',
       
   123         'Date': '{date|utcdate}',
       
   124         'RCSFile': '{file|basename},v',
       
   125         'Source': '{root}/{file},v',
       
   126         'Id': '{file|basename},v {node|short} {date|utcdate} {author|user}',
       
   127         'Header': '{root}/{file},v {node|short} {date|utcdate} {author|user}',
       
   128     }
       
   129 
   147     def __init__(self, ui, repo, path='', node=None, expand=True):
   130     def __init__(self, ui, repo, path='', node=None, expand=True):
   148         self.ui = ui
   131         self.ui = ui
   149         self.repo = repo
   132         self.repo = repo
   150         self.path = path
   133         self.path = path
   151         self.node = node
   134         self.node = node
       
   135         self.t = expand or None
       
   136 
   152         templates = dict(ui.configitems('keywordmaps'))
   137         templates = dict(ui.configitems('keywordmaps'))
   153         if templates:
   138         if templates:
   154             for k in templates.keys():
   139             for k in templates.keys():
   155                 templates[k] = templater.parsestring(templates[k],
   140                 templates[k] = templater.parsestring(templates[k],
   156                                                      quoted=False)
   141                                                      quoted=False)
   157         self.templates = templates or deftemplates
   142         self.templates = templates or self.deftemplates
   158         escaped = [re.escape(k) for k in self.templates.keys()]
   143         escaped = [re.escape(k) for k in self.templates.keys()]
   159         self.re_kw = re.compile(keyword_raw % '|'.join(escaped))
   144         rawkeyword = r'\$(%s)[^$\n\r]*?\$'
   160         if expand:
   145         self.re_kw = re.compile(rawkeyword % '|'.join(escaped))
       
   146         if self.t:
   161             templater.common_filters['utcdate'] = utcdate
   147             templater.common_filters['utcdate'] = utcdate
   162             try:
   148             try:
   163                 self.t = cmdutil.changeset_templater(ui, repo,
   149                 self.t = cmdutil.changeset_templater(self.ui, self.repo,
   164                                                      False, '', False)
   150                                                      False, '', False)
   165             except TypeError:
   151             except TypeError:
   166                 # depending on hg rev changeset_templater has extra "brinfo" arg
   152                 # depending on hg rev changeset_templater has extra "brinfo" arg
   167                 self.t = cmdutil.changeset_templater(ui, repo,
   153                 self.t = cmdutil.changeset_templater(self.ui, self.repo,
   168                                                      False, None, '', False)
   154                                                      False, None, '', False)
   169         else:
       
   170             self.t = None
       
   171 
   155 
   172     def ctxnode(self, node):
   156     def ctxnode(self, node):
   173         '''Obtains missing node from file context.'''
   157         '''Obtains missing node from file context.'''
   174         if not self.node:
   158         if not self.node:
   175             c = context.filectx(self.repo, self.path, fileid=node)
   159             c = context.filectx(self.repo, self.path, fileid=node)
   321     # for backwards compatibility
   305     # for backwards compatibility
   322     ui = _repo.ui
   306     ui = _repo.ui
   323     ui.setconfig('keyword', fn, '')
   307     ui.setconfig('keyword', fn, '')
   324     if opts['default']:
   308     if opts['default']:
   325         kwstatus = 'default'
   309         kwstatus = 'default'
   326         kwmaps = deftemplates
   310         kwmaps = kwtemplater.deftemplates
   327     else:
   311     else:
   328         if args or opts['rcfile']:
   312         if args or opts['rcfile']:
   329             kwstatus = 'custom'
   313             kwstatus = 'custom'
   330         for tmap in args:
   314         for tmap in args:
   331             k, v = tmap.split('=', 1)
   315             k, v = tmap.split('=', 1)
   332             ui.setconfig('keywordmaps', k.strip(), v.strip())
   316             ui.setconfig('keywordmaps', k.strip(), v.strip())
   333         if opts['rcfile']:
   317         if opts['rcfile']:
   334             ui.readconfig(opts['rcfile'])
   318             ui.readconfig(opts['rcfile'])
   335         kwmaps = dict(ui.configitems('keywordmaps')) or deftemplates
   319         kwmaps = (dict(ui.configitems('keywordmaps')) or
       
   320                   kwtemplater.deftemplates)
   336     if ui.configitems('keywordmaps'):
   321     if ui.configitems('keywordmaps'):
   337         for k, v in kwmaps.items():
   322         for k, v in kwmaps.items():
   338             ui.setconfig('keywordmaps', k, v)
   323             ui.setconfig('keywordmaps', k, v)
   339     reposetup(ui, _repo)
   324     reposetup(ui, _repo)
   340     ui.status(_('config with %s keyword template maps:\n') % kwstatus)
   325     ui.status(_('config with %s keyword template maps:\n') % kwstatus)
   363     Wraps commit to overwrite configured files with updated
   348     Wraps commit to overwrite configured files with updated
   364     keyword substitutions.
   349     keyword substitutions.
   365     This is done for local repos only, and only if there are
   350     This is done for local repos only, and only if there are
   366     files configured at all for keyword substitution.'''
   351     files configured at all for keyword substitution.'''
   367 
   352 
       
   353     nokwcommands = ['add', 'addremove', 'bundle', 'clone', 'copy', 'export',
       
   354                     'grep', 'identify', 'incoming', 'init', 'outgoing', 'push',
       
   355                     'remove', 'rename', 'rollback']
       
   356 
   368     # for backwards compatibility
   357     # for backwards compatibility
   369     ui = repo.ui
   358     ui = repo.ui
   370 
   359 
   371     if not repo.local() or getcmd(ui) in nokwcommands:
   360     def getcmd():
       
   361         # cmdutil.parse(ui, sys.argv[1:])[0] doesn't work for "hg diff -r"
       
   362         args = fancyopts.fancyopts(sys.argv[1:], commands.globalopts, {})
       
   363         if args:
       
   364             cmd = args[0]
       
   365             aliases, i = findcmd(ui, cmd)
       
   366             return aliases[0]
       
   367 
       
   368     if not repo.local() or getcmd() in nokwcommands:
   372         return
   369         return
   373 
   370 
   374     kwfmatcher = keywordmatcher(ui, repo)
   371     kwfmatcher = keywordmatcher(ui, repo)
   375     if kwfmatcher is None:
   372     if kwfmatcher is None:
   376         return
   373         return
   380             if f[0] == '/':
   377             if f[0] == '/':
   381                 f = f[1:]
   378                 f = f[1:]
   382             if kwfmatcher(f):
   379             if kwfmatcher(f):
   383                 kwt = kwtemplater(ui, self, path=f, expand=kwexp)
   380                 kwt = kwtemplater(ui, self, path=f, expand=kwexp)
   384                 return kwfilelog(self.sopener, f, kwt, kwcnt)
   381                 return kwfilelog(self.sopener, f, kwt, kwcnt)
   385             else:
   382             return filelog.filelog(self.sopener, f)
   386                 return filelog.filelog(self.sopener, f)
       
   387 
   383 
   388         def commit(self, files=None, text='', user=None, date=None,
   384         def commit(self, files=None, text='', user=None, date=None,
   389                    match=util.always, force=False, lock=None, wlock=None,
   385                    match=util.always, force=False, lock=None, wlock=None,
   390                    force_editor=False, p1=None, p2=None, extra={}):
   386                    force_editor=False, p1=None, p2=None, extra={}):
   391             wrelease = False
   387             wrelease = False