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