##// END OF EJS Templates
show extensions loaded on traceback
Benoit Boissinot -
r6985:5cf3bf3c default
parent child Browse files
Show More
@@ -1,417 +1,419 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
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 8 from i18n import _
9 9 from repo import RepoError
10 10 import os, sys, atexit, signal, pdb, traceback, socket, errno, shlex, time
11 11 import util, commands, hg, lock, fancyopts, revlog, version, extensions, hook
12 12 import cmdutil
13 13 import ui as _ui
14 14
15 15 class ParseError(Exception):
16 16 """Exception raised on errors in parsing the command line."""
17 17
18 18 def run():
19 19 "run the command in sys.argv"
20 20 sys.exit(dispatch(sys.argv[1:]))
21 21
22 22 def dispatch(args):
23 23 "run the command specified in args"
24 24 try:
25 25 u = _ui.ui(traceback='--traceback' in args)
26 26 except util.Abort, inst:
27 27 sys.stderr.write(_("abort: %s\n") % inst)
28 28 return -1
29 29 return _runcatch(u, args)
30 30
31 31 def _runcatch(ui, args):
32 32 def catchterm(*args):
33 33 raise util.SignalInterrupt
34 34
35 35 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
36 36 num = getattr(signal, name, None)
37 37 if num: signal.signal(num, catchterm)
38 38
39 39 try:
40 40 try:
41 41 # enter the debugger before command execution
42 42 if '--debugger' in args:
43 43 pdb.set_trace()
44 44 try:
45 45 return _dispatch(ui, args)
46 46 finally:
47 47 ui.flush()
48 48 except:
49 49 # enter the debugger when we hit an exception
50 50 if '--debugger' in args:
51 51 pdb.post_mortem(sys.exc_info()[2])
52 52 ui.print_exc()
53 53 raise
54 54
55 55 except ParseError, inst:
56 56 if inst.args[0]:
57 57 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
58 58 commands.help_(ui, inst.args[0])
59 59 else:
60 60 ui.warn(_("hg: %s\n") % inst.args[1])
61 61 commands.help_(ui, 'shortlist')
62 62 except cmdutil.AmbiguousCommand, inst:
63 63 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
64 64 (inst.args[0], " ".join(inst.args[1])))
65 65 except cmdutil.UnknownCommand, inst:
66 66 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
67 67 commands.help_(ui, 'shortlist')
68 68 except RepoError, inst:
69 69 ui.warn(_("abort: %s!\n") % inst)
70 70 except lock.LockHeld, inst:
71 71 if inst.errno == errno.ETIMEDOUT:
72 72 reason = _('timed out waiting for lock held by %s') % inst.locker
73 73 else:
74 74 reason = _('lock held by %s') % inst.locker
75 75 ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
76 76 except lock.LockUnavailable, inst:
77 77 ui.warn(_("abort: could not lock %s: %s\n") %
78 78 (inst.desc or inst.filename, inst.strerror))
79 79 except revlog.RevlogError, inst:
80 80 ui.warn(_("abort: %s!\n") % inst)
81 81 except util.SignalInterrupt:
82 82 ui.warn(_("killed!\n"))
83 83 except KeyboardInterrupt:
84 84 try:
85 85 ui.warn(_("interrupted!\n"))
86 86 except IOError, inst:
87 87 if inst.errno == errno.EPIPE:
88 88 if ui.debugflag:
89 89 ui.warn(_("\nbroken pipe\n"))
90 90 else:
91 91 raise
92 92 except socket.error, inst:
93 93 ui.warn(_("abort: %s\n") % inst[1])
94 94 except IOError, inst:
95 95 if hasattr(inst, "code"):
96 96 ui.warn(_("abort: %s\n") % inst)
97 97 elif hasattr(inst, "reason"):
98 98 try: # usually it is in the form (errno, strerror)
99 99 reason = inst.reason.args[1]
100 100 except: # it might be anything, for example a string
101 101 reason = inst.reason
102 102 ui.warn(_("abort: error: %s\n") % reason)
103 103 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
104 104 if ui.debugflag:
105 105 ui.warn(_("broken pipe\n"))
106 106 elif getattr(inst, "strerror", None):
107 107 if getattr(inst, "filename", None):
108 108 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
109 109 else:
110 110 ui.warn(_("abort: %s\n") % inst.strerror)
111 111 else:
112 112 raise
113 113 except OSError, inst:
114 114 if getattr(inst, "filename", None):
115 115 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
116 116 else:
117 117 ui.warn(_("abort: %s\n") % inst.strerror)
118 118 except util.UnexpectedOutput, inst:
119 119 ui.warn(_("abort: %s") % inst[0])
120 120 if not isinstance(inst[1], basestring):
121 121 ui.warn(" %r\n" % (inst[1],))
122 122 elif not inst[1]:
123 123 ui.warn(_(" empty string\n"))
124 124 else:
125 125 ui.warn("\n%r\n" % util.ellipsis(inst[1]))
126 126 except ImportError, inst:
127 127 m = str(inst).split()[-1]
128 128 ui.warn(_("abort: could not import module %s!\n") % m)
129 129 if m in "mpatch bdiff".split():
130 130 ui.warn(_("(did you forget to compile extensions?)\n"))
131 131 elif m in "zlib".split():
132 132 ui.warn(_("(is your Python install correct?)\n"))
133 133
134 134 except util.Abort, inst:
135 135 ui.warn(_("abort: %s\n") % inst)
136 136 except MemoryError:
137 137 ui.warn(_("abort: out of memory\n"))
138 138 except SystemExit, inst:
139 139 # Commands shouldn't sys.exit directly, but give a return code.
140 140 # Just in case catch this and and pass exit code to caller.
141 141 return inst.code
142 142 except:
143 143 ui.warn(_("** unknown exception encountered, details follow\n"))
144 144 ui.warn(_("** report bug details to "
145 145 "http://www.selenic.com/mercurial/bts\n"))
146 146 ui.warn(_("** or mercurial@selenic.com\n"))
147 147 ui.warn(_("** Mercurial Distributed SCM (version %s)\n")
148 148 % version.get_version())
149 ui.warn(_("** Extensions loaded: %s\n")
150 % ", ".join([x[0] for x in extensions.extensions()]))
149 151 raise
150 152
151 153 return -1
152 154
153 155 def _findrepo(p):
154 156 while not os.path.isdir(os.path.join(p, ".hg")):
155 157 oldp, p = p, os.path.dirname(p)
156 158 if p == oldp:
157 159 return None
158 160
159 161 return p
160 162
161 163 def _parse(ui, args):
162 164 options = {}
163 165 cmdoptions = {}
164 166
165 167 try:
166 168 args = fancyopts.fancyopts(args, commands.globalopts, options)
167 169 except fancyopts.getopt.GetoptError, inst:
168 170 raise ParseError(None, inst)
169 171
170 172 if args:
171 173 cmd, args = args[0], args[1:]
172 174 aliases, i = cmdutil.findcmd(ui, cmd, commands.table)
173 175 cmd = aliases[0]
174 176 defaults = ui.config("defaults", cmd)
175 177 if defaults:
176 178 args = shlex.split(defaults) + args
177 179 c = list(i[1])
178 180 else:
179 181 cmd = None
180 182 c = []
181 183
182 184 # combine global options into local
183 185 for o in commands.globalopts:
184 186 c.append((o[0], o[1], options[o[1]], o[3]))
185 187
186 188 try:
187 189 args = fancyopts.fancyopts(args, c, cmdoptions)
188 190 except fancyopts.getopt.GetoptError, inst:
189 191 raise ParseError(cmd, inst)
190 192
191 193 # separate global options back out
192 194 for o in commands.globalopts:
193 195 n = o[1]
194 196 options[n] = cmdoptions[n]
195 197 del cmdoptions[n]
196 198
197 199 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
198 200
199 201 def _parseconfig(config):
200 202 """parse the --config options from the command line"""
201 203 parsed = []
202 204 for cfg in config:
203 205 try:
204 206 name, value = cfg.split('=', 1)
205 207 section, name = name.split('.', 1)
206 208 if not section or not name:
207 209 raise IndexError
208 210 parsed.append((section, name, value))
209 211 except (IndexError, ValueError):
210 212 raise util.Abort(_('malformed --config option: %s') % cfg)
211 213 return parsed
212 214
213 215 def _earlygetopt(aliases, args):
214 216 """Return list of values for an option (or aliases).
215 217
216 218 The values are listed in the order they appear in args.
217 219 The options and values are removed from args.
218 220 """
219 221 try:
220 222 argcount = args.index("--")
221 223 except ValueError:
222 224 argcount = len(args)
223 225 shortopts = [opt for opt in aliases if len(opt) == 2]
224 226 values = []
225 227 pos = 0
226 228 while pos < argcount:
227 229 if args[pos] in aliases:
228 230 if pos + 1 >= argcount:
229 231 # ignore and let getopt report an error if there is no value
230 232 break
231 233 del args[pos]
232 234 values.append(args.pop(pos))
233 235 argcount -= 2
234 236 elif args[pos][:2] in shortopts:
235 237 # short option can have no following space, e.g. hg log -Rfoo
236 238 values.append(args.pop(pos)[2:])
237 239 argcount -= 1
238 240 else:
239 241 pos += 1
240 242 return values
241 243
242 244 _loaded = {}
243 245 def _dispatch(ui, args):
244 246 # read --config before doing anything else
245 247 # (e.g. to change trust settings for reading .hg/hgrc)
246 248 config = _earlygetopt(['--config'], args)
247 249 if config:
248 250 ui.updateopts(config=_parseconfig(config))
249 251
250 252 # check for cwd
251 253 cwd = _earlygetopt(['--cwd'], args)
252 254 if cwd:
253 255 os.chdir(cwd[-1])
254 256
255 257 # read the local repository .hgrc into a local ui object
256 258 path = _findrepo(os.getcwd()) or ""
257 259 if not path:
258 260 lui = ui
259 261 if path:
260 262 try:
261 263 lui = _ui.ui(parentui=ui)
262 264 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
263 265 except IOError:
264 266 pass
265 267
266 268 # now we can expand paths, even ones in .hg/hgrc
267 269 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
268 270 if rpath:
269 271 path = lui.expandpath(rpath[-1])
270 272 lui = _ui.ui(parentui=ui)
271 273 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
272 274
273 275 extensions.loadall(lui)
274 276 for name, module in extensions.extensions():
275 277 if name in _loaded:
276 278 continue
277 279
278 280 # setup extensions
279 281 # TODO this should be generalized to scheme, where extensions can
280 282 # redepend on other extensions. then we should toposort them, and
281 283 # do initialization in correct order
282 284 extsetup = getattr(module, 'extsetup', None)
283 285 if extsetup:
284 286 extsetup()
285 287
286 288 cmdtable = getattr(module, 'cmdtable', {})
287 289 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
288 290 if overrides:
289 291 ui.warn(_("extension '%s' overrides commands: %s\n")
290 292 % (name, " ".join(overrides)))
291 293 commands.table.update(cmdtable)
292 294 _loaded[name] = 1
293 295 # check for fallback encoding
294 296 fallback = lui.config('ui', 'fallbackencoding')
295 297 if fallback:
296 298 util._fallbackencoding = fallback
297 299
298 300 fullargs = args
299 301 cmd, func, args, options, cmdoptions = _parse(lui, args)
300 302
301 303 if options["config"]:
302 304 raise util.Abort(_("Option --config may not be abbreviated!"))
303 305 if options["cwd"]:
304 306 raise util.Abort(_("Option --cwd may not be abbreviated!"))
305 307 if options["repository"]:
306 308 raise util.Abort(_(
307 309 "Option -R has to be separated from other options (i.e. not -qR) "
308 310 "and --repository may only be abbreviated as --repo!"))
309 311
310 312 if options["encoding"]:
311 313 util._encoding = options["encoding"]
312 314 if options["encodingmode"]:
313 315 util._encodingmode = options["encodingmode"]
314 316 if options["time"]:
315 317 def get_times():
316 318 t = os.times()
317 319 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
318 320 t = (t[0], t[1], t[2], t[3], time.clock())
319 321 return t
320 322 s = get_times()
321 323 def print_time():
322 324 t = get_times()
323 325 ui.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
324 326 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
325 327 atexit.register(print_time)
326 328
327 329 ui.updateopts(options["verbose"], options["debug"], options["quiet"],
328 330 not options["noninteractive"], options["traceback"])
329 331
330 332 if options['help']:
331 333 return commands.help_(ui, cmd, options['version'])
332 334 elif options['version']:
333 335 return commands.version_(ui)
334 336 elif not cmd:
335 337 return commands.help_(ui, 'shortlist')
336 338
337 339 repo = None
338 340 if cmd not in commands.norepo.split():
339 341 try:
340 342 repo = hg.repository(ui, path=path)
341 343 ui = repo.ui
342 344 if not repo.local():
343 345 raise util.Abort(_("repository '%s' is not local") % path)
344 346 ui.setconfig("bundle", "mainreporoot", repo.root)
345 347 except RepoError:
346 348 if cmd not in commands.optionalrepo.split():
347 349 if args and not path: # try to infer -R from command args
348 350 repos = map(_findrepo, args)
349 351 guess = repos[0]
350 352 if guess and repos.count(guess) == len(repos):
351 353 return _dispatch(ui, ['--repository', guess] + fullargs)
352 354 if not path:
353 355 raise RepoError(_("There is no Mercurial repository here"
354 356 " (.hg not found)"))
355 357 raise
356 358 d = lambda: func(ui, repo, *args, **cmdoptions)
357 359 else:
358 360 d = lambda: func(ui, *args, **cmdoptions)
359 361
360 362 # run pre-hook, and abort if it fails
361 363 ret = hook.hook(lui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs))
362 364 if ret:
363 365 return ret
364 366 ret = _runcommand(ui, options, cmd, d)
365 367 # run post-hook, passing command result
366 368 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
367 369 result = ret)
368 370 return ret
369 371
370 372 def _runcommand(ui, options, cmd, cmdfunc):
371 373 def checkargs():
372 374 try:
373 375 return cmdfunc()
374 376 except TypeError, inst:
375 377 # was this an argument error?
376 378 tb = traceback.extract_tb(sys.exc_info()[2])
377 379 if len(tb) != 2: # no
378 380 raise
379 381 raise ParseError(cmd, _("invalid arguments"))
380 382
381 383 if options['profile']:
382 384 import hotshot, hotshot.stats
383 385 prof = hotshot.Profile("hg.prof")
384 386 try:
385 387 try:
386 388 return prof.runcall(checkargs)
387 389 except:
388 390 try:
389 391 ui.warn(_('exception raised - generating '
390 392 'profile anyway\n'))
391 393 except:
392 394 pass
393 395 raise
394 396 finally:
395 397 prof.close()
396 398 stats = hotshot.stats.load("hg.prof")
397 399 stats.strip_dirs()
398 400 stats.sort_stats('time', 'calls')
399 401 stats.print_stats(40)
400 402 elif options['lsprof']:
401 403 try:
402 404 from mercurial import lsprof
403 405 except ImportError:
404 406 raise util.Abort(_(
405 407 'lsprof not available - install from '
406 408 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
407 409 p = lsprof.Profiler()
408 410 p.enable(subcalls=True)
409 411 try:
410 412 return checkargs()
411 413 finally:
412 414 p.disable()
413 415 stats = lsprof.Stats(p.getstats())
414 416 stats.sort()
415 417 stats.pprint(top=10, file=sys.stderr, climit=5)
416 418 else:
417 419 return checkargs()
General Comments 0
You need to be logged in to leave comments. Login now