##// END OF EJS Templates
merge with stable
Augie Fackler -
r22378:c828b61e merge default
parent child Browse files
Show More
@@ -1,920 +1,939 b''
1 1 # dispatch.py - command dispatching for mercurial
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
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 from i18n import _
9 9 import os, sys, atexit, signal, pdb, socket, errno, shlex, time, traceback, re
10 10 import util, commands, hg, fancyopts, extensions, hook, error
11 11 import cmdutil, encoding
12 12 import ui as uimod
13 13
14 14 class request(object):
15 15 def __init__(self, args, ui=None, repo=None, fin=None, fout=None,
16 16 ferr=None):
17 17 self.args = args
18 18 self.ui = ui
19 19 self.repo = repo
20 20
21 21 # input/output/error streams
22 22 self.fin = fin
23 23 self.fout = fout
24 24 self.ferr = ferr
25 25
26 26 def run():
27 27 "run the command in sys.argv"
28 28 sys.exit((dispatch(request(sys.argv[1:])) or 0) & 255)
29 29
30 30 def dispatch(req):
31 31 "run the command specified in req.args"
32 32 if req.ferr:
33 33 ferr = req.ferr
34 34 elif req.ui:
35 35 ferr = req.ui.ferr
36 36 else:
37 37 ferr = sys.stderr
38 38
39 39 try:
40 40 if not req.ui:
41 41 req.ui = uimod.ui()
42 42 if '--traceback' in req.args:
43 43 req.ui.setconfig('ui', 'traceback', 'on', '--traceback')
44 44
45 45 # set ui streams from the request
46 46 if req.fin:
47 47 req.ui.fin = req.fin
48 48 if req.fout:
49 49 req.ui.fout = req.fout
50 50 if req.ferr:
51 51 req.ui.ferr = req.ferr
52 52 except util.Abort, inst:
53 53 ferr.write(_("abort: %s\n") % inst)
54 54 if inst.hint:
55 55 ferr.write(_("(%s)\n") % inst.hint)
56 56 return -1
57 57 except error.ParseError, inst:
58 58 if len(inst.args) > 1:
59 59 ferr.write(_("hg: parse error at %s: %s\n") %
60 60 (inst.args[1], inst.args[0]))
61 61 if (inst.args[0][0] == ' '):
62 62 ferr.write(_("unexpected leading whitespace\n"))
63 63 else:
64 64 ferr.write(_("hg: parse error: %s\n") % inst.args[0])
65 65 return -1
66 66
67 67 msg = ' '.join(' ' in a and repr(a) or a for a in req.args)
68 68 starttime = time.time()
69 69 ret = None
70 70 try:
71 71 ret = _runcatch(req)
72 72 return ret
73 73 finally:
74 74 duration = time.time() - starttime
75 75 req.ui.log("commandfinish", "%s exited %s after %0.2f seconds\n",
76 76 msg, ret or 0, duration)
77 77
78 78 def _runcatch(req):
79 79 def catchterm(*args):
80 80 raise error.SignalInterrupt
81 81
82 82 ui = req.ui
83 83 try:
84 84 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
85 85 num = getattr(signal, name, None)
86 86 if num:
87 87 signal.signal(num, catchterm)
88 88 except ValueError:
89 89 pass # happens if called in a thread
90 90
91 91 try:
92 92 try:
93 93 debugger = 'pdb'
94 94 debugtrace = {
95 95 'pdb' : pdb.set_trace
96 96 }
97 97 debugmortem = {
98 98 'pdb' : pdb.post_mortem
99 99 }
100 100
101 101 # read --config before doing anything else
102 102 # (e.g. to change trust settings for reading .hg/hgrc)
103 103 cfgs = _parseconfig(req.ui, _earlygetopt(['--config'], req.args))
104 104
105 105 if req.repo:
106 106 # copy configs that were passed on the cmdline (--config) to
107 107 # the repo ui
108 108 for sec, name, val in cfgs:
109 109 req.repo.ui.setconfig(sec, name, val, source='--config')
110 110
111 111 # if we are in HGPLAIN mode, then disable custom debugging
112 112 debugger = ui.config("ui", "debugger")
113 113 debugmod = pdb
114 114 if not debugger or ui.plain():
115 115 debugger = 'pdb'
116 116 elif '--debugger' in req.args:
117 117 # This import can be slow for fancy debuggers, so only
118 118 # do it when absolutely necessary, i.e. when actual
119 119 # debugging has been requested
120 120 try:
121 121 debugmod = __import__(debugger)
122 122 except ImportError:
123 123 pass # Leave debugmod = pdb
124 124
125 125 debugtrace[debugger] = debugmod.set_trace
126 126 debugmortem[debugger] = debugmod.post_mortem
127 127
128 128 # enter the debugger before command execution
129 129 if '--debugger' in req.args:
130 130 ui.warn(_("entering debugger - "
131 131 "type c to continue starting hg or h for help\n"))
132 132
133 133 if (debugger != 'pdb' and
134 134 debugtrace[debugger] == debugtrace['pdb']):
135 135 ui.warn(_("%s debugger specified "
136 136 "but its module was not found\n") % debugger)
137 137
138 138 debugtrace[debugger]()
139 139 try:
140 140 return _dispatch(req)
141 141 finally:
142 142 ui.flush()
143 143 except: # re-raises
144 144 # enter the debugger when we hit an exception
145 145 if '--debugger' in req.args:
146 146 traceback.print_exc()
147 147 debugmortem[debugger](sys.exc_info()[2])
148 148 ui.traceback()
149 149 raise
150 150
151 151 # Global exception handling, alphabetically
152 152 # Mercurial-specific first, followed by built-in and library exceptions
153 153 except error.AmbiguousCommand, inst:
154 154 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
155 155 (inst.args[0], " ".join(inst.args[1])))
156 156 except error.ParseError, inst:
157 157 if len(inst.args) > 1:
158 158 ui.warn(_("hg: parse error at %s: %s\n") %
159 159 (inst.args[1], inst.args[0]))
160 160 if (inst.args[0][0] == ' '):
161 161 ui.warn(_("unexpected leading whitespace\n"))
162 162 else:
163 163 ui.warn(_("hg: parse error: %s\n") % inst.args[0])
164 164 return -1
165 165 except error.LockHeld, inst:
166 166 if inst.errno == errno.ETIMEDOUT:
167 167 reason = _('timed out waiting for lock held by %s') % inst.locker
168 168 else:
169 169 reason = _('lock held by %s') % inst.locker
170 170 ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
171 171 except error.LockUnavailable, inst:
172 172 ui.warn(_("abort: could not lock %s: %s\n") %
173 173 (inst.desc or inst.filename, inst.strerror))
174 174 except error.CommandError, inst:
175 175 if inst.args[0]:
176 176 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
177 177 commands.help_(ui, inst.args[0], full=False, command=True)
178 178 else:
179 179 ui.warn(_("hg: %s\n") % inst.args[1])
180 180 commands.help_(ui, 'shortlist')
181 181 except error.OutOfBandError, inst:
182 182 ui.warn(_("abort: remote error:\n"))
183 183 ui.warn(''.join(inst.args))
184 184 except error.RepoError, inst:
185 185 ui.warn(_("abort: %s!\n") % inst)
186 186 if inst.hint:
187 187 ui.warn(_("(%s)\n") % inst.hint)
188 188 except error.ResponseError, inst:
189 189 ui.warn(_("abort: %s") % inst.args[0])
190 190 if not isinstance(inst.args[1], basestring):
191 191 ui.warn(" %r\n" % (inst.args[1],))
192 192 elif not inst.args[1]:
193 193 ui.warn(_(" empty string\n"))
194 194 else:
195 195 ui.warn("\n%r\n" % util.ellipsis(inst.args[1]))
196 196 except error.RevlogError, inst:
197 197 ui.warn(_("abort: %s!\n") % inst)
198 198 except error.SignalInterrupt:
199 199 ui.warn(_("killed!\n"))
200 200 except error.UnknownCommand, inst:
201 201 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
202 202 try:
203 203 # check if the command is in a disabled extension
204 204 # (but don't check for extensions themselves)
205 205 commands.help_(ui, inst.args[0], unknowncmd=True)
206 206 except error.UnknownCommand:
207 207 commands.help_(ui, 'shortlist')
208 208 except error.InterventionRequired, inst:
209 209 ui.warn("%s\n" % inst)
210 210 return 1
211 211 except util.Abort, inst:
212 212 ui.warn(_("abort: %s\n") % inst)
213 213 if inst.hint:
214 214 ui.warn(_("(%s)\n") % inst.hint)
215 215 except ImportError, inst:
216 216 ui.warn(_("abort: %s!\n") % inst)
217 217 m = str(inst).split()[-1]
218 218 if m in "mpatch bdiff".split():
219 219 ui.warn(_("(did you forget to compile extensions?)\n"))
220 220 elif m in "zlib".split():
221 221 ui.warn(_("(is your Python install correct?)\n"))
222 222 except IOError, inst:
223 223 if util.safehasattr(inst, "code"):
224 224 ui.warn(_("abort: %s\n") % inst)
225 225 elif util.safehasattr(inst, "reason"):
226 226 try: # usually it is in the form (errno, strerror)
227 227 reason = inst.reason.args[1]
228 228 except (AttributeError, IndexError):
229 229 # it might be anything, for example a string
230 230 reason = inst.reason
231 231 ui.warn(_("abort: error: %s\n") % reason)
232 232 elif (util.safehasattr(inst, "args")
233 233 and inst.args and inst.args[0] == errno.EPIPE):
234 234 if ui.debugflag:
235 235 ui.warn(_("broken pipe\n"))
236 236 elif getattr(inst, "strerror", None):
237 237 if getattr(inst, "filename", None):
238 238 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
239 239 else:
240 240 ui.warn(_("abort: %s\n") % inst.strerror)
241 241 else:
242 242 raise
243 243 except OSError, inst:
244 244 if getattr(inst, "filename", None) is not None:
245 245 ui.warn(_("abort: %s: '%s'\n") % (inst.strerror, inst.filename))
246 246 else:
247 247 ui.warn(_("abort: %s\n") % inst.strerror)
248 248 except KeyboardInterrupt:
249 249 try:
250 250 ui.warn(_("interrupted!\n"))
251 251 except IOError, inst:
252 252 if inst.errno == errno.EPIPE:
253 253 if ui.debugflag:
254 254 ui.warn(_("\nbroken pipe\n"))
255 255 else:
256 256 raise
257 257 except MemoryError:
258 258 ui.warn(_("abort: out of memory\n"))
259 259 except SystemExit, inst:
260 260 # Commands shouldn't sys.exit directly, but give a return code.
261 261 # Just in case catch this and and pass exit code to caller.
262 262 return inst.code
263 263 except socket.error, inst:
264 264 ui.warn(_("abort: %s\n") % inst.args[-1])
265 265 except: # re-raises
266 266 myver = util.version()
267 267 # For compatibility checking, we discard the portion of the hg
268 268 # version after the + on the assumption that if a "normal
269 269 # user" is running a build with a + in it the packager
270 270 # probably built from fairly close to a tag and anyone with a
271 271 # 'make local' copy of hg (where the version number can be out
272 272 # of date) will be clueful enough to notice the implausible
273 273 # version number and try updating.
274 274 compare = myver.split('+')[0]
275 275 ct = tuplever(compare)
276 276 worst = None, ct, ''
277 277 for name, mod in extensions.extensions():
278 278 testedwith = getattr(mod, 'testedwith', '')
279 279 report = getattr(mod, 'buglink', _('the extension author.'))
280 280 if not testedwith.strip():
281 281 # We found an untested extension. It's likely the culprit.
282 282 worst = name, 'unknown', report
283 283 break
284 284 if compare not in testedwith.split() and testedwith != 'internal':
285 285 tested = [tuplever(v) for v in testedwith.split()]
286 286 lower = [t for t in tested if t < ct]
287 287 nearest = max(lower or tested)
288 288 if worst[0] is None or nearest < worst[1]:
289 289 worst = name, nearest, report
290 290 if worst[0] is not None:
291 291 name, testedwith, report = worst
292 292 if not isinstance(testedwith, str):
293 293 testedwith = '.'.join([str(c) for c in testedwith])
294 294 warning = (_('** Unknown exception encountered with '
295 295 'possibly-broken third-party extension %s\n'
296 296 '** which supports versions %s of Mercurial.\n'
297 297 '** Please disable %s and try your action again.\n'
298 298 '** If that fixes the bug please report it to %s\n')
299 299 % (name, testedwith, name, report))
300 300 else:
301 301 warning = (_("** unknown exception encountered, "
302 302 "please report by visiting\n") +
303 303 _("** http://mercurial.selenic.com/wiki/BugTracker\n"))
304 304 warning += ((_("** Python %s\n") % sys.version.replace('\n', '')) +
305 305 (_("** Mercurial Distributed SCM (version %s)\n") % myver) +
306 306 (_("** Extensions loaded: %s\n") %
307 307 ", ".join([x[0] for x in extensions.extensions()])))
308 308 ui.log("commandexception", "%s\n%s\n", warning, traceback.format_exc())
309 309 ui.warn(warning)
310 310 raise
311 311
312 312 return -1
313 313
314 314 def tuplever(v):
315 315 try:
316 316 return tuple([int(i) for i in v.split('.')])
317 317 except ValueError:
318 318 return tuple()
319 319
320 320 def aliasargs(fn, givenargs):
321 321 args = getattr(fn, 'args', [])
322 322 if args:
323 323 cmd = ' '.join(map(util.shellquote, args))
324 324
325 325 nums = []
326 326 def replacer(m):
327 327 num = int(m.group(1)) - 1
328 328 nums.append(num)
329 329 if num < len(givenargs):
330 330 return givenargs[num]
331 331 raise util.Abort(_('too few arguments for command alias'))
332 332 cmd = re.sub(r'\$(\d+|\$)', replacer, cmd)
333 333 givenargs = [x for i, x in enumerate(givenargs)
334 334 if i not in nums]
335 335 args = shlex.split(cmd)
336 336 return args + givenargs
337 337
338 338 def aliasinterpolate(name, args, cmd):
339 339 '''interpolate args into cmd for shell aliases
340 340
341 341 This also handles $0, $@ and "$@".
342 342 '''
343 343 # util.interpolate can't deal with "$@" (with quotes) because it's only
344 344 # built to match prefix + patterns.
345 345 replacemap = dict(('$%d' % (i + 1), arg) for i, arg in enumerate(args))
346 346 replacemap['$0'] = name
347 347 replacemap['$$'] = '$'
348 348 replacemap['$@'] = ' '.join(args)
349 349 # Typical Unix shells interpolate "$@" (with quotes) as all the positional
350 350 # parameters, separated out into words. Emulate the same behavior here by
351 351 # quoting the arguments individually. POSIX shells will then typically
352 352 # tokenize each argument into exactly one word.
353 353 replacemap['"$@"'] = ' '.join(util.shellquote(arg) for arg in args)
354 354 # escape '\$' for regex
355 355 regex = '|'.join(replacemap.keys()).replace('$', r'\$')
356 356 r = re.compile(regex)
357 357 return r.sub(lambda x: replacemap[x.group()], cmd)
358 358
359 359 class cmdalias(object):
360 360 def __init__(self, name, definition, cmdtable):
361 361 self.name = self.cmd = name
362 362 self.cmdname = ''
363 363 self.definition = definition
364 364 self.fn = None
365 365 self.args = []
366 366 self.opts = []
367 367 self.help = ''
368 368 self.norepo = True
369 369 self.optionalrepo = False
370 370 self.badalias = None
371 371 self.unknowncmd = False
372 372
373 373 try:
374 374 aliases, entry = cmdutil.findcmd(self.name, cmdtable)
375 375 for alias, e in cmdtable.iteritems():
376 376 if e is entry:
377 377 self.cmd = alias
378 378 break
379 379 self.shadows = True
380 380 except error.UnknownCommand:
381 381 self.shadows = False
382 382
383 383 if not self.definition:
384 384 self.badalias = _("no definition for alias '%s'") % self.name
385 385 return
386 386
387 387 if self.definition.startswith('!'):
388 388 self.shell = True
389 389 def fn(ui, *args):
390 390 env = {'HG_ARGS': ' '.join((self.name,) + args)}
391 391 def _checkvar(m):
392 392 if m.groups()[0] == '$':
393 393 return m.group()
394 394 elif int(m.groups()[0]) <= len(args):
395 395 return m.group()
396 396 else:
397 397 ui.debug("No argument found for substitution "
398 398 "of %i variable in alias '%s' definition."
399 399 % (int(m.groups()[0]), self.name))
400 400 return ''
401 401 cmd = re.sub(r'\$(\d+|\$)', _checkvar, self.definition[1:])
402 402 cmd = aliasinterpolate(self.name, args, cmd)
403 403 return util.system(cmd, environ=env, out=ui.fout)
404 404 self.fn = fn
405 405 return
406 406
407 407 try:
408 408 args = shlex.split(self.definition)
409 409 except ValueError, inst:
410 410 self.badalias = (_("error in definition for alias '%s': %s")
411 411 % (self.name, inst))
412 412 return
413 413 self.cmdname = cmd = args.pop(0)
414 414 args = map(util.expandpath, args)
415 415
416 416 for invalidarg in ("--cwd", "-R", "--repository", "--repo", "--config"):
417 417 if _earlygetopt([invalidarg], args):
418 418 self.badalias = (_("error in definition for alias '%s': %s may "
419 419 "only be given on the command line")
420 420 % (self.name, invalidarg))
421 421 return
422 422
423 423 try:
424 424 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
425 425 if len(tableentry) > 2:
426 426 self.fn, self.opts, self.help = tableentry
427 427 else:
428 428 self.fn, self.opts = tableentry
429 429
430 430 self.args = aliasargs(self.fn, args)
431 431 if cmd not in commands.norepo.split(' '):
432 432 self.norepo = False
433 433 if cmd in commands.optionalrepo.split(' '):
434 434 self.optionalrepo = True
435 435 if self.help.startswith("hg " + cmd):
436 436 # drop prefix in old-style help lines so hg shows the alias
437 437 self.help = self.help[4 + len(cmd):]
438 438 self.__doc__ = self.fn.__doc__
439 439
440 440 except error.UnknownCommand:
441 441 self.badalias = (_("alias '%s' resolves to unknown command '%s'")
442 442 % (self.name, cmd))
443 443 self.unknowncmd = True
444 444 except error.AmbiguousCommand:
445 445 self.badalias = (_("alias '%s' resolves to ambiguous command '%s'")
446 446 % (self.name, cmd))
447 447
448 448 def __call__(self, ui, *args, **opts):
449 449 if self.badalias:
450 450 hint = None
451 451 if self.unknowncmd:
452 452 try:
453 453 # check if the command is in a disabled extension
454 454 cmd, ext = extensions.disabledcmd(ui, self.cmdname)[:2]
455 455 hint = _("'%s' is provided by '%s' extension") % (cmd, ext)
456 456 except error.UnknownCommand:
457 457 pass
458 458 raise util.Abort(self.badalias, hint=hint)
459 459 if self.shadows:
460 460 ui.debug("alias '%s' shadows command '%s'\n" %
461 461 (self.name, self.cmdname))
462 462
463 463 if util.safehasattr(self, 'shell'):
464 464 return self.fn(ui, *args, **opts)
465 465 else:
466 466 try:
467 467 return util.checksignature(self.fn)(ui, *args, **opts)
468 468 except error.SignatureError:
469 469 args = ' '.join([self.cmdname] + self.args)
470 470 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args))
471 471 raise
472 472
473 473 def addaliases(ui, cmdtable):
474 474 # aliases are processed after extensions have been loaded, so they
475 475 # may use extension commands. Aliases can also use other alias definitions,
476 476 # but only if they have been defined prior to the current definition.
477 477 for alias, definition in ui.configitems('alias'):
478 478 aliasdef = cmdalias(alias, definition, cmdtable)
479 479
480 480 try:
481 481 olddef = cmdtable[aliasdef.cmd][0]
482 482 if olddef.definition == aliasdef.definition:
483 483 continue
484 484 except (KeyError, AttributeError):
485 485 # definition might not exist or it might not be a cmdalias
486 486 pass
487 487
488 488 cmdtable[aliasdef.name] = (aliasdef, aliasdef.opts, aliasdef.help)
489 489 if aliasdef.norepo:
490 490 commands.norepo += ' %s' % alias
491 491 if aliasdef.optionalrepo:
492 492 commands.optionalrepo += ' %s' % alias
493 493
494 494 def _parse(ui, args):
495 495 options = {}
496 496 cmdoptions = {}
497 497
498 498 try:
499 499 args = fancyopts.fancyopts(args, commands.globalopts, options)
500 500 except fancyopts.getopt.GetoptError, inst:
501 501 raise error.CommandError(None, inst)
502 502
503 503 if args:
504 504 cmd, args = args[0], args[1:]
505 505 aliases, entry = cmdutil.findcmd(cmd, commands.table,
506 506 ui.configbool("ui", "strict"))
507 507 cmd = aliases[0]
508 508 args = aliasargs(entry[0], args)
509 509 defaults = ui.config("defaults", cmd)
510 510 if defaults:
511 511 args = map(util.expandpath, shlex.split(defaults)) + args
512 512 c = list(entry[1])
513 513 else:
514 514 cmd = None
515 515 c = []
516 516
517 517 # combine global options into local
518 518 for o in commands.globalopts:
519 519 c.append((o[0], o[1], options[o[1]], o[3]))
520 520
521 521 try:
522 522 args = fancyopts.fancyopts(args, c, cmdoptions, True)
523 523 except fancyopts.getopt.GetoptError, inst:
524 524 raise error.CommandError(cmd, inst)
525 525
526 526 # separate global options back out
527 527 for o in commands.globalopts:
528 528 n = o[1]
529 529 options[n] = cmdoptions[n]
530 530 del cmdoptions[n]
531 531
532 532 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
533 533
534 534 def _parseconfig(ui, config):
535 535 """parse the --config options from the command line"""
536 536 configs = []
537 537
538 538 for cfg in config:
539 539 try:
540 540 name, value = cfg.split('=', 1)
541 541 section, name = name.split('.', 1)
542 542 if not section or not name:
543 543 raise IndexError
544 544 ui.setconfig(section, name, value, '--config')
545 545 configs.append((section, name, value))
546 546 except (IndexError, ValueError):
547 547 raise util.Abort(_('malformed --config option: %r '
548 548 '(use --config section.name=value)') % cfg)
549 549
550 550 return configs
551 551
552 552 def _earlygetopt(aliases, args):
553 553 """Return list of values for an option (or aliases).
554 554
555 555 The values are listed in the order they appear in args.
556 556 The options and values are removed from args.
557 557
558 558 >>> args = ['x', '--cwd', 'foo', 'y']
559 559 >>> _earlygetopt(['--cwd'], args), args
560 560 (['foo'], ['x', 'y'])
561 561
562 562 >>> args = ['x', '--cwd=bar', 'y']
563 563 >>> _earlygetopt(['--cwd'], args), args
564 564 (['bar'], ['x', 'y'])
565 565
566 566 >>> args = ['x', '-R', 'foo', 'y']
567 567 >>> _earlygetopt(['-R'], args), args
568 568 (['foo'], ['x', 'y'])
569 569
570 570 >>> args = ['x', '-Rbar', 'y']
571 571 >>> _earlygetopt(['-R'], args), args
572 572 (['bar'], ['x', 'y'])
573 573 """
574 574 try:
575 575 argcount = args.index("--")
576 576 except ValueError:
577 577 argcount = len(args)
578 578 shortopts = [opt for opt in aliases if len(opt) == 2]
579 579 values = []
580 580 pos = 0
581 581 while pos < argcount:
582 582 fullarg = arg = args[pos]
583 583 equals = arg.find('=')
584 584 if equals > -1:
585 585 arg = arg[:equals]
586 586 if arg in aliases:
587 587 del args[pos]
588 588 if equals > -1:
589 589 values.append(fullarg[equals + 1:])
590 590 argcount -= 1
591 591 else:
592 592 if pos + 1 >= argcount:
593 593 # ignore and let getopt report an error if there is no value
594 594 break
595 595 values.append(args.pop(pos))
596 596 argcount -= 2
597 597 elif arg[:2] in shortopts:
598 598 # short option can have no following space, e.g. hg log -Rfoo
599 599 values.append(args.pop(pos)[2:])
600 600 argcount -= 1
601 601 else:
602 602 pos += 1
603 603 return values
604 604
605 605 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
606 606 # run pre-hook, and abort if it fails
607 607 hook.hook(lui, repo, "pre-%s" % cmd, True, args=" ".join(fullargs),
608 608 pats=cmdpats, opts=cmdoptions)
609 609 ret = _runcommand(ui, options, cmd, d)
610 610 # run post-hook, passing command result
611 611 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
612 612 result=ret, pats=cmdpats, opts=cmdoptions)
613 613 return ret
614 614
615 615 def _getlocal(ui, rpath):
616 616 """Return (path, local ui object) for the given target path.
617 617
618 618 Takes paths in [cwd]/.hg/hgrc into account."
619 619 """
620 620 try:
621 621 wd = os.getcwd()
622 622 except OSError, e:
623 623 raise util.Abort(_("error getting current working directory: %s") %
624 624 e.strerror)
625 625 path = cmdutil.findrepo(wd) or ""
626 626 if not path:
627 627 lui = ui
628 628 else:
629 629 lui = ui.copy()
630 630 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
631 631
632 632 if rpath and rpath[-1]:
633 633 path = lui.expandpath(rpath[-1])
634 634 lui = ui.copy()
635 635 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
636 636
637 637 return path, lui
638 638
639 def _checkshellalias(lui, ui, args):
639 def _checkshellalias(lui, ui, args, precheck=True):
640 """Return the function to run the shell alias, if it is required
641
642 'precheck' is whether this function is invoked before adding
643 aliases or not.
644 """
640 645 options = {}
641 646
642 647 try:
643 648 args = fancyopts.fancyopts(args, commands.globalopts, options)
644 649 except fancyopts.getopt.GetoptError:
645 650 return
646 651
647 652 if not args:
648 653 return
649 654
650 norepo = commands.norepo
651 optionalrepo = commands.optionalrepo
652 def restorecommands():
653 commands.norepo = norepo
654 commands.optionalrepo = optionalrepo
655
656 cmdtable = commands.table.copy()
657 addaliases(lui, cmdtable)
655 if precheck:
656 strict = True
657 norepo = commands.norepo
658 optionalrepo = commands.optionalrepo
659 def restorecommands():
660 commands.norepo = norepo
661 commands.optionalrepo = optionalrepo
662 cmdtable = commands.table.copy()
663 addaliases(lui, cmdtable)
664 else:
665 strict = False
666 def restorecommands():
667 pass
668 cmdtable = commands.table
658 669
659 670 cmd = args[0]
660 671 try:
661 aliases, entry = cmdutil.findcmd(cmd, cmdtable)
672 aliases, entry = cmdutil.findcmd(cmd, cmdtable, strict)
662 673 except (error.AmbiguousCommand, error.UnknownCommand):
663 674 restorecommands()
664 675 return
665 676
666 677 cmd = aliases[0]
667 678 fn = entry[0]
668 679
669 680 if cmd and util.safehasattr(fn, 'shell'):
670 681 d = lambda: fn(ui, *args[1:])
671 682 return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d,
672 683 [], {})
673 684
674 685 restorecommands()
675 686
676 687 _loaded = set()
677 688 def _dispatch(req):
678 689 args = req.args
679 690 ui = req.ui
680 691
681 692 # check for cwd
682 693 cwd = _earlygetopt(['--cwd'], args)
683 694 if cwd:
684 695 os.chdir(cwd[-1])
685 696
686 697 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
687 698 path, lui = _getlocal(ui, rpath)
688 699
689 700 # Now that we're operating in the right directory/repository with
690 701 # the right config settings, check for shell aliases
691 702 shellaliasfn = _checkshellalias(lui, ui, args)
692 703 if shellaliasfn:
693 704 return shellaliasfn()
694 705
695 706 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
696 707 # reposetup. Programs like TortoiseHg will call _dispatch several
697 708 # times so we keep track of configured extensions in _loaded.
698 709 extensions.loadall(lui)
699 710 exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
700 711 # Propagate any changes to lui.__class__ by extensions
701 712 ui.__class__ = lui.__class__
702 713
703 714 # (uisetup and extsetup are handled in extensions.loadall)
704 715
705 716 for name, module in exts:
706 717 cmdtable = getattr(module, 'cmdtable', {})
707 718 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
708 719 if overrides:
709 720 ui.warn(_("extension '%s' overrides commands: %s\n")
710 721 % (name, " ".join(overrides)))
711 722 commands.table.update(cmdtable)
712 723 _loaded.add(name)
713 724
714 725 # (reposetup is handled in hg.repository)
715 726
716 727 addaliases(lui, commands.table)
717 728
729 if not lui.configbool("ui", "strict"):
730 # All aliases and commands are completely defined, now.
731 # Check abbreviation/ambiguity of shell alias again, because shell
732 # alias may cause failure of "_parse" (see issue4355)
733 shellaliasfn = _checkshellalias(lui, ui, args, precheck=False)
734 if shellaliasfn:
735 return shellaliasfn()
736
718 737 # check for fallback encoding
719 738 fallback = lui.config('ui', 'fallbackencoding')
720 739 if fallback:
721 740 encoding.fallbackencoding = fallback
722 741
723 742 fullargs = args
724 743 cmd, func, args, options, cmdoptions = _parse(lui, args)
725 744
726 745 if options["config"]:
727 746 raise util.Abort(_("option --config may not be abbreviated!"))
728 747 if options["cwd"]:
729 748 raise util.Abort(_("option --cwd may not be abbreviated!"))
730 749 if options["repository"]:
731 750 raise util.Abort(_(
732 751 "option -R has to be separated from other options (e.g. not -qR) "
733 752 "and --repository may only be abbreviated as --repo!"))
734 753
735 754 if options["encoding"]:
736 755 encoding.encoding = options["encoding"]
737 756 if options["encodingmode"]:
738 757 encoding.encodingmode = options["encodingmode"]
739 758 if options["time"]:
740 759 def get_times():
741 760 t = os.times()
742 761 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
743 762 t = (t[0], t[1], t[2], t[3], time.clock())
744 763 return t
745 764 s = get_times()
746 765 def print_time():
747 766 t = get_times()
748 767 ui.warn(_("time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
749 768 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
750 769 atexit.register(print_time)
751 770
752 771 uis = set([ui, lui])
753 772
754 773 if req.repo:
755 774 uis.add(req.repo.ui)
756 775
757 776 if options['verbose'] or options['debug'] or options['quiet']:
758 777 for opt in ('verbose', 'debug', 'quiet'):
759 778 val = str(bool(options[opt]))
760 779 for ui_ in uis:
761 780 ui_.setconfig('ui', opt, val, '--' + opt)
762 781
763 782 if options['traceback']:
764 783 for ui_ in uis:
765 784 ui_.setconfig('ui', 'traceback', 'on', '--traceback')
766 785
767 786 if options['noninteractive']:
768 787 for ui_ in uis:
769 788 ui_.setconfig('ui', 'interactive', 'off', '-y')
770 789
771 790 if cmdoptions.get('insecure', False):
772 791 for ui_ in uis:
773 792 ui_.setconfig('web', 'cacerts', '', '--insecure')
774 793
775 794 if options['version']:
776 795 return commands.version_(ui)
777 796 if options['help']:
778 797 return commands.help_(ui, cmd, command=True)
779 798 elif not cmd:
780 799 return commands.help_(ui, 'shortlist')
781 800
782 801 repo = None
783 802 cmdpats = args[:]
784 803 if cmd not in commands.norepo.split():
785 804 # use the repo from the request only if we don't have -R
786 805 if not rpath and not cwd:
787 806 repo = req.repo
788 807
789 808 if repo:
790 809 # set the descriptors of the repo ui to those of ui
791 810 repo.ui.fin = ui.fin
792 811 repo.ui.fout = ui.fout
793 812 repo.ui.ferr = ui.ferr
794 813 else:
795 814 try:
796 815 repo = hg.repository(ui, path=path)
797 816 if not repo.local():
798 817 raise util.Abort(_("repository '%s' is not local") % path)
799 818 repo.ui.setconfig("bundle", "mainreporoot", repo.root, 'repo')
800 819 except error.RequirementError:
801 820 raise
802 821 except error.RepoError:
803 822 if cmd not in commands.optionalrepo.split():
804 823 if (cmd in commands.inferrepo.split() and
805 824 args and not path): # try to infer -R from command args
806 825 repos = map(cmdutil.findrepo, args)
807 826 guess = repos[0]
808 827 if guess and repos.count(guess) == len(repos):
809 828 req.args = ['--repository', guess] + fullargs
810 829 return _dispatch(req)
811 830 if not path:
812 831 raise error.RepoError(_("no repository found in '%s'"
813 832 " (.hg not found)")
814 833 % os.getcwd())
815 834 raise
816 835 if repo:
817 836 ui = repo.ui
818 837 if options['hidden']:
819 838 repo = repo.unfiltered()
820 839 args.insert(0, repo)
821 840 elif rpath:
822 841 ui.warn(_("warning: --repository ignored\n"))
823 842
824 843 msg = ' '.join(' ' in a and repr(a) or a for a in fullargs)
825 844 ui.log("command", '%s\n', msg)
826 845 d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
827 846 try:
828 847 return runcommand(lui, repo, cmd, fullargs, ui, options, d,
829 848 cmdpats, cmdoptions)
830 849 finally:
831 850 if repo and repo != req.repo:
832 851 repo.close()
833 852
834 853 def lsprofile(ui, func, fp):
835 854 format = ui.config('profiling', 'format', default='text')
836 855 field = ui.config('profiling', 'sort', default='inlinetime')
837 856 limit = ui.configint('profiling', 'limit', default=30)
838 857 climit = ui.configint('profiling', 'nested', default=5)
839 858
840 859 if format not in ['text', 'kcachegrind']:
841 860 ui.warn(_("unrecognized profiling format '%s'"
842 861 " - Ignored\n") % format)
843 862 format = 'text'
844 863
845 864 try:
846 865 from mercurial import lsprof
847 866 except ImportError:
848 867 raise util.Abort(_(
849 868 'lsprof not available - install from '
850 869 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
851 870 p = lsprof.Profiler()
852 871 p.enable(subcalls=True)
853 872 try:
854 873 return func()
855 874 finally:
856 875 p.disable()
857 876
858 877 if format == 'kcachegrind':
859 878 import lsprofcalltree
860 879 calltree = lsprofcalltree.KCacheGrind(p)
861 880 calltree.output(fp)
862 881 else:
863 882 # format == 'text'
864 883 stats = lsprof.Stats(p.getstats())
865 884 stats.sort(field)
866 885 stats.pprint(limit=limit, file=fp, climit=climit)
867 886
868 887 def statprofile(ui, func, fp):
869 888 try:
870 889 import statprof
871 890 except ImportError:
872 891 raise util.Abort(_(
873 892 'statprof not available - install using "easy_install statprof"'))
874 893
875 894 freq = ui.configint('profiling', 'freq', default=1000)
876 895 if freq > 0:
877 896 statprof.reset(freq)
878 897 else:
879 898 ui.warn(_("invalid sampling frequency '%s' - ignoring\n") % freq)
880 899
881 900 statprof.start()
882 901 try:
883 902 return func()
884 903 finally:
885 904 statprof.stop()
886 905 statprof.display(fp)
887 906
888 907 def _runcommand(ui, options, cmd, cmdfunc):
889 908 def checkargs():
890 909 try:
891 910 return cmdfunc()
892 911 except error.SignatureError:
893 912 raise error.CommandError(cmd, _("invalid arguments"))
894 913
895 914 if options['profile']:
896 915 profiler = os.getenv('HGPROF')
897 916 if profiler is None:
898 917 profiler = ui.config('profiling', 'type', default='ls')
899 918 if profiler not in ('ls', 'stat'):
900 919 ui.warn(_("unrecognized profiler '%s' - ignored\n") % profiler)
901 920 profiler = 'ls'
902 921
903 922 output = ui.config('profiling', 'output')
904 923
905 924 if output:
906 925 path = ui.expandpath(output)
907 926 fp = open(path, 'wb')
908 927 else:
909 928 fp = sys.stderr
910 929
911 930 try:
912 931 if profiler == 'ls':
913 932 return lsprofile(ui, checkargs, fp)
914 933 else:
915 934 return statprofile(ui, checkargs, fp)
916 935 finally:
917 936 if output:
918 937 fp.close()
919 938 else:
920 939 return checkargs()
@@ -1,515 +1,517 b''
1 1 $ HGFOO=BAR; export HGFOO
2 2 $ cat >> $HGRCPATH <<EOF
3 3 > [alias]
4 4 > # should clobber ci but not commit (issue2993)
5 5 > ci = version
6 6 > myinit = init
7 7 > mycommit = commit
8 8 > optionalrepo = showconfig alias.myinit
9 9 > cleanstatus = status -c
10 10 > unknown = bargle
11 11 > ambiguous = s
12 12 > recursive = recursive
13 13 > disabled = email
14 14 > nodefinition =
15 15 > noclosingquotation = '
16 16 > no--cwd = status --cwd elsewhere
17 17 > no-R = status -R elsewhere
18 18 > no--repo = status --repo elsewhere
19 19 > no--repository = status --repository elsewhere
20 20 > no--config = status --config a.config=1
21 21 > mylog = log
22 22 > lognull = log -r null
23 23 > shortlog = log --template '{rev} {node|short} | {date|isodate}\n'
24 24 > positional = log --template '{\$2} {\$1} | {date|isodate}\n'
25 25 > dln = lognull --debug
26 26 > nousage = rollback
27 27 > put = export -r 0 -o "\$FOO/%R.diff"
28 28 > blank = !printf '\n'
29 29 > self = !printf '\$0\n'
30 30 > echoall = !printf '\$@\n'
31 31 > echo1 = !printf '\$1\n'
32 32 > echo2 = !printf '\$2\n'
33 33 > echo13 = !printf '\$1 \$3\n'
34 34 > echotokens = !printf "%s\n" "\$@"
35 35 > count = !hg log -r "\$@" --template=. | wc -c | sed -e 's/ //g'
36 36 > mcount = !hg log \$@ --template=. | wc -c | sed -e 's/ //g'
37 37 > rt = root
38 38 > tglog = log -G --template "{rev}:{node|short}: '{desc}' {branches}\n"
39 39 > idalias = id
40 40 > idaliaslong = id
41 41 > idaliasshell = !echo test
42 42 > parentsshell1 = !echo one
43 43 > parentsshell2 = !echo two
44 44 > escaped1 = !printf 'test\$\$test\n'
45 45 > escaped2 = !sh -c 'echo "HGFOO is \$\$HGFOO"'
46 46 > escaped3 = !sh -c 'echo "\$1 is \$\$\$1"'
47 47 > escaped4 = !printf '\$\$0 \$\$@\n'
48 48 > exit1 = !sh -c 'exit 1'
49 49 >
50 50 > [defaults]
51 51 > mylog = -q
52 52 > lognull = -q
53 53 > log = -v
54 54 > EOF
55 55
56 56
57 57 basic
58 58
59 59 $ hg myinit alias
60 60
61 61
62 62 unknown
63 63
64 64 $ hg unknown
65 65 abort: alias 'unknown' resolves to unknown command 'bargle'
66 66 [255]
67 67 $ hg help unknown
68 68 alias 'unknown' resolves to unknown command 'bargle'
69 69
70 70
71 71 ambiguous
72 72
73 73 $ hg ambiguous
74 74 abort: alias 'ambiguous' resolves to ambiguous command 's'
75 75 [255]
76 76 $ hg help ambiguous
77 77 alias 'ambiguous' resolves to ambiguous command 's'
78 78
79 79
80 80 recursive
81 81
82 82 $ hg recursive
83 83 abort: alias 'recursive' resolves to unknown command 'recursive'
84 84 [255]
85 85 $ hg help recursive
86 86 alias 'recursive' resolves to unknown command 'recursive'
87 87
88 88
89 89 disabled
90 90
91 91 $ hg disabled
92 92 abort: alias 'disabled' resolves to unknown command 'email'
93 93 ('email' is provided by 'patchbomb' extension)
94 94 [255]
95 95 $ hg help disabled
96 96 alias 'disabled' resolves to unknown command 'email'
97 97
98 98 'email' is provided by the following extension:
99 99
100 100 patchbomb command to send changesets as (a series of) patch emails
101 101
102 102 (use "hg help extensions" for information on enabling extensions)
103 103
104 104
105 105 no definition
106 106
107 107 $ hg nodef
108 108 abort: no definition for alias 'nodefinition'
109 109 [255]
110 110 $ hg help nodef
111 111 no definition for alias 'nodefinition'
112 112
113 113
114 114 no closing quotation
115 115
116 116 $ hg noclosing
117 117 abort: error in definition for alias 'noclosingquotation': No closing quotation
118 118 [255]
119 119 $ hg help noclosing
120 120 error in definition for alias 'noclosingquotation': No closing quotation
121 121
122 122
123 123 invalid options
124 124
125 125 $ hg no--cwd
126 126 abort: error in definition for alias 'no--cwd': --cwd may only be given on the command line
127 127 [255]
128 128 $ hg help no--cwd
129 129 error in definition for alias 'no--cwd': --cwd may only be given on the
130 130 command line
131 131 $ hg no-R
132 132 abort: error in definition for alias 'no-R': -R may only be given on the command line
133 133 [255]
134 134 $ hg help no-R
135 135 error in definition for alias 'no-R': -R may only be given on the command line
136 136 $ hg no--repo
137 137 abort: error in definition for alias 'no--repo': --repo may only be given on the command line
138 138 [255]
139 139 $ hg help no--repo
140 140 error in definition for alias 'no--repo': --repo may only be given on the
141 141 command line
142 142 $ hg no--repository
143 143 abort: error in definition for alias 'no--repository': --repository may only be given on the command line
144 144 [255]
145 145 $ hg help no--repository
146 146 error in definition for alias 'no--repository': --repository may only be given
147 147 on the command line
148 148 $ hg no--config
149 149 abort: error in definition for alias 'no--config': --config may only be given on the command line
150 150 [255]
151 151
152 152 optional repository
153 153
154 154 #if no-outer-repo
155 155 $ hg optionalrepo
156 156 init
157 157 #endif
158 158 $ cd alias
159 159 $ cat > .hg/hgrc <<EOF
160 160 > [alias]
161 161 > myinit = init -q
162 162 > EOF
163 163 $ hg optionalrepo
164 164 init -q
165 165
166 166 no usage
167 167
168 168 $ hg nousage
169 169 no rollback information available
170 170 [1]
171 171
172 172 $ echo foo > foo
173 173 $ hg commit -Amfoo
174 174 adding foo
175 175
176 176
177 177 with opts
178 178
179 179 $ hg cleanst
180 180 C foo
181 181
182 182
183 183 with opts and whitespace
184 184
185 185 $ hg shortlog
186 186 0 e63c23eaa88a | 1970-01-01 00:00 +0000
187 187
188 188 positional arguments
189 189
190 190 $ hg positional
191 191 abort: too few arguments for command alias
192 192 [255]
193 193 $ hg positional a
194 194 abort: too few arguments for command alias
195 195 [255]
196 196 $ hg positional 'node|short' rev
197 197 0 e63c23eaa88a | 1970-01-01 00:00 +0000
198 198
199 199 interaction with defaults
200 200
201 201 $ hg mylog
202 202 0:e63c23eaa88a
203 203 $ hg lognull
204 204 -1:000000000000
205 205
206 206
207 207 properly recursive
208 208
209 209 $ hg dln
210 210 changeset: -1:0000000000000000000000000000000000000000
211 211 parent: -1:0000000000000000000000000000000000000000
212 212 parent: -1:0000000000000000000000000000000000000000
213 213 manifest: -1:0000000000000000000000000000000000000000
214 214 user:
215 215 date: Thu Jan 01 00:00:00 1970 +0000
216 216 extra: branch=default
217 217
218 218
219 219
220 220 path expanding
221 221
222 222 $ FOO=`pwd` hg put
223 223 $ cat 0.diff
224 224 # HG changeset patch
225 225 # User test
226 226 # Date 0 0
227 227 # Thu Jan 01 00:00:00 1970 +0000
228 228 # Node ID e63c23eaa88ae77967edcf4ea194d31167c478b0
229 229 # Parent 0000000000000000000000000000000000000000
230 230 foo
231 231
232 232 diff -r 000000000000 -r e63c23eaa88a foo
233 233 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
234 234 +++ b/foo Thu Jan 01 00:00:00 1970 +0000
235 235 @@ -0,0 +1,1 @@
236 236 +foo
237 237
238 238
239 239 simple shell aliases
240 240
241 241 $ hg blank
242 242
243 243 $ hg blank foo
244 244
245 245 $ hg self
246 246 self
247 247 $ hg echoall
248 248
249 249 $ hg echoall foo
250 250 foo
251 251 $ hg echoall 'test $2' foo
252 252 test $2 foo
253 253 $ hg echoall 'test $@' foo '$@'
254 254 test $@ foo $@
255 255 $ hg echoall 'test "$@"' foo '"$@"'
256 256 test "$@" foo "$@"
257 257 $ hg echo1 foo bar baz
258 258 foo
259 259 $ hg echo2 foo bar baz
260 260 bar
261 261 $ hg echo13 foo bar baz test
262 262 foo baz
263 263 $ hg echo2 foo
264 264
265 265 $ hg echotokens
266 266
267 267 $ hg echotokens foo 'bar $1 baz'
268 268 foo
269 269 bar $1 baz
270 270 $ hg echotokens 'test $2' foo
271 271 test $2
272 272 foo
273 273 $ hg echotokens 'test $@' foo '$@'
274 274 test $@
275 275 foo
276 276 $@
277 277 $ hg echotokens 'test "$@"' foo '"$@"'
278 278 test "$@"
279 279 foo
280 280 "$@"
281 281 $ echo bar > bar
282 282 $ hg commit -qA -m bar
283 283 $ hg count .
284 284 1
285 285 $ hg count 'branch(default)'
286 286 2
287 287 $ hg mcount -r '"branch(default)"'
288 288 2
289 289
290 290 $ hg tglog
291 291 @ 1:042423737847: 'bar'
292 292 |
293 293 o 0:e63c23eaa88a: 'foo'
294 294
295 295
296 296
297 297 shadowing
298 298
299 299 $ hg i
300 300 hg: command 'i' is ambiguous:
301 301 idalias idaliaslong idaliasshell identify import incoming init
302 302 [255]
303 303 $ hg id
304 304 042423737847 tip
305 305 $ hg ida
306 306 hg: command 'ida' is ambiguous:
307 307 idalias idaliaslong idaliasshell
308 308 [255]
309 309 $ hg idalias
310 310 042423737847 tip
311 311 $ hg idaliasl
312 312 042423737847 tip
313 313 $ hg idaliass
314 314 test
315 315 $ hg parentsshell
316 316 hg: command 'parentsshell' is ambiguous:
317 317 parentsshell1 parentsshell2
318 318 [255]
319 319 $ hg parentsshell1
320 320 one
321 321 $ hg parentsshell2
322 322 two
323 323
324 324
325 325 shell aliases with global options
326 326
327 327 $ hg init sub
328 328 $ cd sub
329 329 $ hg count 'branch(default)'
330 330 abort: unknown revision 'default'!
331 331 0
332 332 $ hg -v count 'branch(default)'
333 333 abort: unknown revision 'default'!
334 334 0
335 335 $ hg -R .. count 'branch(default)'
336 336 abort: unknown revision 'default'!
337 337 0
338 338 $ hg --cwd .. count 'branch(default)'
339 339 2
340 340 $ hg echoall --cwd ..
341 341
342 342
343 343
344 344 repo specific shell aliases
345 345
346 346 $ cat >> .hg/hgrc <<EOF
347 347 > [alias]
348 348 > subalias = !echo sub
349 349 > EOF
350 350 $ cat >> ../.hg/hgrc <<EOF
351 351 > [alias]
352 352 > mainalias = !echo main
353 353 > EOF
354 354
355 355
356 356 shell alias defined in current repo
357 357
358 358 $ hg subalias
359 359 sub
360 360 $ hg --cwd .. subalias > /dev/null
361 361 hg: unknown command 'subalias'
362 362 [255]
363 363 $ hg -R .. subalias > /dev/null
364 364 hg: unknown command 'subalias'
365 365 [255]
366 366
367 367
368 368 shell alias defined in other repo
369 369
370 370 $ hg mainalias > /dev/null
371 371 hg: unknown command 'mainalias'
372 372 [255]
373 373 $ hg -R .. mainalias
374 374 main
375 375 $ hg --cwd .. mainalias
376 376 main
377 377
378 378
379 379 shell aliases with escaped $ chars
380 380
381 381 $ hg escaped1
382 382 test$test
383 383 $ hg escaped2
384 384 HGFOO is BAR
385 385 $ hg escaped3 HGFOO
386 386 HGFOO is BAR
387 387 $ hg escaped4 test
388 388 $0 $@
389 389
390 390 abbreviated name, which matches against both shell alias and the
391 391 command provided extension, should be aborted.
392 392
393 393 $ cat >> .hg/hgrc <<EOF
394 394 > [extensions]
395 395 > hgext.rebase =
396 396 > [alias]
397 > rebate = !echo this is rebate
397 > rebate = !echo this is \$HG_ARGS
398 398 > EOF
399 399 $ hg reba
400 400 hg: command 'reba' is ambiguous:
401 401 rebase rebate
402 402 [255]
403 403 $ hg rebat
404 404 this is rebate
405 $ hg rebat --foo-bar
406 this is rebate --foo-bar
405 407
406 408 invalid arguments
407 409
408 410 $ hg rt foo
409 411 hg rt: invalid arguments
410 412 hg rt
411 413
412 414 alias for: hg root
413 415
414 416 (use "hg rt -h" to show more help)
415 417 [255]
416 418
417 419 invalid global arguments for normal commands, aliases, and shell aliases
418 420
419 421 $ hg --invalid root
420 422 hg: option --invalid not recognized
421 423 Mercurial Distributed SCM
422 424
423 425 basic commands:
424 426
425 427 add add the specified files on the next commit
426 428 annotate show changeset information by line for each file
427 429 clone make a copy of an existing repository
428 430 commit commit the specified files or all outstanding changes
429 431 diff diff repository (or selected files)
430 432 export dump the header and diffs for one or more changesets
431 433 forget forget the specified files on the next commit
432 434 init create a new repository in the given directory
433 435 log show revision history of entire repository or files
434 436 merge merge working directory with another revision
435 437 pull pull changes from the specified source
436 438 push push changes to the specified destination
437 439 remove remove the specified files on the next commit
438 440 serve start stand-alone webserver
439 441 status show changed files in the working directory
440 442 summary summarize working directory state
441 443 update update working directory (or switch revisions)
442 444
443 445 (use "hg help" for the full list of commands or "hg -v" for details)
444 446 [255]
445 447 $ hg --invalid mylog
446 448 hg: option --invalid not recognized
447 449 Mercurial Distributed SCM
448 450
449 451 basic commands:
450 452
451 453 add add the specified files on the next commit
452 454 annotate show changeset information by line for each file
453 455 clone make a copy of an existing repository
454 456 commit commit the specified files or all outstanding changes
455 457 diff diff repository (or selected files)
456 458 export dump the header and diffs for one or more changesets
457 459 forget forget the specified files on the next commit
458 460 init create a new repository in the given directory
459 461 log show revision history of entire repository or files
460 462 merge merge working directory with another revision
461 463 pull pull changes from the specified source
462 464 push push changes to the specified destination
463 465 remove remove the specified files on the next commit
464 466 serve start stand-alone webserver
465 467 status show changed files in the working directory
466 468 summary summarize working directory state
467 469 update update working directory (or switch revisions)
468 470
469 471 (use "hg help" for the full list of commands or "hg -v" for details)
470 472 [255]
471 473 $ hg --invalid blank
472 474 hg: option --invalid not recognized
473 475 Mercurial Distributed SCM
474 476
475 477 basic commands:
476 478
477 479 add add the specified files on the next commit
478 480 annotate show changeset information by line for each file
479 481 clone make a copy of an existing repository
480 482 commit commit the specified files or all outstanding changes
481 483 diff diff repository (or selected files)
482 484 export dump the header and diffs for one or more changesets
483 485 forget forget the specified files on the next commit
484 486 init create a new repository in the given directory
485 487 log show revision history of entire repository or files
486 488 merge merge working directory with another revision
487 489 pull pull changes from the specified source
488 490 push push changes to the specified destination
489 491 remove remove the specified files on the next commit
490 492 serve start stand-alone webserver
491 493 status show changed files in the working directory
492 494 summary summarize working directory state
493 495 update update working directory (or switch revisions)
494 496
495 497 (use "hg help" for the full list of commands or "hg -v" for details)
496 498 [255]
497 499
498 500 This should show id:
499 501
500 502 $ hg --config alias.log='id' log
501 503 000000000000 tip
502 504
503 505 This shouldn't:
504 506
505 507 $ hg --config alias.log='id' history
506 508
507 509 $ cd ../..
508 510
509 511 return code of command and shell aliases:
510 512
511 513 $ hg mycommit -R alias
512 514 nothing changed
513 515 [1]
514 516 $ hg exit1
515 517 [1]
General Comments 0
You need to be logged in to leave comments. Login now