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