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