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