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