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