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