##// END OF EJS Templates
keyword: add extra datefilters in a single update call
Christian Ebert -
r11616:fda0e478 default
parent child Browse files
Show More
@@ -1,576 +1,576 b''
1 1 # keyword.py - $Keyword$ expansion for Mercurial
2 2 #
3 3 # Copyright 2007-2010 Christian Ebert <blacktrash@gmx.net>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7 #
8 8 # $Id$
9 9 #
10 10 # Keyword expansion hack against the grain of a DSCM
11 11 #
12 12 # There are many good reasons why this is not needed in a distributed
13 13 # SCM, still it may be useful in very small projects based on single
14 14 # files (like LaTeX packages), that are mostly addressed to an
15 15 # audience not running a version control system.
16 16 #
17 17 # For in-depth discussion refer to
18 18 # <http://mercurial.selenic.com/wiki/KeywordPlan>.
19 19 #
20 20 # Keyword expansion is based on Mercurial's changeset template mappings.
21 21 #
22 22 # Binary files are not touched.
23 23 #
24 24 # Files to act upon/ignore are specified in the [keyword] section.
25 25 # Customized keyword template mappings in the [keywordmaps] section.
26 26 #
27 27 # Run "hg help keyword" and "hg kwdemo" to get info on configuration.
28 28
29 29 '''expand keywords in tracked files
30 30
31 31 This extension expands RCS/CVS-like or self-customized $Keywords$ in
32 32 tracked text files selected by your configuration.
33 33
34 34 Keywords are only expanded in local repositories and not stored in the
35 35 change history. The mechanism can be regarded as a convenience for the
36 36 current user or for archive distribution.
37 37
38 38 Configuration is done in the [keyword], [keywordset] and [keywordmaps]
39 39 sections of hgrc files.
40 40
41 41 Example::
42 42
43 43 [keyword]
44 44 # expand keywords in every python file except those matching "x*"
45 45 **.py =
46 46 x* = ignore
47 47
48 48 [keywordset]
49 49 # prefer svn- over cvs-like default keywordmaps
50 50 svn = True
51 51
52 52 NOTE: the more specific you are in your filename patterns the less you
53 53 lose speed in huge repositories.
54 54
55 55 For [keywordmaps] template mapping and expansion demonstration and
56 56 control run :hg:`kwdemo`. See :hg:`help templates` for a list of
57 57 available templates and filters.
58 58
59 59 Three additional date template filters are provided::
60 60
61 61 utcdate "2006/09/18 15:13:13"
62 62 svnutcdate "2006-09-18 15:13:13Z"
63 63 svnisodate "2006-09-18 08:13:13 -700 (Mon, 18 Sep 2006)"
64 64
65 65 The default template mappings (view with :hg:`kwdemo -d`) can be
66 66 replaced with customized keywords and templates. Again, run
67 67 :hg:`kwdemo` to control the results of your config changes.
68 68
69 69 Before changing/disabling active keywords, run :hg:`kwshrink` to avoid
70 70 the risk of inadvertently storing expanded keywords in the change
71 71 history.
72 72
73 73 To force expansion after enabling it, or a configuration change, run
74 74 :hg:`kwexpand`.
75 75
76 76 Expansions spanning more than one line and incremental expansions,
77 77 like CVS' $Log$, are not supported. A keyword template map "Log =
78 78 {desc}" expands to the first line of the changeset description.
79 79 '''
80 80
81 81 from mercurial import commands, cmdutil, dispatch, filelog, revlog, extensions
82 82 from mercurial import patch, localrepo, templater, templatefilters, util, match
83 83 from mercurial.hgweb import webcommands
84 84 from mercurial.i18n import _
85 85 import re, shutil, tempfile
86 86
87 87 commands.optionalrepo += ' kwdemo'
88 88
89 89 # hg commands that do not act on keywords
90 90 nokwcommands = ('add addremove annotate bundle copy export grep incoming init'
91 91 ' log outgoing push rename rollback tip verify'
92 92 ' convert email glog')
93 93
94 94 # hg commands that trigger expansion only when writing to working dir,
95 95 # not when reading filelog, and unexpand when reading from working dir
96 96 restricted = 'merge record qrecord resolve transplant'
97 97
98 98 # commands using dorecord
99 99 recordcommands = 'record qrecord'
100 100 # names of extensions using dorecord
101 101 recordextensions = 'record'
102 102
103 103 # date like in cvs' $Date
104 104 utcdate = lambda x: util.datestr((x[0], 0), '%Y/%m/%d %H:%M:%S')
105 105 # date like in svn's $Date
106 106 svnisodate = lambda x: util.datestr(x, '%Y-%m-%d %H:%M:%S %1%2 (%a, %d %b %Y)')
107 107 # date like in svn's $Id
108 108 svnutcdate = lambda x: util.datestr((x[0], 0), '%Y-%m-%d %H:%M:%SZ')
109 109
110 110 # make keyword tools accessible
111 111 kwtools = {'templater': None, 'hgcmd': '', 'inc': [], 'exc': ['.hg*']}
112 112
113 113
114 114 def _defaultkwmaps(ui):
115 115 '''Returns default keywordmaps according to keywordset configuration.'''
116 116 templates = {
117 117 'Revision': '{node|short}',
118 118 'Author': '{author|user}',
119 119 }
120 120 kwsets = ({
121 121 'Date': '{date|utcdate}',
122 122 'RCSfile': '{file|basename},v',
123 123 'RCSFile': '{file|basename},v', # kept for backwards compatibility
124 124 # with hg-keyword
125 125 'Source': '{root}/{file},v',
126 126 'Id': '{file|basename},v {node|short} {date|utcdate} {author|user}',
127 127 'Header': '{root}/{file},v {node|short} {date|utcdate} {author|user}',
128 128 }, {
129 129 'Date': '{date|svnisodate}',
130 130 'Id': '{file|basename},v {node|short} {date|svnutcdate} {author|user}',
131 131 'LastChangedRevision': '{node|short}',
132 132 'LastChangedBy': '{author|user}',
133 133 'LastChangedDate': '{date|svnisodate}',
134 134 })
135 135 templates.update(kwsets[ui.configbool('keywordset', 'svn')])
136 136 return templates
137 137
138 138 class kwtemplater(object):
139 139 '''
140 140 Sets up keyword templates, corresponding keyword regex, and
141 141 provides keyword substitution functions.
142 142 '''
143 143
144 144 def __init__(self, ui, repo):
145 145 self.ui = ui
146 146 self.repo = repo
147 147 self.match = match.match(repo.root, '', [],
148 148 kwtools['inc'], kwtools['exc'])
149 149 self.restrict = kwtools['hgcmd'] in restricted.split()
150 150 self.record = kwtools['hgcmd'] in recordcommands.split()
151 151
152 152 kwmaps = self.ui.configitems('keywordmaps')
153 153 if kwmaps: # override default templates
154 154 self.templates = dict((k, templater.parsestring(v, False))
155 155 for k, v in kwmaps)
156 156 else:
157 157 self.templates = _defaultkwmaps(self.ui)
158 158 escaped = map(re.escape, self.templates.keys())
159 159 kwpat = r'\$(%s)(: [^$\n\r]*? )??\$' % '|'.join(escaped)
160 160 self.re_kw = re.compile(kwpat)
161 161
162 templatefilters.filters['utcdate'] = utcdate
163 templatefilters.filters['svnisodate'] = svnisodate
164 templatefilters.filters['svnutcdate'] = svnutcdate
162 templatefilters.filters.update({'utcdate': utcdate,
163 'svnisodate': svnisodate,
164 'svnutcdate': svnutcdate})
165 165
166 166 def substitute(self, data, path, ctx, subfunc):
167 167 '''Replaces keywords in data with expanded template.'''
168 168 def kwsub(mobj):
169 169 kw = mobj.group(1)
170 170 ct = cmdutil.changeset_templater(self.ui, self.repo,
171 171 False, None, '', False)
172 172 ct.use_template(self.templates[kw])
173 173 self.ui.pushbuffer()
174 174 ct.show(ctx, root=self.repo.root, file=path)
175 175 ekw = templatefilters.firstline(self.ui.popbuffer())
176 176 return '$%s: %s $' % (kw, ekw)
177 177 return subfunc(kwsub, data)
178 178
179 179 def expand(self, path, node, data):
180 180 '''Returns data with keywords expanded.'''
181 181 if not self.restrict and self.match(path) and not util.binary(data):
182 182 ctx = self.repo.filectx(path, fileid=node).changectx()
183 183 return self.substitute(data, path, ctx, self.re_kw.sub)
184 184 return data
185 185
186 186 def iskwfile(self, path, flagfunc):
187 187 '''Returns true if path matches [keyword] pattern
188 188 and is not a symbolic link.
189 189 Caveat: localrepository._link fails on Windows.'''
190 190 return self.match(path) and not 'l' in flagfunc(path)
191 191
192 192 def overwrite(self, ctx, candidates, iswctx, expand):
193 193 '''Overwrites selected files expanding/shrinking keywords.'''
194 194 if self.record:
195 195 candidates = [f for f in ctx.files() if f in ctx]
196 196 candidates = [f for f in candidates if self.iskwfile(f, ctx.flags)]
197 197 if candidates:
198 198 self.restrict = True # do not expand when reading
199 199 mf = ctx.manifest()
200 200 msg = (expand and _('overwriting %s expanding keywords\n')
201 201 or _('overwriting %s shrinking keywords\n'))
202 202 for f in candidates:
203 203 if not self.record:
204 204 data = self.repo.file(f).read(mf[f])
205 205 else:
206 206 data = self.repo.wread(f)
207 207 if util.binary(data):
208 208 continue
209 209 if expand:
210 210 if iswctx:
211 211 ctx = self.repo.filectx(f, fileid=mf[f]).changectx()
212 212 data, found = self.substitute(data, f, ctx,
213 213 self.re_kw.subn)
214 214 else:
215 215 found = self.re_kw.search(data)
216 216 if found:
217 217 self.ui.note(msg % f)
218 218 self.repo.wwrite(f, data, mf.flags(f))
219 219 if iswctx:
220 220 self.repo.dirstate.normal(f)
221 221 elif self.record:
222 222 self.repo.dirstate.normallookup(f)
223 223 self.restrict = False
224 224
225 225 def shrinktext(self, text):
226 226 '''Unconditionally removes all keyword substitutions from text.'''
227 227 return self.re_kw.sub(r'$\1$', text)
228 228
229 229 def shrink(self, fname, text):
230 230 '''Returns text with all keyword substitutions removed.'''
231 231 if self.match(fname) and not util.binary(text):
232 232 return self.shrinktext(text)
233 233 return text
234 234
235 235 def shrinklines(self, fname, lines):
236 236 '''Returns lines with keyword substitutions removed.'''
237 237 if self.match(fname):
238 238 text = ''.join(lines)
239 239 if not util.binary(text):
240 240 return self.shrinktext(text).splitlines(True)
241 241 return lines
242 242
243 243 def wread(self, fname, data):
244 244 '''If in restricted mode returns data read from wdir with
245 245 keyword substitutions removed.'''
246 246 return self.restrict and self.shrink(fname, data) or data
247 247
248 248 class kwfilelog(filelog.filelog):
249 249 '''
250 250 Subclass of filelog to hook into its read, add, cmp methods.
251 251 Keywords are "stored" unexpanded, and processed on reading.
252 252 '''
253 253 def __init__(self, opener, kwt, path):
254 254 super(kwfilelog, self).__init__(opener, path)
255 255 self.kwt = kwt
256 256 self.path = path
257 257
258 258 def read(self, node):
259 259 '''Expands keywords when reading filelog.'''
260 260 data = super(kwfilelog, self).read(node)
261 261 return self.kwt.expand(self.path, node, data)
262 262
263 263 def add(self, text, meta, tr, link, p1=None, p2=None):
264 264 '''Removes keyword substitutions when adding to filelog.'''
265 265 text = self.kwt.shrink(self.path, text)
266 266 return super(kwfilelog, self).add(text, meta, tr, link, p1, p2)
267 267
268 268 def cmp(self, node, text):
269 269 '''Removes keyword substitutions for comparison.'''
270 270 text = self.kwt.shrink(self.path, text)
271 271 if self.renamed(node):
272 272 t2 = super(kwfilelog, self).read(node)
273 273 return t2 != text
274 274 return revlog.revlog.cmp(self, node, text)
275 275
276 276 def _status(ui, repo, kwt, *pats, **opts):
277 277 '''Bails out if [keyword] configuration is not active.
278 278 Returns status of working directory.'''
279 279 if kwt:
280 280 return repo.status(match=cmdutil.match(repo, pats, opts), clean=True,
281 281 unknown=opts.get('unknown') or opts.get('all'))
282 282 if ui.configitems('keyword'):
283 283 raise util.Abort(_('[keyword] patterns cannot match'))
284 284 raise util.Abort(_('no [keyword] patterns configured'))
285 285
286 286 def _kwfwrite(ui, repo, expand, *pats, **opts):
287 287 '''Selects files and passes them to kwtemplater.overwrite.'''
288 288 wctx = repo[None]
289 289 if len(wctx.parents()) > 1:
290 290 raise util.Abort(_('outstanding uncommitted merge'))
291 291 kwt = kwtools['templater']
292 292 wlock = repo.wlock()
293 293 try:
294 294 status = _status(ui, repo, kwt, *pats, **opts)
295 295 modified, added, removed, deleted, unknown, ignored, clean = status
296 296 if modified or added or removed or deleted:
297 297 raise util.Abort(_('outstanding uncommitted changes'))
298 298 kwt.overwrite(wctx, clean, True, expand)
299 299 finally:
300 300 wlock.release()
301 301
302 302 def demo(ui, repo, *args, **opts):
303 303 '''print [keywordmaps] configuration and an expansion example
304 304
305 305 Show current, custom, or default keyword template maps and their
306 306 expansions.
307 307
308 308 Extend the current configuration by specifying maps as arguments
309 309 and using -f/--rcfile to source an external hgrc file.
310 310
311 311 Use -d/--default to disable current configuration.
312 312
313 313 See :hg:`help templates` for information on templates and filters.
314 314 '''
315 315 def demoitems(section, items):
316 316 ui.write('[%s]\n' % section)
317 317 for k, v in sorted(items):
318 318 ui.write('%s = %s\n' % (k, v))
319 319
320 320 fn = 'demo.txt'
321 321 tmpdir = tempfile.mkdtemp('', 'kwdemo.')
322 322 ui.note(_('creating temporary repository at %s\n') % tmpdir)
323 323 repo = localrepo.localrepository(ui, tmpdir, True)
324 324 ui.setconfig('keyword', fn, '')
325 325
326 326 uikwmaps = ui.configitems('keywordmaps')
327 327 if args or opts.get('rcfile'):
328 328 ui.status(_('\n\tconfiguration using custom keyword template maps\n'))
329 329 if uikwmaps:
330 330 ui.status(_('\textending current template maps\n'))
331 331 if opts.get('default') or not uikwmaps:
332 332 ui.status(_('\toverriding default template maps\n'))
333 333 if opts.get('rcfile'):
334 334 ui.readconfig(opts.get('rcfile'))
335 335 if args:
336 336 # simulate hgrc parsing
337 337 rcmaps = ['[keywordmaps]\n'] + [a + '\n' for a in args]
338 338 fp = repo.opener('hgrc', 'w')
339 339 fp.writelines(rcmaps)
340 340 fp.close()
341 341 ui.readconfig(repo.join('hgrc'))
342 342 kwmaps = dict(ui.configitems('keywordmaps'))
343 343 elif opts.get('default'):
344 344 ui.status(_('\n\tconfiguration using default keyword template maps\n'))
345 345 kwmaps = _defaultkwmaps(ui)
346 346 if uikwmaps:
347 347 ui.status(_('\tdisabling current template maps\n'))
348 348 for k, v in kwmaps.iteritems():
349 349 ui.setconfig('keywordmaps', k, v)
350 350 else:
351 351 ui.status(_('\n\tconfiguration using current keyword template maps\n'))
352 352 kwmaps = dict(uikwmaps) or _defaultkwmaps(ui)
353 353
354 354 uisetup(ui)
355 355 reposetup(ui, repo)
356 356 ui.write('[extensions]\nkeyword =\n')
357 357 demoitems('keyword', ui.configitems('keyword'))
358 358 demoitems('keywordmaps', kwmaps.iteritems())
359 359 keywords = '$' + '$\n$'.join(sorted(kwmaps.keys())) + '$\n'
360 360 repo.wopener(fn, 'w').write(keywords)
361 361 repo[None].add([fn])
362 362 ui.note(_('\nkeywords written to %s:\n') % fn)
363 363 ui.note(keywords)
364 364 repo.dirstate.setbranch('demobranch')
365 365 for name, cmd in ui.configitems('hooks'):
366 366 if name.split('.', 1)[0].find('commit') > -1:
367 367 repo.ui.setconfig('hooks', name, '')
368 368 msg = _('hg keyword configuration and expansion example')
369 369 ui.note("hg ci -m '%s'\n" % msg)
370 370 repo.commit(text=msg)
371 371 ui.status(_('\n\tkeywords expanded\n'))
372 372 ui.write(repo.wread(fn))
373 373 shutil.rmtree(tmpdir, ignore_errors=True)
374 374
375 375 def expand(ui, repo, *pats, **opts):
376 376 '''expand keywords in the working directory
377 377
378 378 Run after (re)enabling keyword expansion.
379 379
380 380 kwexpand refuses to run if given files contain local changes.
381 381 '''
382 382 # 3rd argument sets expansion to True
383 383 _kwfwrite(ui, repo, True, *pats, **opts)
384 384
385 385 def files(ui, repo, *pats, **opts):
386 386 '''show files configured for keyword expansion
387 387
388 388 List which files in the working directory are matched by the
389 389 [keyword] configuration patterns.
390 390
391 391 Useful to prevent inadvertent keyword expansion and to speed up
392 392 execution by including only files that are actual candidates for
393 393 expansion.
394 394
395 395 See :hg:`help keyword` on how to construct patterns both for
396 396 inclusion and exclusion of files.
397 397
398 398 With -A/--all and -v/--verbose the codes used to show the status
399 399 of files are::
400 400
401 401 K = keyword expansion candidate
402 402 k = keyword expansion candidate (not tracked)
403 403 I = ignored
404 404 i = ignored (not tracked)
405 405 '''
406 406 kwt = kwtools['templater']
407 407 status = _status(ui, repo, kwt, *pats, **opts)
408 408 cwd = pats and repo.getcwd() or ''
409 409 modified, added, removed, deleted, unknown, ignored, clean = status
410 410 files = []
411 411 if not opts.get('unknown') or opts.get('all'):
412 412 files = sorted(modified + added + clean)
413 413 wctx = repo[None]
414 414 kwfiles = [f for f in files if kwt.iskwfile(f, wctx.flags)]
415 415 kwunknown = [f for f in unknown if kwt.iskwfile(f, wctx.flags)]
416 416 if not opts.get('ignore') or opts.get('all'):
417 417 showfiles = kwfiles, kwunknown
418 418 else:
419 419 showfiles = [], []
420 420 if opts.get('all') or opts.get('ignore'):
421 421 showfiles += ([f for f in files if f not in kwfiles],
422 422 [f for f in unknown if f not in kwunknown])
423 423 for char, filenames in zip('KkIi', showfiles):
424 424 fmt = (opts.get('all') or ui.verbose) and '%s %%s\n' % char or '%s\n'
425 425 for f in filenames:
426 426 ui.write(fmt % repo.pathto(f, cwd))
427 427
428 428 def shrink(ui, repo, *pats, **opts):
429 429 '''revert expanded keywords in the working directory
430 430
431 431 Run before changing/disabling active keywords or if you experience
432 432 problems with :hg:`import` or :hg:`merge`.
433 433
434 434 kwshrink refuses to run if given files contain local changes.
435 435 '''
436 436 # 3rd argument sets expansion to False
437 437 _kwfwrite(ui, repo, False, *pats, **opts)
438 438
439 439
440 440 def uisetup(ui):
441 441 '''Collects [keyword] config in kwtools.
442 442 Monkeypatches dispatch._parse if needed.'''
443 443
444 444 for pat, opt in ui.configitems('keyword'):
445 445 if opt != 'ignore':
446 446 kwtools['inc'].append(pat)
447 447 else:
448 448 kwtools['exc'].append(pat)
449 449
450 450 if kwtools['inc']:
451 451 def kwdispatch_parse(orig, ui, args):
452 452 '''Monkeypatch dispatch._parse to obtain running hg command.'''
453 453 cmd, func, args, options, cmdoptions = orig(ui, args)
454 454 kwtools['hgcmd'] = cmd
455 455 return cmd, func, args, options, cmdoptions
456 456
457 457 extensions.wrapfunction(dispatch, '_parse', kwdispatch_parse)
458 458
459 459 def reposetup(ui, repo):
460 460 '''Sets up repo as kwrepo for keyword substitution.
461 461 Overrides file method to return kwfilelog instead of filelog
462 462 if file matches user configuration.
463 463 Wraps commit to overwrite configured files with updated
464 464 keyword substitutions.
465 465 Monkeypatches patch and webcommands.'''
466 466
467 467 try:
468 468 if (not repo.local() or not kwtools['inc']
469 469 or kwtools['hgcmd'] in nokwcommands.split()
470 470 or '.hg' in util.splitpath(repo.root)
471 471 or repo._url.startswith('bundle:')):
472 472 return
473 473 except AttributeError:
474 474 pass
475 475
476 476 kwtools['templater'] = kwt = kwtemplater(ui, repo)
477 477
478 478 class kwrepo(repo.__class__):
479 479 def file(self, f):
480 480 if f[0] == '/':
481 481 f = f[1:]
482 482 return kwfilelog(self.sopener, kwt, f)
483 483
484 484 def wread(self, filename):
485 485 data = super(kwrepo, self).wread(filename)
486 486 return kwt.wread(filename, data)
487 487
488 488 def commit(self, *args, **opts):
489 489 # use custom commitctx for user commands
490 490 # other extensions can still wrap repo.commitctx directly
491 491 self.commitctx = self.kwcommitctx
492 492 try:
493 493 return super(kwrepo, self).commit(*args, **opts)
494 494 finally:
495 495 del self.commitctx
496 496
497 497 def kwcommitctx(self, ctx, error=False):
498 498 n = super(kwrepo, self).commitctx(ctx, error)
499 499 # no lock needed, only called from repo.commit() which already locks
500 500 if not kwt.record:
501 501 kwt.overwrite(self[n], sorted(ctx.added() + ctx.modified()),
502 502 False, True)
503 503 return n
504 504
505 505 # monkeypatches
506 506 def kwpatchfile_init(orig, self, ui, fname, opener,
507 507 missing=False, eolmode=None):
508 508 '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
509 509 rejects or conflicts due to expanded keywords in working dir.'''
510 510 orig(self, ui, fname, opener, missing, eolmode)
511 511 # shrink keywords read from working dir
512 512 self.lines = kwt.shrinklines(self.fname, self.lines)
513 513
514 514 def kw_diff(orig, repo, node1=None, node2=None, match=None, changes=None,
515 515 opts=None):
516 516 '''Monkeypatch patch.diff to avoid expansion except when
517 517 comparing against working dir.'''
518 518 if node2 is not None:
519 519 kwt.match = util.never
520 520 elif node1 is not None and node1 != repo['.'].node():
521 521 kwt.restrict = True
522 522 return orig(repo, node1, node2, match, changes, opts)
523 523
524 524 def kwweb_skip(orig, web, req, tmpl):
525 525 '''Wraps webcommands.x turning off keyword expansion.'''
526 526 kwt.match = util.never
527 527 return orig(web, req, tmpl)
528 528
529 529 def kw_dorecord(orig, ui, repo, commitfunc, *pats, **opts):
530 530 '''Wraps record.dorecord expanding keywords after recording.'''
531 531 wlock = repo.wlock()
532 532 try:
533 533 # record returns 0 even when nothing has changed
534 534 # therefore compare nodes before and after
535 535 ctx = repo['.']
536 536 ret = orig(ui, repo, commitfunc, *pats, **opts)
537 537 recordctx = repo['.']
538 538 if ctx != recordctx:
539 539 kwt.overwrite(recordctx, None, False, True)
540 540 return ret
541 541 finally:
542 542 wlock.release()
543 543
544 544 repo.__class__ = kwrepo
545 545
546 546 extensions.wrapfunction(patch.patchfile, '__init__', kwpatchfile_init)
547 547 if not kwt.restrict:
548 548 extensions.wrapfunction(patch, 'diff', kw_diff)
549 549 for c in 'annotate changeset rev filediff diff'.split():
550 550 extensions.wrapfunction(webcommands, c, kwweb_skip)
551 551 for name in recordextensions.split():
552 552 try:
553 553 record = extensions.find(name)
554 554 extensions.wrapfunction(record, 'dorecord', kw_dorecord)
555 555 except KeyError:
556 556 pass
557 557
558 558 cmdtable = {
559 559 'kwdemo':
560 560 (demo,
561 561 [('d', 'default', None, _('show default keyword template maps')),
562 562 ('f', 'rcfile', '',
563 563 _('read maps from rcfile'), _('FILE'))],
564 564 _('hg kwdemo [-d] [-f RCFILE] [TEMPLATEMAP]...')),
565 565 'kwexpand': (expand, commands.walkopts,
566 566 _('hg kwexpand [OPTION]... [FILE]...')),
567 567 'kwfiles':
568 568 (files,
569 569 [('A', 'all', None, _('show keyword status flags of all files')),
570 570 ('i', 'ignore', None, _('show files excluded from expansion')),
571 571 ('u', 'unknown', None, _('only show unknown (not tracked) files')),
572 572 ] + commands.walkopts,
573 573 _('hg kwfiles [OPTION]... [FILE]...')),
574 574 'kwshrink': (shrink, commands.walkopts,
575 575 _('hg kwshrink [OPTION]... [FILE]...')),
576 576 }
General Comments 0
You need to be logged in to leave comments. Login now