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