69 the risk of inadvertedly storing expanded keywords in the change history. |
69 the risk of inadvertedly storing expanded keywords in the change history. |
70 |
70 |
71 To force expansion after enabling it, or a configuration change, run |
71 To force expansion after enabling it, or a configuration change, run |
72 "hg kwexpand". |
72 "hg kwexpand". |
73 |
73 |
|
74 Also, when committing with the record extension or using mq's qrecord, be aware |
|
75 that keywords cannot be updated. Again, run "hg kwexpand" on the files in |
|
76 question to update keyword expansions after all changes have been checked in. |
|
77 |
74 Expansions spanning more than one line and incremental expansions, |
78 Expansions spanning more than one line and incremental expansions, |
75 like CVS' $Log$, are not supported. A keyword template map |
79 like CVS' $Log$, are not supported. A keyword template map |
76 "Log = {desc}" expands to the first line of the changeset description. |
80 "Log = {desc}" expands to the first line of the changeset description. |
77 ''' |
81 ''' |
78 |
82 |
79 from mercurial import commands, cmdutil, context, fancyopts, filelog |
83 from mercurial import commands, cmdutil, context, dispatch, filelog |
80 from mercurial import patch, localrepo, revlog, templater, util |
84 from mercurial import patch, localrepo, revlog, templater, util |
81 from mercurial.node import * |
85 from mercurial.node import * |
82 from mercurial.i18n import _ |
86 from mercurial.i18n import _ |
83 import re, shutil, sys, tempfile, time |
87 import re, shutil, sys, tempfile, time |
84 |
88 |
85 commands.optionalrepo += ' kwdemo' |
89 commands.optionalrepo += ' kwdemo' |
86 |
90 |
87 def utcdate(date): |
91 def utcdate(date): |
88 '''Returns hgdate in cvs-like UTC format.''' |
92 '''Returns hgdate in cvs-like UTC format.''' |
89 return time.strftime('%Y/%m/%d %H:%M:%S', time.gmtime(date[0])) |
93 return time.strftime('%Y/%m/%d %H:%M:%S', time.gmtime(date[0])) |
|
94 |
|
95 def _kwrestrict(cmd): |
|
96 '''Returns True if cmd should trigger restricted expansion. |
|
97 Keywords will only expanded when writing to working dir. |
|
98 Crucial for mq as expanded keywords should not make it into patches.''' |
|
99 return cmd in ('qimport', 'qnew', 'qpush', 'qrefresh', 'record', 'qrecord') |
|
100 |
90 |
101 |
91 _kwtemplater = None |
102 _kwtemplater = None |
92 |
103 |
93 class kwtemplater(object): |
104 class kwtemplater(object): |
94 ''' |
105 ''' |
103 'Source': '{root}/{file},v', |
114 'Source': '{root}/{file},v', |
104 'Id': '{file|basename},v {node|short} {date|utcdate} {author|user}', |
115 'Id': '{file|basename},v {node|short} {date|utcdate} {author|user}', |
105 'Header': '{root}/{file},v {node|short} {date|utcdate} {author|user}', |
116 'Header': '{root}/{file},v {node|short} {date|utcdate} {author|user}', |
106 } |
117 } |
107 |
118 |
108 def __init__(self, ui, repo, inc, exc): |
119 def __init__(self, ui, repo, inc, exc, hgcmd): |
109 self.ui = ui |
120 self.ui = ui |
110 self.repo = repo |
121 self.repo = repo |
111 self.matcher = util.matcher(repo.root, inc=inc, exc=exc)[1] |
122 self.matcher = util.matcher(repo.root, inc=inc, exc=exc)[1] |
|
123 self.hgcmd = hgcmd |
112 self.commitnode = None |
124 self.commitnode = None |
113 self.path = '' |
125 self.path = '' |
114 |
126 |
115 kwmaps = self.ui.configitems('keywordmaps') |
127 kwmaps = self.ui.configitems('keywordmaps') |
116 if kwmaps: # override default templates |
128 if kwmaps: # override default templates |
144 |
156 |
145 return subfunc(kwsub, data) |
157 return subfunc(kwsub, data) |
146 |
158 |
147 def expand(self, node, data): |
159 def expand(self, node, data): |
148 '''Returns data with keywords expanded.''' |
160 '''Returns data with keywords expanded.''' |
149 if util.binary(data): |
161 if util.binary(data) or _kwrestrict(self.hgcmd): |
150 return data |
162 return data |
151 return self.substitute(node, data, self.re_kw.sub) |
163 return self.substitute(node, data, self.re_kw.sub) |
152 |
164 |
153 def process(self, node, data, expand): |
165 def process(self, node, data, expand): |
154 '''Returns a tuple: data, count. |
166 '''Returns a tuple: data, count. |
395 Wraps commit to overwrite configured files with updated |
407 Wraps commit to overwrite configured files with updated |
396 keyword substitutions. |
408 keyword substitutions. |
397 This is done for local repos only, and only if there are |
409 This is done for local repos only, and only if there are |
398 files configured at all for keyword substitution.''' |
410 files configured at all for keyword substitution.''' |
399 |
411 |
400 def kwbailout(): |
412 if not repo.local(): |
401 '''Obtains command via simplified cmdline parsing, |
413 return |
402 returns True if keyword expansion not needed.''' |
414 |
403 nokwcommands = ('add', 'addremove', 'bundle', 'clone', 'copy', |
415 nokwcommands = ('add', 'addremove', 'bundle', 'clone', 'copy', |
404 'export', 'grep', 'identify', 'incoming', 'init', |
416 'export', 'grep', 'identify', 'incoming', 'init', |
405 'log', 'outgoing', 'push', 'remove', 'rename', |
417 'log', 'outgoing', 'push', 'remove', 'rename', |
406 'rollback', 'tip', |
418 'rollback', 'tip', |
407 'convert') |
419 'convert') |
408 args = fancyopts.fancyopts(sys.argv[1:], commands.globalopts, {}) |
420 hgcmd, func, args, opts, cmdopts = dispatch._parse(ui, sys.argv[1:]) |
409 if args: |
421 if hgcmd in nokwcommands: |
410 aliases, i = cmdutil.findcmd(ui, args[0], commands.table) |
|
411 return aliases[0] in nokwcommands |
|
412 |
|
413 if not repo.local() or kwbailout(): |
|
414 return |
422 return |
415 |
423 |
416 inc, exc = [], ['.hgtags'] |
424 inc, exc = [], ['.hgtags'] |
417 for pat, opt in ui.configitems('keyword'): |
425 for pat, opt in ui.configitems('keyword'): |
418 if opt != 'ignore': |
426 if opt != 'ignore': |
421 exc.append(pat) |
429 exc.append(pat) |
422 if not inc: |
430 if not inc: |
423 return |
431 return |
424 |
432 |
425 global _kwtemplater |
433 global _kwtemplater |
426 _kwtemplater = kwtemplater(ui, repo, inc, exc) |
434 _kwtemplater = kwtemplater(ui, repo, inc, exc, hgcmd) |
427 |
435 |
428 class kwrepo(repo.__class__): |
436 class kwrepo(repo.__class__): |
429 def file(self, f, kwmatch=False): |
437 def file(self, f, kwmatch=False): |
430 if f[0] == '/': |
438 if f[0] == '/': |
431 f = f[1:] |
439 f = f[1:] |
432 if kwmatch or _kwtemplater.matcher(f): |
440 if kwmatch or _kwtemplater.matcher(f): |
433 return kwfilelog(self.sopener, f) |
441 return kwfilelog(self.sopener, f) |
434 return filelog.filelog(self.sopener, f) |
442 return filelog.filelog(self.sopener, f) |
|
443 |
|
444 def wread(self, filename): |
|
445 data = super(kwrepo, self).wread(filename) |
|
446 if _kwrestrict(hgcmd) and _kwtemplater.matcher(filename): |
|
447 return _kwtemplater.shrink(data) |
|
448 return data |
435 |
449 |
436 def commit(self, files=None, text='', user=None, date=None, |
450 def commit(self, files=None, text='', user=None, date=None, |
437 match=util.always, force=False, force_editor=False, |
451 match=util.always, force=False, force_editor=False, |
438 p1=None, p2=None, extra={}): |
452 p1=None, p2=None, extra={}): |
439 wlock = lock = None |
453 wlock = lock = None |