##// END OF EJS Templates
alias: back up and restore commands.norepo before checking for shell aliases
Steve Losh -
r12633:301d7626 default
parent child Browse files
Show More
@@ -1,638 +1,641
1 # dispatch.py - command dispatching for mercurial
1 # dispatch.py - command dispatching for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from i18n import _
8 from i18n import _
9 import os, sys, atexit, signal, pdb, socket, errno, shlex, time, traceback, re
9 import os, sys, atexit, signal, pdb, socket, errno, shlex, time, traceback, re
10 import util, commands, hg, fancyopts, extensions, hook, error
10 import util, commands, hg, fancyopts, extensions, hook, error
11 import cmdutil, encoding
11 import cmdutil, encoding
12 import ui as uimod
12 import ui as uimod
13
13
14 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 = self.cmd = name
192 self.name = self.cmd = name
193 self.cmdname = ''
193 self.cmdname = ''
194 self.definition = definition
194 self.definition = definition
195 self.args = []
195 self.args = []
196 self.opts = []
196 self.opts = []
197 self.help = ''
197 self.help = ''
198 self.norepo = True
198 self.norepo = True
199 self.badalias = False
199 self.badalias = False
200
200
201 try:
201 try:
202 aliases, entry = cmdutil.findcmd(self.name, cmdtable)
202 aliases, entry = cmdutil.findcmd(self.name, cmdtable)
203 for alias, e in cmdtable.iteritems():
203 for alias, e in cmdtable.iteritems():
204 if e is entry:
204 if e is entry:
205 self.cmd = alias
205 self.cmd = alias
206 break
206 break
207 self.shadows = True
207 self.shadows = True
208 except error.UnknownCommand:
208 except error.UnknownCommand:
209 self.shadows = False
209 self.shadows = False
210
210
211 if not self.definition:
211 if not self.definition:
212 def fn(ui, *args):
212 def fn(ui, *args):
213 ui.warn(_("no definition for alias '%s'\n") % self.name)
213 ui.warn(_("no definition for alias '%s'\n") % self.name)
214 return 1
214 return 1
215 self.fn = fn
215 self.fn = fn
216 self.badalias = True
216 self.badalias = True
217
217
218 return
218 return
219
219
220 if self.definition.startswith('!'):
220 if self.definition.startswith('!'):
221 self.shell = True
221 self.shell = True
222 def fn(ui, *args):
222 def fn(ui, *args):
223 env = {'HG_ARGS': ' '.join((self.name,) + args)}
223 env = {'HG_ARGS': ' '.join((self.name,) + args)}
224 def _checkvar(m):
224 def _checkvar(m):
225 if int(m.groups()[0]) <= len(args):
225 if int(m.groups()[0]) <= len(args):
226 return m.group()
226 return m.group()
227 else:
227 else:
228 return ''
228 return ''
229 cmd = re.sub(r'\$(\d+)', _checkvar, self.definition[1:])
229 cmd = re.sub(r'\$(\d+)', _checkvar, self.definition[1:])
230 replace = dict((str(i + 1), arg) for i, arg in enumerate(args))
230 replace = dict((str(i + 1), arg) for i, arg in enumerate(args))
231 replace['0'] = self.name
231 replace['0'] = self.name
232 replace['@'] = ' '.join(args)
232 replace['@'] = ' '.join(args)
233 cmd = util.interpolate(r'\$', replace, cmd)
233 cmd = util.interpolate(r'\$', replace, cmd)
234 return util.system(cmd, environ=env)
234 return util.system(cmd, environ=env)
235 self.fn = fn
235 self.fn = fn
236 return
236 return
237
237
238 args = shlex.split(self.definition)
238 args = shlex.split(self.definition)
239 self.cmdname = cmd = args.pop(0)
239 self.cmdname = cmd = args.pop(0)
240 args = map(util.expandpath, args)
240 args = map(util.expandpath, args)
241
241
242 for invalidarg in ("--cwd", "-R", "--repository", "--repo"):
242 for invalidarg in ("--cwd", "-R", "--repository", "--repo"):
243 if _earlygetopt([invalidarg], args):
243 if _earlygetopt([invalidarg], args):
244 def fn(ui, *args):
244 def fn(ui, *args):
245 ui.warn(_("error in definition for alias '%s': %s may only "
245 ui.warn(_("error in definition for alias '%s': %s may only "
246 "be given on the command line\n")
246 "be given on the command line\n")
247 % (self.name, invalidarg))
247 % (self.name, invalidarg))
248 return 1
248 return 1
249
249
250 self.fn = fn
250 self.fn = fn
251 self.badalias = True
251 self.badalias = True
252 return
252 return
253
253
254 try:
254 try:
255 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
255 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
256 if len(tableentry) > 2:
256 if len(tableentry) > 2:
257 self.fn, self.opts, self.help = tableentry
257 self.fn, self.opts, self.help = tableentry
258 else:
258 else:
259 self.fn, self.opts = tableentry
259 self.fn, self.opts = tableentry
260
260
261 self.args = aliasargs(self.fn) + args
261 self.args = aliasargs(self.fn) + args
262 if cmd not in commands.norepo.split(' '):
262 if cmd not in commands.norepo.split(' '):
263 self.norepo = False
263 self.norepo = False
264 if self.help.startswith("hg " + cmd):
264 if self.help.startswith("hg " + cmd):
265 # drop prefix in old-style help lines so hg shows the alias
265 # drop prefix in old-style help lines so hg shows the alias
266 self.help = self.help[4 + len(cmd):]
266 self.help = self.help[4 + len(cmd):]
267 self.__doc__ = self.fn.__doc__
267 self.__doc__ = self.fn.__doc__
268
268
269 except error.UnknownCommand:
269 except error.UnknownCommand:
270 def fn(ui, *args):
270 def fn(ui, *args):
271 ui.warn(_("alias '%s' resolves to unknown command '%s'\n") \
271 ui.warn(_("alias '%s' resolves to unknown command '%s'\n") \
272 % (self.name, cmd))
272 % (self.name, cmd))
273 try:
273 try:
274 # check if the command is in a disabled extension
274 # check if the command is in a disabled extension
275 commands.help_(ui, cmd, unknowncmd=True)
275 commands.help_(ui, cmd, unknowncmd=True)
276 except error.UnknownCommand:
276 except error.UnknownCommand:
277 pass
277 pass
278 return 1
278 return 1
279 self.fn = fn
279 self.fn = fn
280 self.badalias = True
280 self.badalias = True
281 except error.AmbiguousCommand:
281 except error.AmbiguousCommand:
282 def fn(ui, *args):
282 def fn(ui, *args):
283 ui.warn(_("alias '%s' resolves to ambiguous command '%s'\n") \
283 ui.warn(_("alias '%s' resolves to ambiguous command '%s'\n") \
284 % (self.name, cmd))
284 % (self.name, cmd))
285 return 1
285 return 1
286 self.fn = fn
286 self.fn = fn
287 self.badalias = True
287 self.badalias = True
288
288
289 def __call__(self, ui, *args, **opts):
289 def __call__(self, ui, *args, **opts):
290 if self.shadows:
290 if self.shadows:
291 ui.debug("alias '%s' shadows command '%s'\n" %
291 ui.debug("alias '%s' shadows command '%s'\n" %
292 (self.name, self.cmdname))
292 (self.name, self.cmdname))
293
293
294 if self.definition.startswith('!'):
294 if self.definition.startswith('!'):
295 return self.fn(ui, *args, **opts)
295 return self.fn(ui, *args, **opts)
296 else:
296 else:
297 try:
297 try:
298 util.checksignature(self.fn)(ui, *args, **opts)
298 util.checksignature(self.fn)(ui, *args, **opts)
299 except error.SignatureError:
299 except error.SignatureError:
300 args = ' '.join([self.cmdname] + self.args)
300 args = ' '.join([self.cmdname] + self.args)
301 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args))
301 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args))
302 raise
302 raise
303
303
304 def addaliases(ui, cmdtable):
304 def addaliases(ui, cmdtable):
305 # aliases are processed after extensions have been loaded, so they
305 # aliases are processed after extensions have been loaded, so they
306 # may use extension commands. Aliases can also use other alias definitions,
306 # may use extension commands. Aliases can also use other alias definitions,
307 # but only if they have been defined prior to the current definition.
307 # but only if they have been defined prior to the current definition.
308 for alias, definition in ui.configitems('alias'):
308 for alias, definition in ui.configitems('alias'):
309 aliasdef = cmdalias(alias, definition, cmdtable)
309 aliasdef = cmdalias(alias, definition, cmdtable)
310 cmdtable[aliasdef.cmd] = (aliasdef, aliasdef.opts, aliasdef.help)
310 cmdtable[aliasdef.cmd] = (aliasdef, aliasdef.opts, aliasdef.help)
311 if aliasdef.norepo:
311 if aliasdef.norepo:
312 commands.norepo += ' %s' % alias
312 commands.norepo += ' %s' % alias
313
313
314 def _parse(ui, args):
314 def _parse(ui, args):
315 options = {}
315 options = {}
316 cmdoptions = {}
316 cmdoptions = {}
317
317
318 try:
318 try:
319 args = fancyopts.fancyopts(args, commands.globalopts, options)
319 args = fancyopts.fancyopts(args, commands.globalopts, options)
320 except fancyopts.getopt.GetoptError, inst:
320 except fancyopts.getopt.GetoptError, inst:
321 raise error.CommandError(None, inst)
321 raise error.CommandError(None, inst)
322
322
323 if args:
323 if args:
324 cmd, args = args[0], args[1:]
324 cmd, args = args[0], args[1:]
325 aliases, entry = cmdutil.findcmd(cmd, commands.table,
325 aliases, entry = cmdutil.findcmd(cmd, commands.table,
326 ui.config("ui", "strict"))
326 ui.config("ui", "strict"))
327 cmd = aliases[0]
327 cmd = aliases[0]
328 args = aliasargs(entry[0]) + args
328 args = aliasargs(entry[0]) + args
329 defaults = ui.config("defaults", cmd)
329 defaults = ui.config("defaults", cmd)
330 if defaults:
330 if defaults:
331 args = map(util.expandpath, shlex.split(defaults)) + args
331 args = map(util.expandpath, shlex.split(defaults)) + args
332 c = list(entry[1])
332 c = list(entry[1])
333 else:
333 else:
334 cmd = None
334 cmd = None
335 c = []
335 c = []
336
336
337 # combine global options into local
337 # combine global options into local
338 for o in commands.globalopts:
338 for o in commands.globalopts:
339 c.append((o[0], o[1], options[o[1]], o[3]))
339 c.append((o[0], o[1], options[o[1]], o[3]))
340
340
341 try:
341 try:
342 args = fancyopts.fancyopts(args, c, cmdoptions, True)
342 args = fancyopts.fancyopts(args, c, cmdoptions, True)
343 except fancyopts.getopt.GetoptError, inst:
343 except fancyopts.getopt.GetoptError, inst:
344 raise error.CommandError(cmd, inst)
344 raise error.CommandError(cmd, inst)
345
345
346 # separate global options back out
346 # separate global options back out
347 for o in commands.globalopts:
347 for o in commands.globalopts:
348 n = o[1]
348 n = o[1]
349 options[n] = cmdoptions[n]
349 options[n] = cmdoptions[n]
350 del cmdoptions[n]
350 del cmdoptions[n]
351
351
352 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
352 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
353
353
354 def _parseconfig(ui, config):
354 def _parseconfig(ui, config):
355 """parse the --config options from the command line"""
355 """parse the --config options from the command line"""
356 for cfg in config:
356 for cfg in config:
357 try:
357 try:
358 name, value = cfg.split('=', 1)
358 name, value = cfg.split('=', 1)
359 section, name = name.split('.', 1)
359 section, name = name.split('.', 1)
360 if not section or not name:
360 if not section or not name:
361 raise IndexError
361 raise IndexError
362 ui.setconfig(section, name, value)
362 ui.setconfig(section, name, value)
363 except (IndexError, ValueError):
363 except (IndexError, ValueError):
364 raise util.Abort(_('malformed --config option: %r '
364 raise util.Abort(_('malformed --config option: %r '
365 '(use --config section.name=value)') % cfg)
365 '(use --config section.name=value)') % cfg)
366
366
367 def _earlygetopt(aliases, args):
367 def _earlygetopt(aliases, args):
368 """Return list of values for an option (or aliases).
368 """Return list of values for an option (or aliases).
369
369
370 The values are listed in the order they appear in args.
370 The values are listed in the order they appear in args.
371 The options and values are removed from args.
371 The options and values are removed from args.
372 """
372 """
373 try:
373 try:
374 argcount = args.index("--")
374 argcount = args.index("--")
375 except ValueError:
375 except ValueError:
376 argcount = len(args)
376 argcount = len(args)
377 shortopts = [opt for opt in aliases if len(opt) == 2]
377 shortopts = [opt for opt in aliases if len(opt) == 2]
378 values = []
378 values = []
379 pos = 0
379 pos = 0
380 while pos < argcount:
380 while pos < argcount:
381 if args[pos] in aliases:
381 if args[pos] in aliases:
382 if pos + 1 >= argcount:
382 if pos + 1 >= argcount:
383 # ignore and let getopt report an error if there is no value
383 # ignore and let getopt report an error if there is no value
384 break
384 break
385 del args[pos]
385 del args[pos]
386 values.append(args.pop(pos))
386 values.append(args.pop(pos))
387 argcount -= 2
387 argcount -= 2
388 elif args[pos][:2] in shortopts:
388 elif args[pos][:2] in shortopts:
389 # short option can have no following space, e.g. hg log -Rfoo
389 # short option can have no following space, e.g. hg log -Rfoo
390 values.append(args.pop(pos)[2:])
390 values.append(args.pop(pos)[2:])
391 argcount -= 1
391 argcount -= 1
392 else:
392 else:
393 pos += 1
393 pos += 1
394 return values
394 return values
395
395
396 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
396 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
397 # run pre-hook, and abort if it fails
397 # run pre-hook, and abort if it fails
398 ret = hook.hook(lui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs),
398 ret = hook.hook(lui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs),
399 pats=cmdpats, opts=cmdoptions)
399 pats=cmdpats, opts=cmdoptions)
400 if ret:
400 if ret:
401 return ret
401 return ret
402 ret = _runcommand(ui, options, cmd, d)
402 ret = _runcommand(ui, options, cmd, d)
403 # run post-hook, passing command result
403 # run post-hook, passing command result
404 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
404 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
405 result=ret, pats=cmdpats, opts=cmdoptions)
405 result=ret, pats=cmdpats, opts=cmdoptions)
406 return ret
406 return ret
407
407
408 def _getlocal(ui, rpath):
408 def _getlocal(ui, rpath):
409 """Return (path, local ui object) for the given target path.
409 """Return (path, local ui object) for the given target path.
410
410
411 Takes paths in [cwd]/.hg/hgrc into account."
411 Takes paths in [cwd]/.hg/hgrc into account."
412 """
412 """
413 try:
413 try:
414 wd = os.getcwd()
414 wd = os.getcwd()
415 except OSError, e:
415 except OSError, e:
416 raise util.Abort(_("error getting current working directory: %s") %
416 raise util.Abort(_("error getting current working directory: %s") %
417 e.strerror)
417 e.strerror)
418 path = cmdutil.findrepo(wd) or ""
418 path = cmdutil.findrepo(wd) or ""
419 if not path:
419 if not path:
420 lui = ui
420 lui = ui
421 else:
421 else:
422 try:
422 try:
423 lui = ui.copy()
423 lui = ui.copy()
424 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
424 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
425 except IOError:
425 except IOError:
426 pass
426 pass
427
427
428 if rpath:
428 if rpath:
429 path = lui.expandpath(rpath[-1])
429 path = lui.expandpath(rpath[-1])
430 lui = ui.copy()
430 lui = ui.copy()
431 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
431 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
432
432
433 return path, lui
433 return path, lui
434
434
435 def _checkshellalias(ui, args):
435 def _checkshellalias(ui, args):
436 cwd = os.getcwd()
436 cwd = os.getcwd()
437 norepo = commands.norepo
437 options = {}
438 options = {}
438 args = fancyopts.fancyopts(args, commands.globalopts, options)
439 args = fancyopts.fancyopts(args, commands.globalopts, options)
439
440
440 if not args:
441 if not args:
441 return
442 return
442
443
443 _parseconfig(ui, options['config'])
444 _parseconfig(ui, options['config'])
444 if options['cwd']:
445 if options['cwd']:
445 os.chdir(options['cwd'])
446 os.chdir(options['cwd'])
446
447
447 path, lui = _getlocal(ui, [options['repository']])
448 path, lui = _getlocal(ui, [options['repository']])
448
449
449 cmdtable = commands.table.copy()
450 cmdtable = commands.table.copy()
450 addaliases(lui, cmdtable)
451 addaliases(lui, cmdtable)
451
452
452 cmd = args[0]
453 cmd = args[0]
453 try:
454 try:
454 aliases, entry = cmdutil.findcmd(cmd, cmdtable, lui.config("ui", "strict"))
455 aliases, entry = cmdutil.findcmd(cmd, cmdtable, lui.config("ui", "strict"))
455 except error.UnknownCommand:
456 except error.UnknownCommand:
457 commands.norepo = norepo
456 os.chdir(cwd)
458 os.chdir(cwd)
457 return
459 return
458
460
459 cmd = aliases[0]
461 cmd = aliases[0]
460 fn = entry[0]
462 fn = entry[0]
461
463
462 if cmd and hasattr(fn, 'shell'):
464 if cmd and hasattr(fn, 'shell'):
463 d = lambda: fn(ui, *args[1:])
465 d = lambda: fn(ui, *args[1:])
464 return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d, [], {})
466 return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d, [], {})
465
467
468 commands.norepo = norepo
466 os.chdir(cwd)
469 os.chdir(cwd)
467
470
468 _loaded = set()
471 _loaded = set()
469 def _dispatch(ui, args):
472 def _dispatch(ui, args):
470 shellaliasfn = _checkshellalias(ui, args)
473 shellaliasfn = _checkshellalias(ui, args)
471 if shellaliasfn:
474 if shellaliasfn:
472 return shellaliasfn()
475 return shellaliasfn()
473
476
474 # read --config before doing anything else
477 # read --config before doing anything else
475 # (e.g. to change trust settings for reading .hg/hgrc)
478 # (e.g. to change trust settings for reading .hg/hgrc)
476 _parseconfig(ui, _earlygetopt(['--config'], args))
479 _parseconfig(ui, _earlygetopt(['--config'], args))
477
480
478 # check for cwd
481 # check for cwd
479 cwd = _earlygetopt(['--cwd'], args)
482 cwd = _earlygetopt(['--cwd'], args)
480 if cwd:
483 if cwd:
481 os.chdir(cwd[-1])
484 os.chdir(cwd[-1])
482
485
483 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
486 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
484 path, lui = _getlocal(ui, rpath)
487 path, lui = _getlocal(ui, rpath)
485
488
486 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
489 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
487 # reposetup. Programs like TortoiseHg will call _dispatch several
490 # reposetup. Programs like TortoiseHg will call _dispatch several
488 # times so we keep track of configured extensions in _loaded.
491 # times so we keep track of configured extensions in _loaded.
489 extensions.loadall(lui)
492 extensions.loadall(lui)
490 exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
493 exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
491 # Propagate any changes to lui.__class__ by extensions
494 # Propagate any changes to lui.__class__ by extensions
492 ui.__class__ = lui.__class__
495 ui.__class__ = lui.__class__
493
496
494 # (uisetup and extsetup are handled in extensions.loadall)
497 # (uisetup and extsetup are handled in extensions.loadall)
495
498
496 for name, module in exts:
499 for name, module in exts:
497 cmdtable = getattr(module, 'cmdtable', {})
500 cmdtable = getattr(module, 'cmdtable', {})
498 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
501 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
499 if overrides:
502 if overrides:
500 ui.warn(_("extension '%s' overrides commands: %s\n")
503 ui.warn(_("extension '%s' overrides commands: %s\n")
501 % (name, " ".join(overrides)))
504 % (name, " ".join(overrides)))
502 commands.table.update(cmdtable)
505 commands.table.update(cmdtable)
503 _loaded.add(name)
506 _loaded.add(name)
504
507
505 # (reposetup is handled in hg.repository)
508 # (reposetup is handled in hg.repository)
506
509
507 addaliases(lui, commands.table)
510 addaliases(lui, commands.table)
508
511
509 # check for fallback encoding
512 # check for fallback encoding
510 fallback = lui.config('ui', 'fallbackencoding')
513 fallback = lui.config('ui', 'fallbackencoding')
511 if fallback:
514 if fallback:
512 encoding.fallbackencoding = fallback
515 encoding.fallbackencoding = fallback
513
516
514 fullargs = args
517 fullargs = args
515 cmd, func, args, options, cmdoptions = _parse(lui, args)
518 cmd, func, args, options, cmdoptions = _parse(lui, args)
516
519
517 if options["config"]:
520 if options["config"]:
518 raise util.Abort(_("option --config may not be abbreviated!"))
521 raise util.Abort(_("option --config may not be abbreviated!"))
519 if options["cwd"]:
522 if options["cwd"]:
520 raise util.Abort(_("option --cwd may not be abbreviated!"))
523 raise util.Abort(_("option --cwd may not be abbreviated!"))
521 if options["repository"]:
524 if options["repository"]:
522 raise util.Abort(_(
525 raise util.Abort(_(
523 "Option -R has to be separated from other options (e.g. not -qR) "
526 "Option -R has to be separated from other options (e.g. not -qR) "
524 "and --repository may only be abbreviated as --repo!"))
527 "and --repository may only be abbreviated as --repo!"))
525
528
526 if options["encoding"]:
529 if options["encoding"]:
527 encoding.encoding = options["encoding"]
530 encoding.encoding = options["encoding"]
528 if options["encodingmode"]:
531 if options["encodingmode"]:
529 encoding.encodingmode = options["encodingmode"]
532 encoding.encodingmode = options["encodingmode"]
530 if options["time"]:
533 if options["time"]:
531 def get_times():
534 def get_times():
532 t = os.times()
535 t = os.times()
533 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
536 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
534 t = (t[0], t[1], t[2], t[3], time.clock())
537 t = (t[0], t[1], t[2], t[3], time.clock())
535 return t
538 return t
536 s = get_times()
539 s = get_times()
537 def print_time():
540 def print_time():
538 t = get_times()
541 t = get_times()
539 ui.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
542 ui.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
540 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
543 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
541 atexit.register(print_time)
544 atexit.register(print_time)
542
545
543 if options['verbose'] or options['debug'] or options['quiet']:
546 if options['verbose'] or options['debug'] or options['quiet']:
544 ui.setconfig('ui', 'verbose', str(bool(options['verbose'])))
547 ui.setconfig('ui', 'verbose', str(bool(options['verbose'])))
545 ui.setconfig('ui', 'debug', str(bool(options['debug'])))
548 ui.setconfig('ui', 'debug', str(bool(options['debug'])))
546 ui.setconfig('ui', 'quiet', str(bool(options['quiet'])))
549 ui.setconfig('ui', 'quiet', str(bool(options['quiet'])))
547 if options['traceback']:
550 if options['traceback']:
548 ui.setconfig('ui', 'traceback', 'on')
551 ui.setconfig('ui', 'traceback', 'on')
549 if options['noninteractive']:
552 if options['noninteractive']:
550 ui.setconfig('ui', 'interactive', 'off')
553 ui.setconfig('ui', 'interactive', 'off')
551
554
552 if options['help']:
555 if options['help']:
553 return commands.help_(ui, cmd, options['version'])
556 return commands.help_(ui, cmd, options['version'])
554 elif options['version']:
557 elif options['version']:
555 return commands.version_(ui)
558 return commands.version_(ui)
556 elif not cmd:
559 elif not cmd:
557 return commands.help_(ui, 'shortlist')
560 return commands.help_(ui, 'shortlist')
558
561
559 repo = None
562 repo = None
560 cmdpats = args[:]
563 cmdpats = args[:]
561 if cmd not in commands.norepo.split():
564 if cmd not in commands.norepo.split():
562 try:
565 try:
563 repo = hg.repository(ui, path=path)
566 repo = hg.repository(ui, path=path)
564 ui = repo.ui
567 ui = repo.ui
565 if not repo.local():
568 if not repo.local():
566 raise util.Abort(_("repository '%s' is not local") % path)
569 raise util.Abort(_("repository '%s' is not local") % path)
567 ui.setconfig("bundle", "mainreporoot", repo.root)
570 ui.setconfig("bundle", "mainreporoot", repo.root)
568 except error.RepoError:
571 except error.RepoError:
569 if cmd not in commands.optionalrepo.split():
572 if cmd not in commands.optionalrepo.split():
570 if args and not path: # try to infer -R from command args
573 if args and not path: # try to infer -R from command args
571 repos = map(cmdutil.findrepo, args)
574 repos = map(cmdutil.findrepo, args)
572 guess = repos[0]
575 guess = repos[0]
573 if guess and repos.count(guess) == len(repos):
576 if guess and repos.count(guess) == len(repos):
574 return _dispatch(ui, ['--repository', guess] + fullargs)
577 return _dispatch(ui, ['--repository', guess] + fullargs)
575 if not path:
578 if not path:
576 raise error.RepoError(_("There is no Mercurial repository"
579 raise error.RepoError(_("There is no Mercurial repository"
577 " here (.hg not found)"))
580 " here (.hg not found)"))
578 raise
581 raise
579 args.insert(0, repo)
582 args.insert(0, repo)
580 elif rpath:
583 elif rpath:
581 ui.warn(_("warning: --repository ignored\n"))
584 ui.warn(_("warning: --repository ignored\n"))
582
585
583 msg = ' '.join(' ' in a and repr(a) or a for a in fullargs)
586 msg = ' '.join(' ' in a and repr(a) or a for a in fullargs)
584 ui.log("command", msg + "\n")
587 ui.log("command", msg + "\n")
585 d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
588 d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
586 return runcommand(lui, repo, cmd, fullargs, ui, options, d,
589 return runcommand(lui, repo, cmd, fullargs, ui, options, d,
587 cmdpats, cmdoptions)
590 cmdpats, cmdoptions)
588
591
589 def _runcommand(ui, options, cmd, cmdfunc):
592 def _runcommand(ui, options, cmd, cmdfunc):
590 def checkargs():
593 def checkargs():
591 try:
594 try:
592 return cmdfunc()
595 return cmdfunc()
593 except error.SignatureError:
596 except error.SignatureError:
594 raise error.CommandError(cmd, _("invalid arguments"))
597 raise error.CommandError(cmd, _("invalid arguments"))
595
598
596 if options['profile']:
599 if options['profile']:
597 format = ui.config('profiling', 'format', default='text')
600 format = ui.config('profiling', 'format', default='text')
598
601
599 if not format in ['text', 'kcachegrind']:
602 if not format in ['text', 'kcachegrind']:
600 ui.warn(_("unrecognized profiling format '%s'"
603 ui.warn(_("unrecognized profiling format '%s'"
601 " - Ignored\n") % format)
604 " - Ignored\n") % format)
602 format = 'text'
605 format = 'text'
603
606
604 output = ui.config('profiling', 'output')
607 output = ui.config('profiling', 'output')
605
608
606 if output:
609 if output:
607 path = ui.expandpath(output)
610 path = ui.expandpath(output)
608 ostream = open(path, 'wb')
611 ostream = open(path, 'wb')
609 else:
612 else:
610 ostream = sys.stderr
613 ostream = sys.stderr
611
614
612 try:
615 try:
613 from mercurial import lsprof
616 from mercurial import lsprof
614 except ImportError:
617 except ImportError:
615 raise util.Abort(_(
618 raise util.Abort(_(
616 'lsprof not available - install from '
619 'lsprof not available - install from '
617 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
620 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
618 p = lsprof.Profiler()
621 p = lsprof.Profiler()
619 p.enable(subcalls=True)
622 p.enable(subcalls=True)
620 try:
623 try:
621 return checkargs()
624 return checkargs()
622 finally:
625 finally:
623 p.disable()
626 p.disable()
624
627
625 if format == 'kcachegrind':
628 if format == 'kcachegrind':
626 import lsprofcalltree
629 import lsprofcalltree
627 calltree = lsprofcalltree.KCacheGrind(p)
630 calltree = lsprofcalltree.KCacheGrind(p)
628 calltree.output(ostream)
631 calltree.output(ostream)
629 else:
632 else:
630 # format == 'text'
633 # format == 'text'
631 stats = lsprof.Stats(p.getstats())
634 stats = lsprof.Stats(p.getstats())
632 stats.sort()
635 stats.sort()
633 stats.pprint(top=10, file=ostream, climit=5)
636 stats.pprint(top=10, file=ostream, climit=5)
634
637
635 if output:
638 if output:
636 ostream.close()
639 ostream.close()
637 else:
640 else:
638 return checkargs()
641 return checkargs()
General Comments 0
You need to be logged in to leave comments. Login now