##// END OF EJS Templates
dispatch: offer near-edit-distance suggestions for {file,rev}set functions...
Augie Fackler -
r24221:4e240d6a default
parent child Browse files
Show More
@@ -1,951 +1,968 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 difflib
10 import util, commands, hg, fancyopts, extensions, hook, error
11 import util, commands, hg, fancyopts, extensions, hook, error
11 import cmdutil, encoding
12 import cmdutil, encoding
12 import ui as uimod
13 import ui as uimod
13
14
14 class request(object):
15 class request(object):
15 def __init__(self, args, ui=None, repo=None, fin=None, fout=None,
16 def __init__(self, args, ui=None, repo=None, fin=None, fout=None,
16 ferr=None):
17 ferr=None):
17 self.args = args
18 self.args = args
18 self.ui = ui
19 self.ui = ui
19 self.repo = repo
20 self.repo = repo
20
21
21 # input/output/error streams
22 # input/output/error streams
22 self.fin = fin
23 self.fin = fin
23 self.fout = fout
24 self.fout = fout
24 self.ferr = ferr
25 self.ferr = ferr
25
26
26 def run():
27 def run():
27 "run the command in sys.argv"
28 "run the command in sys.argv"
28 sys.exit((dispatch(request(sys.argv[1:])) or 0) & 255)
29 sys.exit((dispatch(request(sys.argv[1:])) or 0) & 255)
29
30
31 def _getsimilar(symbols, value):
32 sim = lambda x: difflib.SequenceMatcher(None, value, x).ratio()
33 # The cutoff for similarity here is pretty arbitrary. It should
34 # probably be investigated and tweaked.
35 return [s for s in symbols if sim(s) > 0.6]
36
30 def _formatparse(write, inst):
37 def _formatparse(write, inst):
38 similar = []
39 if isinstance(inst, error.UnknownIdentifier):
40 # make sure to check fileset first, as revset can invoke fileset
41 similar = _getsimilar(inst.symbols, inst.function)
31 if len(inst.args) > 1:
42 if len(inst.args) > 1:
32 write(_("hg: parse error at %s: %s\n") %
43 write(_("hg: parse error at %s: %s\n") %
33 (inst.args[1], inst.args[0]))
44 (inst.args[1], inst.args[0]))
34 if (inst.args[0][0] == ' '):
45 if (inst.args[0][0] == ' '):
35 write(_("unexpected leading whitespace\n"))
46 write(_("unexpected leading whitespace\n"))
36 else:
47 else:
37 write(_("hg: parse error: %s\n") % inst.args[0])
48 write(_("hg: parse error: %s\n") % inst.args[0])
49 if similar:
50 if len(similar) == 1:
51 write(_("(did you mean %r?)\n") % similar[0])
52 else:
53 ss = ", ".join(sorted(similar))
54 write(_("(did you mean one of %s?)\n") % ss)
38
55
39 def dispatch(req):
56 def dispatch(req):
40 "run the command specified in req.args"
57 "run the command specified in req.args"
41 if req.ferr:
58 if req.ferr:
42 ferr = req.ferr
59 ferr = req.ferr
43 elif req.ui:
60 elif req.ui:
44 ferr = req.ui.ferr
61 ferr = req.ui.ferr
45 else:
62 else:
46 ferr = sys.stderr
63 ferr = sys.stderr
47
64
48 try:
65 try:
49 if not req.ui:
66 if not req.ui:
50 req.ui = uimod.ui()
67 req.ui = uimod.ui()
51 if '--traceback' in req.args:
68 if '--traceback' in req.args:
52 req.ui.setconfig('ui', 'traceback', 'on', '--traceback')
69 req.ui.setconfig('ui', 'traceback', 'on', '--traceback')
53
70
54 # set ui streams from the request
71 # set ui streams from the request
55 if req.fin:
72 if req.fin:
56 req.ui.fin = req.fin
73 req.ui.fin = req.fin
57 if req.fout:
74 if req.fout:
58 req.ui.fout = req.fout
75 req.ui.fout = req.fout
59 if req.ferr:
76 if req.ferr:
60 req.ui.ferr = req.ferr
77 req.ui.ferr = req.ferr
61 except util.Abort, inst:
78 except util.Abort, inst:
62 ferr.write(_("abort: %s\n") % inst)
79 ferr.write(_("abort: %s\n") % inst)
63 if inst.hint:
80 if inst.hint:
64 ferr.write(_("(%s)\n") % inst.hint)
81 ferr.write(_("(%s)\n") % inst.hint)
65 return -1
82 return -1
66 except error.ParseError, inst:
83 except error.ParseError, inst:
67 _formatparse(ferr.write, inst)
84 _formatparse(ferr.write, inst)
68 return -1
85 return -1
69
86
70 msg = ' '.join(' ' in a and repr(a) or a for a in req.args)
87 msg = ' '.join(' ' in a and repr(a) or a for a in req.args)
71 starttime = time.time()
88 starttime = time.time()
72 ret = None
89 ret = None
73 try:
90 try:
74 ret = _runcatch(req)
91 ret = _runcatch(req)
75 return ret
92 return ret
76 finally:
93 finally:
77 duration = time.time() - starttime
94 duration = time.time() - starttime
78 req.ui.log("commandfinish", "%s exited %s after %0.2f seconds\n",
95 req.ui.log("commandfinish", "%s exited %s after %0.2f seconds\n",
79 msg, ret or 0, duration)
96 msg, ret or 0, duration)
80
97
81 def _runcatch(req):
98 def _runcatch(req):
82 def catchterm(*args):
99 def catchterm(*args):
83 raise error.SignalInterrupt
100 raise error.SignalInterrupt
84
101
85 ui = req.ui
102 ui = req.ui
86 try:
103 try:
87 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
104 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
88 num = getattr(signal, name, None)
105 num = getattr(signal, name, None)
89 if num:
106 if num:
90 signal.signal(num, catchterm)
107 signal.signal(num, catchterm)
91 except ValueError:
108 except ValueError:
92 pass # happens if called in a thread
109 pass # happens if called in a thread
93
110
94 try:
111 try:
95 try:
112 try:
96 debugger = 'pdb'
113 debugger = 'pdb'
97 debugtrace = {
114 debugtrace = {
98 'pdb' : pdb.set_trace
115 'pdb' : pdb.set_trace
99 }
116 }
100 debugmortem = {
117 debugmortem = {
101 'pdb' : pdb.post_mortem
118 'pdb' : pdb.post_mortem
102 }
119 }
103
120
104 # read --config before doing anything else
121 # read --config before doing anything else
105 # (e.g. to change trust settings for reading .hg/hgrc)
122 # (e.g. to change trust settings for reading .hg/hgrc)
106 cfgs = _parseconfig(req.ui, _earlygetopt(['--config'], req.args))
123 cfgs = _parseconfig(req.ui, _earlygetopt(['--config'], req.args))
107
124
108 if req.repo:
125 if req.repo:
109 # copy configs that were passed on the cmdline (--config) to
126 # copy configs that were passed on the cmdline (--config) to
110 # the repo ui
127 # the repo ui
111 for sec, name, val in cfgs:
128 for sec, name, val in cfgs:
112 req.repo.ui.setconfig(sec, name, val, source='--config')
129 req.repo.ui.setconfig(sec, name, val, source='--config')
113
130
114 # if we are in HGPLAIN mode, then disable custom debugging
131 # if we are in HGPLAIN mode, then disable custom debugging
115 debugger = ui.config("ui", "debugger")
132 debugger = ui.config("ui", "debugger")
116 debugmod = pdb
133 debugmod = pdb
117 if not debugger or ui.plain():
134 if not debugger or ui.plain():
118 debugger = 'pdb'
135 debugger = 'pdb'
119 elif '--debugger' in req.args:
136 elif '--debugger' in req.args:
120 # This import can be slow for fancy debuggers, so only
137 # This import can be slow for fancy debuggers, so only
121 # do it when absolutely necessary, i.e. when actual
138 # do it when absolutely necessary, i.e. when actual
122 # debugging has been requested
139 # debugging has been requested
123 try:
140 try:
124 debugmod = __import__(debugger)
141 debugmod = __import__(debugger)
125 except ImportError:
142 except ImportError:
126 pass # Leave debugmod = pdb
143 pass # Leave debugmod = pdb
127
144
128 debugtrace[debugger] = debugmod.set_trace
145 debugtrace[debugger] = debugmod.set_trace
129 debugmortem[debugger] = debugmod.post_mortem
146 debugmortem[debugger] = debugmod.post_mortem
130
147
131 # enter the debugger before command execution
148 # enter the debugger before command execution
132 if '--debugger' in req.args:
149 if '--debugger' in req.args:
133 ui.warn(_("entering debugger - "
150 ui.warn(_("entering debugger - "
134 "type c to continue starting hg or h for help\n"))
151 "type c to continue starting hg or h for help\n"))
135
152
136 if (debugger != 'pdb' and
153 if (debugger != 'pdb' and
137 debugtrace[debugger] == debugtrace['pdb']):
154 debugtrace[debugger] == debugtrace['pdb']):
138 ui.warn(_("%s debugger specified "
155 ui.warn(_("%s debugger specified "
139 "but its module was not found\n") % debugger)
156 "but its module was not found\n") % debugger)
140
157
141 debugtrace[debugger]()
158 debugtrace[debugger]()
142 try:
159 try:
143 return _dispatch(req)
160 return _dispatch(req)
144 finally:
161 finally:
145 ui.flush()
162 ui.flush()
146 except: # re-raises
163 except: # re-raises
147 # enter the debugger when we hit an exception
164 # enter the debugger when we hit an exception
148 if '--debugger' in req.args:
165 if '--debugger' in req.args:
149 traceback.print_exc()
166 traceback.print_exc()
150 debugmortem[debugger](sys.exc_info()[2])
167 debugmortem[debugger](sys.exc_info()[2])
151 ui.traceback()
168 ui.traceback()
152 raise
169 raise
153
170
154 # Global exception handling, alphabetically
171 # Global exception handling, alphabetically
155 # Mercurial-specific first, followed by built-in and library exceptions
172 # Mercurial-specific first, followed by built-in and library exceptions
156 except error.AmbiguousCommand, inst:
173 except error.AmbiguousCommand, inst:
157 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
174 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
158 (inst.args[0], " ".join(inst.args[1])))
175 (inst.args[0], " ".join(inst.args[1])))
159 except error.ParseError, inst:
176 except error.ParseError, inst:
160 _formatparse(ui.warn, inst)
177 _formatparse(ui.warn, inst)
161 return -1
178 return -1
162 except error.LockHeld, inst:
179 except error.LockHeld, inst:
163 if inst.errno == errno.ETIMEDOUT:
180 if inst.errno == errno.ETIMEDOUT:
164 reason = _('timed out waiting for lock held by %s') % inst.locker
181 reason = _('timed out waiting for lock held by %s') % inst.locker
165 else:
182 else:
166 reason = _('lock held by %s') % inst.locker
183 reason = _('lock held by %s') % inst.locker
167 ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
184 ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
168 except error.LockUnavailable, inst:
185 except error.LockUnavailable, inst:
169 ui.warn(_("abort: could not lock %s: %s\n") %
186 ui.warn(_("abort: could not lock %s: %s\n") %
170 (inst.desc or inst.filename, inst.strerror))
187 (inst.desc or inst.filename, inst.strerror))
171 except error.CommandError, inst:
188 except error.CommandError, inst:
172 if inst.args[0]:
189 if inst.args[0]:
173 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
190 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
174 commands.help_(ui, inst.args[0], full=False, command=True)
191 commands.help_(ui, inst.args[0], full=False, command=True)
175 else:
192 else:
176 ui.warn(_("hg: %s\n") % inst.args[1])
193 ui.warn(_("hg: %s\n") % inst.args[1])
177 commands.help_(ui, 'shortlist')
194 commands.help_(ui, 'shortlist')
178 except error.OutOfBandError, inst:
195 except error.OutOfBandError, inst:
179 ui.warn(_("abort: remote error:\n"))
196 ui.warn(_("abort: remote error:\n"))
180 ui.warn(''.join(inst.args))
197 ui.warn(''.join(inst.args))
181 except error.RepoError, inst:
198 except error.RepoError, inst:
182 ui.warn(_("abort: %s!\n") % inst)
199 ui.warn(_("abort: %s!\n") % inst)
183 if inst.hint:
200 if inst.hint:
184 ui.warn(_("(%s)\n") % inst.hint)
201 ui.warn(_("(%s)\n") % inst.hint)
185 except error.ResponseError, inst:
202 except error.ResponseError, inst:
186 ui.warn(_("abort: %s") % inst.args[0])
203 ui.warn(_("abort: %s") % inst.args[0])
187 if not isinstance(inst.args[1], basestring):
204 if not isinstance(inst.args[1], basestring):
188 ui.warn(" %r\n" % (inst.args[1],))
205 ui.warn(" %r\n" % (inst.args[1],))
189 elif not inst.args[1]:
206 elif not inst.args[1]:
190 ui.warn(_(" empty string\n"))
207 ui.warn(_(" empty string\n"))
191 else:
208 else:
192 ui.warn("\n%r\n" % util.ellipsis(inst.args[1]))
209 ui.warn("\n%r\n" % util.ellipsis(inst.args[1]))
193 except error.CensoredNodeError, inst:
210 except error.CensoredNodeError, inst:
194 ui.warn(_("abort: file censored %s!\n") % inst)
211 ui.warn(_("abort: file censored %s!\n") % inst)
195 except error.RevlogError, inst:
212 except error.RevlogError, inst:
196 ui.warn(_("abort: %s!\n") % inst)
213 ui.warn(_("abort: %s!\n") % inst)
197 except error.SignalInterrupt:
214 except error.SignalInterrupt:
198 ui.warn(_("killed!\n"))
215 ui.warn(_("killed!\n"))
199 except error.UnknownCommand, inst:
216 except error.UnknownCommand, inst:
200 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
217 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
201 try:
218 try:
202 # check if the command is in a disabled extension
219 # check if the command is in a disabled extension
203 # (but don't check for extensions themselves)
220 # (but don't check for extensions themselves)
204 commands.help_(ui, inst.args[0], unknowncmd=True)
221 commands.help_(ui, inst.args[0], unknowncmd=True)
205 except error.UnknownCommand:
222 except error.UnknownCommand:
206 commands.help_(ui, 'shortlist')
223 commands.help_(ui, 'shortlist')
207 except error.InterventionRequired, inst:
224 except error.InterventionRequired, inst:
208 ui.warn("%s\n" % inst)
225 ui.warn("%s\n" % inst)
209 return 1
226 return 1
210 except util.Abort, inst:
227 except util.Abort, inst:
211 ui.warn(_("abort: %s\n") % inst)
228 ui.warn(_("abort: %s\n") % inst)
212 if inst.hint:
229 if inst.hint:
213 ui.warn(_("(%s)\n") % inst.hint)
230 ui.warn(_("(%s)\n") % inst.hint)
214 except ImportError, inst:
231 except ImportError, inst:
215 ui.warn(_("abort: %s!\n") % inst)
232 ui.warn(_("abort: %s!\n") % inst)
216 m = str(inst).split()[-1]
233 m = str(inst).split()[-1]
217 if m in "mpatch bdiff".split():
234 if m in "mpatch bdiff".split():
218 ui.warn(_("(did you forget to compile extensions?)\n"))
235 ui.warn(_("(did you forget to compile extensions?)\n"))
219 elif m in "zlib".split():
236 elif m in "zlib".split():
220 ui.warn(_("(is your Python install correct?)\n"))
237 ui.warn(_("(is your Python install correct?)\n"))
221 except IOError, inst:
238 except IOError, inst:
222 if util.safehasattr(inst, "code"):
239 if util.safehasattr(inst, "code"):
223 ui.warn(_("abort: %s\n") % inst)
240 ui.warn(_("abort: %s\n") % inst)
224 elif util.safehasattr(inst, "reason"):
241 elif util.safehasattr(inst, "reason"):
225 try: # usually it is in the form (errno, strerror)
242 try: # usually it is in the form (errno, strerror)
226 reason = inst.reason.args[1]
243 reason = inst.reason.args[1]
227 except (AttributeError, IndexError):
244 except (AttributeError, IndexError):
228 # it might be anything, for example a string
245 # it might be anything, for example a string
229 reason = inst.reason
246 reason = inst.reason
230 if isinstance(reason, unicode):
247 if isinstance(reason, unicode):
231 # SSLError of Python 2.7.9 contains a unicode
248 # SSLError of Python 2.7.9 contains a unicode
232 reason = reason.encode(encoding.encoding, 'replace')
249 reason = reason.encode(encoding.encoding, 'replace')
233 ui.warn(_("abort: error: %s\n") % reason)
250 ui.warn(_("abort: error: %s\n") % reason)
234 elif (util.safehasattr(inst, "args")
251 elif (util.safehasattr(inst, "args")
235 and inst.args and inst.args[0] == errno.EPIPE):
252 and inst.args and inst.args[0] == errno.EPIPE):
236 if ui.debugflag:
253 if ui.debugflag:
237 ui.warn(_("broken pipe\n"))
254 ui.warn(_("broken pipe\n"))
238 elif getattr(inst, "strerror", None):
255 elif getattr(inst, "strerror", None):
239 if getattr(inst, "filename", None):
256 if getattr(inst, "filename", None):
240 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
257 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
241 else:
258 else:
242 ui.warn(_("abort: %s\n") % inst.strerror)
259 ui.warn(_("abort: %s\n") % inst.strerror)
243 else:
260 else:
244 raise
261 raise
245 except OSError, inst:
262 except OSError, inst:
246 if getattr(inst, "filename", None) is not None:
263 if getattr(inst, "filename", None) is not None:
247 ui.warn(_("abort: %s: '%s'\n") % (inst.strerror, inst.filename))
264 ui.warn(_("abort: %s: '%s'\n") % (inst.strerror, inst.filename))
248 else:
265 else:
249 ui.warn(_("abort: %s\n") % inst.strerror)
266 ui.warn(_("abort: %s\n") % inst.strerror)
250 except KeyboardInterrupt:
267 except KeyboardInterrupt:
251 try:
268 try:
252 ui.warn(_("interrupted!\n"))
269 ui.warn(_("interrupted!\n"))
253 except IOError, inst:
270 except IOError, inst:
254 if inst.errno == errno.EPIPE:
271 if inst.errno == errno.EPIPE:
255 if ui.debugflag:
272 if ui.debugflag:
256 ui.warn(_("\nbroken pipe\n"))
273 ui.warn(_("\nbroken pipe\n"))
257 else:
274 else:
258 raise
275 raise
259 except MemoryError:
276 except MemoryError:
260 ui.warn(_("abort: out of memory\n"))
277 ui.warn(_("abort: out of memory\n"))
261 except SystemExit, inst:
278 except SystemExit, inst:
262 # Commands shouldn't sys.exit directly, but give a return code.
279 # Commands shouldn't sys.exit directly, but give a return code.
263 # Just in case catch this and and pass exit code to caller.
280 # Just in case catch this and and pass exit code to caller.
264 return inst.code
281 return inst.code
265 except socket.error, inst:
282 except socket.error, inst:
266 ui.warn(_("abort: %s\n") % inst.args[-1])
283 ui.warn(_("abort: %s\n") % inst.args[-1])
267 except: # re-raises
284 except: # re-raises
268 myver = util.version()
285 myver = util.version()
269 # For compatibility checking, we discard the portion of the hg
286 # For compatibility checking, we discard the portion of the hg
270 # version after the + on the assumption that if a "normal
287 # version after the + on the assumption that if a "normal
271 # user" is running a build with a + in it the packager
288 # user" is running a build with a + in it the packager
272 # probably built from fairly close to a tag and anyone with a
289 # probably built from fairly close to a tag and anyone with a
273 # 'make local' copy of hg (where the version number can be out
290 # 'make local' copy of hg (where the version number can be out
274 # of date) will be clueful enough to notice the implausible
291 # of date) will be clueful enough to notice the implausible
275 # version number and try updating.
292 # version number and try updating.
276 compare = myver.split('+')[0]
293 compare = myver.split('+')[0]
277 ct = tuplever(compare)
294 ct = tuplever(compare)
278 worst = None, ct, ''
295 worst = None, ct, ''
279 for name, mod in extensions.extensions():
296 for name, mod in extensions.extensions():
280 testedwith = getattr(mod, 'testedwith', '')
297 testedwith = getattr(mod, 'testedwith', '')
281 report = getattr(mod, 'buglink', _('the extension author.'))
298 report = getattr(mod, 'buglink', _('the extension author.'))
282 if not testedwith.strip():
299 if not testedwith.strip():
283 # We found an untested extension. It's likely the culprit.
300 # We found an untested extension. It's likely the culprit.
284 worst = name, 'unknown', report
301 worst = name, 'unknown', report
285 break
302 break
286
303
287 # Never blame on extensions bundled with Mercurial.
304 # Never blame on extensions bundled with Mercurial.
288 if testedwith == 'internal':
305 if testedwith == 'internal':
289 continue
306 continue
290
307
291 tested = [tuplever(t) for t in testedwith.split()]
308 tested = [tuplever(t) for t in testedwith.split()]
292 if ct in tested:
309 if ct in tested:
293 continue
310 continue
294
311
295 lower = [t for t in tested if t < ct]
312 lower = [t for t in tested if t < ct]
296 nearest = max(lower or tested)
313 nearest = max(lower or tested)
297 if worst[0] is None or nearest < worst[1]:
314 if worst[0] is None or nearest < worst[1]:
298 worst = name, nearest, report
315 worst = name, nearest, report
299 if worst[0] is not None:
316 if worst[0] is not None:
300 name, testedwith, report = worst
317 name, testedwith, report = worst
301 if not isinstance(testedwith, str):
318 if not isinstance(testedwith, str):
302 testedwith = '.'.join([str(c) for c in testedwith])
319 testedwith = '.'.join([str(c) for c in testedwith])
303 warning = (_('** Unknown exception encountered with '
320 warning = (_('** Unknown exception encountered with '
304 'possibly-broken third-party extension %s\n'
321 'possibly-broken third-party extension %s\n'
305 '** which supports versions %s of Mercurial.\n'
322 '** which supports versions %s of Mercurial.\n'
306 '** Please disable %s and try your action again.\n'
323 '** Please disable %s and try your action again.\n'
307 '** If that fixes the bug please report it to %s\n')
324 '** If that fixes the bug please report it to %s\n')
308 % (name, testedwith, name, report))
325 % (name, testedwith, name, report))
309 else:
326 else:
310 warning = (_("** unknown exception encountered, "
327 warning = (_("** unknown exception encountered, "
311 "please report by visiting\n") +
328 "please report by visiting\n") +
312 _("** http://mercurial.selenic.com/wiki/BugTracker\n"))
329 _("** http://mercurial.selenic.com/wiki/BugTracker\n"))
313 warning += ((_("** Python %s\n") % sys.version.replace('\n', '')) +
330 warning += ((_("** Python %s\n") % sys.version.replace('\n', '')) +
314 (_("** Mercurial Distributed SCM (version %s)\n") % myver) +
331 (_("** Mercurial Distributed SCM (version %s)\n") % myver) +
315 (_("** Extensions loaded: %s\n") %
332 (_("** Extensions loaded: %s\n") %
316 ", ".join([x[0] for x in extensions.extensions()])))
333 ", ".join([x[0] for x in extensions.extensions()])))
317 ui.log("commandexception", "%s\n%s\n", warning, traceback.format_exc())
334 ui.log("commandexception", "%s\n%s\n", warning, traceback.format_exc())
318 ui.warn(warning)
335 ui.warn(warning)
319 raise
336 raise
320
337
321 return -1
338 return -1
322
339
323 def tuplever(v):
340 def tuplever(v):
324 try:
341 try:
325 # Assertion: tuplever is only used for extension compatibility
342 # Assertion: tuplever is only used for extension compatibility
326 # checking. Otherwise, the discarding of extra version fields is
343 # checking. Otherwise, the discarding of extra version fields is
327 # incorrect.
344 # incorrect.
328 return tuple([int(i) for i in v.split('.')[0:2]])
345 return tuple([int(i) for i in v.split('.')[0:2]])
329 except ValueError:
346 except ValueError:
330 return tuple()
347 return tuple()
331
348
332 def aliasargs(fn, givenargs):
349 def aliasargs(fn, givenargs):
333 args = getattr(fn, 'args', [])
350 args = getattr(fn, 'args', [])
334 if args:
351 if args:
335 cmd = ' '.join(map(util.shellquote, args))
352 cmd = ' '.join(map(util.shellquote, args))
336
353
337 nums = []
354 nums = []
338 def replacer(m):
355 def replacer(m):
339 num = int(m.group(1)) - 1
356 num = int(m.group(1)) - 1
340 nums.append(num)
357 nums.append(num)
341 if num < len(givenargs):
358 if num < len(givenargs):
342 return givenargs[num]
359 return givenargs[num]
343 raise util.Abort(_('too few arguments for command alias'))
360 raise util.Abort(_('too few arguments for command alias'))
344 cmd = re.sub(r'\$(\d+|\$)', replacer, cmd)
361 cmd = re.sub(r'\$(\d+|\$)', replacer, cmd)
345 givenargs = [x for i, x in enumerate(givenargs)
362 givenargs = [x for i, x in enumerate(givenargs)
346 if i not in nums]
363 if i not in nums]
347 args = shlex.split(cmd)
364 args = shlex.split(cmd)
348 return args + givenargs
365 return args + givenargs
349
366
350 def aliasinterpolate(name, args, cmd):
367 def aliasinterpolate(name, args, cmd):
351 '''interpolate args into cmd for shell aliases
368 '''interpolate args into cmd for shell aliases
352
369
353 This also handles $0, $@ and "$@".
370 This also handles $0, $@ and "$@".
354 '''
371 '''
355 # util.interpolate can't deal with "$@" (with quotes) because it's only
372 # util.interpolate can't deal with "$@" (with quotes) because it's only
356 # built to match prefix + patterns.
373 # built to match prefix + patterns.
357 replacemap = dict(('$%d' % (i + 1), arg) for i, arg in enumerate(args))
374 replacemap = dict(('$%d' % (i + 1), arg) for i, arg in enumerate(args))
358 replacemap['$0'] = name
375 replacemap['$0'] = name
359 replacemap['$$'] = '$'
376 replacemap['$$'] = '$'
360 replacemap['$@'] = ' '.join(args)
377 replacemap['$@'] = ' '.join(args)
361 # Typical Unix shells interpolate "$@" (with quotes) as all the positional
378 # Typical Unix shells interpolate "$@" (with quotes) as all the positional
362 # parameters, separated out into words. Emulate the same behavior here by
379 # parameters, separated out into words. Emulate the same behavior here by
363 # quoting the arguments individually. POSIX shells will then typically
380 # quoting the arguments individually. POSIX shells will then typically
364 # tokenize each argument into exactly one word.
381 # tokenize each argument into exactly one word.
365 replacemap['"$@"'] = ' '.join(util.shellquote(arg) for arg in args)
382 replacemap['"$@"'] = ' '.join(util.shellquote(arg) for arg in args)
366 # escape '\$' for regex
383 # escape '\$' for regex
367 regex = '|'.join(replacemap.keys()).replace('$', r'\$')
384 regex = '|'.join(replacemap.keys()).replace('$', r'\$')
368 r = re.compile(regex)
385 r = re.compile(regex)
369 return r.sub(lambda x: replacemap[x.group()], cmd)
386 return r.sub(lambda x: replacemap[x.group()], cmd)
370
387
371 class cmdalias(object):
388 class cmdalias(object):
372 def __init__(self, name, definition, cmdtable):
389 def __init__(self, name, definition, cmdtable):
373 self.name = self.cmd = name
390 self.name = self.cmd = name
374 self.cmdname = ''
391 self.cmdname = ''
375 self.definition = definition
392 self.definition = definition
376 self.fn = None
393 self.fn = None
377 self.args = []
394 self.args = []
378 self.opts = []
395 self.opts = []
379 self.help = ''
396 self.help = ''
380 self.norepo = True
397 self.norepo = True
381 self.optionalrepo = False
398 self.optionalrepo = False
382 self.badalias = None
399 self.badalias = None
383 self.unknowncmd = False
400 self.unknowncmd = False
384
401
385 try:
402 try:
386 aliases, entry = cmdutil.findcmd(self.name, cmdtable)
403 aliases, entry = cmdutil.findcmd(self.name, cmdtable)
387 for alias, e in cmdtable.iteritems():
404 for alias, e in cmdtable.iteritems():
388 if e is entry:
405 if e is entry:
389 self.cmd = alias
406 self.cmd = alias
390 break
407 break
391 self.shadows = True
408 self.shadows = True
392 except error.UnknownCommand:
409 except error.UnknownCommand:
393 self.shadows = False
410 self.shadows = False
394
411
395 if not self.definition:
412 if not self.definition:
396 self.badalias = _("no definition for alias '%s'") % self.name
413 self.badalias = _("no definition for alias '%s'") % self.name
397 return
414 return
398
415
399 if self.definition.startswith('!'):
416 if self.definition.startswith('!'):
400 self.shell = True
417 self.shell = True
401 def fn(ui, *args):
418 def fn(ui, *args):
402 env = {'HG_ARGS': ' '.join((self.name,) + args)}
419 env = {'HG_ARGS': ' '.join((self.name,) + args)}
403 def _checkvar(m):
420 def _checkvar(m):
404 if m.groups()[0] == '$':
421 if m.groups()[0] == '$':
405 return m.group()
422 return m.group()
406 elif int(m.groups()[0]) <= len(args):
423 elif int(m.groups()[0]) <= len(args):
407 return m.group()
424 return m.group()
408 else:
425 else:
409 ui.debug("No argument found for substitution "
426 ui.debug("No argument found for substitution "
410 "of %i variable in alias '%s' definition."
427 "of %i variable in alias '%s' definition."
411 % (int(m.groups()[0]), self.name))
428 % (int(m.groups()[0]), self.name))
412 return ''
429 return ''
413 cmd = re.sub(r'\$(\d+|\$)', _checkvar, self.definition[1:])
430 cmd = re.sub(r'\$(\d+|\$)', _checkvar, self.definition[1:])
414 cmd = aliasinterpolate(self.name, args, cmd)
431 cmd = aliasinterpolate(self.name, args, cmd)
415 return ui.system(cmd, environ=env)
432 return ui.system(cmd, environ=env)
416 self.fn = fn
433 self.fn = fn
417 return
434 return
418
435
419 try:
436 try:
420 args = shlex.split(self.definition)
437 args = shlex.split(self.definition)
421 except ValueError, inst:
438 except ValueError, inst:
422 self.badalias = (_("error in definition for alias '%s': %s")
439 self.badalias = (_("error in definition for alias '%s': %s")
423 % (self.name, inst))
440 % (self.name, inst))
424 return
441 return
425 self.cmdname = cmd = args.pop(0)
442 self.cmdname = cmd = args.pop(0)
426 args = map(util.expandpath, args)
443 args = map(util.expandpath, args)
427
444
428 for invalidarg in ("--cwd", "-R", "--repository", "--repo", "--config"):
445 for invalidarg in ("--cwd", "-R", "--repository", "--repo", "--config"):
429 if _earlygetopt([invalidarg], args):
446 if _earlygetopt([invalidarg], args):
430 self.badalias = (_("error in definition for alias '%s': %s may "
447 self.badalias = (_("error in definition for alias '%s': %s may "
431 "only be given on the command line")
448 "only be given on the command line")
432 % (self.name, invalidarg))
449 % (self.name, invalidarg))
433 return
450 return
434
451
435 try:
452 try:
436 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
453 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
437 if len(tableentry) > 2:
454 if len(tableentry) > 2:
438 self.fn, self.opts, self.help = tableentry
455 self.fn, self.opts, self.help = tableentry
439 else:
456 else:
440 self.fn, self.opts = tableentry
457 self.fn, self.opts = tableentry
441
458
442 self.args = aliasargs(self.fn, args)
459 self.args = aliasargs(self.fn, args)
443 if cmd not in commands.norepo.split(' '):
460 if cmd not in commands.norepo.split(' '):
444 self.norepo = False
461 self.norepo = False
445 if cmd in commands.optionalrepo.split(' '):
462 if cmd in commands.optionalrepo.split(' '):
446 self.optionalrepo = True
463 self.optionalrepo = True
447 if self.help.startswith("hg " + cmd):
464 if self.help.startswith("hg " + cmd):
448 # drop prefix in old-style help lines so hg shows the alias
465 # drop prefix in old-style help lines so hg shows the alias
449 self.help = self.help[4 + len(cmd):]
466 self.help = self.help[4 + len(cmd):]
450 self.__doc__ = self.fn.__doc__
467 self.__doc__ = self.fn.__doc__
451
468
452 except error.UnknownCommand:
469 except error.UnknownCommand:
453 self.badalias = (_("alias '%s' resolves to unknown command '%s'")
470 self.badalias = (_("alias '%s' resolves to unknown command '%s'")
454 % (self.name, cmd))
471 % (self.name, cmd))
455 self.unknowncmd = True
472 self.unknowncmd = True
456 except error.AmbiguousCommand:
473 except error.AmbiguousCommand:
457 self.badalias = (_("alias '%s' resolves to ambiguous command '%s'")
474 self.badalias = (_("alias '%s' resolves to ambiguous command '%s'")
458 % (self.name, cmd))
475 % (self.name, cmd))
459
476
460 def __call__(self, ui, *args, **opts):
477 def __call__(self, ui, *args, **opts):
461 if self.badalias:
478 if self.badalias:
462 hint = None
479 hint = None
463 if self.unknowncmd:
480 if self.unknowncmd:
464 try:
481 try:
465 # check if the command is in a disabled extension
482 # check if the command is in a disabled extension
466 cmd, ext = extensions.disabledcmd(ui, self.cmdname)[:2]
483 cmd, ext = extensions.disabledcmd(ui, self.cmdname)[:2]
467 hint = _("'%s' is provided by '%s' extension") % (cmd, ext)
484 hint = _("'%s' is provided by '%s' extension") % (cmd, ext)
468 except error.UnknownCommand:
485 except error.UnknownCommand:
469 pass
486 pass
470 raise util.Abort(self.badalias, hint=hint)
487 raise util.Abort(self.badalias, hint=hint)
471 if self.shadows:
488 if self.shadows:
472 ui.debug("alias '%s' shadows command '%s'\n" %
489 ui.debug("alias '%s' shadows command '%s'\n" %
473 (self.name, self.cmdname))
490 (self.name, self.cmdname))
474
491
475 if util.safehasattr(self, 'shell'):
492 if util.safehasattr(self, 'shell'):
476 return self.fn(ui, *args, **opts)
493 return self.fn(ui, *args, **opts)
477 else:
494 else:
478 try:
495 try:
479 return util.checksignature(self.fn)(ui, *args, **opts)
496 return util.checksignature(self.fn)(ui, *args, **opts)
480 except error.SignatureError:
497 except error.SignatureError:
481 args = ' '.join([self.cmdname] + self.args)
498 args = ' '.join([self.cmdname] + self.args)
482 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args))
499 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args))
483 raise
500 raise
484
501
485 def addaliases(ui, cmdtable):
502 def addaliases(ui, cmdtable):
486 # aliases are processed after extensions have been loaded, so they
503 # aliases are processed after extensions have been loaded, so they
487 # may use extension commands. Aliases can also use other alias definitions,
504 # may use extension commands. Aliases can also use other alias definitions,
488 # but only if they have been defined prior to the current definition.
505 # but only if they have been defined prior to the current definition.
489 for alias, definition in ui.configitems('alias'):
506 for alias, definition in ui.configitems('alias'):
490 aliasdef = cmdalias(alias, definition, cmdtable)
507 aliasdef = cmdalias(alias, definition, cmdtable)
491
508
492 try:
509 try:
493 olddef = cmdtable[aliasdef.cmd][0]
510 olddef = cmdtable[aliasdef.cmd][0]
494 if olddef.definition == aliasdef.definition:
511 if olddef.definition == aliasdef.definition:
495 continue
512 continue
496 except (KeyError, AttributeError):
513 except (KeyError, AttributeError):
497 # definition might not exist or it might not be a cmdalias
514 # definition might not exist or it might not be a cmdalias
498 pass
515 pass
499
516
500 cmdtable[aliasdef.name] = (aliasdef, aliasdef.opts, aliasdef.help)
517 cmdtable[aliasdef.name] = (aliasdef, aliasdef.opts, aliasdef.help)
501 if aliasdef.norepo:
518 if aliasdef.norepo:
502 commands.norepo += ' %s' % alias
519 commands.norepo += ' %s' % alias
503 if aliasdef.optionalrepo:
520 if aliasdef.optionalrepo:
504 commands.optionalrepo += ' %s' % alias
521 commands.optionalrepo += ' %s' % alias
505
522
506 def _parse(ui, args):
523 def _parse(ui, args):
507 options = {}
524 options = {}
508 cmdoptions = {}
525 cmdoptions = {}
509
526
510 try:
527 try:
511 args = fancyopts.fancyopts(args, commands.globalopts, options)
528 args = fancyopts.fancyopts(args, commands.globalopts, options)
512 except fancyopts.getopt.GetoptError, inst:
529 except fancyopts.getopt.GetoptError, inst:
513 raise error.CommandError(None, inst)
530 raise error.CommandError(None, inst)
514
531
515 if args:
532 if args:
516 cmd, args = args[0], args[1:]
533 cmd, args = args[0], args[1:]
517 aliases, entry = cmdutil.findcmd(cmd, commands.table,
534 aliases, entry = cmdutil.findcmd(cmd, commands.table,
518 ui.configbool("ui", "strict"))
535 ui.configbool("ui", "strict"))
519 cmd = aliases[0]
536 cmd = aliases[0]
520 args = aliasargs(entry[0], args)
537 args = aliasargs(entry[0], args)
521 defaults = ui.config("defaults", cmd)
538 defaults = ui.config("defaults", cmd)
522 if defaults:
539 if defaults:
523 args = map(util.expandpath, shlex.split(defaults)) + args
540 args = map(util.expandpath, shlex.split(defaults)) + args
524 c = list(entry[1])
541 c = list(entry[1])
525 else:
542 else:
526 cmd = None
543 cmd = None
527 c = []
544 c = []
528
545
529 # combine global options into local
546 # combine global options into local
530 for o in commands.globalopts:
547 for o in commands.globalopts:
531 c.append((o[0], o[1], options[o[1]], o[3]))
548 c.append((o[0], o[1], options[o[1]], o[3]))
532
549
533 try:
550 try:
534 args = fancyopts.fancyopts(args, c, cmdoptions, True)
551 args = fancyopts.fancyopts(args, c, cmdoptions, True)
535 except fancyopts.getopt.GetoptError, inst:
552 except fancyopts.getopt.GetoptError, inst:
536 raise error.CommandError(cmd, inst)
553 raise error.CommandError(cmd, inst)
537
554
538 # separate global options back out
555 # separate global options back out
539 for o in commands.globalopts:
556 for o in commands.globalopts:
540 n = o[1]
557 n = o[1]
541 options[n] = cmdoptions[n]
558 options[n] = cmdoptions[n]
542 del cmdoptions[n]
559 del cmdoptions[n]
543
560
544 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
561 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
545
562
546 def _parseconfig(ui, config):
563 def _parseconfig(ui, config):
547 """parse the --config options from the command line"""
564 """parse the --config options from the command line"""
548 configs = []
565 configs = []
549
566
550 for cfg in config:
567 for cfg in config:
551 try:
568 try:
552 name, value = cfg.split('=', 1)
569 name, value = cfg.split('=', 1)
553 section, name = name.split('.', 1)
570 section, name = name.split('.', 1)
554 if not section or not name:
571 if not section or not name:
555 raise IndexError
572 raise IndexError
556 ui.setconfig(section, name, value, '--config')
573 ui.setconfig(section, name, value, '--config')
557 configs.append((section, name, value))
574 configs.append((section, name, value))
558 except (IndexError, ValueError):
575 except (IndexError, ValueError):
559 raise util.Abort(_('malformed --config option: %r '
576 raise util.Abort(_('malformed --config option: %r '
560 '(use --config section.name=value)') % cfg)
577 '(use --config section.name=value)') % cfg)
561
578
562 return configs
579 return configs
563
580
564 def _earlygetopt(aliases, args):
581 def _earlygetopt(aliases, args):
565 """Return list of values for an option (or aliases).
582 """Return list of values for an option (or aliases).
566
583
567 The values are listed in the order they appear in args.
584 The values are listed in the order they appear in args.
568 The options and values are removed from args.
585 The options and values are removed from args.
569
586
570 >>> args = ['x', '--cwd', 'foo', 'y']
587 >>> args = ['x', '--cwd', 'foo', 'y']
571 >>> _earlygetopt(['--cwd'], args), args
588 >>> _earlygetopt(['--cwd'], args), args
572 (['foo'], ['x', 'y'])
589 (['foo'], ['x', 'y'])
573
590
574 >>> args = ['x', '--cwd=bar', 'y']
591 >>> args = ['x', '--cwd=bar', 'y']
575 >>> _earlygetopt(['--cwd'], args), args
592 >>> _earlygetopt(['--cwd'], args), args
576 (['bar'], ['x', 'y'])
593 (['bar'], ['x', 'y'])
577
594
578 >>> args = ['x', '-R', 'foo', 'y']
595 >>> args = ['x', '-R', 'foo', 'y']
579 >>> _earlygetopt(['-R'], args), args
596 >>> _earlygetopt(['-R'], args), args
580 (['foo'], ['x', 'y'])
597 (['foo'], ['x', 'y'])
581
598
582 >>> args = ['x', '-Rbar', 'y']
599 >>> args = ['x', '-Rbar', 'y']
583 >>> _earlygetopt(['-R'], args), args
600 >>> _earlygetopt(['-R'], args), args
584 (['bar'], ['x', 'y'])
601 (['bar'], ['x', 'y'])
585 """
602 """
586 try:
603 try:
587 argcount = args.index("--")
604 argcount = args.index("--")
588 except ValueError:
605 except ValueError:
589 argcount = len(args)
606 argcount = len(args)
590 shortopts = [opt for opt in aliases if len(opt) == 2]
607 shortopts = [opt for opt in aliases if len(opt) == 2]
591 values = []
608 values = []
592 pos = 0
609 pos = 0
593 while pos < argcount:
610 while pos < argcount:
594 fullarg = arg = args[pos]
611 fullarg = arg = args[pos]
595 equals = arg.find('=')
612 equals = arg.find('=')
596 if equals > -1:
613 if equals > -1:
597 arg = arg[:equals]
614 arg = arg[:equals]
598 if arg in aliases:
615 if arg in aliases:
599 del args[pos]
616 del args[pos]
600 if equals > -1:
617 if equals > -1:
601 values.append(fullarg[equals + 1:])
618 values.append(fullarg[equals + 1:])
602 argcount -= 1
619 argcount -= 1
603 else:
620 else:
604 if pos + 1 >= argcount:
621 if pos + 1 >= argcount:
605 # ignore and let getopt report an error if there is no value
622 # ignore and let getopt report an error if there is no value
606 break
623 break
607 values.append(args.pop(pos))
624 values.append(args.pop(pos))
608 argcount -= 2
625 argcount -= 2
609 elif arg[:2] in shortopts:
626 elif arg[:2] in shortopts:
610 # short option can have no following space, e.g. hg log -Rfoo
627 # short option can have no following space, e.g. hg log -Rfoo
611 values.append(args.pop(pos)[2:])
628 values.append(args.pop(pos)[2:])
612 argcount -= 1
629 argcount -= 1
613 else:
630 else:
614 pos += 1
631 pos += 1
615 return values
632 return values
616
633
617 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
634 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
618 # run pre-hook, and abort if it fails
635 # run pre-hook, and abort if it fails
619 hook.hook(lui, repo, "pre-%s" % cmd, True, args=" ".join(fullargs),
636 hook.hook(lui, repo, "pre-%s" % cmd, True, args=" ".join(fullargs),
620 pats=cmdpats, opts=cmdoptions)
637 pats=cmdpats, opts=cmdoptions)
621 ret = _runcommand(ui, options, cmd, d)
638 ret = _runcommand(ui, options, cmd, d)
622 # run post-hook, passing command result
639 # run post-hook, passing command result
623 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
640 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
624 result=ret, pats=cmdpats, opts=cmdoptions)
641 result=ret, pats=cmdpats, opts=cmdoptions)
625 return ret
642 return ret
626
643
627 def _getlocal(ui, rpath):
644 def _getlocal(ui, rpath):
628 """Return (path, local ui object) for the given target path.
645 """Return (path, local ui object) for the given target path.
629
646
630 Takes paths in [cwd]/.hg/hgrc into account."
647 Takes paths in [cwd]/.hg/hgrc into account."
631 """
648 """
632 try:
649 try:
633 wd = os.getcwd()
650 wd = os.getcwd()
634 except OSError, e:
651 except OSError, e:
635 raise util.Abort(_("error getting current working directory: %s") %
652 raise util.Abort(_("error getting current working directory: %s") %
636 e.strerror)
653 e.strerror)
637 path = cmdutil.findrepo(wd) or ""
654 path = cmdutil.findrepo(wd) or ""
638 if not path:
655 if not path:
639 lui = ui
656 lui = ui
640 else:
657 else:
641 lui = ui.copy()
658 lui = ui.copy()
642 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
659 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
643
660
644 if rpath and rpath[-1]:
661 if rpath and rpath[-1]:
645 path = lui.expandpath(rpath[-1])
662 path = lui.expandpath(rpath[-1])
646 lui = ui.copy()
663 lui = ui.copy()
647 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
664 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
648
665
649 return path, lui
666 return path, lui
650
667
651 def _checkshellalias(lui, ui, args, precheck=True):
668 def _checkshellalias(lui, ui, args, precheck=True):
652 """Return the function to run the shell alias, if it is required
669 """Return the function to run the shell alias, if it is required
653
670
654 'precheck' is whether this function is invoked before adding
671 'precheck' is whether this function is invoked before adding
655 aliases or not.
672 aliases or not.
656 """
673 """
657 options = {}
674 options = {}
658
675
659 try:
676 try:
660 args = fancyopts.fancyopts(args, commands.globalopts, options)
677 args = fancyopts.fancyopts(args, commands.globalopts, options)
661 except fancyopts.getopt.GetoptError:
678 except fancyopts.getopt.GetoptError:
662 return
679 return
663
680
664 if not args:
681 if not args:
665 return
682 return
666
683
667 if precheck:
684 if precheck:
668 strict = True
685 strict = True
669 norepo = commands.norepo
686 norepo = commands.norepo
670 optionalrepo = commands.optionalrepo
687 optionalrepo = commands.optionalrepo
671 def restorecommands():
688 def restorecommands():
672 commands.norepo = norepo
689 commands.norepo = norepo
673 commands.optionalrepo = optionalrepo
690 commands.optionalrepo = optionalrepo
674 cmdtable = commands.table.copy()
691 cmdtable = commands.table.copy()
675 addaliases(lui, cmdtable)
692 addaliases(lui, cmdtable)
676 else:
693 else:
677 strict = False
694 strict = False
678 def restorecommands():
695 def restorecommands():
679 pass
696 pass
680 cmdtable = commands.table
697 cmdtable = commands.table
681
698
682 cmd = args[0]
699 cmd = args[0]
683 try:
700 try:
684 aliases, entry = cmdutil.findcmd(cmd, cmdtable, strict)
701 aliases, entry = cmdutil.findcmd(cmd, cmdtable, strict)
685 except (error.AmbiguousCommand, error.UnknownCommand):
702 except (error.AmbiguousCommand, error.UnknownCommand):
686 restorecommands()
703 restorecommands()
687 return
704 return
688
705
689 cmd = aliases[0]
706 cmd = aliases[0]
690 fn = entry[0]
707 fn = entry[0]
691
708
692 if cmd and util.safehasattr(fn, 'shell'):
709 if cmd and util.safehasattr(fn, 'shell'):
693 d = lambda: fn(ui, *args[1:])
710 d = lambda: fn(ui, *args[1:])
694 return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d,
711 return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d,
695 [], {})
712 [], {})
696
713
697 restorecommands()
714 restorecommands()
698
715
699 _loaded = set()
716 _loaded = set()
700 def _dispatch(req):
717 def _dispatch(req):
701 args = req.args
718 args = req.args
702 ui = req.ui
719 ui = req.ui
703
720
704 # check for cwd
721 # check for cwd
705 cwd = _earlygetopt(['--cwd'], args)
722 cwd = _earlygetopt(['--cwd'], args)
706 if cwd:
723 if cwd:
707 os.chdir(cwd[-1])
724 os.chdir(cwd[-1])
708
725
709 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
726 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
710 path, lui = _getlocal(ui, rpath)
727 path, lui = _getlocal(ui, rpath)
711
728
712 # Now that we're operating in the right directory/repository with
729 # Now that we're operating in the right directory/repository with
713 # the right config settings, check for shell aliases
730 # the right config settings, check for shell aliases
714 shellaliasfn = _checkshellalias(lui, ui, args)
731 shellaliasfn = _checkshellalias(lui, ui, args)
715 if shellaliasfn:
732 if shellaliasfn:
716 return shellaliasfn()
733 return shellaliasfn()
717
734
718 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
735 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
719 # reposetup. Programs like TortoiseHg will call _dispatch several
736 # reposetup. Programs like TortoiseHg will call _dispatch several
720 # times so we keep track of configured extensions in _loaded.
737 # times so we keep track of configured extensions in _loaded.
721 extensions.loadall(lui)
738 extensions.loadall(lui)
722 exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
739 exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
723 # Propagate any changes to lui.__class__ by extensions
740 # Propagate any changes to lui.__class__ by extensions
724 ui.__class__ = lui.__class__
741 ui.__class__ = lui.__class__
725
742
726 # (uisetup and extsetup are handled in extensions.loadall)
743 # (uisetup and extsetup are handled in extensions.loadall)
727
744
728 for name, module in exts:
745 for name, module in exts:
729 cmdtable = getattr(module, 'cmdtable', {})
746 cmdtable = getattr(module, 'cmdtable', {})
730 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
747 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
731 if overrides:
748 if overrides:
732 ui.warn(_("extension '%s' overrides commands: %s\n")
749 ui.warn(_("extension '%s' overrides commands: %s\n")
733 % (name, " ".join(overrides)))
750 % (name, " ".join(overrides)))
734 commands.table.update(cmdtable)
751 commands.table.update(cmdtable)
735 _loaded.add(name)
752 _loaded.add(name)
736
753
737 # (reposetup is handled in hg.repository)
754 # (reposetup is handled in hg.repository)
738
755
739 addaliases(lui, commands.table)
756 addaliases(lui, commands.table)
740
757
741 if not lui.configbool("ui", "strict"):
758 if not lui.configbool("ui", "strict"):
742 # All aliases and commands are completely defined, now.
759 # All aliases and commands are completely defined, now.
743 # Check abbreviation/ambiguity of shell alias again, because shell
760 # Check abbreviation/ambiguity of shell alias again, because shell
744 # alias may cause failure of "_parse" (see issue4355)
761 # alias may cause failure of "_parse" (see issue4355)
745 shellaliasfn = _checkshellalias(lui, ui, args, precheck=False)
762 shellaliasfn = _checkshellalias(lui, ui, args, precheck=False)
746 if shellaliasfn:
763 if shellaliasfn:
747 return shellaliasfn()
764 return shellaliasfn()
748
765
749 # check for fallback encoding
766 # check for fallback encoding
750 fallback = lui.config('ui', 'fallbackencoding')
767 fallback = lui.config('ui', 'fallbackencoding')
751 if fallback:
768 if fallback:
752 encoding.fallbackencoding = fallback
769 encoding.fallbackencoding = fallback
753
770
754 fullargs = args
771 fullargs = args
755 cmd, func, args, options, cmdoptions = _parse(lui, args)
772 cmd, func, args, options, cmdoptions = _parse(lui, args)
756
773
757 if options["config"]:
774 if options["config"]:
758 raise util.Abort(_("option --config may not be abbreviated!"))
775 raise util.Abort(_("option --config may not be abbreviated!"))
759 if options["cwd"]:
776 if options["cwd"]:
760 raise util.Abort(_("option --cwd may not be abbreviated!"))
777 raise util.Abort(_("option --cwd may not be abbreviated!"))
761 if options["repository"]:
778 if options["repository"]:
762 raise util.Abort(_(
779 raise util.Abort(_(
763 "option -R has to be separated from other options (e.g. not -qR) "
780 "option -R has to be separated from other options (e.g. not -qR) "
764 "and --repository may only be abbreviated as --repo!"))
781 "and --repository may only be abbreviated as --repo!"))
765
782
766 if options["encoding"]:
783 if options["encoding"]:
767 encoding.encoding = options["encoding"]
784 encoding.encoding = options["encoding"]
768 if options["encodingmode"]:
785 if options["encodingmode"]:
769 encoding.encodingmode = options["encodingmode"]
786 encoding.encodingmode = options["encodingmode"]
770 if options["time"]:
787 if options["time"]:
771 def get_times():
788 def get_times():
772 t = os.times()
789 t = os.times()
773 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
790 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
774 t = (t[0], t[1], t[2], t[3], time.clock())
791 t = (t[0], t[1], t[2], t[3], time.clock())
775 return t
792 return t
776 s = get_times()
793 s = get_times()
777 def print_time():
794 def print_time():
778 t = get_times()
795 t = get_times()
779 ui.warn(_("time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
796 ui.warn(_("time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
780 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
797 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
781 atexit.register(print_time)
798 atexit.register(print_time)
782
799
783 uis = set([ui, lui])
800 uis = set([ui, lui])
784
801
785 if req.repo:
802 if req.repo:
786 uis.add(req.repo.ui)
803 uis.add(req.repo.ui)
787
804
788 if options['verbose'] or options['debug'] or options['quiet']:
805 if options['verbose'] or options['debug'] or options['quiet']:
789 for opt in ('verbose', 'debug', 'quiet'):
806 for opt in ('verbose', 'debug', 'quiet'):
790 val = str(bool(options[opt]))
807 val = str(bool(options[opt]))
791 for ui_ in uis:
808 for ui_ in uis:
792 ui_.setconfig('ui', opt, val, '--' + opt)
809 ui_.setconfig('ui', opt, val, '--' + opt)
793
810
794 if options['traceback']:
811 if options['traceback']:
795 for ui_ in uis:
812 for ui_ in uis:
796 ui_.setconfig('ui', 'traceback', 'on', '--traceback')
813 ui_.setconfig('ui', 'traceback', 'on', '--traceback')
797
814
798 if options['noninteractive']:
815 if options['noninteractive']:
799 for ui_ in uis:
816 for ui_ in uis:
800 ui_.setconfig('ui', 'interactive', 'off', '-y')
817 ui_.setconfig('ui', 'interactive', 'off', '-y')
801
818
802 if cmdoptions.get('insecure', False):
819 if cmdoptions.get('insecure', False):
803 for ui_ in uis:
820 for ui_ in uis:
804 ui_.setconfig('web', 'cacerts', '', '--insecure')
821 ui_.setconfig('web', 'cacerts', '', '--insecure')
805
822
806 if options['version']:
823 if options['version']:
807 return commands.version_(ui)
824 return commands.version_(ui)
808 if options['help']:
825 if options['help']:
809 return commands.help_(ui, cmd, command=True)
826 return commands.help_(ui, cmd, command=True)
810 elif not cmd:
827 elif not cmd:
811 return commands.help_(ui, 'shortlist')
828 return commands.help_(ui, 'shortlist')
812
829
813 repo = None
830 repo = None
814 cmdpats = args[:]
831 cmdpats = args[:]
815 if cmd not in commands.norepo.split():
832 if cmd not in commands.norepo.split():
816 # use the repo from the request only if we don't have -R
833 # use the repo from the request only if we don't have -R
817 if not rpath and not cwd:
834 if not rpath and not cwd:
818 repo = req.repo
835 repo = req.repo
819
836
820 if repo:
837 if repo:
821 # set the descriptors of the repo ui to those of ui
838 # set the descriptors of the repo ui to those of ui
822 repo.ui.fin = ui.fin
839 repo.ui.fin = ui.fin
823 repo.ui.fout = ui.fout
840 repo.ui.fout = ui.fout
824 repo.ui.ferr = ui.ferr
841 repo.ui.ferr = ui.ferr
825 else:
842 else:
826 try:
843 try:
827 repo = hg.repository(ui, path=path)
844 repo = hg.repository(ui, path=path)
828 if not repo.local():
845 if not repo.local():
829 raise util.Abort(_("repository '%s' is not local") % path)
846 raise util.Abort(_("repository '%s' is not local") % path)
830 repo.ui.setconfig("bundle", "mainreporoot", repo.root, 'repo')
847 repo.ui.setconfig("bundle", "mainreporoot", repo.root, 'repo')
831 except error.RequirementError:
848 except error.RequirementError:
832 raise
849 raise
833 except error.RepoError:
850 except error.RepoError:
834 if cmd not in commands.optionalrepo.split():
851 if cmd not in commands.optionalrepo.split():
835 if (cmd in commands.inferrepo.split() and
852 if (cmd in commands.inferrepo.split() and
836 args and not path): # try to infer -R from command args
853 args and not path): # try to infer -R from command args
837 repos = map(cmdutil.findrepo, args)
854 repos = map(cmdutil.findrepo, args)
838 guess = repos[0]
855 guess = repos[0]
839 if guess and repos.count(guess) == len(repos):
856 if guess and repos.count(guess) == len(repos):
840 req.args = ['--repository', guess] + fullargs
857 req.args = ['--repository', guess] + fullargs
841 return _dispatch(req)
858 return _dispatch(req)
842 if not path:
859 if not path:
843 raise error.RepoError(_("no repository found in '%s'"
860 raise error.RepoError(_("no repository found in '%s'"
844 " (.hg not found)")
861 " (.hg not found)")
845 % os.getcwd())
862 % os.getcwd())
846 raise
863 raise
847 if repo:
864 if repo:
848 ui = repo.ui
865 ui = repo.ui
849 if options['hidden']:
866 if options['hidden']:
850 repo = repo.unfiltered()
867 repo = repo.unfiltered()
851 args.insert(0, repo)
868 args.insert(0, repo)
852 elif rpath:
869 elif rpath:
853 ui.warn(_("warning: --repository ignored\n"))
870 ui.warn(_("warning: --repository ignored\n"))
854
871
855 msg = ' '.join(' ' in a and repr(a) or a for a in fullargs)
872 msg = ' '.join(' ' in a and repr(a) or a for a in fullargs)
856 ui.log("command", '%s\n', msg)
873 ui.log("command", '%s\n', msg)
857 d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
874 d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
858 try:
875 try:
859 return runcommand(lui, repo, cmd, fullargs, ui, options, d,
876 return runcommand(lui, repo, cmd, fullargs, ui, options, d,
860 cmdpats, cmdoptions)
877 cmdpats, cmdoptions)
861 finally:
878 finally:
862 if repo and repo != req.repo:
879 if repo and repo != req.repo:
863 repo.close()
880 repo.close()
864
881
865 def lsprofile(ui, func, fp):
882 def lsprofile(ui, func, fp):
866 format = ui.config('profiling', 'format', default='text')
883 format = ui.config('profiling', 'format', default='text')
867 field = ui.config('profiling', 'sort', default='inlinetime')
884 field = ui.config('profiling', 'sort', default='inlinetime')
868 limit = ui.configint('profiling', 'limit', default=30)
885 limit = ui.configint('profiling', 'limit', default=30)
869 climit = ui.configint('profiling', 'nested', default=5)
886 climit = ui.configint('profiling', 'nested', default=5)
870
887
871 if format not in ['text', 'kcachegrind']:
888 if format not in ['text', 'kcachegrind']:
872 ui.warn(_("unrecognized profiling format '%s'"
889 ui.warn(_("unrecognized profiling format '%s'"
873 " - Ignored\n") % format)
890 " - Ignored\n") % format)
874 format = 'text'
891 format = 'text'
875
892
876 try:
893 try:
877 from mercurial import lsprof
894 from mercurial import lsprof
878 except ImportError:
895 except ImportError:
879 raise util.Abort(_(
896 raise util.Abort(_(
880 'lsprof not available - install from '
897 'lsprof not available - install from '
881 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
898 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
882 p = lsprof.Profiler()
899 p = lsprof.Profiler()
883 p.enable(subcalls=True)
900 p.enable(subcalls=True)
884 try:
901 try:
885 return func()
902 return func()
886 finally:
903 finally:
887 p.disable()
904 p.disable()
888
905
889 if format == 'kcachegrind':
906 if format == 'kcachegrind':
890 import lsprofcalltree
907 import lsprofcalltree
891 calltree = lsprofcalltree.KCacheGrind(p)
908 calltree = lsprofcalltree.KCacheGrind(p)
892 calltree.output(fp)
909 calltree.output(fp)
893 else:
910 else:
894 # format == 'text'
911 # format == 'text'
895 stats = lsprof.Stats(p.getstats())
912 stats = lsprof.Stats(p.getstats())
896 stats.sort(field)
913 stats.sort(field)
897 stats.pprint(limit=limit, file=fp, climit=climit)
914 stats.pprint(limit=limit, file=fp, climit=climit)
898
915
899 def statprofile(ui, func, fp):
916 def statprofile(ui, func, fp):
900 try:
917 try:
901 import statprof
918 import statprof
902 except ImportError:
919 except ImportError:
903 raise util.Abort(_(
920 raise util.Abort(_(
904 'statprof not available - install using "easy_install statprof"'))
921 'statprof not available - install using "easy_install statprof"'))
905
922
906 freq = ui.configint('profiling', 'freq', default=1000)
923 freq = ui.configint('profiling', 'freq', default=1000)
907 if freq > 0:
924 if freq > 0:
908 statprof.reset(freq)
925 statprof.reset(freq)
909 else:
926 else:
910 ui.warn(_("invalid sampling frequency '%s' - ignoring\n") % freq)
927 ui.warn(_("invalid sampling frequency '%s' - ignoring\n") % freq)
911
928
912 statprof.start()
929 statprof.start()
913 try:
930 try:
914 return func()
931 return func()
915 finally:
932 finally:
916 statprof.stop()
933 statprof.stop()
917 statprof.display(fp)
934 statprof.display(fp)
918
935
919 def _runcommand(ui, options, cmd, cmdfunc):
936 def _runcommand(ui, options, cmd, cmdfunc):
920 def checkargs():
937 def checkargs():
921 try:
938 try:
922 return cmdfunc()
939 return cmdfunc()
923 except error.SignatureError:
940 except error.SignatureError:
924 raise error.CommandError(cmd, _("invalid arguments"))
941 raise error.CommandError(cmd, _("invalid arguments"))
925
942
926 if options['profile']:
943 if options['profile']:
927 profiler = os.getenv('HGPROF')
944 profiler = os.getenv('HGPROF')
928 if profiler is None:
945 if profiler is None:
929 profiler = ui.config('profiling', 'type', default='ls')
946 profiler = ui.config('profiling', 'type', default='ls')
930 if profiler not in ('ls', 'stat'):
947 if profiler not in ('ls', 'stat'):
931 ui.warn(_("unrecognized profiler '%s' - ignored\n") % profiler)
948 ui.warn(_("unrecognized profiler '%s' - ignored\n") % profiler)
932 profiler = 'ls'
949 profiler = 'ls'
933
950
934 output = ui.config('profiling', 'output')
951 output = ui.config('profiling', 'output')
935
952
936 if output:
953 if output:
937 path = ui.expandpath(output)
954 path = ui.expandpath(output)
938 fp = open(path, 'wb')
955 fp = open(path, 'wb')
939 else:
956 else:
940 fp = sys.stderr
957 fp = sys.stderr
941
958
942 try:
959 try:
943 if profiler == 'ls':
960 if profiler == 'ls':
944 return lsprofile(ui, checkargs, fp)
961 return lsprofile(ui, checkargs, fp)
945 else:
962 else:
946 return statprofile(ui, checkargs, fp)
963 return statprofile(ui, checkargs, fp)
947 finally:
964 finally:
948 if output:
965 if output:
949 fp.close()
966 fp.close()
950 else:
967 else:
951 return checkargs()
968 return checkargs()
@@ -1,1402 +1,1405 b''
1 $ HGENCODING=utf-8
1 $ HGENCODING=utf-8
2 $ export HGENCODING
2 $ export HGENCODING
3
3
4 $ try() {
4 $ try() {
5 > hg debugrevspec --debug "$@"
5 > hg debugrevspec --debug "$@"
6 > }
6 > }
7
7
8 $ log() {
8 $ log() {
9 > hg log --template '{rev}\n' -r "$1"
9 > hg log --template '{rev}\n' -r "$1"
10 > }
10 > }
11
11
12 $ hg init repo
12 $ hg init repo
13 $ cd repo
13 $ cd repo
14
14
15 $ echo a > a
15 $ echo a > a
16 $ hg branch a
16 $ hg branch a
17 marked working directory as branch a
17 marked working directory as branch a
18 (branches are permanent and global, did you want a bookmark?)
18 (branches are permanent and global, did you want a bookmark?)
19 $ hg ci -Aqm0
19 $ hg ci -Aqm0
20
20
21 $ echo b > b
21 $ echo b > b
22 $ hg branch b
22 $ hg branch b
23 marked working directory as branch b
23 marked working directory as branch b
24 (branches are permanent and global, did you want a bookmark?)
24 (branches are permanent and global, did you want a bookmark?)
25 $ hg ci -Aqm1
25 $ hg ci -Aqm1
26
26
27 $ rm a
27 $ rm a
28 $ hg branch a-b-c-
28 $ hg branch a-b-c-
29 marked working directory as branch a-b-c-
29 marked working directory as branch a-b-c-
30 (branches are permanent and global, did you want a bookmark?)
30 (branches are permanent and global, did you want a bookmark?)
31 $ hg ci -Aqm2 -u Bob
31 $ hg ci -Aqm2 -u Bob
32
32
33 $ hg log -r "extra('branch', 'a-b-c-')" --template '{rev}\n'
33 $ hg log -r "extra('branch', 'a-b-c-')" --template '{rev}\n'
34 2
34 2
35 $ hg log -r "extra('branch')" --template '{rev}\n'
35 $ hg log -r "extra('branch')" --template '{rev}\n'
36 0
36 0
37 1
37 1
38 2
38 2
39 $ hg log -r "extra('branch', 're:a')" --template '{rev} {branch}\n'
39 $ hg log -r "extra('branch', 're:a')" --template '{rev} {branch}\n'
40 0 a
40 0 a
41 2 a-b-c-
41 2 a-b-c-
42
42
43 $ hg co 1
43 $ hg co 1
44 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
44 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
45 $ hg branch +a+b+c+
45 $ hg branch +a+b+c+
46 marked working directory as branch +a+b+c+
46 marked working directory as branch +a+b+c+
47 (branches are permanent and global, did you want a bookmark?)
47 (branches are permanent and global, did you want a bookmark?)
48 $ hg ci -Aqm3
48 $ hg ci -Aqm3
49
49
50 $ hg co 2 # interleave
50 $ hg co 2 # interleave
51 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
51 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
52 $ echo bb > b
52 $ echo bb > b
53 $ hg branch -- -a-b-c-
53 $ hg branch -- -a-b-c-
54 marked working directory as branch -a-b-c-
54 marked working directory as branch -a-b-c-
55 (branches are permanent and global, did you want a bookmark?)
55 (branches are permanent and global, did you want a bookmark?)
56 $ hg ci -Aqm4 -d "May 12 2005"
56 $ hg ci -Aqm4 -d "May 12 2005"
57
57
58 $ hg co 3
58 $ hg co 3
59 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
59 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
60 $ hg branch !a/b/c/
60 $ hg branch !a/b/c/
61 marked working directory as branch !a/b/c/
61 marked working directory as branch !a/b/c/
62 (branches are permanent and global, did you want a bookmark?)
62 (branches are permanent and global, did you want a bookmark?)
63 $ hg ci -Aqm"5 bug"
63 $ hg ci -Aqm"5 bug"
64
64
65 $ hg merge 4
65 $ hg merge 4
66 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
66 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
67 (branch merge, don't forget to commit)
67 (branch merge, don't forget to commit)
68 $ hg branch _a_b_c_
68 $ hg branch _a_b_c_
69 marked working directory as branch _a_b_c_
69 marked working directory as branch _a_b_c_
70 (branches are permanent and global, did you want a bookmark?)
70 (branches are permanent and global, did you want a bookmark?)
71 $ hg ci -Aqm"6 issue619"
71 $ hg ci -Aqm"6 issue619"
72
72
73 $ hg branch .a.b.c.
73 $ hg branch .a.b.c.
74 marked working directory as branch .a.b.c.
74 marked working directory as branch .a.b.c.
75 (branches are permanent and global, did you want a bookmark?)
75 (branches are permanent and global, did you want a bookmark?)
76 $ hg ci -Aqm7
76 $ hg ci -Aqm7
77
77
78 $ hg branch all
78 $ hg branch all
79 marked working directory as branch all
79 marked working directory as branch all
80 (branches are permanent and global, did you want a bookmark?)
80 (branches are permanent and global, did you want a bookmark?)
81
81
82 $ hg co 4
82 $ hg co 4
83 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
83 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
84 $ hg branch Γ©
84 $ hg branch Γ©
85 marked working directory as branch \xc3\xa9 (esc)
85 marked working directory as branch \xc3\xa9 (esc)
86 (branches are permanent and global, did you want a bookmark?)
86 (branches are permanent and global, did you want a bookmark?)
87 $ hg ci -Aqm9
87 $ hg ci -Aqm9
88
88
89 $ hg tag -r6 1.0
89 $ hg tag -r6 1.0
90
90
91 $ hg clone --quiet -U -r 7 . ../remote1
91 $ hg clone --quiet -U -r 7 . ../remote1
92 $ hg clone --quiet -U -r 8 . ../remote2
92 $ hg clone --quiet -U -r 8 . ../remote2
93 $ echo "[paths]" >> .hg/hgrc
93 $ echo "[paths]" >> .hg/hgrc
94 $ echo "default = ../remote1" >> .hg/hgrc
94 $ echo "default = ../remote1" >> .hg/hgrc
95
95
96 names that should work without quoting
96 names that should work without quoting
97
97
98 $ try a
98 $ try a
99 ('symbol', 'a')
99 ('symbol', 'a')
100 0
100 0
101 $ try b-a
101 $ try b-a
102 (minus
102 (minus
103 ('symbol', 'b')
103 ('symbol', 'b')
104 ('symbol', 'a'))
104 ('symbol', 'a'))
105 1
105 1
106 $ try _a_b_c_
106 $ try _a_b_c_
107 ('symbol', '_a_b_c_')
107 ('symbol', '_a_b_c_')
108 6
108 6
109 $ try _a_b_c_-a
109 $ try _a_b_c_-a
110 (minus
110 (minus
111 ('symbol', '_a_b_c_')
111 ('symbol', '_a_b_c_')
112 ('symbol', 'a'))
112 ('symbol', 'a'))
113 6
113 6
114 $ try .a.b.c.
114 $ try .a.b.c.
115 ('symbol', '.a.b.c.')
115 ('symbol', '.a.b.c.')
116 7
116 7
117 $ try .a.b.c.-a
117 $ try .a.b.c.-a
118 (minus
118 (minus
119 ('symbol', '.a.b.c.')
119 ('symbol', '.a.b.c.')
120 ('symbol', 'a'))
120 ('symbol', 'a'))
121 7
121 7
122 $ try -- '-a-b-c-' # complains
122 $ try -- '-a-b-c-' # complains
123 hg: parse error at 7: not a prefix: end
123 hg: parse error at 7: not a prefix: end
124 [255]
124 [255]
125 $ log -a-b-c- # succeeds with fallback
125 $ log -a-b-c- # succeeds with fallback
126 4
126 4
127
127
128 $ try -- -a-b-c--a # complains
128 $ try -- -a-b-c--a # complains
129 (minus
129 (minus
130 (minus
130 (minus
131 (minus
131 (minus
132 (negate
132 (negate
133 ('symbol', 'a'))
133 ('symbol', 'a'))
134 ('symbol', 'b'))
134 ('symbol', 'b'))
135 ('symbol', 'c'))
135 ('symbol', 'c'))
136 (negate
136 (negate
137 ('symbol', 'a')))
137 ('symbol', 'a')))
138 abort: unknown revision '-a'!
138 abort: unknown revision '-a'!
139 [255]
139 [255]
140 $ try Γ©
140 $ try Γ©
141 ('symbol', '\xc3\xa9')
141 ('symbol', '\xc3\xa9')
142 9
142 9
143
143
144 no quoting needed
144 no quoting needed
145
145
146 $ log ::a-b-c-
146 $ log ::a-b-c-
147 0
147 0
148 1
148 1
149 2
149 2
150
150
151 quoting needed
151 quoting needed
152
152
153 $ try '"-a-b-c-"-a'
153 $ try '"-a-b-c-"-a'
154 (minus
154 (minus
155 ('string', '-a-b-c-')
155 ('string', '-a-b-c-')
156 ('symbol', 'a'))
156 ('symbol', 'a'))
157 4
157 4
158
158
159 $ log '1 or 2'
159 $ log '1 or 2'
160 1
160 1
161 2
161 2
162 $ log '1|2'
162 $ log '1|2'
163 1
163 1
164 2
164 2
165 $ log '1 and 2'
165 $ log '1 and 2'
166 $ log '1&2'
166 $ log '1&2'
167 $ try '1&2|3' # precedence - and is higher
167 $ try '1&2|3' # precedence - and is higher
168 (or
168 (or
169 (and
169 (and
170 ('symbol', '1')
170 ('symbol', '1')
171 ('symbol', '2'))
171 ('symbol', '2'))
172 ('symbol', '3'))
172 ('symbol', '3'))
173 3
173 3
174 $ try '1|2&3'
174 $ try '1|2&3'
175 (or
175 (or
176 ('symbol', '1')
176 ('symbol', '1')
177 (and
177 (and
178 ('symbol', '2')
178 ('symbol', '2')
179 ('symbol', '3')))
179 ('symbol', '3')))
180 1
180 1
181 $ try '1&2&3' # associativity
181 $ try '1&2&3' # associativity
182 (and
182 (and
183 (and
183 (and
184 ('symbol', '1')
184 ('symbol', '1')
185 ('symbol', '2'))
185 ('symbol', '2'))
186 ('symbol', '3'))
186 ('symbol', '3'))
187 $ try '1|(2|3)'
187 $ try '1|(2|3)'
188 (or
188 (or
189 ('symbol', '1')
189 ('symbol', '1')
190 (group
190 (group
191 (or
191 (or
192 ('symbol', '2')
192 ('symbol', '2')
193 ('symbol', '3'))))
193 ('symbol', '3'))))
194 1
194 1
195 2
195 2
196 3
196 3
197 $ log '1.0' # tag
197 $ log '1.0' # tag
198 6
198 6
199 $ log 'a' # branch
199 $ log 'a' # branch
200 0
200 0
201 $ log '2785f51ee'
201 $ log '2785f51ee'
202 0
202 0
203 $ log 'date(2005)'
203 $ log 'date(2005)'
204 4
204 4
205 $ log 'date(this is a test)'
205 $ log 'date(this is a test)'
206 hg: parse error at 10: unexpected token: symbol
206 hg: parse error at 10: unexpected token: symbol
207 [255]
207 [255]
208 $ log 'date()'
208 $ log 'date()'
209 hg: parse error: date requires a string
209 hg: parse error: date requires a string
210 [255]
210 [255]
211 $ log 'date'
211 $ log 'date'
212 hg: parse error: can't use date here
212 hg: parse error: can't use date here
213 [255]
213 [255]
214 $ log 'date('
214 $ log 'date('
215 hg: parse error at 5: not a prefix: end
215 hg: parse error at 5: not a prefix: end
216 [255]
216 [255]
217 $ log 'date(tip)'
217 $ log 'date(tip)'
218 abort: invalid date: 'tip'
218 abort: invalid date: 'tip'
219 [255]
219 [255]
220 $ log '"date"'
220 $ log '"date"'
221 abort: unknown revision 'date'!
221 abort: unknown revision 'date'!
222 [255]
222 [255]
223 $ log 'date(2005) and 1::'
223 $ log 'date(2005) and 1::'
224 4
224 4
225
225
226 ancestor can accept 0 or more arguments
226 ancestor can accept 0 or more arguments
227
227
228 $ log 'ancestor()'
228 $ log 'ancestor()'
229 $ log 'ancestor(1)'
229 $ log 'ancestor(1)'
230 1
230 1
231 $ log 'ancestor(4,5)'
231 $ log 'ancestor(4,5)'
232 1
232 1
233 $ log 'ancestor(4,5) and 4'
233 $ log 'ancestor(4,5) and 4'
234 $ log 'ancestor(0,0,1,3)'
234 $ log 'ancestor(0,0,1,3)'
235 0
235 0
236 $ log 'ancestor(3,1,5,3,5,1)'
236 $ log 'ancestor(3,1,5,3,5,1)'
237 1
237 1
238 $ log 'ancestor(0,1,3,5)'
238 $ log 'ancestor(0,1,3,5)'
239 0
239 0
240 $ log 'ancestor(1,2,3,4,5)'
240 $ log 'ancestor(1,2,3,4,5)'
241 1
241 1
242 $ log 'ancestors(5)'
242 $ log 'ancestors(5)'
243 0
243 0
244 1
244 1
245 3
245 3
246 5
246 5
247 $ log 'ancestor(ancestors(5))'
247 $ log 'ancestor(ancestors(5))'
248 0
248 0
249 $ log 'author(bob)'
249 $ log 'author(bob)'
250 2
250 2
251 $ log 'author("re:bob|test")'
251 $ log 'author("re:bob|test")'
252 0
252 0
253 1
253 1
254 2
254 2
255 3
255 3
256 4
256 4
257 5
257 5
258 6
258 6
259 7
259 7
260 8
260 8
261 9
261 9
262 $ log 'branch(Γ©)'
262 $ log 'branch(Γ©)'
263 8
263 8
264 9
264 9
265 $ log 'branch(a)'
265 $ log 'branch(a)'
266 0
266 0
267 $ hg log -r 'branch("re:a")' --template '{rev} {branch}\n'
267 $ hg log -r 'branch("re:a")' --template '{rev} {branch}\n'
268 0 a
268 0 a
269 2 a-b-c-
269 2 a-b-c-
270 3 +a+b+c+
270 3 +a+b+c+
271 4 -a-b-c-
271 4 -a-b-c-
272 5 !a/b/c/
272 5 !a/b/c/
273 6 _a_b_c_
273 6 _a_b_c_
274 7 .a.b.c.
274 7 .a.b.c.
275 $ log 'children(ancestor(4,5))'
275 $ log 'children(ancestor(4,5))'
276 2
276 2
277 3
277 3
278 $ log 'closed()'
278 $ log 'closed()'
279 $ log 'contains(a)'
279 $ log 'contains(a)'
280 0
280 0
281 1
281 1
282 3
282 3
283 5
283 5
284 $ log 'contains("../repo/a")'
284 $ log 'contains("../repo/a")'
285 0
285 0
286 1
286 1
287 3
287 3
288 5
288 5
289 $ log 'desc(B)'
289 $ log 'desc(B)'
290 5
290 5
291 $ log 'descendants(2 or 3)'
291 $ log 'descendants(2 or 3)'
292 2
292 2
293 3
293 3
294 4
294 4
295 5
295 5
296 6
296 6
297 7
297 7
298 8
298 8
299 9
299 9
300 $ log 'file("b*")'
300 $ log 'file("b*")'
301 1
301 1
302 4
302 4
303 $ log 'filelog("b")'
303 $ log 'filelog("b")'
304 1
304 1
305 4
305 4
306 $ log 'filelog("../repo/b")'
306 $ log 'filelog("../repo/b")'
307 1
307 1
308 4
308 4
309 $ log 'follow()'
309 $ log 'follow()'
310 0
310 0
311 1
311 1
312 2
312 2
313 4
313 4
314 8
314 8
315 9
315 9
316 $ log 'grep("issue\d+")'
316 $ log 'grep("issue\d+")'
317 6
317 6
318 $ try 'grep("(")' # invalid regular expression
318 $ try 'grep("(")' # invalid regular expression
319 (func
319 (func
320 ('symbol', 'grep')
320 ('symbol', 'grep')
321 ('string', '('))
321 ('string', '('))
322 hg: parse error: invalid match pattern: unbalanced parenthesis
322 hg: parse error: invalid match pattern: unbalanced parenthesis
323 [255]
323 [255]
324 $ try 'grep("\bissue\d+")'
324 $ try 'grep("\bissue\d+")'
325 (func
325 (func
326 ('symbol', 'grep')
326 ('symbol', 'grep')
327 ('string', '\x08issue\\d+'))
327 ('string', '\x08issue\\d+'))
328 $ try 'grep(r"\bissue\d+")'
328 $ try 'grep(r"\bissue\d+")'
329 (func
329 (func
330 ('symbol', 'grep')
330 ('symbol', 'grep')
331 ('string', '\\bissue\\d+'))
331 ('string', '\\bissue\\d+'))
332 6
332 6
333 $ try 'grep(r"\")'
333 $ try 'grep(r"\")'
334 hg: parse error at 7: unterminated string
334 hg: parse error at 7: unterminated string
335 [255]
335 [255]
336 $ log 'head()'
336 $ log 'head()'
337 0
337 0
338 1
338 1
339 2
339 2
340 3
340 3
341 4
341 4
342 5
342 5
343 6
343 6
344 7
344 7
345 9
345 9
346 $ log 'heads(6::)'
346 $ log 'heads(6::)'
347 7
347 7
348 $ log 'keyword(issue)'
348 $ log 'keyword(issue)'
349 6
349 6
350 $ log 'keyword("test a")'
350 $ log 'keyword("test a")'
351 $ log 'limit(head(), 1)'
351 $ log 'limit(head(), 1)'
352 0
352 0
353 $ log 'matching(6)'
353 $ log 'matching(6)'
354 6
354 6
355 $ log 'matching(6:7, "phase parents user date branch summary files description substate")'
355 $ log 'matching(6:7, "phase parents user date branch summary files description substate")'
356 6
356 6
357 7
357 7
358
358
359 Testing min and max
359 Testing min and max
360
360
361 max: simple
361 max: simple
362
362
363 $ log 'max(contains(a))'
363 $ log 'max(contains(a))'
364 5
364 5
365
365
366 max: simple on unordered set)
366 max: simple on unordered set)
367
367
368 $ log 'max((4+0+2+5+7) and contains(a))'
368 $ log 'max((4+0+2+5+7) and contains(a))'
369 5
369 5
370
370
371 max: no result
371 max: no result
372
372
373 $ log 'max(contains(stringthatdoesnotappearanywhere))'
373 $ log 'max(contains(stringthatdoesnotappearanywhere))'
374
374
375 max: no result on unordered set
375 max: no result on unordered set
376
376
377 $ log 'max((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
377 $ log 'max((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
378
378
379 min: simple
379 min: simple
380
380
381 $ log 'min(contains(a))'
381 $ log 'min(contains(a))'
382 0
382 0
383
383
384 min: simple on unordered set
384 min: simple on unordered set
385
385
386 $ log 'min((4+0+2+5+7) and contains(a))'
386 $ log 'min((4+0+2+5+7) and contains(a))'
387 0
387 0
388
388
389 min: empty
389 min: empty
390
390
391 $ log 'min(contains(stringthatdoesnotappearanywhere))'
391 $ log 'min(contains(stringthatdoesnotappearanywhere))'
392
392
393 min: empty on unordered set
393 min: empty on unordered set
394
394
395 $ log 'min((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
395 $ log 'min((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
396
396
397
397
398 $ log 'merge()'
398 $ log 'merge()'
399 6
399 6
400 $ log 'branchpoint()'
400 $ log 'branchpoint()'
401 1
401 1
402 4
402 4
403 $ log 'modifies(b)'
403 $ log 'modifies(b)'
404 4
404 4
405 $ log 'modifies("path:b")'
405 $ log 'modifies("path:b")'
406 4
406 4
407 $ log 'modifies("*")'
407 $ log 'modifies("*")'
408 4
408 4
409 6
409 6
410 $ log 'modifies("set:modified()")'
410 $ log 'modifies("set:modified()")'
411 4
411 4
412 $ log 'id(5)'
412 $ log 'id(5)'
413 2
413 2
414 $ log 'only(9)'
414 $ log 'only(9)'
415 8
415 8
416 9
416 9
417 $ log 'only(8)'
417 $ log 'only(8)'
418 8
418 8
419 $ log 'only(9, 5)'
419 $ log 'only(9, 5)'
420 2
420 2
421 4
421 4
422 8
422 8
423 9
423 9
424 $ log 'only(7 + 9, 5 + 2)'
424 $ log 'only(7 + 9, 5 + 2)'
425 4
425 4
426 6
426 6
427 7
427 7
428 8
428 8
429 9
429 9
430
430
431 Test empty set input
431 Test empty set input
432 $ log 'only(p2())'
432 $ log 'only(p2())'
433 $ log 'only(p1(), p2())'
433 $ log 'only(p1(), p2())'
434 0
434 0
435 1
435 1
436 2
436 2
437 4
437 4
438 8
438 8
439 9
439 9
440
440
441 Test '%' operator
441 Test '%' operator
442
442
443 $ log '9%'
443 $ log '9%'
444 8
444 8
445 9
445 9
446 $ log '9%5'
446 $ log '9%5'
447 2
447 2
448 4
448 4
449 8
449 8
450 9
450 9
451 $ log '(7 + 9)%(5 + 2)'
451 $ log '(7 + 9)%(5 + 2)'
452 4
452 4
453 6
453 6
454 7
454 7
455 8
455 8
456 9
456 9
457
457
458 Test the order of operations
458 Test the order of operations
459
459
460 $ log '7 + 9%5 + 2'
460 $ log '7 + 9%5 + 2'
461 7
461 7
462 2
462 2
463 4
463 4
464 8
464 8
465 9
465 9
466
466
467 Test explicit numeric revision
467 Test explicit numeric revision
468 $ log 'rev(-2)'
468 $ log 'rev(-2)'
469 $ log 'rev(-1)'
469 $ log 'rev(-1)'
470 -1
470 -1
471 $ log 'rev(0)'
471 $ log 'rev(0)'
472 0
472 0
473 $ log 'rev(9)'
473 $ log 'rev(9)'
474 9
474 9
475 $ log 'rev(10)'
475 $ log 'rev(10)'
476 $ log 'rev(tip)'
476 $ log 'rev(tip)'
477 hg: parse error: rev expects a number
477 hg: parse error: rev expects a number
478 [255]
478 [255]
479
479
480 Test null revision
480 Test null revision
481 $ log '(null)'
481 $ log '(null)'
482 -1
482 -1
483 $ log '(null:0)'
483 $ log '(null:0)'
484 -1
484 -1
485 0
485 0
486 $ log '(0:null)'
486 $ log '(0:null)'
487 0
487 0
488 -1
488 -1
489 $ log 'null::0'
489 $ log 'null::0'
490 -1
490 -1
491 0
491 0
492 $ log 'null:tip - 0:'
492 $ log 'null:tip - 0:'
493 -1
493 -1
494 $ log 'null: and null::' | head -1
494 $ log 'null: and null::' | head -1
495 -1
495 -1
496 $ log 'null: or 0:' | head -2
496 $ log 'null: or 0:' | head -2
497 -1
497 -1
498 0
498 0
499 $ log 'ancestors(null)'
499 $ log 'ancestors(null)'
500 -1
500 -1
501 $ log 'reverse(null:)' | tail -2
501 $ log 'reverse(null:)' | tail -2
502 0
502 0
503 -1
503 -1
504 $ log 'first(null:)'
504 $ log 'first(null:)'
505 -1
505 -1
506 $ log 'min(null:)'
506 $ log 'min(null:)'
507 -1
507 -1
508 $ log 'tip:null and all()' | tail -2
508 $ log 'tip:null and all()' | tail -2
509 1
509 1
510 0
510 0
511
511
512 $ log 'outgoing()'
512 $ log 'outgoing()'
513 8
513 8
514 9
514 9
515 $ log 'outgoing("../remote1")'
515 $ log 'outgoing("../remote1")'
516 8
516 8
517 9
517 9
518 $ log 'outgoing("../remote2")'
518 $ log 'outgoing("../remote2")'
519 3
519 3
520 5
520 5
521 6
521 6
522 7
522 7
523 9
523 9
524 $ log 'p1(merge())'
524 $ log 'p1(merge())'
525 5
525 5
526 $ log 'p2(merge())'
526 $ log 'p2(merge())'
527 4
527 4
528 $ log 'parents(merge())'
528 $ log 'parents(merge())'
529 4
529 4
530 5
530 5
531 $ log 'p1(branchpoint())'
531 $ log 'p1(branchpoint())'
532 0
532 0
533 2
533 2
534 $ log 'p2(branchpoint())'
534 $ log 'p2(branchpoint())'
535 $ log 'parents(branchpoint())'
535 $ log 'parents(branchpoint())'
536 0
536 0
537 2
537 2
538 $ log 'removes(a)'
538 $ log 'removes(a)'
539 2
539 2
540 6
540 6
541 $ log 'roots(all())'
541 $ log 'roots(all())'
542 0
542 0
543 $ log 'reverse(2 or 3 or 4 or 5)'
543 $ log 'reverse(2 or 3 or 4 or 5)'
544 5
544 5
545 4
545 4
546 3
546 3
547 2
547 2
548 $ log 'reverse(all())'
548 $ log 'reverse(all())'
549 9
549 9
550 8
550 8
551 7
551 7
552 6
552 6
553 5
553 5
554 4
554 4
555 3
555 3
556 2
556 2
557 1
557 1
558 0
558 0
559 $ log 'reverse(all()) & filelog(b)'
559 $ log 'reverse(all()) & filelog(b)'
560 4
560 4
561 1
561 1
562 $ log 'rev(5)'
562 $ log 'rev(5)'
563 5
563 5
564 $ log 'sort(limit(reverse(all()), 3))'
564 $ log 'sort(limit(reverse(all()), 3))'
565 7
565 7
566 8
566 8
567 9
567 9
568 $ log 'sort(2 or 3 or 4 or 5, date)'
568 $ log 'sort(2 or 3 or 4 or 5, date)'
569 2
569 2
570 3
570 3
571 5
571 5
572 4
572 4
573 $ log 'tagged()'
573 $ log 'tagged()'
574 6
574 6
575 $ log 'tag()'
575 $ log 'tag()'
576 6
576 6
577 $ log 'tag(1.0)'
577 $ log 'tag(1.0)'
578 6
578 6
579 $ log 'tag(tip)'
579 $ log 'tag(tip)'
580 9
580 9
581
581
582 test sort revset
582 test sort revset
583 --------------------------------------------
583 --------------------------------------------
584
584
585 test when adding two unordered revsets
585 test when adding two unordered revsets
586
586
587 $ log 'sort(keyword(issue) or modifies(b))'
587 $ log 'sort(keyword(issue) or modifies(b))'
588 4
588 4
589 6
589 6
590
590
591 test when sorting a reversed collection in the same way it is
591 test when sorting a reversed collection in the same way it is
592
592
593 $ log 'sort(reverse(all()), -rev)'
593 $ log 'sort(reverse(all()), -rev)'
594 9
594 9
595 8
595 8
596 7
596 7
597 6
597 6
598 5
598 5
599 4
599 4
600 3
600 3
601 2
601 2
602 1
602 1
603 0
603 0
604
604
605 test when sorting a reversed collection
605 test when sorting a reversed collection
606
606
607 $ log 'sort(reverse(all()), rev)'
607 $ log 'sort(reverse(all()), rev)'
608 0
608 0
609 1
609 1
610 2
610 2
611 3
611 3
612 4
612 4
613 5
613 5
614 6
614 6
615 7
615 7
616 8
616 8
617 9
617 9
618
618
619
619
620 test sorting two sorted collections in different orders
620 test sorting two sorted collections in different orders
621
621
622 $ log 'sort(outgoing() or reverse(removes(a)), rev)'
622 $ log 'sort(outgoing() or reverse(removes(a)), rev)'
623 2
623 2
624 6
624 6
625 8
625 8
626 9
626 9
627
627
628 test sorting two sorted collections in different orders backwards
628 test sorting two sorted collections in different orders backwards
629
629
630 $ log 'sort(outgoing() or reverse(removes(a)), -rev)'
630 $ log 'sort(outgoing() or reverse(removes(a)), -rev)'
631 9
631 9
632 8
632 8
633 6
633 6
634 2
634 2
635
635
636 test subtracting something from an addset
636 test subtracting something from an addset
637
637
638 $ log '(outgoing() or removes(a)) - removes(a)'
638 $ log '(outgoing() or removes(a)) - removes(a)'
639 8
639 8
640 9
640 9
641
641
642 test intersecting something with an addset
642 test intersecting something with an addset
643
643
644 $ log 'parents(outgoing() or removes(a))'
644 $ log 'parents(outgoing() or removes(a))'
645 1
645 1
646 4
646 4
647 5
647 5
648 8
648 8
649
649
650 test that `or` operation combines elements in the right order:
650 test that `or` operation combines elements in the right order:
651
651
652 $ log '3:4 or 2:5'
652 $ log '3:4 or 2:5'
653 3
653 3
654 4
654 4
655 2
655 2
656 5
656 5
657 $ log '3:4 or 5:2'
657 $ log '3:4 or 5:2'
658 3
658 3
659 4
659 4
660 5
660 5
661 2
661 2
662 $ log 'sort(3:4 or 2:5)'
662 $ log 'sort(3:4 or 2:5)'
663 2
663 2
664 3
664 3
665 4
665 4
666 5
666 5
667 $ log 'sort(3:4 or 5:2)'
667 $ log 'sort(3:4 or 5:2)'
668 2
668 2
669 3
669 3
670 4
670 4
671 5
671 5
672
672
673 check that conversion to only works
673 check that conversion to only works
674 $ try --optimize '::3 - ::1'
674 $ try --optimize '::3 - ::1'
675 (minus
675 (minus
676 (dagrangepre
676 (dagrangepre
677 ('symbol', '3'))
677 ('symbol', '3'))
678 (dagrangepre
678 (dagrangepre
679 ('symbol', '1')))
679 ('symbol', '1')))
680 * optimized:
680 * optimized:
681 (func
681 (func
682 ('symbol', 'only')
682 ('symbol', 'only')
683 (list
683 (list
684 ('symbol', '3')
684 ('symbol', '3')
685 ('symbol', '1')))
685 ('symbol', '1')))
686 3
686 3
687 $ try --optimize 'ancestors(1) - ancestors(3)'
687 $ try --optimize 'ancestors(1) - ancestors(3)'
688 (minus
688 (minus
689 (func
689 (func
690 ('symbol', 'ancestors')
690 ('symbol', 'ancestors')
691 ('symbol', '1'))
691 ('symbol', '1'))
692 (func
692 (func
693 ('symbol', 'ancestors')
693 ('symbol', 'ancestors')
694 ('symbol', '3')))
694 ('symbol', '3')))
695 * optimized:
695 * optimized:
696 (func
696 (func
697 ('symbol', 'only')
697 ('symbol', 'only')
698 (list
698 (list
699 ('symbol', '1')
699 ('symbol', '1')
700 ('symbol', '3')))
700 ('symbol', '3')))
701 $ try --optimize 'not ::2 and ::6'
701 $ try --optimize 'not ::2 and ::6'
702 (and
702 (and
703 (not
703 (not
704 (dagrangepre
704 (dagrangepre
705 ('symbol', '2')))
705 ('symbol', '2')))
706 (dagrangepre
706 (dagrangepre
707 ('symbol', '6')))
707 ('symbol', '6')))
708 * optimized:
708 * optimized:
709 (func
709 (func
710 ('symbol', 'only')
710 ('symbol', 'only')
711 (list
711 (list
712 ('symbol', '6')
712 ('symbol', '6')
713 ('symbol', '2')))
713 ('symbol', '2')))
714 3
714 3
715 4
715 4
716 5
716 5
717 6
717 6
718 $ try --optimize 'ancestors(6) and not ancestors(4)'
718 $ try --optimize 'ancestors(6) and not ancestors(4)'
719 (and
719 (and
720 (func
720 (func
721 ('symbol', 'ancestors')
721 ('symbol', 'ancestors')
722 ('symbol', '6'))
722 ('symbol', '6'))
723 (not
723 (not
724 (func
724 (func
725 ('symbol', 'ancestors')
725 ('symbol', 'ancestors')
726 ('symbol', '4'))))
726 ('symbol', '4'))))
727 * optimized:
727 * optimized:
728 (func
728 (func
729 ('symbol', 'only')
729 ('symbol', 'only')
730 (list
730 (list
731 ('symbol', '6')
731 ('symbol', '6')
732 ('symbol', '4')))
732 ('symbol', '4')))
733 3
733 3
734 5
734 5
735 6
735 6
736
736
737 we can use patterns when searching for tags
737 we can use patterns when searching for tags
738
738
739 $ log 'tag("1..*")'
739 $ log 'tag("1..*")'
740 abort: tag '1..*' does not exist!
740 abort: tag '1..*' does not exist!
741 [255]
741 [255]
742 $ log 'tag("re:1..*")'
742 $ log 'tag("re:1..*")'
743 6
743 6
744 $ log 'tag("re:[0-9].[0-9]")'
744 $ log 'tag("re:[0-9].[0-9]")'
745 6
745 6
746 $ log 'tag("literal:1.0")'
746 $ log 'tag("literal:1.0")'
747 6
747 6
748 $ log 'tag("re:0..*")'
748 $ log 'tag("re:0..*")'
749
749
750 $ log 'tag(unknown)'
750 $ log 'tag(unknown)'
751 abort: tag 'unknown' does not exist!
751 abort: tag 'unknown' does not exist!
752 [255]
752 [255]
753 $ log 'tag("re:unknown")'
753 $ log 'tag("re:unknown")'
754 $ log 'present(tag("unknown"))'
754 $ log 'present(tag("unknown"))'
755 $ log 'present(tag("re:unknown"))'
755 $ log 'present(tag("re:unknown"))'
756 $ log 'branch(unknown)'
756 $ log 'branch(unknown)'
757 abort: unknown revision 'unknown'!
757 abort: unknown revision 'unknown'!
758 [255]
758 [255]
759 $ log 'branch("re:unknown")'
759 $ log 'branch("re:unknown")'
760 $ log 'present(branch("unknown"))'
760 $ log 'present(branch("unknown"))'
761 $ log 'present(branch("re:unknown"))'
761 $ log 'present(branch("re:unknown"))'
762 $ log 'user(bob)'
762 $ log 'user(bob)'
763 2
763 2
764
764
765 $ log '4::8'
765 $ log '4::8'
766 4
766 4
767 8
767 8
768 $ log '4:8'
768 $ log '4:8'
769 4
769 4
770 5
770 5
771 6
771 6
772 7
772 7
773 8
773 8
774
774
775 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
775 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
776 4
776 4
777 2
777 2
778 5
778 5
779
779
780 $ log 'not 0 and 0:2'
780 $ log 'not 0 and 0:2'
781 1
781 1
782 2
782 2
783 $ log 'not 1 and 0:2'
783 $ log 'not 1 and 0:2'
784 0
784 0
785 2
785 2
786 $ log 'not 2 and 0:2'
786 $ log 'not 2 and 0:2'
787 0
787 0
788 1
788 1
789 $ log '(1 and 2)::'
789 $ log '(1 and 2)::'
790 $ log '(1 and 2):'
790 $ log '(1 and 2):'
791 $ log '(1 and 2):3'
791 $ log '(1 and 2):3'
792 $ log 'sort(head(), -rev)'
792 $ log 'sort(head(), -rev)'
793 9
793 9
794 7
794 7
795 6
795 6
796 5
796 5
797 4
797 4
798 3
798 3
799 2
799 2
800 1
800 1
801 0
801 0
802 $ log '4::8 - 8'
802 $ log '4::8 - 8'
803 4
803 4
804 $ log 'matching(1 or 2 or 3) and (2 or 3 or 1)'
804 $ log 'matching(1 or 2 or 3) and (2 or 3 or 1)'
805 2
805 2
806 3
806 3
807 1
807 1
808
808
809 $ log 'named("unknown")'
809 $ log 'named("unknown")'
810 abort: namespace 'unknown' does not exist!
810 abort: namespace 'unknown' does not exist!
811 [255]
811 [255]
812 $ log 'named("re:unknown")'
812 $ log 'named("re:unknown")'
813 abort: no namespace exists that match 'unknown'!
813 abort: no namespace exists that match 'unknown'!
814 [255]
814 [255]
815 $ log 'present(named("unknown"))'
815 $ log 'present(named("unknown"))'
816 $ log 'present(named("re:unknown"))'
816 $ log 'present(named("re:unknown"))'
817
817
818 $ log 'tag()'
818 $ log 'tag()'
819 6
819 6
820 $ log 'named("tags")'
820 $ log 'named("tags")'
821 6
821 6
822
822
823 issue2437
823 issue2437
824
824
825 $ log '3 and p1(5)'
825 $ log '3 and p1(5)'
826 3
826 3
827 $ log '4 and p2(6)'
827 $ log '4 and p2(6)'
828 4
828 4
829 $ log '1 and parents(:2)'
829 $ log '1 and parents(:2)'
830 1
830 1
831 $ log '2 and children(1:)'
831 $ log '2 and children(1:)'
832 2
832 2
833 $ log 'roots(all()) or roots(all())'
833 $ log 'roots(all()) or roots(all())'
834 0
834 0
835 $ hg debugrevspec 'roots(all()) or roots(all())'
835 $ hg debugrevspec 'roots(all()) or roots(all())'
836 0
836 0
837 $ log 'heads(branch(Γ©)) or heads(branch(Γ©))'
837 $ log 'heads(branch(Γ©)) or heads(branch(Γ©))'
838 9
838 9
839 $ log 'ancestors(8) and (heads(branch("-a-b-c-")) or heads(branch(Γ©)))'
839 $ log 'ancestors(8) and (heads(branch("-a-b-c-")) or heads(branch(Γ©)))'
840 4
840 4
841
841
842 issue2654: report a parse error if the revset was not completely parsed
842 issue2654: report a parse error if the revset was not completely parsed
843
843
844 $ log '1 OR 2'
844 $ log '1 OR 2'
845 hg: parse error at 2: invalid token
845 hg: parse error at 2: invalid token
846 [255]
846 [255]
847
847
848 or operator should preserve ordering:
848 or operator should preserve ordering:
849 $ log 'reverse(2::4) or tip'
849 $ log 'reverse(2::4) or tip'
850 4
850 4
851 2
851 2
852 9
852 9
853
853
854 parentrevspec
854 parentrevspec
855
855
856 $ log 'merge()^0'
856 $ log 'merge()^0'
857 6
857 6
858 $ log 'merge()^'
858 $ log 'merge()^'
859 5
859 5
860 $ log 'merge()^1'
860 $ log 'merge()^1'
861 5
861 5
862 $ log 'merge()^2'
862 $ log 'merge()^2'
863 4
863 4
864 $ log 'merge()^^'
864 $ log 'merge()^^'
865 3
865 3
866 $ log 'merge()^1^'
866 $ log 'merge()^1^'
867 3
867 3
868 $ log 'merge()^^^'
868 $ log 'merge()^^^'
869 1
869 1
870
870
871 $ log 'merge()~0'
871 $ log 'merge()~0'
872 6
872 6
873 $ log 'merge()~1'
873 $ log 'merge()~1'
874 5
874 5
875 $ log 'merge()~2'
875 $ log 'merge()~2'
876 3
876 3
877 $ log 'merge()~2^1'
877 $ log 'merge()~2^1'
878 1
878 1
879 $ log 'merge()~3'
879 $ log 'merge()~3'
880 1
880 1
881
881
882 $ log '(-3:tip)^'
882 $ log '(-3:tip)^'
883 4
883 4
884 6
884 6
885 8
885 8
886
886
887 $ log 'tip^foo'
887 $ log 'tip^foo'
888 hg: parse error: ^ expects a number 0, 1, or 2
888 hg: parse error: ^ expects a number 0, 1, or 2
889 [255]
889 [255]
890
890
891 Bogus function gets suggestions
891 Bogus function gets suggestions
892 $ log 'add()'
892 $ log 'add()'
893 hg: parse error: not a function: add
893 hg: parse error: not a function: add
894 (did you mean 'adds'?)
894 [255]
895 [255]
895 $ log 'added()'
896 $ log 'added()'
896 hg: parse error: not a function: added
897 hg: parse error: not a function: added
898 (did you mean 'adds'?)
897 [255]
899 [255]
898 $ log 'remo()'
900 $ log 'remo()'
899 hg: parse error: not a function: remo
901 hg: parse error: not a function: remo
902 (did you mean one of remote, removes?)
900 [255]
903 [255]
901 $ log 'babar()'
904 $ log 'babar()'
902 hg: parse error: not a function: babar
905 hg: parse error: not a function: babar
903 [255]
906 [255]
904
907
905 multiple revspecs
908 multiple revspecs
906
909
907 $ hg log -r 'tip~1:tip' -r 'tip~2:tip~1' --template '{rev}\n'
910 $ hg log -r 'tip~1:tip' -r 'tip~2:tip~1' --template '{rev}\n'
908 8
911 8
909 9
912 9
910 4
913 4
911 5
914 5
912 6
915 6
913 7
916 7
914
917
915 test usage in revpair (with "+")
918 test usage in revpair (with "+")
916
919
917 (real pair)
920 (real pair)
918
921
919 $ hg diff -r 'tip^^' -r 'tip'
922 $ hg diff -r 'tip^^' -r 'tip'
920 diff -r 2326846efdab -r 24286f4ae135 .hgtags
923 diff -r 2326846efdab -r 24286f4ae135 .hgtags
921 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
924 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
922 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
925 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
923 @@ -0,0 +1,1 @@
926 @@ -0,0 +1,1 @@
924 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
927 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
925 $ hg diff -r 'tip^^::tip'
928 $ hg diff -r 'tip^^::tip'
926 diff -r 2326846efdab -r 24286f4ae135 .hgtags
929 diff -r 2326846efdab -r 24286f4ae135 .hgtags
927 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
930 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
928 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
931 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
929 @@ -0,0 +1,1 @@
932 @@ -0,0 +1,1 @@
930 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
933 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
931
934
932 (single rev)
935 (single rev)
933
936
934 $ hg diff -r 'tip^' -r 'tip^'
937 $ hg diff -r 'tip^' -r 'tip^'
935 $ hg diff -r 'tip^::tip^ or tip^'
938 $ hg diff -r 'tip^::tip^ or tip^'
936
939
937 (single rev that does not looks like a range)
940 (single rev that does not looks like a range)
938
941
939 $ hg diff -r 'tip^ or tip^'
942 $ hg diff -r 'tip^ or tip^'
940 diff -r d5d0dcbdc4d9 .hgtags
943 diff -r d5d0dcbdc4d9 .hgtags
941 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
944 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
942 +++ b/.hgtags * (glob)
945 +++ b/.hgtags * (glob)
943 @@ -0,0 +1,1 @@
946 @@ -0,0 +1,1 @@
944 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
947 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
945
948
946 (no rev)
949 (no rev)
947
950
948 $ hg diff -r 'author("babar") or author("celeste")'
951 $ hg diff -r 'author("babar") or author("celeste")'
949 abort: empty revision range
952 abort: empty revision range
950 [255]
953 [255]
951
954
952 aliases:
955 aliases:
953
956
954 $ echo '[revsetalias]' >> .hg/hgrc
957 $ echo '[revsetalias]' >> .hg/hgrc
955 $ echo 'm = merge()' >> .hg/hgrc
958 $ echo 'm = merge()' >> .hg/hgrc
956 $ echo 'sincem = descendants(m)' >> .hg/hgrc
959 $ echo 'sincem = descendants(m)' >> .hg/hgrc
957 $ echo 'd($1) = reverse(sort($1, date))' >> .hg/hgrc
960 $ echo 'd($1) = reverse(sort($1, date))' >> .hg/hgrc
958 $ echo 'rs(ARG1, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
961 $ echo 'rs(ARG1, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
959 $ echo 'rs4(ARG1, ARGA, ARGB, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
962 $ echo 'rs4(ARG1, ARGA, ARGB, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
960
963
961 $ try m
964 $ try m
962 ('symbol', 'm')
965 ('symbol', 'm')
963 (func
966 (func
964 ('symbol', 'merge')
967 ('symbol', 'merge')
965 None)
968 None)
966 6
969 6
967
970
968 test alias recursion
971 test alias recursion
969
972
970 $ try sincem
973 $ try sincem
971 ('symbol', 'sincem')
974 ('symbol', 'sincem')
972 (func
975 (func
973 ('symbol', 'descendants')
976 ('symbol', 'descendants')
974 (func
977 (func
975 ('symbol', 'merge')
978 ('symbol', 'merge')
976 None))
979 None))
977 6
980 6
978 7
981 7
979
982
980 test infinite recursion
983 test infinite recursion
981
984
982 $ echo 'recurse1 = recurse2' >> .hg/hgrc
985 $ echo 'recurse1 = recurse2' >> .hg/hgrc
983 $ echo 'recurse2 = recurse1' >> .hg/hgrc
986 $ echo 'recurse2 = recurse1' >> .hg/hgrc
984 $ try recurse1
987 $ try recurse1
985 ('symbol', 'recurse1')
988 ('symbol', 'recurse1')
986 hg: parse error: infinite expansion of revset alias "recurse1" detected
989 hg: parse error: infinite expansion of revset alias "recurse1" detected
987 [255]
990 [255]
988
991
989 $ echo 'level1($1, $2) = $1 or $2' >> .hg/hgrc
992 $ echo 'level1($1, $2) = $1 or $2' >> .hg/hgrc
990 $ echo 'level2($1, $2) = level1($2, $1)' >> .hg/hgrc
993 $ echo 'level2($1, $2) = level1($2, $1)' >> .hg/hgrc
991 $ try "level2(level1(1, 2), 3)"
994 $ try "level2(level1(1, 2), 3)"
992 (func
995 (func
993 ('symbol', 'level2')
996 ('symbol', 'level2')
994 (list
997 (list
995 (func
998 (func
996 ('symbol', 'level1')
999 ('symbol', 'level1')
997 (list
1000 (list
998 ('symbol', '1')
1001 ('symbol', '1')
999 ('symbol', '2')))
1002 ('symbol', '2')))
1000 ('symbol', '3')))
1003 ('symbol', '3')))
1001 (or
1004 (or
1002 ('symbol', '3')
1005 ('symbol', '3')
1003 (or
1006 (or
1004 ('symbol', '1')
1007 ('symbol', '1')
1005 ('symbol', '2')))
1008 ('symbol', '2')))
1006 3
1009 3
1007 1
1010 1
1008 2
1011 2
1009
1012
1010 test nesting and variable passing
1013 test nesting and variable passing
1011
1014
1012 $ echo 'nested($1) = nested2($1)' >> .hg/hgrc
1015 $ echo 'nested($1) = nested2($1)' >> .hg/hgrc
1013 $ echo 'nested2($1) = nested3($1)' >> .hg/hgrc
1016 $ echo 'nested2($1) = nested3($1)' >> .hg/hgrc
1014 $ echo 'nested3($1) = max($1)' >> .hg/hgrc
1017 $ echo 'nested3($1) = max($1)' >> .hg/hgrc
1015 $ try 'nested(2:5)'
1018 $ try 'nested(2:5)'
1016 (func
1019 (func
1017 ('symbol', 'nested')
1020 ('symbol', 'nested')
1018 (range
1021 (range
1019 ('symbol', '2')
1022 ('symbol', '2')
1020 ('symbol', '5')))
1023 ('symbol', '5')))
1021 (func
1024 (func
1022 ('symbol', 'max')
1025 ('symbol', 'max')
1023 (range
1026 (range
1024 ('symbol', '2')
1027 ('symbol', '2')
1025 ('symbol', '5')))
1028 ('symbol', '5')))
1026 5
1029 5
1027
1030
1028 test variable isolation, variable placeholders are rewritten as string
1031 test variable isolation, variable placeholders are rewritten as string
1029 then parsed and matched again as string. Check they do not leak too
1032 then parsed and matched again as string. Check they do not leak too
1030 far away.
1033 far away.
1031
1034
1032 $ echo 'injectparamasstring = max("$1")' >> .hg/hgrc
1035 $ echo 'injectparamasstring = max("$1")' >> .hg/hgrc
1033 $ echo 'callinjection($1) = descendants(injectparamasstring)' >> .hg/hgrc
1036 $ echo 'callinjection($1) = descendants(injectparamasstring)' >> .hg/hgrc
1034 $ try 'callinjection(2:5)'
1037 $ try 'callinjection(2:5)'
1035 (func
1038 (func
1036 ('symbol', 'callinjection')
1039 ('symbol', 'callinjection')
1037 (range
1040 (range
1038 ('symbol', '2')
1041 ('symbol', '2')
1039 ('symbol', '5')))
1042 ('symbol', '5')))
1040 (func
1043 (func
1041 ('symbol', 'descendants')
1044 ('symbol', 'descendants')
1042 (func
1045 (func
1043 ('symbol', 'max')
1046 ('symbol', 'max')
1044 ('string', '$1')))
1047 ('string', '$1')))
1045 abort: unknown revision '$1'!
1048 abort: unknown revision '$1'!
1046 [255]
1049 [255]
1047
1050
1048 $ echo 'injectparamasstring2 = max(_aliasarg("$1"))' >> .hg/hgrc
1051 $ echo 'injectparamasstring2 = max(_aliasarg("$1"))' >> .hg/hgrc
1049 $ echo 'callinjection2($1) = descendants(injectparamasstring2)' >> .hg/hgrc
1052 $ echo 'callinjection2($1) = descendants(injectparamasstring2)' >> .hg/hgrc
1050 $ try 'callinjection2(2:5)'
1053 $ try 'callinjection2(2:5)'
1051 (func
1054 (func
1052 ('symbol', 'callinjection2')
1055 ('symbol', 'callinjection2')
1053 (range
1056 (range
1054 ('symbol', '2')
1057 ('symbol', '2')
1055 ('symbol', '5')))
1058 ('symbol', '5')))
1056 abort: failed to parse the definition of revset alias "injectparamasstring2": not a function: _aliasarg
1059 abort: failed to parse the definition of revset alias "injectparamasstring2": not a function: _aliasarg
1057 [255]
1060 [255]
1058 $ hg debugrevspec --debug --config revsetalias.anotherbadone='branch(' "tip"
1061 $ hg debugrevspec --debug --config revsetalias.anotherbadone='branch(' "tip"
1059 ('symbol', 'tip')
1062 ('symbol', 'tip')
1060 warning: failed to parse the definition of revset alias "anotherbadone": at 7: not a prefix: end
1063 warning: failed to parse the definition of revset alias "anotherbadone": at 7: not a prefix: end
1061 warning: failed to parse the definition of revset alias "injectparamasstring2": not a function: _aliasarg
1064 warning: failed to parse the definition of revset alias "injectparamasstring2": not a function: _aliasarg
1062 9
1065 9
1063 >>> data = file('.hg/hgrc', 'rb').read()
1066 >>> data = file('.hg/hgrc', 'rb').read()
1064 >>> file('.hg/hgrc', 'wb').write(data.replace('_aliasarg', ''))
1067 >>> file('.hg/hgrc', 'wb').write(data.replace('_aliasarg', ''))
1065
1068
1066 $ try 'tip'
1069 $ try 'tip'
1067 ('symbol', 'tip')
1070 ('symbol', 'tip')
1068 9
1071 9
1069
1072
1070 $ hg debugrevspec --debug --config revsetalias.'bad name'='tip' "tip"
1073 $ hg debugrevspec --debug --config revsetalias.'bad name'='tip' "tip"
1071 ('symbol', 'tip')
1074 ('symbol', 'tip')
1072 warning: failed to parse the declaration of revset alias "bad name": at 4: invalid token
1075 warning: failed to parse the declaration of revset alias "bad name": at 4: invalid token
1073 9
1076 9
1074 $ echo 'strictreplacing($1, $10) = $10 or desc("$1")' >> .hg/hgrc
1077 $ echo 'strictreplacing($1, $10) = $10 or desc("$1")' >> .hg/hgrc
1075 $ try 'strictreplacing("foo", tip)'
1078 $ try 'strictreplacing("foo", tip)'
1076 (func
1079 (func
1077 ('symbol', 'strictreplacing')
1080 ('symbol', 'strictreplacing')
1078 (list
1081 (list
1079 ('string', 'foo')
1082 ('string', 'foo')
1080 ('symbol', 'tip')))
1083 ('symbol', 'tip')))
1081 (or
1084 (or
1082 ('symbol', 'tip')
1085 ('symbol', 'tip')
1083 (func
1086 (func
1084 ('symbol', 'desc')
1087 ('symbol', 'desc')
1085 ('string', '$1')))
1088 ('string', '$1')))
1086 9
1089 9
1087
1090
1088 $ try 'd(2:5)'
1091 $ try 'd(2:5)'
1089 (func
1092 (func
1090 ('symbol', 'd')
1093 ('symbol', 'd')
1091 (range
1094 (range
1092 ('symbol', '2')
1095 ('symbol', '2')
1093 ('symbol', '5')))
1096 ('symbol', '5')))
1094 (func
1097 (func
1095 ('symbol', 'reverse')
1098 ('symbol', 'reverse')
1096 (func
1099 (func
1097 ('symbol', 'sort')
1100 ('symbol', 'sort')
1098 (list
1101 (list
1099 (range
1102 (range
1100 ('symbol', '2')
1103 ('symbol', '2')
1101 ('symbol', '5'))
1104 ('symbol', '5'))
1102 ('symbol', 'date'))))
1105 ('symbol', 'date'))))
1103 4
1106 4
1104 5
1107 5
1105 3
1108 3
1106 2
1109 2
1107 $ try 'rs(2 or 3, date)'
1110 $ try 'rs(2 or 3, date)'
1108 (func
1111 (func
1109 ('symbol', 'rs')
1112 ('symbol', 'rs')
1110 (list
1113 (list
1111 (or
1114 (or
1112 ('symbol', '2')
1115 ('symbol', '2')
1113 ('symbol', '3'))
1116 ('symbol', '3'))
1114 ('symbol', 'date')))
1117 ('symbol', 'date')))
1115 (func
1118 (func
1116 ('symbol', 'reverse')
1119 ('symbol', 'reverse')
1117 (func
1120 (func
1118 ('symbol', 'sort')
1121 ('symbol', 'sort')
1119 (list
1122 (list
1120 (or
1123 (or
1121 ('symbol', '2')
1124 ('symbol', '2')
1122 ('symbol', '3'))
1125 ('symbol', '3'))
1123 ('symbol', 'date'))))
1126 ('symbol', 'date'))))
1124 3
1127 3
1125 2
1128 2
1126 $ try 'rs()'
1129 $ try 'rs()'
1127 (func
1130 (func
1128 ('symbol', 'rs')
1131 ('symbol', 'rs')
1129 None)
1132 None)
1130 hg: parse error: invalid number of arguments: 0
1133 hg: parse error: invalid number of arguments: 0
1131 [255]
1134 [255]
1132 $ try 'rs(2)'
1135 $ try 'rs(2)'
1133 (func
1136 (func
1134 ('symbol', 'rs')
1137 ('symbol', 'rs')
1135 ('symbol', '2'))
1138 ('symbol', '2'))
1136 hg: parse error: invalid number of arguments: 1
1139 hg: parse error: invalid number of arguments: 1
1137 [255]
1140 [255]
1138 $ try 'rs(2, data, 7)'
1141 $ try 'rs(2, data, 7)'
1139 (func
1142 (func
1140 ('symbol', 'rs')
1143 ('symbol', 'rs')
1141 (list
1144 (list
1142 (list
1145 (list
1143 ('symbol', '2')
1146 ('symbol', '2')
1144 ('symbol', 'data'))
1147 ('symbol', 'data'))
1145 ('symbol', '7')))
1148 ('symbol', '7')))
1146 hg: parse error: invalid number of arguments: 3
1149 hg: parse error: invalid number of arguments: 3
1147 [255]
1150 [255]
1148 $ try 'rs4(2 or 3, x, x, date)'
1151 $ try 'rs4(2 or 3, x, x, date)'
1149 (func
1152 (func
1150 ('symbol', 'rs4')
1153 ('symbol', 'rs4')
1151 (list
1154 (list
1152 (list
1155 (list
1153 (list
1156 (list
1154 (or
1157 (or
1155 ('symbol', '2')
1158 ('symbol', '2')
1156 ('symbol', '3'))
1159 ('symbol', '3'))
1157 ('symbol', 'x'))
1160 ('symbol', 'x'))
1158 ('symbol', 'x'))
1161 ('symbol', 'x'))
1159 ('symbol', 'date')))
1162 ('symbol', 'date')))
1160 (func
1163 (func
1161 ('symbol', 'reverse')
1164 ('symbol', 'reverse')
1162 (func
1165 (func
1163 ('symbol', 'sort')
1166 ('symbol', 'sort')
1164 (list
1167 (list
1165 (or
1168 (or
1166 ('symbol', '2')
1169 ('symbol', '2')
1167 ('symbol', '3'))
1170 ('symbol', '3'))
1168 ('symbol', 'date'))))
1171 ('symbol', 'date'))))
1169 3
1172 3
1170 2
1173 2
1171
1174
1172 issue4553: check that revset aliases override existing hash prefix
1175 issue4553: check that revset aliases override existing hash prefix
1173
1176
1174 $ hg log -qr e
1177 $ hg log -qr e
1175 6:e0cc66ef77e8
1178 6:e0cc66ef77e8
1176
1179
1177 $ hg log -qr e --config revsetalias.e="all()"
1180 $ hg log -qr e --config revsetalias.e="all()"
1178 0:2785f51eece5
1181 0:2785f51eece5
1179 1:d75937da8da0
1182 1:d75937da8da0
1180 2:5ed5505e9f1c
1183 2:5ed5505e9f1c
1181 3:8528aa5637f2
1184 3:8528aa5637f2
1182 4:2326846efdab
1185 4:2326846efdab
1183 5:904fa392b941
1186 5:904fa392b941
1184 6:e0cc66ef77e8
1187 6:e0cc66ef77e8
1185 7:013af1973af4
1188 7:013af1973af4
1186 8:d5d0dcbdc4d9
1189 8:d5d0dcbdc4d9
1187 9:24286f4ae135
1190 9:24286f4ae135
1188
1191
1189 $ hg log -qr e: --config revsetalias.e="0"
1192 $ hg log -qr e: --config revsetalias.e="0"
1190 0:2785f51eece5
1193 0:2785f51eece5
1191 1:d75937da8da0
1194 1:d75937da8da0
1192 2:5ed5505e9f1c
1195 2:5ed5505e9f1c
1193 3:8528aa5637f2
1196 3:8528aa5637f2
1194 4:2326846efdab
1197 4:2326846efdab
1195 5:904fa392b941
1198 5:904fa392b941
1196 6:e0cc66ef77e8
1199 6:e0cc66ef77e8
1197 7:013af1973af4
1200 7:013af1973af4
1198 8:d5d0dcbdc4d9
1201 8:d5d0dcbdc4d9
1199 9:24286f4ae135
1202 9:24286f4ae135
1200
1203
1201 $ hg log -qr :e --config revsetalias.e="9"
1204 $ hg log -qr :e --config revsetalias.e="9"
1202 0:2785f51eece5
1205 0:2785f51eece5
1203 1:d75937da8da0
1206 1:d75937da8da0
1204 2:5ed5505e9f1c
1207 2:5ed5505e9f1c
1205 3:8528aa5637f2
1208 3:8528aa5637f2
1206 4:2326846efdab
1209 4:2326846efdab
1207 5:904fa392b941
1210 5:904fa392b941
1208 6:e0cc66ef77e8
1211 6:e0cc66ef77e8
1209 7:013af1973af4
1212 7:013af1973af4
1210 8:d5d0dcbdc4d9
1213 8:d5d0dcbdc4d9
1211 9:24286f4ae135
1214 9:24286f4ae135
1212
1215
1213 $ hg log -qr e:
1216 $ hg log -qr e:
1214 6:e0cc66ef77e8
1217 6:e0cc66ef77e8
1215 7:013af1973af4
1218 7:013af1973af4
1216 8:d5d0dcbdc4d9
1219 8:d5d0dcbdc4d9
1217 9:24286f4ae135
1220 9:24286f4ae135
1218
1221
1219 $ hg log -qr :e
1222 $ hg log -qr :e
1220 0:2785f51eece5
1223 0:2785f51eece5
1221 1:d75937da8da0
1224 1:d75937da8da0
1222 2:5ed5505e9f1c
1225 2:5ed5505e9f1c
1223 3:8528aa5637f2
1226 3:8528aa5637f2
1224 4:2326846efdab
1227 4:2326846efdab
1225 5:904fa392b941
1228 5:904fa392b941
1226 6:e0cc66ef77e8
1229 6:e0cc66ef77e8
1227
1230
1228 issue2549 - correct optimizations
1231 issue2549 - correct optimizations
1229
1232
1230 $ log 'limit(1 or 2 or 3, 2) and not 2'
1233 $ log 'limit(1 or 2 or 3, 2) and not 2'
1231 1
1234 1
1232 $ log 'max(1 or 2) and not 2'
1235 $ log 'max(1 or 2) and not 2'
1233 $ log 'min(1 or 2) and not 1'
1236 $ log 'min(1 or 2) and not 1'
1234 $ log 'last(1 or 2, 1) and not 2'
1237 $ log 'last(1 or 2, 1) and not 2'
1235
1238
1236 issue4289 - ordering of built-ins
1239 issue4289 - ordering of built-ins
1237 $ hg log -M -q -r 3:2
1240 $ hg log -M -q -r 3:2
1238 3:8528aa5637f2
1241 3:8528aa5637f2
1239 2:5ed5505e9f1c
1242 2:5ed5505e9f1c
1240
1243
1241 test revsets started with 40-chars hash (issue3669)
1244 test revsets started with 40-chars hash (issue3669)
1242
1245
1243 $ ISSUE3669_TIP=`hg tip --template '{node}'`
1246 $ ISSUE3669_TIP=`hg tip --template '{node}'`
1244 $ hg log -r "${ISSUE3669_TIP}" --template '{rev}\n'
1247 $ hg log -r "${ISSUE3669_TIP}" --template '{rev}\n'
1245 9
1248 9
1246 $ hg log -r "${ISSUE3669_TIP}^" --template '{rev}\n'
1249 $ hg log -r "${ISSUE3669_TIP}^" --template '{rev}\n'
1247 8
1250 8
1248
1251
1249 test or-ed indirect predicates (issue3775)
1252 test or-ed indirect predicates (issue3775)
1250
1253
1251 $ log '6 or 6^1' | sort
1254 $ log '6 or 6^1' | sort
1252 5
1255 5
1253 6
1256 6
1254 $ log '6^1 or 6' | sort
1257 $ log '6^1 or 6' | sort
1255 5
1258 5
1256 6
1259 6
1257 $ log '4 or 4~1' | sort
1260 $ log '4 or 4~1' | sort
1258 2
1261 2
1259 4
1262 4
1260 $ log '4~1 or 4' | sort
1263 $ log '4~1 or 4' | sort
1261 2
1264 2
1262 4
1265 4
1263 $ log '(0 or 2):(4 or 6) or 0 or 6' | sort
1266 $ log '(0 or 2):(4 or 6) or 0 or 6' | sort
1264 0
1267 0
1265 1
1268 1
1266 2
1269 2
1267 3
1270 3
1268 4
1271 4
1269 5
1272 5
1270 6
1273 6
1271 $ log '0 or 6 or (0 or 2):(4 or 6)' | sort
1274 $ log '0 or 6 or (0 or 2):(4 or 6)' | sort
1272 0
1275 0
1273 1
1276 1
1274 2
1277 2
1275 3
1278 3
1276 4
1279 4
1277 5
1280 5
1278 6
1281 6
1279
1282
1280 tests for 'remote()' predicate:
1283 tests for 'remote()' predicate:
1281 #. (csets in remote) (id) (remote)
1284 #. (csets in remote) (id) (remote)
1282 1. less than local current branch "default"
1285 1. less than local current branch "default"
1283 2. same with local specified "default"
1286 2. same with local specified "default"
1284 3. more than local specified specified
1287 3. more than local specified specified
1285
1288
1286 $ hg clone --quiet -U . ../remote3
1289 $ hg clone --quiet -U . ../remote3
1287 $ cd ../remote3
1290 $ cd ../remote3
1288 $ hg update -q 7
1291 $ hg update -q 7
1289 $ echo r > r
1292 $ echo r > r
1290 $ hg ci -Aqm 10
1293 $ hg ci -Aqm 10
1291 $ log 'remote()'
1294 $ log 'remote()'
1292 7
1295 7
1293 $ log 'remote("a-b-c-")'
1296 $ log 'remote("a-b-c-")'
1294 2
1297 2
1295 $ cd ../repo
1298 $ cd ../repo
1296 $ log 'remote(".a.b.c.", "../remote3")'
1299 $ log 'remote(".a.b.c.", "../remote3")'
1297
1300
1298 tests for concatenation of strings/symbols by "##"
1301 tests for concatenation of strings/symbols by "##"
1299
1302
1300 $ try "278 ## '5f5' ## 1ee ## 'ce5'"
1303 $ try "278 ## '5f5' ## 1ee ## 'ce5'"
1301 (_concat
1304 (_concat
1302 (_concat
1305 (_concat
1303 (_concat
1306 (_concat
1304 ('symbol', '278')
1307 ('symbol', '278')
1305 ('string', '5f5'))
1308 ('string', '5f5'))
1306 ('symbol', '1ee'))
1309 ('symbol', '1ee'))
1307 ('string', 'ce5'))
1310 ('string', 'ce5'))
1308 ('string', '2785f51eece5')
1311 ('string', '2785f51eece5')
1309 0
1312 0
1310
1313
1311 $ echo 'cat4($1, $2, $3, $4) = $1 ## $2 ## $3 ## $4' >> .hg/hgrc
1314 $ echo 'cat4($1, $2, $3, $4) = $1 ## $2 ## $3 ## $4' >> .hg/hgrc
1312 $ try "cat4(278, '5f5', 1ee, 'ce5')"
1315 $ try "cat4(278, '5f5', 1ee, 'ce5')"
1313 (func
1316 (func
1314 ('symbol', 'cat4')
1317 ('symbol', 'cat4')
1315 (list
1318 (list
1316 (list
1319 (list
1317 (list
1320 (list
1318 ('symbol', '278')
1321 ('symbol', '278')
1319 ('string', '5f5'))
1322 ('string', '5f5'))
1320 ('symbol', '1ee'))
1323 ('symbol', '1ee'))
1321 ('string', 'ce5')))
1324 ('string', 'ce5')))
1322 (_concat
1325 (_concat
1323 (_concat
1326 (_concat
1324 (_concat
1327 (_concat
1325 ('symbol', '278')
1328 ('symbol', '278')
1326 ('string', '5f5'))
1329 ('string', '5f5'))
1327 ('symbol', '1ee'))
1330 ('symbol', '1ee'))
1328 ('string', 'ce5'))
1331 ('string', 'ce5'))
1329 ('string', '2785f51eece5')
1332 ('string', '2785f51eece5')
1330 0
1333 0
1331
1334
1332 (check concatenation in alias nesting)
1335 (check concatenation in alias nesting)
1333
1336
1334 $ echo 'cat2($1, $2) = $1 ## $2' >> .hg/hgrc
1337 $ echo 'cat2($1, $2) = $1 ## $2' >> .hg/hgrc
1335 $ echo 'cat2x2($1, $2, $3, $4) = cat2($1 ## $2, $3 ## $4)' >> .hg/hgrc
1338 $ echo 'cat2x2($1, $2, $3, $4) = cat2($1 ## $2, $3 ## $4)' >> .hg/hgrc
1336 $ log "cat2x2(278, '5f5', 1ee, 'ce5')"
1339 $ log "cat2x2(278, '5f5', 1ee, 'ce5')"
1337 0
1340 0
1338
1341
1339 (check operator priority)
1342 (check operator priority)
1340
1343
1341 $ echo 'cat2n2($1, $2, $3, $4) = $1 ## $2 or $3 ## $4~2' >> .hg/hgrc
1344 $ echo 'cat2n2($1, $2, $3, $4) = $1 ## $2 or $3 ## $4~2' >> .hg/hgrc
1342 $ log "cat2n2(2785f5, 1eece5, 24286f, 4ae135)"
1345 $ log "cat2n2(2785f5, 1eece5, 24286f, 4ae135)"
1343 0
1346 0
1344 4
1347 4
1345
1348
1346 $ cd ..
1349 $ cd ..
1347
1350
1348 test author/desc/keyword in problematic encoding
1351 test author/desc/keyword in problematic encoding
1349 # unicode: cp932:
1352 # unicode: cp932:
1350 # u30A2 0x83 0x41(= 'A')
1353 # u30A2 0x83 0x41(= 'A')
1351 # u30C2 0x83 0x61(= 'a')
1354 # u30C2 0x83 0x61(= 'a')
1352
1355
1353 $ hg init problematicencoding
1356 $ hg init problematicencoding
1354 $ cd problematicencoding
1357 $ cd problematicencoding
1355
1358
1356 $ python > setup.sh <<EOF
1359 $ python > setup.sh <<EOF
1357 > print u'''
1360 > print u'''
1358 > echo a > text
1361 > echo a > text
1359 > hg add text
1362 > hg add text
1360 > hg --encoding utf-8 commit -u '\u30A2' -m none
1363 > hg --encoding utf-8 commit -u '\u30A2' -m none
1361 > echo b > text
1364 > echo b > text
1362 > hg --encoding utf-8 commit -u '\u30C2' -m none
1365 > hg --encoding utf-8 commit -u '\u30C2' -m none
1363 > echo c > text
1366 > echo c > text
1364 > hg --encoding utf-8 commit -u none -m '\u30A2'
1367 > hg --encoding utf-8 commit -u none -m '\u30A2'
1365 > echo d > text
1368 > echo d > text
1366 > hg --encoding utf-8 commit -u none -m '\u30C2'
1369 > hg --encoding utf-8 commit -u none -m '\u30C2'
1367 > '''.encode('utf-8')
1370 > '''.encode('utf-8')
1368 > EOF
1371 > EOF
1369 $ sh < setup.sh
1372 $ sh < setup.sh
1370
1373
1371 test in problematic encoding
1374 test in problematic encoding
1372 $ python > test.sh <<EOF
1375 $ python > test.sh <<EOF
1373 > print u'''
1376 > print u'''
1374 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30A2)'
1377 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30A2)'
1375 > echo ====
1378 > echo ====
1376 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30C2)'
1379 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30C2)'
1377 > echo ====
1380 > echo ====
1378 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30A2)'
1381 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30A2)'
1379 > echo ====
1382 > echo ====
1380 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30C2)'
1383 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30C2)'
1381 > echo ====
1384 > echo ====
1382 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30A2)'
1385 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30A2)'
1383 > echo ====
1386 > echo ====
1384 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30C2)'
1387 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30C2)'
1385 > '''.encode('cp932')
1388 > '''.encode('cp932')
1386 > EOF
1389 > EOF
1387 $ sh < test.sh
1390 $ sh < test.sh
1388 0
1391 0
1389 ====
1392 ====
1390 1
1393 1
1391 ====
1394 ====
1392 2
1395 2
1393 ====
1396 ====
1394 3
1397 3
1395 ====
1398 ====
1396 0
1399 0
1397 2
1400 2
1398 ====
1401 ====
1399 1
1402 1
1400 3
1403 3
1401
1404
1402 $ cd ..
1405 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now