hgkw/keyword.py
branchkwmap-templates
changeset 118 d9cea05cb74c
parent 117 201e9affcf0f
child 119 6b4cba263852
equal deleted inserted replaced
117:201e9affcf0f 118:d9cea05cb74c
     1 # keyword.py - keyword expansion for mercurial
     1 # keyword.py - keyword expansion for Mercurial
     2 # $Id$
     2 # $Id$
     3 
     3 # 
     4 '''keyword expansion hack against the grain of a DSCM
     4 # Keyword expansion hack against the grain of a DSCM
     5 
     5 # 
     6 This extension lets you expand RCS/CVS-like keywords in a Mercurial
     6 # There are many good reasons why this is not needed in a distributed
     7 repository.
     7 # SCM, still it may be useful in very small projects based on single
     8 
     8 # files (like LaTeX packages), that are mostly addressed to an audience
     9 There are many good reasons why this is not needed in a distributed
     9 # not running a version control system.
    10 SCM, still it may be useful in very small projects based on single
    10 # 
    11 files (like LaTeX packages), that are mostly addressed to an audience
    11 # For in-depth discussion refer to
    12 not running a version control system.
    12 # <http://www.selenic.com/mercurial/wiki/index.cgi/KeywordPlan>.
    13 
    13 #
    14 For in-depth discussion refer to
    14 # Keyword expansion is based on Mercurial's changeset template mappings.
    15 <http://www.selenic.com/mercurial/wiki/index.cgi/KeywordPlan>.
    15 # The extension provides an additional UTC-date filter ({date|utcdate}).
       
    16 #
       
    17 # The user has the choice either to create his own keywords and their
       
    18 # expansions or to use the CVS-like default ones.
       
    19 # 
       
    20 # Default $keywords$ and their $keyword: substition $ are:
       
    21 #     Revision: changeset id
       
    22 #     Author:   username
       
    23 #     Date:     %Y/%m/%d %H:%M:%S [UTC]
       
    24 #     RCSFile:  basename,v
       
    25 #     Source:   /path/to/basename,v
       
    26 #     Id:       basename,v csetid %Y/%m/%d %H:%M:%S username
       
    27 #     Header:   /path/to/basename,v csetid %Y/%m/%d %H:%M:%S username
       
    28 # 
       
    29 # Expansions spanning more than one line are truncated to their first line.
       
    30 # Incremental expansion (like CVS' $Log$) is not supported.
       
    31 # 
       
    32 # Simple setup in hgrc:
       
    33 # 
       
    34 #     # enable extension
       
    35 #     keyword = /full/path/to/keyword.py
       
    36 #     # or, if script in hgext folder:
       
    37 #     # hgext.keyword =
       
    38 #     
       
    39 #     # filename patterns for expansion are configured in this section
       
    40 #     # files matching patterns with value 'ignore' are ignored
       
    41 #     [keyword]
       
    42 #     **.py =
       
    43 #     x* = ignore
       
    44 #     ...
       
    45 #     # in case you prefer your own keyword maps over the cvs-like defaults:
       
    46 #     [keywordmaps]
       
    47 #     HGdate = {date|rfc822date}
       
    48 #     lastlog = {desc} ## same as {desc|firstline} in this context
       
    49 #     checked in by = {author}
       
    50 #     ...
       
    51 
       
    52 '''keyword expansion in local repositories
       
    53 
       
    54 This extension expands RCS/CVS-like or self-customized keywords in
       
    55 the text files selected by your configuration.
    16 
    56 
    17 Keywords are only expanded in local repositories and not logged by
    57 Keywords are only expanded in local repositories and not logged by
    18 Mercurial internally. The mechanism can be regarded as a convenience
    58 Mercurial internally. The mechanism can be regarded as a convenience
    19 for the current user and may be turned off anytime.
    59 for the current user and may be turned off anytime.
    20 
    60  
    21 Substitution takes place on every commit and update of the working
    61 Substitution takes place on every commit and update of the working
    22 repository.
    62 repository.
    23 
    63 
    24 Keyword expansion is based on Mercurial's changeset template mappings.
    64 Configuration is done in the [keyword] and [keywordmaps] sections of
    25 The extension provides an additional UTC-date filter.
    65 hgrc files.
    26 
       
    27 The user has the choice either to create his own keywords and their
       
    28 expansions or to use the CVS-like default ones.
       
    29 
       
    30 Default $keywords$ and their $keyword: substition $ are:
       
    31     Revision: changeset id
       
    32     Author:   username
       
    33     Date:     %Y/%m/%d %H:%M:%S [UTC]
       
    34     RCSFile:  basename,v
       
    35     Source:   /path/to/basename,v
       
    36     Id:       basename,v csetid %Y/%m/%d %H:%M:%S username
       
    37     Header:   /path/to/basename,v csetid %Y/%m/%d %H:%M:%S username
       
    38 
       
    39 Expansions spanning more than one line are truncated to their first line.
       
    40 Incremental expansion (like CVS' $Log$) is not supported.
       
    41 
       
    42 Simple setup in hgrc:
       
    43 
       
    44     # enable extension
       
    45     keyword = /full/path/to/keyword.py
       
    46     # or, if script in hgext folder:
       
    47     # hgext.keyword =
       
    48     
       
    49     # filename patterns for expansion are configured in this section
       
    50     # files matching patterns with value 'ignore' are ignored
       
    51     [keyword]
       
    52     **.py =
       
    53     x* = ignore
       
    54     ...
       
    55     # in case you prefer your own keyword maps over the cvs-like defaults:
       
    56     [keywordmaps]
       
    57     HGdate = {date|rfc822date}
       
    58     lastlog = {desc} ## same as {desc|firstline} in this context
       
    59     checked in by = {author}
       
    60     ...
       
    61 '''
    66 '''
    62 
    67  
    63 from mercurial.i18n import gettext as _
    68 from mercurial.i18n import gettext as _
    64 # above line for backwards compatibility; can be changed to
    69 # above line for backwards compatibility; can be changed to
    65 #   from mercurial.i18n import _
    70 #   from mercurial.i18n import _
    66 # some day
    71 # some day
    67 from mercurial import context, filelog, revlog
    72 from mercurial import context, filelog, revlog
    96     else:
   101     else:
    97         sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
   102         sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
    98         return os.path.splitext(os.path.basename(__file__))[0]
   103         return os.path.splitext(os.path.basename(__file__))[0]
    99 
   104 
   100 def kwfmatches(ui, repo, files):
   105 def kwfmatches(ui, repo, files):
   101     '''Selects candidates for keyword substitution
   106     '''Selects and weeds out candidates for keyword substitution
   102     configured in keyword section in hgrc.'''
   107     by patterns configured in [keyword] section in hgrc.'''
   103     inc, exc = [], []
   108     inc, exc = [], []
   104     for pat, opt in ui.configitems('keyword'):
   109     for pat, opt in ui.configitems('keyword'):
   105         if opt != 'ignore':
   110         if opt != 'ignore':
   106             inc.append(pat)
   111             inc.append(pat)
   107         else:
   112         else:
   108             exc.append(pat)
   113             exc.append(pat)
   109     if not inc:
   114     if not inc:
   110         return []
   115         return []
   111     kwfmatcher = util.matcher(repo.root, inc=inc, exc=['.hg*']+exc)[1]
   116     kwfmatcher = util.matcher(repo.root, inc=inc, exc=['.hg*']+exc)[1]
   112     return [f for f in files if kwfmatcher(f)]
   117     return [f for f in files if kwfmatcher(f)]
   113 
       
   114 
   118 
   115 class kwtemplater(object):
   119 class kwtemplater(object):
   116     '''
   120     '''
   117     Sets up keyword templates, corresponding keyword regex, and
   121     Sets up keyword templates, corresponding keyword regex, and
   118     provides keyword expansion function.
   122     provides keyword expansion function.
   126         templater.common_filters['utcdate'] = utcdate
   130         templater.common_filters['utcdate'] = utcdate
   127         self.t = cmdutil.changeset_templater(ui, repo, False, '', False)
   131         self.t = cmdutil.changeset_templater(ui, repo, False, '', False)
   128             
   132             
   129 
   133 
   130     def expand(self, mobj, path, node):
   134     def expand(self, mobj, path, node):
   131         '''Expands keyword with corresponding template.'''
   135         '''Expands keyword using corresponding template.'''
   132         kw = mobj.group(1)
   136         kw = mobj.group(1)
   133         template = templater.parsestring(self.templates[kw], quoted=False)
   137         template = templater.parsestring(self.templates[kw], quoted=False)
   134         self.t.use_template(template)
   138         self.t.use_template(template)
   135         self.ui.pushbuffer()
   139         self.ui.pushbuffer()
   136         self.t.show(changenode=node, root=self.repo.root, file=path)
   140         self.t.show(changenode=node, root=self.repo.root, file=path)
   138         return '$%s: %s $' % (kw, kwsub)
   142         return '$%s: %s $' % (kw, kwsub)
   139 
   143 
   140 
   144 
   141 def reposetup(ui, repo):
   145 def reposetup(ui, repo):
   142     '''Sets up repo, and filelog especially, as kwrepo and kwfilelog
   146     '''Sets up repo, and filelog especially, as kwrepo and kwfilelog
   143     for keyword substitution.  This is done for local repos only.'''
   147     for keyword substitution. This is done for local repos only.'''
   144 
   148 
   145     if not repo.local():
   149     if not repo.local():
   146         return
   150         return
   147 
       
   148 
   151 
   149     class kwrepo(repo.__class__):
   152     class kwrepo(repo.__class__):
   150         def file(self, f):
   153         def file(self, f):
   151             if f[0] == '/':
   154             if f[0] == '/':
   152                 f = f[1:]
   155                 f = f[1:]