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