##// END OF EJS Templates
dispatch: move command dispatching into its own module...
Matt Mackall -
r5178:18a9fbb5 default
parent child Browse files
Show More
@@ -0,0 +1,390 b''
1 # dispatch.py - command dispatching for mercurial
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
7
8 from node import *
9 from i18n import _
10 import os, sys, atexit, signal, pdb, traceback, socket, errno, shlex, time
11 import util, commands, hg, lock, fancyopts, revlog, version, extensions, hook
12 import cmdutil
13 import ui as _ui
14
15 class ParseError(Exception):
16 """Exception raised on errors in parsing the command line."""
17
18 def run():
19 "run the command in sys.argv"
20 sys.exit(dispatch(sys.argv[1:]))
21
22 def dispatch(args):
23 "run the command specified in args"
24 try:
25 u = _ui.ui(traceback='--traceback' in args)
26 except util.Abort, inst:
27 sys.stderr.write(_("abort: %s\n") % inst)
28 return -1
29 return _runcatch(u, args)
30
31 def _runcatch(ui, args):
32 def catchterm(*args):
33 raise util.SignalInterrupt
34
35 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
36 num = getattr(signal, name, None)
37 if num: signal.signal(num, catchterm)
38
39 try:
40 try:
41 # enter the debugger before command execution
42 if '--debugger' in args:
43 pdb.set_trace()
44 try:
45 return _dispatch(ui, args)
46 finally:
47 ui.flush()
48 except:
49 # enter the debugger when we hit an exception
50 if '--debugger' in args:
51 pdb.post_mortem(sys.exc_info()[2])
52 ui.print_exc()
53 raise
54
55 except ParseError, inst:
56 if inst.args[0]:
57 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
58 commands.help_(ui, inst.args[0])
59 else:
60 ui.warn(_("hg: %s\n") % inst.args[1])
61 commands.help_(ui, 'shortlist')
62 except cmdutil.AmbiguousCommand, inst:
63 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
64 (inst.args[0], " ".join(inst.args[1])))
65 except cmdutil.UnknownCommand, inst:
66 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
67 commands.help_(ui, 'shortlist')
68 except hg.RepoError, inst:
69 ui.warn(_("abort: %s!\n") % inst)
70 except lock.LockHeld, inst:
71 if inst.errno == errno.ETIMEDOUT:
72 reason = _('timed out waiting for lock held by %s') % inst.locker
73 else:
74 reason = _('lock held by %s') % inst.locker
75 ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
76 except lock.LockUnavailable, inst:
77 ui.warn(_("abort: could not lock %s: %s\n") %
78 (inst.desc or inst.filename, inst.strerror))
79 except revlog.RevlogError, inst:
80 ui.warn(_("abort: %s!\n") % inst)
81 except util.SignalInterrupt:
82 ui.warn(_("killed!\n"))
83 except KeyboardInterrupt:
84 try:
85 ui.warn(_("interrupted!\n"))
86 except IOError, inst:
87 if inst.errno == errno.EPIPE:
88 if ui.debugflag:
89 ui.warn(_("\nbroken pipe\n"))
90 else:
91 raise
92 except socket.error, inst:
93 ui.warn(_("abort: %s\n") % inst[1])
94 except IOError, inst:
95 if hasattr(inst, "code"):
96 ui.warn(_("abort: %s\n") % inst)
97 elif hasattr(inst, "reason"):
98 try: # usually it is in the form (errno, strerror)
99 reason = inst.reason.args[1]
100 except: # it might be anything, for example a string
101 reason = inst.reason
102 ui.warn(_("abort: error: %s\n") % reason)
103 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
104 if ui.debugflag:
105 ui.warn(_("broken pipe\n"))
106 elif getattr(inst, "strerror", None):
107 if getattr(inst, "filename", None):
108 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
109 else:
110 ui.warn(_("abort: %s\n") % inst.strerror)
111 else:
112 raise
113 except OSError, inst:
114 if getattr(inst, "filename", None):
115 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
116 else:
117 ui.warn(_("abort: %s\n") % inst.strerror)
118 except util.UnexpectedOutput, inst:
119 ui.warn(_("abort: %s") % inst[0])
120 if not isinstance(inst[1], basestring):
121 ui.warn(" %r\n" % (inst[1],))
122 elif not inst[1]:
123 ui.warn(_(" empty string\n"))
124 else:
125 ui.warn("\n%r\n" % util.ellipsis(inst[1]))
126 except ImportError, inst:
127 m = str(inst).split()[-1]
128 ui.warn(_("abort: could not import module %s!\n" % m))
129 if m in "mpatch bdiff".split():
130 ui.warn(_("(did you forget to compile extensions?)\n"))
131 elif m in "zlib".split():
132 ui.warn(_("(is your Python install correct?)\n"))
133
134 except util.Abort, inst:
135 ui.warn(_("abort: %s\n") % inst)
136 except SystemExit, inst:
137 # Commands shouldn't sys.exit directly, but give a return code.
138 # Just in case catch this and and pass exit code to caller.
139 return inst.code
140 except:
141 ui.warn(_("** unknown exception encountered, details follow\n"))
142 ui.warn(_("** report bug details to "
143 "http://www.selenic.com/mercurial/bts\n"))
144 ui.warn(_("** or mercurial@selenic.com\n"))
145 ui.warn(_("** Mercurial Distributed SCM (version %s)\n")
146 % version.get_version())
147 raise
148
149 return -1
150
151 def _findrepo():
152 p = os.getcwd()
153 while not os.path.isdir(os.path.join(p, ".hg")):
154 oldp, p = p, os.path.dirname(p)
155 if p == oldp:
156 return None
157
158 return p
159
160 def _parse(ui, args):
161 options = {}
162 cmdoptions = {}
163
164 try:
165 args = fancyopts.fancyopts(args, commands.globalopts, options)
166 except fancyopts.getopt.GetoptError, inst:
167 raise ParseError(None, inst)
168
169 if args:
170 cmd, args = args[0], args[1:]
171 aliases, i = cmdutil.findcmd(ui, cmd, commands.table)
172 cmd = aliases[0]
173 defaults = ui.config("defaults", cmd)
174 if defaults:
175 args = shlex.split(defaults) + args
176 c = list(i[1])
177 else:
178 cmd = None
179 c = []
180
181 # combine global options into local
182 for o in commands.globalopts:
183 c.append((o[0], o[1], options[o[1]], o[3]))
184
185 try:
186 args = fancyopts.fancyopts(args, c, cmdoptions)
187 except fancyopts.getopt.GetoptError, inst:
188 raise ParseError(cmd, inst)
189
190 # separate global options back out
191 for o in commands.globalopts:
192 n = o[1]
193 options[n] = cmdoptions[n]
194 del cmdoptions[n]
195
196 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
197
198 def _parseconfig(config):
199 """parse the --config options from the command line"""
200 parsed = []
201 for cfg in config:
202 try:
203 name, value = cfg.split('=', 1)
204 section, name = name.split('.', 1)
205 if not section or not name:
206 raise IndexError
207 parsed.append((section, name, value))
208 except (IndexError, ValueError):
209 raise util.Abort(_('malformed --config option: %s') % cfg)
210 return parsed
211
212 def _earlygetopt(aliases, args):
213 """Return list of values for an option (or aliases).
214
215 The values are listed in the order they appear in args.
216 The options and values are removed from args.
217 """
218 try:
219 argcount = args.index("--")
220 except ValueError:
221 argcount = len(args)
222 shortopts = [opt for opt in aliases if len(opt) == 2]
223 values = []
224 pos = 0
225 while pos < argcount:
226 if args[pos] in aliases:
227 if pos + 1 >= argcount:
228 # ignore and let getopt report an error if there is no value
229 break
230 del args[pos]
231 values.append(args.pop(pos))
232 argcount -= 2
233 elif args[pos][:2] in shortopts:
234 # short option can have no following space, e.g. hg log -Rfoo
235 values.append(args.pop(pos)[2:])
236 argcount -= 1
237 else:
238 pos += 1
239 return values
240
241 def _dispatch(ui, args):
242 # read --config before doing anything else
243 # (e.g. to change trust settings for reading .hg/hgrc)
244 config = _earlygetopt(['--config'], args)
245 if config:
246 ui.updateopts(config=_parseconfig(config))
247
248 # check for cwd
249 cwd = _earlygetopt(['--cwd'], args)
250 if cwd:
251 os.chdir(cwd[-1])
252
253 # read the local repository .hgrc into a local ui object
254 path = _findrepo() or ""
255 if not path:
256 lui = ui
257 if path:
258 try:
259 lui = _ui.ui(parentui=ui)
260 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
261 except IOError:
262 pass
263
264 # now we can expand paths, even ones in .hg/hgrc
265 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
266 if rpath:
267 path = lui.expandpath(rpath[-1])
268 lui = _ui.ui(parentui=ui)
269 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
270
271 extensions.loadall(lui)
272 # check for fallback encoding
273 fallback = lui.config('ui', 'fallbackencoding')
274 if fallback:
275 util._fallbackencoding = fallback
276
277 fullargs = args
278 cmd, func, args, options, cmdoptions = _parse(lui, args)
279
280 if options["config"]:
281 raise util.Abort(_("Option --config may not be abbreviated!"))
282 if options["cwd"]:
283 raise util.Abort(_("Option --cwd may not be abbreviated!"))
284 if options["repository"]:
285 raise util.Abort(_(
286 "Option -R has to be separated from other options (i.e. not -qR) "
287 "and --repository may only be abbreviated as --repo!"))
288
289 if options["encoding"]:
290 util._encoding = options["encoding"]
291 if options["encodingmode"]:
292 util._encodingmode = options["encodingmode"]
293 if options["time"]:
294 def get_times():
295 t = os.times()
296 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
297 t = (t[0], t[1], t[2], t[3], time.clock())
298 return t
299 s = get_times()
300 def print_time():
301 t = get_times()
302 ui.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
303 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
304 atexit.register(print_time)
305
306 ui.updateopts(options["verbose"], options["debug"], options["quiet"],
307 not options["noninteractive"], options["traceback"])
308
309 if options['help']:
310 return commands.help_(ui, cmd, options['version'])
311 elif options['version']:
312 return commands.version_(ui)
313 elif not cmd:
314 return commands.help_(ui, 'shortlist')
315
316 repo = None
317 if cmd not in commands.norepo.split():
318 try:
319 repo = hg.repository(ui, path=path)
320 ui = repo.ui
321 if not repo.local():
322 raise util.Abort(_("repository '%s' is not local") % path)
323 except hg.RepoError:
324 if cmd not in commands.optionalrepo.split():
325 if not path:
326 raise hg.RepoError(_("There is no Mercurial repository here"
327 " (.hg not found)"))
328 raise
329 d = lambda: func(ui, repo, *args, **cmdoptions)
330 else:
331 d = lambda: func(ui, *args, **cmdoptions)
332
333 # run pre-hook, and abort if it fails
334 ret = hook.hook(ui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs))
335 if ret:
336 return ret
337 ret = _runcommand(ui, options, cmd, d)
338 # run post-hook, passing command result
339 hook.hook(ui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
340 result = ret)
341 return ret
342
343 def _runcommand(ui, options, cmd, cmdfunc):
344 def checkargs():
345 try:
346 return cmdfunc()
347 except TypeError, inst:
348 # was this an argument error?
349 tb = traceback.extract_tb(sys.exc_info()[2])
350 if len(tb) != 2: # no
351 raise
352 raise ParseError(cmd, _("invalid arguments"))
353
354 if options['profile']:
355 import hotshot, hotshot.stats
356 prof = hotshot.Profile("hg.prof")
357 try:
358 try:
359 return prof.runcall(checkargs)
360 except:
361 try:
362 ui.warn(_('exception raised - generating '
363 'profile anyway\n'))
364 except:
365 pass
366 raise
367 finally:
368 prof.close()
369 stats = hotshot.stats.load("hg.prof")
370 stats.strip_dirs()
371 stats.sort_stats('time', 'calls')
372 stats.print_stats(40)
373 elif options['lsprof']:
374 try:
375 from mercurial import lsprof
376 except ImportError:
377 raise util.Abort(_(
378 'lsprof not available - install from '
379 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
380 p = lsprof.Profiler()
381 p.enable(subcalls=True)
382 try:
383 return checkargs()
384 finally:
385 p.disable()
386 stats = lsprof.Stats(p.getstats())
387 stats.sort()
388 stats.pprint(top=10, file=sys.stderr, climit=5)
389 else:
390 return checkargs()
@@ -7,5 +7,5 b''
7 # This software may be used and distributed according to the terms
7 # This software may be used and distributed according to the terms
8 # of the GNU General Public License, incorporated herein by reference.
8 # of the GNU General Public License, incorporated herein by reference.
9
9
10 import mercurial.commands
10 import mercurial.dispatch
11 mercurial.commands.run()
11 mercurial.dispatch.run()
@@ -42,7 +42,7 b' class lazycommand(object):'
42 return
42 return
43
43
44 try:
44 try:
45 self._cmd = findcmd(self._ui, self._target)[1]
45 self._cmd = findcmd(self._ui, self._target, commands.table)[1]
46 if self._cmd == self:
46 if self._cmd == self:
47 raise RecursiveCommand()
47 raise RecursiveCommand()
48 if self._target in commands.norepo.split(' '):
48 if self._target in commands.norepo.split(' '):
@@ -7,10 +7,8 b''
7
7
8 from node import *
8 from node import *
9 from i18n import _
9 from i18n import _
10 import os, sys, atexit, signal, pdb, traceback, socket, errno, shlex
10 import os, sys, bisect, stat
11 import bisect, stat
11 import mdiff, bdiff, util, templater, patch
12 import mdiff, bdiff, util, templater, patch, commands, hg, lock, time
13 import fancyopts, revlog, version, extensions, hook
14
12
15 revrangesep = ':'
13 revrangesep = ':'
16
14
@@ -18,130 +16,8 b' class UnknownCommand(Exception):'
18 """Exception raised if command is not in the command table."""
16 """Exception raised if command is not in the command table."""
19 class AmbiguousCommand(Exception):
17 class AmbiguousCommand(Exception):
20 """Exception raised if command shortcut matches more than one command."""
18 """Exception raised if command shortcut matches more than one command."""
21 class ParseError(Exception):
22 """Exception raised on errors in parsing the command line."""
23
19
24 def runcatch(ui, args):
20 def findpossible(ui, cmd, table):
25 def catchterm(*args):
26 raise util.SignalInterrupt
27
28 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
29 num = getattr(signal, name, None)
30 if num: signal.signal(num, catchterm)
31
32 try:
33 try:
34 # enter the debugger before command execution
35 if '--debugger' in args:
36 pdb.set_trace()
37 try:
38 return dispatch(ui, args)
39 finally:
40 ui.flush()
41 except:
42 # enter the debugger when we hit an exception
43 if '--debugger' in args:
44 pdb.post_mortem(sys.exc_info()[2])
45 ui.print_exc()
46 raise
47
48 except ParseError, inst:
49 if inst.args[0]:
50 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
51 commands.help_(ui, inst.args[0])
52 else:
53 ui.warn(_("hg: %s\n") % inst.args[1])
54 commands.help_(ui, 'shortlist')
55 except AmbiguousCommand, inst:
56 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
57 (inst.args[0], " ".join(inst.args[1])))
58 except UnknownCommand, inst:
59 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
60 commands.help_(ui, 'shortlist')
61 except hg.RepoError, inst:
62 ui.warn(_("abort: %s!\n") % inst)
63 except lock.LockHeld, inst:
64 if inst.errno == errno.ETIMEDOUT:
65 reason = _('timed out waiting for lock held by %s') % inst.locker
66 else:
67 reason = _('lock held by %s') % inst.locker
68 ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
69 except lock.LockUnavailable, inst:
70 ui.warn(_("abort: could not lock %s: %s\n") %
71 (inst.desc or inst.filename, inst.strerror))
72 except revlog.RevlogError, inst:
73 ui.warn(_("abort: %s!\n") % inst)
74 except util.SignalInterrupt:
75 ui.warn(_("killed!\n"))
76 except KeyboardInterrupt:
77 try:
78 ui.warn(_("interrupted!\n"))
79 except IOError, inst:
80 if inst.errno == errno.EPIPE:
81 if ui.debugflag:
82 ui.warn(_("\nbroken pipe\n"))
83 else:
84 raise
85 except socket.error, inst:
86 ui.warn(_("abort: %s\n") % inst[1])
87 except IOError, inst:
88 if hasattr(inst, "code"):
89 ui.warn(_("abort: %s\n") % inst)
90 elif hasattr(inst, "reason"):
91 try: # usually it is in the form (errno, strerror)
92 reason = inst.reason.args[1]
93 except: # it might be anything, for example a string
94 reason = inst.reason
95 ui.warn(_("abort: error: %s\n") % reason)
96 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
97 if ui.debugflag:
98 ui.warn(_("broken pipe\n"))
99 elif getattr(inst, "strerror", None):
100 if getattr(inst, "filename", None):
101 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
102 else:
103 ui.warn(_("abort: %s\n") % inst.strerror)
104 else:
105 raise
106 except OSError, inst:
107 if getattr(inst, "filename", None):
108 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
109 else:
110 ui.warn(_("abort: %s\n") % inst.strerror)
111 except util.UnexpectedOutput, inst:
112 ui.warn(_("abort: %s") % inst[0])
113 if not isinstance(inst[1], basestring):
114 ui.warn(" %r\n" % (inst[1],))
115 elif not inst[1]:
116 ui.warn(_(" empty string\n"))
117 else:
118 ui.warn("\n%r\n" % util.ellipsis(inst[1]))
119 except ImportError, inst:
120 m = str(inst).split()[-1]
121 ui.warn(_("abort: could not import module %s!\n" % m))
122 if m in "mpatch bdiff".split():
123 ui.warn(_("(did you forget to compile extensions?)\n"))
124 elif m in "zlib".split():
125 ui.warn(_("(is your Python install correct?)\n"))
126
127 except util.Abort, inst:
128 ui.warn(_("abort: %s\n") % inst)
129 except SystemExit, inst:
130 # Commands shouldn't sys.exit directly, but give a return code.
131 # Just in case catch this and and pass exit code to caller.
132 return inst.code
133 except:
134 ui.warn(_("** unknown exception encountered, details follow\n"))
135 ui.warn(_("** report bug details to "
136 "http://www.selenic.com/mercurial/bts\n"))
137 ui.warn(_("** or mercurial@selenic.com\n"))
138 ui.warn(_("** Mercurial Distributed SCM (version %s)\n")
139 % version.get_version())
140 raise
141
142 return -1
143
144 def findpossible(ui, cmd):
145 """
21 """
146 Return cmd -> (aliases, command table entry)
22 Return cmd -> (aliases, command table entry)
147 for each matching command.
23 for each matching command.
@@ -149,7 +25,7 b' def findpossible(ui, cmd):'
149 """
25 """
150 choice = {}
26 choice = {}
151 debugchoice = {}
27 debugchoice = {}
152 for e in commands.table.keys():
28 for e in table.keys():
153 aliases = e.lstrip("^").split("|")
29 aliases = e.lstrip("^").split("|")
154 found = None
30 found = None
155 if cmd in aliases:
31 if cmd in aliases:
@@ -161,18 +37,18 b' def findpossible(ui, cmd):'
161 break
37 break
162 if found is not None:
38 if found is not None:
163 if aliases[0].startswith("debug") or found.startswith("debug"):
39 if aliases[0].startswith("debug") or found.startswith("debug"):
164 debugchoice[found] = (aliases, commands.table[e])
40 debugchoice[found] = (aliases, table[e])
165 else:
41 else:
166 choice[found] = (aliases, commands.table[e])
42 choice[found] = (aliases, table[e])
167
43
168 if not choice and debugchoice:
44 if not choice and debugchoice:
169 choice = debugchoice
45 choice = debugchoice
170
46
171 return choice
47 return choice
172
48
173 def findcmd(ui, cmd):
49 def findcmd(ui, cmd, table):
174 """Return (aliases, command table entry) for command string."""
50 """Return (aliases, command table entry) for command string."""
175 choice = findpossible(ui, cmd)
51 choice = findpossible(ui, cmd, table)
176
52
177 if choice.has_key(cmd):
53 if choice.has_key(cmd):
178 return choice[cmd]
54 return choice[cmd]
@@ -187,247 +63,6 b' def findcmd(ui, cmd):'
187
63
188 raise UnknownCommand(cmd)
64 raise UnknownCommand(cmd)
189
65
190 def findrepo():
191 p = os.getcwd()
192 while not os.path.isdir(os.path.join(p, ".hg")):
193 oldp, p = p, os.path.dirname(p)
194 if p == oldp:
195 return None
196
197 return p
198
199 def parse(ui, args):
200 options = {}
201 cmdoptions = {}
202
203 try:
204 args = fancyopts.fancyopts(args, commands.globalopts, options)
205 except fancyopts.getopt.GetoptError, inst:
206 raise ParseError(None, inst)
207
208 if args:
209 cmd, args = args[0], args[1:]
210 aliases, i = findcmd(ui, cmd)
211 cmd = aliases[0]
212 defaults = ui.config("defaults", cmd)
213 if defaults:
214 args = shlex.split(defaults) + args
215 c = list(i[1])
216 else:
217 cmd = None
218 c = []
219
220 # combine global options into local
221 for o in commands.globalopts:
222 c.append((o[0], o[1], options[o[1]], o[3]))
223
224 try:
225 args = fancyopts.fancyopts(args, c, cmdoptions)
226 except fancyopts.getopt.GetoptError, inst:
227 raise ParseError(cmd, inst)
228
229 # separate global options back out
230 for o in commands.globalopts:
231 n = o[1]
232 options[n] = cmdoptions[n]
233 del cmdoptions[n]
234
235 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
236
237 def parseconfig(config):
238 """parse the --config options from the command line"""
239 parsed = []
240 for cfg in config:
241 try:
242 name, value = cfg.split('=', 1)
243 section, name = name.split('.', 1)
244 if not section or not name:
245 raise IndexError
246 parsed.append((section, name, value))
247 except (IndexError, ValueError):
248 raise util.Abort(_('malformed --config option: %s') % cfg)
249 return parsed
250
251 def earlygetopt(aliases, args):
252 """Return list of values for an option (or aliases).
253
254 The values are listed in the order they appear in args.
255 The options and values are removed from args.
256 """
257 try:
258 argcount = args.index("--")
259 except ValueError:
260 argcount = len(args)
261 shortopts = [opt for opt in aliases if len(opt) == 2]
262 values = []
263 pos = 0
264 while pos < argcount:
265 if args[pos] in aliases:
266 if pos + 1 >= argcount:
267 # ignore and let getopt report an error if there is no value
268 break
269 del args[pos]
270 values.append(args.pop(pos))
271 argcount -= 2
272 elif args[pos][:2] in shortopts:
273 # short option can have no following space, e.g. hg log -Rfoo
274 values.append(args.pop(pos)[2:])
275 argcount -= 1
276 else:
277 pos += 1
278 return values
279
280 def dispatch(ui, args):
281 # read --config before doing anything else
282 # (e.g. to change trust settings for reading .hg/hgrc)
283 config = earlygetopt(['--config'], args)
284 if config:
285 ui.updateopts(config=parseconfig(config))
286
287 # check for cwd
288 cwd = earlygetopt(['--cwd'], args)
289 if cwd:
290 os.chdir(cwd[-1])
291
292 # read the local repository .hgrc into a local ui object
293 path = findrepo() or ""
294 if not path:
295 lui = ui
296 if path:
297 try:
298 lui = commands.ui.ui(parentui=ui)
299 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
300 except IOError:
301 pass
302
303 # now we can expand paths, even ones in .hg/hgrc
304 rpath = earlygetopt(["-R", "--repository", "--repo"], args)
305 if rpath:
306 path = lui.expandpath(rpath[-1])
307 lui = commands.ui.ui(parentui=ui)
308 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
309
310 extensions.loadall(lui)
311 # check for fallback encoding
312 fallback = lui.config('ui', 'fallbackencoding')
313 if fallback:
314 util._fallbackencoding = fallback
315
316 fullargs = args
317 cmd, func, args, options, cmdoptions = parse(lui, args)
318
319 if options["config"]:
320 raise util.Abort(_("Option --config may not be abbreviated!"))
321 if options["cwd"]:
322 raise util.Abort(_("Option --cwd may not be abbreviated!"))
323 if options["repository"]:
324 raise util.Abort(_(
325 "Option -R has to be separated from other options (i.e. not -qR) "
326 "and --repository may only be abbreviated as --repo!"))
327
328 if options["encoding"]:
329 util._encoding = options["encoding"]
330 if options["encodingmode"]:
331 util._encodingmode = options["encodingmode"]
332 if options["time"]:
333 def get_times():
334 t = os.times()
335 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
336 t = (t[0], t[1], t[2], t[3], time.clock())
337 return t
338 s = get_times()
339 def print_time():
340 t = get_times()
341 ui.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
342 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
343 atexit.register(print_time)
344
345 ui.updateopts(options["verbose"], options["debug"], options["quiet"],
346 not options["noninteractive"], options["traceback"])
347
348 if options['help']:
349 return commands.help_(ui, cmd, options['version'])
350 elif options['version']:
351 return commands.version_(ui)
352 elif not cmd:
353 return commands.help_(ui, 'shortlist')
354
355 repo = None
356 if cmd not in commands.norepo.split():
357 try:
358 repo = hg.repository(ui, path=path)
359 ui = repo.ui
360 if not repo.local():
361 raise util.Abort(_("repository '%s' is not local") % path)
362 except hg.RepoError:
363 if cmd not in commands.optionalrepo.split():
364 if not path:
365 raise hg.RepoError(_("There is no Mercurial repository here"
366 " (.hg not found)"))
367 raise
368 d = lambda: func(ui, repo, *args, **cmdoptions)
369 else:
370 d = lambda: func(ui, *args, **cmdoptions)
371
372 # run pre-hook, and abort if it fails
373 ret = hook.hook(ui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs))
374 if ret:
375 return ret
376 ret = runcommand(ui, options, cmd, d)
377 # run post-hook, passing command result
378 hook.hook(ui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
379 result = ret)
380 return ret
381
382 def runcommand(ui, options, cmd, cmdfunc):
383 def checkargs():
384 try:
385 return cmdfunc()
386 except TypeError, inst:
387 # was this an argument error?
388 tb = traceback.extract_tb(sys.exc_info()[2])
389 if len(tb) != 2: # no
390 raise
391 raise ParseError(cmd, _("invalid arguments"))
392
393 if options['profile']:
394 import hotshot, hotshot.stats
395 prof = hotshot.Profile("hg.prof")
396 try:
397 try:
398 return prof.runcall(checkargs)
399 except:
400 try:
401 ui.warn(_('exception raised - generating '
402 'profile anyway\n'))
403 except:
404 pass
405 raise
406 finally:
407 prof.close()
408 stats = hotshot.stats.load("hg.prof")
409 stats.strip_dirs()
410 stats.sort_stats('time', 'calls')
411 stats.print_stats(40)
412 elif options['lsprof']:
413 try:
414 from mercurial import lsprof
415 except ImportError:
416 raise util.Abort(_(
417 'lsprof not available - install from '
418 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
419 p = lsprof.Profiler()
420 p.enable(subcalls=True)
421 try:
422 return checkargs()
423 finally:
424 p.disable()
425 stats = lsprof.Stats(p.getstats())
426 stats.sort()
427 stats.pprint(top=10, file=sys.stderr, climit=5)
428 else:
429 return checkargs()
430
431 def bail_if_changed(repo):
66 def bail_if_changed(repo):
432 modified, added, removed, deleted = repo.status()[:4]
67 modified, added, removed, deleted = repo.status()[:4]
433 if modified or added or removed or deleted:
68 if modified or added or removed or deleted:
@@ -9,7 +9,7 b' import demandimport; demandimport.enable'
9 from node import *
9 from node import *
10 from i18n import _
10 from i18n import _
11 import os, re, sys, urllib
11 import os, re, sys, urllib
12 import ui, hg, util, revlog, bundlerepo, extensions
12 import hg, util, revlog, bundlerepo, extensions
13 import difflib, patch, time, help, mdiff, tempfile
13 import difflib, patch, time, help, mdiff, tempfile
14 import errno, version, socket
14 import errno, version, socket
15 import archival, changegroup, cmdutil, hgweb.server, sshserver
15 import archival, changegroup, cmdutil, hgweb.server, sshserver
@@ -662,7 +662,7 b" def debugcomplete(ui, cmd='', **opts):"
662 options = []
662 options = []
663 otables = [globalopts]
663 otables = [globalopts]
664 if cmd:
664 if cmd:
665 aliases, entry = cmdutil.findcmd(ui, cmd)
665 aliases, entry = cmdutil.findcmd(ui, cmd, table)
666 otables.append(entry[1])
666 otables.append(entry[1])
667 for t in otables:
667 for t in otables:
668 for o in t:
668 for o in t:
@@ -672,7 +672,7 b" def debugcomplete(ui, cmd='', **opts):"
672 ui.write("%s\n" % "\n".join(options))
672 ui.write("%s\n" % "\n".join(options))
673 return
673 return
674
674
675 clist = cmdutil.findpossible(ui, cmd).keys()
675 clist = cmdutil.findpossible(ui, cmd, table).keys()
676 clist.sort()
676 clist.sort()
677 ui.write("%s\n" % "\n".join(clist))
677 ui.write("%s\n" % "\n".join(clist))
678
678
@@ -1307,7 +1307,7 b' def help_(ui, name=None, with_version=Fa'
1307 if with_version:
1307 if with_version:
1308 version_(ui)
1308 version_(ui)
1309 ui.write('\n')
1309 ui.write('\n')
1310 aliases, i = cmdutil.findcmd(ui, name)
1310 aliases, i = cmdutil.findcmd(ui, name, table)
1311 # synopsis
1311 # synopsis
1312 ui.write("%s\n\n" % i[2])
1312 ui.write("%s\n\n" % i[2])
1313
1313
@@ -3134,14 +3134,3 b' extensions.commandtable = table'
3134 norepo = ("clone init version help debugancestor debugcomplete debugdata"
3134 norepo = ("clone init version help debugancestor debugcomplete debugdata"
3135 " debugindex debugindexdot debugdate debuginstall")
3135 " debugindex debugindexdot debugdate debuginstall")
3136 optionalrepo = ("paths serve showconfig")
3136 optionalrepo = ("paths serve showconfig")
3137
3138 def dispatch(args):
3139 try:
3140 u = ui.ui(traceback='--traceback' in args)
3141 except util.Abort, inst:
3142 sys.stderr.write(_("abort: %s\n") % inst)
3143 return -1
3144 return cmdutil.runcatch(u, args)
3145
3146 def run():
3147 sys.exit(dispatch(sys.argv[1:]))
@@ -1,32 +1,32 b''
1 import os
1 import os
2 from mercurial import commands
2 from mercurial import dispatch
3
3
4 def dispatch(cmd):
4 def testdispatch(cmd):
5 """Simple wrapper around commands.dispatch()
5 """Simple wrapper around dispatch.dispatch()
6
6
7 Prints command and result value, but does not handle quoting.
7 Prints command and result value, but does not handle quoting.
8 """
8 """
9 print "running: %s" % (cmd,)
9 print "running: %s" % (cmd,)
10 result = commands.dispatch(cmd.split())
10 result = dispatch.dispatch(cmd.split())
11 print "result: %r" % (result,)
11 print "result: %r" % (result,)
12
12
13
13
14 dispatch("init test1")
14 testdispatch("init test1")
15 os.chdir('test1')
15 os.chdir('test1')
16
16
17 # create file 'foo', add and commit
17 # create file 'foo', add and commit
18 f = file('foo', 'wb')
18 f = file('foo', 'wb')
19 f.write('foo\n')
19 f.write('foo\n')
20 f.close()
20 f.close()
21 dispatch("add foo")
21 testdispatch("add foo")
22 dispatch("commit -m commit1 -d 2000-01-01 foo")
22 testdispatch("commit -m commit1 -d 2000-01-01 foo")
23
23
24 # append to file 'foo' and commit
24 # append to file 'foo' and commit
25 f = file('foo', 'ab')
25 f = file('foo', 'ab')
26 f.write('bar\n')
26 f.write('bar\n')
27 f.close()
27 f.close()
28 dispatch("commit -m commit2 -d 2000-01-02 foo")
28 testdispatch("commit -m commit2 -d 2000-01-02 foo")
29
29
30 # check 88803a69b24 (fancyopts modified command table)
30 # check 88803a69b24 (fancyopts modified command table)
31 dispatch("log -r 0")
31 testdispatch("log -r 0")
32 dispatch("log -r tip")
32 testdispatch("log -r tip")
@@ -1,10 +1,10 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2
2
3 import ConfigParser
3 import ConfigParser
4 from mercurial import ui, util, cmdutil
4 from mercurial import ui, util, dispatch
5
5
6 testui = ui.ui()
6 testui = ui.ui()
7 parsed = cmdutil.parseconfig([
7 parsed = dispatch._parseconfig([
8 'values.string=string value',
8 'values.string=string value',
9 'values.bool1=true',
9 'values.bool1=true',
10 'values.bool2=false',
10 'values.bool2=false',
General Comments 0
You need to be logged in to leave comments. Login now