##// END OF EJS Templates
dispatch: backout 0c605364373c...
Martin Geisler -
r12800:598bf07f stable
parent child Browse files
Show More
@@ -1,642 +1,642 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])
93 commands.help_(ui, inst.args[0])
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: # it might be anything, for example a string
136 except: # it might be anything, for example a string
137 reason = inst.reason
137 reason = inst.reason
138 ui.warn(_("abort: error: %s\n") % reason)
138 ui.warn(_("abort: error: %s\n") % reason)
139 elif hasattr(inst, "args") and inst.args[0] == errno.EPIPE:
139 elif hasattr(inst, "args") and inst.args[0] == errno.EPIPE:
140 if ui.debugflag:
140 if ui.debugflag:
141 ui.warn(_("broken pipe\n"))
141 ui.warn(_("broken pipe\n"))
142 elif getattr(inst, "strerror", None):
142 elif getattr(inst, "strerror", None):
143 if getattr(inst, "filename", None):
143 if getattr(inst, "filename", None):
144 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
144 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
145 else:
145 else:
146 ui.warn(_("abort: %s\n") % inst.strerror)
146 ui.warn(_("abort: %s\n") % inst.strerror)
147 else:
147 else:
148 raise
148 raise
149 except OSError, inst:
149 except OSError, inst:
150 if getattr(inst, "filename", None):
150 if getattr(inst, "filename", None):
151 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
151 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
152 else:
152 else:
153 ui.warn(_("abort: %s\n") % inst.strerror)
153 ui.warn(_("abort: %s\n") % inst.strerror)
154 except KeyboardInterrupt:
154 except KeyboardInterrupt:
155 try:
155 try:
156 ui.warn(_("interrupted!\n"))
156 ui.warn(_("interrupted!\n"))
157 except IOError, inst:
157 except IOError, inst:
158 if inst.errno == errno.EPIPE:
158 if inst.errno == errno.EPIPE:
159 if ui.debugflag:
159 if ui.debugflag:
160 ui.warn(_("\nbroken pipe\n"))
160 ui.warn(_("\nbroken pipe\n"))
161 else:
161 else:
162 raise
162 raise
163 except MemoryError:
163 except MemoryError:
164 ui.warn(_("abort: out of memory\n"))
164 ui.warn(_("abort: out of memory\n"))
165 except SystemExit, inst:
165 except SystemExit, inst:
166 # Commands shouldn't sys.exit directly, but give a return code.
166 # Commands shouldn't sys.exit directly, but give a return code.
167 # Just in case catch this and and pass exit code to caller.
167 # Just in case catch this and and pass exit code to caller.
168 return inst.code
168 return inst.code
169 except socket.error, inst:
169 except socket.error, inst:
170 ui.warn(_("abort: %s\n") % inst.args[-1])
170 ui.warn(_("abort: %s\n") % inst.args[-1])
171 except:
171 except:
172 ui.warn(_("** unknown exception encountered, details follow\n"))
172 ui.warn(_("** unknown exception encountered, details follow\n"))
173 ui.warn(_("** report bug details to "
173 ui.warn(_("** report bug details to "
174 "http://mercurial.selenic.com/bts/\n"))
174 "http://mercurial.selenic.com/bts/\n"))
175 ui.warn(_("** or mercurial@selenic.com\n"))
175 ui.warn(_("** or mercurial@selenic.com\n"))
176 ui.warn(_("** Python %s\n") % sys.version.replace('\n', ''))
176 ui.warn(_("** Python %s\n") % sys.version.replace('\n', ''))
177 ui.warn(_("** Mercurial Distributed SCM (version %s)\n")
177 ui.warn(_("** Mercurial Distributed SCM (version %s)\n")
178 % util.version())
178 % util.version())
179 ui.warn(_("** Extensions loaded: %s\n")
179 ui.warn(_("** Extensions loaded: %s\n")
180 % ", ".join([x[0] for x in extensions.extensions()]))
180 % ", ".join([x[0] for x in extensions.extensions()]))
181 raise
181 raise
182
182
183 return -1
183 return -1
184
184
185 def aliasargs(fn):
185 def aliasargs(fn):
186 if hasattr(fn, 'args'):
186 if hasattr(fn, 'args'):
187 return fn.args
187 return fn.args
188 return []
188 return []
189
189
190 class cmdalias(object):
190 class cmdalias(object):
191 def __init__(self, name, definition, cmdtable):
191 def __init__(self, name, definition, cmdtable):
192 self.name = self.cmd = name
192 self.name = self.cmd = name
193 self.cmdname = ''
193 self.cmdname = ''
194 self.definition = definition
194 self.definition = definition
195 self.args = []
195 self.args = []
196 self.opts = []
196 self.opts = []
197 self.help = ''
197 self.help = ''
198 self.norepo = True
198 self.norepo = True
199 self.badalias = False
199 self.badalias = False
200
200
201 try:
201 try:
202 aliases, entry = cmdutil.findcmd(self.name, cmdtable)
202 aliases, entry = cmdutil.findcmd(self.name, cmdtable)
203 for alias, e in cmdtable.iteritems():
203 for alias, e in cmdtable.iteritems():
204 if e is entry:
204 if e is entry:
205 self.cmd = alias
205 self.cmd = alias
206 break
206 break
207 self.shadows = True
207 self.shadows = True
208 except error.UnknownCommand:
208 except error.UnknownCommand:
209 self.shadows = False
209 self.shadows = False
210
210
211 if not self.definition:
211 if not self.definition:
212 def fn(ui, *args):
212 def fn(ui, *args):
213 ui.warn(_("no definition for alias '%s'\n") % self.name)
213 ui.warn(_("no definition for alias '%s'\n") % self.name)
214 return 1
214 return 1
215 self.fn = fn
215 self.fn = fn
216 self.badalias = True
216 self.badalias = True
217
217
218 return
218 return
219
219
220 if self.definition.startswith('!'):
220 if self.definition.startswith('!'):
221 self.shell = True
221 self.shell = True
222 def fn(ui, *args):
222 def fn(ui, *args):
223 env = {'HG_ARGS': ' '.join((self.name,) + args)}
223 env = {'HG_ARGS': ' '.join((self.name,) + args)}
224 def _checkvar(m):
224 def _checkvar(m):
225 if int(m.groups()[0]) <= len(args):
225 if int(m.groups()[0]) <= len(args):
226 return m.group()
226 return m.group()
227 else:
227 else:
228 return ''
228 return ''
229 cmd = re.sub(r'\$(\d+)', _checkvar, self.definition[1:])
229 cmd = re.sub(r'\$(\d+)', _checkvar, self.definition[1:])
230 replace = dict((str(i + 1), arg) for i, arg in enumerate(args))
230 replace = dict((str(i + 1), arg) for i, arg in enumerate(args))
231 replace['0'] = self.name
231 replace['0'] = self.name
232 replace['@'] = ' '.join(args)
232 replace['@'] = ' '.join(args)
233 cmd = util.interpolate(r'\$', replace, cmd)
233 cmd = util.interpolate(r'\$', replace, cmd)
234 return util.system(cmd, environ=env)
234 return util.system(cmd, environ=env)
235 self.fn = fn
235 self.fn = fn
236 return
236 return
237
237
238 args = shlex.split(self.definition)
238 args = shlex.split(self.definition)
239 self.cmdname = cmd = args.pop(0)
239 self.cmdname = cmd = args.pop(0)
240 args = map(util.expandpath, args)
240 args = map(util.expandpath, args)
241
241
242 for invalidarg in ("--cwd", "-R", "--repository", "--repo"):
242 for invalidarg in ("--cwd", "-R", "--repository", "--repo"):
243 if _earlygetopt([invalidarg], args):
243 if _earlygetopt([invalidarg], args):
244 def fn(ui, *args):
244 def fn(ui, *args):
245 ui.warn(_("error in definition for alias '%s': %s may only "
245 ui.warn(_("error in definition for alias '%s': %s may only "
246 "be given on the command line\n")
246 "be given on the command line\n")
247 % (self.name, invalidarg))
247 % (self.name, invalidarg))
248 return 1
248 return 1
249
249
250 self.fn = fn
250 self.fn = fn
251 self.badalias = True
251 self.badalias = True
252 return
252 return
253
253
254 try:
254 try:
255 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
255 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
256 if len(tableentry) > 2:
256 if len(tableentry) > 2:
257 self.fn, self.opts, self.help = tableentry
257 self.fn, self.opts, self.help = tableentry
258 else:
258 else:
259 self.fn, self.opts = tableentry
259 self.fn, self.opts = tableentry
260
260
261 self.args = aliasargs(self.fn) + args
261 self.args = aliasargs(self.fn) + args
262 if cmd not in commands.norepo.split(' '):
262 if cmd not in commands.norepo.split(' '):
263 self.norepo = False
263 self.norepo = False
264 if self.help.startswith("hg " + cmd):
264 if self.help.startswith("hg " + cmd):
265 # drop prefix in old-style help lines so hg shows the alias
265 # drop prefix in old-style help lines so hg shows the alias
266 self.help = self.help[4 + len(cmd):]
266 self.help = self.help[4 + len(cmd):]
267 self.__doc__ = self.fn.__doc__
267 self.__doc__ = self.fn.__doc__
268
268
269 except error.UnknownCommand:
269 except error.UnknownCommand:
270 def fn(ui, *args):
270 def fn(ui, *args):
271 ui.warn(_("alias '%s' resolves to unknown command '%s'\n") \
271 ui.warn(_("alias '%s' resolves to unknown command '%s'\n") \
272 % (self.name, cmd))
272 % (self.name, cmd))
273 try:
273 try:
274 # check if the command is in a disabled extension
274 # check if the command is in a disabled extension
275 commands.help_(ui, cmd, unknowncmd=True)
275 commands.help_(ui, cmd, unknowncmd=True)
276 except error.UnknownCommand:
276 except error.UnknownCommand:
277 pass
277 pass
278 return 1
278 return 1
279 self.fn = fn
279 self.fn = fn
280 self.badalias = True
280 self.badalias = True
281 except error.AmbiguousCommand:
281 except error.AmbiguousCommand:
282 def fn(ui, *args):
282 def fn(ui, *args):
283 ui.warn(_("alias '%s' resolves to ambiguous command '%s'\n") \
283 ui.warn(_("alias '%s' resolves to ambiguous command '%s'\n") \
284 % (self.name, cmd))
284 % (self.name, cmd))
285 return 1
285 return 1
286 self.fn = fn
286 self.fn = fn
287 self.badalias = True
287 self.badalias = True
288
288
289 def __call__(self, ui, *args, **opts):
289 def __call__(self, ui, *args, **opts):
290 if self.shadows:
290 if self.shadows:
291 ui.debug("alias '%s' shadows command '%s'\n" %
291 ui.debug("alias '%s' shadows command '%s'\n" %
292 (self.name, self.cmdname))
292 (self.name, self.cmdname))
293
293
294 if self.definition.startswith('!'):
294 if self.definition.startswith('!'):
295 return self.fn(ui, *args, **opts)
295 return self.fn(ui, *args, **opts)
296 else:
296 else:
297 try:
297 try:
298 util.checksignature(self.fn)(ui, *args, **opts)
298 util.checksignature(self.fn)(ui, *args, **opts)
299 except error.SignatureError:
299 except error.SignatureError:
300 args = ' '.join([self.cmdname] + self.args)
300 args = ' '.join([self.cmdname] + self.args)
301 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args))
301 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args))
302 raise
302 raise
303
303
304 def addaliases(ui, cmdtable):
304 def addaliases(ui, cmdtable):
305 # aliases are processed after extensions have been loaded, so they
305 # aliases are processed after extensions have been loaded, so they
306 # may use extension commands. Aliases can also use other alias definitions,
306 # may use extension commands. Aliases can also use other alias definitions,
307 # but only if they have been defined prior to the current definition.
307 # but only if they have been defined prior to the current definition.
308 for alias, definition in ui.configitems('alias'):
308 for alias, definition in ui.configitems('alias'):
309 aliasdef = cmdalias(alias, definition, cmdtable)
309 aliasdef = cmdalias(alias, definition, cmdtable)
310 cmdtable[aliasdef.cmd] = (aliasdef, aliasdef.opts, aliasdef.help)
310 cmdtable[aliasdef.cmd] = (aliasdef, aliasdef.opts, aliasdef.help)
311 if aliasdef.norepo:
311 if aliasdef.norepo:
312 commands.norepo += ' %s' % alias
312 commands.norepo += ' %s' % alias
313
313
314 def _parse(ui, args):
314 def _parse(ui, args):
315 options = {}
315 options = {}
316 cmdoptions = {}
316 cmdoptions = {}
317
317
318 try:
318 try:
319 args = fancyopts.fancyopts(args, commands.globalopts, options)
319 args = fancyopts.fancyopts(args, commands.globalopts, options)
320 except fancyopts.getopt.GetoptError, inst:
320 except fancyopts.getopt.GetoptError, inst:
321 raise error.CommandError(None, inst)
321 raise error.CommandError(None, inst)
322
322
323 if args:
323 if args:
324 cmd, args = args[0], args[1:]
324 cmd, args = args[0], args[1:]
325 aliases, entry = cmdutil.findcmd(cmd, commands.table,
325 aliases, entry = cmdutil.findcmd(cmd, commands.table,
326 ui.config("ui", "strict"))
326 ui.config("ui", "strict"))
327 cmd = aliases[0]
327 cmd = aliases[0]
328 args = aliasargs(entry[0]) + args
328 args = aliasargs(entry[0]) + args
329 defaults = ui.config("defaults", cmd)
329 defaults = ui.config("defaults", cmd)
330 if defaults:
330 if defaults:
331 args = map(util.expandpath, shlex.split(defaults)) + args
331 args = map(util.expandpath, shlex.split(defaults)) + args
332 c = list(entry[1])
332 c = list(entry[1])
333 else:
333 else:
334 cmd = None
334 cmd = None
335 c = []
335 c = []
336
336
337 # combine global options into local
337 # combine global options into local
338 for o in commands.globalopts:
338 for o in commands.globalopts:
339 c.append((o[0], o[1], options[o[1]], o[3]))
339 c.append((o[0], o[1], options[o[1]], o[3]))
340
340
341 try:
341 try:
342 args = fancyopts.fancyopts(args, c, cmdoptions, True)
342 args = fancyopts.fancyopts(args, c, cmdoptions, True)
343 except fancyopts.getopt.GetoptError, inst:
343 except fancyopts.getopt.GetoptError, inst:
344 raise error.CommandError(cmd, inst)
344 raise error.CommandError(cmd, inst)
345
345
346 # separate global options back out
346 # separate global options back out
347 for o in commands.globalopts:
347 for o in commands.globalopts:
348 n = o[1]
348 n = o[1]
349 options[n] = cmdoptions[n]
349 options[n] = cmdoptions[n]
350 del cmdoptions[n]
350 del cmdoptions[n]
351
351
352 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
352 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
353
353
354 def _parseconfig(ui, config):
354 def _parseconfig(ui, config):
355 """parse the --config options from the command line"""
355 """parse the --config options from the command line"""
356 for cfg in config:
356 for cfg in config:
357 try:
357 try:
358 name, value = cfg.split('=', 1)
358 name, value = cfg.split('=', 1)
359 section, name = name.split('.', 1)
359 section, name = name.split('.', 1)
360 if not section or not name:
360 if not section or not name:
361 raise IndexError
361 raise IndexError
362 ui.setconfig(section, name, value)
362 ui.setconfig(section, name, value)
363 except (IndexError, ValueError):
363 except (IndexError, ValueError):
364 raise util.Abort(_('malformed --config option: %r '
364 raise util.Abort(_('malformed --config option: %r '
365 '(use --config section.name=value)') % cfg)
365 '(use --config section.name=value)') % cfg)
366
366
367 def _earlygetopt(aliases, args):
367 def _earlygetopt(aliases, args):
368 """Return list of values for an option (or aliases).
368 """Return list of values for an option (or aliases).
369
369
370 The values are listed in the order they appear in args.
370 The values are listed in the order they appear in args.
371 The options and values are removed from args.
371 The options and values are removed from args.
372 """
372 """
373 try:
373 try:
374 argcount = args.index("--")
374 argcount = args.index("--")
375 except ValueError:
375 except ValueError:
376 argcount = len(args)
376 argcount = len(args)
377 shortopts = [opt for opt in aliases if len(opt) == 2]
377 shortopts = [opt for opt in aliases if len(opt) == 2]
378 values = []
378 values = []
379 pos = 0
379 pos = 0
380 while pos < argcount:
380 while pos < argcount:
381 if args[pos] in aliases:
381 if args[pos] in aliases:
382 if pos + 1 >= argcount:
382 if pos + 1 >= argcount:
383 # ignore and let getopt report an error if there is no value
383 # ignore and let getopt report an error if there is no value
384 break
384 break
385 del args[pos]
385 del args[pos]
386 values.append(args.pop(pos))
386 values.append(args.pop(pos))
387 argcount -= 2
387 argcount -= 2
388 elif args[pos][:2] in shortopts:
388 elif args[pos][:2] in shortopts:
389 # short option can have no following space, e.g. hg log -Rfoo
389 # short option can have no following space, e.g. hg log -Rfoo
390 values.append(args.pop(pos)[2:])
390 values.append(args.pop(pos)[2:])
391 argcount -= 1
391 argcount -= 1
392 else:
392 else:
393 pos += 1
393 pos += 1
394 return values
394 return values
395
395
396 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
396 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
397 # run pre-hook, and abort if it fails
397 # run pre-hook, and abort if it fails
398 ret = hook.hook(lui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs),
398 ret = hook.hook(lui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs),
399 pats=cmdpats, opts=cmdoptions)
399 pats=cmdpats, opts=cmdoptions)
400 if ret:
400 if ret:
401 return ret
401 return ret
402 ret = _runcommand(ui, options, cmd, d)
402 ret = _runcommand(ui, options, cmd, d)
403 # run post-hook, passing command result
403 # run post-hook, passing command result
404 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
404 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
405 result=ret, pats=cmdpats, opts=cmdoptions)
405 result=ret, pats=cmdpats, opts=cmdoptions)
406 return ret
406 return ret
407
407
408 def _getlocal(ui, rpath):
408 def _getlocal(ui, rpath):
409 """Return (path, local ui object) for the given target path.
409 """Return (path, local ui object) for the given target path.
410
410
411 Takes paths in [cwd]/.hg/hgrc into account."
411 Takes paths in [cwd]/.hg/hgrc into account."
412 """
412 """
413 try:
413 try:
414 wd = os.getcwd()
414 wd = os.getcwd()
415 except OSError, e:
415 except OSError, e:
416 raise util.Abort(_("error getting current working directory: %s") %
416 raise util.Abort(_("error getting current working directory: %s") %
417 e.strerror)
417 e.strerror)
418 path = cmdutil.findrepo(wd) or ""
418 path = cmdutil.findrepo(wd) or ""
419 if not path:
419 if not path:
420 lui = ui
420 lui = ui
421 else:
421 else:
422 lui = ui.copy()
422 lui = ui.copy()
423 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
423 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
424
424
425 if rpath:
425 if rpath:
426 path = lui.expandpath(rpath[-1])
426 path = lui.expandpath(rpath[-1])
427 lui = ui.copy()
427 lui = ui.copy()
428 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
428 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
429
429
430 return path, lui
430 return path, lui
431
431
432 def _checkshellalias(ui, args):
432 def _checkshellalias(ui, args):
433 cwd = os.getcwd()
433 cwd = os.getcwd()
434 norepo = commands.norepo
434 norepo = commands.norepo
435 options = {}
435 options = {}
436
436
437 try:
437 try:
438 args = fancyopts.fancyopts(args, commands.globalopts, options)
438 args = fancyopts.fancyopts(args, commands.globalopts, options)
439 except fancyopts.getopt.GetoptError:
439 except fancyopts.getopt.GetoptError:
440 return
440 return
441
441
442 if not args:
442 if not args:
443 return
443 return
444
444
445 _parseconfig(ui, options['config'])
445 _parseconfig(ui, options['config'])
446 if options['cwd']:
446 if options['cwd']:
447 os.chdir(options['cwd'])
447 os.chdir(options['cwd'])
448
448
449 path, lui = _getlocal(ui, [options['repository']])
449 path, lui = _getlocal(ui, [options['repository']])
450
450
451 cmdtable = commands.table.copy()
451 cmdtable = commands.table.copy()
452 addaliases(lui, cmdtable)
452 addaliases(lui, cmdtable)
453
453
454 cmd = args[0]
454 cmd = args[0]
455 try:
455 try:
456 aliases, entry = cmdutil.findcmd(cmd, cmdtable, lui.config("ui", "strict"))
456 aliases, entry = cmdutil.findcmd(cmd, cmdtable, lui.config("ui", "strict"))
457 except error.UnknownCommand:
457 except error.UnknownCommand:
458 commands.norepo = norepo
458 commands.norepo = norepo
459 os.chdir(cwd)
459 os.chdir(cwd)
460 return
460 return
461
461
462 cmd = aliases[0]
462 cmd = aliases[0]
463 fn = entry[0]
463 fn = entry[0]
464
464
465 if cmd and hasattr(fn, 'shell'):
465 if cmd and hasattr(fn, 'shell'):
466 d = lambda: fn(ui, *args[1:])
466 d = lambda: fn(ui, *args[1:])
467 return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d, [], {})
467 return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d, [], {})
468
468
469 commands.norepo = norepo
469 commands.norepo = norepo
470 os.chdir(cwd)
470 os.chdir(cwd)
471
471
472 _loaded = set()
472 _loaded = set()
473 def _dispatch(ui, args):
473 def _dispatch(ui, args):
474 shellaliasfn = _checkshellalias(ui, args)
474 shellaliasfn = _checkshellalias(ui, args)
475 if shellaliasfn:
475 if shellaliasfn:
476 return shellaliasfn()
476 return shellaliasfn()
477
477
478 # read --config before doing anything else
478 # read --config before doing anything else
479 # (e.g. to change trust settings for reading .hg/hgrc)
479 # (e.g. to change trust settings for reading .hg/hgrc)
480 _parseconfig(ui, _earlygetopt(['--config'], args))
480 _parseconfig(ui, _earlygetopt(['--config'], args))
481
481
482 # check for cwd
482 # check for cwd
483 cwd = _earlygetopt(['--cwd'], args)
483 cwd = _earlygetopt(['--cwd'], args)
484 if cwd:
484 if cwd:
485 os.chdir(cwd[-1])
485 os.chdir(cwd[-1])
486
486
487 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
487 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
488 path, lui = _getlocal(ui, rpath)
488 path, lui = _getlocal(ui, rpath)
489
489
490 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
490 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
491 # reposetup. Programs like TortoiseHg will call _dispatch several
491 # reposetup. Programs like TortoiseHg will call _dispatch several
492 # times so we keep track of configured extensions in _loaded.
492 # times so we keep track of configured extensions in _loaded.
493 extensions.loadall(lui)
493 extensions.loadall(lui)
494 exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
494 exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
495 # Propagate any changes to lui.__class__ by extensions
495 # Propagate any changes to lui.__class__ by extensions
496 ui.__class__ = lui.__class__
496 ui.__class__ = lui.__class__
497
497
498 # (uisetup and extsetup are handled in extensions.loadall)
498 # (uisetup and extsetup are handled in extensions.loadall)
499
499
500 for name, module in exts:
500 for name, module in exts:
501 cmdtable = getattr(module, 'cmdtable', {})
501 cmdtable = getattr(module, 'cmdtable', {})
502 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
502 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
503 if overrides:
503 if overrides:
504 ui.warn(_("extension '%s' overrides commands: %s\n")
504 ui.warn(_("extension '%s' overrides commands: %s\n")
505 % (name, " ".join(overrides)))
505 % (name, " ".join(overrides)))
506 commands.table.update(cmdtable)
506 commands.table.update(cmdtable)
507 _loaded.add(name)
507 _loaded.add(name)
508
508
509 # (reposetup is handled in hg.repository)
509 # (reposetup is handled in hg.repository)
510
510
511 addaliases(lui, commands.table)
511 addaliases(lui, commands.table)
512
512
513 # check for fallback encoding
513 # check for fallback encoding
514 fallback = lui.config('ui', 'fallbackencoding')
514 fallback = lui.config('ui', 'fallbackencoding')
515 if fallback:
515 if fallback:
516 encoding.fallbackencoding = fallback
516 encoding.fallbackencoding = fallback
517
517
518 fullargs = args
518 fullargs = args
519 cmd, func, args, options, cmdoptions = _parse(lui, args)
519 cmd, func, args, options, cmdoptions = _parse(lui, args)
520
520
521 if options["config"]:
521 if options["config"]:
522 raise util.Abort(_("option --config may not be abbreviated!"))
522 raise util.Abort(_("option --config may not be abbreviated!"))
523 if options["cwd"]:
523 if options["cwd"]:
524 raise util.Abort(_("option --cwd may not be abbreviated!"))
524 raise util.Abort(_("option --cwd may not be abbreviated!"))
525 if options["repository"]:
525 if options["repository"]:
526 raise util.Abort(_(
526 raise util.Abort(_(
527 "Option -R has to be separated from other options (e.g. not -qR) "
527 "Option -R has to be separated from other options (e.g. not -qR) "
528 "and --repository may only be abbreviated as --repo!"))
528 "and --repository may only be abbreviated as --repo!"))
529
529
530 if options["encoding"]:
530 if options["encoding"]:
531 encoding.encoding = options["encoding"]
531 encoding.encoding = options["encoding"]
532 if options["encodingmode"]:
532 if options["encodingmode"]:
533 encoding.encodingmode = options["encodingmode"]
533 encoding.encodingmode = options["encodingmode"]
534 if options["time"]:
534 if options["time"]:
535 def get_times():
535 def get_times():
536 t = os.times()
536 t = os.times()
537 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
537 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
538 t = (t[0], t[1], t[2], t[3], time.clock())
538 t = (t[0], t[1], t[2], t[3], time.clock())
539 return t
539 return t
540 s = get_times()
540 s = get_times()
541 def print_time():
541 def print_time():
542 t = get_times()
542 t = get_times()
543 ui.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
543 ui.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
544 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
544 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
545 atexit.register(print_time)
545 atexit.register(print_time)
546
546
547 if options['verbose'] or options['debug'] or options['quiet']:
547 if options['verbose'] or options['debug'] or options['quiet']:
548 ui.setconfig('ui', 'verbose', str(bool(options['verbose'])))
548 ui.setconfig('ui', 'verbose', str(bool(options['verbose'])))
549 ui.setconfig('ui', 'debug', str(bool(options['debug'])))
549 ui.setconfig('ui', 'debug', str(bool(options['debug'])))
550 ui.setconfig('ui', 'quiet', str(bool(options['quiet'])))
550 ui.setconfig('ui', 'quiet', str(bool(options['quiet'])))
551 if options['traceback']:
551 if options['traceback']:
552 ui.setconfig('ui', 'traceback', 'on')
552 ui.setconfig('ui', 'traceback', 'on')
553 if options['noninteractive']:
553 if options['noninteractive']:
554 ui.setconfig('ui', 'interactive', 'off')
554 ui.setconfig('ui', 'interactive', 'off')
555
555
556 if options['help']:
556 if options['help']:
557 return commands.help_(ui, cmd, options['version'])
557 return commands.help_(ui, cmd, options['version'])
558 elif options['version']:
558 elif options['version']:
559 return commands.version_(ui)
559 return commands.version_(ui)
560 elif not cmd:
560 elif not cmd:
561 return commands.help_(ui, 'shortlist')
561 return commands.help_(ui, 'shortlist')
562
562
563 repo = None
563 repo = None
564 cmdpats = args[:]
564 cmdpats = args[:]
565 if cmd not in commands.norepo.split():
565 if cmd not in commands.norepo.split():
566 try:
566 try:
567 repo = hg.repository(ui, path=path)
567 repo = hg.repository(ui, path=path)
568 ui = repo.ui
568 ui = repo.ui
569 if not repo.local():
569 if not repo.local():
570 raise util.Abort(_("repository '%s' is not local") % path)
570 raise util.Abort(_("repository '%s' is not local") % path)
571 ui.setconfig("bundle", "mainreporoot", repo.root)
571 ui.setconfig("bundle", "mainreporoot", repo.root)
572 except error.RepoError:
572 except error.RepoError:
573 if cmd not in commands.optionalrepo.split():
573 if cmd not in commands.optionalrepo.split():
574 if args and not path: # try to infer -R from command args
574 if args and not path: # try to infer -R from command args
575 repos = map(cmdutil.findrepo, args)
575 repos = map(cmdutil.findrepo, args)
576 guess = repos[0]
576 guess = repos[0]
577 if guess and repos.count(guess) == len(repos):
577 if guess and repos.count(guess) == len(repos):
578 return _dispatch(ui, ['--repository', guess] + fullargs)
578 return _dispatch(ui, ['--repository', guess] + fullargs)
579 if not path:
579 if not path:
580 raise error.RepoError(_("There is no Mercurial repository"
580 raise error.RepoError(_("There is no Mercurial repository"
581 " here (.hg not found)"))
581 " here (.hg not found)"))
582 raise
582 raise
583 args.insert(0, repo)
583 args.insert(0, repo)
584 elif rpath:
584 elif rpath:
585 ui.warn(_("warning: --repository ignored\n"))
585 ui.warn(_("warning: --repository ignored\n"))
586
586
587 msg = ' '.join(' ' in a and repr(a) or a for a in fullargs)
587 msg = ' '.join(' ' in a and repr(a) or a for a in fullargs)
588 ui.log("command", msg + "\n")
588 ui.log("command", msg + "\n")
589 d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
589 d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
590 return runcommand(lui, repo, cmd, fullargs, ui, options, d,
590 return runcommand(lui, repo, cmd, fullargs, ui, options, d,
591 cmdpats, cmdoptions)
591 cmdpats, cmdoptions)
592
592
593 def _runcommand(ui, options, cmd, cmdfunc):
593 def _runcommand(ui, options, cmd, cmdfunc):
594 def checkargs():
594 def checkargs():
595 try:
595 try:
596 return cmdfunc()
596 return cmdfunc()
597 except error.SignatureError:
597 except error.SignatureError:
598 raise error.CommandError(cmd, _("invalid arguments"))
598 raise error.CommandError(cmd, _("invalid arguments"))
599
599
600 if options['profile']:
600 if options['profile']:
601 format = ui.config('profiling', 'format', default='text')
601 format = ui.config('profiling', 'format', default='text')
602
602
603 if not format in ['text', 'kcachegrind']:
603 if not format in ['text', 'kcachegrind']:
604 ui.warn(_("unrecognized profiling format '%s'"
604 ui.warn(_("unrecognized profiling format '%s'"
605 " - Ignored\n") % format)
605 " - Ignored\n") % format)
606 format = 'text'
606 format = 'text'
607
607
608 output = ui.config('profiling', 'output')
608 output = ui.config('profiling', 'output')
609
609
610 if output:
610 if output:
611 path = ui.expandpath(output)
611 path = ui.expandpath(output)
612 ostream = open(path, 'wb')
612 ostream = open(path, 'wb')
613 else:
613 else:
614 ostream = sys.stderr
614 ostream = sys.stderr
615
615
616 try:
616 try:
617 from mercurial import lsprof
617 from mercurial import lsprof
618 except ImportError:
618 except ImportError:
619 raise util.Abort(_(
619 raise util.Abort(_(
620 'lsprof not available - install from '
620 'lsprof not available - install from '
621 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
621 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
622 p = lsprof.Profiler()
622 p = lsprof.Profiler()
623 p.enable(subcalls=True)
623 p.enable(subcalls=True)
624 try:
624 try:
625 return checkargs()
625 return checkargs()
626 finally:
626 finally:
627 p.disable()
627 p.disable()
628
628
629 if format == 'kcachegrind':
629 if format == 'kcachegrind':
630 import lsprofcalltree
630 import lsprofcalltree
631 calltree = lsprofcalltree.KCacheGrind(p)
631 calltree = lsprofcalltree.KCacheGrind(p)
632 calltree.output(ostream)
632 calltree.output(ostream)
633 else:
633 else:
634 # format == 'text'
634 # format == 'text'
635 stats = lsprof.Stats(p.getstats())
635 stats = lsprof.Stats(p.getstats())
636 stats.sort()
636 stats.sort()
637 stats.pprint(top=10, file=ostream, climit=5)
637 stats.pprint(top=10, file=ostream, climit=5)
638
638
639 if output:
639 if output:
640 ostream.close()
640 ostream.close()
641 else:
641 else:
642 return checkargs()
642 return checkargs()
General Comments 0
You need to be logged in to leave comments. Login now