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