##// END OF EJS Templates
dispatch: catch InterventionRequired and print the message with no prefix
Augie Fackler -
r18932:7b4b9e8e default
parent child Browse files
Show More
@@ -1,841 +1,843 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 except error.InterventionRequired, inst:
155 ui.warn("%s\n" % inst)
154 156 except util.Abort, inst:
155 157 ui.warn(_("abort: %s\n") % inst)
156 158 if inst.hint:
157 159 ui.warn(_("(%s)\n") % inst.hint)
158 160 except ImportError, inst:
159 161 ui.warn(_("abort: %s!\n") % inst)
160 162 m = str(inst).split()[-1]
161 163 if m in "mpatch bdiff".split():
162 164 ui.warn(_("(did you forget to compile extensions?)\n"))
163 165 elif m in "zlib".split():
164 166 ui.warn(_("(is your Python install correct?)\n"))
165 167 except IOError, inst:
166 168 if util.safehasattr(inst, "code"):
167 169 ui.warn(_("abort: %s\n") % inst)
168 170 elif util.safehasattr(inst, "reason"):
169 171 try: # usually it is in the form (errno, strerror)
170 172 reason = inst.reason.args[1]
171 173 except (AttributeError, IndexError):
172 174 # it might be anything, for example a string
173 175 reason = inst.reason
174 176 ui.warn(_("abort: error: %s\n") % reason)
175 177 elif util.safehasattr(inst, "args") and inst.args[0] == errno.EPIPE:
176 178 if ui.debugflag:
177 179 ui.warn(_("broken pipe\n"))
178 180 elif getattr(inst, "strerror", None):
179 181 if getattr(inst, "filename", None):
180 182 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
181 183 else:
182 184 ui.warn(_("abort: %s\n") % inst.strerror)
183 185 else:
184 186 raise
185 187 except OSError, inst:
186 188 if getattr(inst, "filename", None) is not None:
187 189 ui.warn(_("abort: %s: '%s'\n") % (inst.strerror, inst.filename))
188 190 else:
189 191 ui.warn(_("abort: %s\n") % inst.strerror)
190 192 except KeyboardInterrupt:
191 193 try:
192 194 ui.warn(_("interrupted!\n"))
193 195 except IOError, inst:
194 196 if inst.errno == errno.EPIPE:
195 197 if ui.debugflag:
196 198 ui.warn(_("\nbroken pipe\n"))
197 199 else:
198 200 raise
199 201 except MemoryError:
200 202 ui.warn(_("abort: out of memory\n"))
201 203 except SystemExit, inst:
202 204 # Commands shouldn't sys.exit directly, but give a return code.
203 205 # Just in case catch this and and pass exit code to caller.
204 206 return inst.code
205 207 except socket.error, inst:
206 208 ui.warn(_("abort: %s\n") % inst.args[-1])
207 209 except: # re-raises
208 210 myver = util.version()
209 211 # For compatibility checking, we discard the portion of the hg
210 212 # version after the + on the assumption that if a "normal
211 213 # user" is running a build with a + in it the packager
212 214 # probably built from fairly close to a tag and anyone with a
213 215 # 'make local' copy of hg (where the version number can be out
214 216 # of date) will be clueful enough to notice the implausible
215 217 # version number and try updating.
216 218 compare = myver.split('+')[0]
217 219 ct = tuplever(compare)
218 220 worst = None, ct, ''
219 221 for name, mod in extensions.extensions():
220 222 testedwith = getattr(mod, 'testedwith', '')
221 223 report = getattr(mod, 'buglink', _('the extension author.'))
222 224 if not testedwith.strip():
223 225 # We found an untested extension. It's likely the culprit.
224 226 worst = name, 'unknown', report
225 227 break
226 228 if compare not in testedwith.split() and testedwith != 'internal':
227 229 tested = [tuplever(v) for v in testedwith.split()]
228 230 lower = [t for t in tested if t < ct]
229 231 nearest = max(lower or tested)
230 232 if worst[0] is None or nearest < worst[1]:
231 233 worst = name, nearest, report
232 234 if worst[0] is not None:
233 235 name, testedwith, report = worst
234 236 if not isinstance(testedwith, str):
235 237 testedwith = '.'.join([str(c) for c in testedwith])
236 238 warning = (_('** Unknown exception encountered with '
237 239 'possibly-broken third-party extension %s\n'
238 240 '** which supports versions %s of Mercurial.\n'
239 241 '** Please disable %s and try your action again.\n'
240 242 '** If that fixes the bug please report it to %s\n')
241 243 % (name, testedwith, name, report))
242 244 else:
243 245 warning = (_("** unknown exception encountered, "
244 246 "please report by visiting\n") +
245 247 _("** http://mercurial.selenic.com/wiki/BugTracker\n"))
246 248 warning += ((_("** Python %s\n") % sys.version.replace('\n', '')) +
247 249 (_("** Mercurial Distributed SCM (version %s)\n") % myver) +
248 250 (_("** Extensions loaded: %s\n") %
249 251 ", ".join([x[0] for x in extensions.extensions()])))
250 252 ui.log("commandexception", "%s\n%s\n", warning, traceback.format_exc())
251 253 ui.warn(warning)
252 254 raise
253 255
254 256 return -1
255 257
256 258 def tuplever(v):
257 259 try:
258 260 return tuple([int(i) for i in v.split('.')])
259 261 except ValueError:
260 262 return tuple()
261 263
262 264 def aliasargs(fn, givenargs):
263 265 args = getattr(fn, 'args', [])
264 266 if args:
265 267 cmd = ' '.join(map(util.shellquote, args))
266 268
267 269 nums = []
268 270 def replacer(m):
269 271 num = int(m.group(1)) - 1
270 272 nums.append(num)
271 273 if num < len(givenargs):
272 274 return givenargs[num]
273 275 raise util.Abort(_('too few arguments for command alias'))
274 276 cmd = re.sub(r'\$(\d+|\$)', replacer, cmd)
275 277 givenargs = [x for i, x in enumerate(givenargs)
276 278 if i not in nums]
277 279 args = shlex.split(cmd)
278 280 return args + givenargs
279 281
280 282 class cmdalias(object):
281 283 def __init__(self, name, definition, cmdtable):
282 284 self.name = self.cmd = name
283 285 self.cmdname = ''
284 286 self.definition = definition
285 287 self.args = []
286 288 self.opts = []
287 289 self.help = ''
288 290 self.norepo = True
289 291 self.optionalrepo = False
290 292 self.badalias = False
291 293
292 294 try:
293 295 aliases, entry = cmdutil.findcmd(self.name, cmdtable)
294 296 for alias, e in cmdtable.iteritems():
295 297 if e is entry:
296 298 self.cmd = alias
297 299 break
298 300 self.shadows = True
299 301 except error.UnknownCommand:
300 302 self.shadows = False
301 303
302 304 if not self.definition:
303 305 def fn(ui, *args):
304 306 ui.warn(_("no definition for alias '%s'\n") % self.name)
305 307 return 1
306 308 self.fn = fn
307 309 self.badalias = True
308 310 return
309 311
310 312 if self.definition.startswith('!'):
311 313 self.shell = True
312 314 def fn(ui, *args):
313 315 env = {'HG_ARGS': ' '.join((self.name,) + args)}
314 316 def _checkvar(m):
315 317 if m.groups()[0] == '$':
316 318 return m.group()
317 319 elif int(m.groups()[0]) <= len(args):
318 320 return m.group()
319 321 else:
320 322 ui.debug("No argument found for substitution "
321 323 "of %i variable in alias '%s' definition."
322 324 % (int(m.groups()[0]), self.name))
323 325 return ''
324 326 cmd = re.sub(r'\$(\d+|\$)', _checkvar, self.definition[1:])
325 327 replace = dict((str(i + 1), arg) for i, arg in enumerate(args))
326 328 replace['0'] = self.name
327 329 replace['@'] = ' '.join(args)
328 330 cmd = util.interpolate(r'\$', replace, cmd, escape_prefix=True)
329 331 return util.system(cmd, environ=env, out=ui.fout)
330 332 self.fn = fn
331 333 return
332 334
333 335 args = shlex.split(self.definition)
334 336 self.cmdname = cmd = args.pop(0)
335 337 args = map(util.expandpath, args)
336 338
337 339 for invalidarg in ("--cwd", "-R", "--repository", "--repo", "--config"):
338 340 if _earlygetopt([invalidarg], args):
339 341 def fn(ui, *args):
340 342 ui.warn(_("error in definition for alias '%s': %s may only "
341 343 "be given on the command line\n")
342 344 % (self.name, invalidarg))
343 345 return 1
344 346
345 347 self.fn = fn
346 348 self.badalias = True
347 349 return
348 350
349 351 try:
350 352 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
351 353 if len(tableentry) > 2:
352 354 self.fn, self.opts, self.help = tableentry
353 355 else:
354 356 self.fn, self.opts = tableentry
355 357
356 358 self.args = aliasargs(self.fn, args)
357 359 if cmd not in commands.norepo.split(' '):
358 360 self.norepo = False
359 361 if cmd in commands.optionalrepo.split(' '):
360 362 self.optionalrepo = True
361 363 if self.help.startswith("hg " + cmd):
362 364 # drop prefix in old-style help lines so hg shows the alias
363 365 self.help = self.help[4 + len(cmd):]
364 366 self.__doc__ = self.fn.__doc__
365 367
366 368 except error.UnknownCommand:
367 369 def fn(ui, *args):
368 370 ui.warn(_("alias '%s' resolves to unknown command '%s'\n") \
369 371 % (self.name, cmd))
370 372 try:
371 373 # check if the command is in a disabled extension
372 374 commands.help_(ui, cmd, unknowncmd=True)
373 375 except error.UnknownCommand:
374 376 pass
375 377 return 1
376 378 self.fn = fn
377 379 self.badalias = True
378 380 except error.AmbiguousCommand:
379 381 def fn(ui, *args):
380 382 ui.warn(_("alias '%s' resolves to ambiguous command '%s'\n") \
381 383 % (self.name, cmd))
382 384 return 1
383 385 self.fn = fn
384 386 self.badalias = True
385 387
386 388 def __call__(self, ui, *args, **opts):
387 389 if self.shadows:
388 390 ui.debug("alias '%s' shadows command '%s'\n" %
389 391 (self.name, self.cmdname))
390 392
391 393 if util.safehasattr(self, 'shell'):
392 394 return self.fn(ui, *args, **opts)
393 395 else:
394 396 try:
395 397 util.checksignature(self.fn)(ui, *args, **opts)
396 398 except error.SignatureError:
397 399 args = ' '.join([self.cmdname] + self.args)
398 400 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args))
399 401 raise
400 402
401 403 def addaliases(ui, cmdtable):
402 404 # aliases are processed after extensions have been loaded, so they
403 405 # may use extension commands. Aliases can also use other alias definitions,
404 406 # but only if they have been defined prior to the current definition.
405 407 for alias, definition in ui.configitems('alias'):
406 408 aliasdef = cmdalias(alias, definition, cmdtable)
407 409
408 410 try:
409 411 olddef = cmdtable[aliasdef.cmd][0]
410 412 if olddef.definition == aliasdef.definition:
411 413 continue
412 414 except (KeyError, AttributeError):
413 415 # definition might not exist or it might not be a cmdalias
414 416 pass
415 417
416 418 cmdtable[aliasdef.name] = (aliasdef, aliasdef.opts, aliasdef.help)
417 419 if aliasdef.norepo:
418 420 commands.norepo += ' %s' % alias
419 421 if aliasdef.optionalrepo:
420 422 commands.optionalrepo += ' %s' % alias
421 423
422 424 def _parse(ui, args):
423 425 options = {}
424 426 cmdoptions = {}
425 427
426 428 try:
427 429 args = fancyopts.fancyopts(args, commands.globalopts, options)
428 430 except fancyopts.getopt.GetoptError, inst:
429 431 raise error.CommandError(None, inst)
430 432
431 433 if args:
432 434 cmd, args = args[0], args[1:]
433 435 aliases, entry = cmdutil.findcmd(cmd, commands.table,
434 436 ui.configbool("ui", "strict"))
435 437 cmd = aliases[0]
436 438 args = aliasargs(entry[0], args)
437 439 defaults = ui.config("defaults", cmd)
438 440 if defaults:
439 441 args = map(util.expandpath, shlex.split(defaults)) + args
440 442 c = list(entry[1])
441 443 else:
442 444 cmd = None
443 445 c = []
444 446
445 447 # combine global options into local
446 448 for o in commands.globalopts:
447 449 c.append((o[0], o[1], options[o[1]], o[3]))
448 450
449 451 try:
450 452 args = fancyopts.fancyopts(args, c, cmdoptions, True)
451 453 except fancyopts.getopt.GetoptError, inst:
452 454 raise error.CommandError(cmd, inst)
453 455
454 456 # separate global options back out
455 457 for o in commands.globalopts:
456 458 n = o[1]
457 459 options[n] = cmdoptions[n]
458 460 del cmdoptions[n]
459 461
460 462 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
461 463
462 464 def _parseconfig(ui, config):
463 465 """parse the --config options from the command line"""
464 466 configs = []
465 467
466 468 for cfg in config:
467 469 try:
468 470 name, value = cfg.split('=', 1)
469 471 section, name = name.split('.', 1)
470 472 if not section or not name:
471 473 raise IndexError
472 474 ui.setconfig(section, name, value)
473 475 configs.append((section, name, value))
474 476 except (IndexError, ValueError):
475 477 raise util.Abort(_('malformed --config option: %r '
476 478 '(use --config section.name=value)') % cfg)
477 479
478 480 return configs
479 481
480 482 def _earlygetopt(aliases, args):
481 483 """Return list of values for an option (or aliases).
482 484
483 485 The values are listed in the order they appear in args.
484 486 The options and values are removed from args.
485 487 """
486 488 try:
487 489 argcount = args.index("--")
488 490 except ValueError:
489 491 argcount = len(args)
490 492 shortopts = [opt for opt in aliases if len(opt) == 2]
491 493 values = []
492 494 pos = 0
493 495 while pos < argcount:
494 496 if args[pos] in aliases:
495 497 if pos + 1 >= argcount:
496 498 # ignore and let getopt report an error if there is no value
497 499 break
498 500 del args[pos]
499 501 values.append(args.pop(pos))
500 502 argcount -= 2
501 503 elif args[pos][:2] in shortopts:
502 504 # short option can have no following space, e.g. hg log -Rfoo
503 505 values.append(args.pop(pos)[2:])
504 506 argcount -= 1
505 507 else:
506 508 pos += 1
507 509 return values
508 510
509 511 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
510 512 # run pre-hook, and abort if it fails
511 513 ret = hook.hook(lui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs),
512 514 pats=cmdpats, opts=cmdoptions)
513 515 if ret:
514 516 return ret
515 517 ret = _runcommand(ui, options, cmd, d)
516 518 # run post-hook, passing command result
517 519 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
518 520 result=ret, pats=cmdpats, opts=cmdoptions)
519 521 return ret
520 522
521 523 def _getlocal(ui, rpath):
522 524 """Return (path, local ui object) for the given target path.
523 525
524 526 Takes paths in [cwd]/.hg/hgrc into account."
525 527 """
526 528 try:
527 529 wd = os.getcwd()
528 530 except OSError, e:
529 531 raise util.Abort(_("error getting current working directory: %s") %
530 532 e.strerror)
531 533 path = cmdutil.findrepo(wd) or ""
532 534 if not path:
533 535 lui = ui
534 536 else:
535 537 lui = ui.copy()
536 538 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
537 539
538 540 if rpath and rpath[-1]:
539 541 path = lui.expandpath(rpath[-1])
540 542 lui = ui.copy()
541 543 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
542 544
543 545 return path, lui
544 546
545 547 def _checkshellalias(lui, ui, args):
546 548 options = {}
547 549
548 550 try:
549 551 args = fancyopts.fancyopts(args, commands.globalopts, options)
550 552 except fancyopts.getopt.GetoptError:
551 553 return
552 554
553 555 if not args:
554 556 return
555 557
556 558 norepo = commands.norepo
557 559 optionalrepo = commands.optionalrepo
558 560 def restorecommands():
559 561 commands.norepo = norepo
560 562 commands.optionalrepo = optionalrepo
561 563
562 564 cmdtable = commands.table.copy()
563 565 addaliases(lui, cmdtable)
564 566
565 567 cmd = args[0]
566 568 try:
567 569 aliases, entry = cmdutil.findcmd(cmd, cmdtable,
568 570 lui.configbool("ui", "strict"))
569 571 except (error.AmbiguousCommand, error.UnknownCommand):
570 572 restorecommands()
571 573 return
572 574
573 575 cmd = aliases[0]
574 576 fn = entry[0]
575 577
576 578 if cmd and util.safehasattr(fn, 'shell'):
577 579 d = lambda: fn(ui, *args[1:])
578 580 return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d,
579 581 [], {})
580 582
581 583 restorecommands()
582 584
583 585 _loaded = set()
584 586 def _dispatch(req):
585 587 args = req.args
586 588 ui = req.ui
587 589
588 590 # read --config before doing anything else
589 591 # (e.g. to change trust settings for reading .hg/hgrc)
590 592 cfgs = _parseconfig(ui, _earlygetopt(['--config'], args))
591 593
592 594 # check for cwd
593 595 cwd = _earlygetopt(['--cwd'], args)
594 596 if cwd:
595 597 os.chdir(cwd[-1])
596 598
597 599 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
598 600 path, lui = _getlocal(ui, rpath)
599 601
600 602 # Now that we're operating in the right directory/repository with
601 603 # the right config settings, check for shell aliases
602 604 shellaliasfn = _checkshellalias(lui, ui, args)
603 605 if shellaliasfn:
604 606 return shellaliasfn()
605 607
606 608 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
607 609 # reposetup. Programs like TortoiseHg will call _dispatch several
608 610 # times so we keep track of configured extensions in _loaded.
609 611 extensions.loadall(lui)
610 612 exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
611 613 # Propagate any changes to lui.__class__ by extensions
612 614 ui.__class__ = lui.__class__
613 615
614 616 # (uisetup and extsetup are handled in extensions.loadall)
615 617
616 618 for name, module in exts:
617 619 cmdtable = getattr(module, 'cmdtable', {})
618 620 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
619 621 if overrides:
620 622 ui.warn(_("extension '%s' overrides commands: %s\n")
621 623 % (name, " ".join(overrides)))
622 624 commands.table.update(cmdtable)
623 625 _loaded.add(name)
624 626
625 627 # (reposetup is handled in hg.repository)
626 628
627 629 addaliases(lui, commands.table)
628 630
629 631 # check for fallback encoding
630 632 fallback = lui.config('ui', 'fallbackencoding')
631 633 if fallback:
632 634 encoding.fallbackencoding = fallback
633 635
634 636 fullargs = args
635 637 cmd, func, args, options, cmdoptions = _parse(lui, args)
636 638
637 639 if options["config"]:
638 640 raise util.Abort(_("option --config may not be abbreviated!"))
639 641 if options["cwd"]:
640 642 raise util.Abort(_("option --cwd may not be abbreviated!"))
641 643 if options["repository"]:
642 644 raise util.Abort(_(
643 645 "option -R has to be separated from other options (e.g. not -qR) "
644 646 "and --repository may only be abbreviated as --repo!"))
645 647
646 648 if options["encoding"]:
647 649 encoding.encoding = options["encoding"]
648 650 if options["encodingmode"]:
649 651 encoding.encodingmode = options["encodingmode"]
650 652 if options["time"]:
651 653 def get_times():
652 654 t = os.times()
653 655 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
654 656 t = (t[0], t[1], t[2], t[3], time.clock())
655 657 return t
656 658 s = get_times()
657 659 def print_time():
658 660 t = get_times()
659 661 ui.warn(_("time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
660 662 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
661 663 atexit.register(print_time)
662 664
663 665 uis = set([ui, lui])
664 666
665 667 if req.repo:
666 668 uis.add(req.repo.ui)
667 669
668 670 # copy configs that were passed on the cmdline (--config) to the repo ui
669 671 for cfg in cfgs:
670 672 req.repo.ui.setconfig(*cfg)
671 673
672 674 if options['verbose'] or options['debug'] or options['quiet']:
673 675 for opt in ('verbose', 'debug', 'quiet'):
674 676 val = str(bool(options[opt]))
675 677 for ui_ in uis:
676 678 ui_.setconfig('ui', opt, val)
677 679
678 680 if options['traceback']:
679 681 for ui_ in uis:
680 682 ui_.setconfig('ui', 'traceback', 'on')
681 683
682 684 if options['noninteractive']:
683 685 for ui_ in uis:
684 686 ui_.setconfig('ui', 'interactive', 'off')
685 687
686 688 if cmdoptions.get('insecure', False):
687 689 for ui_ in uis:
688 690 ui_.setconfig('web', 'cacerts', '')
689 691
690 692 if options['version']:
691 693 return commands.version_(ui)
692 694 if options['help']:
693 695 return commands.help_(ui, cmd)
694 696 elif not cmd:
695 697 return commands.help_(ui, 'shortlist')
696 698
697 699 repo = None
698 700 cmdpats = args[:]
699 701 if cmd not in commands.norepo.split():
700 702 # use the repo from the request only if we don't have -R
701 703 if not rpath and not cwd:
702 704 repo = req.repo
703 705
704 706 if repo:
705 707 # set the descriptors of the repo ui to those of ui
706 708 repo.ui.fin = ui.fin
707 709 repo.ui.fout = ui.fout
708 710 repo.ui.ferr = ui.ferr
709 711 else:
710 712 try:
711 713 repo = hg.repository(ui, path=path)
712 714 if not repo.local():
713 715 raise util.Abort(_("repository '%s' is not local") % path)
714 716 if options['hidden']:
715 717 repo = repo.unfiltered()
716 718 repo.ui.setconfig("bundle", "mainreporoot", repo.root)
717 719 except error.RequirementError:
718 720 raise
719 721 except error.RepoError:
720 722 if cmd not in commands.optionalrepo.split():
721 723 if (cmd in commands.inferrepo.split() and
722 724 args and not path): # try to infer -R from command args
723 725 repos = map(cmdutil.findrepo, args)
724 726 guess = repos[0]
725 727 if guess and repos.count(guess) == len(repos):
726 728 req.args = ['--repository', guess] + fullargs
727 729 return _dispatch(req)
728 730 if not path:
729 731 raise error.RepoError(_("no repository found in '%s'"
730 732 " (.hg not found)")
731 733 % os.getcwd())
732 734 raise
733 735 if repo:
734 736 ui = repo.ui
735 737 args.insert(0, repo)
736 738 elif rpath:
737 739 ui.warn(_("warning: --repository ignored\n"))
738 740
739 741 msg = ' '.join(' ' in a and repr(a) or a for a in fullargs)
740 742 ui.log("command", '%s\n', msg)
741 743 d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
742 744 starttime = time.time()
743 745 ret = None
744 746 try:
745 747 ret = runcommand(lui, repo, cmd, fullargs, ui, options, d,
746 748 cmdpats, cmdoptions)
747 749 return ret
748 750 finally:
749 751 duration = time.time() - starttime
750 752 ui.log("commandfinish", "%s exited %s after %0.2f seconds\n",
751 753 cmd, ret, duration)
752 754 if repo and repo != req.repo:
753 755 repo.close()
754 756
755 757 def lsprofile(ui, func, fp):
756 758 format = ui.config('profiling', 'format', default='text')
757 759 field = ui.config('profiling', 'sort', default='inlinetime')
758 760 limit = ui.configint('profiling', 'limit', default=30)
759 761 climit = ui.configint('profiling', 'nested', default=5)
760 762
761 763 if format not in ['text', 'kcachegrind']:
762 764 ui.warn(_("unrecognized profiling format '%s'"
763 765 " - Ignored\n") % format)
764 766 format = 'text'
765 767
766 768 try:
767 769 from mercurial import lsprof
768 770 except ImportError:
769 771 raise util.Abort(_(
770 772 'lsprof not available - install from '
771 773 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
772 774 p = lsprof.Profiler()
773 775 p.enable(subcalls=True)
774 776 try:
775 777 return func()
776 778 finally:
777 779 p.disable()
778 780
779 781 if format == 'kcachegrind':
780 782 import lsprofcalltree
781 783 calltree = lsprofcalltree.KCacheGrind(p)
782 784 calltree.output(fp)
783 785 else:
784 786 # format == 'text'
785 787 stats = lsprof.Stats(p.getstats())
786 788 stats.sort(field)
787 789 stats.pprint(limit=limit, file=fp, climit=climit)
788 790
789 791 def statprofile(ui, func, fp):
790 792 try:
791 793 import statprof
792 794 except ImportError:
793 795 raise util.Abort(_(
794 796 'statprof not available - install using "easy_install statprof"'))
795 797
796 798 freq = ui.configint('profiling', 'freq', default=1000)
797 799 if freq > 0:
798 800 statprof.reset(freq)
799 801 else:
800 802 ui.warn(_("invalid sampling frequency '%s' - ignoring\n") % freq)
801 803
802 804 statprof.start()
803 805 try:
804 806 return func()
805 807 finally:
806 808 statprof.stop()
807 809 statprof.display(fp)
808 810
809 811 def _runcommand(ui, options, cmd, cmdfunc):
810 812 def checkargs():
811 813 try:
812 814 return cmdfunc()
813 815 except error.SignatureError:
814 816 raise error.CommandError(cmd, _("invalid arguments"))
815 817
816 818 if options['profile']:
817 819 profiler = os.getenv('HGPROF')
818 820 if profiler is None:
819 821 profiler = ui.config('profiling', 'type', default='ls')
820 822 if profiler not in ('ls', 'stat'):
821 823 ui.warn(_("unrecognized profiler '%s' - ignored\n") % profiler)
822 824 profiler = 'ls'
823 825
824 826 output = ui.config('profiling', 'output')
825 827
826 828 if output:
827 829 path = ui.expandpath(output)
828 830 fp = open(path, 'wb')
829 831 else:
830 832 fp = sys.stderr
831 833
832 834 try:
833 835 if profiler == 'ls':
834 836 return lsprofile(ui, checkargs, fp)
835 837 else:
836 838 return statprofile(ui, checkargs, fp)
837 839 finally:
838 840 if output:
839 841 fp.close()
840 842 else:
841 843 return checkargs()
General Comments 0
You need to be logged in to leave comments. Login now