Mercurial > hg
comparison hgext/keyword.py @ 6115:8121e9d7bfd2
keyword: make main class and hg command accessible
Switch from global vars to top level dictionary.
Goal: make it easier for external tools (like tortoisehg)
to hook into keyword extension.
author | Christian Ebert <blacktrash@gmx.net> |
---|---|
date | Fri, 15 Feb 2008 18:36:28 +0100 |
parents | ee83510fe567 |
children | c74f1d9092f8 |
comparison
equal
deleted
inserted
replaced
6114:ee83510fe567 | 6115:8121e9d7bfd2 |
---|---|
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 = _cmd = None | 104 # make keyword tools accessible |
105 kwtools = {'templater': None, 'hgcmd': None} | |
105 | 106 |
106 # store originals of monkeypatches | 107 # store originals of monkeypatches |
107 _patchfile_init = patch.patchfile.__init__ | 108 _patchfile_init = patch.patchfile.__init__ |
108 _patch_diff = patch.diff | 109 _patch_diff = patch.diff |
109 _dispatch_parse = dispatch._parse | 110 _dispatch_parse = dispatch._parse |
111 def _kwpatchfile_init(self, ui, fname, missing=False): | 112 def _kwpatchfile_init(self, ui, fname, missing=False): |
112 '''Monkeypatch/wrap patch.patchfile.__init__ to avoid | 113 '''Monkeypatch/wrap patch.patchfile.__init__ to avoid |
113 rejects or conflicts due to expanded keywords in working dir.''' | 114 rejects or conflicts due to expanded keywords in working dir.''' |
114 _patchfile_init(self, ui, fname, missing=missing) | 115 _patchfile_init(self, ui, fname, missing=missing) |
115 # shrink keywords read from working dir | 116 # shrink keywords read from working dir |
116 self.lines = _kwtemplater.shrinklines(self.fname, self.lines) | 117 kwt = kwtools['templater'] |
118 self.lines = kwt.shrinklines(self.fname, self.lines) | |
117 | 119 |
118 def _kw_diff(repo, node1=None, node2=None, files=None, match=util.always, | 120 def _kw_diff(repo, node1=None, node2=None, files=None, match=util.always, |
119 fp=None, changes=None, opts=None): | 121 fp=None, changes=None, opts=None): |
120 # only expand if comparing against working dir | 122 '''Monkeypatch patch.diff to avoid expansion except when |
123 comparing against working dir.''' | |
121 if node2 is not None: | 124 if node2 is not None: |
122 _kwtemplater.matcher = util.never | 125 kwtools['templater'].matcher = util.never |
123 if node1 is not None and node1 != repo.changectx().node(): | 126 if node1 is not None and node1 != repo.changectx().node(): |
124 _kwtemplater.restrict = True | 127 kwtools['templater'].restrict = True |
125 _patch_diff(repo, node1=node1, node2=node2, files=files, match=match, | 128 _patch_diff(repo, node1=node1, node2=node2, files=files, match=match, |
126 fp=fp, changes=changes, opts=opts) | 129 fp=fp, changes=changes, opts=opts) |
127 | 130 |
128 def _kwweb_changeset(web, req, tmpl): | 131 def _kwweb_changeset(web, req, tmpl): |
129 '''Wraps webcommands.changeset turning off keyword expansion.''' | 132 '''Wraps webcommands.changeset turning off keyword expansion.''' |
130 _kwtemplater.matcher = util.never | 133 kwtools['templater'].matcher = util.never |
131 return web.changeset(tmpl, web.changectx(req)) | 134 return web.changeset(tmpl, web.changectx(req)) |
132 | 135 |
133 def _kwweb_filediff(web, req, tmpl): | 136 def _kwweb_filediff(web, req, tmpl): |
134 '''Wraps webcommands.filediff turning off keyword expansion.''' | 137 '''Wraps webcommands.filediff turning off keyword expansion.''' |
135 _kwtemplater.matcher = util.never | 138 kwtools['templater'].matcher = util.never |
136 return web.filediff(tmpl, web.filectx(req)) | 139 return web.filediff(tmpl, web.filectx(req)) |
137 | 140 |
138 def _kwdispatch_parse(ui, args): | 141 def _kwdispatch_parse(ui, args): |
139 '''Monkeypatch dispatch._parse to obtain running hg command.''' | 142 '''Monkeypatch dispatch._parse to obtain running hg command.''' |
140 global _cmd | 143 cmd, func, args, options, cmdoptions = _dispatch_parse(ui, args) |
141 _cmd, func, args, options, cmdoptions = _dispatch_parse(ui, args) | 144 kwtools['hgcmd'] = cmd |
142 return _cmd, func, args, options, cmdoptions | 145 return cmd, func, args, options, cmdoptions |
143 | 146 |
144 # dispatch._parse is run before reposetup, so wrap it here | 147 # dispatch._parse is run before reposetup, so wrap it here |
145 dispatch._parse = _kwdispatch_parse | 148 dispatch._parse = _kwdispatch_parse |
146 | 149 |
147 | 150 |
162 | 165 |
163 def __init__(self, ui, repo, inc, exc): | 166 def __init__(self, ui, repo, inc, exc): |
164 self.ui = ui | 167 self.ui = ui |
165 self.repo = repo | 168 self.repo = repo |
166 self.matcher = util.matcher(repo.root, inc=inc, exc=exc)[1] | 169 self.matcher = util.matcher(repo.root, inc=inc, exc=exc)[1] |
167 self.restrict = _cmd in restricted.split() | 170 self.restrict = kwtools['hgcmd'] in restricted.split() |
168 | 171 |
169 kwmaps = self.ui.configitems('keywordmaps') | 172 kwmaps = self.ui.configitems('keywordmaps') |
170 if kwmaps: # override default templates | 173 if kwmaps: # override default templates |
171 kwmaps = [(k, templater.parsestring(v, quoted=False)) | 174 kwmaps = [(k, templater.parsestring(v, quoted=False)) |
172 for (k, v) in kwmaps] | 175 for (k, v) in kwmaps] |
268 Subclass of filelog to hook into its read, add, cmp methods. | 271 Subclass of filelog to hook into its read, add, cmp methods. |
269 Keywords are "stored" unexpanded, and processed on reading. | 272 Keywords are "stored" unexpanded, and processed on reading. |
270 ''' | 273 ''' |
271 def __init__(self, opener, path): | 274 def __init__(self, opener, path): |
272 super(kwfilelog, self).__init__(opener, path) | 275 super(kwfilelog, self).__init__(opener, path) |
276 self.kwt = kwtools['templater'] | |
273 self.path = path | 277 self.path = path |
274 | 278 |
275 def read(self, node): | 279 def read(self, node): |
276 '''Expands keywords when reading filelog.''' | 280 '''Expands keywords when reading filelog.''' |
277 data = super(kwfilelog, self).read(node) | 281 data = super(kwfilelog, self).read(node) |
278 return _kwtemplater.expand(self.path, node, data) | 282 return self.kwt.expand(self.path, node, data) |
279 | 283 |
280 def add(self, text, meta, tr, link, p1=None, p2=None): | 284 def add(self, text, meta, tr, link, p1=None, p2=None): |
281 '''Removes keyword substitutions when adding to filelog.''' | 285 '''Removes keyword substitutions when adding to filelog.''' |
282 text = _kwtemplater.shrink(self.path, text) | 286 text = self.kwt.shrink(self.path, text) |
283 return super(kwfilelog, self).add(text, meta, tr, link, p1=p1, p2=p2) | 287 return super(kwfilelog, self).add(text, meta, tr, link, p1=p1, p2=p2) |
284 | 288 |
285 def cmp(self, node, text): | 289 def cmp(self, node, text): |
286 '''Removes keyword substitutions for comparison.''' | 290 '''Removes keyword substitutions for comparison.''' |
287 text = _kwtemplater.shrink(self.path, text) | 291 text = self.kwt.shrink(self.path, text) |
288 if self.renamed(node): | 292 if self.renamed(node): |
289 t2 = super(kwfilelog, self).read(node) | 293 t2 = super(kwfilelog, self).read(node) |
290 return t2 != text | 294 return t2 != text |
291 return revlog.revlog.cmp(self, node, text) | 295 return revlog.revlog.cmp(self, node, text) |
292 | 296 |
293 def _status(ui, repo, *pats, **opts): | 297 def _status(ui, repo, kwt, *pats, **opts): |
294 '''Bails out if [keyword] configuration is not active. | 298 '''Bails out if [keyword] configuration is not active. |
295 Returns status of working directory.''' | 299 Returns status of working directory.''' |
296 if _kwtemplater: | 300 if kwt: |
297 files, match, anypats = cmdutil.matchpats(repo, pats, opts) | 301 files, match, anypats = cmdutil.matchpats(repo, pats, opts) |
298 return repo.status(files=files, match=match, list_clean=True) | 302 return repo.status(files=files, match=match, list_clean=True) |
299 if ui.configitems('keyword'): | 303 if ui.configitems('keyword'): |
300 raise util.Abort(_('[keyword] patterns cannot match')) | 304 raise util.Abort(_('[keyword] patterns cannot match')) |
301 raise util.Abort(_('no [keyword] patterns configured')) | 305 raise util.Abort(_('no [keyword] patterns configured')) |
302 | 306 |
303 def _kwfwrite(ui, repo, expand, *pats, **opts): | 307 def _kwfwrite(ui, repo, expand, *pats, **opts): |
304 '''Selects files and passes them to kwtemplater.overwrite.''' | 308 '''Selects files and passes them to kwtemplater.overwrite.''' |
305 status = _status(ui, repo, *pats, **opts) | 309 kwt = kwtools['templater'] |
310 status = _status(ui, repo, kwt, *pats, **opts) | |
306 modified, added, removed, deleted, unknown, ignored, clean = status | 311 modified, added, removed, deleted, unknown, ignored, clean = status |
307 if modified or added or removed or deleted: | 312 if modified or added or removed or deleted: |
308 raise util.Abort(_('outstanding uncommitted changes in given files')) | 313 raise util.Abort(_('outstanding uncommitted changes in given files')) |
309 wlock = lock = None | 314 wlock = lock = None |
310 try: | 315 try: |
311 wlock = repo.wlock() | 316 wlock = repo.wlock() |
312 lock = repo.lock() | 317 lock = repo.lock() |
313 _kwtemplater.overwrite(expand=expand, files=clean) | 318 kwt.overwrite(expand=expand, files=clean) |
314 finally: | 319 finally: |
315 del wlock, lock | 320 del wlock, lock |
316 | 321 |
317 | 322 |
318 def demo(ui, repo, *args, **opts): | 323 def demo(ui, repo, *args, **opts): |
410 | 415 |
411 Crosscheck which files in working directory are potential targets for | 416 Crosscheck which files in working directory are potential targets for |
412 keyword expansion. | 417 keyword expansion. |
413 That is, files matched by [keyword] config patterns but not symlinks. | 418 That is, files matched by [keyword] config patterns but not symlinks. |
414 ''' | 419 ''' |
415 status = _status(ui, repo, *pats, **opts) | 420 kwt = kwtools['templater'] |
421 status = _status(ui, repo, kwt, *pats, **opts) | |
416 modified, added, removed, deleted, unknown, ignored, clean = status | 422 modified, added, removed, deleted, unknown, ignored, clean = status |
417 files = modified + added + clean | 423 files = modified + added + clean |
418 if opts.get('untracked'): | 424 if opts.get('untracked'): |
419 files += unknown | 425 files += unknown |
420 files.sort() | 426 files.sort() |
421 wctx = repo.workingctx() | 427 wctx = repo.workingctx() |
422 islink = lambda p: 'l' in wctx.fileflags(p) | 428 islink = lambda p: 'l' in wctx.fileflags(p) |
423 kwfiles = [f for f in files if _kwtemplater.iskwfile(f, islink)] | 429 kwfiles = [f for f in files if kwt.iskwfile(f, islink)] |
424 cwd = pats and repo.getcwd() or '' | 430 cwd = pats and repo.getcwd() or '' |
425 kwfstats = not opts.get('ignore') and (('K', kwfiles),) or () | 431 kwfstats = not opts.get('ignore') and (('K', kwfiles),) or () |
426 if opts.get('all') or opts.get('ignore'): | 432 if opts.get('all') or opts.get('ignore'): |
427 kwfstats += (('I', [f for f in files if f not in kwfiles]),) | 433 kwfstats += (('I', [f for f in files if f not in kwfiles]),) |
428 for char, filenames in kwfstats: | 434 for char, filenames in kwfstats: |
449 Wraps commit to overwrite configured files with updated | 455 Wraps commit to overwrite configured files with updated |
450 keyword substitutions. | 456 keyword substitutions. |
451 This is done for local repos only, and only if there are | 457 This is done for local repos only, and only if there are |
452 files configured at all for keyword substitution.''' | 458 files configured at all for keyword substitution.''' |
453 | 459 |
454 global _kwtemplater | |
455 | |
456 try: | 460 try: |
457 if (not repo.local() or _cmd in nokwcommands.split() | 461 if (not repo.local() or kwtools['hgcmd'] in nokwcommands.split() |
458 or '.hg' in util.splitpath(repo.root) | 462 or '.hg' in util.splitpath(repo.root) |
459 or repo._url.startswith('bundle:')): | 463 or repo._url.startswith('bundle:')): |
460 return | 464 return |
461 except AttributeError: | 465 except AttributeError: |
462 pass | 466 pass |
468 else: | 472 else: |
469 exc.append(pat) | 473 exc.append(pat) |
470 if not inc: | 474 if not inc: |
471 return | 475 return |
472 | 476 |
473 _kwtemplater = kwtemplater(ui, repo, inc, exc) | 477 kwtools['templater'] = kwt = kwtemplater(ui, repo, inc, exc) |
474 | 478 |
475 class kwrepo(repo.__class__): | 479 class kwrepo(repo.__class__): |
476 def file(self, f): | 480 def file(self, f): |
477 if f[0] == '/': | 481 if f[0] == '/': |
478 f = f[1:] | 482 f = f[1:] |
479 return kwfilelog(self.sopener, f) | 483 return kwfilelog(self.sopener, f) |
480 | 484 |
481 def wread(self, filename): | 485 def wread(self, filename): |
482 data = super(kwrepo, self).wread(filename) | 486 data = super(kwrepo, self).wread(filename) |
483 return _kwtemplater.wread(filename, data) | 487 return kwt.wread(filename, data) |
484 | 488 |
485 def commit(self, files=None, text='', user=None, date=None, | 489 def commit(self, files=None, text='', user=None, date=None, |
486 match=util.always, force=False, force_editor=False, | 490 match=util.always, force=False, force_editor=False, |
487 p1=None, p2=None, extra={}, empty_ok=False): | 491 p1=None, p2=None, extra={}, empty_ok=False): |
488 wlock = lock = None | 492 wlock = lock = None |
517 | 521 |
518 # restore commit hooks | 522 # restore commit hooks |
519 for name, cmd in commithooks.iteritems(): | 523 for name, cmd in commithooks.iteritems(): |
520 ui.setconfig('hooks', name, cmd) | 524 ui.setconfig('hooks', name, cmd) |
521 if node is not None: | 525 if node is not None: |
522 _kwtemplater.overwrite(node=node) | 526 kwt.overwrite(node=node) |
523 repo.hook('commit', node=node, parent1=_p1, parent2=_p2) | 527 repo.hook('commit', node=node, parent1=_p1, parent2=_p2) |
524 return node | 528 return node |
525 finally: | 529 finally: |
526 del wlock, lock | 530 del wlock, lock |
527 | 531 |