##// END OF EJS Templates
log: add logging for commands
Matt Mackall -
r11985:81edef14 default
parent child Browse files
Show More
@@ -1,567 +1,569 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
9 import os, sys, atexit, signal, pdb, socket, errno, shlex, time, traceback
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 def run():
14 def run():
15 "run the command in sys.argv"
15 "run the command in sys.argv"
16 sys.exit(dispatch(sys.argv[1:]))
16 sys.exit(dispatch(sys.argv[1:]))
17
17
18 def dispatch(args):
18 def dispatch(args):
19 "run the command specified in args"
19 "run the command specified in args"
20 try:
20 try:
21 u = uimod.ui()
21 u = uimod.ui()
22 if '--traceback' in args:
22 if '--traceback' in args:
23 u.setconfig('ui', 'traceback', 'on')
23 u.setconfig('ui', 'traceback', 'on')
24 except util.Abort, inst:
24 except util.Abort, inst:
25 sys.stderr.write(_("abort: %s\n") % inst)
25 sys.stderr.write(_("abort: %s\n") % inst)
26 if inst.hint:
26 if inst.hint:
27 sys.stderr.write(_("(%s)\n") % inst.hint)
27 sys.stderr.write(_("(%s)\n") % inst.hint)
28 return -1
28 return -1
29 except error.ParseError, inst:
29 except error.ParseError, inst:
30 if len(inst.args) > 1:
30 if len(inst.args) > 1:
31 sys.stderr.write(_("hg: parse error at %s: %s\n") %
31 sys.stderr.write(_("hg: parse error at %s: %s\n") %
32 (inst.args[1], inst.args[0]))
32 (inst.args[1], inst.args[0]))
33 else:
33 else:
34 sys.stderr.write(_("hg: parse error: %s\n") % inst.args[0])
34 sys.stderr.write(_("hg: parse error: %s\n") % inst.args[0])
35 return -1
35 return -1
36 return _runcatch(u, args)
36 return _runcatch(u, args)
37
37
38 def _runcatch(ui, args):
38 def _runcatch(ui, args):
39 def catchterm(*args):
39 def catchterm(*args):
40 raise error.SignalInterrupt
40 raise error.SignalInterrupt
41
41
42 try:
42 try:
43 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
43 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
44 num = getattr(signal, name, None)
44 num = getattr(signal, name, None)
45 if num:
45 if num:
46 signal.signal(num, catchterm)
46 signal.signal(num, catchterm)
47 except ValueError:
47 except ValueError:
48 pass # happens if called in a thread
48 pass # happens if called in a thread
49
49
50 try:
50 try:
51 try:
51 try:
52 # enter the debugger before command execution
52 # enter the debugger before command execution
53 if '--debugger' in args:
53 if '--debugger' in args:
54 ui.warn(_("entering debugger - "
54 ui.warn(_("entering debugger - "
55 "type c to continue starting hg or h for help\n"))
55 "type c to continue starting hg or h for help\n"))
56 pdb.set_trace()
56 pdb.set_trace()
57 try:
57 try:
58 return _dispatch(ui, args)
58 return _dispatch(ui, args)
59 finally:
59 finally:
60 ui.flush()
60 ui.flush()
61 except:
61 except:
62 # enter the debugger when we hit an exception
62 # enter the debugger when we hit an exception
63 if '--debugger' in args:
63 if '--debugger' in args:
64 traceback.print_exc()
64 traceback.print_exc()
65 pdb.post_mortem(sys.exc_info()[2])
65 pdb.post_mortem(sys.exc_info()[2])
66 ui.traceback()
66 ui.traceback()
67 raise
67 raise
68
68
69 # Global exception handling, alphabetically
69 # Global exception handling, alphabetically
70 # Mercurial-specific first, followed by built-in and library exceptions
70 # Mercurial-specific first, followed by built-in and library exceptions
71 except error.AmbiguousCommand, inst:
71 except error.AmbiguousCommand, inst:
72 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
72 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
73 (inst.args[0], " ".join(inst.args[1])))
73 (inst.args[0], " ".join(inst.args[1])))
74 except error.ParseError, inst:
74 except error.ParseError, inst:
75 if len(inst.args) > 1:
75 if len(inst.args) > 1:
76 ui.warn(_("hg: parse error at %s: %s\n") %
76 ui.warn(_("hg: parse error at %s: %s\n") %
77 (inst.args[1], inst.args[0]))
77 (inst.args[1], inst.args[0]))
78 else:
78 else:
79 ui.warn(_("hg: parse error: %s\n") % inst.args[0])
79 ui.warn(_("hg: parse error: %s\n") % inst.args[0])
80 return -1
80 return -1
81 except error.LockHeld, inst:
81 except error.LockHeld, inst:
82 if inst.errno == errno.ETIMEDOUT:
82 if inst.errno == errno.ETIMEDOUT:
83 reason = _('timed out waiting for lock held by %s') % inst.locker
83 reason = _('timed out waiting for lock held by %s') % inst.locker
84 else:
84 else:
85 reason = _('lock held by %s') % inst.locker
85 reason = _('lock held by %s') % inst.locker
86 ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
86 ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
87 except error.LockUnavailable, inst:
87 except error.LockUnavailable, inst:
88 ui.warn(_("abort: could not lock %s: %s\n") %
88 ui.warn(_("abort: could not lock %s: %s\n") %
89 (inst.desc or inst.filename, inst.strerror))
89 (inst.desc or inst.filename, inst.strerror))
90 except error.CommandError, inst:
90 except error.CommandError, inst:
91 if inst.args[0]:
91 if inst.args[0]:
92 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
92 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
93 commands.help_(ui, inst.args[0])
93 commands.help_(ui, inst.args[0])
94 else:
94 else:
95 ui.warn(_("hg: %s\n") % inst.args[1])
95 ui.warn(_("hg: %s\n") % inst.args[1])
96 commands.help_(ui, 'shortlist')
96 commands.help_(ui, 'shortlist')
97 except error.RepoError, inst:
97 except error.RepoError, inst:
98 ui.warn(_("abort: %s!\n") % inst)
98 ui.warn(_("abort: %s!\n") % inst)
99 except error.ResponseError, inst:
99 except error.ResponseError, inst:
100 ui.warn(_("abort: %s") % inst.args[0])
100 ui.warn(_("abort: %s") % inst.args[0])
101 if not isinstance(inst.args[1], basestring):
101 if not isinstance(inst.args[1], basestring):
102 ui.warn(" %r\n" % (inst.args[1],))
102 ui.warn(" %r\n" % (inst.args[1],))
103 elif not inst.args[1]:
103 elif not inst.args[1]:
104 ui.warn(_(" empty string\n"))
104 ui.warn(_(" empty string\n"))
105 else:
105 else:
106 ui.warn("\n%r\n" % util.ellipsis(inst.args[1]))
106 ui.warn("\n%r\n" % util.ellipsis(inst.args[1]))
107 except error.RevlogError, inst:
107 except error.RevlogError, inst:
108 ui.warn(_("abort: %s!\n") % inst)
108 ui.warn(_("abort: %s!\n") % inst)
109 except error.SignalInterrupt:
109 except error.SignalInterrupt:
110 ui.warn(_("killed!\n"))
110 ui.warn(_("killed!\n"))
111 except error.UnknownCommand, inst:
111 except error.UnknownCommand, inst:
112 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
112 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
113 try:
113 try:
114 # check if the command is in a disabled extension
114 # check if the command is in a disabled extension
115 # (but don't check for extensions themselves)
115 # (but don't check for extensions themselves)
116 commands.help_(ui, inst.args[0], unknowncmd=True)
116 commands.help_(ui, inst.args[0], unknowncmd=True)
117 except error.UnknownCommand:
117 except error.UnknownCommand:
118 commands.help_(ui, 'shortlist')
118 commands.help_(ui, 'shortlist')
119 except util.Abort, inst:
119 except util.Abort, inst:
120 ui.warn(_("abort: %s\n") % inst)
120 ui.warn(_("abort: %s\n") % inst)
121 if inst.hint:
121 if inst.hint:
122 ui.warn(_("(%s)\n") % inst.hint)
122 ui.warn(_("(%s)\n") % inst.hint)
123 except ImportError, inst:
123 except ImportError, inst:
124 ui.warn(_("abort: %s!\n") % inst)
124 ui.warn(_("abort: %s!\n") % inst)
125 m = str(inst).split()[-1]
125 m = str(inst).split()[-1]
126 if m in "mpatch bdiff".split():
126 if m in "mpatch bdiff".split():
127 ui.warn(_("(did you forget to compile extensions?)\n"))
127 ui.warn(_("(did you forget to compile extensions?)\n"))
128 elif m in "zlib".split():
128 elif m in "zlib".split():
129 ui.warn(_("(is your Python install correct?)\n"))
129 ui.warn(_("(is your Python install correct?)\n"))
130 except IOError, inst:
130 except IOError, inst:
131 if hasattr(inst, "code"):
131 if hasattr(inst, "code"):
132 ui.warn(_("abort: %s\n") % inst)
132 ui.warn(_("abort: %s\n") % inst)
133 elif hasattr(inst, "reason"):
133 elif hasattr(inst, "reason"):
134 try: # usually it is in the form (errno, strerror)
134 try: # usually it is in the form (errno, strerror)
135 reason = inst.reason.args[1]
135 reason = inst.reason.args[1]
136 except: # it might be anything, for example a string
136 except: # it might be anything, for example a string
137 reason = inst.reason
137 reason = inst.reason
138 ui.warn(_("abort: error: %s\n") % reason)
138 ui.warn(_("abort: error: %s\n") % reason)
139 elif hasattr(inst, "args") and inst.args[0] == errno.EPIPE:
139 elif hasattr(inst, "args") and inst.args[0] == errno.EPIPE:
140 if ui.debugflag:
140 if ui.debugflag:
141 ui.warn(_("broken pipe\n"))
141 ui.warn(_("broken pipe\n"))
142 elif getattr(inst, "strerror", None):
142 elif getattr(inst, "strerror", None):
143 if getattr(inst, "filename", None):
143 if getattr(inst, "filename", None):
144 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
144 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
145 else:
145 else:
146 ui.warn(_("abort: %s\n") % inst.strerror)
146 ui.warn(_("abort: %s\n") % inst.strerror)
147 else:
147 else:
148 raise
148 raise
149 except OSError, inst:
149 except OSError, inst:
150 if getattr(inst, "filename", None):
150 if getattr(inst, "filename", None):
151 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
151 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
152 else:
152 else:
153 ui.warn(_("abort: %s\n") % inst.strerror)
153 ui.warn(_("abort: %s\n") % inst.strerror)
154 except KeyboardInterrupt:
154 except KeyboardInterrupt:
155 try:
155 try:
156 ui.warn(_("interrupted!\n"))
156 ui.warn(_("interrupted!\n"))
157 except IOError, inst:
157 except IOError, inst:
158 if inst.errno == errno.EPIPE:
158 if inst.errno == errno.EPIPE:
159 if ui.debugflag:
159 if ui.debugflag:
160 ui.warn(_("\nbroken pipe\n"))
160 ui.warn(_("\nbroken pipe\n"))
161 else:
161 else:
162 raise
162 raise
163 except MemoryError:
163 except MemoryError:
164 ui.warn(_("abort: out of memory\n"))
164 ui.warn(_("abort: out of memory\n"))
165 except SystemExit, inst:
165 except SystemExit, inst:
166 # Commands shouldn't sys.exit directly, but give a return code.
166 # Commands shouldn't sys.exit directly, but give a return code.
167 # Just in case catch this and and pass exit code to caller.
167 # Just in case catch this and and pass exit code to caller.
168 return inst.code
168 return inst.code
169 except socket.error, inst:
169 except socket.error, inst:
170 ui.warn(_("abort: %s\n") % inst.args[-1])
170 ui.warn(_("abort: %s\n") % inst.args[-1])
171 except:
171 except:
172 ui.warn(_("** unknown exception encountered, details follow\n"))
172 ui.warn(_("** unknown exception encountered, details follow\n"))
173 ui.warn(_("** report bug details to "
173 ui.warn(_("** report bug details to "
174 "http://mercurial.selenic.com/bts/\n"))
174 "http://mercurial.selenic.com/bts/\n"))
175 ui.warn(_("** or mercurial@selenic.com\n"))
175 ui.warn(_("** or mercurial@selenic.com\n"))
176 ui.warn(_("** Python %s\n") % sys.version.replace('\n', ''))
176 ui.warn(_("** Python %s\n") % sys.version.replace('\n', ''))
177 ui.warn(_("** Mercurial Distributed SCM (version %s)\n")
177 ui.warn(_("** Mercurial Distributed SCM (version %s)\n")
178 % util.version())
178 % util.version())
179 ui.warn(_("** Extensions loaded: %s\n")
179 ui.warn(_("** Extensions loaded: %s\n")
180 % ", ".join([x[0] for x in extensions.extensions()]))
180 % ", ".join([x[0] for x in extensions.extensions()]))
181 raise
181 raise
182
182
183 return -1
183 return -1
184
184
185 def aliasargs(fn):
185 def aliasargs(fn):
186 if hasattr(fn, 'args'):
186 if hasattr(fn, 'args'):
187 return fn.args
187 return fn.args
188 return []
188 return []
189
189
190 class cmdalias(object):
190 class cmdalias(object):
191 def __init__(self, name, definition, cmdtable):
191 def __init__(self, name, definition, cmdtable):
192 self.name = name
192 self.name = name
193 self.definition = definition
193 self.definition = definition
194 self.args = []
194 self.args = []
195 self.opts = []
195 self.opts = []
196 self.help = ''
196 self.help = ''
197 self.norepo = True
197 self.norepo = True
198 self.badalias = False
198 self.badalias = False
199
199
200 try:
200 try:
201 cmdutil.findcmd(self.name, cmdtable, True)
201 cmdutil.findcmd(self.name, cmdtable, True)
202 self.shadows = True
202 self.shadows = True
203 except error.UnknownCommand:
203 except error.UnknownCommand:
204 self.shadows = False
204 self.shadows = False
205
205
206 if not self.definition:
206 if not self.definition:
207 def fn(ui, *args):
207 def fn(ui, *args):
208 ui.warn(_("no definition for alias '%s'\n") % self.name)
208 ui.warn(_("no definition for alias '%s'\n") % self.name)
209 return 1
209 return 1
210 self.fn = fn
210 self.fn = fn
211 self.badalias = True
211 self.badalias = True
212
212
213 return
213 return
214
214
215 if self.definition.startswith('!'):
215 if self.definition.startswith('!'):
216 def fn(ui, *args):
216 def fn(ui, *args):
217 cmd = '%s %s' % (self.definition[1:], ' '.join(args))
217 cmd = '%s %s' % (self.definition[1:], ' '.join(args))
218 return util.system(cmd)
218 return util.system(cmd)
219 self.fn = fn
219 self.fn = fn
220 return
220 return
221
221
222 args = shlex.split(self.definition)
222 args = shlex.split(self.definition)
223 cmd = args.pop(0)
223 cmd = args.pop(0)
224 args = map(util.expandpath, args)
224 args = map(util.expandpath, args)
225
225
226 for invalidarg in ("--cwd", "-R", "--repository", "--repo"):
226 for invalidarg in ("--cwd", "-R", "--repository", "--repo"):
227 if _earlygetopt([invalidarg], args):
227 if _earlygetopt([invalidarg], args):
228 def fn(ui, *args):
228 def fn(ui, *args):
229 ui.warn(_("error in definition for alias '%s': %s may only "
229 ui.warn(_("error in definition for alias '%s': %s may only "
230 "be given on the command line\n")
230 "be given on the command line\n")
231 % (self.name, invalidarg))
231 % (self.name, invalidarg))
232 return 1
232 return 1
233
233
234 self.fn = fn
234 self.fn = fn
235 self.badalias = True
235 self.badalias = True
236 return
236 return
237
237
238 try:
238 try:
239 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
239 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
240 if len(tableentry) > 2:
240 if len(tableentry) > 2:
241 self.fn, self.opts, self.help = tableentry
241 self.fn, self.opts, self.help = tableentry
242 else:
242 else:
243 self.fn, self.opts = tableentry
243 self.fn, self.opts = tableentry
244
244
245 self.args = aliasargs(self.fn) + args
245 self.args = aliasargs(self.fn) + args
246 if cmd not in commands.norepo.split(' '):
246 if cmd not in commands.norepo.split(' '):
247 self.norepo = False
247 self.norepo = False
248 if self.help.startswith("hg " + cmd):
248 if self.help.startswith("hg " + cmd):
249 # drop prefix in old-style help lines so hg shows the alias
249 # drop prefix in old-style help lines so hg shows the alias
250 self.help = self.help[4 + len(cmd):]
250 self.help = self.help[4 + len(cmd):]
251 self.__doc__ = self.fn.__doc__
251 self.__doc__ = self.fn.__doc__
252
252
253 except error.UnknownCommand:
253 except error.UnknownCommand:
254 def fn(ui, *args):
254 def fn(ui, *args):
255 ui.warn(_("alias '%s' resolves to unknown command '%s'\n") \
255 ui.warn(_("alias '%s' resolves to unknown command '%s'\n") \
256 % (self.name, cmd))
256 % (self.name, cmd))
257 try:
257 try:
258 # check if the command is in a disabled extension
258 # check if the command is in a disabled extension
259 commands.help_(ui, cmd, unknowncmd=True)
259 commands.help_(ui, cmd, unknowncmd=True)
260 except error.UnknownCommand:
260 except error.UnknownCommand:
261 pass
261 pass
262 return 1
262 return 1
263 self.fn = fn
263 self.fn = fn
264 self.badalias = True
264 self.badalias = True
265 except error.AmbiguousCommand:
265 except error.AmbiguousCommand:
266 def fn(ui, *args):
266 def fn(ui, *args):
267 ui.warn(_("alias '%s' resolves to ambiguous command '%s'\n") \
267 ui.warn(_("alias '%s' resolves to ambiguous command '%s'\n") \
268 % (self.name, cmd))
268 % (self.name, cmd))
269 return 1
269 return 1
270 self.fn = fn
270 self.fn = fn
271 self.badalias = True
271 self.badalias = True
272
272
273 def __call__(self, ui, *args, **opts):
273 def __call__(self, ui, *args, **opts):
274 if self.shadows:
274 if self.shadows:
275 ui.debug("alias '%s' shadows command\n" % self.name)
275 ui.debug("alias '%s' shadows command\n" % self.name)
276
276
277 return util.checksignature(self.fn)(ui, *args, **opts)
277 return util.checksignature(self.fn)(ui, *args, **opts)
278
278
279 def addaliases(ui, cmdtable):
279 def addaliases(ui, cmdtable):
280 # aliases are processed after extensions have been loaded, so they
280 # aliases are processed after extensions have been loaded, so they
281 # may use extension commands. Aliases can also use other alias definitions,
281 # may use extension commands. Aliases can also use other alias definitions,
282 # but only if they have been defined prior to the current definition.
282 # but only if they have been defined prior to the current definition.
283 for alias, definition in ui.configitems('alias'):
283 for alias, definition in ui.configitems('alias'):
284 aliasdef = cmdalias(alias, definition, cmdtable)
284 aliasdef = cmdalias(alias, definition, cmdtable)
285 cmdtable[alias] = (aliasdef, aliasdef.opts, aliasdef.help)
285 cmdtable[alias] = (aliasdef, aliasdef.opts, aliasdef.help)
286 if aliasdef.norepo:
286 if aliasdef.norepo:
287 commands.norepo += ' %s' % alias
287 commands.norepo += ' %s' % alias
288
288
289 def _parse(ui, args):
289 def _parse(ui, args):
290 options = {}
290 options = {}
291 cmdoptions = {}
291 cmdoptions = {}
292
292
293 try:
293 try:
294 args = fancyopts.fancyopts(args, commands.globalopts, options)
294 args = fancyopts.fancyopts(args, commands.globalopts, options)
295 except fancyopts.getopt.GetoptError, inst:
295 except fancyopts.getopt.GetoptError, inst:
296 raise error.CommandError(None, inst)
296 raise error.CommandError(None, inst)
297
297
298 if args:
298 if args:
299 cmd, args = args[0], args[1:]
299 cmd, args = args[0], args[1:]
300 aliases, entry = cmdutil.findcmd(cmd, commands.table,
300 aliases, entry = cmdutil.findcmd(cmd, commands.table,
301 ui.config("ui", "strict"))
301 ui.config("ui", "strict"))
302 cmd = aliases[0]
302 cmd = aliases[0]
303 args = aliasargs(entry[0]) + args
303 args = aliasargs(entry[0]) + args
304 defaults = ui.config("defaults", cmd)
304 defaults = ui.config("defaults", cmd)
305 if defaults:
305 if defaults:
306 args = map(util.expandpath, shlex.split(defaults)) + args
306 args = map(util.expandpath, shlex.split(defaults)) + args
307 c = list(entry[1])
307 c = list(entry[1])
308 else:
308 else:
309 cmd = None
309 cmd = None
310 c = []
310 c = []
311
311
312 # combine global options into local
312 # combine global options into local
313 for o in commands.globalopts:
313 for o in commands.globalopts:
314 c.append((o[0], o[1], options[o[1]], o[3]))
314 c.append((o[0], o[1], options[o[1]], o[3]))
315
315
316 try:
316 try:
317 args = fancyopts.fancyopts(args, c, cmdoptions, True)
317 args = fancyopts.fancyopts(args, c, cmdoptions, True)
318 except fancyopts.getopt.GetoptError, inst:
318 except fancyopts.getopt.GetoptError, inst:
319 raise error.CommandError(cmd, inst)
319 raise error.CommandError(cmd, inst)
320
320
321 # separate global options back out
321 # separate global options back out
322 for o in commands.globalopts:
322 for o in commands.globalopts:
323 n = o[1]
323 n = o[1]
324 options[n] = cmdoptions[n]
324 options[n] = cmdoptions[n]
325 del cmdoptions[n]
325 del cmdoptions[n]
326
326
327 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
327 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
328
328
329 def _parseconfig(ui, config):
329 def _parseconfig(ui, config):
330 """parse the --config options from the command line"""
330 """parse the --config options from the command line"""
331 for cfg in config:
331 for cfg in config:
332 try:
332 try:
333 name, value = cfg.split('=', 1)
333 name, value = cfg.split('=', 1)
334 section, name = name.split('.', 1)
334 section, name = name.split('.', 1)
335 if not section or not name:
335 if not section or not name:
336 raise IndexError
336 raise IndexError
337 ui.setconfig(section, name, value)
337 ui.setconfig(section, name, value)
338 except (IndexError, ValueError):
338 except (IndexError, ValueError):
339 raise util.Abort(_('malformed --config option: %r '
339 raise util.Abort(_('malformed --config option: %r '
340 '(use --config section.name=value)') % cfg)
340 '(use --config section.name=value)') % cfg)
341
341
342 def _earlygetopt(aliases, args):
342 def _earlygetopt(aliases, args):
343 """Return list of values for an option (or aliases).
343 """Return list of values for an option (or aliases).
344
344
345 The values are listed in the order they appear in args.
345 The values are listed in the order they appear in args.
346 The options and values are removed from args.
346 The options and values are removed from args.
347 """
347 """
348 try:
348 try:
349 argcount = args.index("--")
349 argcount = args.index("--")
350 except ValueError:
350 except ValueError:
351 argcount = len(args)
351 argcount = len(args)
352 shortopts = [opt for opt in aliases if len(opt) == 2]
352 shortopts = [opt for opt in aliases if len(opt) == 2]
353 values = []
353 values = []
354 pos = 0
354 pos = 0
355 while pos < argcount:
355 while pos < argcount:
356 if args[pos] in aliases:
356 if args[pos] in aliases:
357 if pos + 1 >= argcount:
357 if pos + 1 >= argcount:
358 # ignore and let getopt report an error if there is no value
358 # ignore and let getopt report an error if there is no value
359 break
359 break
360 del args[pos]
360 del args[pos]
361 values.append(args.pop(pos))
361 values.append(args.pop(pos))
362 argcount -= 2
362 argcount -= 2
363 elif args[pos][:2] in shortopts:
363 elif args[pos][:2] in shortopts:
364 # short option can have no following space, e.g. hg log -Rfoo
364 # short option can have no following space, e.g. hg log -Rfoo
365 values.append(args.pop(pos)[2:])
365 values.append(args.pop(pos)[2:])
366 argcount -= 1
366 argcount -= 1
367 else:
367 else:
368 pos += 1
368 pos += 1
369 return values
369 return values
370
370
371 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
371 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
372 # run pre-hook, and abort if it fails
372 # run pre-hook, and abort if it fails
373 ret = hook.hook(lui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs),
373 ret = hook.hook(lui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs),
374 pats=cmdpats, opts=cmdoptions)
374 pats=cmdpats, opts=cmdoptions)
375 if ret:
375 if ret:
376 return ret
376 return ret
377 ret = _runcommand(ui, options, cmd, d)
377 ret = _runcommand(ui, options, cmd, d)
378 # run post-hook, passing command result
378 # run post-hook, passing command result
379 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
379 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
380 result=ret, pats=cmdpats, opts=cmdoptions)
380 result=ret, pats=cmdpats, opts=cmdoptions)
381 return ret
381 return ret
382
382
383 _loaded = set()
383 _loaded = set()
384 def _dispatch(ui, args):
384 def _dispatch(ui, args):
385 # read --config before doing anything else
385 # read --config before doing anything else
386 # (e.g. to change trust settings for reading .hg/hgrc)
386 # (e.g. to change trust settings for reading .hg/hgrc)
387 _parseconfig(ui, _earlygetopt(['--config'], args))
387 _parseconfig(ui, _earlygetopt(['--config'], args))
388
388
389 # check for cwd
389 # check for cwd
390 cwd = _earlygetopt(['--cwd'], args)
390 cwd = _earlygetopt(['--cwd'], args)
391 if cwd:
391 if cwd:
392 os.chdir(cwd[-1])
392 os.chdir(cwd[-1])
393
393
394 # read the local repository .hgrc into a local ui object
394 # read the local repository .hgrc into a local ui object
395 try:
395 try:
396 wd = os.getcwd()
396 wd = os.getcwd()
397 except OSError, e:
397 except OSError, e:
398 raise util.Abort(_("error getting current working directory: %s") %
398 raise util.Abort(_("error getting current working directory: %s") %
399 e.strerror)
399 e.strerror)
400 path = cmdutil.findrepo(wd) or ""
400 path = cmdutil.findrepo(wd) or ""
401 if not path:
401 if not path:
402 lui = ui
402 lui = ui
403 else:
403 else:
404 try:
404 try:
405 lui = ui.copy()
405 lui = ui.copy()
406 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
406 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
407 except IOError:
407 except IOError:
408 pass
408 pass
409
409
410 # now we can expand paths, even ones in .hg/hgrc
410 # now we can expand paths, even ones in .hg/hgrc
411 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
411 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
412 if rpath:
412 if rpath:
413 path = lui.expandpath(rpath[-1])
413 path = lui.expandpath(rpath[-1])
414 lui = ui.copy()
414 lui = ui.copy()
415 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
415 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
416
416
417 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
417 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
418 # reposetup. Programs like TortoiseHg will call _dispatch several
418 # reposetup. Programs like TortoiseHg will call _dispatch several
419 # times so we keep track of configured extensions in _loaded.
419 # times so we keep track of configured extensions in _loaded.
420 extensions.loadall(lui)
420 extensions.loadall(lui)
421 exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
421 exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
422 # Propagate any changes to lui.__class__ by extensions
422 # Propagate any changes to lui.__class__ by extensions
423 ui.__class__ = lui.__class__
423 ui.__class__ = lui.__class__
424
424
425 # (uisetup and extsetup are handled in extensions.loadall)
425 # (uisetup and extsetup are handled in extensions.loadall)
426
426
427 for name, module in exts:
427 for name, module in exts:
428 cmdtable = getattr(module, 'cmdtable', {})
428 cmdtable = getattr(module, 'cmdtable', {})
429 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
429 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
430 if overrides:
430 if overrides:
431 ui.warn(_("extension '%s' overrides commands: %s\n")
431 ui.warn(_("extension '%s' overrides commands: %s\n")
432 % (name, " ".join(overrides)))
432 % (name, " ".join(overrides)))
433 commands.table.update(cmdtable)
433 commands.table.update(cmdtable)
434 _loaded.add(name)
434 _loaded.add(name)
435
435
436 # (reposetup is handled in hg.repository)
436 # (reposetup is handled in hg.repository)
437
437
438 addaliases(lui, commands.table)
438 addaliases(lui, commands.table)
439
439
440 # check for fallback encoding
440 # check for fallback encoding
441 fallback = lui.config('ui', 'fallbackencoding')
441 fallback = lui.config('ui', 'fallbackencoding')
442 if fallback:
442 if fallback:
443 encoding.fallbackencoding = fallback
443 encoding.fallbackencoding = fallback
444
444
445 fullargs = args
445 fullargs = args
446 cmd, func, args, options, cmdoptions = _parse(lui, args)
446 cmd, func, args, options, cmdoptions = _parse(lui, args)
447
447
448 if options["config"]:
448 if options["config"]:
449 raise util.Abort(_("Option --config may not be abbreviated!"))
449 raise util.Abort(_("Option --config may not be abbreviated!"))
450 if options["cwd"]:
450 if options["cwd"]:
451 raise util.Abort(_("Option --cwd may not be abbreviated!"))
451 raise util.Abort(_("Option --cwd may not be abbreviated!"))
452 if options["repository"]:
452 if options["repository"]:
453 raise util.Abort(_(
453 raise util.Abort(_(
454 "Option -R has to be separated from other options (e.g. not -qR) "
454 "Option -R has to be separated from other options (e.g. not -qR) "
455 "and --repository may only be abbreviated as --repo!"))
455 "and --repository may only be abbreviated as --repo!"))
456
456
457 if options["encoding"]:
457 if options["encoding"]:
458 encoding.encoding = options["encoding"]
458 encoding.encoding = options["encoding"]
459 if options["encodingmode"]:
459 if options["encodingmode"]:
460 encoding.encodingmode = options["encodingmode"]
460 encoding.encodingmode = options["encodingmode"]
461 if options["time"]:
461 if options["time"]:
462 def get_times():
462 def get_times():
463 t = os.times()
463 t = os.times()
464 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
464 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
465 t = (t[0], t[1], t[2], t[3], time.clock())
465 t = (t[0], t[1], t[2], t[3], time.clock())
466 return t
466 return t
467 s = get_times()
467 s = get_times()
468 def print_time():
468 def print_time():
469 t = get_times()
469 t = get_times()
470 ui.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
470 ui.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
471 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
471 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
472 atexit.register(print_time)
472 atexit.register(print_time)
473
473
474 if options['verbose'] or options['debug'] or options['quiet']:
474 if options['verbose'] or options['debug'] or options['quiet']:
475 ui.setconfig('ui', 'verbose', str(bool(options['verbose'])))
475 ui.setconfig('ui', 'verbose', str(bool(options['verbose'])))
476 ui.setconfig('ui', 'debug', str(bool(options['debug'])))
476 ui.setconfig('ui', 'debug', str(bool(options['debug'])))
477 ui.setconfig('ui', 'quiet', str(bool(options['quiet'])))
477 ui.setconfig('ui', 'quiet', str(bool(options['quiet'])))
478 if options['traceback']:
478 if options['traceback']:
479 ui.setconfig('ui', 'traceback', 'on')
479 ui.setconfig('ui', 'traceback', 'on')
480 if options['noninteractive']:
480 if options['noninteractive']:
481 ui.setconfig('ui', 'interactive', 'off')
481 ui.setconfig('ui', 'interactive', 'off')
482
482
483 if options['help']:
483 if options['help']:
484 return commands.help_(ui, cmd, options['version'])
484 return commands.help_(ui, cmd, options['version'])
485 elif options['version']:
485 elif options['version']:
486 return commands.version_(ui)
486 return commands.version_(ui)
487 elif not cmd:
487 elif not cmd:
488 return commands.help_(ui, 'shortlist')
488 return commands.help_(ui, 'shortlist')
489
489
490 repo = None
490 repo = None
491 cmdpats = args[:]
491 cmdpats = args[:]
492 if cmd not in commands.norepo.split():
492 if cmd not in commands.norepo.split():
493 try:
493 try:
494 repo = hg.repository(ui, path=path)
494 repo = hg.repository(ui, path=path)
495 ui = repo.ui
495 ui = repo.ui
496 if not repo.local():
496 if not repo.local():
497 raise util.Abort(_("repository '%s' is not local") % path)
497 raise util.Abort(_("repository '%s' is not local") % path)
498 ui.setconfig("bundle", "mainreporoot", repo.root)
498 ui.setconfig("bundle", "mainreporoot", repo.root)
499 except error.RepoError:
499 except error.RepoError:
500 if cmd not in commands.optionalrepo.split():
500 if cmd not in commands.optionalrepo.split():
501 if args and not path: # try to infer -R from command args
501 if args and not path: # try to infer -R from command args
502 repos = map(cmdutil.findrepo, args)
502 repos = map(cmdutil.findrepo, args)
503 guess = repos[0]
503 guess = repos[0]
504 if guess and repos.count(guess) == len(repos):
504 if guess and repos.count(guess) == len(repos):
505 return _dispatch(ui, ['--repository', guess] + fullargs)
505 return _dispatch(ui, ['--repository', guess] + fullargs)
506 if not path:
506 if not path:
507 raise error.RepoError(_("There is no Mercurial repository"
507 raise error.RepoError(_("There is no Mercurial repository"
508 " here (.hg not found)"))
508 " here (.hg not found)"))
509 raise
509 raise
510 args.insert(0, repo)
510 args.insert(0, repo)
511 elif rpath:
511 elif rpath:
512 ui.warn(_("warning: --repository ignored\n"))
512 ui.warn(_("warning: --repository ignored\n"))
513
513
514 msg = ' '.join(' ' in a and repr(a) or a for a in fullargs)
515 ui.log("command", msg + "\n")
514 d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
516 d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
515 return runcommand(lui, repo, cmd, fullargs, ui, options, d,
517 return runcommand(lui, repo, cmd, fullargs, ui, options, d,
516 cmdpats, cmdoptions)
518 cmdpats, cmdoptions)
517
519
518 def _runcommand(ui, options, cmd, cmdfunc):
520 def _runcommand(ui, options, cmd, cmdfunc):
519 def checkargs():
521 def checkargs():
520 try:
522 try:
521 return cmdfunc()
523 return cmdfunc()
522 except error.SignatureError:
524 except error.SignatureError:
523 raise error.CommandError(cmd, _("invalid arguments"))
525 raise error.CommandError(cmd, _("invalid arguments"))
524
526
525 if options['profile']:
527 if options['profile']:
526 format = ui.config('profiling', 'format', default='text')
528 format = ui.config('profiling', 'format', default='text')
527
529
528 if not format in ['text', 'kcachegrind']:
530 if not format in ['text', 'kcachegrind']:
529 ui.warn(_("unrecognized profiling format '%s'"
531 ui.warn(_("unrecognized profiling format '%s'"
530 " - Ignored\n") % format)
532 " - Ignored\n") % format)
531 format = 'text'
533 format = 'text'
532
534
533 output = ui.config('profiling', 'output')
535 output = ui.config('profiling', 'output')
534
536
535 if output:
537 if output:
536 path = ui.expandpath(output)
538 path = ui.expandpath(output)
537 ostream = open(path, 'wb')
539 ostream = open(path, 'wb')
538 else:
540 else:
539 ostream = sys.stderr
541 ostream = sys.stderr
540
542
541 try:
543 try:
542 from mercurial import lsprof
544 from mercurial import lsprof
543 except ImportError:
545 except ImportError:
544 raise util.Abort(_(
546 raise util.Abort(_(
545 'lsprof not available - install from '
547 'lsprof not available - install from '
546 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
548 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
547 p = lsprof.Profiler()
549 p = lsprof.Profiler()
548 p.enable(subcalls=True)
550 p.enable(subcalls=True)
549 try:
551 try:
550 return checkargs()
552 return checkargs()
551 finally:
553 finally:
552 p.disable()
554 p.disable()
553
555
554 if format == 'kcachegrind':
556 if format == 'kcachegrind':
555 import lsprofcalltree
557 import lsprofcalltree
556 calltree = lsprofcalltree.KCacheGrind(p)
558 calltree = lsprofcalltree.KCacheGrind(p)
557 calltree.output(ostream)
559 calltree.output(ostream)
558 else:
560 else:
559 # format == 'text'
561 # format == 'text'
560 stats = lsprof.Stats(p.getstats())
562 stats = lsprof.Stats(p.getstats())
561 stats.sort()
563 stats.sort()
562 stats.pprint(top=10, file=ostream, climit=5)
564 stats.pprint(top=10, file=ostream, climit=5)
563
565
564 if output:
566 if output:
565 ostream.close()
567 ostream.close()
566 else:
568 else:
567 return checkargs()
569 return checkargs()
General Comments 0
You need to be logged in to leave comments. Login now