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