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