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