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) |