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