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