82 |
82 |
83 from mercurial import commands, cmdutil, context, dispatch, filelog, revlog |
83 from mercurial import commands, cmdutil, context, dispatch, filelog, revlog |
84 from mercurial import patch, localrepo, templater, templatefilters, util |
84 from mercurial import patch, localrepo, templater, templatefilters, util |
85 from mercurial.node import * |
85 from mercurial.node import * |
86 from mercurial.i18n import _ |
86 from mercurial.i18n import _ |
87 import re, shutil, sys, tempfile, time |
87 import re, shutil, tempfile, time |
88 |
88 |
89 commands.optionalrepo += ' kwdemo' |
89 commands.optionalrepo += ' kwdemo' |
90 |
90 |
91 # hg commands that do not act on keywords |
91 # hg commands that do not act on keywords |
92 nokwcommands = ('add addremove bundle copy export grep identify incoming init' |
92 nokwcommands = ('add addremove bundle copy export grep identify incoming init' |
99 def utcdate(date): |
99 def utcdate(date): |
100 '''Returns hgdate in cvs-like UTC format.''' |
100 '''Returns hgdate in cvs-like UTC format.''' |
101 return time.strftime('%Y/%m/%d %H:%M:%S', time.gmtime(date[0])) |
101 return time.strftime('%Y/%m/%d %H:%M:%S', time.gmtime(date[0])) |
102 |
102 |
103 |
103 |
104 _kwtemplater = None |
104 _kwtemplater, _cmd, _cmdoptions = None, None, None |
|
105 |
|
106 # store originals of monkeypatches |
|
107 _patchfile_init = patch.patchfile.__init__ |
|
108 _dispatch_parse = dispatch._parse |
|
109 |
|
110 def _kwpatchfile_init(self, ui, fname, missing=False): |
|
111 '''Monkeypatch/wrap patch.patchfile.__init__ to avoid |
|
112 rejects or conflicts due to expanded keywords in working dir.''' |
|
113 _patchfile_init(self, ui, fname, missing=missing) |
|
114 if _kwtemplater.matcher(self.fname): |
|
115 # shrink keywords read from working dir |
|
116 kwshrunk = _kwtemplater.shrink(''.join(self.lines)) |
|
117 self.lines = kwshrunk.splitlines(True) |
|
118 |
|
119 def _kwdispatch_parse(ui, args): |
|
120 '''Monkeypatch dispatch._parse to obtain |
|
121 current command and command options (global _cmd, _cmdoptions).''' |
|
122 global _cmd, _cmdoptions |
|
123 _cmd, func, args, options, _cmdoptions = _dispatch_parse(ui, args) |
|
124 return _cmd, func, args, options, _cmdoptions |
|
125 |
|
126 dispatch._parse = _kwdispatch_parse |
|
127 |
105 |
128 |
106 class kwtemplater(object): |
129 class kwtemplater(object): |
107 ''' |
130 ''' |
108 Sets up keyword templates, corresponding keyword regex, and |
131 Sets up keyword templates, corresponding keyword regex, and |
109 provides keyword substitution functions. |
132 provides keyword substitution functions. |
210 text = _kwtemplater.shrink(text) |
233 text = _kwtemplater.shrink(text) |
211 if self.renamed(node): |
234 if self.renamed(node): |
212 t2 = super(kwfilelog, self).read(node) |
235 t2 = super(kwfilelog, self).read(node) |
213 return t2 != text |
236 return t2 != text |
214 return revlog.revlog.cmp(self, node, text) |
237 return revlog.revlog.cmp(self, node, text) |
215 |
|
216 |
|
217 # store original patch.patchfile.__init__ |
|
218 _patchfile_init = patch.patchfile.__init__ |
|
219 |
|
220 def _kwpatchfile_init(self, ui, fname, missing=False): |
|
221 '''Monkeypatch/wrap patch.patchfile.__init__ to avoid |
|
222 rejects or conflicts due to expanded keywords in working dir.''' |
|
223 _patchfile_init(self, ui, fname, missing=missing) |
|
224 |
|
225 if _kwtemplater.matcher(self.fname): |
|
226 # shrink keywords read from working dir |
|
227 kwshrunk = _kwtemplater.shrink(''.join(self.lines)) |
|
228 self.lines = kwshrunk.splitlines(True) |
|
229 |
|
230 |
238 |
231 def _iskwfile(f, link): |
239 def _iskwfile(f, link): |
232 return not link(f) and _kwtemplater.matcher(f) |
240 return not link(f) and _kwtemplater.matcher(f) |
233 |
241 |
234 def _status(ui, repo, *pats, **opts): |
242 def _status(ui, repo, *pats, **opts): |
410 Wraps commit to overwrite configured files with updated |
418 Wraps commit to overwrite configured files with updated |
411 keyword substitutions. |
419 keyword substitutions. |
412 This is done for local repos only, and only if there are |
420 This is done for local repos only, and only if there are |
413 files configured at all for keyword substitution.''' |
421 files configured at all for keyword substitution.''' |
414 |
422 |
|
423 global _kwtemplater |
|
424 hgcmd, hgcmdopts = _cmd, _cmdoptions |
|
425 |
415 try: |
426 try: |
416 if (not repo.local() or '.hg' in repo.root.split('/') |
427 if (not repo.local() or hgcmd in nokwcommands.split() |
|
428 or '.hg' in repo.root.split('/') |
417 or repo._url.startswith('bundle:')): |
429 or repo._url.startswith('bundle:')): |
418 return |
430 return |
419 except AttributeError: |
431 except AttributeError: |
420 pass |
432 pass |
421 |
|
422 hgcmd, func, args, opts, cmdopts = dispatch._parse(ui, sys.argv[1:]) |
|
423 if hgcmd in nokwcommands.split(): |
|
424 return |
|
425 |
|
426 if hgcmd == 'diff': |
|
427 # only expand if comparing against working dir |
|
428 node1, node2 = cmdutil.revpair(repo, cmdopts.get('rev')) |
|
429 if node2 is not None: |
|
430 return |
|
431 # shrink if rev is not current node |
|
432 if node1 is not None and node1 != repo.changectx().node(): |
|
433 hgcmd = 'diff1' |
|
434 |
433 |
435 inc, exc = [], ['.hgtags', '.hg_archival.txt'] |
434 inc, exc = [], ['.hgtags', '.hg_archival.txt'] |
436 for pat, opt in ui.configitems('keyword'): |
435 for pat, opt in ui.configitems('keyword'): |
437 if opt != 'ignore': |
436 if opt != 'ignore': |
438 inc.append(pat) |
437 inc.append(pat) |
439 else: |
438 else: |
440 exc.append(pat) |
439 exc.append(pat) |
441 if not inc: |
440 if not inc: |
442 return |
441 return |
443 |
442 |
444 global _kwtemplater |
443 if hgcmd == 'diff': |
|
444 # only expand if comparing against working dir |
|
445 node1, node2 = cmdutil.revpair(repo, hgcmdopts.get('rev')) |
|
446 if node2 is not None: |
|
447 return |
|
448 # shrink if rev is not current node |
|
449 if node1 is not None and node1 != repo.changectx().node(): |
|
450 hgcmd = 'diff1' |
|
451 |
445 restrict = hgcmd in restricted.split() |
452 restrict = hgcmd in restricted.split() |
446 _kwtemplater = kwtemplater(ui, repo, inc, exc, restrict) |
453 _kwtemplater = kwtemplater(ui, repo, inc, exc, restrict) |
447 |
454 |
448 class kwrepo(repo.__class__): |
455 class kwrepo(repo.__class__): |
449 def file(self, f, kwmatch=False): |
456 def file(self, f, kwmatch=False): |