##// END OF EJS Templates
dispatch: move shell alias handling after early arg handling...
Matt Mackall -
r14886:9a3831d6 default
parent child Browse files
Show More
@@ -1,729 +1,731
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, ferr=None):
16 16 self.args = args
17 17 self.ui = ui
18 18 self.repo = repo
19 19
20 20 # input/output/error streams
21 21 self.fin = fin
22 22 self.fout = fout
23 23 self.ferr = ferr
24 24
25 25 def run():
26 26 "run the command in sys.argv"
27 27 sys.exit(dispatch(request(sys.argv[1:])))
28 28
29 29 def dispatch(req):
30 30 "run the command specified in req.args"
31 31 if req.ferr:
32 32 ferr = req.ferr
33 33 elif req.ui:
34 34 ferr = req.ui.ferr
35 35 else:
36 36 ferr = sys.stderr
37 37
38 38 try:
39 39 if not req.ui:
40 40 req.ui = uimod.ui()
41 41 if '--traceback' in req.args:
42 42 req.ui.setconfig('ui', 'traceback', 'on')
43 43
44 44 # set ui streams from the request
45 45 if req.fin:
46 46 req.ui.fin = req.fin
47 47 if req.fout:
48 48 req.ui.fout = req.fout
49 49 if req.ferr:
50 50 req.ui.ferr = req.ferr
51 51 except util.Abort, inst:
52 52 ferr.write(_("abort: %s\n") % inst)
53 53 if inst.hint:
54 54 ferr.write(_("(%s)\n") % inst.hint)
55 55 return -1
56 56 except error.ParseError, inst:
57 57 if len(inst.args) > 1:
58 58 ferr.write(_("hg: parse error at %s: %s\n") %
59 59 (inst.args[1], inst.args[0]))
60 60 else:
61 61 ferr.write(_("hg: parse error: %s\n") % inst.args[0])
62 62 return -1
63 63
64 64 return _runcatch(req)
65 65
66 66 def _runcatch(req):
67 67 def catchterm(*args):
68 68 raise error.SignalInterrupt
69 69
70 70 ui = req.ui
71 71 try:
72 72 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
73 73 num = getattr(signal, name, None)
74 74 if num:
75 75 signal.signal(num, catchterm)
76 76 except ValueError:
77 77 pass # happens if called in a thread
78 78
79 79 try:
80 80 try:
81 81 # enter the debugger before command execution
82 82 if '--debugger' in req.args:
83 83 ui.warn(_("entering debugger - "
84 84 "type c to continue starting hg or h for help\n"))
85 85 pdb.set_trace()
86 86 try:
87 87 return _dispatch(req)
88 88 finally:
89 89 ui.flush()
90 90 except:
91 91 # enter the debugger when we hit an exception
92 92 if '--debugger' in req.args:
93 93 traceback.print_exc()
94 94 pdb.post_mortem(sys.exc_info()[2])
95 95 ui.traceback()
96 96 raise
97 97
98 98 # Global exception handling, alphabetically
99 99 # Mercurial-specific first, followed by built-in and library exceptions
100 100 except error.AmbiguousCommand, inst:
101 101 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
102 102 (inst.args[0], " ".join(inst.args[1])))
103 103 except error.ParseError, inst:
104 104 if len(inst.args) > 1:
105 105 ui.warn(_("hg: parse error at %s: %s\n") %
106 106 (inst.args[1], inst.args[0]))
107 107 else:
108 108 ui.warn(_("hg: parse error: %s\n") % inst.args[0])
109 109 return -1
110 110 except error.LockHeld, inst:
111 111 if inst.errno == errno.ETIMEDOUT:
112 112 reason = _('timed out waiting for lock held by %s') % inst.locker
113 113 else:
114 114 reason = _('lock held by %s') % inst.locker
115 115 ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
116 116 except error.LockUnavailable, inst:
117 117 ui.warn(_("abort: could not lock %s: %s\n") %
118 118 (inst.desc or inst.filename, inst.strerror))
119 119 except error.CommandError, inst:
120 120 if inst.args[0]:
121 121 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
122 122 commands.help_(ui, inst.args[0], full=False, command=True)
123 123 else:
124 124 ui.warn(_("hg: %s\n") % inst.args[1])
125 125 commands.help_(ui, 'shortlist')
126 126 except error.RepoError, inst:
127 127 ui.warn(_("abort: %s!\n") % inst)
128 128 if inst.hint:
129 129 ui.warn(_("(%s)\n") % inst.hint)
130 130 except error.ResponseError, inst:
131 131 ui.warn(_("abort: %s") % inst.args[0])
132 132 if not isinstance(inst.args[1], basestring):
133 133 ui.warn(" %r\n" % (inst.args[1],))
134 134 elif not inst.args[1]:
135 135 ui.warn(_(" empty string\n"))
136 136 else:
137 137 ui.warn("\n%r\n" % util.ellipsis(inst.args[1]))
138 138 except error.RevlogError, inst:
139 139 ui.warn(_("abort: %s!\n") % inst)
140 140 except error.SignalInterrupt:
141 141 ui.warn(_("killed!\n"))
142 142 except error.UnknownCommand, inst:
143 143 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
144 144 try:
145 145 # check if the command is in a disabled extension
146 146 # (but don't check for extensions themselves)
147 147 commands.help_(ui, inst.args[0], unknowncmd=True)
148 148 except error.UnknownCommand:
149 149 commands.help_(ui, 'shortlist')
150 150 except util.Abort, inst:
151 151 ui.warn(_("abort: %s\n") % inst)
152 152 if inst.hint:
153 153 ui.warn(_("(%s)\n") % inst.hint)
154 154 except ImportError, inst:
155 155 ui.warn(_("abort: %s!\n") % inst)
156 156 m = str(inst).split()[-1]
157 157 if m in "mpatch bdiff".split():
158 158 ui.warn(_("(did you forget to compile extensions?)\n"))
159 159 elif m in "zlib".split():
160 160 ui.warn(_("(is your Python install correct?)\n"))
161 161 except IOError, inst:
162 162 if hasattr(inst, "code"):
163 163 ui.warn(_("abort: %s\n") % inst)
164 164 elif hasattr(inst, "reason"):
165 165 try: # usually it is in the form (errno, strerror)
166 166 reason = inst.reason.args[1]
167 167 except (AttributeError, IndexError):
168 168 # it might be anything, for example a string
169 169 reason = inst.reason
170 170 ui.warn(_("abort: error: %s\n") % reason)
171 171 elif hasattr(inst, "args") and inst.args[0] == errno.EPIPE:
172 172 if ui.debugflag:
173 173 ui.warn(_("broken pipe\n"))
174 174 elif getattr(inst, "strerror", None):
175 175 if getattr(inst, "filename", None):
176 176 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
177 177 else:
178 178 ui.warn(_("abort: %s\n") % inst.strerror)
179 179 else:
180 180 raise
181 181 except OSError, inst:
182 182 if getattr(inst, "filename", None):
183 183 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
184 184 else:
185 185 ui.warn(_("abort: %s\n") % inst.strerror)
186 186 except KeyboardInterrupt:
187 187 try:
188 188 ui.warn(_("interrupted!\n"))
189 189 except IOError, inst:
190 190 if inst.errno == errno.EPIPE:
191 191 if ui.debugflag:
192 192 ui.warn(_("\nbroken pipe\n"))
193 193 else:
194 194 raise
195 195 except MemoryError:
196 196 ui.warn(_("abort: out of memory\n"))
197 197 except SystemExit, inst:
198 198 # Commands shouldn't sys.exit directly, but give a return code.
199 199 # Just in case catch this and and pass exit code to caller.
200 200 return inst.code
201 201 except socket.error, inst:
202 202 ui.warn(_("abort: %s\n") % inst.args[-1])
203 203 except:
204 204 ui.warn(_("** unknown exception encountered,"
205 205 " please report by visiting\n"))
206 206 ui.warn(_("** http://mercurial.selenic.com/wiki/BugTracker\n"))
207 207 ui.warn(_("** Python %s\n") % sys.version.replace('\n', ''))
208 208 ui.warn(_("** Mercurial Distributed SCM (version %s)\n")
209 209 % util.version())
210 210 ui.warn(_("** Extensions loaded: %s\n")
211 211 % ", ".join([x[0] for x in extensions.extensions()]))
212 212 raise
213 213
214 214 return -1
215 215
216 216 def aliasargs(fn, givenargs):
217 217 args = getattr(fn, 'args', [])
218 218 if args and givenargs:
219 219 cmd = ' '.join(map(util.shellquote, args))
220 220
221 221 nums = []
222 222 def replacer(m):
223 223 num = int(m.group(1)) - 1
224 224 nums.append(num)
225 225 return givenargs[num]
226 226 cmd = re.sub(r'\$(\d+|\$)', replacer, cmd)
227 227 givenargs = [x for i, x in enumerate(givenargs)
228 228 if i not in nums]
229 229 args = shlex.split(cmd)
230 230 return args + givenargs
231 231
232 232 class cmdalias(object):
233 233 def __init__(self, name, definition, cmdtable):
234 234 self.name = self.cmd = name
235 235 self.cmdname = ''
236 236 self.definition = definition
237 237 self.args = []
238 238 self.opts = []
239 239 self.help = ''
240 240 self.norepo = True
241 241 self.badalias = False
242 242
243 243 try:
244 244 aliases, entry = cmdutil.findcmd(self.name, cmdtable)
245 245 for alias, e in cmdtable.iteritems():
246 246 if e is entry:
247 247 self.cmd = alias
248 248 break
249 249 self.shadows = True
250 250 except error.UnknownCommand:
251 251 self.shadows = False
252 252
253 253 if not self.definition:
254 254 def fn(ui, *args):
255 255 ui.warn(_("no definition for alias '%s'\n") % self.name)
256 256 return 1
257 257 self.fn = fn
258 258 self.badalias = True
259 259
260 260 return
261 261
262 262 if self.definition.startswith('!'):
263 263 self.shell = True
264 264 def fn(ui, *args):
265 265 env = {'HG_ARGS': ' '.join((self.name,) + args)}
266 266 def _checkvar(m):
267 267 if m.groups()[0] == '$':
268 268 return m.group()
269 269 elif int(m.groups()[0]) <= len(args):
270 270 return m.group()
271 271 else:
272 272 ui.debug("No argument found for substitution "
273 273 "of %i variable in alias '%s' definition."
274 274 % (int(m.groups()[0]), self.name))
275 275 return ''
276 276 cmd = re.sub(r'\$(\d+|\$)', _checkvar, self.definition[1:])
277 277 replace = dict((str(i + 1), arg) for i, arg in enumerate(args))
278 278 replace['0'] = self.name
279 279 replace['@'] = ' '.join(args)
280 280 cmd = util.interpolate(r'\$', replace, cmd, escape_prefix=True)
281 281 return util.system(cmd, environ=env, out=ui.fout)
282 282 self.fn = fn
283 283 return
284 284
285 285 args = shlex.split(self.definition)
286 286 self.cmdname = cmd = args.pop(0)
287 287 args = map(util.expandpath, args)
288 288
289 289 for invalidarg in ("--cwd", "-R", "--repository", "--repo"):
290 290 if _earlygetopt([invalidarg], args):
291 291 def fn(ui, *args):
292 292 ui.warn(_("error in definition for alias '%s': %s may only "
293 293 "be given on the command line\n")
294 294 % (self.name, invalidarg))
295 295 return 1
296 296
297 297 self.fn = fn
298 298 self.badalias = True
299 299 return
300 300
301 301 try:
302 302 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
303 303 if len(tableentry) > 2:
304 304 self.fn, self.opts, self.help = tableentry
305 305 else:
306 306 self.fn, self.opts = tableentry
307 307
308 308 self.args = aliasargs(self.fn, args)
309 309 if cmd not in commands.norepo.split(' '):
310 310 self.norepo = False
311 311 if self.help.startswith("hg " + cmd):
312 312 # drop prefix in old-style help lines so hg shows the alias
313 313 self.help = self.help[4 + len(cmd):]
314 314 self.__doc__ = self.fn.__doc__
315 315
316 316 except error.UnknownCommand:
317 317 def fn(ui, *args):
318 318 ui.warn(_("alias '%s' resolves to unknown command '%s'\n") \
319 319 % (self.name, cmd))
320 320 try:
321 321 # check if the command is in a disabled extension
322 322 commands.help_(ui, cmd, unknowncmd=True)
323 323 except error.UnknownCommand:
324 324 pass
325 325 return 1
326 326 self.fn = fn
327 327 self.badalias = True
328 328 except error.AmbiguousCommand:
329 329 def fn(ui, *args):
330 330 ui.warn(_("alias '%s' resolves to ambiguous command '%s'\n") \
331 331 % (self.name, cmd))
332 332 return 1
333 333 self.fn = fn
334 334 self.badalias = True
335 335
336 336 def __call__(self, ui, *args, **opts):
337 337 if self.shadows:
338 338 ui.debug("alias '%s' shadows command '%s'\n" %
339 339 (self.name, self.cmdname))
340 340
341 341 if hasattr(self, 'shell'):
342 342 return self.fn(ui, *args, **opts)
343 343 else:
344 344 try:
345 345 util.checksignature(self.fn)(ui, *args, **opts)
346 346 except error.SignatureError:
347 347 args = ' '.join([self.cmdname] + self.args)
348 348 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args))
349 349 raise
350 350
351 351 def addaliases(ui, cmdtable):
352 352 # aliases are processed after extensions have been loaded, so they
353 353 # may use extension commands. Aliases can also use other alias definitions,
354 354 # but only if they have been defined prior to the current definition.
355 355 for alias, definition in ui.configitems('alias'):
356 356 aliasdef = cmdalias(alias, definition, cmdtable)
357 357 cmdtable[aliasdef.cmd] = (aliasdef, aliasdef.opts, aliasdef.help)
358 358 if aliasdef.norepo:
359 359 commands.norepo += ' %s' % alias
360 360
361 361 def _parse(ui, args):
362 362 options = {}
363 363 cmdoptions = {}
364 364
365 365 try:
366 366 args = fancyopts.fancyopts(args, commands.globalopts, options)
367 367 except fancyopts.getopt.GetoptError, inst:
368 368 raise error.CommandError(None, inst)
369 369
370 370 if args:
371 371 cmd, args = args[0], args[1:]
372 372 aliases, entry = cmdutil.findcmd(cmd, commands.table,
373 373 ui.config("ui", "strict"))
374 374 cmd = aliases[0]
375 375 args = aliasargs(entry[0], args)
376 376 defaults = ui.config("defaults", cmd)
377 377 if defaults:
378 378 args = map(util.expandpath, shlex.split(defaults)) + args
379 379 c = list(entry[1])
380 380 else:
381 381 cmd = None
382 382 c = []
383 383
384 384 # combine global options into local
385 385 for o in commands.globalopts:
386 386 c.append((o[0], o[1], options[o[1]], o[3]))
387 387
388 388 try:
389 389 args = fancyopts.fancyopts(args, c, cmdoptions, True)
390 390 except fancyopts.getopt.GetoptError, inst:
391 391 raise error.CommandError(cmd, inst)
392 392
393 393 # separate global options back out
394 394 for o in commands.globalopts:
395 395 n = o[1]
396 396 options[n] = cmdoptions[n]
397 397 del cmdoptions[n]
398 398
399 399 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
400 400
401 401 def _parseconfig(ui, config):
402 402 """parse the --config options from the command line"""
403 403 configs = []
404 404
405 405 for cfg in config:
406 406 try:
407 407 name, value = cfg.split('=', 1)
408 408 section, name = name.split('.', 1)
409 409 if not section or not name:
410 410 raise IndexError
411 411 ui.setconfig(section, name, value)
412 412 configs.append((section, name, value))
413 413 except (IndexError, ValueError):
414 414 raise util.Abort(_('malformed --config option: %r '
415 415 '(use --config section.name=value)') % cfg)
416 416
417 417 return configs
418 418
419 419 def _earlygetopt(aliases, args):
420 420 """Return list of values for an option (or aliases).
421 421
422 422 The values are listed in the order they appear in args.
423 423 The options and values are removed from args.
424 424 """
425 425 try:
426 426 argcount = args.index("--")
427 427 except ValueError:
428 428 argcount = len(args)
429 429 shortopts = [opt for opt in aliases if len(opt) == 2]
430 430 values = []
431 431 pos = 0
432 432 while pos < argcount:
433 433 if args[pos] in aliases:
434 434 if pos + 1 >= argcount:
435 435 # ignore and let getopt report an error if there is no value
436 436 break
437 437 del args[pos]
438 438 values.append(args.pop(pos))
439 439 argcount -= 2
440 440 elif args[pos][:2] in shortopts:
441 441 # short option can have no following space, e.g. hg log -Rfoo
442 442 values.append(args.pop(pos)[2:])
443 443 argcount -= 1
444 444 else:
445 445 pos += 1
446 446 return values
447 447
448 448 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
449 449 # run pre-hook, and abort if it fails
450 450 ret = hook.hook(lui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs),
451 451 pats=cmdpats, opts=cmdoptions)
452 452 if ret:
453 453 return ret
454 454 ret = _runcommand(ui, options, cmd, d)
455 455 # run post-hook, passing command result
456 456 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
457 457 result=ret, pats=cmdpats, opts=cmdoptions)
458 458 return ret
459 459
460 460 def _getlocal(ui, rpath):
461 461 """Return (path, local ui object) for the given target path.
462 462
463 463 Takes paths in [cwd]/.hg/hgrc into account."
464 464 """
465 465 try:
466 466 wd = os.getcwd()
467 467 except OSError, e:
468 468 raise util.Abort(_("error getting current working directory: %s") %
469 469 e.strerror)
470 470 path = cmdutil.findrepo(wd) or ""
471 471 if not path:
472 472 lui = ui
473 473 else:
474 474 lui = ui.copy()
475 475 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
476 476
477 477 if rpath and rpath[-1]:
478 478 path = lui.expandpath(rpath[-1])
479 479 lui = ui.copy()
480 480 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
481 481
482 482 return path, lui
483 483
484 484 def _checkshellalias(ui, args):
485 485 cwd = os.getcwd()
486 486 norepo = commands.norepo
487 487 options = {}
488 488
489 489 try:
490 490 args = fancyopts.fancyopts(args, commands.globalopts, options)
491 491 except fancyopts.getopt.GetoptError:
492 492 return
493 493
494 494 if not args:
495 495 return
496 496
497 497 _parseconfig(ui, options['config'])
498 498 if options['cwd']:
499 499 os.chdir(options['cwd'])
500 500
501 501 path, lui = _getlocal(ui, [options['repository']])
502 502
503 503 cmdtable = commands.table.copy()
504 504 addaliases(lui, cmdtable)
505 505
506 506 cmd = args[0]
507 507 try:
508 508 aliases, entry = cmdutil.findcmd(cmd, cmdtable, lui.config("ui", "strict"))
509 509 except (error.AmbiguousCommand, error.UnknownCommand):
510 510 commands.norepo = norepo
511 511 os.chdir(cwd)
512 512 return
513 513
514 514 cmd = aliases[0]
515 515 fn = entry[0]
516 516
517 517 if cmd and hasattr(fn, 'shell'):
518 518 d = lambda: fn(ui, *args[1:])
519 519 return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d, [], {})
520 520
521 521 commands.norepo = norepo
522 522 os.chdir(cwd)
523 523
524 524 _loaded = set()
525 525 def _dispatch(req):
526 526 args = req.args
527 527 ui = req.ui
528 528
529 shellaliasfn = _checkshellalias(ui, args)
530 if shellaliasfn:
531 return shellaliasfn()
532
533 529 # read --config before doing anything else
534 530 # (e.g. to change trust settings for reading .hg/hgrc)
535 531 cfgs = _parseconfig(ui, _earlygetopt(['--config'], args))
536 532
537 533 # check for cwd
538 534 cwd = _earlygetopt(['--cwd'], args)
539 535 if cwd:
540 536 os.chdir(cwd[-1])
541 537
542 538 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
543 539 path, lui = _getlocal(ui, rpath)
544 540
541 # Now that we're operating in the right directory/repository with
542 # the right config settings, check for shell aliases
543 shellaliasfn = _checkshellalias(ui, args)
544 if shellaliasfn:
545 return shellaliasfn()
546
545 547 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
546 548 # reposetup. Programs like TortoiseHg will call _dispatch several
547 549 # times so we keep track of configured extensions in _loaded.
548 550 extensions.loadall(lui)
549 551 exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
550 552 # Propagate any changes to lui.__class__ by extensions
551 553 ui.__class__ = lui.__class__
552 554
553 555 # (uisetup and extsetup are handled in extensions.loadall)
554 556
555 557 for name, module in exts:
556 558 cmdtable = getattr(module, 'cmdtable', {})
557 559 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
558 560 if overrides:
559 561 ui.warn(_("extension '%s' overrides commands: %s\n")
560 562 % (name, " ".join(overrides)))
561 563 commands.table.update(cmdtable)
562 564 _loaded.add(name)
563 565
564 566 # (reposetup is handled in hg.repository)
565 567
566 568 addaliases(lui, commands.table)
567 569
568 570 # check for fallback encoding
569 571 fallback = lui.config('ui', 'fallbackencoding')
570 572 if fallback:
571 573 encoding.fallbackencoding = fallback
572 574
573 575 fullargs = args
574 576 cmd, func, args, options, cmdoptions = _parse(lui, args)
575 577
576 578 if options["config"]:
577 579 raise util.Abort(_("option --config may not be abbreviated!"))
578 580 if options["cwd"]:
579 581 raise util.Abort(_("option --cwd may not be abbreviated!"))
580 582 if options["repository"]:
581 583 raise util.Abort(_(
582 584 "Option -R has to be separated from other options (e.g. not -qR) "
583 585 "and --repository may only be abbreviated as --repo!"))
584 586
585 587 if options["encoding"]:
586 588 encoding.encoding = options["encoding"]
587 589 if options["encodingmode"]:
588 590 encoding.encodingmode = options["encodingmode"]
589 591 if options["time"]:
590 592 def get_times():
591 593 t = os.times()
592 594 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
593 595 t = (t[0], t[1], t[2], t[3], time.clock())
594 596 return t
595 597 s = get_times()
596 598 def print_time():
597 599 t = get_times()
598 600 ui.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
599 601 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
600 602 atexit.register(print_time)
601 603
602 604 uis = set([ui, lui])
603 605
604 606 if req.repo:
605 607 uis.add(req.repo.ui)
606 608
607 609 # copy configs that were passed on the cmdline (--config) to the repo ui
608 610 for cfg in cfgs:
609 611 req.repo.ui.setconfig(*cfg)
610 612
611 613 for opt in ('verbose', 'debug', 'quiet', 'traceback'):
612 614 val = bool(options[opt])
613 615 if val:
614 616 for ui_ in uis:
615 617 ui_.setconfig('ui', opt, str(val))
616 618
617 619 if options['noninteractive']:
618 620 for ui_ in uis:
619 621 ui_.setconfig('ui', 'interactive', 'off')
620 622
621 623 if cmdoptions.get('insecure', False):
622 624 for ui_ in uis:
623 625 ui_.setconfig('web', 'cacerts', '')
624 626
625 627 if options['help']:
626 628 return commands.help_(ui, cmd, options['version'])
627 629 elif options['version']:
628 630 return commands.version_(ui)
629 631 elif not cmd:
630 632 return commands.help_(ui, 'shortlist')
631 633
632 634 repo = None
633 635 cmdpats = args[:]
634 636 if cmd not in commands.norepo.split():
635 637 # use the repo from the request only if we don't have -R
636 638 if not rpath and not cwd:
637 639 repo = req.repo
638 640
639 641 if repo:
640 642 # set the descriptors of the repo ui to those of ui
641 643 repo.ui.fin = ui.fin
642 644 repo.ui.fout = ui.fout
643 645 repo.ui.ferr = ui.ferr
644 646 else:
645 647 try:
646 648 repo = hg.repository(ui, path=path)
647 649 if not repo.local():
648 650 raise util.Abort(_("repository '%s' is not local") % path)
649 651 repo.ui.setconfig("bundle", "mainreporoot", repo.root)
650 652 except error.RequirementError:
651 653 raise
652 654 except error.RepoError:
653 655 if cmd not in commands.optionalrepo.split():
654 656 if args and not path: # try to infer -R from command args
655 657 repos = map(cmdutil.findrepo, args)
656 658 guess = repos[0]
657 659 if guess and repos.count(guess) == len(repos):
658 660 req.args = ['--repository', guess] + fullargs
659 661 return _dispatch(req)
660 662 if not path:
661 663 raise error.RepoError(_("no repository found in %r"
662 664 " (.hg not found)") % os.getcwd())
663 665 raise
664 666 if repo:
665 667 ui = repo.ui
666 668 args.insert(0, repo)
667 669 elif rpath:
668 670 ui.warn(_("warning: --repository ignored\n"))
669 671
670 672 msg = ' '.join(' ' in a and repr(a) or a for a in fullargs)
671 673 ui.log("command", msg + "\n")
672 674 d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
673 675 try:
674 676 return runcommand(lui, repo, cmd, fullargs, ui, options, d,
675 677 cmdpats, cmdoptions)
676 678 finally:
677 679 if repo and repo != req.repo:
678 680 repo.close()
679 681
680 682 def _runcommand(ui, options, cmd, cmdfunc):
681 683 def checkargs():
682 684 try:
683 685 return cmdfunc()
684 686 except error.SignatureError:
685 687 raise error.CommandError(cmd, _("invalid arguments"))
686 688
687 689 if options['profile']:
688 690 format = ui.config('profiling', 'format', default='text')
689 691
690 692 if not format in ['text', 'kcachegrind']:
691 693 ui.warn(_("unrecognized profiling format '%s'"
692 694 " - Ignored\n") % format)
693 695 format = 'text'
694 696
695 697 output = ui.config('profiling', 'output')
696 698
697 699 if output:
698 700 path = ui.expandpath(output)
699 701 ostream = open(path, 'wb')
700 702 else:
701 703 ostream = sys.stderr
702 704
703 705 try:
704 706 from mercurial import lsprof
705 707 except ImportError:
706 708 raise util.Abort(_(
707 709 'lsprof not available - install from '
708 710 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
709 711 p = lsprof.Profiler()
710 712 p.enable(subcalls=True)
711 713 try:
712 714 return checkargs()
713 715 finally:
714 716 p.disable()
715 717
716 718 if format == 'kcachegrind':
717 719 import lsprofcalltree
718 720 calltree = lsprofcalltree.KCacheGrind(p)
719 721 calltree.output(ostream)
720 722 else:
721 723 # format == 'text'
722 724 stats = lsprof.Stats(p.getstats())
723 725 stats.sort()
724 726 stats.pprint(top=10, file=ostream, climit=5)
725 727
726 728 if output:
727 729 ostream.close()
728 730 else:
729 731 return checkargs()
@@ -1,395 +1,394
1 1 $ HGFOO=BAR; export HGFOO
2 2 $ cat >> $HGRCPATH <<EOF
3 3 > [extensions]
4 4 > graphlog=
5 5 >
6 6 > [alias]
7 7 > myinit = init
8 8 > cleanstatus = status -c
9 9 > unknown = bargle
10 10 > ambiguous = s
11 11 > recursive = recursive
12 12 > nodefinition =
13 13 > no--cwd = status --cwd elsewhere
14 14 > no-R = status -R elsewhere
15 15 > no--repo = status --repo elsewhere
16 16 > no--repository = status --repository elsewhere
17 17 > mylog = log
18 18 > lognull = log -r null
19 19 > shortlog = log --template '{rev} {node|short} | {date|isodate}\n'
20 20 > positional = log --template '{\$2} {\$1} | {date|isodate}\n'
21 21 > dln = lognull --debug
22 22 > nousage = rollback
23 23 > put = export -r 0 -o "\$FOO/%R.diff"
24 24 > blank = !echo
25 25 > self = !echo '\$0'
26 26 > echo = !echo '\$@'
27 27 > echo1 = !echo '\$1'
28 28 > echo2 = !echo '\$2'
29 29 > echo13 = !echo '\$1' '\$3'
30 30 > count = !hg log -r '\$@' --template='.' | wc -c | sed -e 's/ //g'
31 31 > mcount = !hg log \$@ --template='.' | wc -c | sed -e 's/ //g'
32 32 > rt = root
33 33 > tglog = glog --template "{rev}:{node|short}: '{desc}' {branches}\n"
34 34 > idalias = id
35 35 > idaliaslong = id
36 36 > idaliasshell = !echo test
37 37 > parentsshell1 = !echo one
38 38 > parentsshell2 = !echo two
39 39 > escaped1 = !echo 'test\$\$test'
40 40 > escaped2 = !echo "HGFOO is \$\$HGFOO"
41 41 > escaped3 = !echo "\$1 is \$\$\$1"
42 42 > escaped4 = !echo '\$\$0' '\$\$@'
43 43 >
44 44 > [defaults]
45 45 > mylog = -q
46 46 > lognull = -q
47 47 > log = -v
48 48 > EOF
49 49
50 50
51 51 basic
52 52
53 53 $ hg myinit alias
54 54
55 55
56 56 unknown
57 57
58 58 $ hg unknown
59 59 alias 'unknown' resolves to unknown command 'bargle'
60 60 $ hg help unknown
61 61 alias 'unknown' resolves to unknown command 'bargle'
62 62
63 63
64 64 ambiguous
65 65
66 66 $ hg ambiguous
67 67 alias 'ambiguous' resolves to ambiguous command 's'
68 68 $ hg help ambiguous
69 69 alias 'ambiguous' resolves to ambiguous command 's'
70 70
71 71
72 72 recursive
73 73
74 74 $ hg recursive
75 75 alias 'recursive' resolves to unknown command 'recursive'
76 76 $ hg help recursive
77 77 alias 'recursive' resolves to unknown command 'recursive'
78 78
79 79
80 80 no definition
81 81
82 82 $ hg nodef
83 83 no definition for alias 'nodefinition'
84 84 $ hg help nodef
85 85 no definition for alias 'nodefinition'
86 86
87 87
88 88 invalid options
89 89
90 90 $ hg no--cwd
91 91 error in definition for alias 'no--cwd': --cwd may only be given on the command line
92 92 $ hg help no--cwd
93 93 error in definition for alias 'no--cwd': --cwd may only be given on the command line
94 94 $ hg no-R
95 95 error in definition for alias 'no-R': -R may only be given on the command line
96 96 $ hg help no-R
97 97 error in definition for alias 'no-R': -R may only be given on the command line
98 98 $ hg no--repo
99 99 error in definition for alias 'no--repo': --repo may only be given on the command line
100 100 $ hg help no--repo
101 101 error in definition for alias 'no--repo': --repo may only be given on the command line
102 102 $ hg no--repository
103 103 error in definition for alias 'no--repository': --repository may only be given on the command line
104 104 $ hg help no--repository
105 105 error in definition for alias 'no--repository': --repository may only be given on the command line
106 106
107 107 $ cd alias
108 108
109 109
110 110 no usage
111 111
112 112 $ hg nousage
113 113 no rollback information available
114 114
115 115 $ echo foo > foo
116 116 $ hg ci -Amfoo
117 117 adding foo
118 118
119 119
120 120 with opts
121 121
122 122 $ hg cleanst
123 123 C foo
124 124
125 125
126 126 with opts and whitespace
127 127
128 128 $ hg shortlog
129 129 0 e63c23eaa88a | 1970-01-01 00:00 +0000
130 130
131 131 positional arguments
132 132
133 133 $ hg positional 'node|short' rev
134 134 0 e63c23eaa88a | 1970-01-01 00:00 +0000
135 135
136 136 interaction with defaults
137 137
138 138 $ hg mylog
139 139 0:e63c23eaa88a
140 140 $ hg lognull
141 141 -1:000000000000
142 142
143 143
144 144 properly recursive
145 145
146 146 $ hg dln
147 147 changeset: -1:0000000000000000000000000000000000000000
148 148 parent: -1:0000000000000000000000000000000000000000
149 149 parent: -1:0000000000000000000000000000000000000000
150 150 manifest: -1:0000000000000000000000000000000000000000
151 151 user:
152 152 date: Thu Jan 01 00:00:00 1970 +0000
153 153 extra: branch=default
154 154
155 155
156 156
157 157 path expanding
158 158
159 159 $ FOO=`pwd` hg put
160 160 $ cat 0.diff
161 161 # HG changeset patch
162 162 # User test
163 163 # Date 0 0
164 164 # Node ID e63c23eaa88ae77967edcf4ea194d31167c478b0
165 165 # Parent 0000000000000000000000000000000000000000
166 166 foo
167 167
168 168 diff -r 000000000000 -r e63c23eaa88a foo
169 169 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
170 170 +++ b/foo Thu Jan 01 00:00:00 1970 +0000
171 171 @@ -0,0 +1,1 @@
172 172 +foo
173 173
174 174
175 175 simple shell aliases
176 176
177 177 $ hg blank
178 178
179 179 $ hg blank foo
180 180
181 181 $ hg self
182 182 self
183 183 $ hg echo
184 184
185 185 $ hg echo foo
186 186 foo
187 187 $ hg echo 'test $2' foo
188 188 test $2 foo
189 189 $ hg echo1 foo bar baz
190 190 foo
191 191 $ hg echo2 foo bar baz
192 192 bar
193 193 $ hg echo13 foo bar baz test
194 194 foo baz
195 195 $ hg echo2 foo
196 196
197 197 $ echo bar > bar
198 198 $ hg ci -qA -m bar
199 199 $ hg count .
200 200 1
201 201 $ hg count 'branch(default)'
202 202 2
203 203 $ hg mcount -r '"branch(default)"'
204 204 2
205 205
206 206 $ hg tglog
207 207 @ 1:7e7f92de180e: 'bar'
208 208 |
209 209 o 0:e63c23eaa88a: 'foo'
210 210
211 211
212 212
213 213 shadowing
214 214
215 215 $ hg i
216 216 hg: command 'i' is ambiguous:
217 217 idalias idaliaslong idaliasshell identify import incoming init
218 218 [255]
219 219 $ hg id
220 220 7e7f92de180e tip
221 221 $ hg ida
222 222 hg: command 'ida' is ambiguous:
223 223 idalias idaliaslong idaliasshell
224 224 [255]
225 225 $ hg idalias
226 226 7e7f92de180e tip
227 227 $ hg idaliasl
228 228 7e7f92de180e tip
229 229 $ hg idaliass
230 230 test
231 231 $ hg parentsshell
232 232 hg: command 'parentsshell' is ambiguous:
233 233 parentsshell1 parentsshell2
234 234 [255]
235 235 $ hg parentsshell1
236 236 one
237 237 $ hg parentsshell2
238 238 two
239 239
240 240
241 241 shell aliases with global options
242 242
243 243 $ hg init sub
244 244 $ cd sub
245 245 $ hg count 'branch(default)'
246 246 0
247 247 $ hg -v count 'branch(default)'
248 248 0
249 249 $ hg -R .. count 'branch(default)'
250 250 0
251 251 $ hg --cwd .. count 'branch(default)'
252 252 2
253 253 $ hg echo --cwd ..
254 --cwd ..
254
255 255
256 256
257 257 repo specific shell aliases
258 258
259 259 $ cat >> .hg/hgrc <<EOF
260 260 > [alias]
261 261 > subalias = !echo sub \$@
262 262 > EOF
263 263 $ cat >> ../.hg/hgrc <<EOF
264 264 > [alias]
265 265 > mainalias = !echo main \$@
266 266 > EOF
267 267
268 268
269 269 shell alias defined in current repo
270 270
271 271 $ hg subalias
272 272 sub
273 273 $ hg --cwd .. subalias > /dev/null
274 274 hg: unknown command 'subalias'
275 275 [255]
276 276 $ hg -R .. subalias > /dev/null
277 hg: unknown command 'subalias'
278 [255]
279 277
280 278
281 279 shell alias defined in other repo
282 280
283 281 $ hg mainalias > /dev/null
284 282 hg: unknown command 'mainalias'
285 283 [255]
286 284 $ hg -R .. mainalias
285 warning: --repository ignored
287 286 main
288 287 $ hg --cwd .. mainalias
289 288 main
290 289
291 290
292 291 shell aliases with escaped $ chars
293 292
294 293 $ hg escaped1
295 294 test$test
296 295 $ hg escaped2
297 296 HGFOO is BAR
298 297 $ hg escaped3 HGFOO
299 298 HGFOO is BAR
300 299 $ hg escaped4 test
301 300 $0 $@
302 301
303 302
304 303 invalid arguments
305 304
306 305 $ hg rt foo
307 306 hg rt: invalid arguments
308 307 hg rt
309 308
310 309 alias for: hg root
311 310
312 311 use "hg help rt" to show the full help text
313 312 [255]
314 313
315 314 invalid global arguments for normal commands, aliases, and shell aliases
316 315
317 316 $ hg --invalid root
318 317 hg: option --invalid not recognized
319 318 Mercurial Distributed SCM
320 319
321 320 basic commands:
322 321
323 322 add add the specified files on the next commit
324 323 annotate show changeset information by line for each file
325 324 clone make a copy of an existing repository
326 325 commit commit the specified files or all outstanding changes
327 326 diff diff repository (or selected files)
328 327 export dump the header and diffs for one or more changesets
329 328 forget forget the specified files on the next commit
330 329 init create a new repository in the given directory
331 330 log show revision history of entire repository or files
332 331 merge merge working directory with another revision
333 332 pull pull changes from the specified source
334 333 push push changes to the specified destination
335 334 remove remove the specified files on the next commit
336 335 serve start stand-alone webserver
337 336 status show changed files in the working directory
338 337 summary summarize working directory state
339 338 update update working directory (or switch revisions)
340 339
341 340 use "hg help" for the full list of commands or "hg -v" for details
342 341 [255]
343 342 $ hg --invalid mylog
344 343 hg: option --invalid not recognized
345 344 Mercurial Distributed SCM
346 345
347 346 basic commands:
348 347
349 348 add add the specified files on the next commit
350 349 annotate show changeset information by line for each file
351 350 clone make a copy of an existing repository
352 351 commit commit the specified files or all outstanding changes
353 352 diff diff repository (or selected files)
354 353 export dump the header and diffs for one or more changesets
355 354 forget forget the specified files on the next commit
356 355 init create a new repository in the given directory
357 356 log show revision history of entire repository or files
358 357 merge merge working directory with another revision
359 358 pull pull changes from the specified source
360 359 push push changes to the specified destination
361 360 remove remove the specified files on the next commit
362 361 serve start stand-alone webserver
363 362 status show changed files in the working directory
364 363 summary summarize working directory state
365 364 update update working directory (or switch revisions)
366 365
367 366 use "hg help" for the full list of commands or "hg -v" for details
368 367 [255]
369 368 $ hg --invalid blank
370 369 hg: option --invalid not recognized
371 370 Mercurial Distributed SCM
372 371
373 372 basic commands:
374 373
375 374 add add the specified files on the next commit
376 375 annotate show changeset information by line for each file
377 376 clone make a copy of an existing repository
378 377 commit commit the specified files or all outstanding changes
379 378 diff diff repository (or selected files)
380 379 export dump the header and diffs for one or more changesets
381 380 forget forget the specified files on the next commit
382 381 init create a new repository in the given directory
383 382 log show revision history of entire repository or files
384 383 merge merge working directory with another revision
385 384 pull pull changes from the specified source
386 385 push push changes to the specified destination
387 386 remove remove the specified files on the next commit
388 387 serve start stand-alone webserver
389 388 status show changed files in the working directory
390 389 summary summarize working directory state
391 390 update update working directory (or switch revisions)
392 391
393 392 use "hg help" for the full list of commands or "hg -v" for details
394 393 [255]
395 394
General Comments 0
You need to be logged in to leave comments. Login now