##// END OF EJS Templates
a socket error might be a tuple or a singleton
Benoit Boissinot -
r6993:b9d012ce default
parent child Browse files
Show More
@@ -1,417 +1,417
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 ui.warn(_("abort: %s\n") % inst[1])
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 149 raise
150 150
151 151 return -1
152 152
153 153 def _findrepo(p):
154 154 while not os.path.isdir(os.path.join(p, ".hg")):
155 155 oldp, p = p, os.path.dirname(p)
156 156 if p == oldp:
157 157 return None
158 158
159 159 return p
160 160
161 161 def _parse(ui, args):
162 162 options = {}
163 163 cmdoptions = {}
164 164
165 165 try:
166 166 args = fancyopts.fancyopts(args, commands.globalopts, options)
167 167 except fancyopts.getopt.GetoptError, inst:
168 168 raise ParseError(None, inst)
169 169
170 170 if args:
171 171 cmd, args = args[0], args[1:]
172 172 aliases, i = cmdutil.findcmd(ui, cmd, commands.table)
173 173 cmd = aliases[0]
174 174 defaults = ui.config("defaults", cmd)
175 175 if defaults:
176 176 args = shlex.split(defaults) + args
177 177 c = list(i[1])
178 178 else:
179 179 cmd = None
180 180 c = []
181 181
182 182 # combine global options into local
183 183 for o in commands.globalopts:
184 184 c.append((o[0], o[1], options[o[1]], o[3]))
185 185
186 186 try:
187 187 args = fancyopts.fancyopts(args, c, cmdoptions)
188 188 except fancyopts.getopt.GetoptError, inst:
189 189 raise ParseError(cmd, inst)
190 190
191 191 # separate global options back out
192 192 for o in commands.globalopts:
193 193 n = o[1]
194 194 options[n] = cmdoptions[n]
195 195 del cmdoptions[n]
196 196
197 197 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
198 198
199 199 def _parseconfig(config):
200 200 """parse the --config options from the command line"""
201 201 parsed = []
202 202 for cfg in config:
203 203 try:
204 204 name, value = cfg.split('=', 1)
205 205 section, name = name.split('.', 1)
206 206 if not section or not name:
207 207 raise IndexError
208 208 parsed.append((section, name, value))
209 209 except (IndexError, ValueError):
210 210 raise util.Abort(_('malformed --config option: %s') % cfg)
211 211 return parsed
212 212
213 213 def _earlygetopt(aliases, args):
214 214 """Return list of values for an option (or aliases).
215 215
216 216 The values are listed in the order they appear in args.
217 217 The options and values are removed from args.
218 218 """
219 219 try:
220 220 argcount = args.index("--")
221 221 except ValueError:
222 222 argcount = len(args)
223 223 shortopts = [opt for opt in aliases if len(opt) == 2]
224 224 values = []
225 225 pos = 0
226 226 while pos < argcount:
227 227 if args[pos] in aliases:
228 228 if pos + 1 >= argcount:
229 229 # ignore and let getopt report an error if there is no value
230 230 break
231 231 del args[pos]
232 232 values.append(args.pop(pos))
233 233 argcount -= 2
234 234 elif args[pos][:2] in shortopts:
235 235 # short option can have no following space, e.g. hg log -Rfoo
236 236 values.append(args.pop(pos)[2:])
237 237 argcount -= 1
238 238 else:
239 239 pos += 1
240 240 return values
241 241
242 242 _loaded = {}
243 243 def _dispatch(ui, args):
244 244 # read --config before doing anything else
245 245 # (e.g. to change trust settings for reading .hg/hgrc)
246 246 config = _earlygetopt(['--config'], args)
247 247 if config:
248 248 ui.updateopts(config=_parseconfig(config))
249 249
250 250 # check for cwd
251 251 cwd = _earlygetopt(['--cwd'], args)
252 252 if cwd:
253 253 os.chdir(cwd[-1])
254 254
255 255 # read the local repository .hgrc into a local ui object
256 256 path = _findrepo(os.getcwd()) or ""
257 257 if not path:
258 258 lui = ui
259 259 if path:
260 260 try:
261 261 lui = _ui.ui(parentui=ui)
262 262 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
263 263 except IOError:
264 264 pass
265 265
266 266 # now we can expand paths, even ones in .hg/hgrc
267 267 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
268 268 if rpath:
269 269 path = lui.expandpath(rpath[-1])
270 270 lui = _ui.ui(parentui=ui)
271 271 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
272 272
273 273 extensions.loadall(lui)
274 274 for name, module in extensions.extensions():
275 275 if name in _loaded:
276 276 continue
277 277
278 278 # setup extensions
279 279 # TODO this should be generalized to scheme, where extensions can
280 280 # redepend on other extensions. then we should toposort them, and
281 281 # do initialization in correct order
282 282 extsetup = getattr(module, 'extsetup', None)
283 283 if extsetup:
284 284 extsetup()
285 285
286 286 cmdtable = getattr(module, 'cmdtable', {})
287 287 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
288 288 if overrides:
289 289 ui.warn(_("extension '%s' overrides commands: %s\n")
290 290 % (name, " ".join(overrides)))
291 291 commands.table.update(cmdtable)
292 292 _loaded[name] = 1
293 293 # check for fallback encoding
294 294 fallback = lui.config('ui', 'fallbackencoding')
295 295 if fallback:
296 296 util._fallbackencoding = fallback
297 297
298 298 fullargs = args
299 299 cmd, func, args, options, cmdoptions = _parse(lui, args)
300 300
301 301 if options["config"]:
302 302 raise util.Abort(_("Option --config may not be abbreviated!"))
303 303 if options["cwd"]:
304 304 raise util.Abort(_("Option --cwd may not be abbreviated!"))
305 305 if options["repository"]:
306 306 raise util.Abort(_(
307 307 "Option -R has to be separated from other options (i.e. not -qR) "
308 308 "and --repository may only be abbreviated as --repo!"))
309 309
310 310 if options["encoding"]:
311 311 util._encoding = options["encoding"]
312 312 if options["encodingmode"]:
313 313 util._encodingmode = options["encodingmode"]
314 314 if options["time"]:
315 315 def get_times():
316 316 t = os.times()
317 317 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
318 318 t = (t[0], t[1], t[2], t[3], time.clock())
319 319 return t
320 320 s = get_times()
321 321 def print_time():
322 322 t = get_times()
323 323 ui.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
324 324 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
325 325 atexit.register(print_time)
326 326
327 327 ui.updateopts(options["verbose"], options["debug"], options["quiet"],
328 328 not options["noninteractive"], options["traceback"])
329 329
330 330 if options['help']:
331 331 return commands.help_(ui, cmd, options['version'])
332 332 elif options['version']:
333 333 return commands.version_(ui)
334 334 elif not cmd:
335 335 return commands.help_(ui, 'shortlist')
336 336
337 337 repo = None
338 338 if cmd not in commands.norepo.split():
339 339 try:
340 340 repo = hg.repository(ui, path=path)
341 341 ui = repo.ui
342 342 if not repo.local():
343 343 raise util.Abort(_("repository '%s' is not local") % path)
344 344 ui.setconfig("bundle", "mainreporoot", repo.root)
345 345 except RepoError:
346 346 if cmd not in commands.optionalrepo.split():
347 347 if args and not path: # try to infer -R from command args
348 348 repos = map(_findrepo, args)
349 349 guess = repos[0]
350 350 if guess and repos.count(guess) == len(repos):
351 351 return _dispatch(ui, ['--repository', guess] + fullargs)
352 352 if not path:
353 353 raise RepoError(_("There is no Mercurial repository here"
354 354 " (.hg not found)"))
355 355 raise
356 356 d = lambda: func(ui, repo, *args, **cmdoptions)
357 357 else:
358 358 d = lambda: func(ui, *args, **cmdoptions)
359 359
360 360 # run pre-hook, and abort if it fails
361 361 ret = hook.hook(lui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs))
362 362 if ret:
363 363 return ret
364 364 ret = _runcommand(ui, options, cmd, d)
365 365 # run post-hook, passing command result
366 366 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
367 367 result = ret)
368 368 return ret
369 369
370 370 def _runcommand(ui, options, cmd, cmdfunc):
371 371 def checkargs():
372 372 try:
373 373 return cmdfunc()
374 374 except TypeError, inst:
375 375 # was this an argument error?
376 376 tb = traceback.extract_tb(sys.exc_info()[2])
377 377 if len(tb) != 2: # no
378 378 raise
379 379 raise ParseError(cmd, _("invalid arguments"))
380 380
381 381 if options['profile']:
382 382 import hotshot, hotshot.stats
383 383 prof = hotshot.Profile("hg.prof")
384 384 try:
385 385 try:
386 386 return prof.runcall(checkargs)
387 387 except:
388 388 try:
389 389 ui.warn(_('exception raised - generating '
390 390 'profile anyway\n'))
391 391 except:
392 392 pass
393 393 raise
394 394 finally:
395 395 prof.close()
396 396 stats = hotshot.stats.load("hg.prof")
397 397 stats.strip_dirs()
398 398 stats.sort_stats('time', 'calls')
399 399 stats.print_stats(40)
400 400 elif options['lsprof']:
401 401 try:
402 402 from mercurial import lsprof
403 403 except ImportError:
404 404 raise util.Abort(_(
405 405 'lsprof not available - install from '
406 406 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
407 407 p = lsprof.Profiler()
408 408 p.enable(subcalls=True)
409 409 try:
410 410 return checkargs()
411 411 finally:
412 412 p.disable()
413 413 stats = lsprof.Stats(p.getstats())
414 414 stats.sort()
415 415 stats.pprint(top=10, file=sys.stderr, climit=5)
416 416 else:
417 417 return checkargs()
General Comments 0
You need to be logged in to leave comments. Login now