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