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