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