Show More
@@ -0,0 +1,390 | |||
|
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 | |||
|
7 | 7 | # This software may be used and distributed according to the terms |
|
8 | 8 | # of the GNU General Public License, incorporated herein by reference. |
|
9 | 9 | |
|
10 |
import mercurial. |
|
|
11 |
mercurial. |
|
|
10 | import mercurial.dispatch | |
|
11 | mercurial.dispatch.run() |
@@ -42,7 +42,7 class lazycommand(object): | |||
|
42 | 42 | return |
|
43 | 43 | |
|
44 | 44 | try: |
|
45 | self._cmd = findcmd(self._ui, self._target)[1] | |
|
45 | self._cmd = findcmd(self._ui, self._target, commands.table)[1] | |
|
46 | 46 | if self._cmd == self: |
|
47 | 47 | raise RecursiveCommand() |
|
48 | 48 | if self._target in commands.norepo.split(' '): |
@@ -7,10 +7,8 | |||
|
7 | 7 | |
|
8 | 8 | from node import * |
|
9 | 9 | from i18n import _ |
|
10 | import os, sys, atexit, signal, pdb, traceback, socket, errno, shlex | |
|
11 | import bisect, stat | |
|
12 | import mdiff, bdiff, util, templater, patch, commands, hg, lock, time | |
|
13 | import fancyopts, revlog, version, extensions, hook | |
|
10 | import os, sys, bisect, stat | |
|
11 | import mdiff, bdiff, util, templater, patch | |
|
14 | 12 | |
|
15 | 13 | revrangesep = ':' |
|
16 | 14 | |
@@ -18,130 +16,8 class UnknownCommand(Exception): | |||
|
18 | 16 | """Exception raised if command is not in the command table.""" |
|
19 | 17 | class AmbiguousCommand(Exception): |
|
20 | 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): | |
|
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): | |
|
20 | def findpossible(ui, cmd, table): | |
|
145 | 21 | """ |
|
146 | 22 | Return cmd -> (aliases, command table entry) |
|
147 | 23 | for each matching command. |
@@ -149,7 +25,7 def findpossible(ui, cmd): | |||
|
149 | 25 | """ |
|
150 | 26 | choice = {} |
|
151 | 27 | debugchoice = {} |
|
152 |
for e in |
|
|
28 | for e in table.keys(): | |
|
153 | 29 | aliases = e.lstrip("^").split("|") |
|
154 | 30 | found = None |
|
155 | 31 | if cmd in aliases: |
@@ -161,18 +37,18 def findpossible(ui, cmd): | |||
|
161 | 37 | break |
|
162 | 38 | if found is not None: |
|
163 | 39 | if aliases[0].startswith("debug") or found.startswith("debug"): |
|
164 |
debugchoice[found] = (aliases, |
|
|
40 | debugchoice[found] = (aliases, table[e]) | |
|
165 | 41 | else: |
|
166 |
choice[found] = (aliases, |
|
|
42 | choice[found] = (aliases, table[e]) | |
|
167 | 43 | |
|
168 | 44 | if not choice and debugchoice: |
|
169 | 45 | choice = debugchoice |
|
170 | 46 | |
|
171 | 47 | return choice |
|
172 | 48 | |
|
173 | def findcmd(ui, cmd): | |
|
49 | def findcmd(ui, cmd, table): | |
|
174 | 50 | """Return (aliases, command table entry) for command string.""" |
|
175 | choice = findpossible(ui, cmd) | |
|
51 | choice = findpossible(ui, cmd, table) | |
|
176 | 52 | |
|
177 | 53 | if choice.has_key(cmd): |
|
178 | 54 | return choice[cmd] |
@@ -187,247 +63,6 def findcmd(ui, cmd): | |||
|
187 | 63 | |
|
188 | 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 | 66 | def bail_if_changed(repo): |
|
432 | 67 | modified, added, removed, deleted = repo.status()[:4] |
|
433 | 68 | if modified or added or removed or deleted: |
@@ -9,7 +9,7 import demandimport; demandimport.enable | |||
|
9 | 9 | from node import * |
|
10 | 10 | from i18n import _ |
|
11 | 11 | import os, re, sys, urllib |
|
12 |
import |
|
|
12 | import hg, util, revlog, bundlerepo, extensions | |
|
13 | 13 | import difflib, patch, time, help, mdiff, tempfile |
|
14 | 14 | import errno, version, socket |
|
15 | 15 | import archival, changegroup, cmdutil, hgweb.server, sshserver |
@@ -662,7 +662,7 def debugcomplete(ui, cmd='', **opts): | |||
|
662 | 662 | options = [] |
|
663 | 663 | otables = [globalopts] |
|
664 | 664 | if cmd: |
|
665 | aliases, entry = cmdutil.findcmd(ui, cmd) | |
|
665 | aliases, entry = cmdutil.findcmd(ui, cmd, table) | |
|
666 | 666 | otables.append(entry[1]) |
|
667 | 667 | for t in otables: |
|
668 | 668 | for o in t: |
@@ -672,7 +672,7 def debugcomplete(ui, cmd='', **opts): | |||
|
672 | 672 | ui.write("%s\n" % "\n".join(options)) |
|
673 | 673 | return |
|
674 | 674 | |
|
675 | clist = cmdutil.findpossible(ui, cmd).keys() | |
|
675 | clist = cmdutil.findpossible(ui, cmd, table).keys() | |
|
676 | 676 | clist.sort() |
|
677 | 677 | ui.write("%s\n" % "\n".join(clist)) |
|
678 | 678 | |
@@ -1307,7 +1307,7 def help_(ui, name=None, with_version=Fa | |||
|
1307 | 1307 | if with_version: |
|
1308 | 1308 | version_(ui) |
|
1309 | 1309 | ui.write('\n') |
|
1310 | aliases, i = cmdutil.findcmd(ui, name) | |
|
1310 | aliases, i = cmdutil.findcmd(ui, name, table) | |
|
1311 | 1311 | # synopsis |
|
1312 | 1312 | ui.write("%s\n\n" % i[2]) |
|
1313 | 1313 | |
@@ -3134,14 +3134,3 extensions.commandtable = table | |||
|
3134 | 3134 | norepo = ("clone init version help debugancestor debugcomplete debugdata" |
|
3135 | 3135 | " debugindex debugindexdot debugdate debuginstall") |
|
3136 | 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 | |||
|
1 | 1 | import os |
|
2 |
from mercurial import |
|
|
2 | from mercurial import dispatch | |
|
3 | 3 | |
|
4 | def dispatch(cmd): | |
|
5 |
"""Simple wrapper around |
|
|
4 | def testdispatch(cmd): | |
|
5 | """Simple wrapper around dispatch.dispatch() | |
|
6 | 6 | |
|
7 | 7 | Prints command and result value, but does not handle quoting. |
|
8 | 8 | """ |
|
9 | 9 | print "running: %s" % (cmd,) |
|
10 |
result = |
|
|
10 | result = dispatch.dispatch(cmd.split()) | |
|
11 | 11 | print "result: %r" % (result,) |
|
12 | 12 | |
|
13 | 13 | |
|
14 | dispatch("init test1") | |
|
14 | testdispatch("init test1") | |
|
15 | 15 | os.chdir('test1') |
|
16 | 16 | |
|
17 | 17 | # create file 'foo', add and commit |
|
18 | 18 | f = file('foo', 'wb') |
|
19 | 19 | f.write('foo\n') |
|
20 | 20 | f.close() |
|
21 | dispatch("add foo") | |
|
22 | dispatch("commit -m commit1 -d 2000-01-01 foo") | |
|
21 | testdispatch("add foo") | |
|
22 | testdispatch("commit -m commit1 -d 2000-01-01 foo") | |
|
23 | 23 | |
|
24 | 24 | # append to file 'foo' and commit |
|
25 | 25 | f = file('foo', 'ab') |
|
26 | 26 | f.write('bar\n') |
|
27 | 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 | 30 | # check 88803a69b24 (fancyopts modified command table) |
|
31 | dispatch("log -r 0") | |
|
32 | dispatch("log -r tip") | |
|
31 | testdispatch("log -r 0") | |
|
32 | testdispatch("log -r tip") |
@@ -1,10 +1,10 | |||
|
1 | 1 | #!/usr/bin/env python |
|
2 | 2 | |
|
3 | 3 | import ConfigParser |
|
4 |
from mercurial import ui, util, |
|
|
4 | from mercurial import ui, util, dispatch | |
|
5 | 5 | |
|
6 | 6 | testui = ui.ui() |
|
7 |
parsed = |
|
|
7 | parsed = dispatch._parseconfig([ | |
|
8 | 8 | 'values.string=string value', |
|
9 | 9 | 'values.bool1=true', |
|
10 | 10 | 'values.bool2=false', |
General Comments 0
You need to be logged in to leave comments.
Login now