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