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