16 # |
16 # |
17 # For in-depth discussion refer to |
17 # For in-depth discussion refer to |
18 # <http://www.selenic.com/mercurial/wiki/index.cgi/KeywordPlan>. |
18 # <http://www.selenic.com/mercurial/wiki/index.cgi/KeywordPlan>. |
19 # |
19 # |
20 # Keyword expansion is based on Mercurial's changeset template mappings. |
20 # Keyword expansion is based on Mercurial's changeset template mappings. |
21 # The extension provides an additional UTC-date filter ({date|utcdate}). |
|
22 # |
|
23 # Expansions spanning more than one line are truncated to their first line. |
|
24 # Incremental expansion (like CVS' $Log$) is not supported. |
|
25 # |
21 # |
26 # Binary files are not touched. |
22 # Binary files are not touched. |
27 # |
23 # |
28 # Setup in hgrc: |
24 # Setup in hgrc: |
29 # |
25 # |
30 # # enable extension |
26 # [extensions] |
31 # keyword = /full/path/to/keyword.py |
27 # # enable extension |
32 # # or, if script in hgext folder: |
28 # keyword = /full/path/to/hgkw/keyword.py |
33 # # hgext.keyword = |
29 # # or, if script in canonical hgext folder: |
|
30 # # hgext.keyword = |
|
31 # |
|
32 # Files to act upon/ignore are specified in the [keyword] section. |
|
33 # Customized keyword template mappings in the [keywordmaps] section. |
|
34 # |
|
35 # Run "hg help keyword" and "hg kwdemo" to get info on configuration. |
34 |
36 |
35 '''keyword expansion in local repositories |
37 '''keyword expansion in local repositories |
36 |
38 |
37 This extension expands RCS/CVS-like or self-customized $Keywords$ |
39 This extension expands RCS/CVS-like or self-customized $Keywords$ |
38 in the text files selected by your configuration. |
40 in tracked text files selected by your configuration. |
39 |
41 |
40 Keywords are only expanded in local repositories and not logged by |
42 Keywords are only expanded in local repositories and not stored in |
41 Mercurial internally. The mechanism can be regarded as a convenience |
43 the change history. The mechanism can be regarded as a convenience |
42 for the current user or archive distribution. |
44 for the current user or for archive distribution. |
43 |
45 |
44 Configuration is done in the [keyword] and [keywordmaps] sections of |
46 Configuration is done in the [keyword] and [keywordmaps] sections |
45 hgrc files. |
47 of hgrc files. |
46 |
48 |
47 Example: |
49 Example: |
48 [extensions] |
|
49 hgext.keyword = |
|
50 |
50 |
51 [keyword] |
51 [keyword] |
52 # expand keywords in every python file except those matching "x*" |
52 # expand keywords in every python file except those matching "x*" |
53 **.py = |
53 **.py = |
54 x* = ignore |
54 x* = ignore |
55 |
55 |
56 Note: the more specific you are in your [keyword] filename patterns |
56 Note: the more specific you are in your filename patterns |
57 the less you lose speed in huge repos. |
57 the less you lose speed in huge repos. |
58 |
58 |
59 For a [keywordmaps] template mapping and expansion demonstration |
59 For [keywordmaps] template mapping and expansion demonstration and |
60 run "hg kwdemo". |
60 control run "hg kwdemo". |
61 |
61 |
62 An additional date template filter {date|utcdate} is provided. |
62 An additional date template filter {date|utcdate} is provided. |
63 |
63 |
64 You can replace the default template mappings with customized keywords |
64 The default template mappings (view with "hg kwdemo -d") can be replaced |
65 and templates of your choice. |
65 with customized keywords and templates. |
66 Again, run "hg kwdemo" to control the results of your config changes. |
66 Again, run "hg kwdemo" to control the results of your config changes. |
67 |
67 |
68 When you change keyword configuration, especially the active keywords, |
68 Before changing/disabling active keywords, run "hg kwshrink" to avoid |
69 and do not want to store expanded keywords in change history, run |
69 the risk of inadvertedly storing expanded keywords in the change history. |
70 "hg kwshrink", and then change configuration. |
70 |
71 |
71 Expansions spanning more than one line and incremental expansions, |
72 Expansions spanning more than one line and incremental exapansions |
72 like CVS' $Log$, are not supported. A keyword template map |
73 (like CVS' $Log$) are not supported. A keyword template map |
|
74 "Log = {desc}" expands to the first line of the changeset description. |
73 "Log = {desc}" expands to the first line of the changeset description. |
75 |
74 |
76 Caveat: "hg import" fails if the patch context contains an active |
75 Caveat: "hg import" fails if the patch context contains an active |
77 keyword. In that case run "hg kwshrink", reimport, and then |
76 keyword. In that case run "hg kwshrink", reimport, and then |
78 "hg kwexpand". |
77 "hg kwexpand". |
137 except TypeError: |
136 except TypeError: |
138 # depending on hg rev changeset_templater has extra "brinfo" arg |
137 # depending on hg rev changeset_templater has extra "brinfo" arg |
139 self.t = cmdutil.changeset_templater(self.ui, self.repo, |
138 self.t = cmdutil.changeset_templater(self.ui, self.repo, |
140 False, None, '', False) |
139 False, None, '', False) |
141 |
140 |
142 def ctxnode(self, node): |
141 def _ctxnode(self, node): |
143 '''Obtains missing node from file context.''' |
142 '''Obtains missing node from file context.''' |
144 if not self.node: |
143 if not self.node: |
145 c = context.filectx(self.repo, self.path, fileid=node) |
144 c = context.filectx(self.repo, self.path, fileid=node) |
146 self.node = c.node() |
145 self.node = c.node() |
147 |
146 |
148 def kwsub(self, mobj): |
147 def _kwsub(self, mobj): |
149 '''Substitutes keyword using corresponding template.''' |
148 '''Substitutes keyword using corresponding template.''' |
150 kw = mobj.group(1) |
149 kw = mobj.group(1) |
151 self.t.use_template(self.templates[kw]) |
150 self.t.use_template(self.templates[kw]) |
152 self.ui.pushbuffer() |
151 self.ui.pushbuffer() |
153 self.t.show(changenode=self.node, root=self.repo.root, file=self.path) |
152 self.t.show(changenode=self.node, root=self.repo.root, file=self.path) |
156 |
155 |
157 def expand(self, node, data): |
156 def expand(self, node, data): |
158 '''Returns data with keywords expanded.''' |
157 '''Returns data with keywords expanded.''' |
159 if util.binary(data): |
158 if util.binary(data): |
160 return data |
159 return data |
161 self.ctxnode(node) |
160 self._ctxnode(node) |
162 return self.re_kw.sub(self.kwsub, data) |
161 return self.re_kw.sub(self._kwsub, data) |
163 |
162 |
164 def process(self, node, data): |
163 def process(self, node, data): |
165 '''Returns a tuple: data, count. |
164 '''Returns a tuple: data, count. |
166 Count is number of keywords/keyword substitutions. |
165 Count is number of keywords/keyword substitutions. |
167 Keywords in data are expanded, if templater was initialized.''' |
166 Keywords in data are expanded, if templater was initialized.''' |
168 if util.binary(data): |
167 if util.binary(data): |
169 return data, None |
168 return data, None |
170 if self.t: |
169 if self.t: |
171 self.ctxnode(node) |
170 self._ctxnode(node) |
172 return self.re_kw.subn(self.kwsub, data) |
171 return self.re_kw.subn(self._kwsub, data) |
173 return data, self.re_kw.search(data) |
172 return data, self.re_kw.search(data) |
174 |
173 |
175 def shrink(self, text): |
174 def shrink(self, text): |
176 '''Returns text with all keyword substitutions removed.''' |
175 '''Returns text with all keyword substitutions removed.''' |
177 if util.binary(text): |
176 if util.binary(text): |
278 |
277 |
279 |
278 |
280 def shrink(ui, repo, *args): |
279 def shrink(ui, repo, *args): |
281 '''revert expanded keywords in working directory |
280 '''revert expanded keywords in working directory |
282 |
281 |
283 run before: |
282 run before changing/disabling active keywords |
284 disabling keyword expansion |
283 or if you experience problems with "hg import" or "hg merge" |
285 changing keyword expansion configuration |
|
286 or if you experience problems with "hg import" |
|
287 ''' |
284 ''' |
288 expand = False |
285 expand = False |
289 _overwrite(ui, repo, args, expand) |
286 _overwrite(ui, repo, args, expand) |
290 |
287 |
291 def expand(ui, repo, *args): |
288 def expand(ui, repo, *args): |
319 ui.setconfig('keywordmaps', k.strip(), v.strip()) |
316 ui.setconfig('keywordmaps', k.strip(), v.strip()) |
320 if opts['rcfile']: |
317 if opts['rcfile']: |
321 ui.readconfig(opts['rcfile']) |
318 ui.readconfig(opts['rcfile']) |
322 kwmaps = (dict(ui.configitems('keywordmaps')) or |
319 kwmaps = (dict(ui.configitems('keywordmaps')) or |
323 kwtemplater.deftemplates) |
320 kwtemplater.deftemplates) |
|
321 for k, v in ui.configitems('extensions'): |
|
322 if k.endswith('keyword'): |
|
323 extension = '%s = %s' % (k, v) |
|
324 break |
324 tmpdir = tempfile.mkdtemp('', 'kwdemo.') |
325 tmpdir = tempfile.mkdtemp('', 'kwdemo.') |
325 ui.note(_('creating temporary repo at %s\n') % tmpdir) |
326 ui.note(_('creating temporary repo at %s\n') % tmpdir) |
326 repo = localrepo.localrepository(ui, path=tmpdir, create=True) |
327 repo = localrepo.localrepository(ui, path=tmpdir, create=True) |
327 repo.ui = ui # backwards compatibility |
328 repo.ui = ui # backwards compatibility |
328 reposetup(ui, repo) |
329 reposetup(ui, repo) |
329 ui.status(_('config with %s keyword template maps:\n') % kwstatus) |
330 ui.status(_('config using %s keyword template maps:\n') % kwstatus) |
330 ui.write('[keyword]\n%s =\n[keywordmaps]\n' % fn) |
331 ui.write('[extensions]\n%s\n' |
|
332 '[keyword]\n%s =\n' |
|
333 '[keywordmaps]\n' % (extension, fn)) |
331 for k, v in kwmaps.items(): |
334 for k, v in kwmaps.items(): |
332 ui.write('%s = %s\n' % (k, v)) |
335 ui.write('%s = %s\n' % (k, v)) |
333 path = repo.wjoin(fn) |
336 path = repo.wjoin(fn) |
334 keywords = '$' + '$\n$'.join(kwmaps.keys()) + '$\n' |
337 keywords = '$' + '$\n$'.join(kwmaps.keys()) + '$\n' |
335 repo.wopener(fn, 'w').write(keywords) |
338 repo.wopener(fn, 'w').write(keywords) |