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