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