##// END OF EJS Templates
i18n: unmark untranslatable string
Wagner Bruna -
r12276:0c605364 default
parent child Browse files
Show More
@@ -1,593 +1,593 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 sys.stderr.write(_("(%s)\n") % inst.hint)
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, details follow\n"))
173 173 ui.warn(_("** report bug details to "
174 174 "http://mercurial.selenic.com/bts/\n"))
175 175 ui.warn(_("** or mercurial@selenic.com\n"))
176 176 ui.warn(_("** Python %s\n") % sys.version.replace('\n', ''))
177 177 ui.warn(_("** Mercurial Distributed SCM (version %s)\n")
178 178 % util.version())
179 179 ui.warn(_("** Extensions loaded: %s\n")
180 180 % ", ".join([x[0] for x in extensions.extensions()]))
181 181 raise
182 182
183 183 return -1
184 184
185 185 def aliasargs(fn):
186 186 if hasattr(fn, 'args'):
187 187 return fn.args
188 188 return []
189 189
190 190 class cmdalias(object):
191 191 def __init__(self, name, definition, cmdtable):
192 192 self.name = self.cmd = name
193 193 self.cmdname = ''
194 194 self.definition = definition
195 195 self.args = []
196 196 self.opts = []
197 197 self.help = ''
198 198 self.norepo = True
199 199 self.badalias = False
200 200
201 201 try:
202 202 aliases, entry = cmdutil.findcmd(self.name, cmdtable)
203 203 for alias, e in cmdtable.iteritems():
204 204 if e is entry:
205 205 self.cmd = alias
206 206 break
207 207 self.shadows = True
208 208 except error.UnknownCommand:
209 209 self.shadows = False
210 210
211 211 if not self.definition:
212 212 def fn(ui, *args):
213 213 ui.warn(_("no definition for alias '%s'\n") % self.name)
214 214 return 1
215 215 self.fn = fn
216 216 self.badalias = True
217 217
218 218 return
219 219
220 220 if self.definition.startswith('!'):
221 221 def fn(ui, *args):
222 222 env = {'HG_ARGS': ' '.join((self.name,) + args)}
223 223 def _checkvar(m):
224 224 if int(m.groups()[0]) <= len(args):
225 225 return m.group()
226 226 else:
227 227 return ''
228 228 cmd = re.sub(r'\$(\d+)', _checkvar, self.definition[1:])
229 229 replace = dict((str(i + 1), arg) for i, arg in enumerate(args))
230 230 replace['0'] = self.name
231 231 replace['@'] = ' '.join(args)
232 232 cmd = util.interpolate(r'\$', replace, cmd)
233 233 return util.system(cmd, environ=env)
234 234 self.fn = fn
235 235 return
236 236
237 237 args = shlex.split(self.definition)
238 238 self.cmdname = cmd = args.pop(0)
239 239 args = map(util.expandpath, args)
240 240
241 241 for invalidarg in ("--cwd", "-R", "--repository", "--repo"):
242 242 if _earlygetopt([invalidarg], args):
243 243 def fn(ui, *args):
244 244 ui.warn(_("error in definition for alias '%s': %s may only "
245 245 "be given on the command line\n")
246 246 % (self.name, invalidarg))
247 247 return 1
248 248
249 249 self.fn = fn
250 250 self.badalias = True
251 251 return
252 252
253 253 try:
254 254 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
255 255 if len(tableentry) > 2:
256 256 self.fn, self.opts, self.help = tableentry
257 257 else:
258 258 self.fn, self.opts = tableentry
259 259
260 260 self.args = aliasargs(self.fn) + args
261 261 if cmd not in commands.norepo.split(' '):
262 262 self.norepo = False
263 263 if self.help.startswith("hg " + cmd):
264 264 # drop prefix in old-style help lines so hg shows the alias
265 265 self.help = self.help[4 + len(cmd):]
266 266 self.__doc__ = self.fn.__doc__
267 267
268 268 except error.UnknownCommand:
269 269 def fn(ui, *args):
270 270 ui.warn(_("alias '%s' resolves to unknown command '%s'\n") \
271 271 % (self.name, cmd))
272 272 try:
273 273 # check if the command is in a disabled extension
274 274 commands.help_(ui, cmd, unknowncmd=True)
275 275 except error.UnknownCommand:
276 276 pass
277 277 return 1
278 278 self.fn = fn
279 279 self.badalias = True
280 280 except error.AmbiguousCommand:
281 281 def fn(ui, *args):
282 282 ui.warn(_("alias '%s' resolves to ambiguous command '%s'\n") \
283 283 % (self.name, cmd))
284 284 return 1
285 285 self.fn = fn
286 286 self.badalias = True
287 287
288 288 def __call__(self, ui, *args, **opts):
289 289 if self.shadows:
290 290 ui.debug("alias '%s' shadows command '%s'\n" %
291 291 (self.name, self.cmdname))
292 292
293 293 if self.definition.startswith('!'):
294 294 return self.fn(ui, *args, **opts)
295 295 else:
296 296 try:
297 297 util.checksignature(self.fn)(ui, *args, **opts)
298 298 except error.SignatureError:
299 299 args = ' '.join([self.cmdname] + self.args)
300 300 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args))
301 301 raise
302 302
303 303 def addaliases(ui, cmdtable):
304 304 # aliases are processed after extensions have been loaded, so they
305 305 # may use extension commands. Aliases can also use other alias definitions,
306 306 # but only if they have been defined prior to the current definition.
307 307 for alias, definition in ui.configitems('alias'):
308 308 aliasdef = cmdalias(alias, definition, cmdtable)
309 309 cmdtable[aliasdef.cmd] = (aliasdef, aliasdef.opts, aliasdef.help)
310 310 if aliasdef.norepo:
311 311 commands.norepo += ' %s' % alias
312 312
313 313 def _parse(ui, args):
314 314 options = {}
315 315 cmdoptions = {}
316 316
317 317 try:
318 318 args = fancyopts.fancyopts(args, commands.globalopts, options)
319 319 except fancyopts.getopt.GetoptError, inst:
320 320 raise error.CommandError(None, inst)
321 321
322 322 if args:
323 323 cmd, args = args[0], args[1:]
324 324 aliases, entry = cmdutil.findcmd(cmd, commands.table,
325 325 ui.config("ui", "strict"))
326 326 cmd = aliases[0]
327 327 args = aliasargs(entry[0]) + args
328 328 defaults = ui.config("defaults", cmd)
329 329 if defaults:
330 330 args = map(util.expandpath, shlex.split(defaults)) + args
331 331 c = list(entry[1])
332 332 else:
333 333 cmd = None
334 334 c = []
335 335
336 336 # combine global options into local
337 337 for o in commands.globalopts:
338 338 c.append((o[0], o[1], options[o[1]], o[3]))
339 339
340 340 try:
341 341 args = fancyopts.fancyopts(args, c, cmdoptions, True)
342 342 except fancyopts.getopt.GetoptError, inst:
343 343 raise error.CommandError(cmd, inst)
344 344
345 345 # separate global options back out
346 346 for o in commands.globalopts:
347 347 n = o[1]
348 348 options[n] = cmdoptions[n]
349 349 del cmdoptions[n]
350 350
351 351 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
352 352
353 353 def _parseconfig(ui, config):
354 354 """parse the --config options from the command line"""
355 355 for cfg in config:
356 356 try:
357 357 name, value = cfg.split('=', 1)
358 358 section, name = name.split('.', 1)
359 359 if not section or not name:
360 360 raise IndexError
361 361 ui.setconfig(section, name, value)
362 362 except (IndexError, ValueError):
363 363 raise util.Abort(_('malformed --config option: %r '
364 364 '(use --config section.name=value)') % cfg)
365 365
366 366 def _earlygetopt(aliases, args):
367 367 """Return list of values for an option (or aliases).
368 368
369 369 The values are listed in the order they appear in args.
370 370 The options and values are removed from args.
371 371 """
372 372 try:
373 373 argcount = args.index("--")
374 374 except ValueError:
375 375 argcount = len(args)
376 376 shortopts = [opt for opt in aliases if len(opt) == 2]
377 377 values = []
378 378 pos = 0
379 379 while pos < argcount:
380 380 if args[pos] in aliases:
381 381 if pos + 1 >= argcount:
382 382 # ignore and let getopt report an error if there is no value
383 383 break
384 384 del args[pos]
385 385 values.append(args.pop(pos))
386 386 argcount -= 2
387 387 elif args[pos][:2] in shortopts:
388 388 # short option can have no following space, e.g. hg log -Rfoo
389 389 values.append(args.pop(pos)[2:])
390 390 argcount -= 1
391 391 else:
392 392 pos += 1
393 393 return values
394 394
395 395 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
396 396 # run pre-hook, and abort if it fails
397 397 ret = hook.hook(lui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs),
398 398 pats=cmdpats, opts=cmdoptions)
399 399 if ret:
400 400 return ret
401 401 ret = _runcommand(ui, options, cmd, d)
402 402 # run post-hook, passing command result
403 403 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
404 404 result=ret, pats=cmdpats, opts=cmdoptions)
405 405 return ret
406 406
407 407 _loaded = set()
408 408 def _dispatch(ui, args):
409 409 # read --config before doing anything else
410 410 # (e.g. to change trust settings for reading .hg/hgrc)
411 411 _parseconfig(ui, _earlygetopt(['--config'], args))
412 412
413 413 # check for cwd
414 414 cwd = _earlygetopt(['--cwd'], args)
415 415 if cwd:
416 416 os.chdir(cwd[-1])
417 417
418 418 # read the local repository .hgrc into a local ui object
419 419 try:
420 420 wd = os.getcwd()
421 421 except OSError, e:
422 422 raise util.Abort(_("error getting current working directory: %s") %
423 423 e.strerror)
424 424 path = cmdutil.findrepo(wd) or ""
425 425 if not path:
426 426 lui = ui
427 427 else:
428 428 try:
429 429 lui = ui.copy()
430 430 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
431 431 except IOError:
432 432 pass
433 433
434 434 # now we can expand paths, even ones in .hg/hgrc
435 435 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
436 436 if rpath:
437 437 path = lui.expandpath(rpath[-1])
438 438 lui = ui.copy()
439 439 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
440 440
441 441 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
442 442 # reposetup. Programs like TortoiseHg will call _dispatch several
443 443 # times so we keep track of configured extensions in _loaded.
444 444 extensions.loadall(lui)
445 445 exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
446 446 # Propagate any changes to lui.__class__ by extensions
447 447 ui.__class__ = lui.__class__
448 448
449 449 # (uisetup and extsetup are handled in extensions.loadall)
450 450
451 451 for name, module in exts:
452 452 cmdtable = getattr(module, 'cmdtable', {})
453 453 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
454 454 if overrides:
455 455 ui.warn(_("extension '%s' overrides commands: %s\n")
456 456 % (name, " ".join(overrides)))
457 457 commands.table.update(cmdtable)
458 458 _loaded.add(name)
459 459
460 460 # (reposetup is handled in hg.repository)
461 461
462 462 addaliases(lui, commands.table)
463 463
464 464 # check for fallback encoding
465 465 fallback = lui.config('ui', 'fallbackencoding')
466 466 if fallback:
467 467 encoding.fallbackencoding = fallback
468 468
469 469 fullargs = args
470 470 cmd, func, args, options, cmdoptions = _parse(lui, args)
471 471
472 472 if options["config"]:
473 473 raise util.Abort(_("option --config may not be abbreviated!"))
474 474 if options["cwd"]:
475 475 raise util.Abort(_("option --cwd may not be abbreviated!"))
476 476 if options["repository"]:
477 477 raise util.Abort(_(
478 478 "Option -R has to be separated from other options (e.g. not -qR) "
479 479 "and --repository may only be abbreviated as --repo!"))
480 480
481 481 if options["encoding"]:
482 482 encoding.encoding = options["encoding"]
483 483 if options["encodingmode"]:
484 484 encoding.encodingmode = options["encodingmode"]
485 485 if options["time"]:
486 486 def get_times():
487 487 t = os.times()
488 488 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
489 489 t = (t[0], t[1], t[2], t[3], time.clock())
490 490 return t
491 491 s = get_times()
492 492 def print_time():
493 493 t = get_times()
494 494 ui.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
495 495 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
496 496 atexit.register(print_time)
497 497
498 498 if options['verbose'] or options['debug'] or options['quiet']:
499 499 ui.setconfig('ui', 'verbose', str(bool(options['verbose'])))
500 500 ui.setconfig('ui', 'debug', str(bool(options['debug'])))
501 501 ui.setconfig('ui', 'quiet', str(bool(options['quiet'])))
502 502 if options['traceback']:
503 503 ui.setconfig('ui', 'traceback', 'on')
504 504 if options['noninteractive']:
505 505 ui.setconfig('ui', 'interactive', 'off')
506 506
507 507 if options['help']:
508 508 return commands.help_(ui, cmd, options['version'])
509 509 elif options['version']:
510 510 return commands.version_(ui)
511 511 elif not cmd:
512 512 return commands.help_(ui, 'shortlist')
513 513
514 514 repo = None
515 515 cmdpats = args[:]
516 516 if cmd not in commands.norepo.split():
517 517 try:
518 518 repo = hg.repository(ui, path=path)
519 519 ui = repo.ui
520 520 if not repo.local():
521 521 raise util.Abort(_("repository '%s' is not local") % path)
522 522 ui.setconfig("bundle", "mainreporoot", repo.root)
523 523 except error.RepoError:
524 524 if cmd not in commands.optionalrepo.split():
525 525 if args and not path: # try to infer -R from command args
526 526 repos = map(cmdutil.findrepo, args)
527 527 guess = repos[0]
528 528 if guess and repos.count(guess) == len(repos):
529 529 return _dispatch(ui, ['--repository', guess] + fullargs)
530 530 if not path:
531 531 raise error.RepoError(_("There is no Mercurial repository"
532 532 " here (.hg not found)"))
533 533 raise
534 534 args.insert(0, repo)
535 535 elif rpath:
536 536 ui.warn(_("warning: --repository ignored\n"))
537 537
538 538 msg = ' '.join(' ' in a and repr(a) or a for a in fullargs)
539 539 ui.log("command", msg + "\n")
540 540 d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
541 541 return runcommand(lui, repo, cmd, fullargs, ui, options, d,
542 542 cmdpats, cmdoptions)
543 543
544 544 def _runcommand(ui, options, cmd, cmdfunc):
545 545 def checkargs():
546 546 try:
547 547 return cmdfunc()
548 548 except error.SignatureError:
549 549 raise error.CommandError(cmd, _("invalid arguments"))
550 550
551 551 if options['profile']:
552 552 format = ui.config('profiling', 'format', default='text')
553 553
554 554 if not format in ['text', 'kcachegrind']:
555 555 ui.warn(_("unrecognized profiling format '%s'"
556 556 " - Ignored\n") % format)
557 557 format = 'text'
558 558
559 559 output = ui.config('profiling', 'output')
560 560
561 561 if output:
562 562 path = ui.expandpath(output)
563 563 ostream = open(path, 'wb')
564 564 else:
565 565 ostream = sys.stderr
566 566
567 567 try:
568 568 from mercurial import lsprof
569 569 except ImportError:
570 570 raise util.Abort(_(
571 571 'lsprof not available - install from '
572 572 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
573 573 p = lsprof.Profiler()
574 574 p.enable(subcalls=True)
575 575 try:
576 576 return checkargs()
577 577 finally:
578 578 p.disable()
579 579
580 580 if format == 'kcachegrind':
581 581 import lsprofcalltree
582 582 calltree = lsprofcalltree.KCacheGrind(p)
583 583 calltree.output(ostream)
584 584 else:
585 585 # format == 'text'
586 586 stats = lsprof.Stats(p.getstats())
587 587 stats.sort()
588 588 stats.pprint(top=10, file=ostream, climit=5)
589 589
590 590 if output:
591 591 ostream.close()
592 592 else:
593 593 return checkargs()
General Comments 0
You need to be logged in to leave comments. Login now