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