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