##// END OF EJS Templates
revset: fix order of last() n members where n > 1 (BC)...
Yuya Nishihara -
r32797:573b7928 default
parent child Browse files
Show More
@@ -1,2349 +1,2350 b''
1 # revset.py - revision set queries for mercurial
1 # revset.py - revision set queries for mercurial
2 #
2 #
3 # Copyright 2010 Matt Mackall <mpm@selenic.com>
3 # Copyright 2010 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 __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import heapq
10 import heapq
11 import re
11 import re
12
12
13 from .i18n import _
13 from .i18n import _
14 from . import (
14 from . import (
15 destutil,
15 destutil,
16 encoding,
16 encoding,
17 error,
17 error,
18 hbisect,
18 hbisect,
19 match as matchmod,
19 match as matchmod,
20 node,
20 node,
21 obsolete as obsmod,
21 obsolete as obsmod,
22 pathutil,
22 pathutil,
23 phases,
23 phases,
24 registrar,
24 registrar,
25 repoview,
25 repoview,
26 revsetlang,
26 revsetlang,
27 scmutil,
27 scmutil,
28 smartset,
28 smartset,
29 util,
29 util,
30 )
30 )
31
31
32 # helpers for processing parsed tree
32 # helpers for processing parsed tree
33 getsymbol = revsetlang.getsymbol
33 getsymbol = revsetlang.getsymbol
34 getstring = revsetlang.getstring
34 getstring = revsetlang.getstring
35 getinteger = revsetlang.getinteger
35 getinteger = revsetlang.getinteger
36 getboolean = revsetlang.getboolean
36 getboolean = revsetlang.getboolean
37 getlist = revsetlang.getlist
37 getlist = revsetlang.getlist
38 getrange = revsetlang.getrange
38 getrange = revsetlang.getrange
39 getargs = revsetlang.getargs
39 getargs = revsetlang.getargs
40 getargsdict = revsetlang.getargsdict
40 getargsdict = revsetlang.getargsdict
41
41
42 # constants used as an argument of match() and matchany()
42 # constants used as an argument of match() and matchany()
43 anyorder = revsetlang.anyorder
43 anyorder = revsetlang.anyorder
44 defineorder = revsetlang.defineorder
44 defineorder = revsetlang.defineorder
45 followorder = revsetlang.followorder
45 followorder = revsetlang.followorder
46
46
47 baseset = smartset.baseset
47 baseset = smartset.baseset
48 generatorset = smartset.generatorset
48 generatorset = smartset.generatorset
49 spanset = smartset.spanset
49 spanset = smartset.spanset
50 fullreposet = smartset.fullreposet
50 fullreposet = smartset.fullreposet
51
51
52 def _revancestors(repo, revs, followfirst):
52 def _revancestors(repo, revs, followfirst):
53 """Like revlog.ancestors(), but supports followfirst."""
53 """Like revlog.ancestors(), but supports followfirst."""
54 if followfirst:
54 if followfirst:
55 cut = 1
55 cut = 1
56 else:
56 else:
57 cut = None
57 cut = None
58 cl = repo.changelog
58 cl = repo.changelog
59
59
60 def iterate():
60 def iterate():
61 revs.sort(reverse=True)
61 revs.sort(reverse=True)
62 irevs = iter(revs)
62 irevs = iter(revs)
63 h = []
63 h = []
64
64
65 inputrev = next(irevs, None)
65 inputrev = next(irevs, None)
66 if inputrev is not None:
66 if inputrev is not None:
67 heapq.heappush(h, -inputrev)
67 heapq.heappush(h, -inputrev)
68
68
69 seen = set()
69 seen = set()
70 while h:
70 while h:
71 current = -heapq.heappop(h)
71 current = -heapq.heappop(h)
72 if current == inputrev:
72 if current == inputrev:
73 inputrev = next(irevs, None)
73 inputrev = next(irevs, None)
74 if inputrev is not None:
74 if inputrev is not None:
75 heapq.heappush(h, -inputrev)
75 heapq.heappush(h, -inputrev)
76 if current not in seen:
76 if current not in seen:
77 seen.add(current)
77 seen.add(current)
78 yield current
78 yield current
79 try:
79 try:
80 for parent in cl.parentrevs(current)[:cut]:
80 for parent in cl.parentrevs(current)[:cut]:
81 if parent != node.nullrev:
81 if parent != node.nullrev:
82 heapq.heappush(h, -parent)
82 heapq.heappush(h, -parent)
83 except error.WdirUnsupported:
83 except error.WdirUnsupported:
84 for parent in repo[current].parents()[:cut]:
84 for parent in repo[current].parents()[:cut]:
85 if parent.rev() != node.nullrev:
85 if parent.rev() != node.nullrev:
86 heapq.heappush(h, -parent.rev())
86 heapq.heappush(h, -parent.rev())
87
87
88 return generatorset(iterate(), iterasc=False)
88 return generatorset(iterate(), iterasc=False)
89
89
90 def _revdescendants(repo, revs, followfirst):
90 def _revdescendants(repo, revs, followfirst):
91 """Like revlog.descendants() but supports followfirst."""
91 """Like revlog.descendants() but supports followfirst."""
92 if followfirst:
92 if followfirst:
93 cut = 1
93 cut = 1
94 else:
94 else:
95 cut = None
95 cut = None
96
96
97 def iterate():
97 def iterate():
98 cl = repo.changelog
98 cl = repo.changelog
99 # XXX this should be 'parentset.min()' assuming 'parentset' is a
99 # XXX this should be 'parentset.min()' assuming 'parentset' is a
100 # smartset (and if it is not, it should.)
100 # smartset (and if it is not, it should.)
101 first = min(revs)
101 first = min(revs)
102 nullrev = node.nullrev
102 nullrev = node.nullrev
103 if first == nullrev:
103 if first == nullrev:
104 # Are there nodes with a null first parent and a non-null
104 # Are there nodes with a null first parent and a non-null
105 # second one? Maybe. Do we care? Probably not.
105 # second one? Maybe. Do we care? Probably not.
106 for i in cl:
106 for i in cl:
107 yield i
107 yield i
108 else:
108 else:
109 seen = set(revs)
109 seen = set(revs)
110 for i in cl.revs(first + 1):
110 for i in cl.revs(first + 1):
111 for x in cl.parentrevs(i)[:cut]:
111 for x in cl.parentrevs(i)[:cut]:
112 if x != nullrev and x in seen:
112 if x != nullrev and x in seen:
113 seen.add(i)
113 seen.add(i)
114 yield i
114 yield i
115 break
115 break
116
116
117 return generatorset(iterate(), iterasc=True)
117 return generatorset(iterate(), iterasc=True)
118
118
119 def _reachablerootspure(repo, minroot, roots, heads, includepath):
119 def _reachablerootspure(repo, minroot, roots, heads, includepath):
120 """return (heads(::<roots> and ::<heads>))
120 """return (heads(::<roots> and ::<heads>))
121
121
122 If includepath is True, return (<roots>::<heads>)."""
122 If includepath is True, return (<roots>::<heads>)."""
123 if not roots:
123 if not roots:
124 return []
124 return []
125 parentrevs = repo.changelog.parentrevs
125 parentrevs = repo.changelog.parentrevs
126 roots = set(roots)
126 roots = set(roots)
127 visit = list(heads)
127 visit = list(heads)
128 reachable = set()
128 reachable = set()
129 seen = {}
129 seen = {}
130 # prefetch all the things! (because python is slow)
130 # prefetch all the things! (because python is slow)
131 reached = reachable.add
131 reached = reachable.add
132 dovisit = visit.append
132 dovisit = visit.append
133 nextvisit = visit.pop
133 nextvisit = visit.pop
134 # open-code the post-order traversal due to the tiny size of
134 # open-code the post-order traversal due to the tiny size of
135 # sys.getrecursionlimit()
135 # sys.getrecursionlimit()
136 while visit:
136 while visit:
137 rev = nextvisit()
137 rev = nextvisit()
138 if rev in roots:
138 if rev in roots:
139 reached(rev)
139 reached(rev)
140 if not includepath:
140 if not includepath:
141 continue
141 continue
142 parents = parentrevs(rev)
142 parents = parentrevs(rev)
143 seen[rev] = parents
143 seen[rev] = parents
144 for parent in parents:
144 for parent in parents:
145 if parent >= minroot and parent not in seen:
145 if parent >= minroot and parent not in seen:
146 dovisit(parent)
146 dovisit(parent)
147 if not reachable:
147 if not reachable:
148 return baseset()
148 return baseset()
149 if not includepath:
149 if not includepath:
150 return reachable
150 return reachable
151 for rev in sorted(seen):
151 for rev in sorted(seen):
152 for parent in seen[rev]:
152 for parent in seen[rev]:
153 if parent in reachable:
153 if parent in reachable:
154 reached(rev)
154 reached(rev)
155 return reachable
155 return reachable
156
156
157 def reachableroots(repo, roots, heads, includepath=False):
157 def reachableroots(repo, roots, heads, includepath=False):
158 """return (heads(::<roots> and ::<heads>))
158 """return (heads(::<roots> and ::<heads>))
159
159
160 If includepath is True, return (<roots>::<heads>)."""
160 If includepath is True, return (<roots>::<heads>)."""
161 if not roots:
161 if not roots:
162 return baseset()
162 return baseset()
163 minroot = roots.min()
163 minroot = roots.min()
164 roots = list(roots)
164 roots = list(roots)
165 heads = list(heads)
165 heads = list(heads)
166 try:
166 try:
167 revs = repo.changelog.reachableroots(minroot, heads, roots, includepath)
167 revs = repo.changelog.reachableroots(minroot, heads, roots, includepath)
168 except AttributeError:
168 except AttributeError:
169 revs = _reachablerootspure(repo, minroot, roots, heads, includepath)
169 revs = _reachablerootspure(repo, minroot, roots, heads, includepath)
170 revs = baseset(revs)
170 revs = baseset(revs)
171 revs.sort()
171 revs.sort()
172 return revs
172 return revs
173
173
174 # helpers
174 # helpers
175
175
176 def getset(repo, subset, x):
176 def getset(repo, subset, x):
177 if not x:
177 if not x:
178 raise error.ParseError(_("missing argument"))
178 raise error.ParseError(_("missing argument"))
179 return methods[x[0]](repo, subset, *x[1:])
179 return methods[x[0]](repo, subset, *x[1:])
180
180
181 def _getrevsource(repo, r):
181 def _getrevsource(repo, r):
182 extra = repo[r].extra()
182 extra = repo[r].extra()
183 for label in ('source', 'transplant_source', 'rebase_source'):
183 for label in ('source', 'transplant_source', 'rebase_source'):
184 if label in extra:
184 if label in extra:
185 try:
185 try:
186 return repo[extra[label]].rev()
186 return repo[extra[label]].rev()
187 except error.RepoLookupError:
187 except error.RepoLookupError:
188 pass
188 pass
189 return None
189 return None
190
190
191 # operator methods
191 # operator methods
192
192
193 def stringset(repo, subset, x):
193 def stringset(repo, subset, x):
194 x = scmutil.intrev(repo[x])
194 x = scmutil.intrev(repo[x])
195 if (x in subset
195 if (x in subset
196 or x == node.nullrev and isinstance(subset, fullreposet)):
196 or x == node.nullrev and isinstance(subset, fullreposet)):
197 return baseset([x])
197 return baseset([x])
198 return baseset()
198 return baseset()
199
199
200 def rangeset(repo, subset, x, y, order):
200 def rangeset(repo, subset, x, y, order):
201 m = getset(repo, fullreposet(repo), x)
201 m = getset(repo, fullreposet(repo), x)
202 n = getset(repo, fullreposet(repo), y)
202 n = getset(repo, fullreposet(repo), y)
203
203
204 if not m or not n:
204 if not m or not n:
205 return baseset()
205 return baseset()
206 return _makerangeset(repo, subset, m.first(), n.last(), order)
206 return _makerangeset(repo, subset, m.first(), n.last(), order)
207
207
208 def rangeall(repo, subset, x, order):
208 def rangeall(repo, subset, x, order):
209 assert x is None
209 assert x is None
210 return _makerangeset(repo, subset, 0, len(repo) - 1, order)
210 return _makerangeset(repo, subset, 0, len(repo) - 1, order)
211
211
212 def rangepre(repo, subset, y, order):
212 def rangepre(repo, subset, y, order):
213 # ':y' can't be rewritten to '0:y' since '0' may be hidden
213 # ':y' can't be rewritten to '0:y' since '0' may be hidden
214 n = getset(repo, fullreposet(repo), y)
214 n = getset(repo, fullreposet(repo), y)
215 if not n:
215 if not n:
216 return baseset()
216 return baseset()
217 return _makerangeset(repo, subset, 0, n.last(), order)
217 return _makerangeset(repo, subset, 0, n.last(), order)
218
218
219 def rangepost(repo, subset, x, order):
219 def rangepost(repo, subset, x, order):
220 m = getset(repo, fullreposet(repo), x)
220 m = getset(repo, fullreposet(repo), x)
221 if not m:
221 if not m:
222 return baseset()
222 return baseset()
223 return _makerangeset(repo, subset, m.first(), len(repo) - 1, order)
223 return _makerangeset(repo, subset, m.first(), len(repo) - 1, order)
224
224
225 def _makerangeset(repo, subset, m, n, order):
225 def _makerangeset(repo, subset, m, n, order):
226 if m == n:
226 if m == n:
227 r = baseset([m])
227 r = baseset([m])
228 elif n == node.wdirrev:
228 elif n == node.wdirrev:
229 r = spanset(repo, m, len(repo)) + baseset([n])
229 r = spanset(repo, m, len(repo)) + baseset([n])
230 elif m == node.wdirrev:
230 elif m == node.wdirrev:
231 r = baseset([m]) + spanset(repo, len(repo) - 1, n - 1)
231 r = baseset([m]) + spanset(repo, len(repo) - 1, n - 1)
232 elif m < n:
232 elif m < n:
233 r = spanset(repo, m, n + 1)
233 r = spanset(repo, m, n + 1)
234 else:
234 else:
235 r = spanset(repo, m, n - 1)
235 r = spanset(repo, m, n - 1)
236
236
237 if order == defineorder:
237 if order == defineorder:
238 return r & subset
238 return r & subset
239 else:
239 else:
240 # carrying the sorting over when possible would be more efficient
240 # carrying the sorting over when possible would be more efficient
241 return subset & r
241 return subset & r
242
242
243 def dagrange(repo, subset, x, y, order):
243 def dagrange(repo, subset, x, y, order):
244 r = fullreposet(repo)
244 r = fullreposet(repo)
245 xs = reachableroots(repo, getset(repo, r, x), getset(repo, r, y),
245 xs = reachableroots(repo, getset(repo, r, x), getset(repo, r, y),
246 includepath=True)
246 includepath=True)
247 return subset & xs
247 return subset & xs
248
248
249 def andset(repo, subset, x, y, order):
249 def andset(repo, subset, x, y, order):
250 return getset(repo, getset(repo, subset, x), y)
250 return getset(repo, getset(repo, subset, x), y)
251
251
252 def differenceset(repo, subset, x, y, order):
252 def differenceset(repo, subset, x, y, order):
253 return getset(repo, subset, x) - getset(repo, subset, y)
253 return getset(repo, subset, x) - getset(repo, subset, y)
254
254
255 def _orsetlist(repo, subset, xs):
255 def _orsetlist(repo, subset, xs):
256 assert xs
256 assert xs
257 if len(xs) == 1:
257 if len(xs) == 1:
258 return getset(repo, subset, xs[0])
258 return getset(repo, subset, xs[0])
259 p = len(xs) // 2
259 p = len(xs) // 2
260 a = _orsetlist(repo, subset, xs[:p])
260 a = _orsetlist(repo, subset, xs[:p])
261 b = _orsetlist(repo, subset, xs[p:])
261 b = _orsetlist(repo, subset, xs[p:])
262 return a + b
262 return a + b
263
263
264 def orset(repo, subset, x, order):
264 def orset(repo, subset, x, order):
265 xs = getlist(x)
265 xs = getlist(x)
266 if order == followorder:
266 if order == followorder:
267 # slow path to take the subset order
267 # slow path to take the subset order
268 return subset & _orsetlist(repo, fullreposet(repo), xs)
268 return subset & _orsetlist(repo, fullreposet(repo), xs)
269 else:
269 else:
270 return _orsetlist(repo, subset, xs)
270 return _orsetlist(repo, subset, xs)
271
271
272 def notset(repo, subset, x, order):
272 def notset(repo, subset, x, order):
273 return subset - getset(repo, subset, x)
273 return subset - getset(repo, subset, x)
274
274
275 def listset(repo, subset, *xs):
275 def listset(repo, subset, *xs):
276 raise error.ParseError(_("can't use a list in this context"),
276 raise error.ParseError(_("can't use a list in this context"),
277 hint=_('see hg help "revsets.x or y"'))
277 hint=_('see hg help "revsets.x or y"'))
278
278
279 def keyvaluepair(repo, subset, k, v):
279 def keyvaluepair(repo, subset, k, v):
280 raise error.ParseError(_("can't use a key-value pair in this context"))
280 raise error.ParseError(_("can't use a key-value pair in this context"))
281
281
282 def func(repo, subset, a, b, order):
282 def func(repo, subset, a, b, order):
283 f = getsymbol(a)
283 f = getsymbol(a)
284 if f in symbols:
284 if f in symbols:
285 func = symbols[f]
285 func = symbols[f]
286 if getattr(func, '_takeorder', False):
286 if getattr(func, '_takeorder', False):
287 return func(repo, subset, b, order)
287 return func(repo, subset, b, order)
288 return func(repo, subset, b)
288 return func(repo, subset, b)
289
289
290 keep = lambda fn: getattr(fn, '__doc__', None) is not None
290 keep = lambda fn: getattr(fn, '__doc__', None) is not None
291
291
292 syms = [s for (s, fn) in symbols.items() if keep(fn)]
292 syms = [s for (s, fn) in symbols.items() if keep(fn)]
293 raise error.UnknownIdentifier(f, syms)
293 raise error.UnknownIdentifier(f, syms)
294
294
295 # functions
295 # functions
296
296
297 # symbols are callables like:
297 # symbols are callables like:
298 # fn(repo, subset, x)
298 # fn(repo, subset, x)
299 # with:
299 # with:
300 # repo - current repository instance
300 # repo - current repository instance
301 # subset - of revisions to be examined
301 # subset - of revisions to be examined
302 # x - argument in tree form
302 # x - argument in tree form
303 symbols = {}
303 symbols = {}
304
304
305 # symbols which can't be used for a DoS attack for any given input
305 # symbols which can't be used for a DoS attack for any given input
306 # (e.g. those which accept regexes as plain strings shouldn't be included)
306 # (e.g. those which accept regexes as plain strings shouldn't be included)
307 # functions that just return a lot of changesets (like all) don't count here
307 # functions that just return a lot of changesets (like all) don't count here
308 safesymbols = set()
308 safesymbols = set()
309
309
310 predicate = registrar.revsetpredicate()
310 predicate = registrar.revsetpredicate()
311
311
312 @predicate('_destupdate')
312 @predicate('_destupdate')
313 def _destupdate(repo, subset, x):
313 def _destupdate(repo, subset, x):
314 # experimental revset for update destination
314 # experimental revset for update destination
315 args = getargsdict(x, 'limit', 'clean')
315 args = getargsdict(x, 'limit', 'clean')
316 return subset & baseset([destutil.destupdate(repo, **args)[0]])
316 return subset & baseset([destutil.destupdate(repo, **args)[0]])
317
317
318 @predicate('_destmerge')
318 @predicate('_destmerge')
319 def _destmerge(repo, subset, x):
319 def _destmerge(repo, subset, x):
320 # experimental revset for merge destination
320 # experimental revset for merge destination
321 sourceset = None
321 sourceset = None
322 if x is not None:
322 if x is not None:
323 sourceset = getset(repo, fullreposet(repo), x)
323 sourceset = getset(repo, fullreposet(repo), x)
324 return subset & baseset([destutil.destmerge(repo, sourceset=sourceset)])
324 return subset & baseset([destutil.destmerge(repo, sourceset=sourceset)])
325
325
326 @predicate('adds(pattern)', safe=True)
326 @predicate('adds(pattern)', safe=True)
327 def adds(repo, subset, x):
327 def adds(repo, subset, x):
328 """Changesets that add a file matching pattern.
328 """Changesets that add a file matching pattern.
329
329
330 The pattern without explicit kind like ``glob:`` is expected to be
330 The pattern without explicit kind like ``glob:`` is expected to be
331 relative to the current directory and match against a file or a
331 relative to the current directory and match against a file or a
332 directory.
332 directory.
333 """
333 """
334 # i18n: "adds" is a keyword
334 # i18n: "adds" is a keyword
335 pat = getstring(x, _("adds requires a pattern"))
335 pat = getstring(x, _("adds requires a pattern"))
336 return checkstatus(repo, subset, pat, 1)
336 return checkstatus(repo, subset, pat, 1)
337
337
338 @predicate('ancestor(*changeset)', safe=True)
338 @predicate('ancestor(*changeset)', safe=True)
339 def ancestor(repo, subset, x):
339 def ancestor(repo, subset, x):
340 """A greatest common ancestor of the changesets.
340 """A greatest common ancestor of the changesets.
341
341
342 Accepts 0 or more changesets.
342 Accepts 0 or more changesets.
343 Will return empty list when passed no args.
343 Will return empty list when passed no args.
344 Greatest common ancestor of a single changeset is that changeset.
344 Greatest common ancestor of a single changeset is that changeset.
345 """
345 """
346 # i18n: "ancestor" is a keyword
346 # i18n: "ancestor" is a keyword
347 l = getlist(x)
347 l = getlist(x)
348 rl = fullreposet(repo)
348 rl = fullreposet(repo)
349 anc = None
349 anc = None
350
350
351 # (getset(repo, rl, i) for i in l) generates a list of lists
351 # (getset(repo, rl, i) for i in l) generates a list of lists
352 for revs in (getset(repo, rl, i) for i in l):
352 for revs in (getset(repo, rl, i) for i in l):
353 for r in revs:
353 for r in revs:
354 if anc is None:
354 if anc is None:
355 anc = repo[r]
355 anc = repo[r]
356 else:
356 else:
357 anc = anc.ancestor(repo[r])
357 anc = anc.ancestor(repo[r])
358
358
359 if anc is not None and anc.rev() in subset:
359 if anc is not None and anc.rev() in subset:
360 return baseset([anc.rev()])
360 return baseset([anc.rev()])
361 return baseset()
361 return baseset()
362
362
363 def _ancestors(repo, subset, x, followfirst=False):
363 def _ancestors(repo, subset, x, followfirst=False):
364 heads = getset(repo, fullreposet(repo), x)
364 heads = getset(repo, fullreposet(repo), x)
365 if not heads:
365 if not heads:
366 return baseset()
366 return baseset()
367 s = _revancestors(repo, heads, followfirst)
367 s = _revancestors(repo, heads, followfirst)
368 return subset & s
368 return subset & s
369
369
370 @predicate('ancestors(set)', safe=True)
370 @predicate('ancestors(set)', safe=True)
371 def ancestors(repo, subset, x):
371 def ancestors(repo, subset, x):
372 """Changesets that are ancestors of a changeset in set.
372 """Changesets that are ancestors of a changeset in set.
373 """
373 """
374 return _ancestors(repo, subset, x)
374 return _ancestors(repo, subset, x)
375
375
376 @predicate('_firstancestors', safe=True)
376 @predicate('_firstancestors', safe=True)
377 def _firstancestors(repo, subset, x):
377 def _firstancestors(repo, subset, x):
378 # ``_firstancestors(set)``
378 # ``_firstancestors(set)``
379 # Like ``ancestors(set)`` but follows only the first parents.
379 # Like ``ancestors(set)`` but follows only the first parents.
380 return _ancestors(repo, subset, x, followfirst=True)
380 return _ancestors(repo, subset, x, followfirst=True)
381
381
382 def _childrenspec(repo, subset, x, n, order):
382 def _childrenspec(repo, subset, x, n, order):
383 """Changesets that are the Nth child of a changeset
383 """Changesets that are the Nth child of a changeset
384 in set.
384 in set.
385 """
385 """
386 cs = set()
386 cs = set()
387 for r in getset(repo, fullreposet(repo), x):
387 for r in getset(repo, fullreposet(repo), x):
388 for i in range(n):
388 for i in range(n):
389 c = repo[r].children()
389 c = repo[r].children()
390 if len(c) == 0:
390 if len(c) == 0:
391 break
391 break
392 if len(c) > 1:
392 if len(c) > 1:
393 raise error.RepoLookupError(
393 raise error.RepoLookupError(
394 _("revision in set has more than one child"))
394 _("revision in set has more than one child"))
395 r = c[0]
395 r = c[0]
396 else:
396 else:
397 cs.add(r)
397 cs.add(r)
398 return subset & cs
398 return subset & cs
399
399
400 def ancestorspec(repo, subset, x, n, order):
400 def ancestorspec(repo, subset, x, n, order):
401 """``set~n``
401 """``set~n``
402 Changesets that are the Nth ancestor (first parents only) of a changeset
402 Changesets that are the Nth ancestor (first parents only) of a changeset
403 in set.
403 in set.
404 """
404 """
405 n = getinteger(n, _("~ expects a number"))
405 n = getinteger(n, _("~ expects a number"))
406 if n < 0:
406 if n < 0:
407 # children lookup
407 # children lookup
408 return _childrenspec(repo, subset, x, -n, order)
408 return _childrenspec(repo, subset, x, -n, order)
409 ps = set()
409 ps = set()
410 cl = repo.changelog
410 cl = repo.changelog
411 for r in getset(repo, fullreposet(repo), x):
411 for r in getset(repo, fullreposet(repo), x):
412 for i in range(n):
412 for i in range(n):
413 try:
413 try:
414 r = cl.parentrevs(r)[0]
414 r = cl.parentrevs(r)[0]
415 except error.WdirUnsupported:
415 except error.WdirUnsupported:
416 r = repo[r].parents()[0].rev()
416 r = repo[r].parents()[0].rev()
417 ps.add(r)
417 ps.add(r)
418 return subset & ps
418 return subset & ps
419
419
420 @predicate('author(string)', safe=True)
420 @predicate('author(string)', safe=True)
421 def author(repo, subset, x):
421 def author(repo, subset, x):
422 """Alias for ``user(string)``.
422 """Alias for ``user(string)``.
423 """
423 """
424 # i18n: "author" is a keyword
424 # i18n: "author" is a keyword
425 n = getstring(x, _("author requires a string"))
425 n = getstring(x, _("author requires a string"))
426 kind, pattern, matcher = _substringmatcher(n, casesensitive=False)
426 kind, pattern, matcher = _substringmatcher(n, casesensitive=False)
427 return subset.filter(lambda x: matcher(repo[x].user()),
427 return subset.filter(lambda x: matcher(repo[x].user()),
428 condrepr=('<user %r>', n))
428 condrepr=('<user %r>', n))
429
429
430 @predicate('bisect(string)', safe=True)
430 @predicate('bisect(string)', safe=True)
431 def bisect(repo, subset, x):
431 def bisect(repo, subset, x):
432 """Changesets marked in the specified bisect status:
432 """Changesets marked in the specified bisect status:
433
433
434 - ``good``, ``bad``, ``skip``: csets explicitly marked as good/bad/skip
434 - ``good``, ``bad``, ``skip``: csets explicitly marked as good/bad/skip
435 - ``goods``, ``bads`` : csets topologically good/bad
435 - ``goods``, ``bads`` : csets topologically good/bad
436 - ``range`` : csets taking part in the bisection
436 - ``range`` : csets taking part in the bisection
437 - ``pruned`` : csets that are goods, bads or skipped
437 - ``pruned`` : csets that are goods, bads or skipped
438 - ``untested`` : csets whose fate is yet unknown
438 - ``untested`` : csets whose fate is yet unknown
439 - ``ignored`` : csets ignored due to DAG topology
439 - ``ignored`` : csets ignored due to DAG topology
440 - ``current`` : the cset currently being bisected
440 - ``current`` : the cset currently being bisected
441 """
441 """
442 # i18n: "bisect" is a keyword
442 # i18n: "bisect" is a keyword
443 status = getstring(x, _("bisect requires a string")).lower()
443 status = getstring(x, _("bisect requires a string")).lower()
444 state = set(hbisect.get(repo, status))
444 state = set(hbisect.get(repo, status))
445 return subset & state
445 return subset & state
446
446
447 # Backward-compatibility
447 # Backward-compatibility
448 # - no help entry so that we do not advertise it any more
448 # - no help entry so that we do not advertise it any more
449 @predicate('bisected', safe=True)
449 @predicate('bisected', safe=True)
450 def bisected(repo, subset, x):
450 def bisected(repo, subset, x):
451 return bisect(repo, subset, x)
451 return bisect(repo, subset, x)
452
452
453 @predicate('bookmark([name])', safe=True)
453 @predicate('bookmark([name])', safe=True)
454 def bookmark(repo, subset, x):
454 def bookmark(repo, subset, x):
455 """The named bookmark or all bookmarks.
455 """The named bookmark or all bookmarks.
456
456
457 Pattern matching is supported for `name`. See :hg:`help revisions.patterns`.
457 Pattern matching is supported for `name`. See :hg:`help revisions.patterns`.
458 """
458 """
459 # i18n: "bookmark" is a keyword
459 # i18n: "bookmark" is a keyword
460 args = getargs(x, 0, 1, _('bookmark takes one or no arguments'))
460 args = getargs(x, 0, 1, _('bookmark takes one or no arguments'))
461 if args:
461 if args:
462 bm = getstring(args[0],
462 bm = getstring(args[0],
463 # i18n: "bookmark" is a keyword
463 # i18n: "bookmark" is a keyword
464 _('the argument to bookmark must be a string'))
464 _('the argument to bookmark must be a string'))
465 kind, pattern, matcher = util.stringmatcher(bm)
465 kind, pattern, matcher = util.stringmatcher(bm)
466 bms = set()
466 bms = set()
467 if kind == 'literal':
467 if kind == 'literal':
468 bmrev = repo._bookmarks.get(pattern, None)
468 bmrev = repo._bookmarks.get(pattern, None)
469 if not bmrev:
469 if not bmrev:
470 raise error.RepoLookupError(_("bookmark '%s' does not exist")
470 raise error.RepoLookupError(_("bookmark '%s' does not exist")
471 % pattern)
471 % pattern)
472 bms.add(repo[bmrev].rev())
472 bms.add(repo[bmrev].rev())
473 else:
473 else:
474 matchrevs = set()
474 matchrevs = set()
475 for name, bmrev in repo._bookmarks.iteritems():
475 for name, bmrev in repo._bookmarks.iteritems():
476 if matcher(name):
476 if matcher(name):
477 matchrevs.add(bmrev)
477 matchrevs.add(bmrev)
478 if not matchrevs:
478 if not matchrevs:
479 raise error.RepoLookupError(_("no bookmarks exist"
479 raise error.RepoLookupError(_("no bookmarks exist"
480 " that match '%s'") % pattern)
480 " that match '%s'") % pattern)
481 for bmrev in matchrevs:
481 for bmrev in matchrevs:
482 bms.add(repo[bmrev].rev())
482 bms.add(repo[bmrev].rev())
483 else:
483 else:
484 bms = {repo[r].rev() for r in repo._bookmarks.values()}
484 bms = {repo[r].rev() for r in repo._bookmarks.values()}
485 bms -= {node.nullrev}
485 bms -= {node.nullrev}
486 return subset & bms
486 return subset & bms
487
487
488 @predicate('branch(string or set)', safe=True)
488 @predicate('branch(string or set)', safe=True)
489 def branch(repo, subset, x):
489 def branch(repo, subset, x):
490 """
490 """
491 All changesets belonging to the given branch or the branches of the given
491 All changesets belonging to the given branch or the branches of the given
492 changesets.
492 changesets.
493
493
494 Pattern matching is supported for `string`. See
494 Pattern matching is supported for `string`. See
495 :hg:`help revisions.patterns`.
495 :hg:`help revisions.patterns`.
496 """
496 """
497 getbi = repo.revbranchcache().branchinfo
497 getbi = repo.revbranchcache().branchinfo
498 def getbranch(r):
498 def getbranch(r):
499 try:
499 try:
500 return getbi(r)[0]
500 return getbi(r)[0]
501 except error.WdirUnsupported:
501 except error.WdirUnsupported:
502 return repo[r].branch()
502 return repo[r].branch()
503
503
504 try:
504 try:
505 b = getstring(x, '')
505 b = getstring(x, '')
506 except error.ParseError:
506 except error.ParseError:
507 # not a string, but another revspec, e.g. tip()
507 # not a string, but another revspec, e.g. tip()
508 pass
508 pass
509 else:
509 else:
510 kind, pattern, matcher = util.stringmatcher(b)
510 kind, pattern, matcher = util.stringmatcher(b)
511 if kind == 'literal':
511 if kind == 'literal':
512 # note: falls through to the revspec case if no branch with
512 # note: falls through to the revspec case if no branch with
513 # this name exists and pattern kind is not specified explicitly
513 # this name exists and pattern kind is not specified explicitly
514 if pattern in repo.branchmap():
514 if pattern in repo.branchmap():
515 return subset.filter(lambda r: matcher(getbranch(r)),
515 return subset.filter(lambda r: matcher(getbranch(r)),
516 condrepr=('<branch %r>', b))
516 condrepr=('<branch %r>', b))
517 if b.startswith('literal:'):
517 if b.startswith('literal:'):
518 raise error.RepoLookupError(_("branch '%s' does not exist")
518 raise error.RepoLookupError(_("branch '%s' does not exist")
519 % pattern)
519 % pattern)
520 else:
520 else:
521 return subset.filter(lambda r: matcher(getbranch(r)),
521 return subset.filter(lambda r: matcher(getbranch(r)),
522 condrepr=('<branch %r>', b))
522 condrepr=('<branch %r>', b))
523
523
524 s = getset(repo, fullreposet(repo), x)
524 s = getset(repo, fullreposet(repo), x)
525 b = set()
525 b = set()
526 for r in s:
526 for r in s:
527 b.add(getbranch(r))
527 b.add(getbranch(r))
528 c = s.__contains__
528 c = s.__contains__
529 return subset.filter(lambda r: c(r) or getbranch(r) in b,
529 return subset.filter(lambda r: c(r) or getbranch(r) in b,
530 condrepr=lambda: '<branch %r>' % sorted(b))
530 condrepr=lambda: '<branch %r>' % sorted(b))
531
531
532 @predicate('bumped()', safe=True)
532 @predicate('bumped()', safe=True)
533 def bumped(repo, subset, x):
533 def bumped(repo, subset, x):
534 """Mutable changesets marked as successors of public changesets.
534 """Mutable changesets marked as successors of public changesets.
535
535
536 Only non-public and non-obsolete changesets can be `bumped`.
536 Only non-public and non-obsolete changesets can be `bumped`.
537 """
537 """
538 # i18n: "bumped" is a keyword
538 # i18n: "bumped" is a keyword
539 getargs(x, 0, 0, _("bumped takes no arguments"))
539 getargs(x, 0, 0, _("bumped takes no arguments"))
540 bumped = obsmod.getrevs(repo, 'bumped')
540 bumped = obsmod.getrevs(repo, 'bumped')
541 return subset & bumped
541 return subset & bumped
542
542
543 @predicate('bundle()', safe=True)
543 @predicate('bundle()', safe=True)
544 def bundle(repo, subset, x):
544 def bundle(repo, subset, x):
545 """Changesets in the bundle.
545 """Changesets in the bundle.
546
546
547 Bundle must be specified by the -R option."""
547 Bundle must be specified by the -R option."""
548
548
549 try:
549 try:
550 bundlerevs = repo.changelog.bundlerevs
550 bundlerevs = repo.changelog.bundlerevs
551 except AttributeError:
551 except AttributeError:
552 raise error.Abort(_("no bundle provided - specify with -R"))
552 raise error.Abort(_("no bundle provided - specify with -R"))
553 return subset & bundlerevs
553 return subset & bundlerevs
554
554
555 def checkstatus(repo, subset, pat, field):
555 def checkstatus(repo, subset, pat, field):
556 hasset = matchmod.patkind(pat) == 'set'
556 hasset = matchmod.patkind(pat) == 'set'
557
557
558 mcache = [None]
558 mcache = [None]
559 def matches(x):
559 def matches(x):
560 c = repo[x]
560 c = repo[x]
561 if not mcache[0] or hasset:
561 if not mcache[0] or hasset:
562 mcache[0] = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
562 mcache[0] = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
563 m = mcache[0]
563 m = mcache[0]
564 fname = None
564 fname = None
565 if not m.anypats() and len(m.files()) == 1:
565 if not m.anypats() and len(m.files()) == 1:
566 fname = m.files()[0]
566 fname = m.files()[0]
567 if fname is not None:
567 if fname is not None:
568 if fname not in c.files():
568 if fname not in c.files():
569 return False
569 return False
570 else:
570 else:
571 for f in c.files():
571 for f in c.files():
572 if m(f):
572 if m(f):
573 break
573 break
574 else:
574 else:
575 return False
575 return False
576 files = repo.status(c.p1().node(), c.node())[field]
576 files = repo.status(c.p1().node(), c.node())[field]
577 if fname is not None:
577 if fname is not None:
578 if fname in files:
578 if fname in files:
579 return True
579 return True
580 else:
580 else:
581 for f in files:
581 for f in files:
582 if m(f):
582 if m(f):
583 return True
583 return True
584
584
585 return subset.filter(matches, condrepr=('<status[%r] %r>', field, pat))
585 return subset.filter(matches, condrepr=('<status[%r] %r>', field, pat))
586
586
587 def _children(repo, subset, parentset):
587 def _children(repo, subset, parentset):
588 if not parentset:
588 if not parentset:
589 return baseset()
589 return baseset()
590 cs = set()
590 cs = set()
591 pr = repo.changelog.parentrevs
591 pr = repo.changelog.parentrevs
592 minrev = parentset.min()
592 minrev = parentset.min()
593 nullrev = node.nullrev
593 nullrev = node.nullrev
594 for r in subset:
594 for r in subset:
595 if r <= minrev:
595 if r <= minrev:
596 continue
596 continue
597 p1, p2 = pr(r)
597 p1, p2 = pr(r)
598 if p1 in parentset:
598 if p1 in parentset:
599 cs.add(r)
599 cs.add(r)
600 if p2 != nullrev and p2 in parentset:
600 if p2 != nullrev and p2 in parentset:
601 cs.add(r)
601 cs.add(r)
602 return baseset(cs)
602 return baseset(cs)
603
603
604 @predicate('children(set)', safe=True)
604 @predicate('children(set)', safe=True)
605 def children(repo, subset, x):
605 def children(repo, subset, x):
606 """Child changesets of changesets in set.
606 """Child changesets of changesets in set.
607 """
607 """
608 s = getset(repo, fullreposet(repo), x)
608 s = getset(repo, fullreposet(repo), x)
609 cs = _children(repo, subset, s)
609 cs = _children(repo, subset, s)
610 return subset & cs
610 return subset & cs
611
611
612 @predicate('closed()', safe=True)
612 @predicate('closed()', safe=True)
613 def closed(repo, subset, x):
613 def closed(repo, subset, x):
614 """Changeset is closed.
614 """Changeset is closed.
615 """
615 """
616 # i18n: "closed" is a keyword
616 # i18n: "closed" is a keyword
617 getargs(x, 0, 0, _("closed takes no arguments"))
617 getargs(x, 0, 0, _("closed takes no arguments"))
618 return subset.filter(lambda r: repo[r].closesbranch(),
618 return subset.filter(lambda r: repo[r].closesbranch(),
619 condrepr='<branch closed>')
619 condrepr='<branch closed>')
620
620
621 @predicate('contains(pattern)')
621 @predicate('contains(pattern)')
622 def contains(repo, subset, x):
622 def contains(repo, subset, x):
623 """The revision's manifest contains a file matching pattern (but might not
623 """The revision's manifest contains a file matching pattern (but might not
624 modify it). See :hg:`help patterns` for information about file patterns.
624 modify it). See :hg:`help patterns` for information about file patterns.
625
625
626 The pattern without explicit kind like ``glob:`` is expected to be
626 The pattern without explicit kind like ``glob:`` is expected to be
627 relative to the current directory and match against a file exactly
627 relative to the current directory and match against a file exactly
628 for efficiency.
628 for efficiency.
629 """
629 """
630 # i18n: "contains" is a keyword
630 # i18n: "contains" is a keyword
631 pat = getstring(x, _("contains requires a pattern"))
631 pat = getstring(x, _("contains requires a pattern"))
632
632
633 def matches(x):
633 def matches(x):
634 if not matchmod.patkind(pat):
634 if not matchmod.patkind(pat):
635 pats = pathutil.canonpath(repo.root, repo.getcwd(), pat)
635 pats = pathutil.canonpath(repo.root, repo.getcwd(), pat)
636 if pats in repo[x]:
636 if pats in repo[x]:
637 return True
637 return True
638 else:
638 else:
639 c = repo[x]
639 c = repo[x]
640 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
640 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
641 for f in c.manifest():
641 for f in c.manifest():
642 if m(f):
642 if m(f):
643 return True
643 return True
644 return False
644 return False
645
645
646 return subset.filter(matches, condrepr=('<contains %r>', pat))
646 return subset.filter(matches, condrepr=('<contains %r>', pat))
647
647
648 @predicate('converted([id])', safe=True)
648 @predicate('converted([id])', safe=True)
649 def converted(repo, subset, x):
649 def converted(repo, subset, x):
650 """Changesets converted from the given identifier in the old repository if
650 """Changesets converted from the given identifier in the old repository if
651 present, or all converted changesets if no identifier is specified.
651 present, or all converted changesets if no identifier is specified.
652 """
652 """
653
653
654 # There is exactly no chance of resolving the revision, so do a simple
654 # There is exactly no chance of resolving the revision, so do a simple
655 # string compare and hope for the best
655 # string compare and hope for the best
656
656
657 rev = None
657 rev = None
658 # i18n: "converted" is a keyword
658 # i18n: "converted" is a keyword
659 l = getargs(x, 0, 1, _('converted takes one or no arguments'))
659 l = getargs(x, 0, 1, _('converted takes one or no arguments'))
660 if l:
660 if l:
661 # i18n: "converted" is a keyword
661 # i18n: "converted" is a keyword
662 rev = getstring(l[0], _('converted requires a revision'))
662 rev = getstring(l[0], _('converted requires a revision'))
663
663
664 def _matchvalue(r):
664 def _matchvalue(r):
665 source = repo[r].extra().get('convert_revision', None)
665 source = repo[r].extra().get('convert_revision', None)
666 return source is not None and (rev is None or source.startswith(rev))
666 return source is not None and (rev is None or source.startswith(rev))
667
667
668 return subset.filter(lambda r: _matchvalue(r),
668 return subset.filter(lambda r: _matchvalue(r),
669 condrepr=('<converted %r>', rev))
669 condrepr=('<converted %r>', rev))
670
670
671 @predicate('date(interval)', safe=True)
671 @predicate('date(interval)', safe=True)
672 def date(repo, subset, x):
672 def date(repo, subset, x):
673 """Changesets within the interval, see :hg:`help dates`.
673 """Changesets within the interval, see :hg:`help dates`.
674 """
674 """
675 # i18n: "date" is a keyword
675 # i18n: "date" is a keyword
676 ds = getstring(x, _("date requires a string"))
676 ds = getstring(x, _("date requires a string"))
677 dm = util.matchdate(ds)
677 dm = util.matchdate(ds)
678 return subset.filter(lambda x: dm(repo[x].date()[0]),
678 return subset.filter(lambda x: dm(repo[x].date()[0]),
679 condrepr=('<date %r>', ds))
679 condrepr=('<date %r>', ds))
680
680
681 @predicate('desc(string)', safe=True)
681 @predicate('desc(string)', safe=True)
682 def desc(repo, subset, x):
682 def desc(repo, subset, x):
683 """Search commit message for string. The match is case-insensitive.
683 """Search commit message for string. The match is case-insensitive.
684
684
685 Pattern matching is supported for `string`. See
685 Pattern matching is supported for `string`. See
686 :hg:`help revisions.patterns`.
686 :hg:`help revisions.patterns`.
687 """
687 """
688 # i18n: "desc" is a keyword
688 # i18n: "desc" is a keyword
689 ds = getstring(x, _("desc requires a string"))
689 ds = getstring(x, _("desc requires a string"))
690
690
691 kind, pattern, matcher = _substringmatcher(ds, casesensitive=False)
691 kind, pattern, matcher = _substringmatcher(ds, casesensitive=False)
692
692
693 return subset.filter(lambda r: matcher(repo[r].description()),
693 return subset.filter(lambda r: matcher(repo[r].description()),
694 condrepr=('<desc %r>', ds))
694 condrepr=('<desc %r>', ds))
695
695
696 def _descendants(repo, subset, x, followfirst=False):
696 def _descendants(repo, subset, x, followfirst=False):
697 roots = getset(repo, fullreposet(repo), x)
697 roots = getset(repo, fullreposet(repo), x)
698 if not roots:
698 if not roots:
699 return baseset()
699 return baseset()
700 s = _revdescendants(repo, roots, followfirst)
700 s = _revdescendants(repo, roots, followfirst)
701
701
702 # Both sets need to be ascending in order to lazily return the union
702 # Both sets need to be ascending in order to lazily return the union
703 # in the correct order.
703 # in the correct order.
704 base = subset & roots
704 base = subset & roots
705 desc = subset & s
705 desc = subset & s
706 result = base + desc
706 result = base + desc
707 if subset.isascending():
707 if subset.isascending():
708 result.sort()
708 result.sort()
709 elif subset.isdescending():
709 elif subset.isdescending():
710 result.sort(reverse=True)
710 result.sort(reverse=True)
711 else:
711 else:
712 result = subset & result
712 result = subset & result
713 return result
713 return result
714
714
715 @predicate('descendants(set)', safe=True)
715 @predicate('descendants(set)', safe=True)
716 def descendants(repo, subset, x):
716 def descendants(repo, subset, x):
717 """Changesets which are descendants of changesets in set.
717 """Changesets which are descendants of changesets in set.
718 """
718 """
719 return _descendants(repo, subset, x)
719 return _descendants(repo, subset, x)
720
720
721 @predicate('_firstdescendants', safe=True)
721 @predicate('_firstdescendants', safe=True)
722 def _firstdescendants(repo, subset, x):
722 def _firstdescendants(repo, subset, x):
723 # ``_firstdescendants(set)``
723 # ``_firstdescendants(set)``
724 # Like ``descendants(set)`` but follows only the first parents.
724 # Like ``descendants(set)`` but follows only the first parents.
725 return _descendants(repo, subset, x, followfirst=True)
725 return _descendants(repo, subset, x, followfirst=True)
726
726
727 @predicate('destination([set])', safe=True)
727 @predicate('destination([set])', safe=True)
728 def destination(repo, subset, x):
728 def destination(repo, subset, x):
729 """Changesets that were created by a graft, transplant or rebase operation,
729 """Changesets that were created by a graft, transplant or rebase operation,
730 with the given revisions specified as the source. Omitting the optional set
730 with the given revisions specified as the source. Omitting the optional set
731 is the same as passing all().
731 is the same as passing all().
732 """
732 """
733 if x is not None:
733 if x is not None:
734 sources = getset(repo, fullreposet(repo), x)
734 sources = getset(repo, fullreposet(repo), x)
735 else:
735 else:
736 sources = fullreposet(repo)
736 sources = fullreposet(repo)
737
737
738 dests = set()
738 dests = set()
739
739
740 # subset contains all of the possible destinations that can be returned, so
740 # subset contains all of the possible destinations that can be returned, so
741 # iterate over them and see if their source(s) were provided in the arg set.
741 # iterate over them and see if their source(s) were provided in the arg set.
742 # Even if the immediate src of r is not in the arg set, src's source (or
742 # Even if the immediate src of r is not in the arg set, src's source (or
743 # further back) may be. Scanning back further than the immediate src allows
743 # further back) may be. Scanning back further than the immediate src allows
744 # transitive transplants and rebases to yield the same results as transitive
744 # transitive transplants and rebases to yield the same results as transitive
745 # grafts.
745 # grafts.
746 for r in subset:
746 for r in subset:
747 src = _getrevsource(repo, r)
747 src = _getrevsource(repo, r)
748 lineage = None
748 lineage = None
749
749
750 while src is not None:
750 while src is not None:
751 if lineage is None:
751 if lineage is None:
752 lineage = list()
752 lineage = list()
753
753
754 lineage.append(r)
754 lineage.append(r)
755
755
756 # The visited lineage is a match if the current source is in the arg
756 # The visited lineage is a match if the current source is in the arg
757 # set. Since every candidate dest is visited by way of iterating
757 # set. Since every candidate dest is visited by way of iterating
758 # subset, any dests further back in the lineage will be tested by a
758 # subset, any dests further back in the lineage will be tested by a
759 # different iteration over subset. Likewise, if the src was already
759 # different iteration over subset. Likewise, if the src was already
760 # selected, the current lineage can be selected without going back
760 # selected, the current lineage can be selected without going back
761 # further.
761 # further.
762 if src in sources or src in dests:
762 if src in sources or src in dests:
763 dests.update(lineage)
763 dests.update(lineage)
764 break
764 break
765
765
766 r = src
766 r = src
767 src = _getrevsource(repo, r)
767 src = _getrevsource(repo, r)
768
768
769 return subset.filter(dests.__contains__,
769 return subset.filter(dests.__contains__,
770 condrepr=lambda: '<destination %r>' % sorted(dests))
770 condrepr=lambda: '<destination %r>' % sorted(dests))
771
771
772 @predicate('divergent()', safe=True)
772 @predicate('divergent()', safe=True)
773 def divergent(repo, subset, x):
773 def divergent(repo, subset, x):
774 """
774 """
775 Final successors of changesets with an alternative set of final successors.
775 Final successors of changesets with an alternative set of final successors.
776 """
776 """
777 # i18n: "divergent" is a keyword
777 # i18n: "divergent" is a keyword
778 getargs(x, 0, 0, _("divergent takes no arguments"))
778 getargs(x, 0, 0, _("divergent takes no arguments"))
779 divergent = obsmod.getrevs(repo, 'divergent')
779 divergent = obsmod.getrevs(repo, 'divergent')
780 return subset & divergent
780 return subset & divergent
781
781
782 @predicate('extinct()', safe=True)
782 @predicate('extinct()', safe=True)
783 def extinct(repo, subset, x):
783 def extinct(repo, subset, x):
784 """Obsolete changesets with obsolete descendants only.
784 """Obsolete changesets with obsolete descendants only.
785 """
785 """
786 # i18n: "extinct" is a keyword
786 # i18n: "extinct" is a keyword
787 getargs(x, 0, 0, _("extinct takes no arguments"))
787 getargs(x, 0, 0, _("extinct takes no arguments"))
788 extincts = obsmod.getrevs(repo, 'extinct')
788 extincts = obsmod.getrevs(repo, 'extinct')
789 return subset & extincts
789 return subset & extincts
790
790
791 @predicate('extra(label, [value])', safe=True)
791 @predicate('extra(label, [value])', safe=True)
792 def extra(repo, subset, x):
792 def extra(repo, subset, x):
793 """Changesets with the given label in the extra metadata, with the given
793 """Changesets with the given label in the extra metadata, with the given
794 optional value.
794 optional value.
795
795
796 Pattern matching is supported for `value`. See
796 Pattern matching is supported for `value`. See
797 :hg:`help revisions.patterns`.
797 :hg:`help revisions.patterns`.
798 """
798 """
799 args = getargsdict(x, 'extra', 'label value')
799 args = getargsdict(x, 'extra', 'label value')
800 if 'label' not in args:
800 if 'label' not in args:
801 # i18n: "extra" is a keyword
801 # i18n: "extra" is a keyword
802 raise error.ParseError(_('extra takes at least 1 argument'))
802 raise error.ParseError(_('extra takes at least 1 argument'))
803 # i18n: "extra" is a keyword
803 # i18n: "extra" is a keyword
804 label = getstring(args['label'], _('first argument to extra must be '
804 label = getstring(args['label'], _('first argument to extra must be '
805 'a string'))
805 'a string'))
806 value = None
806 value = None
807
807
808 if 'value' in args:
808 if 'value' in args:
809 # i18n: "extra" is a keyword
809 # i18n: "extra" is a keyword
810 value = getstring(args['value'], _('second argument to extra must be '
810 value = getstring(args['value'], _('second argument to extra must be '
811 'a string'))
811 'a string'))
812 kind, value, matcher = util.stringmatcher(value)
812 kind, value, matcher = util.stringmatcher(value)
813
813
814 def _matchvalue(r):
814 def _matchvalue(r):
815 extra = repo[r].extra()
815 extra = repo[r].extra()
816 return label in extra and (value is None or matcher(extra[label]))
816 return label in extra and (value is None or matcher(extra[label]))
817
817
818 return subset.filter(lambda r: _matchvalue(r),
818 return subset.filter(lambda r: _matchvalue(r),
819 condrepr=('<extra[%r] %r>', label, value))
819 condrepr=('<extra[%r] %r>', label, value))
820
820
821 @predicate('filelog(pattern)', safe=True)
821 @predicate('filelog(pattern)', safe=True)
822 def filelog(repo, subset, x):
822 def filelog(repo, subset, x):
823 """Changesets connected to the specified filelog.
823 """Changesets connected to the specified filelog.
824
824
825 For performance reasons, visits only revisions mentioned in the file-level
825 For performance reasons, visits only revisions mentioned in the file-level
826 filelog, rather than filtering through all changesets (much faster, but
826 filelog, rather than filtering through all changesets (much faster, but
827 doesn't include deletes or duplicate changes). For a slower, more accurate
827 doesn't include deletes or duplicate changes). For a slower, more accurate
828 result, use ``file()``.
828 result, use ``file()``.
829
829
830 The pattern without explicit kind like ``glob:`` is expected to be
830 The pattern without explicit kind like ``glob:`` is expected to be
831 relative to the current directory and match against a file exactly
831 relative to the current directory and match against a file exactly
832 for efficiency.
832 for efficiency.
833
833
834 If some linkrev points to revisions filtered by the current repoview, we'll
834 If some linkrev points to revisions filtered by the current repoview, we'll
835 work around it to return a non-filtered value.
835 work around it to return a non-filtered value.
836 """
836 """
837
837
838 # i18n: "filelog" is a keyword
838 # i18n: "filelog" is a keyword
839 pat = getstring(x, _("filelog requires a pattern"))
839 pat = getstring(x, _("filelog requires a pattern"))
840 s = set()
840 s = set()
841 cl = repo.changelog
841 cl = repo.changelog
842
842
843 if not matchmod.patkind(pat):
843 if not matchmod.patkind(pat):
844 f = pathutil.canonpath(repo.root, repo.getcwd(), pat)
844 f = pathutil.canonpath(repo.root, repo.getcwd(), pat)
845 files = [f]
845 files = [f]
846 else:
846 else:
847 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=repo[None])
847 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=repo[None])
848 files = (f for f in repo[None] if m(f))
848 files = (f for f in repo[None] if m(f))
849
849
850 for f in files:
850 for f in files:
851 fl = repo.file(f)
851 fl = repo.file(f)
852 known = {}
852 known = {}
853 scanpos = 0
853 scanpos = 0
854 for fr in list(fl):
854 for fr in list(fl):
855 fn = fl.node(fr)
855 fn = fl.node(fr)
856 if fn in known:
856 if fn in known:
857 s.add(known[fn])
857 s.add(known[fn])
858 continue
858 continue
859
859
860 lr = fl.linkrev(fr)
860 lr = fl.linkrev(fr)
861 if lr in cl:
861 if lr in cl:
862 s.add(lr)
862 s.add(lr)
863 elif scanpos is not None:
863 elif scanpos is not None:
864 # lowest matching changeset is filtered, scan further
864 # lowest matching changeset is filtered, scan further
865 # ahead in changelog
865 # ahead in changelog
866 start = max(lr, scanpos) + 1
866 start = max(lr, scanpos) + 1
867 scanpos = None
867 scanpos = None
868 for r in cl.revs(start):
868 for r in cl.revs(start):
869 # minimize parsing of non-matching entries
869 # minimize parsing of non-matching entries
870 if f in cl.revision(r) and f in cl.readfiles(r):
870 if f in cl.revision(r) and f in cl.readfiles(r):
871 try:
871 try:
872 # try to use manifest delta fastpath
872 # try to use manifest delta fastpath
873 n = repo[r].filenode(f)
873 n = repo[r].filenode(f)
874 if n not in known:
874 if n not in known:
875 if n == fn:
875 if n == fn:
876 s.add(r)
876 s.add(r)
877 scanpos = r
877 scanpos = r
878 break
878 break
879 else:
879 else:
880 known[n] = r
880 known[n] = r
881 except error.ManifestLookupError:
881 except error.ManifestLookupError:
882 # deletion in changelog
882 # deletion in changelog
883 continue
883 continue
884
884
885 return subset & s
885 return subset & s
886
886
887 @predicate('first(set, [n])', safe=True)
887 @predicate('first(set, [n])', safe=True)
888 def first(repo, subset, x):
888 def first(repo, subset, x):
889 """An alias for limit().
889 """An alias for limit().
890 """
890 """
891 return limit(repo, subset, x)
891 return limit(repo, subset, x)
892
892
893 def _follow(repo, subset, x, name, followfirst=False):
893 def _follow(repo, subset, x, name, followfirst=False):
894 l = getargs(x, 0, 2, _("%s takes no arguments or a pattern "
894 l = getargs(x, 0, 2, _("%s takes no arguments or a pattern "
895 "and an optional revset") % name)
895 "and an optional revset") % name)
896 c = repo['.']
896 c = repo['.']
897 if l:
897 if l:
898 x = getstring(l[0], _("%s expected a pattern") % name)
898 x = getstring(l[0], _("%s expected a pattern") % name)
899 rev = None
899 rev = None
900 if len(l) >= 2:
900 if len(l) >= 2:
901 revs = getset(repo, fullreposet(repo), l[1])
901 revs = getset(repo, fullreposet(repo), l[1])
902 if len(revs) != 1:
902 if len(revs) != 1:
903 raise error.RepoLookupError(
903 raise error.RepoLookupError(
904 _("%s expected one starting revision") % name)
904 _("%s expected one starting revision") % name)
905 rev = revs.last()
905 rev = revs.last()
906 c = repo[rev]
906 c = repo[rev]
907 matcher = matchmod.match(repo.root, repo.getcwd(), [x],
907 matcher = matchmod.match(repo.root, repo.getcwd(), [x],
908 ctx=repo[rev], default='path')
908 ctx=repo[rev], default='path')
909
909
910 files = c.manifest().walk(matcher)
910 files = c.manifest().walk(matcher)
911
911
912 s = set()
912 s = set()
913 for fname in files:
913 for fname in files:
914 fctx = c[fname]
914 fctx = c[fname]
915 s = s.union(set(c.rev() for c in fctx.ancestors(followfirst)))
915 s = s.union(set(c.rev() for c in fctx.ancestors(followfirst)))
916 # include the revision responsible for the most recent version
916 # include the revision responsible for the most recent version
917 s.add(fctx.introrev())
917 s.add(fctx.introrev())
918 else:
918 else:
919 s = _revancestors(repo, baseset([c.rev()]), followfirst)
919 s = _revancestors(repo, baseset([c.rev()]), followfirst)
920
920
921 return subset & s
921 return subset & s
922
922
923 @predicate('follow([pattern[, startrev]])', safe=True)
923 @predicate('follow([pattern[, startrev]])', safe=True)
924 def follow(repo, subset, x):
924 def follow(repo, subset, x):
925 """
925 """
926 An alias for ``::.`` (ancestors of the working directory's first parent).
926 An alias for ``::.`` (ancestors of the working directory's first parent).
927 If pattern is specified, the histories of files matching given
927 If pattern is specified, the histories of files matching given
928 pattern in the revision given by startrev are followed, including copies.
928 pattern in the revision given by startrev are followed, including copies.
929 """
929 """
930 return _follow(repo, subset, x, 'follow')
930 return _follow(repo, subset, x, 'follow')
931
931
932 @predicate('_followfirst', safe=True)
932 @predicate('_followfirst', safe=True)
933 def _followfirst(repo, subset, x):
933 def _followfirst(repo, subset, x):
934 # ``followfirst([pattern[, startrev]])``
934 # ``followfirst([pattern[, startrev]])``
935 # Like ``follow([pattern[, startrev]])`` but follows only the first parent
935 # Like ``follow([pattern[, startrev]])`` but follows only the first parent
936 # of every revisions or files revisions.
936 # of every revisions or files revisions.
937 return _follow(repo, subset, x, '_followfirst', followfirst=True)
937 return _follow(repo, subset, x, '_followfirst', followfirst=True)
938
938
939 @predicate('followlines(file, fromline:toline[, startrev=., descend=False])',
939 @predicate('followlines(file, fromline:toline[, startrev=., descend=False])',
940 safe=True)
940 safe=True)
941 def followlines(repo, subset, x):
941 def followlines(repo, subset, x):
942 """Changesets modifying `file` in line range ('fromline', 'toline').
942 """Changesets modifying `file` in line range ('fromline', 'toline').
943
943
944 Line range corresponds to 'file' content at 'startrev' and should hence be
944 Line range corresponds to 'file' content at 'startrev' and should hence be
945 consistent with file size. If startrev is not specified, working directory's
945 consistent with file size. If startrev is not specified, working directory's
946 parent is used.
946 parent is used.
947
947
948 By default, ancestors of 'startrev' are returned. If 'descend' is True,
948 By default, ancestors of 'startrev' are returned. If 'descend' is True,
949 descendants of 'startrev' are returned though renames are (currently) not
949 descendants of 'startrev' are returned though renames are (currently) not
950 followed in this direction.
950 followed in this direction.
951 """
951 """
952 from . import context # avoid circular import issues
952 from . import context # avoid circular import issues
953
953
954 args = getargsdict(x, 'followlines', 'file *lines startrev descend')
954 args = getargsdict(x, 'followlines', 'file *lines startrev descend')
955 if len(args['lines']) != 1:
955 if len(args['lines']) != 1:
956 raise error.ParseError(_("followlines requires a line range"))
956 raise error.ParseError(_("followlines requires a line range"))
957
957
958 rev = '.'
958 rev = '.'
959 if 'startrev' in args:
959 if 'startrev' in args:
960 revs = getset(repo, fullreposet(repo), args['startrev'])
960 revs = getset(repo, fullreposet(repo), args['startrev'])
961 if len(revs) != 1:
961 if len(revs) != 1:
962 raise error.ParseError(
962 raise error.ParseError(
963 # i18n: "followlines" is a keyword
963 # i18n: "followlines" is a keyword
964 _("followlines expects exactly one revision"))
964 _("followlines expects exactly one revision"))
965 rev = revs.last()
965 rev = revs.last()
966
966
967 pat = getstring(args['file'], _("followlines requires a pattern"))
967 pat = getstring(args['file'], _("followlines requires a pattern"))
968 if not matchmod.patkind(pat):
968 if not matchmod.patkind(pat):
969 fname = pathutil.canonpath(repo.root, repo.getcwd(), pat)
969 fname = pathutil.canonpath(repo.root, repo.getcwd(), pat)
970 else:
970 else:
971 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=repo[rev])
971 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=repo[rev])
972 files = [f for f in repo[rev] if m(f)]
972 files = [f for f in repo[rev] if m(f)]
973 if len(files) != 1:
973 if len(files) != 1:
974 # i18n: "followlines" is a keyword
974 # i18n: "followlines" is a keyword
975 raise error.ParseError(_("followlines expects exactly one file"))
975 raise error.ParseError(_("followlines expects exactly one file"))
976 fname = files[0]
976 fname = files[0]
977
977
978 # i18n: "followlines" is a keyword
978 # i18n: "followlines" is a keyword
979 lr = getrange(args['lines'][0], _("followlines expects a line range"))
979 lr = getrange(args['lines'][0], _("followlines expects a line range"))
980 fromline, toline = [getinteger(a, _("line range bounds must be integers"))
980 fromline, toline = [getinteger(a, _("line range bounds must be integers"))
981 for a in lr]
981 for a in lr]
982 fromline, toline = util.processlinerange(fromline, toline)
982 fromline, toline = util.processlinerange(fromline, toline)
983
983
984 fctx = repo[rev].filectx(fname)
984 fctx = repo[rev].filectx(fname)
985 descend = False
985 descend = False
986 if 'descend' in args:
986 if 'descend' in args:
987 descend = getboolean(args['descend'],
987 descend = getboolean(args['descend'],
988 # i18n: "descend" is a keyword
988 # i18n: "descend" is a keyword
989 _("descend argument must be a boolean"))
989 _("descend argument must be a boolean"))
990 if descend:
990 if descend:
991 rs = generatorset(
991 rs = generatorset(
992 (c.rev() for c, _linerange
992 (c.rev() for c, _linerange
993 in context.blockdescendants(fctx, fromline, toline)),
993 in context.blockdescendants(fctx, fromline, toline)),
994 iterasc=True)
994 iterasc=True)
995 else:
995 else:
996 rs = generatorset(
996 rs = generatorset(
997 (c.rev() for c, _linerange
997 (c.rev() for c, _linerange
998 in context.blockancestors(fctx, fromline, toline)),
998 in context.blockancestors(fctx, fromline, toline)),
999 iterasc=False)
999 iterasc=False)
1000 return subset & rs
1000 return subset & rs
1001
1001
1002 @predicate('all()', safe=True)
1002 @predicate('all()', safe=True)
1003 def getall(repo, subset, x):
1003 def getall(repo, subset, x):
1004 """All changesets, the same as ``0:tip``.
1004 """All changesets, the same as ``0:tip``.
1005 """
1005 """
1006 # i18n: "all" is a keyword
1006 # i18n: "all" is a keyword
1007 getargs(x, 0, 0, _("all takes no arguments"))
1007 getargs(x, 0, 0, _("all takes no arguments"))
1008 return subset & spanset(repo) # drop "null" if any
1008 return subset & spanset(repo) # drop "null" if any
1009
1009
1010 @predicate('grep(regex)')
1010 @predicate('grep(regex)')
1011 def grep(repo, subset, x):
1011 def grep(repo, subset, x):
1012 """Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
1012 """Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
1013 to ensure special escape characters are handled correctly. Unlike
1013 to ensure special escape characters are handled correctly. Unlike
1014 ``keyword(string)``, the match is case-sensitive.
1014 ``keyword(string)``, the match is case-sensitive.
1015 """
1015 """
1016 try:
1016 try:
1017 # i18n: "grep" is a keyword
1017 # i18n: "grep" is a keyword
1018 gr = re.compile(getstring(x, _("grep requires a string")))
1018 gr = re.compile(getstring(x, _("grep requires a string")))
1019 except re.error as e:
1019 except re.error as e:
1020 raise error.ParseError(_('invalid match pattern: %s') % e)
1020 raise error.ParseError(_('invalid match pattern: %s') % e)
1021
1021
1022 def matches(x):
1022 def matches(x):
1023 c = repo[x]
1023 c = repo[x]
1024 for e in c.files() + [c.user(), c.description()]:
1024 for e in c.files() + [c.user(), c.description()]:
1025 if gr.search(e):
1025 if gr.search(e):
1026 return True
1026 return True
1027 return False
1027 return False
1028
1028
1029 return subset.filter(matches, condrepr=('<grep %r>', gr.pattern))
1029 return subset.filter(matches, condrepr=('<grep %r>', gr.pattern))
1030
1030
1031 @predicate('_matchfiles', safe=True)
1031 @predicate('_matchfiles', safe=True)
1032 def _matchfiles(repo, subset, x):
1032 def _matchfiles(repo, subset, x):
1033 # _matchfiles takes a revset list of prefixed arguments:
1033 # _matchfiles takes a revset list of prefixed arguments:
1034 #
1034 #
1035 # [p:foo, i:bar, x:baz]
1035 # [p:foo, i:bar, x:baz]
1036 #
1036 #
1037 # builds a match object from them and filters subset. Allowed
1037 # builds a match object from them and filters subset. Allowed
1038 # prefixes are 'p:' for regular patterns, 'i:' for include
1038 # prefixes are 'p:' for regular patterns, 'i:' for include
1039 # patterns and 'x:' for exclude patterns. Use 'r:' prefix to pass
1039 # patterns and 'x:' for exclude patterns. Use 'r:' prefix to pass
1040 # a revision identifier, or the empty string to reference the
1040 # a revision identifier, or the empty string to reference the
1041 # working directory, from which the match object is
1041 # working directory, from which the match object is
1042 # initialized. Use 'd:' to set the default matching mode, default
1042 # initialized. Use 'd:' to set the default matching mode, default
1043 # to 'glob'. At most one 'r:' and 'd:' argument can be passed.
1043 # to 'glob'. At most one 'r:' and 'd:' argument can be passed.
1044
1044
1045 l = getargs(x, 1, -1, "_matchfiles requires at least one argument")
1045 l = getargs(x, 1, -1, "_matchfiles requires at least one argument")
1046 pats, inc, exc = [], [], []
1046 pats, inc, exc = [], [], []
1047 rev, default = None, None
1047 rev, default = None, None
1048 for arg in l:
1048 for arg in l:
1049 s = getstring(arg, "_matchfiles requires string arguments")
1049 s = getstring(arg, "_matchfiles requires string arguments")
1050 prefix, value = s[:2], s[2:]
1050 prefix, value = s[:2], s[2:]
1051 if prefix == 'p:':
1051 if prefix == 'p:':
1052 pats.append(value)
1052 pats.append(value)
1053 elif prefix == 'i:':
1053 elif prefix == 'i:':
1054 inc.append(value)
1054 inc.append(value)
1055 elif prefix == 'x:':
1055 elif prefix == 'x:':
1056 exc.append(value)
1056 exc.append(value)
1057 elif prefix == 'r:':
1057 elif prefix == 'r:':
1058 if rev is not None:
1058 if rev is not None:
1059 raise error.ParseError('_matchfiles expected at most one '
1059 raise error.ParseError('_matchfiles expected at most one '
1060 'revision')
1060 'revision')
1061 if value != '': # empty means working directory; leave rev as None
1061 if value != '': # empty means working directory; leave rev as None
1062 rev = value
1062 rev = value
1063 elif prefix == 'd:':
1063 elif prefix == 'd:':
1064 if default is not None:
1064 if default is not None:
1065 raise error.ParseError('_matchfiles expected at most one '
1065 raise error.ParseError('_matchfiles expected at most one '
1066 'default mode')
1066 'default mode')
1067 default = value
1067 default = value
1068 else:
1068 else:
1069 raise error.ParseError('invalid _matchfiles prefix: %s' % prefix)
1069 raise error.ParseError('invalid _matchfiles prefix: %s' % prefix)
1070 if not default:
1070 if not default:
1071 default = 'glob'
1071 default = 'glob'
1072
1072
1073 m = matchmod.match(repo.root, repo.getcwd(), pats, include=inc,
1073 m = matchmod.match(repo.root, repo.getcwd(), pats, include=inc,
1074 exclude=exc, ctx=repo[rev], default=default)
1074 exclude=exc, ctx=repo[rev], default=default)
1075
1075
1076 # This directly read the changelog data as creating changectx for all
1076 # This directly read the changelog data as creating changectx for all
1077 # revisions is quite expensive.
1077 # revisions is quite expensive.
1078 getfiles = repo.changelog.readfiles
1078 getfiles = repo.changelog.readfiles
1079 wdirrev = node.wdirrev
1079 wdirrev = node.wdirrev
1080 def matches(x):
1080 def matches(x):
1081 if x == wdirrev:
1081 if x == wdirrev:
1082 files = repo[x].files()
1082 files = repo[x].files()
1083 else:
1083 else:
1084 files = getfiles(x)
1084 files = getfiles(x)
1085 for f in files:
1085 for f in files:
1086 if m(f):
1086 if m(f):
1087 return True
1087 return True
1088 return False
1088 return False
1089
1089
1090 return subset.filter(matches,
1090 return subset.filter(matches,
1091 condrepr=('<matchfiles patterns=%r, include=%r '
1091 condrepr=('<matchfiles patterns=%r, include=%r '
1092 'exclude=%r, default=%r, rev=%r>',
1092 'exclude=%r, default=%r, rev=%r>',
1093 pats, inc, exc, default, rev))
1093 pats, inc, exc, default, rev))
1094
1094
1095 @predicate('file(pattern)', safe=True)
1095 @predicate('file(pattern)', safe=True)
1096 def hasfile(repo, subset, x):
1096 def hasfile(repo, subset, x):
1097 """Changesets affecting files matched by pattern.
1097 """Changesets affecting files matched by pattern.
1098
1098
1099 For a faster but less accurate result, consider using ``filelog()``
1099 For a faster but less accurate result, consider using ``filelog()``
1100 instead.
1100 instead.
1101
1101
1102 This predicate uses ``glob:`` as the default kind of pattern.
1102 This predicate uses ``glob:`` as the default kind of pattern.
1103 """
1103 """
1104 # i18n: "file" is a keyword
1104 # i18n: "file" is a keyword
1105 pat = getstring(x, _("file requires a pattern"))
1105 pat = getstring(x, _("file requires a pattern"))
1106 return _matchfiles(repo, subset, ('string', 'p:' + pat))
1106 return _matchfiles(repo, subset, ('string', 'p:' + pat))
1107
1107
1108 @predicate('head()', safe=True)
1108 @predicate('head()', safe=True)
1109 def head(repo, subset, x):
1109 def head(repo, subset, x):
1110 """Changeset is a named branch head.
1110 """Changeset is a named branch head.
1111 """
1111 """
1112 # i18n: "head" is a keyword
1112 # i18n: "head" is a keyword
1113 getargs(x, 0, 0, _("head takes no arguments"))
1113 getargs(x, 0, 0, _("head takes no arguments"))
1114 hs = set()
1114 hs = set()
1115 cl = repo.changelog
1115 cl = repo.changelog
1116 for ls in repo.branchmap().itervalues():
1116 for ls in repo.branchmap().itervalues():
1117 hs.update(cl.rev(h) for h in ls)
1117 hs.update(cl.rev(h) for h in ls)
1118 return subset & baseset(hs)
1118 return subset & baseset(hs)
1119
1119
1120 @predicate('heads(set)', safe=True)
1120 @predicate('heads(set)', safe=True)
1121 def heads(repo, subset, x):
1121 def heads(repo, subset, x):
1122 """Members of set with no children in set.
1122 """Members of set with no children in set.
1123 """
1123 """
1124 s = getset(repo, subset, x)
1124 s = getset(repo, subset, x)
1125 ps = parents(repo, subset, x)
1125 ps = parents(repo, subset, x)
1126 return s - ps
1126 return s - ps
1127
1127
1128 @predicate('hidden()', safe=True)
1128 @predicate('hidden()', safe=True)
1129 def hidden(repo, subset, x):
1129 def hidden(repo, subset, x):
1130 """Hidden changesets.
1130 """Hidden changesets.
1131 """
1131 """
1132 # i18n: "hidden" is a keyword
1132 # i18n: "hidden" is a keyword
1133 getargs(x, 0, 0, _("hidden takes no arguments"))
1133 getargs(x, 0, 0, _("hidden takes no arguments"))
1134 hiddenrevs = repoview.filterrevs(repo, 'visible')
1134 hiddenrevs = repoview.filterrevs(repo, 'visible')
1135 return subset & hiddenrevs
1135 return subset & hiddenrevs
1136
1136
1137 @predicate('keyword(string)', safe=True)
1137 @predicate('keyword(string)', safe=True)
1138 def keyword(repo, subset, x):
1138 def keyword(repo, subset, x):
1139 """Search commit message, user name, and names of changed files for
1139 """Search commit message, user name, and names of changed files for
1140 string. The match is case-insensitive.
1140 string. The match is case-insensitive.
1141
1141
1142 For a regular expression or case sensitive search of these fields, use
1142 For a regular expression or case sensitive search of these fields, use
1143 ``grep(regex)``.
1143 ``grep(regex)``.
1144 """
1144 """
1145 # i18n: "keyword" is a keyword
1145 # i18n: "keyword" is a keyword
1146 kw = encoding.lower(getstring(x, _("keyword requires a string")))
1146 kw = encoding.lower(getstring(x, _("keyword requires a string")))
1147
1147
1148 def matches(r):
1148 def matches(r):
1149 c = repo[r]
1149 c = repo[r]
1150 return any(kw in encoding.lower(t)
1150 return any(kw in encoding.lower(t)
1151 for t in c.files() + [c.user(), c.description()])
1151 for t in c.files() + [c.user(), c.description()])
1152
1152
1153 return subset.filter(matches, condrepr=('<keyword %r>', kw))
1153 return subset.filter(matches, condrepr=('<keyword %r>', kw))
1154
1154
1155 @predicate('limit(set[, n[, offset]])', safe=True)
1155 @predicate('limit(set[, n[, offset]])', safe=True)
1156 def limit(repo, subset, x):
1156 def limit(repo, subset, x):
1157 """First n members of set, defaulting to 1, starting from offset.
1157 """First n members of set, defaulting to 1, starting from offset.
1158 """
1158 """
1159 args = getargsdict(x, 'limit', 'set n offset')
1159 args = getargsdict(x, 'limit', 'set n offset')
1160 if 'set' not in args:
1160 if 'set' not in args:
1161 # i18n: "limit" is a keyword
1161 # i18n: "limit" is a keyword
1162 raise error.ParseError(_("limit requires one to three arguments"))
1162 raise error.ParseError(_("limit requires one to three arguments"))
1163 # i18n: "limit" is a keyword
1163 # i18n: "limit" is a keyword
1164 lim = getinteger(args.get('n'), _("limit expects a number"), default=1)
1164 lim = getinteger(args.get('n'), _("limit expects a number"), default=1)
1165 # i18n: "limit" is a keyword
1165 # i18n: "limit" is a keyword
1166 ofs = getinteger(args.get('offset'), _("limit expects a number"), default=0)
1166 ofs = getinteger(args.get('offset'), _("limit expects a number"), default=0)
1167 if ofs < 0:
1167 if ofs < 0:
1168 raise error.ParseError(_("negative offset"))
1168 raise error.ParseError(_("negative offset"))
1169 os = getset(repo, fullreposet(repo), args['set'])
1169 os = getset(repo, fullreposet(repo), args['set'])
1170 result = []
1170 result = []
1171 it = iter(os)
1171 it = iter(os)
1172 for x in xrange(ofs):
1172 for x in xrange(ofs):
1173 y = next(it, None)
1173 y = next(it, None)
1174 if y is None:
1174 if y is None:
1175 break
1175 break
1176 for x in xrange(lim):
1176 for x in xrange(lim):
1177 y = next(it, None)
1177 y = next(it, None)
1178 if y is None:
1178 if y is None:
1179 break
1179 break
1180 elif y in subset:
1180 elif y in subset:
1181 result.append(y)
1181 result.append(y)
1182 return baseset(result, datarepr=('<limit n=%d, offset=%d, %r, %r>',
1182 return baseset(result, datarepr=('<limit n=%d, offset=%d, %r, %r>',
1183 lim, ofs, subset, os))
1183 lim, ofs, subset, os))
1184
1184
1185 @predicate('last(set, [n])', safe=True)
1185 @predicate('last(set, [n])', safe=True)
1186 def last(repo, subset, x):
1186 def last(repo, subset, x):
1187 """Last n members of set, defaulting to 1.
1187 """Last n members of set, defaulting to 1.
1188 """
1188 """
1189 # i18n: "last" is a keyword
1189 # i18n: "last" is a keyword
1190 l = getargs(x, 1, 2, _("last requires one or two arguments"))
1190 l = getargs(x, 1, 2, _("last requires one or two arguments"))
1191 lim = 1
1191 lim = 1
1192 if len(l) == 2:
1192 if len(l) == 2:
1193 # i18n: "last" is a keyword
1193 # i18n: "last" is a keyword
1194 lim = getinteger(l[1], _("last expects a number"))
1194 lim = getinteger(l[1], _("last expects a number"))
1195 os = getset(repo, fullreposet(repo), l[0])
1195 os = getset(repo, fullreposet(repo), l[0])
1196 os.reverse()
1196 os.reverse()
1197 result = []
1197 result = []
1198 it = iter(os)
1198 it = iter(os)
1199 for x in xrange(lim):
1199 for x in xrange(lim):
1200 y = next(it, None)
1200 y = next(it, None)
1201 if y is None:
1201 if y is None:
1202 break
1202 break
1203 elif y in subset:
1203 elif y in subset:
1204 result.append(y)
1204 result.append(y)
1205 return baseset(result, datarepr=('<last n=%d, %r, %r>', lim, subset, os))
1205 return baseset(result[::-1], datarepr=('<last n=%d, %r, %r>',
1206 lim, subset, os))
1206
1207
1207 @predicate('max(set)', safe=True)
1208 @predicate('max(set)', safe=True)
1208 def maxrev(repo, subset, x):
1209 def maxrev(repo, subset, x):
1209 """Changeset with highest revision number in set.
1210 """Changeset with highest revision number in set.
1210 """
1211 """
1211 os = getset(repo, fullreposet(repo), x)
1212 os = getset(repo, fullreposet(repo), x)
1212 try:
1213 try:
1213 m = os.max()
1214 m = os.max()
1214 if m in subset:
1215 if m in subset:
1215 return baseset([m], datarepr=('<max %r, %r>', subset, os))
1216 return baseset([m], datarepr=('<max %r, %r>', subset, os))
1216 except ValueError:
1217 except ValueError:
1217 # os.max() throws a ValueError when the collection is empty.
1218 # os.max() throws a ValueError when the collection is empty.
1218 # Same as python's max().
1219 # Same as python's max().
1219 pass
1220 pass
1220 return baseset(datarepr=('<max %r, %r>', subset, os))
1221 return baseset(datarepr=('<max %r, %r>', subset, os))
1221
1222
1222 @predicate('merge()', safe=True)
1223 @predicate('merge()', safe=True)
1223 def merge(repo, subset, x):
1224 def merge(repo, subset, x):
1224 """Changeset is a merge changeset.
1225 """Changeset is a merge changeset.
1225 """
1226 """
1226 # i18n: "merge" is a keyword
1227 # i18n: "merge" is a keyword
1227 getargs(x, 0, 0, _("merge takes no arguments"))
1228 getargs(x, 0, 0, _("merge takes no arguments"))
1228 cl = repo.changelog
1229 cl = repo.changelog
1229 return subset.filter(lambda r: cl.parentrevs(r)[1] != -1,
1230 return subset.filter(lambda r: cl.parentrevs(r)[1] != -1,
1230 condrepr='<merge>')
1231 condrepr='<merge>')
1231
1232
1232 @predicate('branchpoint()', safe=True)
1233 @predicate('branchpoint()', safe=True)
1233 def branchpoint(repo, subset, x):
1234 def branchpoint(repo, subset, x):
1234 """Changesets with more than one child.
1235 """Changesets with more than one child.
1235 """
1236 """
1236 # i18n: "branchpoint" is a keyword
1237 # i18n: "branchpoint" is a keyword
1237 getargs(x, 0, 0, _("branchpoint takes no arguments"))
1238 getargs(x, 0, 0, _("branchpoint takes no arguments"))
1238 cl = repo.changelog
1239 cl = repo.changelog
1239 if not subset:
1240 if not subset:
1240 return baseset()
1241 return baseset()
1241 # XXX this should be 'parentset.min()' assuming 'parentset' is a smartset
1242 # XXX this should be 'parentset.min()' assuming 'parentset' is a smartset
1242 # (and if it is not, it should.)
1243 # (and if it is not, it should.)
1243 baserev = min(subset)
1244 baserev = min(subset)
1244 parentscount = [0]*(len(repo) - baserev)
1245 parentscount = [0]*(len(repo) - baserev)
1245 for r in cl.revs(start=baserev + 1):
1246 for r in cl.revs(start=baserev + 1):
1246 for p in cl.parentrevs(r):
1247 for p in cl.parentrevs(r):
1247 if p >= baserev:
1248 if p >= baserev:
1248 parentscount[p - baserev] += 1
1249 parentscount[p - baserev] += 1
1249 return subset.filter(lambda r: parentscount[r - baserev] > 1,
1250 return subset.filter(lambda r: parentscount[r - baserev] > 1,
1250 condrepr='<branchpoint>')
1251 condrepr='<branchpoint>')
1251
1252
1252 @predicate('min(set)', safe=True)
1253 @predicate('min(set)', safe=True)
1253 def minrev(repo, subset, x):
1254 def minrev(repo, subset, x):
1254 """Changeset with lowest revision number in set.
1255 """Changeset with lowest revision number in set.
1255 """
1256 """
1256 os = getset(repo, fullreposet(repo), x)
1257 os = getset(repo, fullreposet(repo), x)
1257 try:
1258 try:
1258 m = os.min()
1259 m = os.min()
1259 if m in subset:
1260 if m in subset:
1260 return baseset([m], datarepr=('<min %r, %r>', subset, os))
1261 return baseset([m], datarepr=('<min %r, %r>', subset, os))
1261 except ValueError:
1262 except ValueError:
1262 # os.min() throws a ValueError when the collection is empty.
1263 # os.min() throws a ValueError when the collection is empty.
1263 # Same as python's min().
1264 # Same as python's min().
1264 pass
1265 pass
1265 return baseset(datarepr=('<min %r, %r>', subset, os))
1266 return baseset(datarepr=('<min %r, %r>', subset, os))
1266
1267
1267 @predicate('modifies(pattern)', safe=True)
1268 @predicate('modifies(pattern)', safe=True)
1268 def modifies(repo, subset, x):
1269 def modifies(repo, subset, x):
1269 """Changesets modifying files matched by pattern.
1270 """Changesets modifying files matched by pattern.
1270
1271
1271 The pattern without explicit kind like ``glob:`` is expected to be
1272 The pattern without explicit kind like ``glob:`` is expected to be
1272 relative to the current directory and match against a file or a
1273 relative to the current directory and match against a file or a
1273 directory.
1274 directory.
1274 """
1275 """
1275 # i18n: "modifies" is a keyword
1276 # i18n: "modifies" is a keyword
1276 pat = getstring(x, _("modifies requires a pattern"))
1277 pat = getstring(x, _("modifies requires a pattern"))
1277 return checkstatus(repo, subset, pat, 0)
1278 return checkstatus(repo, subset, pat, 0)
1278
1279
1279 @predicate('named(namespace)')
1280 @predicate('named(namespace)')
1280 def named(repo, subset, x):
1281 def named(repo, subset, x):
1281 """The changesets in a given namespace.
1282 """The changesets in a given namespace.
1282
1283
1283 Pattern matching is supported for `namespace`. See
1284 Pattern matching is supported for `namespace`. See
1284 :hg:`help revisions.patterns`.
1285 :hg:`help revisions.patterns`.
1285 """
1286 """
1286 # i18n: "named" is a keyword
1287 # i18n: "named" is a keyword
1287 args = getargs(x, 1, 1, _('named requires a namespace argument'))
1288 args = getargs(x, 1, 1, _('named requires a namespace argument'))
1288
1289
1289 ns = getstring(args[0],
1290 ns = getstring(args[0],
1290 # i18n: "named" is a keyword
1291 # i18n: "named" is a keyword
1291 _('the argument to named must be a string'))
1292 _('the argument to named must be a string'))
1292 kind, pattern, matcher = util.stringmatcher(ns)
1293 kind, pattern, matcher = util.stringmatcher(ns)
1293 namespaces = set()
1294 namespaces = set()
1294 if kind == 'literal':
1295 if kind == 'literal':
1295 if pattern not in repo.names:
1296 if pattern not in repo.names:
1296 raise error.RepoLookupError(_("namespace '%s' does not exist")
1297 raise error.RepoLookupError(_("namespace '%s' does not exist")
1297 % ns)
1298 % ns)
1298 namespaces.add(repo.names[pattern])
1299 namespaces.add(repo.names[pattern])
1299 else:
1300 else:
1300 for name, ns in repo.names.iteritems():
1301 for name, ns in repo.names.iteritems():
1301 if matcher(name):
1302 if matcher(name):
1302 namespaces.add(ns)
1303 namespaces.add(ns)
1303 if not namespaces:
1304 if not namespaces:
1304 raise error.RepoLookupError(_("no namespace exists"
1305 raise error.RepoLookupError(_("no namespace exists"
1305 " that match '%s'") % pattern)
1306 " that match '%s'") % pattern)
1306
1307
1307 names = set()
1308 names = set()
1308 for ns in namespaces:
1309 for ns in namespaces:
1309 for name in ns.listnames(repo):
1310 for name in ns.listnames(repo):
1310 if name not in ns.deprecated:
1311 if name not in ns.deprecated:
1311 names.update(repo[n].rev() for n in ns.nodes(repo, name))
1312 names.update(repo[n].rev() for n in ns.nodes(repo, name))
1312
1313
1313 names -= {node.nullrev}
1314 names -= {node.nullrev}
1314 return subset & names
1315 return subset & names
1315
1316
1316 @predicate('id(string)', safe=True)
1317 @predicate('id(string)', safe=True)
1317 def node_(repo, subset, x):
1318 def node_(repo, subset, x):
1318 """Revision non-ambiguously specified by the given hex string prefix.
1319 """Revision non-ambiguously specified by the given hex string prefix.
1319 """
1320 """
1320 # i18n: "id" is a keyword
1321 # i18n: "id" is a keyword
1321 l = getargs(x, 1, 1, _("id requires one argument"))
1322 l = getargs(x, 1, 1, _("id requires one argument"))
1322 # i18n: "id" is a keyword
1323 # i18n: "id" is a keyword
1323 n = getstring(l[0], _("id requires a string"))
1324 n = getstring(l[0], _("id requires a string"))
1324 if len(n) == 40:
1325 if len(n) == 40:
1325 try:
1326 try:
1326 rn = repo.changelog.rev(node.bin(n))
1327 rn = repo.changelog.rev(node.bin(n))
1327 except error.WdirUnsupported:
1328 except error.WdirUnsupported:
1328 rn = node.wdirrev
1329 rn = node.wdirrev
1329 except (LookupError, TypeError):
1330 except (LookupError, TypeError):
1330 rn = None
1331 rn = None
1331 else:
1332 else:
1332 rn = None
1333 rn = None
1333 try:
1334 try:
1334 pm = repo.changelog._partialmatch(n)
1335 pm = repo.changelog._partialmatch(n)
1335 if pm is not None:
1336 if pm is not None:
1336 rn = repo.changelog.rev(pm)
1337 rn = repo.changelog.rev(pm)
1337 except error.WdirUnsupported:
1338 except error.WdirUnsupported:
1338 rn = node.wdirrev
1339 rn = node.wdirrev
1339
1340
1340 if rn is None:
1341 if rn is None:
1341 return baseset()
1342 return baseset()
1342 result = baseset([rn])
1343 result = baseset([rn])
1343 return result & subset
1344 return result & subset
1344
1345
1345 @predicate('obsolete()', safe=True)
1346 @predicate('obsolete()', safe=True)
1346 def obsolete(repo, subset, x):
1347 def obsolete(repo, subset, x):
1347 """Mutable changeset with a newer version."""
1348 """Mutable changeset with a newer version."""
1348 # i18n: "obsolete" is a keyword
1349 # i18n: "obsolete" is a keyword
1349 getargs(x, 0, 0, _("obsolete takes no arguments"))
1350 getargs(x, 0, 0, _("obsolete takes no arguments"))
1350 obsoletes = obsmod.getrevs(repo, 'obsolete')
1351 obsoletes = obsmod.getrevs(repo, 'obsolete')
1351 return subset & obsoletes
1352 return subset & obsoletes
1352
1353
1353 @predicate('only(set, [set])', safe=True)
1354 @predicate('only(set, [set])', safe=True)
1354 def only(repo, subset, x):
1355 def only(repo, subset, x):
1355 """Changesets that are ancestors of the first set that are not ancestors
1356 """Changesets that are ancestors of the first set that are not ancestors
1356 of any other head in the repo. If a second set is specified, the result
1357 of any other head in the repo. If a second set is specified, the result
1357 is ancestors of the first set that are not ancestors of the second set
1358 is ancestors of the first set that are not ancestors of the second set
1358 (i.e. ::<set1> - ::<set2>).
1359 (i.e. ::<set1> - ::<set2>).
1359 """
1360 """
1360 cl = repo.changelog
1361 cl = repo.changelog
1361 # i18n: "only" is a keyword
1362 # i18n: "only" is a keyword
1362 args = getargs(x, 1, 2, _('only takes one or two arguments'))
1363 args = getargs(x, 1, 2, _('only takes one or two arguments'))
1363 include = getset(repo, fullreposet(repo), args[0])
1364 include = getset(repo, fullreposet(repo), args[0])
1364 if len(args) == 1:
1365 if len(args) == 1:
1365 if not include:
1366 if not include:
1366 return baseset()
1367 return baseset()
1367
1368
1368 descendants = set(_revdescendants(repo, include, False))
1369 descendants = set(_revdescendants(repo, include, False))
1369 exclude = [rev for rev in cl.headrevs()
1370 exclude = [rev for rev in cl.headrevs()
1370 if not rev in descendants and not rev in include]
1371 if not rev in descendants and not rev in include]
1371 else:
1372 else:
1372 exclude = getset(repo, fullreposet(repo), args[1])
1373 exclude = getset(repo, fullreposet(repo), args[1])
1373
1374
1374 results = set(cl.findmissingrevs(common=exclude, heads=include))
1375 results = set(cl.findmissingrevs(common=exclude, heads=include))
1375 # XXX we should turn this into a baseset instead of a set, smartset may do
1376 # XXX we should turn this into a baseset instead of a set, smartset may do
1376 # some optimizations from the fact this is a baseset.
1377 # some optimizations from the fact this is a baseset.
1377 return subset & results
1378 return subset & results
1378
1379
1379 @predicate('origin([set])', safe=True)
1380 @predicate('origin([set])', safe=True)
1380 def origin(repo, subset, x):
1381 def origin(repo, subset, x):
1381 """
1382 """
1382 Changesets that were specified as a source for the grafts, transplants or
1383 Changesets that were specified as a source for the grafts, transplants or
1383 rebases that created the given revisions. Omitting the optional set is the
1384 rebases that created the given revisions. Omitting the optional set is the
1384 same as passing all(). If a changeset created by these operations is itself
1385 same as passing all(). If a changeset created by these operations is itself
1385 specified as a source for one of these operations, only the source changeset
1386 specified as a source for one of these operations, only the source changeset
1386 for the first operation is selected.
1387 for the first operation is selected.
1387 """
1388 """
1388 if x is not None:
1389 if x is not None:
1389 dests = getset(repo, fullreposet(repo), x)
1390 dests = getset(repo, fullreposet(repo), x)
1390 else:
1391 else:
1391 dests = fullreposet(repo)
1392 dests = fullreposet(repo)
1392
1393
1393 def _firstsrc(rev):
1394 def _firstsrc(rev):
1394 src = _getrevsource(repo, rev)
1395 src = _getrevsource(repo, rev)
1395 if src is None:
1396 if src is None:
1396 return None
1397 return None
1397
1398
1398 while True:
1399 while True:
1399 prev = _getrevsource(repo, src)
1400 prev = _getrevsource(repo, src)
1400
1401
1401 if prev is None:
1402 if prev is None:
1402 return src
1403 return src
1403 src = prev
1404 src = prev
1404
1405
1405 o = {_firstsrc(r) for r in dests}
1406 o = {_firstsrc(r) for r in dests}
1406 o -= {None}
1407 o -= {None}
1407 # XXX we should turn this into a baseset instead of a set, smartset may do
1408 # XXX we should turn this into a baseset instead of a set, smartset may do
1408 # some optimizations from the fact this is a baseset.
1409 # some optimizations from the fact this is a baseset.
1409 return subset & o
1410 return subset & o
1410
1411
1411 @predicate('outgoing([path])', safe=False)
1412 @predicate('outgoing([path])', safe=False)
1412 def outgoing(repo, subset, x):
1413 def outgoing(repo, subset, x):
1413 """Changesets not found in the specified destination repository, or the
1414 """Changesets not found in the specified destination repository, or the
1414 default push location.
1415 default push location.
1415 """
1416 """
1416 # Avoid cycles.
1417 # Avoid cycles.
1417 from . import (
1418 from . import (
1418 discovery,
1419 discovery,
1419 hg,
1420 hg,
1420 )
1421 )
1421 # i18n: "outgoing" is a keyword
1422 # i18n: "outgoing" is a keyword
1422 l = getargs(x, 0, 1, _("outgoing takes one or no arguments"))
1423 l = getargs(x, 0, 1, _("outgoing takes one or no arguments"))
1423 # i18n: "outgoing" is a keyword
1424 # i18n: "outgoing" is a keyword
1424 dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
1425 dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
1425 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
1426 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
1426 dest, branches = hg.parseurl(dest)
1427 dest, branches = hg.parseurl(dest)
1427 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1428 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1428 if revs:
1429 if revs:
1429 revs = [repo.lookup(rev) for rev in revs]
1430 revs = [repo.lookup(rev) for rev in revs]
1430 other = hg.peer(repo, {}, dest)
1431 other = hg.peer(repo, {}, dest)
1431 repo.ui.pushbuffer()
1432 repo.ui.pushbuffer()
1432 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs)
1433 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs)
1433 repo.ui.popbuffer()
1434 repo.ui.popbuffer()
1434 cl = repo.changelog
1435 cl = repo.changelog
1435 o = {cl.rev(r) for r in outgoing.missing}
1436 o = {cl.rev(r) for r in outgoing.missing}
1436 return subset & o
1437 return subset & o
1437
1438
1438 @predicate('p1([set])', safe=True)
1439 @predicate('p1([set])', safe=True)
1439 def p1(repo, subset, x):
1440 def p1(repo, subset, x):
1440 """First parent of changesets in set, or the working directory.
1441 """First parent of changesets in set, or the working directory.
1441 """
1442 """
1442 if x is None:
1443 if x is None:
1443 p = repo[x].p1().rev()
1444 p = repo[x].p1().rev()
1444 if p >= 0:
1445 if p >= 0:
1445 return subset & baseset([p])
1446 return subset & baseset([p])
1446 return baseset()
1447 return baseset()
1447
1448
1448 ps = set()
1449 ps = set()
1449 cl = repo.changelog
1450 cl = repo.changelog
1450 for r in getset(repo, fullreposet(repo), x):
1451 for r in getset(repo, fullreposet(repo), x):
1451 try:
1452 try:
1452 ps.add(cl.parentrevs(r)[0])
1453 ps.add(cl.parentrevs(r)[0])
1453 except error.WdirUnsupported:
1454 except error.WdirUnsupported:
1454 ps.add(repo[r].parents()[0].rev())
1455 ps.add(repo[r].parents()[0].rev())
1455 ps -= {node.nullrev}
1456 ps -= {node.nullrev}
1456 # XXX we should turn this into a baseset instead of a set, smartset may do
1457 # XXX we should turn this into a baseset instead of a set, smartset may do
1457 # some optimizations from the fact this is a baseset.
1458 # some optimizations from the fact this is a baseset.
1458 return subset & ps
1459 return subset & ps
1459
1460
1460 @predicate('p2([set])', safe=True)
1461 @predicate('p2([set])', safe=True)
1461 def p2(repo, subset, x):
1462 def p2(repo, subset, x):
1462 """Second parent of changesets in set, or the working directory.
1463 """Second parent of changesets in set, or the working directory.
1463 """
1464 """
1464 if x is None:
1465 if x is None:
1465 ps = repo[x].parents()
1466 ps = repo[x].parents()
1466 try:
1467 try:
1467 p = ps[1].rev()
1468 p = ps[1].rev()
1468 if p >= 0:
1469 if p >= 0:
1469 return subset & baseset([p])
1470 return subset & baseset([p])
1470 return baseset()
1471 return baseset()
1471 except IndexError:
1472 except IndexError:
1472 return baseset()
1473 return baseset()
1473
1474
1474 ps = set()
1475 ps = set()
1475 cl = repo.changelog
1476 cl = repo.changelog
1476 for r in getset(repo, fullreposet(repo), x):
1477 for r in getset(repo, fullreposet(repo), x):
1477 try:
1478 try:
1478 ps.add(cl.parentrevs(r)[1])
1479 ps.add(cl.parentrevs(r)[1])
1479 except error.WdirUnsupported:
1480 except error.WdirUnsupported:
1480 parents = repo[r].parents()
1481 parents = repo[r].parents()
1481 if len(parents) == 2:
1482 if len(parents) == 2:
1482 ps.add(parents[1])
1483 ps.add(parents[1])
1483 ps -= {node.nullrev}
1484 ps -= {node.nullrev}
1484 # XXX we should turn this into a baseset instead of a set, smartset may do
1485 # XXX we should turn this into a baseset instead of a set, smartset may do
1485 # some optimizations from the fact this is a baseset.
1486 # some optimizations from the fact this is a baseset.
1486 return subset & ps
1487 return subset & ps
1487
1488
1488 def parentpost(repo, subset, x, order):
1489 def parentpost(repo, subset, x, order):
1489 return p1(repo, subset, x)
1490 return p1(repo, subset, x)
1490
1491
1491 @predicate('parents([set])', safe=True)
1492 @predicate('parents([set])', safe=True)
1492 def parents(repo, subset, x):
1493 def parents(repo, subset, x):
1493 """
1494 """
1494 The set of all parents for all changesets in set, or the working directory.
1495 The set of all parents for all changesets in set, or the working directory.
1495 """
1496 """
1496 if x is None:
1497 if x is None:
1497 ps = set(p.rev() for p in repo[x].parents())
1498 ps = set(p.rev() for p in repo[x].parents())
1498 else:
1499 else:
1499 ps = set()
1500 ps = set()
1500 cl = repo.changelog
1501 cl = repo.changelog
1501 up = ps.update
1502 up = ps.update
1502 parentrevs = cl.parentrevs
1503 parentrevs = cl.parentrevs
1503 for r in getset(repo, fullreposet(repo), x):
1504 for r in getset(repo, fullreposet(repo), x):
1504 try:
1505 try:
1505 up(parentrevs(r))
1506 up(parentrevs(r))
1506 except error.WdirUnsupported:
1507 except error.WdirUnsupported:
1507 up(p.rev() for p in repo[r].parents())
1508 up(p.rev() for p in repo[r].parents())
1508 ps -= {node.nullrev}
1509 ps -= {node.nullrev}
1509 return subset & ps
1510 return subset & ps
1510
1511
1511 def _phase(repo, subset, *targets):
1512 def _phase(repo, subset, *targets):
1512 """helper to select all rev in <targets> phases"""
1513 """helper to select all rev in <targets> phases"""
1513 s = repo._phasecache.getrevset(repo, targets)
1514 s = repo._phasecache.getrevset(repo, targets)
1514 return subset & s
1515 return subset & s
1515
1516
1516 @predicate('draft()', safe=True)
1517 @predicate('draft()', safe=True)
1517 def draft(repo, subset, x):
1518 def draft(repo, subset, x):
1518 """Changeset in draft phase."""
1519 """Changeset in draft phase."""
1519 # i18n: "draft" is a keyword
1520 # i18n: "draft" is a keyword
1520 getargs(x, 0, 0, _("draft takes no arguments"))
1521 getargs(x, 0, 0, _("draft takes no arguments"))
1521 target = phases.draft
1522 target = phases.draft
1522 return _phase(repo, subset, target)
1523 return _phase(repo, subset, target)
1523
1524
1524 @predicate('secret()', safe=True)
1525 @predicate('secret()', safe=True)
1525 def secret(repo, subset, x):
1526 def secret(repo, subset, x):
1526 """Changeset in secret phase."""
1527 """Changeset in secret phase."""
1527 # i18n: "secret" is a keyword
1528 # i18n: "secret" is a keyword
1528 getargs(x, 0, 0, _("secret takes no arguments"))
1529 getargs(x, 0, 0, _("secret takes no arguments"))
1529 target = phases.secret
1530 target = phases.secret
1530 return _phase(repo, subset, target)
1531 return _phase(repo, subset, target)
1531
1532
1532 def parentspec(repo, subset, x, n, order):
1533 def parentspec(repo, subset, x, n, order):
1533 """``set^0``
1534 """``set^0``
1534 The set.
1535 The set.
1535 ``set^1`` (or ``set^``), ``set^2``
1536 ``set^1`` (or ``set^``), ``set^2``
1536 First or second parent, respectively, of all changesets in set.
1537 First or second parent, respectively, of all changesets in set.
1537 """
1538 """
1538 try:
1539 try:
1539 n = int(n[1])
1540 n = int(n[1])
1540 if n not in (0, 1, 2):
1541 if n not in (0, 1, 2):
1541 raise ValueError
1542 raise ValueError
1542 except (TypeError, ValueError):
1543 except (TypeError, ValueError):
1543 raise error.ParseError(_("^ expects a number 0, 1, or 2"))
1544 raise error.ParseError(_("^ expects a number 0, 1, or 2"))
1544 ps = set()
1545 ps = set()
1545 cl = repo.changelog
1546 cl = repo.changelog
1546 for r in getset(repo, fullreposet(repo), x):
1547 for r in getset(repo, fullreposet(repo), x):
1547 if n == 0:
1548 if n == 0:
1548 ps.add(r)
1549 ps.add(r)
1549 elif n == 1:
1550 elif n == 1:
1550 try:
1551 try:
1551 ps.add(cl.parentrevs(r)[0])
1552 ps.add(cl.parentrevs(r)[0])
1552 except error.WdirUnsupported:
1553 except error.WdirUnsupported:
1553 ps.add(repo[r].parents()[0].rev())
1554 ps.add(repo[r].parents()[0].rev())
1554 else:
1555 else:
1555 try:
1556 try:
1556 parents = cl.parentrevs(r)
1557 parents = cl.parentrevs(r)
1557 if parents[1] != node.nullrev:
1558 if parents[1] != node.nullrev:
1558 ps.add(parents[1])
1559 ps.add(parents[1])
1559 except error.WdirUnsupported:
1560 except error.WdirUnsupported:
1560 parents = repo[r].parents()
1561 parents = repo[r].parents()
1561 if len(parents) == 2:
1562 if len(parents) == 2:
1562 ps.add(parents[1].rev())
1563 ps.add(parents[1].rev())
1563 return subset & ps
1564 return subset & ps
1564
1565
1565 @predicate('present(set)', safe=True)
1566 @predicate('present(set)', safe=True)
1566 def present(repo, subset, x):
1567 def present(repo, subset, x):
1567 """An empty set, if any revision in set isn't found; otherwise,
1568 """An empty set, if any revision in set isn't found; otherwise,
1568 all revisions in set.
1569 all revisions in set.
1569
1570
1570 If any of specified revisions is not present in the local repository,
1571 If any of specified revisions is not present in the local repository,
1571 the query is normally aborted. But this predicate allows the query
1572 the query is normally aborted. But this predicate allows the query
1572 to continue even in such cases.
1573 to continue even in such cases.
1573 """
1574 """
1574 try:
1575 try:
1575 return getset(repo, subset, x)
1576 return getset(repo, subset, x)
1576 except error.RepoLookupError:
1577 except error.RepoLookupError:
1577 return baseset()
1578 return baseset()
1578
1579
1579 # for internal use
1580 # for internal use
1580 @predicate('_notpublic', safe=True)
1581 @predicate('_notpublic', safe=True)
1581 def _notpublic(repo, subset, x):
1582 def _notpublic(repo, subset, x):
1582 getargs(x, 0, 0, "_notpublic takes no arguments")
1583 getargs(x, 0, 0, "_notpublic takes no arguments")
1583 return _phase(repo, subset, phases.draft, phases.secret)
1584 return _phase(repo, subset, phases.draft, phases.secret)
1584
1585
1585 @predicate('public()', safe=True)
1586 @predicate('public()', safe=True)
1586 def public(repo, subset, x):
1587 def public(repo, subset, x):
1587 """Changeset in public phase."""
1588 """Changeset in public phase."""
1588 # i18n: "public" is a keyword
1589 # i18n: "public" is a keyword
1589 getargs(x, 0, 0, _("public takes no arguments"))
1590 getargs(x, 0, 0, _("public takes no arguments"))
1590 phase = repo._phasecache.phase
1591 phase = repo._phasecache.phase
1591 target = phases.public
1592 target = phases.public
1592 condition = lambda r: phase(repo, r) == target
1593 condition = lambda r: phase(repo, r) == target
1593 return subset.filter(condition, condrepr=('<phase %r>', target),
1594 return subset.filter(condition, condrepr=('<phase %r>', target),
1594 cache=False)
1595 cache=False)
1595
1596
1596 @predicate('remote([id [,path]])', safe=False)
1597 @predicate('remote([id [,path]])', safe=False)
1597 def remote(repo, subset, x):
1598 def remote(repo, subset, x):
1598 """Local revision that corresponds to the given identifier in a
1599 """Local revision that corresponds to the given identifier in a
1599 remote repository, if present. Here, the '.' identifier is a
1600 remote repository, if present. Here, the '.' identifier is a
1600 synonym for the current local branch.
1601 synonym for the current local branch.
1601 """
1602 """
1602
1603
1603 from . import hg # avoid start-up nasties
1604 from . import hg # avoid start-up nasties
1604 # i18n: "remote" is a keyword
1605 # i18n: "remote" is a keyword
1605 l = getargs(x, 0, 2, _("remote takes zero, one, or two arguments"))
1606 l = getargs(x, 0, 2, _("remote takes zero, one, or two arguments"))
1606
1607
1607 q = '.'
1608 q = '.'
1608 if len(l) > 0:
1609 if len(l) > 0:
1609 # i18n: "remote" is a keyword
1610 # i18n: "remote" is a keyword
1610 q = getstring(l[0], _("remote requires a string id"))
1611 q = getstring(l[0], _("remote requires a string id"))
1611 if q == '.':
1612 if q == '.':
1612 q = repo['.'].branch()
1613 q = repo['.'].branch()
1613
1614
1614 dest = ''
1615 dest = ''
1615 if len(l) > 1:
1616 if len(l) > 1:
1616 # i18n: "remote" is a keyword
1617 # i18n: "remote" is a keyword
1617 dest = getstring(l[1], _("remote requires a repository path"))
1618 dest = getstring(l[1], _("remote requires a repository path"))
1618 dest = repo.ui.expandpath(dest or 'default')
1619 dest = repo.ui.expandpath(dest or 'default')
1619 dest, branches = hg.parseurl(dest)
1620 dest, branches = hg.parseurl(dest)
1620 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1621 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1621 if revs:
1622 if revs:
1622 revs = [repo.lookup(rev) for rev in revs]
1623 revs = [repo.lookup(rev) for rev in revs]
1623 other = hg.peer(repo, {}, dest)
1624 other = hg.peer(repo, {}, dest)
1624 n = other.lookup(q)
1625 n = other.lookup(q)
1625 if n in repo:
1626 if n in repo:
1626 r = repo[n].rev()
1627 r = repo[n].rev()
1627 if r in subset:
1628 if r in subset:
1628 return baseset([r])
1629 return baseset([r])
1629 return baseset()
1630 return baseset()
1630
1631
1631 @predicate('removes(pattern)', safe=True)
1632 @predicate('removes(pattern)', safe=True)
1632 def removes(repo, subset, x):
1633 def removes(repo, subset, x):
1633 """Changesets which remove files matching pattern.
1634 """Changesets which remove files matching pattern.
1634
1635
1635 The pattern without explicit kind like ``glob:`` is expected to be
1636 The pattern without explicit kind like ``glob:`` is expected to be
1636 relative to the current directory and match against a file or a
1637 relative to the current directory and match against a file or a
1637 directory.
1638 directory.
1638 """
1639 """
1639 # i18n: "removes" is a keyword
1640 # i18n: "removes" is a keyword
1640 pat = getstring(x, _("removes requires a pattern"))
1641 pat = getstring(x, _("removes requires a pattern"))
1641 return checkstatus(repo, subset, pat, 2)
1642 return checkstatus(repo, subset, pat, 2)
1642
1643
1643 @predicate('rev(number)', safe=True)
1644 @predicate('rev(number)', safe=True)
1644 def rev(repo, subset, x):
1645 def rev(repo, subset, x):
1645 """Revision with the given numeric identifier.
1646 """Revision with the given numeric identifier.
1646 """
1647 """
1647 # i18n: "rev" is a keyword
1648 # i18n: "rev" is a keyword
1648 l = getargs(x, 1, 1, _("rev requires one argument"))
1649 l = getargs(x, 1, 1, _("rev requires one argument"))
1649 try:
1650 try:
1650 # i18n: "rev" is a keyword
1651 # i18n: "rev" is a keyword
1651 l = int(getstring(l[0], _("rev requires a number")))
1652 l = int(getstring(l[0], _("rev requires a number")))
1652 except (TypeError, ValueError):
1653 except (TypeError, ValueError):
1653 # i18n: "rev" is a keyword
1654 # i18n: "rev" is a keyword
1654 raise error.ParseError(_("rev expects a number"))
1655 raise error.ParseError(_("rev expects a number"))
1655 if l not in repo.changelog and l not in (node.nullrev, node.wdirrev):
1656 if l not in repo.changelog and l not in (node.nullrev, node.wdirrev):
1656 return baseset()
1657 return baseset()
1657 return subset & baseset([l])
1658 return subset & baseset([l])
1658
1659
1659 @predicate('matching(revision [, field])', safe=True)
1660 @predicate('matching(revision [, field])', safe=True)
1660 def matching(repo, subset, x):
1661 def matching(repo, subset, x):
1661 """Changesets in which a given set of fields match the set of fields in the
1662 """Changesets in which a given set of fields match the set of fields in the
1662 selected revision or set.
1663 selected revision or set.
1663
1664
1664 To match more than one field pass the list of fields to match separated
1665 To match more than one field pass the list of fields to match separated
1665 by spaces (e.g. ``author description``).
1666 by spaces (e.g. ``author description``).
1666
1667
1667 Valid fields are most regular revision fields and some special fields.
1668 Valid fields are most regular revision fields and some special fields.
1668
1669
1669 Regular revision fields are ``description``, ``author``, ``branch``,
1670 Regular revision fields are ``description``, ``author``, ``branch``,
1670 ``date``, ``files``, ``phase``, ``parents``, ``substate``, ``user``
1671 ``date``, ``files``, ``phase``, ``parents``, ``substate``, ``user``
1671 and ``diff``.
1672 and ``diff``.
1672 Note that ``author`` and ``user`` are synonyms. ``diff`` refers to the
1673 Note that ``author`` and ``user`` are synonyms. ``diff`` refers to the
1673 contents of the revision. Two revisions matching their ``diff`` will
1674 contents of the revision. Two revisions matching their ``diff`` will
1674 also match their ``files``.
1675 also match their ``files``.
1675
1676
1676 Special fields are ``summary`` and ``metadata``:
1677 Special fields are ``summary`` and ``metadata``:
1677 ``summary`` matches the first line of the description.
1678 ``summary`` matches the first line of the description.
1678 ``metadata`` is equivalent to matching ``description user date``
1679 ``metadata`` is equivalent to matching ``description user date``
1679 (i.e. it matches the main metadata fields).
1680 (i.e. it matches the main metadata fields).
1680
1681
1681 ``metadata`` is the default field which is used when no fields are
1682 ``metadata`` is the default field which is used when no fields are
1682 specified. You can match more than one field at a time.
1683 specified. You can match more than one field at a time.
1683 """
1684 """
1684 # i18n: "matching" is a keyword
1685 # i18n: "matching" is a keyword
1685 l = getargs(x, 1, 2, _("matching takes 1 or 2 arguments"))
1686 l = getargs(x, 1, 2, _("matching takes 1 or 2 arguments"))
1686
1687
1687 revs = getset(repo, fullreposet(repo), l[0])
1688 revs = getset(repo, fullreposet(repo), l[0])
1688
1689
1689 fieldlist = ['metadata']
1690 fieldlist = ['metadata']
1690 if len(l) > 1:
1691 if len(l) > 1:
1691 fieldlist = getstring(l[1],
1692 fieldlist = getstring(l[1],
1692 # i18n: "matching" is a keyword
1693 # i18n: "matching" is a keyword
1693 _("matching requires a string "
1694 _("matching requires a string "
1694 "as its second argument")).split()
1695 "as its second argument")).split()
1695
1696
1696 # Make sure that there are no repeated fields,
1697 # Make sure that there are no repeated fields,
1697 # expand the 'special' 'metadata' field type
1698 # expand the 'special' 'metadata' field type
1698 # and check the 'files' whenever we check the 'diff'
1699 # and check the 'files' whenever we check the 'diff'
1699 fields = []
1700 fields = []
1700 for field in fieldlist:
1701 for field in fieldlist:
1701 if field == 'metadata':
1702 if field == 'metadata':
1702 fields += ['user', 'description', 'date']
1703 fields += ['user', 'description', 'date']
1703 elif field == 'diff':
1704 elif field == 'diff':
1704 # a revision matching the diff must also match the files
1705 # a revision matching the diff must also match the files
1705 # since matching the diff is very costly, make sure to
1706 # since matching the diff is very costly, make sure to
1706 # also match the files first
1707 # also match the files first
1707 fields += ['files', 'diff']
1708 fields += ['files', 'diff']
1708 else:
1709 else:
1709 if field == 'author':
1710 if field == 'author':
1710 field = 'user'
1711 field = 'user'
1711 fields.append(field)
1712 fields.append(field)
1712 fields = set(fields)
1713 fields = set(fields)
1713 if 'summary' in fields and 'description' in fields:
1714 if 'summary' in fields and 'description' in fields:
1714 # If a revision matches its description it also matches its summary
1715 # If a revision matches its description it also matches its summary
1715 fields.discard('summary')
1716 fields.discard('summary')
1716
1717
1717 # We may want to match more than one field
1718 # We may want to match more than one field
1718 # Not all fields take the same amount of time to be matched
1719 # Not all fields take the same amount of time to be matched
1719 # Sort the selected fields in order of increasing matching cost
1720 # Sort the selected fields in order of increasing matching cost
1720 fieldorder = ['phase', 'parents', 'user', 'date', 'branch', 'summary',
1721 fieldorder = ['phase', 'parents', 'user', 'date', 'branch', 'summary',
1721 'files', 'description', 'substate', 'diff']
1722 'files', 'description', 'substate', 'diff']
1722 def fieldkeyfunc(f):
1723 def fieldkeyfunc(f):
1723 try:
1724 try:
1724 return fieldorder.index(f)
1725 return fieldorder.index(f)
1725 except ValueError:
1726 except ValueError:
1726 # assume an unknown field is very costly
1727 # assume an unknown field is very costly
1727 return len(fieldorder)
1728 return len(fieldorder)
1728 fields = list(fields)
1729 fields = list(fields)
1729 fields.sort(key=fieldkeyfunc)
1730 fields.sort(key=fieldkeyfunc)
1730
1731
1731 # Each field will be matched with its own "getfield" function
1732 # Each field will be matched with its own "getfield" function
1732 # which will be added to the getfieldfuncs array of functions
1733 # which will be added to the getfieldfuncs array of functions
1733 getfieldfuncs = []
1734 getfieldfuncs = []
1734 _funcs = {
1735 _funcs = {
1735 'user': lambda r: repo[r].user(),
1736 'user': lambda r: repo[r].user(),
1736 'branch': lambda r: repo[r].branch(),
1737 'branch': lambda r: repo[r].branch(),
1737 'date': lambda r: repo[r].date(),
1738 'date': lambda r: repo[r].date(),
1738 'description': lambda r: repo[r].description(),
1739 'description': lambda r: repo[r].description(),
1739 'files': lambda r: repo[r].files(),
1740 'files': lambda r: repo[r].files(),
1740 'parents': lambda r: repo[r].parents(),
1741 'parents': lambda r: repo[r].parents(),
1741 'phase': lambda r: repo[r].phase(),
1742 'phase': lambda r: repo[r].phase(),
1742 'substate': lambda r: repo[r].substate,
1743 'substate': lambda r: repo[r].substate,
1743 'summary': lambda r: repo[r].description().splitlines()[0],
1744 'summary': lambda r: repo[r].description().splitlines()[0],
1744 'diff': lambda r: list(repo[r].diff(git=True),)
1745 'diff': lambda r: list(repo[r].diff(git=True),)
1745 }
1746 }
1746 for info in fields:
1747 for info in fields:
1747 getfield = _funcs.get(info, None)
1748 getfield = _funcs.get(info, None)
1748 if getfield is None:
1749 if getfield is None:
1749 raise error.ParseError(
1750 raise error.ParseError(
1750 # i18n: "matching" is a keyword
1751 # i18n: "matching" is a keyword
1751 _("unexpected field name passed to matching: %s") % info)
1752 _("unexpected field name passed to matching: %s") % info)
1752 getfieldfuncs.append(getfield)
1753 getfieldfuncs.append(getfield)
1753 # convert the getfield array of functions into a "getinfo" function
1754 # convert the getfield array of functions into a "getinfo" function
1754 # which returns an array of field values (or a single value if there
1755 # which returns an array of field values (or a single value if there
1755 # is only one field to match)
1756 # is only one field to match)
1756 getinfo = lambda r: [f(r) for f in getfieldfuncs]
1757 getinfo = lambda r: [f(r) for f in getfieldfuncs]
1757
1758
1758 def matches(x):
1759 def matches(x):
1759 for rev in revs:
1760 for rev in revs:
1760 target = getinfo(rev)
1761 target = getinfo(rev)
1761 match = True
1762 match = True
1762 for n, f in enumerate(getfieldfuncs):
1763 for n, f in enumerate(getfieldfuncs):
1763 if target[n] != f(x):
1764 if target[n] != f(x):
1764 match = False
1765 match = False
1765 if match:
1766 if match:
1766 return True
1767 return True
1767 return False
1768 return False
1768
1769
1769 return subset.filter(matches, condrepr=('<matching%r %r>', fields, revs))
1770 return subset.filter(matches, condrepr=('<matching%r %r>', fields, revs))
1770
1771
1771 @predicate('reverse(set)', safe=True, takeorder=True)
1772 @predicate('reverse(set)', safe=True, takeorder=True)
1772 def reverse(repo, subset, x, order):
1773 def reverse(repo, subset, x, order):
1773 """Reverse order of set.
1774 """Reverse order of set.
1774 """
1775 """
1775 l = getset(repo, subset, x)
1776 l = getset(repo, subset, x)
1776 if order == defineorder:
1777 if order == defineorder:
1777 l.reverse()
1778 l.reverse()
1778 return l
1779 return l
1779
1780
1780 @predicate('roots(set)', safe=True)
1781 @predicate('roots(set)', safe=True)
1781 def roots(repo, subset, x):
1782 def roots(repo, subset, x):
1782 """Changesets in set with no parent changeset in set.
1783 """Changesets in set with no parent changeset in set.
1783 """
1784 """
1784 s = getset(repo, fullreposet(repo), x)
1785 s = getset(repo, fullreposet(repo), x)
1785 parents = repo.changelog.parentrevs
1786 parents = repo.changelog.parentrevs
1786 def filter(r):
1787 def filter(r):
1787 for p in parents(r):
1788 for p in parents(r):
1788 if 0 <= p and p in s:
1789 if 0 <= p and p in s:
1789 return False
1790 return False
1790 return True
1791 return True
1791 return subset & s.filter(filter, condrepr='<roots>')
1792 return subset & s.filter(filter, condrepr='<roots>')
1792
1793
1793 _sortkeyfuncs = {
1794 _sortkeyfuncs = {
1794 'rev': lambda c: c.rev(),
1795 'rev': lambda c: c.rev(),
1795 'branch': lambda c: c.branch(),
1796 'branch': lambda c: c.branch(),
1796 'desc': lambda c: c.description(),
1797 'desc': lambda c: c.description(),
1797 'user': lambda c: c.user(),
1798 'user': lambda c: c.user(),
1798 'author': lambda c: c.user(),
1799 'author': lambda c: c.user(),
1799 'date': lambda c: c.date()[0],
1800 'date': lambda c: c.date()[0],
1800 }
1801 }
1801
1802
1802 def _getsortargs(x):
1803 def _getsortargs(x):
1803 """Parse sort options into (set, [(key, reverse)], opts)"""
1804 """Parse sort options into (set, [(key, reverse)], opts)"""
1804 args = getargsdict(x, 'sort', 'set keys topo.firstbranch')
1805 args = getargsdict(x, 'sort', 'set keys topo.firstbranch')
1805 if 'set' not in args:
1806 if 'set' not in args:
1806 # i18n: "sort" is a keyword
1807 # i18n: "sort" is a keyword
1807 raise error.ParseError(_('sort requires one or two arguments'))
1808 raise error.ParseError(_('sort requires one or two arguments'))
1808 keys = "rev"
1809 keys = "rev"
1809 if 'keys' in args:
1810 if 'keys' in args:
1810 # i18n: "sort" is a keyword
1811 # i18n: "sort" is a keyword
1811 keys = getstring(args['keys'], _("sort spec must be a string"))
1812 keys = getstring(args['keys'], _("sort spec must be a string"))
1812
1813
1813 keyflags = []
1814 keyflags = []
1814 for k in keys.split():
1815 for k in keys.split():
1815 fk = k
1816 fk = k
1816 reverse = (k[0] == '-')
1817 reverse = (k[0] == '-')
1817 if reverse:
1818 if reverse:
1818 k = k[1:]
1819 k = k[1:]
1819 if k not in _sortkeyfuncs and k != 'topo':
1820 if k not in _sortkeyfuncs and k != 'topo':
1820 raise error.ParseError(_("unknown sort key %r") % fk)
1821 raise error.ParseError(_("unknown sort key %r") % fk)
1821 keyflags.append((k, reverse))
1822 keyflags.append((k, reverse))
1822
1823
1823 if len(keyflags) > 1 and any(k == 'topo' for k, reverse in keyflags):
1824 if len(keyflags) > 1 and any(k == 'topo' for k, reverse in keyflags):
1824 # i18n: "topo" is a keyword
1825 # i18n: "topo" is a keyword
1825 raise error.ParseError(_('topo sort order cannot be combined '
1826 raise error.ParseError(_('topo sort order cannot be combined '
1826 'with other sort keys'))
1827 'with other sort keys'))
1827
1828
1828 opts = {}
1829 opts = {}
1829 if 'topo.firstbranch' in args:
1830 if 'topo.firstbranch' in args:
1830 if any(k == 'topo' for k, reverse in keyflags):
1831 if any(k == 'topo' for k, reverse in keyflags):
1831 opts['topo.firstbranch'] = args['topo.firstbranch']
1832 opts['topo.firstbranch'] = args['topo.firstbranch']
1832 else:
1833 else:
1833 # i18n: "topo" and "topo.firstbranch" are keywords
1834 # i18n: "topo" and "topo.firstbranch" are keywords
1834 raise error.ParseError(_('topo.firstbranch can only be used '
1835 raise error.ParseError(_('topo.firstbranch can only be used '
1835 'when using the topo sort key'))
1836 'when using the topo sort key'))
1836
1837
1837 return args['set'], keyflags, opts
1838 return args['set'], keyflags, opts
1838
1839
1839 @predicate('sort(set[, [-]key... [, ...]])', safe=True, takeorder=True)
1840 @predicate('sort(set[, [-]key... [, ...]])', safe=True, takeorder=True)
1840 def sort(repo, subset, x, order):
1841 def sort(repo, subset, x, order):
1841 """Sort set by keys. The default sort order is ascending, specify a key
1842 """Sort set by keys. The default sort order is ascending, specify a key
1842 as ``-key`` to sort in descending order.
1843 as ``-key`` to sort in descending order.
1843
1844
1844 The keys can be:
1845 The keys can be:
1845
1846
1846 - ``rev`` for the revision number,
1847 - ``rev`` for the revision number,
1847 - ``branch`` for the branch name,
1848 - ``branch`` for the branch name,
1848 - ``desc`` for the commit message (description),
1849 - ``desc`` for the commit message (description),
1849 - ``user`` for user name (``author`` can be used as an alias),
1850 - ``user`` for user name (``author`` can be used as an alias),
1850 - ``date`` for the commit date
1851 - ``date`` for the commit date
1851 - ``topo`` for a reverse topographical sort
1852 - ``topo`` for a reverse topographical sort
1852
1853
1853 The ``topo`` sort order cannot be combined with other sort keys. This sort
1854 The ``topo`` sort order cannot be combined with other sort keys. This sort
1854 takes one optional argument, ``topo.firstbranch``, which takes a revset that
1855 takes one optional argument, ``topo.firstbranch``, which takes a revset that
1855 specifies what topographical branches to prioritize in the sort.
1856 specifies what topographical branches to prioritize in the sort.
1856
1857
1857 """
1858 """
1858 s, keyflags, opts = _getsortargs(x)
1859 s, keyflags, opts = _getsortargs(x)
1859 revs = getset(repo, subset, s)
1860 revs = getset(repo, subset, s)
1860
1861
1861 if not keyflags or order != defineorder:
1862 if not keyflags or order != defineorder:
1862 return revs
1863 return revs
1863 if len(keyflags) == 1 and keyflags[0][0] == "rev":
1864 if len(keyflags) == 1 and keyflags[0][0] == "rev":
1864 revs.sort(reverse=keyflags[0][1])
1865 revs.sort(reverse=keyflags[0][1])
1865 return revs
1866 return revs
1866 elif keyflags[0][0] == "topo":
1867 elif keyflags[0][0] == "topo":
1867 firstbranch = ()
1868 firstbranch = ()
1868 if 'topo.firstbranch' in opts:
1869 if 'topo.firstbranch' in opts:
1869 firstbranch = getset(repo, subset, opts['topo.firstbranch'])
1870 firstbranch = getset(repo, subset, opts['topo.firstbranch'])
1870 revs = baseset(_toposort(revs, repo.changelog.parentrevs, firstbranch),
1871 revs = baseset(_toposort(revs, repo.changelog.parentrevs, firstbranch),
1871 istopo=True)
1872 istopo=True)
1872 if keyflags[0][1]:
1873 if keyflags[0][1]:
1873 revs.reverse()
1874 revs.reverse()
1874 return revs
1875 return revs
1875
1876
1876 # sort() is guaranteed to be stable
1877 # sort() is guaranteed to be stable
1877 ctxs = [repo[r] for r in revs]
1878 ctxs = [repo[r] for r in revs]
1878 for k, reverse in reversed(keyflags):
1879 for k, reverse in reversed(keyflags):
1879 ctxs.sort(key=_sortkeyfuncs[k], reverse=reverse)
1880 ctxs.sort(key=_sortkeyfuncs[k], reverse=reverse)
1880 return baseset([c.rev() for c in ctxs])
1881 return baseset([c.rev() for c in ctxs])
1881
1882
1882 def _toposort(revs, parentsfunc, firstbranch=()):
1883 def _toposort(revs, parentsfunc, firstbranch=()):
1883 """Yield revisions from heads to roots one (topo) branch at a time.
1884 """Yield revisions from heads to roots one (topo) branch at a time.
1884
1885
1885 This function aims to be used by a graph generator that wishes to minimize
1886 This function aims to be used by a graph generator that wishes to minimize
1886 the number of parallel branches and their interleaving.
1887 the number of parallel branches and their interleaving.
1887
1888
1888 Example iteration order (numbers show the "true" order in a changelog):
1889 Example iteration order (numbers show the "true" order in a changelog):
1889
1890
1890 o 4
1891 o 4
1891 |
1892 |
1892 o 1
1893 o 1
1893 |
1894 |
1894 | o 3
1895 | o 3
1895 | |
1896 | |
1896 | o 2
1897 | o 2
1897 |/
1898 |/
1898 o 0
1899 o 0
1899
1900
1900 Note that the ancestors of merges are understood by the current
1901 Note that the ancestors of merges are understood by the current
1901 algorithm to be on the same branch. This means no reordering will
1902 algorithm to be on the same branch. This means no reordering will
1902 occur behind a merge.
1903 occur behind a merge.
1903 """
1904 """
1904
1905
1905 ### Quick summary of the algorithm
1906 ### Quick summary of the algorithm
1906 #
1907 #
1907 # This function is based around a "retention" principle. We keep revisions
1908 # This function is based around a "retention" principle. We keep revisions
1908 # in memory until we are ready to emit a whole branch that immediately
1909 # in memory until we are ready to emit a whole branch that immediately
1909 # "merges" into an existing one. This reduces the number of parallel
1910 # "merges" into an existing one. This reduces the number of parallel
1910 # branches with interleaved revisions.
1911 # branches with interleaved revisions.
1911 #
1912 #
1912 # During iteration revs are split into two groups:
1913 # During iteration revs are split into two groups:
1913 # A) revision already emitted
1914 # A) revision already emitted
1914 # B) revision in "retention". They are stored as different subgroups.
1915 # B) revision in "retention". They are stored as different subgroups.
1915 #
1916 #
1916 # for each REV, we do the following logic:
1917 # for each REV, we do the following logic:
1917 #
1918 #
1918 # 1) if REV is a parent of (A), we will emit it. If there is a
1919 # 1) if REV is a parent of (A), we will emit it. If there is a
1919 # retention group ((B) above) that is blocked on REV being
1920 # retention group ((B) above) that is blocked on REV being
1920 # available, we emit all the revisions out of that retention
1921 # available, we emit all the revisions out of that retention
1921 # group first.
1922 # group first.
1922 #
1923 #
1923 # 2) else, we'll search for a subgroup in (B) awaiting for REV to be
1924 # 2) else, we'll search for a subgroup in (B) awaiting for REV to be
1924 # available, if such subgroup exist, we add REV to it and the subgroup is
1925 # available, if such subgroup exist, we add REV to it and the subgroup is
1925 # now awaiting for REV.parents() to be available.
1926 # now awaiting for REV.parents() to be available.
1926 #
1927 #
1927 # 3) finally if no such group existed in (B), we create a new subgroup.
1928 # 3) finally if no such group existed in (B), we create a new subgroup.
1928 #
1929 #
1929 #
1930 #
1930 # To bootstrap the algorithm, we emit the tipmost revision (which
1931 # To bootstrap the algorithm, we emit the tipmost revision (which
1931 # puts it in group (A) from above).
1932 # puts it in group (A) from above).
1932
1933
1933 revs.sort(reverse=True)
1934 revs.sort(reverse=True)
1934
1935
1935 # Set of parents of revision that have been emitted. They can be considered
1936 # Set of parents of revision that have been emitted. They can be considered
1936 # unblocked as the graph generator is already aware of them so there is no
1937 # unblocked as the graph generator is already aware of them so there is no
1937 # need to delay the revisions that reference them.
1938 # need to delay the revisions that reference them.
1938 #
1939 #
1939 # If someone wants to prioritize a branch over the others, pre-filling this
1940 # If someone wants to prioritize a branch over the others, pre-filling this
1940 # set will force all other branches to wait until this branch is ready to be
1941 # set will force all other branches to wait until this branch is ready to be
1941 # emitted.
1942 # emitted.
1942 unblocked = set(firstbranch)
1943 unblocked = set(firstbranch)
1943
1944
1944 # list of groups waiting to be displayed, each group is defined by:
1945 # list of groups waiting to be displayed, each group is defined by:
1945 #
1946 #
1946 # (revs: lists of revs waiting to be displayed,
1947 # (revs: lists of revs waiting to be displayed,
1947 # blocked: set of that cannot be displayed before those in 'revs')
1948 # blocked: set of that cannot be displayed before those in 'revs')
1948 #
1949 #
1949 # The second value ('blocked') correspond to parents of any revision in the
1950 # The second value ('blocked') correspond to parents of any revision in the
1950 # group ('revs') that is not itself contained in the group. The main idea
1951 # group ('revs') that is not itself contained in the group. The main idea
1951 # of this algorithm is to delay as much as possible the emission of any
1952 # of this algorithm is to delay as much as possible the emission of any
1952 # revision. This means waiting for the moment we are about to display
1953 # revision. This means waiting for the moment we are about to display
1953 # these parents to display the revs in a group.
1954 # these parents to display the revs in a group.
1954 #
1955 #
1955 # This first implementation is smart until it encounters a merge: it will
1956 # This first implementation is smart until it encounters a merge: it will
1956 # emit revs as soon as any parent is about to be emitted and can grow an
1957 # emit revs as soon as any parent is about to be emitted and can grow an
1957 # arbitrary number of revs in 'blocked'. In practice this mean we properly
1958 # arbitrary number of revs in 'blocked'. In practice this mean we properly
1958 # retains new branches but gives up on any special ordering for ancestors
1959 # retains new branches but gives up on any special ordering for ancestors
1959 # of merges. The implementation can be improved to handle this better.
1960 # of merges. The implementation can be improved to handle this better.
1960 #
1961 #
1961 # The first subgroup is special. It corresponds to all the revision that
1962 # The first subgroup is special. It corresponds to all the revision that
1962 # were already emitted. The 'revs' lists is expected to be empty and the
1963 # were already emitted. The 'revs' lists is expected to be empty and the
1963 # 'blocked' set contains the parents revisions of already emitted revision.
1964 # 'blocked' set contains the parents revisions of already emitted revision.
1964 #
1965 #
1965 # You could pre-seed the <parents> set of groups[0] to a specific
1966 # You could pre-seed the <parents> set of groups[0] to a specific
1966 # changesets to select what the first emitted branch should be.
1967 # changesets to select what the first emitted branch should be.
1967 groups = [([], unblocked)]
1968 groups = [([], unblocked)]
1968 pendingheap = []
1969 pendingheap = []
1969 pendingset = set()
1970 pendingset = set()
1970
1971
1971 heapq.heapify(pendingheap)
1972 heapq.heapify(pendingheap)
1972 heappop = heapq.heappop
1973 heappop = heapq.heappop
1973 heappush = heapq.heappush
1974 heappush = heapq.heappush
1974 for currentrev in revs:
1975 for currentrev in revs:
1975 # Heap works with smallest element, we want highest so we invert
1976 # Heap works with smallest element, we want highest so we invert
1976 if currentrev not in pendingset:
1977 if currentrev not in pendingset:
1977 heappush(pendingheap, -currentrev)
1978 heappush(pendingheap, -currentrev)
1978 pendingset.add(currentrev)
1979 pendingset.add(currentrev)
1979 # iterates on pending rev until after the current rev have been
1980 # iterates on pending rev until after the current rev have been
1980 # processed.
1981 # processed.
1981 rev = None
1982 rev = None
1982 while rev != currentrev:
1983 while rev != currentrev:
1983 rev = -heappop(pendingheap)
1984 rev = -heappop(pendingheap)
1984 pendingset.remove(rev)
1985 pendingset.remove(rev)
1985
1986
1986 # Seek for a subgroup blocked, waiting for the current revision.
1987 # Seek for a subgroup blocked, waiting for the current revision.
1987 matching = [i for i, g in enumerate(groups) if rev in g[1]]
1988 matching = [i for i, g in enumerate(groups) if rev in g[1]]
1988
1989
1989 if matching:
1990 if matching:
1990 # The main idea is to gather together all sets that are blocked
1991 # The main idea is to gather together all sets that are blocked
1991 # on the same revision.
1992 # on the same revision.
1992 #
1993 #
1993 # Groups are merged when a common blocking ancestor is
1994 # Groups are merged when a common blocking ancestor is
1994 # observed. For example, given two groups:
1995 # observed. For example, given two groups:
1995 #
1996 #
1996 # revs [5, 4] waiting for 1
1997 # revs [5, 4] waiting for 1
1997 # revs [3, 2] waiting for 1
1998 # revs [3, 2] waiting for 1
1998 #
1999 #
1999 # These two groups will be merged when we process
2000 # These two groups will be merged when we process
2000 # 1. In theory, we could have merged the groups when
2001 # 1. In theory, we could have merged the groups when
2001 # we added 2 to the group it is now in (we could have
2002 # we added 2 to the group it is now in (we could have
2002 # noticed the groups were both blocked on 1 then), but
2003 # noticed the groups were both blocked on 1 then), but
2003 # the way it works now makes the algorithm simpler.
2004 # the way it works now makes the algorithm simpler.
2004 #
2005 #
2005 # We also always keep the oldest subgroup first. We can
2006 # We also always keep the oldest subgroup first. We can
2006 # probably improve the behavior by having the longest set
2007 # probably improve the behavior by having the longest set
2007 # first. That way, graph algorithms could minimise the length
2008 # first. That way, graph algorithms could minimise the length
2008 # of parallel lines their drawing. This is currently not done.
2009 # of parallel lines their drawing. This is currently not done.
2009 targetidx = matching.pop(0)
2010 targetidx = matching.pop(0)
2010 trevs, tparents = groups[targetidx]
2011 trevs, tparents = groups[targetidx]
2011 for i in matching:
2012 for i in matching:
2012 gr = groups[i]
2013 gr = groups[i]
2013 trevs.extend(gr[0])
2014 trevs.extend(gr[0])
2014 tparents |= gr[1]
2015 tparents |= gr[1]
2015 # delete all merged subgroups (except the one we kept)
2016 # delete all merged subgroups (except the one we kept)
2016 # (starting from the last subgroup for performance and
2017 # (starting from the last subgroup for performance and
2017 # sanity reasons)
2018 # sanity reasons)
2018 for i in reversed(matching):
2019 for i in reversed(matching):
2019 del groups[i]
2020 del groups[i]
2020 else:
2021 else:
2021 # This is a new head. We create a new subgroup for it.
2022 # This is a new head. We create a new subgroup for it.
2022 targetidx = len(groups)
2023 targetidx = len(groups)
2023 groups.append(([], {rev}))
2024 groups.append(([], {rev}))
2024
2025
2025 gr = groups[targetidx]
2026 gr = groups[targetidx]
2026
2027
2027 # We now add the current nodes to this subgroups. This is done
2028 # We now add the current nodes to this subgroups. This is done
2028 # after the subgroup merging because all elements from a subgroup
2029 # after the subgroup merging because all elements from a subgroup
2029 # that relied on this rev must precede it.
2030 # that relied on this rev must precede it.
2030 #
2031 #
2031 # we also update the <parents> set to include the parents of the
2032 # we also update the <parents> set to include the parents of the
2032 # new nodes.
2033 # new nodes.
2033 if rev == currentrev: # only display stuff in rev
2034 if rev == currentrev: # only display stuff in rev
2034 gr[0].append(rev)
2035 gr[0].append(rev)
2035 gr[1].remove(rev)
2036 gr[1].remove(rev)
2036 parents = [p for p in parentsfunc(rev) if p > node.nullrev]
2037 parents = [p for p in parentsfunc(rev) if p > node.nullrev]
2037 gr[1].update(parents)
2038 gr[1].update(parents)
2038 for p in parents:
2039 for p in parents:
2039 if p not in pendingset:
2040 if p not in pendingset:
2040 pendingset.add(p)
2041 pendingset.add(p)
2041 heappush(pendingheap, -p)
2042 heappush(pendingheap, -p)
2042
2043
2043 # Look for a subgroup to display
2044 # Look for a subgroup to display
2044 #
2045 #
2045 # When unblocked is empty (if clause), we were not waiting for any
2046 # When unblocked is empty (if clause), we were not waiting for any
2046 # revisions during the first iteration (if no priority was given) or
2047 # revisions during the first iteration (if no priority was given) or
2047 # if we emitted a whole disconnected set of the graph (reached a
2048 # if we emitted a whole disconnected set of the graph (reached a
2048 # root). In that case we arbitrarily take the oldest known
2049 # root). In that case we arbitrarily take the oldest known
2049 # subgroup. The heuristic could probably be better.
2050 # subgroup. The heuristic could probably be better.
2050 #
2051 #
2051 # Otherwise (elif clause) if the subgroup is blocked on
2052 # Otherwise (elif clause) if the subgroup is blocked on
2052 # a revision we just emitted, we can safely emit it as
2053 # a revision we just emitted, we can safely emit it as
2053 # well.
2054 # well.
2054 if not unblocked:
2055 if not unblocked:
2055 if len(groups) > 1: # display other subset
2056 if len(groups) > 1: # display other subset
2056 targetidx = 1
2057 targetidx = 1
2057 gr = groups[1]
2058 gr = groups[1]
2058 elif not gr[1] & unblocked:
2059 elif not gr[1] & unblocked:
2059 gr = None
2060 gr = None
2060
2061
2061 if gr is not None:
2062 if gr is not None:
2062 # update the set of awaited revisions with the one from the
2063 # update the set of awaited revisions with the one from the
2063 # subgroup
2064 # subgroup
2064 unblocked |= gr[1]
2065 unblocked |= gr[1]
2065 # output all revisions in the subgroup
2066 # output all revisions in the subgroup
2066 for r in gr[0]:
2067 for r in gr[0]:
2067 yield r
2068 yield r
2068 # delete the subgroup that you just output
2069 # delete the subgroup that you just output
2069 # unless it is groups[0] in which case you just empty it.
2070 # unless it is groups[0] in which case you just empty it.
2070 if targetidx:
2071 if targetidx:
2071 del groups[targetidx]
2072 del groups[targetidx]
2072 else:
2073 else:
2073 gr[0][:] = []
2074 gr[0][:] = []
2074 # Check if we have some subgroup waiting for revisions we are not going to
2075 # Check if we have some subgroup waiting for revisions we are not going to
2075 # iterate over
2076 # iterate over
2076 for g in groups:
2077 for g in groups:
2077 for r in g[0]:
2078 for r in g[0]:
2078 yield r
2079 yield r
2079
2080
2080 @predicate('subrepo([pattern])')
2081 @predicate('subrepo([pattern])')
2081 def subrepo(repo, subset, x):
2082 def subrepo(repo, subset, x):
2082 """Changesets that add, modify or remove the given subrepo. If no subrepo
2083 """Changesets that add, modify or remove the given subrepo. If no subrepo
2083 pattern is named, any subrepo changes are returned.
2084 pattern is named, any subrepo changes are returned.
2084 """
2085 """
2085 # i18n: "subrepo" is a keyword
2086 # i18n: "subrepo" is a keyword
2086 args = getargs(x, 0, 1, _('subrepo takes at most one argument'))
2087 args = getargs(x, 0, 1, _('subrepo takes at most one argument'))
2087 pat = None
2088 pat = None
2088 if len(args) != 0:
2089 if len(args) != 0:
2089 pat = getstring(args[0], _("subrepo requires a pattern"))
2090 pat = getstring(args[0], _("subrepo requires a pattern"))
2090
2091
2091 m = matchmod.exact(repo.root, repo.root, ['.hgsubstate'])
2092 m = matchmod.exact(repo.root, repo.root, ['.hgsubstate'])
2092
2093
2093 def submatches(names):
2094 def submatches(names):
2094 k, p, m = util.stringmatcher(pat)
2095 k, p, m = util.stringmatcher(pat)
2095 for name in names:
2096 for name in names:
2096 if m(name):
2097 if m(name):
2097 yield name
2098 yield name
2098
2099
2099 def matches(x):
2100 def matches(x):
2100 c = repo[x]
2101 c = repo[x]
2101 s = repo.status(c.p1().node(), c.node(), match=m)
2102 s = repo.status(c.p1().node(), c.node(), match=m)
2102
2103
2103 if pat is None:
2104 if pat is None:
2104 return s.added or s.modified or s.removed
2105 return s.added or s.modified or s.removed
2105
2106
2106 if s.added:
2107 if s.added:
2107 return any(submatches(c.substate.keys()))
2108 return any(submatches(c.substate.keys()))
2108
2109
2109 if s.modified:
2110 if s.modified:
2110 subs = set(c.p1().substate.keys())
2111 subs = set(c.p1().substate.keys())
2111 subs.update(c.substate.keys())
2112 subs.update(c.substate.keys())
2112
2113
2113 for path in submatches(subs):
2114 for path in submatches(subs):
2114 if c.p1().substate.get(path) != c.substate.get(path):
2115 if c.p1().substate.get(path) != c.substate.get(path):
2115 return True
2116 return True
2116
2117
2117 if s.removed:
2118 if s.removed:
2118 return any(submatches(c.p1().substate.keys()))
2119 return any(submatches(c.p1().substate.keys()))
2119
2120
2120 return False
2121 return False
2121
2122
2122 return subset.filter(matches, condrepr=('<subrepo %r>', pat))
2123 return subset.filter(matches, condrepr=('<subrepo %r>', pat))
2123
2124
2124 def _substringmatcher(pattern, casesensitive=True):
2125 def _substringmatcher(pattern, casesensitive=True):
2125 kind, pattern, matcher = util.stringmatcher(pattern,
2126 kind, pattern, matcher = util.stringmatcher(pattern,
2126 casesensitive=casesensitive)
2127 casesensitive=casesensitive)
2127 if kind == 'literal':
2128 if kind == 'literal':
2128 if not casesensitive:
2129 if not casesensitive:
2129 pattern = encoding.lower(pattern)
2130 pattern = encoding.lower(pattern)
2130 matcher = lambda s: pattern in encoding.lower(s)
2131 matcher = lambda s: pattern in encoding.lower(s)
2131 else:
2132 else:
2132 matcher = lambda s: pattern in s
2133 matcher = lambda s: pattern in s
2133 return kind, pattern, matcher
2134 return kind, pattern, matcher
2134
2135
2135 @predicate('tag([name])', safe=True)
2136 @predicate('tag([name])', safe=True)
2136 def tag(repo, subset, x):
2137 def tag(repo, subset, x):
2137 """The specified tag by name, or all tagged revisions if no name is given.
2138 """The specified tag by name, or all tagged revisions if no name is given.
2138
2139
2139 Pattern matching is supported for `name`. See
2140 Pattern matching is supported for `name`. See
2140 :hg:`help revisions.patterns`.
2141 :hg:`help revisions.patterns`.
2141 """
2142 """
2142 # i18n: "tag" is a keyword
2143 # i18n: "tag" is a keyword
2143 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
2144 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
2144 cl = repo.changelog
2145 cl = repo.changelog
2145 if args:
2146 if args:
2146 pattern = getstring(args[0],
2147 pattern = getstring(args[0],
2147 # i18n: "tag" is a keyword
2148 # i18n: "tag" is a keyword
2148 _('the argument to tag must be a string'))
2149 _('the argument to tag must be a string'))
2149 kind, pattern, matcher = util.stringmatcher(pattern)
2150 kind, pattern, matcher = util.stringmatcher(pattern)
2150 if kind == 'literal':
2151 if kind == 'literal':
2151 # avoid resolving all tags
2152 # avoid resolving all tags
2152 tn = repo._tagscache.tags.get(pattern, None)
2153 tn = repo._tagscache.tags.get(pattern, None)
2153 if tn is None:
2154 if tn is None:
2154 raise error.RepoLookupError(_("tag '%s' does not exist")
2155 raise error.RepoLookupError(_("tag '%s' does not exist")
2155 % pattern)
2156 % pattern)
2156 s = {repo[tn].rev()}
2157 s = {repo[tn].rev()}
2157 else:
2158 else:
2158 s = {cl.rev(n) for t, n in repo.tagslist() if matcher(t)}
2159 s = {cl.rev(n) for t, n in repo.tagslist() if matcher(t)}
2159 else:
2160 else:
2160 s = {cl.rev(n) for t, n in repo.tagslist() if t != 'tip'}
2161 s = {cl.rev(n) for t, n in repo.tagslist() if t != 'tip'}
2161 return subset & s
2162 return subset & s
2162
2163
2163 @predicate('tagged', safe=True)
2164 @predicate('tagged', safe=True)
2164 def tagged(repo, subset, x):
2165 def tagged(repo, subset, x):
2165 return tag(repo, subset, x)
2166 return tag(repo, subset, x)
2166
2167
2167 @predicate('unstable()', safe=True)
2168 @predicate('unstable()', safe=True)
2168 def unstable(repo, subset, x):
2169 def unstable(repo, subset, x):
2169 """Non-obsolete changesets with obsolete ancestors.
2170 """Non-obsolete changesets with obsolete ancestors.
2170 """
2171 """
2171 # i18n: "unstable" is a keyword
2172 # i18n: "unstable" is a keyword
2172 getargs(x, 0, 0, _("unstable takes no arguments"))
2173 getargs(x, 0, 0, _("unstable takes no arguments"))
2173 unstables = obsmod.getrevs(repo, 'unstable')
2174 unstables = obsmod.getrevs(repo, 'unstable')
2174 return subset & unstables
2175 return subset & unstables
2175
2176
2176
2177
2177 @predicate('user(string)', safe=True)
2178 @predicate('user(string)', safe=True)
2178 def user(repo, subset, x):
2179 def user(repo, subset, x):
2179 """User name contains string. The match is case-insensitive.
2180 """User name contains string. The match is case-insensitive.
2180
2181
2181 Pattern matching is supported for `string`. See
2182 Pattern matching is supported for `string`. See
2182 :hg:`help revisions.patterns`.
2183 :hg:`help revisions.patterns`.
2183 """
2184 """
2184 return author(repo, subset, x)
2185 return author(repo, subset, x)
2185
2186
2186 @predicate('wdir()', safe=True)
2187 @predicate('wdir()', safe=True)
2187 def wdir(repo, subset, x):
2188 def wdir(repo, subset, x):
2188 """Working directory. (EXPERIMENTAL)"""
2189 """Working directory. (EXPERIMENTAL)"""
2189 # i18n: "wdir" is a keyword
2190 # i18n: "wdir" is a keyword
2190 getargs(x, 0, 0, _("wdir takes no arguments"))
2191 getargs(x, 0, 0, _("wdir takes no arguments"))
2191 if node.wdirrev in subset or isinstance(subset, fullreposet):
2192 if node.wdirrev in subset or isinstance(subset, fullreposet):
2192 return baseset([node.wdirrev])
2193 return baseset([node.wdirrev])
2193 return baseset()
2194 return baseset()
2194
2195
2195 def _orderedlist(repo, subset, x):
2196 def _orderedlist(repo, subset, x):
2196 s = getstring(x, "internal error")
2197 s = getstring(x, "internal error")
2197 if not s:
2198 if not s:
2198 return baseset()
2199 return baseset()
2199 # remove duplicates here. it's difficult for caller to deduplicate sets
2200 # remove duplicates here. it's difficult for caller to deduplicate sets
2200 # because different symbols can point to the same rev.
2201 # because different symbols can point to the same rev.
2201 cl = repo.changelog
2202 cl = repo.changelog
2202 ls = []
2203 ls = []
2203 seen = set()
2204 seen = set()
2204 for t in s.split('\0'):
2205 for t in s.split('\0'):
2205 try:
2206 try:
2206 # fast path for integer revision
2207 # fast path for integer revision
2207 r = int(t)
2208 r = int(t)
2208 if str(r) != t or r not in cl:
2209 if str(r) != t or r not in cl:
2209 raise ValueError
2210 raise ValueError
2210 revs = [r]
2211 revs = [r]
2211 except ValueError:
2212 except ValueError:
2212 revs = stringset(repo, subset, t)
2213 revs = stringset(repo, subset, t)
2213
2214
2214 for r in revs:
2215 for r in revs:
2215 if r in seen:
2216 if r in seen:
2216 continue
2217 continue
2217 if (r in subset
2218 if (r in subset
2218 or r == node.nullrev and isinstance(subset, fullreposet)):
2219 or r == node.nullrev and isinstance(subset, fullreposet)):
2219 ls.append(r)
2220 ls.append(r)
2220 seen.add(r)
2221 seen.add(r)
2221 return baseset(ls)
2222 return baseset(ls)
2222
2223
2223 # for internal use
2224 # for internal use
2224 @predicate('_list', safe=True, takeorder=True)
2225 @predicate('_list', safe=True, takeorder=True)
2225 def _list(repo, subset, x, order):
2226 def _list(repo, subset, x, order):
2226 if order == followorder:
2227 if order == followorder:
2227 # slow path to take the subset order
2228 # slow path to take the subset order
2228 return subset & _orderedlist(repo, fullreposet(repo), x)
2229 return subset & _orderedlist(repo, fullreposet(repo), x)
2229 else:
2230 else:
2230 return _orderedlist(repo, subset, x)
2231 return _orderedlist(repo, subset, x)
2231
2232
2232 def _orderedintlist(repo, subset, x):
2233 def _orderedintlist(repo, subset, x):
2233 s = getstring(x, "internal error")
2234 s = getstring(x, "internal error")
2234 if not s:
2235 if not s:
2235 return baseset()
2236 return baseset()
2236 ls = [int(r) for r in s.split('\0')]
2237 ls = [int(r) for r in s.split('\0')]
2237 s = subset
2238 s = subset
2238 return baseset([r for r in ls if r in s])
2239 return baseset([r for r in ls if r in s])
2239
2240
2240 # for internal use
2241 # for internal use
2241 @predicate('_intlist', safe=True, takeorder=True)
2242 @predicate('_intlist', safe=True, takeorder=True)
2242 def _intlist(repo, subset, x, order):
2243 def _intlist(repo, subset, x, order):
2243 if order == followorder:
2244 if order == followorder:
2244 # slow path to take the subset order
2245 # slow path to take the subset order
2245 return subset & _orderedintlist(repo, fullreposet(repo), x)
2246 return subset & _orderedintlist(repo, fullreposet(repo), x)
2246 else:
2247 else:
2247 return _orderedintlist(repo, subset, x)
2248 return _orderedintlist(repo, subset, x)
2248
2249
2249 def _orderedhexlist(repo, subset, x):
2250 def _orderedhexlist(repo, subset, x):
2250 s = getstring(x, "internal error")
2251 s = getstring(x, "internal error")
2251 if not s:
2252 if not s:
2252 return baseset()
2253 return baseset()
2253 cl = repo.changelog
2254 cl = repo.changelog
2254 ls = [cl.rev(node.bin(r)) for r in s.split('\0')]
2255 ls = [cl.rev(node.bin(r)) for r in s.split('\0')]
2255 s = subset
2256 s = subset
2256 return baseset([r for r in ls if r in s])
2257 return baseset([r for r in ls if r in s])
2257
2258
2258 # for internal use
2259 # for internal use
2259 @predicate('_hexlist', safe=True, takeorder=True)
2260 @predicate('_hexlist', safe=True, takeorder=True)
2260 def _hexlist(repo, subset, x, order):
2261 def _hexlist(repo, subset, x, order):
2261 if order == followorder:
2262 if order == followorder:
2262 # slow path to take the subset order
2263 # slow path to take the subset order
2263 return subset & _orderedhexlist(repo, fullreposet(repo), x)
2264 return subset & _orderedhexlist(repo, fullreposet(repo), x)
2264 else:
2265 else:
2265 return _orderedhexlist(repo, subset, x)
2266 return _orderedhexlist(repo, subset, x)
2266
2267
2267 methods = {
2268 methods = {
2268 "range": rangeset,
2269 "range": rangeset,
2269 "rangeall": rangeall,
2270 "rangeall": rangeall,
2270 "rangepre": rangepre,
2271 "rangepre": rangepre,
2271 "rangepost": rangepost,
2272 "rangepost": rangepost,
2272 "dagrange": dagrange,
2273 "dagrange": dagrange,
2273 "string": stringset,
2274 "string": stringset,
2274 "symbol": stringset,
2275 "symbol": stringset,
2275 "and": andset,
2276 "and": andset,
2276 "or": orset,
2277 "or": orset,
2277 "not": notset,
2278 "not": notset,
2278 "difference": differenceset,
2279 "difference": differenceset,
2279 "list": listset,
2280 "list": listset,
2280 "keyvalue": keyvaluepair,
2281 "keyvalue": keyvaluepair,
2281 "func": func,
2282 "func": func,
2282 "ancestor": ancestorspec,
2283 "ancestor": ancestorspec,
2283 "parent": parentspec,
2284 "parent": parentspec,
2284 "parentpost": parentpost,
2285 "parentpost": parentpost,
2285 }
2286 }
2286
2287
2287 def posttreebuilthook(tree, repo):
2288 def posttreebuilthook(tree, repo):
2288 # hook for extensions to execute code on the optimized tree
2289 # hook for extensions to execute code on the optimized tree
2289 pass
2290 pass
2290
2291
2291 def match(ui, spec, repo=None, order=defineorder):
2292 def match(ui, spec, repo=None, order=defineorder):
2292 """Create a matcher for a single revision spec
2293 """Create a matcher for a single revision spec
2293
2294
2294 If order=followorder, a matcher takes the ordering specified by the input
2295 If order=followorder, a matcher takes the ordering specified by the input
2295 set.
2296 set.
2296 """
2297 """
2297 return matchany(ui, [spec], repo=repo, order=order)
2298 return matchany(ui, [spec], repo=repo, order=order)
2298
2299
2299 def matchany(ui, specs, repo=None, order=defineorder):
2300 def matchany(ui, specs, repo=None, order=defineorder):
2300 """Create a matcher that will include any revisions matching one of the
2301 """Create a matcher that will include any revisions matching one of the
2301 given specs
2302 given specs
2302
2303
2303 If order=followorder, a matcher takes the ordering specified by the input
2304 If order=followorder, a matcher takes the ordering specified by the input
2304 set.
2305 set.
2305 """
2306 """
2306 if not specs:
2307 if not specs:
2307 def mfunc(repo, subset=None):
2308 def mfunc(repo, subset=None):
2308 return baseset()
2309 return baseset()
2309 return mfunc
2310 return mfunc
2310 if not all(specs):
2311 if not all(specs):
2311 raise error.ParseError(_("empty query"))
2312 raise error.ParseError(_("empty query"))
2312 lookup = None
2313 lookup = None
2313 if repo:
2314 if repo:
2314 lookup = repo.__contains__
2315 lookup = repo.__contains__
2315 if len(specs) == 1:
2316 if len(specs) == 1:
2316 tree = revsetlang.parse(specs[0], lookup)
2317 tree = revsetlang.parse(specs[0], lookup)
2317 else:
2318 else:
2318 tree = ('or',
2319 tree = ('or',
2319 ('list',) + tuple(revsetlang.parse(s, lookup) for s in specs))
2320 ('list',) + tuple(revsetlang.parse(s, lookup) for s in specs))
2320
2321
2321 if ui:
2322 if ui:
2322 tree = revsetlang.expandaliases(ui, tree)
2323 tree = revsetlang.expandaliases(ui, tree)
2323 tree = revsetlang.foldconcat(tree)
2324 tree = revsetlang.foldconcat(tree)
2324 tree = revsetlang.analyze(tree, order)
2325 tree = revsetlang.analyze(tree, order)
2325 tree = revsetlang.optimize(tree)
2326 tree = revsetlang.optimize(tree)
2326 posttreebuilthook(tree, repo)
2327 posttreebuilthook(tree, repo)
2327 return makematcher(tree)
2328 return makematcher(tree)
2328
2329
2329 def makematcher(tree):
2330 def makematcher(tree):
2330 """Create a matcher from an evaluatable tree"""
2331 """Create a matcher from an evaluatable tree"""
2331 def mfunc(repo, subset=None):
2332 def mfunc(repo, subset=None):
2332 if subset is None:
2333 if subset is None:
2333 subset = fullreposet(repo)
2334 subset = fullreposet(repo)
2334 return getset(repo, subset, tree)
2335 return getset(repo, subset, tree)
2335 return mfunc
2336 return mfunc
2336
2337
2337 def loadpredicate(ui, extname, registrarobj):
2338 def loadpredicate(ui, extname, registrarobj):
2338 """Load revset predicates from specified registrarobj
2339 """Load revset predicates from specified registrarobj
2339 """
2340 """
2340 for name, func in registrarobj._table.iteritems():
2341 for name, func in registrarobj._table.iteritems():
2341 symbols[name] = func
2342 symbols[name] = func
2342 if func._safe:
2343 if func._safe:
2343 safesymbols.add(name)
2344 safesymbols.add(name)
2344
2345
2345 # load built-in predicates explicitly to setup safesymbols
2346 # load built-in predicates explicitly to setup safesymbols
2346 loadpredicate(None, None, predicate)
2347 loadpredicate(None, None, predicate)
2347
2348
2348 # tell hggettext to extract docstrings from these functions:
2349 # tell hggettext to extract docstrings from these functions:
2349 i18nfunctions = symbols.values()
2350 i18nfunctions = symbols.values()
@@ -1,3862 +1,3875 b''
1 $ HGENCODING=utf-8
1 $ HGENCODING=utf-8
2 $ export HGENCODING
2 $ export HGENCODING
3 $ cat > testrevset.py << EOF
3 $ cat > testrevset.py << EOF
4 > import mercurial.revset
4 > import mercurial.revset
5 >
5 >
6 > baseset = mercurial.revset.baseset
6 > baseset = mercurial.revset.baseset
7 >
7 >
8 > def r3232(repo, subset, x):
8 > def r3232(repo, subset, x):
9 > """"simple revset that return [3,2,3,2]
9 > """"simple revset that return [3,2,3,2]
10 >
10 >
11 > revisions duplicated on purpose.
11 > revisions duplicated on purpose.
12 > """
12 > """
13 > if 3 not in subset:
13 > if 3 not in subset:
14 > if 2 in subset:
14 > if 2 in subset:
15 > return baseset([2,2])
15 > return baseset([2,2])
16 > return baseset()
16 > return baseset()
17 > return baseset([3,3,2,2])
17 > return baseset([3,3,2,2])
18 >
18 >
19 > mercurial.revset.symbols['r3232'] = r3232
19 > mercurial.revset.symbols['r3232'] = r3232
20 > EOF
20 > EOF
21 $ cat >> $HGRCPATH << EOF
21 $ cat >> $HGRCPATH << EOF
22 > [extensions]
22 > [extensions]
23 > testrevset=$TESTTMP/testrevset.py
23 > testrevset=$TESTTMP/testrevset.py
24 > EOF
24 > EOF
25
25
26 $ try() {
26 $ try() {
27 > hg debugrevspec --debug "$@"
27 > hg debugrevspec --debug "$@"
28 > }
28 > }
29
29
30 $ log() {
30 $ log() {
31 > hg log --template '{rev}\n' -r "$1"
31 > hg log --template '{rev}\n' -r "$1"
32 > }
32 > }
33
33
34 extension to build '_intlist()' and '_hexlist()', which is necessary because
34 extension to build '_intlist()' and '_hexlist()', which is necessary because
35 these predicates use '\0' as a separator:
35 these predicates use '\0' as a separator:
36
36
37 $ cat <<EOF > debugrevlistspec.py
37 $ cat <<EOF > debugrevlistspec.py
38 > from __future__ import absolute_import
38 > from __future__ import absolute_import
39 > from mercurial import (
39 > from mercurial import (
40 > node as nodemod,
40 > node as nodemod,
41 > registrar,
41 > registrar,
42 > revset,
42 > revset,
43 > revsetlang,
43 > revsetlang,
44 > smartset,
44 > smartset,
45 > )
45 > )
46 > cmdtable = {}
46 > cmdtable = {}
47 > command = registrar.command(cmdtable)
47 > command = registrar.command(cmdtable)
48 > @command('debugrevlistspec',
48 > @command('debugrevlistspec',
49 > [('', 'optimize', None, 'print parsed tree after optimizing'),
49 > [('', 'optimize', None, 'print parsed tree after optimizing'),
50 > ('', 'bin', None, 'unhexlify arguments')])
50 > ('', 'bin', None, 'unhexlify arguments')])
51 > def debugrevlistspec(ui, repo, fmt, *args, **opts):
51 > def debugrevlistspec(ui, repo, fmt, *args, **opts):
52 > if opts['bin']:
52 > if opts['bin']:
53 > args = map(nodemod.bin, args)
53 > args = map(nodemod.bin, args)
54 > expr = revsetlang.formatspec(fmt, list(args))
54 > expr = revsetlang.formatspec(fmt, list(args))
55 > if ui.verbose:
55 > if ui.verbose:
56 > tree = revsetlang.parse(expr, lookup=repo.__contains__)
56 > tree = revsetlang.parse(expr, lookup=repo.__contains__)
57 > ui.note(revsetlang.prettyformat(tree), "\n")
57 > ui.note(revsetlang.prettyformat(tree), "\n")
58 > if opts["optimize"]:
58 > if opts["optimize"]:
59 > opttree = revsetlang.optimize(revsetlang.analyze(tree))
59 > opttree = revsetlang.optimize(revsetlang.analyze(tree))
60 > ui.note("* optimized:\n", revsetlang.prettyformat(opttree),
60 > ui.note("* optimized:\n", revsetlang.prettyformat(opttree),
61 > "\n")
61 > "\n")
62 > func = revset.match(ui, expr, repo)
62 > func = revset.match(ui, expr, repo)
63 > revs = func(repo)
63 > revs = func(repo)
64 > if ui.verbose:
64 > if ui.verbose:
65 > ui.note("* set:\n", smartset.prettyformat(revs), "\n")
65 > ui.note("* set:\n", smartset.prettyformat(revs), "\n")
66 > for c in revs:
66 > for c in revs:
67 > ui.write("%s\n" % c)
67 > ui.write("%s\n" % c)
68 > EOF
68 > EOF
69 $ cat <<EOF >> $HGRCPATH
69 $ cat <<EOF >> $HGRCPATH
70 > [extensions]
70 > [extensions]
71 > debugrevlistspec = $TESTTMP/debugrevlistspec.py
71 > debugrevlistspec = $TESTTMP/debugrevlistspec.py
72 > EOF
72 > EOF
73 $ trylist() {
73 $ trylist() {
74 > hg debugrevlistspec --debug "$@"
74 > hg debugrevlistspec --debug "$@"
75 > }
75 > }
76
76
77 $ hg init repo
77 $ hg init repo
78 $ cd repo
78 $ cd repo
79
79
80 $ echo a > a
80 $ echo a > a
81 $ hg branch a
81 $ hg branch a
82 marked working directory as branch a
82 marked working directory as branch a
83 (branches are permanent and global, did you want a bookmark?)
83 (branches are permanent and global, did you want a bookmark?)
84 $ hg ci -Aqm0
84 $ hg ci -Aqm0
85
85
86 $ echo b > b
86 $ echo b > b
87 $ hg branch b
87 $ hg branch b
88 marked working directory as branch b
88 marked working directory as branch b
89 $ hg ci -Aqm1
89 $ hg ci -Aqm1
90
90
91 $ rm a
91 $ rm a
92 $ hg branch a-b-c-
92 $ hg branch a-b-c-
93 marked working directory as branch a-b-c-
93 marked working directory as branch a-b-c-
94 $ hg ci -Aqm2 -u Bob
94 $ hg ci -Aqm2 -u Bob
95
95
96 $ hg log -r "extra('branch', 'a-b-c-')" --template '{rev}\n'
96 $ hg log -r "extra('branch', 'a-b-c-')" --template '{rev}\n'
97 2
97 2
98 $ hg log -r "extra('branch')" --template '{rev}\n'
98 $ hg log -r "extra('branch')" --template '{rev}\n'
99 0
99 0
100 1
100 1
101 2
101 2
102 $ hg log -r "extra('branch', 're:a')" --template '{rev} {branch}\n'
102 $ hg log -r "extra('branch', 're:a')" --template '{rev} {branch}\n'
103 0 a
103 0 a
104 2 a-b-c-
104 2 a-b-c-
105
105
106 $ hg co 1
106 $ hg co 1
107 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
107 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
108 $ hg branch +a+b+c+
108 $ hg branch +a+b+c+
109 marked working directory as branch +a+b+c+
109 marked working directory as branch +a+b+c+
110 $ hg ci -Aqm3
110 $ hg ci -Aqm3
111
111
112 $ hg co 2 # interleave
112 $ hg co 2 # interleave
113 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
113 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
114 $ echo bb > b
114 $ echo bb > b
115 $ hg branch -- -a-b-c-
115 $ hg branch -- -a-b-c-
116 marked working directory as branch -a-b-c-
116 marked working directory as branch -a-b-c-
117 $ hg ci -Aqm4 -d "May 12 2005"
117 $ hg ci -Aqm4 -d "May 12 2005"
118
118
119 $ hg co 3
119 $ hg co 3
120 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
120 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
121 $ hg branch !a/b/c/
121 $ hg branch !a/b/c/
122 marked working directory as branch !a/b/c/
122 marked working directory as branch !a/b/c/
123 $ hg ci -Aqm"5 bug"
123 $ hg ci -Aqm"5 bug"
124
124
125 $ hg merge 4
125 $ hg merge 4
126 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
126 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
127 (branch merge, don't forget to commit)
127 (branch merge, don't forget to commit)
128 $ hg branch _a_b_c_
128 $ hg branch _a_b_c_
129 marked working directory as branch _a_b_c_
129 marked working directory as branch _a_b_c_
130 $ hg ci -Aqm"6 issue619"
130 $ hg ci -Aqm"6 issue619"
131
131
132 $ hg branch .a.b.c.
132 $ hg branch .a.b.c.
133 marked working directory as branch .a.b.c.
133 marked working directory as branch .a.b.c.
134 $ hg ci -Aqm7
134 $ hg ci -Aqm7
135
135
136 $ hg branch all
136 $ hg branch all
137 marked working directory as branch all
137 marked working directory as branch all
138
138
139 $ hg co 4
139 $ hg co 4
140 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
140 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
141 $ hg branch Γ©
141 $ hg branch Γ©
142 marked working directory as branch \xc3\xa9 (esc)
142 marked working directory as branch \xc3\xa9 (esc)
143 $ hg ci -Aqm9
143 $ hg ci -Aqm9
144
144
145 $ hg tag -r6 1.0
145 $ hg tag -r6 1.0
146 $ hg bookmark -r6 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
146 $ hg bookmark -r6 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
147
147
148 $ hg clone --quiet -U -r 7 . ../remote1
148 $ hg clone --quiet -U -r 7 . ../remote1
149 $ hg clone --quiet -U -r 8 . ../remote2
149 $ hg clone --quiet -U -r 8 . ../remote2
150 $ echo "[paths]" >> .hg/hgrc
150 $ echo "[paths]" >> .hg/hgrc
151 $ echo "default = ../remote1" >> .hg/hgrc
151 $ echo "default = ../remote1" >> .hg/hgrc
152
152
153 trivial
153 trivial
154
154
155 $ try 0:1
155 $ try 0:1
156 (range
156 (range
157 ('symbol', '0')
157 ('symbol', '0')
158 ('symbol', '1'))
158 ('symbol', '1'))
159 * set:
159 * set:
160 <spanset+ 0:1>
160 <spanset+ 0:1>
161 0
161 0
162 1
162 1
163 $ try --optimize :
163 $ try --optimize :
164 (rangeall
164 (rangeall
165 None)
165 None)
166 * optimized:
166 * optimized:
167 (rangeall
167 (rangeall
168 None
168 None
169 define)
169 define)
170 * set:
170 * set:
171 <spanset+ 0:9>
171 <spanset+ 0:9>
172 0
172 0
173 1
173 1
174 2
174 2
175 3
175 3
176 4
176 4
177 5
177 5
178 6
178 6
179 7
179 7
180 8
180 8
181 9
181 9
182 $ try 3::6
182 $ try 3::6
183 (dagrange
183 (dagrange
184 ('symbol', '3')
184 ('symbol', '3')
185 ('symbol', '6'))
185 ('symbol', '6'))
186 * set:
186 * set:
187 <baseset+ [3, 5, 6]>
187 <baseset+ [3, 5, 6]>
188 3
188 3
189 5
189 5
190 6
190 6
191 $ try '0|1|2'
191 $ try '0|1|2'
192 (or
192 (or
193 (list
193 (list
194 ('symbol', '0')
194 ('symbol', '0')
195 ('symbol', '1')
195 ('symbol', '1')
196 ('symbol', '2')))
196 ('symbol', '2')))
197 * set:
197 * set:
198 <baseset [0, 1, 2]>
198 <baseset [0, 1, 2]>
199 0
199 0
200 1
200 1
201 2
201 2
202
202
203 names that should work without quoting
203 names that should work without quoting
204
204
205 $ try a
205 $ try a
206 ('symbol', 'a')
206 ('symbol', 'a')
207 * set:
207 * set:
208 <baseset [0]>
208 <baseset [0]>
209 0
209 0
210 $ try b-a
210 $ try b-a
211 (minus
211 (minus
212 ('symbol', 'b')
212 ('symbol', 'b')
213 ('symbol', 'a'))
213 ('symbol', 'a'))
214 * set:
214 * set:
215 <filteredset
215 <filteredset
216 <baseset [1]>,
216 <baseset [1]>,
217 <not
217 <not
218 <baseset [0]>>>
218 <baseset [0]>>>
219 1
219 1
220 $ try _a_b_c_
220 $ try _a_b_c_
221 ('symbol', '_a_b_c_')
221 ('symbol', '_a_b_c_')
222 * set:
222 * set:
223 <baseset [6]>
223 <baseset [6]>
224 6
224 6
225 $ try _a_b_c_-a
225 $ try _a_b_c_-a
226 (minus
226 (minus
227 ('symbol', '_a_b_c_')
227 ('symbol', '_a_b_c_')
228 ('symbol', 'a'))
228 ('symbol', 'a'))
229 * set:
229 * set:
230 <filteredset
230 <filteredset
231 <baseset [6]>,
231 <baseset [6]>,
232 <not
232 <not
233 <baseset [0]>>>
233 <baseset [0]>>>
234 6
234 6
235 $ try .a.b.c.
235 $ try .a.b.c.
236 ('symbol', '.a.b.c.')
236 ('symbol', '.a.b.c.')
237 * set:
237 * set:
238 <baseset [7]>
238 <baseset [7]>
239 7
239 7
240 $ try .a.b.c.-a
240 $ try .a.b.c.-a
241 (minus
241 (minus
242 ('symbol', '.a.b.c.')
242 ('symbol', '.a.b.c.')
243 ('symbol', 'a'))
243 ('symbol', 'a'))
244 * set:
244 * set:
245 <filteredset
245 <filteredset
246 <baseset [7]>,
246 <baseset [7]>,
247 <not
247 <not
248 <baseset [0]>>>
248 <baseset [0]>>>
249 7
249 7
250
250
251 names that should be caught by fallback mechanism
251 names that should be caught by fallback mechanism
252
252
253 $ try -- '-a-b-c-'
253 $ try -- '-a-b-c-'
254 ('symbol', '-a-b-c-')
254 ('symbol', '-a-b-c-')
255 * set:
255 * set:
256 <baseset [4]>
256 <baseset [4]>
257 4
257 4
258 $ log -a-b-c-
258 $ log -a-b-c-
259 4
259 4
260 $ try '+a+b+c+'
260 $ try '+a+b+c+'
261 ('symbol', '+a+b+c+')
261 ('symbol', '+a+b+c+')
262 * set:
262 * set:
263 <baseset [3]>
263 <baseset [3]>
264 3
264 3
265 $ try '+a+b+c+:'
265 $ try '+a+b+c+:'
266 (rangepost
266 (rangepost
267 ('symbol', '+a+b+c+'))
267 ('symbol', '+a+b+c+'))
268 * set:
268 * set:
269 <spanset+ 3:9>
269 <spanset+ 3:9>
270 3
270 3
271 4
271 4
272 5
272 5
273 6
273 6
274 7
274 7
275 8
275 8
276 9
276 9
277 $ try ':+a+b+c+'
277 $ try ':+a+b+c+'
278 (rangepre
278 (rangepre
279 ('symbol', '+a+b+c+'))
279 ('symbol', '+a+b+c+'))
280 * set:
280 * set:
281 <spanset+ 0:3>
281 <spanset+ 0:3>
282 0
282 0
283 1
283 1
284 2
284 2
285 3
285 3
286 $ try -- '-a-b-c-:+a+b+c+'
286 $ try -- '-a-b-c-:+a+b+c+'
287 (range
287 (range
288 ('symbol', '-a-b-c-')
288 ('symbol', '-a-b-c-')
289 ('symbol', '+a+b+c+'))
289 ('symbol', '+a+b+c+'))
290 * set:
290 * set:
291 <spanset- 3:4>
291 <spanset- 3:4>
292 4
292 4
293 3
293 3
294 $ log '-a-b-c-:+a+b+c+'
294 $ log '-a-b-c-:+a+b+c+'
295 4
295 4
296 3
296 3
297
297
298 $ try -- -a-b-c--a # complains
298 $ try -- -a-b-c--a # complains
299 (minus
299 (minus
300 (minus
300 (minus
301 (minus
301 (minus
302 (negate
302 (negate
303 ('symbol', 'a'))
303 ('symbol', 'a'))
304 ('symbol', 'b'))
304 ('symbol', 'b'))
305 ('symbol', 'c'))
305 ('symbol', 'c'))
306 (negate
306 (negate
307 ('symbol', 'a')))
307 ('symbol', 'a')))
308 abort: unknown revision '-a'!
308 abort: unknown revision '-a'!
309 [255]
309 [255]
310 $ try Γ©
310 $ try Γ©
311 ('symbol', '\xc3\xa9')
311 ('symbol', '\xc3\xa9')
312 * set:
312 * set:
313 <baseset [9]>
313 <baseset [9]>
314 9
314 9
315
315
316 no quoting needed
316 no quoting needed
317
317
318 $ log ::a-b-c-
318 $ log ::a-b-c-
319 0
319 0
320 1
320 1
321 2
321 2
322
322
323 quoting needed
323 quoting needed
324
324
325 $ try '"-a-b-c-"-a'
325 $ try '"-a-b-c-"-a'
326 (minus
326 (minus
327 ('string', '-a-b-c-')
327 ('string', '-a-b-c-')
328 ('symbol', 'a'))
328 ('symbol', 'a'))
329 * set:
329 * set:
330 <filteredset
330 <filteredset
331 <baseset [4]>,
331 <baseset [4]>,
332 <not
332 <not
333 <baseset [0]>>>
333 <baseset [0]>>>
334 4
334 4
335
335
336 $ log '1 or 2'
336 $ log '1 or 2'
337 1
337 1
338 2
338 2
339 $ log '1|2'
339 $ log '1|2'
340 1
340 1
341 2
341 2
342 $ log '1 and 2'
342 $ log '1 and 2'
343 $ log '1&2'
343 $ log '1&2'
344 $ try '1&2|3' # precedence - and is higher
344 $ try '1&2|3' # precedence - and is higher
345 (or
345 (or
346 (list
346 (list
347 (and
347 (and
348 ('symbol', '1')
348 ('symbol', '1')
349 ('symbol', '2'))
349 ('symbol', '2'))
350 ('symbol', '3')))
350 ('symbol', '3')))
351 * set:
351 * set:
352 <addset
352 <addset
353 <baseset []>,
353 <baseset []>,
354 <baseset [3]>>
354 <baseset [3]>>
355 3
355 3
356 $ try '1|2&3'
356 $ try '1|2&3'
357 (or
357 (or
358 (list
358 (list
359 ('symbol', '1')
359 ('symbol', '1')
360 (and
360 (and
361 ('symbol', '2')
361 ('symbol', '2')
362 ('symbol', '3'))))
362 ('symbol', '3'))))
363 * set:
363 * set:
364 <addset
364 <addset
365 <baseset [1]>,
365 <baseset [1]>,
366 <baseset []>>
366 <baseset []>>
367 1
367 1
368 $ try '1&2&3' # associativity
368 $ try '1&2&3' # associativity
369 (and
369 (and
370 (and
370 (and
371 ('symbol', '1')
371 ('symbol', '1')
372 ('symbol', '2'))
372 ('symbol', '2'))
373 ('symbol', '3'))
373 ('symbol', '3'))
374 * set:
374 * set:
375 <baseset []>
375 <baseset []>
376 $ try '1|(2|3)'
376 $ try '1|(2|3)'
377 (or
377 (or
378 (list
378 (list
379 ('symbol', '1')
379 ('symbol', '1')
380 (group
380 (group
381 (or
381 (or
382 (list
382 (list
383 ('symbol', '2')
383 ('symbol', '2')
384 ('symbol', '3'))))))
384 ('symbol', '3'))))))
385 * set:
385 * set:
386 <addset
386 <addset
387 <baseset [1]>,
387 <baseset [1]>,
388 <baseset [2, 3]>>
388 <baseset [2, 3]>>
389 1
389 1
390 2
390 2
391 3
391 3
392 $ log '1.0' # tag
392 $ log '1.0' # tag
393 6
393 6
394 $ log 'a' # branch
394 $ log 'a' # branch
395 0
395 0
396 $ log '2785f51ee'
396 $ log '2785f51ee'
397 0
397 0
398 $ log 'date(2005)'
398 $ log 'date(2005)'
399 4
399 4
400 $ log 'date(this is a test)'
400 $ log 'date(this is a test)'
401 hg: parse error at 10: unexpected token: symbol
401 hg: parse error at 10: unexpected token: symbol
402 [255]
402 [255]
403 $ log 'date()'
403 $ log 'date()'
404 hg: parse error: date requires a string
404 hg: parse error: date requires a string
405 [255]
405 [255]
406 $ log 'date'
406 $ log 'date'
407 abort: unknown revision 'date'!
407 abort: unknown revision 'date'!
408 [255]
408 [255]
409 $ log 'date('
409 $ log 'date('
410 hg: parse error at 5: not a prefix: end
410 hg: parse error at 5: not a prefix: end
411 [255]
411 [255]
412 $ log 'date("\xy")'
412 $ log 'date("\xy")'
413 hg: parse error: invalid \x escape
413 hg: parse error: invalid \x escape
414 [255]
414 [255]
415 $ log 'date(tip)'
415 $ log 'date(tip)'
416 hg: parse error: invalid date: 'tip'
416 hg: parse error: invalid date: 'tip'
417 [255]
417 [255]
418 $ log '0:date'
418 $ log '0:date'
419 abort: unknown revision 'date'!
419 abort: unknown revision 'date'!
420 [255]
420 [255]
421 $ log '::"date"'
421 $ log '::"date"'
422 abort: unknown revision 'date'!
422 abort: unknown revision 'date'!
423 [255]
423 [255]
424 $ hg book date -r 4
424 $ hg book date -r 4
425 $ log '0:date'
425 $ log '0:date'
426 0
426 0
427 1
427 1
428 2
428 2
429 3
429 3
430 4
430 4
431 $ log '::date'
431 $ log '::date'
432 0
432 0
433 1
433 1
434 2
434 2
435 4
435 4
436 $ log '::"date"'
436 $ log '::"date"'
437 0
437 0
438 1
438 1
439 2
439 2
440 4
440 4
441 $ log 'date(2005) and 1::'
441 $ log 'date(2005) and 1::'
442 4
442 4
443 $ hg book -d date
443 $ hg book -d date
444
444
445 function name should be a symbol
445 function name should be a symbol
446
446
447 $ log '"date"(2005)'
447 $ log '"date"(2005)'
448 hg: parse error: not a symbol
448 hg: parse error: not a symbol
449 [255]
449 [255]
450
450
451 keyword arguments
451 keyword arguments
452
452
453 $ log 'extra(branch, value=a)'
453 $ log 'extra(branch, value=a)'
454 0
454 0
455
455
456 $ log 'extra(branch, a, b)'
456 $ log 'extra(branch, a, b)'
457 hg: parse error: extra takes at most 2 positional arguments
457 hg: parse error: extra takes at most 2 positional arguments
458 [255]
458 [255]
459 $ log 'extra(a, label=b)'
459 $ log 'extra(a, label=b)'
460 hg: parse error: extra got multiple values for keyword argument 'label'
460 hg: parse error: extra got multiple values for keyword argument 'label'
461 [255]
461 [255]
462 $ log 'extra(label=branch, default)'
462 $ log 'extra(label=branch, default)'
463 hg: parse error: extra got an invalid argument
463 hg: parse error: extra got an invalid argument
464 [255]
464 [255]
465 $ log 'extra(branch, foo+bar=baz)'
465 $ log 'extra(branch, foo+bar=baz)'
466 hg: parse error: extra got an invalid argument
466 hg: parse error: extra got an invalid argument
467 [255]
467 [255]
468 $ log 'extra(unknown=branch)'
468 $ log 'extra(unknown=branch)'
469 hg: parse error: extra got an unexpected keyword argument 'unknown'
469 hg: parse error: extra got an unexpected keyword argument 'unknown'
470 [255]
470 [255]
471
471
472 $ try 'foo=bar|baz'
472 $ try 'foo=bar|baz'
473 (keyvalue
473 (keyvalue
474 ('symbol', 'foo')
474 ('symbol', 'foo')
475 (or
475 (or
476 (list
476 (list
477 ('symbol', 'bar')
477 ('symbol', 'bar')
478 ('symbol', 'baz'))))
478 ('symbol', 'baz'))))
479 hg: parse error: can't use a key-value pair in this context
479 hg: parse error: can't use a key-value pair in this context
480 [255]
480 [255]
481
481
482 right-hand side should be optimized recursively
482 right-hand side should be optimized recursively
483
483
484 $ try --optimize 'foo=(not public())'
484 $ try --optimize 'foo=(not public())'
485 (keyvalue
485 (keyvalue
486 ('symbol', 'foo')
486 ('symbol', 'foo')
487 (group
487 (group
488 (not
488 (not
489 (func
489 (func
490 ('symbol', 'public')
490 ('symbol', 'public')
491 None))))
491 None))))
492 * optimized:
492 * optimized:
493 (keyvalue
493 (keyvalue
494 ('symbol', 'foo')
494 ('symbol', 'foo')
495 (func
495 (func
496 ('symbol', '_notpublic')
496 ('symbol', '_notpublic')
497 None
497 None
498 any))
498 any))
499 hg: parse error: can't use a key-value pair in this context
499 hg: parse error: can't use a key-value pair in this context
500 [255]
500 [255]
501
501
502 parsed tree at stages:
502 parsed tree at stages:
503
503
504 $ hg debugrevspec -p all '()'
504 $ hg debugrevspec -p all '()'
505 * parsed:
505 * parsed:
506 (group
506 (group
507 None)
507 None)
508 * expanded:
508 * expanded:
509 (group
509 (group
510 None)
510 None)
511 * concatenated:
511 * concatenated:
512 (group
512 (group
513 None)
513 None)
514 * analyzed:
514 * analyzed:
515 None
515 None
516 * optimized:
516 * optimized:
517 None
517 None
518 hg: parse error: missing argument
518 hg: parse error: missing argument
519 [255]
519 [255]
520
520
521 $ hg debugrevspec --no-optimized -p all '()'
521 $ hg debugrevspec --no-optimized -p all '()'
522 * parsed:
522 * parsed:
523 (group
523 (group
524 None)
524 None)
525 * expanded:
525 * expanded:
526 (group
526 (group
527 None)
527 None)
528 * concatenated:
528 * concatenated:
529 (group
529 (group
530 None)
530 None)
531 * analyzed:
531 * analyzed:
532 None
532 None
533 hg: parse error: missing argument
533 hg: parse error: missing argument
534 [255]
534 [255]
535
535
536 $ hg debugrevspec -p parsed -p analyzed -p optimized '(0|1)-1'
536 $ hg debugrevspec -p parsed -p analyzed -p optimized '(0|1)-1'
537 * parsed:
537 * parsed:
538 (minus
538 (minus
539 (group
539 (group
540 (or
540 (or
541 (list
541 (list
542 ('symbol', '0')
542 ('symbol', '0')
543 ('symbol', '1'))))
543 ('symbol', '1'))))
544 ('symbol', '1'))
544 ('symbol', '1'))
545 * analyzed:
545 * analyzed:
546 (and
546 (and
547 (or
547 (or
548 (list
548 (list
549 ('symbol', '0')
549 ('symbol', '0')
550 ('symbol', '1'))
550 ('symbol', '1'))
551 define)
551 define)
552 (not
552 (not
553 ('symbol', '1')
553 ('symbol', '1')
554 follow)
554 follow)
555 define)
555 define)
556 * optimized:
556 * optimized:
557 (difference
557 (difference
558 (func
558 (func
559 ('symbol', '_list')
559 ('symbol', '_list')
560 ('string', '0\x001')
560 ('string', '0\x001')
561 define)
561 define)
562 ('symbol', '1')
562 ('symbol', '1')
563 define)
563 define)
564 0
564 0
565
565
566 $ hg debugrevspec -p unknown '0'
566 $ hg debugrevspec -p unknown '0'
567 abort: invalid stage name: unknown
567 abort: invalid stage name: unknown
568 [255]
568 [255]
569
569
570 $ hg debugrevspec -p all --optimize '0'
570 $ hg debugrevspec -p all --optimize '0'
571 abort: cannot use --optimize with --show-stage
571 abort: cannot use --optimize with --show-stage
572 [255]
572 [255]
573
573
574 verify optimized tree:
574 verify optimized tree:
575
575
576 $ hg debugrevspec --verify '0|1'
576 $ hg debugrevspec --verify '0|1'
577
577
578 $ hg debugrevspec --verify -v -p analyzed -p optimized 'r3232() & 2'
578 $ hg debugrevspec --verify -v -p analyzed -p optimized 'r3232() & 2'
579 * analyzed:
579 * analyzed:
580 (and
580 (and
581 (func
581 (func
582 ('symbol', 'r3232')
582 ('symbol', 'r3232')
583 None
583 None
584 define)
584 define)
585 ('symbol', '2')
585 ('symbol', '2')
586 define)
586 define)
587 * optimized:
587 * optimized:
588 (and
588 (and
589 ('symbol', '2')
589 ('symbol', '2')
590 (func
590 (func
591 ('symbol', 'r3232')
591 ('symbol', 'r3232')
592 None
592 None
593 define)
593 define)
594 define)
594 define)
595 * analyzed set:
595 * analyzed set:
596 <baseset [2]>
596 <baseset [2]>
597 * optimized set:
597 * optimized set:
598 <baseset [2, 2]>
598 <baseset [2, 2]>
599 --- analyzed
599 --- analyzed
600 +++ optimized
600 +++ optimized
601 2
601 2
602 +2
602 +2
603 [1]
603 [1]
604
604
605 $ hg debugrevspec --no-optimized --verify-optimized '0'
605 $ hg debugrevspec --no-optimized --verify-optimized '0'
606 abort: cannot use --verify-optimized with --no-optimized
606 abort: cannot use --verify-optimized with --no-optimized
607 [255]
607 [255]
608
608
609 Test that symbols only get parsed as functions if there's an opening
609 Test that symbols only get parsed as functions if there's an opening
610 parenthesis.
610 parenthesis.
611
611
612 $ hg book only -r 9
612 $ hg book only -r 9
613 $ log 'only(only)' # Outer "only" is a function, inner "only" is the bookmark
613 $ log 'only(only)' # Outer "only" is a function, inner "only" is the bookmark
614 8
614 8
615 9
615 9
616
616
617 ':y' behaves like '0:y', but can't be rewritten as such since the revision '0'
617 ':y' behaves like '0:y', but can't be rewritten as such since the revision '0'
618 may be hidden (issue5385)
618 may be hidden (issue5385)
619
619
620 $ try -p parsed -p analyzed ':'
620 $ try -p parsed -p analyzed ':'
621 * parsed:
621 * parsed:
622 (rangeall
622 (rangeall
623 None)
623 None)
624 * analyzed:
624 * analyzed:
625 (rangeall
625 (rangeall
626 None
626 None
627 define)
627 define)
628 * set:
628 * set:
629 <spanset+ 0:9>
629 <spanset+ 0:9>
630 0
630 0
631 1
631 1
632 2
632 2
633 3
633 3
634 4
634 4
635 5
635 5
636 6
636 6
637 7
637 7
638 8
638 8
639 9
639 9
640 $ try -p analyzed ':1'
640 $ try -p analyzed ':1'
641 * analyzed:
641 * analyzed:
642 (rangepre
642 (rangepre
643 ('symbol', '1')
643 ('symbol', '1')
644 define)
644 define)
645 * set:
645 * set:
646 <spanset+ 0:1>
646 <spanset+ 0:1>
647 0
647 0
648 1
648 1
649 $ try -p analyzed ':(1|2)'
649 $ try -p analyzed ':(1|2)'
650 * analyzed:
650 * analyzed:
651 (rangepre
651 (rangepre
652 (or
652 (or
653 (list
653 (list
654 ('symbol', '1')
654 ('symbol', '1')
655 ('symbol', '2'))
655 ('symbol', '2'))
656 define)
656 define)
657 define)
657 define)
658 * set:
658 * set:
659 <spanset+ 0:2>
659 <spanset+ 0:2>
660 0
660 0
661 1
661 1
662 2
662 2
663 $ try -p analyzed ':(1&2)'
663 $ try -p analyzed ':(1&2)'
664 * analyzed:
664 * analyzed:
665 (rangepre
665 (rangepre
666 (and
666 (and
667 ('symbol', '1')
667 ('symbol', '1')
668 ('symbol', '2')
668 ('symbol', '2')
669 define)
669 define)
670 define)
670 define)
671 * set:
671 * set:
672 <baseset []>
672 <baseset []>
673
673
674 infix/suffix resolution of ^ operator (issue2884):
674 infix/suffix resolution of ^ operator (issue2884):
675
675
676 x^:y means (x^):y
676 x^:y means (x^):y
677
677
678 $ try '1^:2'
678 $ try '1^:2'
679 (range
679 (range
680 (parentpost
680 (parentpost
681 ('symbol', '1'))
681 ('symbol', '1'))
682 ('symbol', '2'))
682 ('symbol', '2'))
683 * set:
683 * set:
684 <spanset+ 0:2>
684 <spanset+ 0:2>
685 0
685 0
686 1
686 1
687 2
687 2
688
688
689 $ try '1^::2'
689 $ try '1^::2'
690 (dagrange
690 (dagrange
691 (parentpost
691 (parentpost
692 ('symbol', '1'))
692 ('symbol', '1'))
693 ('symbol', '2'))
693 ('symbol', '2'))
694 * set:
694 * set:
695 <baseset+ [0, 1, 2]>
695 <baseset+ [0, 1, 2]>
696 0
696 0
697 1
697 1
698 2
698 2
699
699
700 $ try '9^:'
700 $ try '9^:'
701 (rangepost
701 (rangepost
702 (parentpost
702 (parentpost
703 ('symbol', '9')))
703 ('symbol', '9')))
704 * set:
704 * set:
705 <spanset+ 8:9>
705 <spanset+ 8:9>
706 8
706 8
707 9
707 9
708
708
709 x^:y should be resolved before omitting group operators
709 x^:y should be resolved before omitting group operators
710
710
711 $ try '1^(:2)'
711 $ try '1^(:2)'
712 (parent
712 (parent
713 ('symbol', '1')
713 ('symbol', '1')
714 (group
714 (group
715 (rangepre
715 (rangepre
716 ('symbol', '2'))))
716 ('symbol', '2'))))
717 hg: parse error: ^ expects a number 0, 1, or 2
717 hg: parse error: ^ expects a number 0, 1, or 2
718 [255]
718 [255]
719
719
720 x^:y should be resolved recursively
720 x^:y should be resolved recursively
721
721
722 $ try 'sort(1^:2)'
722 $ try 'sort(1^:2)'
723 (func
723 (func
724 ('symbol', 'sort')
724 ('symbol', 'sort')
725 (range
725 (range
726 (parentpost
726 (parentpost
727 ('symbol', '1'))
727 ('symbol', '1'))
728 ('symbol', '2')))
728 ('symbol', '2')))
729 * set:
729 * set:
730 <spanset+ 0:2>
730 <spanset+ 0:2>
731 0
731 0
732 1
732 1
733 2
733 2
734
734
735 $ try '(3^:4)^:2'
735 $ try '(3^:4)^:2'
736 (range
736 (range
737 (parentpost
737 (parentpost
738 (group
738 (group
739 (range
739 (range
740 (parentpost
740 (parentpost
741 ('symbol', '3'))
741 ('symbol', '3'))
742 ('symbol', '4'))))
742 ('symbol', '4'))))
743 ('symbol', '2'))
743 ('symbol', '2'))
744 * set:
744 * set:
745 <spanset+ 0:2>
745 <spanset+ 0:2>
746 0
746 0
747 1
747 1
748 2
748 2
749
749
750 $ try '(3^::4)^::2'
750 $ try '(3^::4)^::2'
751 (dagrange
751 (dagrange
752 (parentpost
752 (parentpost
753 (group
753 (group
754 (dagrange
754 (dagrange
755 (parentpost
755 (parentpost
756 ('symbol', '3'))
756 ('symbol', '3'))
757 ('symbol', '4'))))
757 ('symbol', '4'))))
758 ('symbol', '2'))
758 ('symbol', '2'))
759 * set:
759 * set:
760 <baseset+ [0, 1, 2]>
760 <baseset+ [0, 1, 2]>
761 0
761 0
762 1
762 1
763 2
763 2
764
764
765 $ try '(9^:)^:'
765 $ try '(9^:)^:'
766 (rangepost
766 (rangepost
767 (parentpost
767 (parentpost
768 (group
768 (group
769 (rangepost
769 (rangepost
770 (parentpost
770 (parentpost
771 ('symbol', '9'))))))
771 ('symbol', '9'))))))
772 * set:
772 * set:
773 <spanset+ 4:9>
773 <spanset+ 4:9>
774 4
774 4
775 5
775 5
776 6
776 6
777 7
777 7
778 8
778 8
779 9
779 9
780
780
781 x^ in alias should also be resolved
781 x^ in alias should also be resolved
782
782
783 $ try 'A' --config 'revsetalias.A=1^:2'
783 $ try 'A' --config 'revsetalias.A=1^:2'
784 ('symbol', 'A')
784 ('symbol', 'A')
785 * expanded:
785 * expanded:
786 (range
786 (range
787 (parentpost
787 (parentpost
788 ('symbol', '1'))
788 ('symbol', '1'))
789 ('symbol', '2'))
789 ('symbol', '2'))
790 * set:
790 * set:
791 <spanset+ 0:2>
791 <spanset+ 0:2>
792 0
792 0
793 1
793 1
794 2
794 2
795
795
796 $ try 'A:2' --config 'revsetalias.A=1^'
796 $ try 'A:2' --config 'revsetalias.A=1^'
797 (range
797 (range
798 ('symbol', 'A')
798 ('symbol', 'A')
799 ('symbol', '2'))
799 ('symbol', '2'))
800 * expanded:
800 * expanded:
801 (range
801 (range
802 (parentpost
802 (parentpost
803 ('symbol', '1'))
803 ('symbol', '1'))
804 ('symbol', '2'))
804 ('symbol', '2'))
805 * set:
805 * set:
806 <spanset+ 0:2>
806 <spanset+ 0:2>
807 0
807 0
808 1
808 1
809 2
809 2
810
810
811 but not beyond the boundary of alias expansion, because the resolution should
811 but not beyond the boundary of alias expansion, because the resolution should
812 be made at the parsing stage
812 be made at the parsing stage
813
813
814 $ try '1^A' --config 'revsetalias.A=:2'
814 $ try '1^A' --config 'revsetalias.A=:2'
815 (parent
815 (parent
816 ('symbol', '1')
816 ('symbol', '1')
817 ('symbol', 'A'))
817 ('symbol', 'A'))
818 * expanded:
818 * expanded:
819 (parent
819 (parent
820 ('symbol', '1')
820 ('symbol', '1')
821 (rangepre
821 (rangepre
822 ('symbol', '2')))
822 ('symbol', '2')))
823 hg: parse error: ^ expects a number 0, 1, or 2
823 hg: parse error: ^ expects a number 0, 1, or 2
824 [255]
824 [255]
825
825
826 ancestor can accept 0 or more arguments
826 ancestor can accept 0 or more arguments
827
827
828 $ log 'ancestor()'
828 $ log 'ancestor()'
829 $ log 'ancestor(1)'
829 $ log 'ancestor(1)'
830 1
830 1
831 $ log 'ancestor(4,5)'
831 $ log 'ancestor(4,5)'
832 1
832 1
833 $ log 'ancestor(4,5) and 4'
833 $ log 'ancestor(4,5) and 4'
834 $ log 'ancestor(0,0,1,3)'
834 $ log 'ancestor(0,0,1,3)'
835 0
835 0
836 $ log 'ancestor(3,1,5,3,5,1)'
836 $ log 'ancestor(3,1,5,3,5,1)'
837 1
837 1
838 $ log 'ancestor(0,1,3,5)'
838 $ log 'ancestor(0,1,3,5)'
839 0
839 0
840 $ log 'ancestor(1,2,3,4,5)'
840 $ log 'ancestor(1,2,3,4,5)'
841 1
841 1
842
842
843 test ancestors
843 test ancestors
844
844
845 $ log 'ancestors(5)'
845 $ log 'ancestors(5)'
846 0
846 0
847 1
847 1
848 3
848 3
849 5
849 5
850 $ log 'ancestor(ancestors(5))'
850 $ log 'ancestor(ancestors(5))'
851 0
851 0
852 $ log '::r3232()'
852 $ log '::r3232()'
853 0
853 0
854 1
854 1
855 2
855 2
856 3
856 3
857
857
858 $ log 'author(bob)'
858 $ log 'author(bob)'
859 2
859 2
860 $ log 'author("re:bob|test")'
860 $ log 'author("re:bob|test")'
861 0
861 0
862 1
862 1
863 2
863 2
864 3
864 3
865 4
865 4
866 5
866 5
867 6
867 6
868 7
868 7
869 8
869 8
870 9
870 9
871 $ log 'author(r"re:\S")'
871 $ log 'author(r"re:\S")'
872 0
872 0
873 1
873 1
874 2
874 2
875 3
875 3
876 4
876 4
877 5
877 5
878 6
878 6
879 7
879 7
880 8
880 8
881 9
881 9
882 $ log 'branch(Γ©)'
882 $ log 'branch(Γ©)'
883 8
883 8
884 9
884 9
885 $ log 'branch(a)'
885 $ log 'branch(a)'
886 0
886 0
887 $ hg log -r 'branch("re:a")' --template '{rev} {branch}\n'
887 $ hg log -r 'branch("re:a")' --template '{rev} {branch}\n'
888 0 a
888 0 a
889 2 a-b-c-
889 2 a-b-c-
890 3 +a+b+c+
890 3 +a+b+c+
891 4 -a-b-c-
891 4 -a-b-c-
892 5 !a/b/c/
892 5 !a/b/c/
893 6 _a_b_c_
893 6 _a_b_c_
894 7 .a.b.c.
894 7 .a.b.c.
895 $ log 'children(ancestor(4,5))'
895 $ log 'children(ancestor(4,5))'
896 2
896 2
897 3
897 3
898
898
899 $ log 'children(4)'
899 $ log 'children(4)'
900 6
900 6
901 8
901 8
902 $ log 'children(null)'
902 $ log 'children(null)'
903 0
903 0
904
904
905 $ log 'closed()'
905 $ log 'closed()'
906 $ log 'contains(a)'
906 $ log 'contains(a)'
907 0
907 0
908 1
908 1
909 3
909 3
910 5
910 5
911 $ log 'contains("../repo/a")'
911 $ log 'contains("../repo/a")'
912 0
912 0
913 1
913 1
914 3
914 3
915 5
915 5
916 $ log 'desc(B)'
916 $ log 'desc(B)'
917 5
917 5
918 $ hg log -r 'desc(r"re:S?u")' --template "{rev} {desc|firstline}\n"
918 $ hg log -r 'desc(r"re:S?u")' --template "{rev} {desc|firstline}\n"
919 5 5 bug
919 5 5 bug
920 6 6 issue619
920 6 6 issue619
921 $ log 'descendants(2 or 3)'
921 $ log 'descendants(2 or 3)'
922 2
922 2
923 3
923 3
924 4
924 4
925 5
925 5
926 6
926 6
927 7
927 7
928 8
928 8
929 9
929 9
930 $ log 'file("b*")'
930 $ log 'file("b*")'
931 1
931 1
932 4
932 4
933 $ log 'filelog("b")'
933 $ log 'filelog("b")'
934 1
934 1
935 4
935 4
936 $ log 'filelog("../repo/b")'
936 $ log 'filelog("../repo/b")'
937 1
937 1
938 4
938 4
939 $ log 'follow()'
939 $ log 'follow()'
940 0
940 0
941 1
941 1
942 2
942 2
943 4
943 4
944 8
944 8
945 9
945 9
946 $ log 'grep("issue\d+")'
946 $ log 'grep("issue\d+")'
947 6
947 6
948 $ try 'grep("(")' # invalid regular expression
948 $ try 'grep("(")' # invalid regular expression
949 (func
949 (func
950 ('symbol', 'grep')
950 ('symbol', 'grep')
951 ('string', '('))
951 ('string', '('))
952 hg: parse error: invalid match pattern: unbalanced parenthesis
952 hg: parse error: invalid match pattern: unbalanced parenthesis
953 [255]
953 [255]
954 $ try 'grep("\bissue\d+")'
954 $ try 'grep("\bissue\d+")'
955 (func
955 (func
956 ('symbol', 'grep')
956 ('symbol', 'grep')
957 ('string', '\x08issue\\d+'))
957 ('string', '\x08issue\\d+'))
958 * set:
958 * set:
959 <filteredset
959 <filteredset
960 <fullreposet+ 0:9>,
960 <fullreposet+ 0:9>,
961 <grep '\x08issue\\d+'>>
961 <grep '\x08issue\\d+'>>
962 $ try 'grep(r"\bissue\d+")'
962 $ try 'grep(r"\bissue\d+")'
963 (func
963 (func
964 ('symbol', 'grep')
964 ('symbol', 'grep')
965 ('string', '\\bissue\\d+'))
965 ('string', '\\bissue\\d+'))
966 * set:
966 * set:
967 <filteredset
967 <filteredset
968 <fullreposet+ 0:9>,
968 <fullreposet+ 0:9>,
969 <grep '\\bissue\\d+'>>
969 <grep '\\bissue\\d+'>>
970 6
970 6
971 $ try 'grep(r"\")'
971 $ try 'grep(r"\")'
972 hg: parse error at 7: unterminated string
972 hg: parse error at 7: unterminated string
973 [255]
973 [255]
974 $ log 'head()'
974 $ log 'head()'
975 0
975 0
976 1
976 1
977 2
977 2
978 3
978 3
979 4
979 4
980 5
980 5
981 6
981 6
982 7
982 7
983 9
983 9
984 $ log 'heads(6::)'
984 $ log 'heads(6::)'
985 7
985 7
986 $ log 'keyword(issue)'
986 $ log 'keyword(issue)'
987 6
987 6
988 $ log 'keyword("test a")'
988 $ log 'keyword("test a")'
989
990 Test first (=limit) and last
991
989 $ log 'limit(head(), 1)'
992 $ log 'limit(head(), 1)'
990 0
993 0
991 $ log 'limit(author("re:bob|test"), 3, 5)'
994 $ log 'limit(author("re:bob|test"), 3, 5)'
992 5
995 5
993 6
996 6
994 7
997 7
995 $ log 'limit(author("re:bob|test"), offset=6)'
998 $ log 'limit(author("re:bob|test"), offset=6)'
996 6
999 6
997 $ log 'limit(author("re:bob|test"), offset=10)'
1000 $ log 'limit(author("re:bob|test"), offset=10)'
998 $ log 'limit(all(), 1, -1)'
1001 $ log 'limit(all(), 1, -1)'
999 hg: parse error: negative offset
1002 hg: parse error: negative offset
1000 [255]
1003 [255]
1004
1005 $ log 'last(all(), 0)'
1006 $ log 'last(all(), 1)'
1007 9
1008 $ log 'last(all(), 2)'
1009 8
1010 9
1011
1012 Test matching
1013
1001 $ log 'matching(6)'
1014 $ log 'matching(6)'
1002 6
1015 6
1003 $ log 'matching(6:7, "phase parents user date branch summary files description substate")'
1016 $ log 'matching(6:7, "phase parents user date branch summary files description substate")'
1004 6
1017 6
1005 7
1018 7
1006
1019
1007 Testing min and max
1020 Testing min and max
1008
1021
1009 max: simple
1022 max: simple
1010
1023
1011 $ log 'max(contains(a))'
1024 $ log 'max(contains(a))'
1012 5
1025 5
1013
1026
1014 max: simple on unordered set)
1027 max: simple on unordered set)
1015
1028
1016 $ log 'max((4+0+2+5+7) and contains(a))'
1029 $ log 'max((4+0+2+5+7) and contains(a))'
1017 5
1030 5
1018
1031
1019 max: no result
1032 max: no result
1020
1033
1021 $ log 'max(contains(stringthatdoesnotappearanywhere))'
1034 $ log 'max(contains(stringthatdoesnotappearanywhere))'
1022
1035
1023 max: no result on unordered set
1036 max: no result on unordered set
1024
1037
1025 $ log 'max((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
1038 $ log 'max((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
1026
1039
1027 min: simple
1040 min: simple
1028
1041
1029 $ log 'min(contains(a))'
1042 $ log 'min(contains(a))'
1030 0
1043 0
1031
1044
1032 min: simple on unordered set
1045 min: simple on unordered set
1033
1046
1034 $ log 'min((4+0+2+5+7) and contains(a))'
1047 $ log 'min((4+0+2+5+7) and contains(a))'
1035 0
1048 0
1036
1049
1037 min: empty
1050 min: empty
1038
1051
1039 $ log 'min(contains(stringthatdoesnotappearanywhere))'
1052 $ log 'min(contains(stringthatdoesnotappearanywhere))'
1040
1053
1041 min: empty on unordered set
1054 min: empty on unordered set
1042
1055
1043 $ log 'min((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
1056 $ log 'min((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
1044
1057
1045
1058
1046 $ log 'merge()'
1059 $ log 'merge()'
1047 6
1060 6
1048 $ log 'branchpoint()'
1061 $ log 'branchpoint()'
1049 1
1062 1
1050 4
1063 4
1051 $ log 'modifies(b)'
1064 $ log 'modifies(b)'
1052 4
1065 4
1053 $ log 'modifies("path:b")'
1066 $ log 'modifies("path:b")'
1054 4
1067 4
1055 $ log 'modifies("*")'
1068 $ log 'modifies("*")'
1056 4
1069 4
1057 6
1070 6
1058 $ log 'modifies("set:modified()")'
1071 $ log 'modifies("set:modified()")'
1059 4
1072 4
1060 $ log 'id(5)'
1073 $ log 'id(5)'
1061 2
1074 2
1062 $ log 'only(9)'
1075 $ log 'only(9)'
1063 8
1076 8
1064 9
1077 9
1065 $ log 'only(8)'
1078 $ log 'only(8)'
1066 8
1079 8
1067 $ log 'only(9, 5)'
1080 $ log 'only(9, 5)'
1068 2
1081 2
1069 4
1082 4
1070 8
1083 8
1071 9
1084 9
1072 $ log 'only(7 + 9, 5 + 2)'
1085 $ log 'only(7 + 9, 5 + 2)'
1073 4
1086 4
1074 6
1087 6
1075 7
1088 7
1076 8
1089 8
1077 9
1090 9
1078
1091
1079 Test empty set input
1092 Test empty set input
1080 $ log 'only(p2())'
1093 $ log 'only(p2())'
1081 $ log 'only(p1(), p2())'
1094 $ log 'only(p1(), p2())'
1082 0
1095 0
1083 1
1096 1
1084 2
1097 2
1085 4
1098 4
1086 8
1099 8
1087 9
1100 9
1088
1101
1089 Test '%' operator
1102 Test '%' operator
1090
1103
1091 $ log '9%'
1104 $ log '9%'
1092 8
1105 8
1093 9
1106 9
1094 $ log '9%5'
1107 $ log '9%5'
1095 2
1108 2
1096 4
1109 4
1097 8
1110 8
1098 9
1111 9
1099 $ log '(7 + 9)%(5 + 2)'
1112 $ log '(7 + 9)%(5 + 2)'
1100 4
1113 4
1101 6
1114 6
1102 7
1115 7
1103 8
1116 8
1104 9
1117 9
1105
1118
1106 Test operand of '%' is optimized recursively (issue4670)
1119 Test operand of '%' is optimized recursively (issue4670)
1107
1120
1108 $ try --optimize '8:9-8%'
1121 $ try --optimize '8:9-8%'
1109 (onlypost
1122 (onlypost
1110 (minus
1123 (minus
1111 (range
1124 (range
1112 ('symbol', '8')
1125 ('symbol', '8')
1113 ('symbol', '9'))
1126 ('symbol', '9'))
1114 ('symbol', '8')))
1127 ('symbol', '8')))
1115 * optimized:
1128 * optimized:
1116 (func
1129 (func
1117 ('symbol', 'only')
1130 ('symbol', 'only')
1118 (difference
1131 (difference
1119 (range
1132 (range
1120 ('symbol', '8')
1133 ('symbol', '8')
1121 ('symbol', '9')
1134 ('symbol', '9')
1122 define)
1135 define)
1123 ('symbol', '8')
1136 ('symbol', '8')
1124 define)
1137 define)
1125 define)
1138 define)
1126 * set:
1139 * set:
1127 <baseset+ [8, 9]>
1140 <baseset+ [8, 9]>
1128 8
1141 8
1129 9
1142 9
1130 $ try --optimize '(9)%(5)'
1143 $ try --optimize '(9)%(5)'
1131 (only
1144 (only
1132 (group
1145 (group
1133 ('symbol', '9'))
1146 ('symbol', '9'))
1134 (group
1147 (group
1135 ('symbol', '5')))
1148 ('symbol', '5')))
1136 * optimized:
1149 * optimized:
1137 (func
1150 (func
1138 ('symbol', 'only')
1151 ('symbol', 'only')
1139 (list
1152 (list
1140 ('symbol', '9')
1153 ('symbol', '9')
1141 ('symbol', '5'))
1154 ('symbol', '5'))
1142 define)
1155 define)
1143 * set:
1156 * set:
1144 <baseset+ [2, 4, 8, 9]>
1157 <baseset+ [2, 4, 8, 9]>
1145 2
1158 2
1146 4
1159 4
1147 8
1160 8
1148 9
1161 9
1149
1162
1150 Test the order of operations
1163 Test the order of operations
1151
1164
1152 $ log '7 + 9%5 + 2'
1165 $ log '7 + 9%5 + 2'
1153 7
1166 7
1154 2
1167 2
1155 4
1168 4
1156 8
1169 8
1157 9
1170 9
1158
1171
1159 Test explicit numeric revision
1172 Test explicit numeric revision
1160 $ log 'rev(-2)'
1173 $ log 'rev(-2)'
1161 $ log 'rev(-1)'
1174 $ log 'rev(-1)'
1162 -1
1175 -1
1163 $ log 'rev(0)'
1176 $ log 'rev(0)'
1164 0
1177 0
1165 $ log 'rev(9)'
1178 $ log 'rev(9)'
1166 9
1179 9
1167 $ log 'rev(10)'
1180 $ log 'rev(10)'
1168 $ log 'rev(tip)'
1181 $ log 'rev(tip)'
1169 hg: parse error: rev expects a number
1182 hg: parse error: rev expects a number
1170 [255]
1183 [255]
1171
1184
1172 Test hexadecimal revision
1185 Test hexadecimal revision
1173 $ log 'id(2)'
1186 $ log 'id(2)'
1174 abort: 00changelog.i@2: ambiguous identifier!
1187 abort: 00changelog.i@2: ambiguous identifier!
1175 [255]
1188 [255]
1176 $ log 'id(23268)'
1189 $ log 'id(23268)'
1177 4
1190 4
1178 $ log 'id(2785f51eece)'
1191 $ log 'id(2785f51eece)'
1179 0
1192 0
1180 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532c)'
1193 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532c)'
1181 8
1194 8
1182 $ log 'id(d5d0dcbdc4a)'
1195 $ log 'id(d5d0dcbdc4a)'
1183 $ log 'id(d5d0dcbdc4w)'
1196 $ log 'id(d5d0dcbdc4w)'
1184 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532d)'
1197 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532d)'
1185 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532q)'
1198 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532q)'
1186 $ log 'id(1.0)'
1199 $ log 'id(1.0)'
1187 $ log 'id(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)'
1200 $ log 'id(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)'
1188
1201
1189 Test null revision
1202 Test null revision
1190 $ log '(null)'
1203 $ log '(null)'
1191 -1
1204 -1
1192 $ log '(null:0)'
1205 $ log '(null:0)'
1193 -1
1206 -1
1194 0
1207 0
1195 $ log '(0:null)'
1208 $ log '(0:null)'
1196 0
1209 0
1197 -1
1210 -1
1198 $ log 'null::0'
1211 $ log 'null::0'
1199 -1
1212 -1
1200 0
1213 0
1201 $ log 'null:tip - 0:'
1214 $ log 'null:tip - 0:'
1202 -1
1215 -1
1203 $ log 'null: and null::' | head -1
1216 $ log 'null: and null::' | head -1
1204 -1
1217 -1
1205 $ log 'null: or 0:' | head -2
1218 $ log 'null: or 0:' | head -2
1206 -1
1219 -1
1207 0
1220 0
1208 $ log 'ancestors(null)'
1221 $ log 'ancestors(null)'
1209 -1
1222 -1
1210 $ log 'reverse(null:)' | tail -2
1223 $ log 'reverse(null:)' | tail -2
1211 0
1224 0
1212 -1
1225 -1
1213 BROKEN: should be '-1'
1226 BROKEN: should be '-1'
1214 $ log 'first(null:)'
1227 $ log 'first(null:)'
1215 BROKEN: should be '-1'
1228 BROKEN: should be '-1'
1216 $ log 'min(null:)'
1229 $ log 'min(null:)'
1217 $ log 'tip:null and all()' | tail -2
1230 $ log 'tip:null and all()' | tail -2
1218 1
1231 1
1219 0
1232 0
1220
1233
1221 Test working-directory revision
1234 Test working-directory revision
1222 $ hg debugrevspec 'wdir()'
1235 $ hg debugrevspec 'wdir()'
1223 2147483647
1236 2147483647
1224 $ hg debugrevspec 'wdir()^'
1237 $ hg debugrevspec 'wdir()^'
1225 9
1238 9
1226 $ hg up 7
1239 $ hg up 7
1227 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1240 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1228 $ hg debugrevspec 'wdir()^'
1241 $ hg debugrevspec 'wdir()^'
1229 7
1242 7
1230 $ hg debugrevspec 'wdir()^0'
1243 $ hg debugrevspec 'wdir()^0'
1231 2147483647
1244 2147483647
1232 $ hg debugrevspec 'wdir()~3'
1245 $ hg debugrevspec 'wdir()~3'
1233 5
1246 5
1234 $ hg debugrevspec 'ancestors(wdir())'
1247 $ hg debugrevspec 'ancestors(wdir())'
1235 0
1248 0
1236 1
1249 1
1237 2
1250 2
1238 3
1251 3
1239 4
1252 4
1240 5
1253 5
1241 6
1254 6
1242 7
1255 7
1243 2147483647
1256 2147483647
1244 $ hg debugrevspec 'wdir()~0'
1257 $ hg debugrevspec 'wdir()~0'
1245 2147483647
1258 2147483647
1246 $ hg debugrevspec 'p1(wdir())'
1259 $ hg debugrevspec 'p1(wdir())'
1247 7
1260 7
1248 $ hg debugrevspec 'p2(wdir())'
1261 $ hg debugrevspec 'p2(wdir())'
1249 $ hg debugrevspec 'parents(wdir())'
1262 $ hg debugrevspec 'parents(wdir())'
1250 7
1263 7
1251 $ hg debugrevspec 'wdir()^1'
1264 $ hg debugrevspec 'wdir()^1'
1252 7
1265 7
1253 $ hg debugrevspec 'wdir()^2'
1266 $ hg debugrevspec 'wdir()^2'
1254 $ hg debugrevspec 'wdir()^3'
1267 $ hg debugrevspec 'wdir()^3'
1255 hg: parse error: ^ expects a number 0, 1, or 2
1268 hg: parse error: ^ expects a number 0, 1, or 2
1256 [255]
1269 [255]
1257 For tests consistency
1270 For tests consistency
1258 $ hg up 9
1271 $ hg up 9
1259 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1272 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1260 $ hg debugrevspec 'tip or wdir()'
1273 $ hg debugrevspec 'tip or wdir()'
1261 9
1274 9
1262 2147483647
1275 2147483647
1263 $ hg debugrevspec '0:tip and wdir()'
1276 $ hg debugrevspec '0:tip and wdir()'
1264 $ log '0:wdir()' | tail -3
1277 $ log '0:wdir()' | tail -3
1265 8
1278 8
1266 9
1279 9
1267 2147483647
1280 2147483647
1268 $ log 'wdir():0' | head -3
1281 $ log 'wdir():0' | head -3
1269 2147483647
1282 2147483647
1270 9
1283 9
1271 8
1284 8
1272 $ log 'wdir():wdir()'
1285 $ log 'wdir():wdir()'
1273 2147483647
1286 2147483647
1274 $ log '(all() + wdir()) & min(. + wdir())'
1287 $ log '(all() + wdir()) & min(. + wdir())'
1275 9
1288 9
1276 $ log '(all() + wdir()) & max(. + wdir())'
1289 $ log '(all() + wdir()) & max(. + wdir())'
1277 2147483647
1290 2147483647
1278 $ log '(all() + wdir()) & first(wdir() + .)'
1291 $ log '(all() + wdir()) & first(wdir() + .)'
1279 2147483647
1292 2147483647
1280 $ log '(all() + wdir()) & last(. + wdir())'
1293 $ log '(all() + wdir()) & last(. + wdir())'
1281 2147483647
1294 2147483647
1282
1295
1283 Test working-directory integer revision and node id
1296 Test working-directory integer revision and node id
1284 (BUG: '0:wdir()' is still needed to populate wdir revision)
1297 (BUG: '0:wdir()' is still needed to populate wdir revision)
1285
1298
1286 $ hg debugrevspec '0:wdir() & 2147483647'
1299 $ hg debugrevspec '0:wdir() & 2147483647'
1287 2147483647
1300 2147483647
1288 $ hg debugrevspec '0:wdir() & rev(2147483647)'
1301 $ hg debugrevspec '0:wdir() & rev(2147483647)'
1289 2147483647
1302 2147483647
1290 $ hg debugrevspec '0:wdir() & ffffffffffffffffffffffffffffffffffffffff'
1303 $ hg debugrevspec '0:wdir() & ffffffffffffffffffffffffffffffffffffffff'
1291 2147483647
1304 2147483647
1292 $ hg debugrevspec '0:wdir() & ffffffffffff'
1305 $ hg debugrevspec '0:wdir() & ffffffffffff'
1293 2147483647
1306 2147483647
1294 $ hg debugrevspec '0:wdir() & id(ffffffffffffffffffffffffffffffffffffffff)'
1307 $ hg debugrevspec '0:wdir() & id(ffffffffffffffffffffffffffffffffffffffff)'
1295 2147483647
1308 2147483647
1296 $ hg debugrevspec '0:wdir() & id(ffffffffffff)'
1309 $ hg debugrevspec '0:wdir() & id(ffffffffffff)'
1297 2147483647
1310 2147483647
1298
1311
1299 $ cd ..
1312 $ cd ..
1300
1313
1301 Test short 'ff...' hash collision
1314 Test short 'ff...' hash collision
1302 (BUG: '0:wdir()' is still needed to populate wdir revision)
1315 (BUG: '0:wdir()' is still needed to populate wdir revision)
1303
1316
1304 $ hg init wdir-hashcollision
1317 $ hg init wdir-hashcollision
1305 $ cd wdir-hashcollision
1318 $ cd wdir-hashcollision
1306 $ cat <<EOF >> .hg/hgrc
1319 $ cat <<EOF >> .hg/hgrc
1307 > [experimental]
1320 > [experimental]
1308 > evolution = createmarkers
1321 > evolution = createmarkers
1309 > EOF
1322 > EOF
1310 $ echo 0 > a
1323 $ echo 0 > a
1311 $ hg ci -qAm 0
1324 $ hg ci -qAm 0
1312 $ for i in 2463 2961 6726 78127; do
1325 $ for i in 2463 2961 6726 78127; do
1313 > hg up -q 0
1326 > hg up -q 0
1314 > echo $i > a
1327 > echo $i > a
1315 > hg ci -qm $i
1328 > hg ci -qm $i
1316 > done
1329 > done
1317 $ hg up -q null
1330 $ hg up -q null
1318 $ hg log -r '0:wdir()' -T '{rev}:{node} {shortest(node, 3)}\n'
1331 $ hg log -r '0:wdir()' -T '{rev}:{node} {shortest(node, 3)}\n'
1319 0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a b4e
1332 0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a b4e
1320 1:fffbae3886c8fbb2114296380d276fd37715d571 fffba
1333 1:fffbae3886c8fbb2114296380d276fd37715d571 fffba
1321 2:fffb6093b00943f91034b9bdad069402c834e572 fffb6
1334 2:fffb6093b00943f91034b9bdad069402c834e572 fffb6
1322 3:fff48a9b9de34a4d64120c29548214c67980ade3 fff4
1335 3:fff48a9b9de34a4d64120c29548214c67980ade3 fff4
1323 4:ffff85cff0ff78504fcdc3c0bc10de0c65379249 ffff8
1336 4:ffff85cff0ff78504fcdc3c0bc10de0c65379249 ffff8
1324 2147483647:ffffffffffffffffffffffffffffffffffffffff fffff
1337 2147483647:ffffffffffffffffffffffffffffffffffffffff fffff
1325 $ hg debugobsolete fffbae3886c8fbb2114296380d276fd37715d571
1338 $ hg debugobsolete fffbae3886c8fbb2114296380d276fd37715d571
1326
1339
1327 $ hg debugrevspec '0:wdir() & fff'
1340 $ hg debugrevspec '0:wdir() & fff'
1328 abort: 00changelog.i@fff: ambiguous identifier!
1341 abort: 00changelog.i@fff: ambiguous identifier!
1329 [255]
1342 [255]
1330 $ hg debugrevspec '0:wdir() & ffff'
1343 $ hg debugrevspec '0:wdir() & ffff'
1331 abort: 00changelog.i@ffff: ambiguous identifier!
1344 abort: 00changelog.i@ffff: ambiguous identifier!
1332 [255]
1345 [255]
1333 $ hg debugrevspec '0:wdir() & fffb'
1346 $ hg debugrevspec '0:wdir() & fffb'
1334 abort: 00changelog.i@fffb: ambiguous identifier!
1347 abort: 00changelog.i@fffb: ambiguous identifier!
1335 [255]
1348 [255]
1336 BROKEN should be '2' (node lookup uses unfiltered repo since dc25ed84bee8)
1349 BROKEN should be '2' (node lookup uses unfiltered repo since dc25ed84bee8)
1337 $ hg debugrevspec '0:wdir() & id(fffb)'
1350 $ hg debugrevspec '0:wdir() & id(fffb)'
1338 2
1351 2
1339 $ hg debugrevspec '0:wdir() & ffff8'
1352 $ hg debugrevspec '0:wdir() & ffff8'
1340 4
1353 4
1341 $ hg debugrevspec '0:wdir() & fffff'
1354 $ hg debugrevspec '0:wdir() & fffff'
1342 2147483647
1355 2147483647
1343
1356
1344 $ cd ..
1357 $ cd ..
1345
1358
1346 Test branch() with wdir()
1359 Test branch() with wdir()
1347
1360
1348 $ cd repo
1361 $ cd repo
1349
1362
1350 $ log '0:wdir() & branch("literal:Γ©")'
1363 $ log '0:wdir() & branch("literal:Γ©")'
1351 8
1364 8
1352 9
1365 9
1353 2147483647
1366 2147483647
1354 $ log '0:wdir() & branch("re:Γ©")'
1367 $ log '0:wdir() & branch("re:Γ©")'
1355 8
1368 8
1356 9
1369 9
1357 2147483647
1370 2147483647
1358 $ log '0:wdir() & branch("re:^a")'
1371 $ log '0:wdir() & branch("re:^a")'
1359 0
1372 0
1360 2
1373 2
1361 $ log '0:wdir() & branch(8)'
1374 $ log '0:wdir() & branch(8)'
1362 8
1375 8
1363 9
1376 9
1364 2147483647
1377 2147483647
1365
1378
1366 branch(wdir()) returns all revisions belonging to the working branch. The wdir
1379 branch(wdir()) returns all revisions belonging to the working branch. The wdir
1367 itself isn't returned unless it is explicitly populated.
1380 itself isn't returned unless it is explicitly populated.
1368
1381
1369 $ log 'branch(wdir())'
1382 $ log 'branch(wdir())'
1370 8
1383 8
1371 9
1384 9
1372 $ log '0:wdir() & branch(wdir())'
1385 $ log '0:wdir() & branch(wdir())'
1373 8
1386 8
1374 9
1387 9
1375 2147483647
1388 2147483647
1376
1389
1377 $ log 'outgoing()'
1390 $ log 'outgoing()'
1378 8
1391 8
1379 9
1392 9
1380 $ log 'outgoing("../remote1")'
1393 $ log 'outgoing("../remote1")'
1381 8
1394 8
1382 9
1395 9
1383 $ log 'outgoing("../remote2")'
1396 $ log 'outgoing("../remote2")'
1384 3
1397 3
1385 5
1398 5
1386 6
1399 6
1387 7
1400 7
1388 9
1401 9
1389 $ log 'p1(merge())'
1402 $ log 'p1(merge())'
1390 5
1403 5
1391 $ log 'p2(merge())'
1404 $ log 'p2(merge())'
1392 4
1405 4
1393 $ log 'parents(merge())'
1406 $ log 'parents(merge())'
1394 4
1407 4
1395 5
1408 5
1396 $ log 'p1(branchpoint())'
1409 $ log 'p1(branchpoint())'
1397 0
1410 0
1398 2
1411 2
1399 $ log 'p2(branchpoint())'
1412 $ log 'p2(branchpoint())'
1400 $ log 'parents(branchpoint())'
1413 $ log 'parents(branchpoint())'
1401 0
1414 0
1402 2
1415 2
1403 $ log 'removes(a)'
1416 $ log 'removes(a)'
1404 2
1417 2
1405 6
1418 6
1406 $ log 'roots(all())'
1419 $ log 'roots(all())'
1407 0
1420 0
1408 $ log 'reverse(2 or 3 or 4 or 5)'
1421 $ log 'reverse(2 or 3 or 4 or 5)'
1409 5
1422 5
1410 4
1423 4
1411 3
1424 3
1412 2
1425 2
1413 $ log 'reverse(all())'
1426 $ log 'reverse(all())'
1414 9
1427 9
1415 8
1428 8
1416 7
1429 7
1417 6
1430 6
1418 5
1431 5
1419 4
1432 4
1420 3
1433 3
1421 2
1434 2
1422 1
1435 1
1423 0
1436 0
1424 $ log 'reverse(all()) & filelog(b)'
1437 $ log 'reverse(all()) & filelog(b)'
1425 4
1438 4
1426 1
1439 1
1427 $ log 'rev(5)'
1440 $ log 'rev(5)'
1428 5
1441 5
1429 $ log 'sort(limit(reverse(all()), 3))'
1442 $ log 'sort(limit(reverse(all()), 3))'
1430 7
1443 7
1431 8
1444 8
1432 9
1445 9
1433 $ log 'sort(2 or 3 or 4 or 5, date)'
1446 $ log 'sort(2 or 3 or 4 or 5, date)'
1434 2
1447 2
1435 3
1448 3
1436 5
1449 5
1437 4
1450 4
1438 $ log 'tagged()'
1451 $ log 'tagged()'
1439 6
1452 6
1440 $ log 'tag()'
1453 $ log 'tag()'
1441 6
1454 6
1442 $ log 'tag(1.0)'
1455 $ log 'tag(1.0)'
1443 6
1456 6
1444 $ log 'tag(tip)'
1457 $ log 'tag(tip)'
1445 9
1458 9
1446
1459
1447 Test order of revisions in compound expression
1460 Test order of revisions in compound expression
1448 ----------------------------------------------
1461 ----------------------------------------------
1449
1462
1450 The general rule is that only the outermost (= leftmost) predicate can
1463 The general rule is that only the outermost (= leftmost) predicate can
1451 enforce its ordering requirement. The other predicates should take the
1464 enforce its ordering requirement. The other predicates should take the
1452 ordering defined by it.
1465 ordering defined by it.
1453
1466
1454 'A & B' should follow the order of 'A':
1467 'A & B' should follow the order of 'A':
1455
1468
1456 $ log '2:0 & 0::2'
1469 $ log '2:0 & 0::2'
1457 2
1470 2
1458 1
1471 1
1459 0
1472 0
1460
1473
1461 'head()' combines sets in right order:
1474 'head()' combines sets in right order:
1462
1475
1463 $ log '2:0 & head()'
1476 $ log '2:0 & head()'
1464 2
1477 2
1465 1
1478 1
1466 0
1479 0
1467
1480
1468 'x:y' takes ordering parameter into account:
1481 'x:y' takes ordering parameter into account:
1469
1482
1470 $ try -p optimized '3:0 & 0:3 & not 2:1'
1483 $ try -p optimized '3:0 & 0:3 & not 2:1'
1471 * optimized:
1484 * optimized:
1472 (difference
1485 (difference
1473 (and
1486 (and
1474 (range
1487 (range
1475 ('symbol', '3')
1488 ('symbol', '3')
1476 ('symbol', '0')
1489 ('symbol', '0')
1477 define)
1490 define)
1478 (range
1491 (range
1479 ('symbol', '0')
1492 ('symbol', '0')
1480 ('symbol', '3')
1493 ('symbol', '3')
1481 follow)
1494 follow)
1482 define)
1495 define)
1483 (range
1496 (range
1484 ('symbol', '2')
1497 ('symbol', '2')
1485 ('symbol', '1')
1498 ('symbol', '1')
1486 any)
1499 any)
1487 define)
1500 define)
1488 * set:
1501 * set:
1489 <filteredset
1502 <filteredset
1490 <filteredset
1503 <filteredset
1491 <spanset- 0:3>,
1504 <spanset- 0:3>,
1492 <spanset+ 0:3>>,
1505 <spanset+ 0:3>>,
1493 <not
1506 <not
1494 <spanset+ 1:2>>>
1507 <spanset+ 1:2>>>
1495 3
1508 3
1496 0
1509 0
1497
1510
1498 'a + b', which is optimized to '_list(a b)', should take the ordering of
1511 'a + b', which is optimized to '_list(a b)', should take the ordering of
1499 the left expression:
1512 the left expression:
1500
1513
1501 $ try --optimize '2:0 & (0 + 1 + 2)'
1514 $ try --optimize '2:0 & (0 + 1 + 2)'
1502 (and
1515 (and
1503 (range
1516 (range
1504 ('symbol', '2')
1517 ('symbol', '2')
1505 ('symbol', '0'))
1518 ('symbol', '0'))
1506 (group
1519 (group
1507 (or
1520 (or
1508 (list
1521 (list
1509 ('symbol', '0')
1522 ('symbol', '0')
1510 ('symbol', '1')
1523 ('symbol', '1')
1511 ('symbol', '2')))))
1524 ('symbol', '2')))))
1512 * optimized:
1525 * optimized:
1513 (and
1526 (and
1514 (range
1527 (range
1515 ('symbol', '2')
1528 ('symbol', '2')
1516 ('symbol', '0')
1529 ('symbol', '0')
1517 define)
1530 define)
1518 (func
1531 (func
1519 ('symbol', '_list')
1532 ('symbol', '_list')
1520 ('string', '0\x001\x002')
1533 ('string', '0\x001\x002')
1521 follow)
1534 follow)
1522 define)
1535 define)
1523 * set:
1536 * set:
1524 <filteredset
1537 <filteredset
1525 <spanset- 0:2>,
1538 <spanset- 0:2>,
1526 <baseset [0, 1, 2]>>
1539 <baseset [0, 1, 2]>>
1527 2
1540 2
1528 1
1541 1
1529 0
1542 0
1530
1543
1531 'A + B' should take the ordering of the left expression:
1544 'A + B' should take the ordering of the left expression:
1532
1545
1533 $ try --optimize '2:0 & (0:1 + 2)'
1546 $ try --optimize '2:0 & (0:1 + 2)'
1534 (and
1547 (and
1535 (range
1548 (range
1536 ('symbol', '2')
1549 ('symbol', '2')
1537 ('symbol', '0'))
1550 ('symbol', '0'))
1538 (group
1551 (group
1539 (or
1552 (or
1540 (list
1553 (list
1541 (range
1554 (range
1542 ('symbol', '0')
1555 ('symbol', '0')
1543 ('symbol', '1'))
1556 ('symbol', '1'))
1544 ('symbol', '2')))))
1557 ('symbol', '2')))))
1545 * optimized:
1558 * optimized:
1546 (and
1559 (and
1547 (range
1560 (range
1548 ('symbol', '2')
1561 ('symbol', '2')
1549 ('symbol', '0')
1562 ('symbol', '0')
1550 define)
1563 define)
1551 (or
1564 (or
1552 (list
1565 (list
1553 ('symbol', '2')
1566 ('symbol', '2')
1554 (range
1567 (range
1555 ('symbol', '0')
1568 ('symbol', '0')
1556 ('symbol', '1')
1569 ('symbol', '1')
1557 follow))
1570 follow))
1558 follow)
1571 follow)
1559 define)
1572 define)
1560 * set:
1573 * set:
1561 <filteredset
1574 <filteredset
1562 <spanset- 0:2>,
1575 <spanset- 0:2>,
1563 <addset
1576 <addset
1564 <baseset [2]>,
1577 <baseset [2]>,
1565 <spanset+ 0:1>>>
1578 <spanset+ 0:1>>>
1566 2
1579 2
1567 1
1580 1
1568 0
1581 0
1569
1582
1570 '_intlist(a b)' should behave like 'a + b':
1583 '_intlist(a b)' should behave like 'a + b':
1571
1584
1572 $ trylist --optimize '2:0 & %ld' 0 1 2
1585 $ trylist --optimize '2:0 & %ld' 0 1 2
1573 (and
1586 (and
1574 (range
1587 (range
1575 ('symbol', '2')
1588 ('symbol', '2')
1576 ('symbol', '0'))
1589 ('symbol', '0'))
1577 (func
1590 (func
1578 ('symbol', '_intlist')
1591 ('symbol', '_intlist')
1579 ('string', '0\x001\x002')))
1592 ('string', '0\x001\x002')))
1580 * optimized:
1593 * optimized:
1581 (and
1594 (and
1582 (func
1595 (func
1583 ('symbol', '_intlist')
1596 ('symbol', '_intlist')
1584 ('string', '0\x001\x002')
1597 ('string', '0\x001\x002')
1585 follow)
1598 follow)
1586 (range
1599 (range
1587 ('symbol', '2')
1600 ('symbol', '2')
1588 ('symbol', '0')
1601 ('symbol', '0')
1589 define)
1602 define)
1590 define)
1603 define)
1591 * set:
1604 * set:
1592 <filteredset
1605 <filteredset
1593 <spanset- 0:2>,
1606 <spanset- 0:2>,
1594 <baseset+ [0, 1, 2]>>
1607 <baseset+ [0, 1, 2]>>
1595 2
1608 2
1596 1
1609 1
1597 0
1610 0
1598
1611
1599 $ trylist --optimize '%ld & 2:0' 0 2 1
1612 $ trylist --optimize '%ld & 2:0' 0 2 1
1600 (and
1613 (and
1601 (func
1614 (func
1602 ('symbol', '_intlist')
1615 ('symbol', '_intlist')
1603 ('string', '0\x002\x001'))
1616 ('string', '0\x002\x001'))
1604 (range
1617 (range
1605 ('symbol', '2')
1618 ('symbol', '2')
1606 ('symbol', '0')))
1619 ('symbol', '0')))
1607 * optimized:
1620 * optimized:
1608 (and
1621 (and
1609 (func
1622 (func
1610 ('symbol', '_intlist')
1623 ('symbol', '_intlist')
1611 ('string', '0\x002\x001')
1624 ('string', '0\x002\x001')
1612 define)
1625 define)
1613 (range
1626 (range
1614 ('symbol', '2')
1627 ('symbol', '2')
1615 ('symbol', '0')
1628 ('symbol', '0')
1616 follow)
1629 follow)
1617 define)
1630 define)
1618 * set:
1631 * set:
1619 <filteredset
1632 <filteredset
1620 <baseset [0, 2, 1]>,
1633 <baseset [0, 2, 1]>,
1621 <spanset- 0:2>>
1634 <spanset- 0:2>>
1622 0
1635 0
1623 2
1636 2
1624 1
1637 1
1625
1638
1626 '_hexlist(a b)' should behave like 'a + b':
1639 '_hexlist(a b)' should behave like 'a + b':
1627
1640
1628 $ trylist --optimize --bin '2:0 & %ln' `hg log -T '{node} ' -r0:2`
1641 $ trylist --optimize --bin '2:0 & %ln' `hg log -T '{node} ' -r0:2`
1629 (and
1642 (and
1630 (range
1643 (range
1631 ('symbol', '2')
1644 ('symbol', '2')
1632 ('symbol', '0'))
1645 ('symbol', '0'))
1633 (func
1646 (func
1634 ('symbol', '_hexlist')
1647 ('symbol', '_hexlist')
1635 ('string', '*'))) (glob)
1648 ('string', '*'))) (glob)
1636 * optimized:
1649 * optimized:
1637 (and
1650 (and
1638 (range
1651 (range
1639 ('symbol', '2')
1652 ('symbol', '2')
1640 ('symbol', '0')
1653 ('symbol', '0')
1641 define)
1654 define)
1642 (func
1655 (func
1643 ('symbol', '_hexlist')
1656 ('symbol', '_hexlist')
1644 ('string', '*') (glob)
1657 ('string', '*') (glob)
1645 follow)
1658 follow)
1646 define)
1659 define)
1647 * set:
1660 * set:
1648 <filteredset
1661 <filteredset
1649 <spanset- 0:2>,
1662 <spanset- 0:2>,
1650 <baseset [0, 1, 2]>>
1663 <baseset [0, 1, 2]>>
1651 2
1664 2
1652 1
1665 1
1653 0
1666 0
1654
1667
1655 $ trylist --optimize --bin '%ln & 2:0' `hg log -T '{node} ' -r0+2+1`
1668 $ trylist --optimize --bin '%ln & 2:0' `hg log -T '{node} ' -r0+2+1`
1656 (and
1669 (and
1657 (func
1670 (func
1658 ('symbol', '_hexlist')
1671 ('symbol', '_hexlist')
1659 ('string', '*')) (glob)
1672 ('string', '*')) (glob)
1660 (range
1673 (range
1661 ('symbol', '2')
1674 ('symbol', '2')
1662 ('symbol', '0')))
1675 ('symbol', '0')))
1663 * optimized:
1676 * optimized:
1664 (and
1677 (and
1665 (range
1678 (range
1666 ('symbol', '2')
1679 ('symbol', '2')
1667 ('symbol', '0')
1680 ('symbol', '0')
1668 follow)
1681 follow)
1669 (func
1682 (func
1670 ('symbol', '_hexlist')
1683 ('symbol', '_hexlist')
1671 ('string', '*') (glob)
1684 ('string', '*') (glob)
1672 define)
1685 define)
1673 define)
1686 define)
1674 * set:
1687 * set:
1675 <baseset [0, 2, 1]>
1688 <baseset [0, 2, 1]>
1676 0
1689 0
1677 2
1690 2
1678 1
1691 1
1679
1692
1680 '_list' should not go through the slow follow-order path if order doesn't
1693 '_list' should not go through the slow follow-order path if order doesn't
1681 matter:
1694 matter:
1682
1695
1683 $ try -p optimized '2:0 & not (0 + 1)'
1696 $ try -p optimized '2:0 & not (0 + 1)'
1684 * optimized:
1697 * optimized:
1685 (difference
1698 (difference
1686 (range
1699 (range
1687 ('symbol', '2')
1700 ('symbol', '2')
1688 ('symbol', '0')
1701 ('symbol', '0')
1689 define)
1702 define)
1690 (func
1703 (func
1691 ('symbol', '_list')
1704 ('symbol', '_list')
1692 ('string', '0\x001')
1705 ('string', '0\x001')
1693 any)
1706 any)
1694 define)
1707 define)
1695 * set:
1708 * set:
1696 <filteredset
1709 <filteredset
1697 <spanset- 0:2>,
1710 <spanset- 0:2>,
1698 <not
1711 <not
1699 <baseset [0, 1]>>>
1712 <baseset [0, 1]>>>
1700 2
1713 2
1701
1714
1702 $ try -p optimized '2:0 & not (0:2 & (0 + 1))'
1715 $ try -p optimized '2:0 & not (0:2 & (0 + 1))'
1703 * optimized:
1716 * optimized:
1704 (difference
1717 (difference
1705 (range
1718 (range
1706 ('symbol', '2')
1719 ('symbol', '2')
1707 ('symbol', '0')
1720 ('symbol', '0')
1708 define)
1721 define)
1709 (and
1722 (and
1710 (range
1723 (range
1711 ('symbol', '0')
1724 ('symbol', '0')
1712 ('symbol', '2')
1725 ('symbol', '2')
1713 any)
1726 any)
1714 (func
1727 (func
1715 ('symbol', '_list')
1728 ('symbol', '_list')
1716 ('string', '0\x001')
1729 ('string', '0\x001')
1717 any)
1730 any)
1718 any)
1731 any)
1719 define)
1732 define)
1720 * set:
1733 * set:
1721 <filteredset
1734 <filteredset
1722 <spanset- 0:2>,
1735 <spanset- 0:2>,
1723 <not
1736 <not
1724 <baseset [0, 1]>>>
1737 <baseset [0, 1]>>>
1725 2
1738 2
1726
1739
1727 because 'present()' does nothing other than suppressing an error, the
1740 because 'present()' does nothing other than suppressing an error, the
1728 ordering requirement should be forwarded to the nested expression
1741 ordering requirement should be forwarded to the nested expression
1729
1742
1730 $ try -p optimized 'present(2 + 0 + 1)'
1743 $ try -p optimized 'present(2 + 0 + 1)'
1731 * optimized:
1744 * optimized:
1732 (func
1745 (func
1733 ('symbol', 'present')
1746 ('symbol', 'present')
1734 (func
1747 (func
1735 ('symbol', '_list')
1748 ('symbol', '_list')
1736 ('string', '2\x000\x001')
1749 ('string', '2\x000\x001')
1737 define)
1750 define)
1738 define)
1751 define)
1739 * set:
1752 * set:
1740 <baseset [2, 0, 1]>
1753 <baseset [2, 0, 1]>
1741 2
1754 2
1742 0
1755 0
1743 1
1756 1
1744
1757
1745 $ try --optimize '2:0 & present(0 + 1 + 2)'
1758 $ try --optimize '2:0 & present(0 + 1 + 2)'
1746 (and
1759 (and
1747 (range
1760 (range
1748 ('symbol', '2')
1761 ('symbol', '2')
1749 ('symbol', '0'))
1762 ('symbol', '0'))
1750 (func
1763 (func
1751 ('symbol', 'present')
1764 ('symbol', 'present')
1752 (or
1765 (or
1753 (list
1766 (list
1754 ('symbol', '0')
1767 ('symbol', '0')
1755 ('symbol', '1')
1768 ('symbol', '1')
1756 ('symbol', '2')))))
1769 ('symbol', '2')))))
1757 * optimized:
1770 * optimized:
1758 (and
1771 (and
1759 (range
1772 (range
1760 ('symbol', '2')
1773 ('symbol', '2')
1761 ('symbol', '0')
1774 ('symbol', '0')
1762 define)
1775 define)
1763 (func
1776 (func
1764 ('symbol', 'present')
1777 ('symbol', 'present')
1765 (func
1778 (func
1766 ('symbol', '_list')
1779 ('symbol', '_list')
1767 ('string', '0\x001\x002')
1780 ('string', '0\x001\x002')
1768 follow)
1781 follow)
1769 follow)
1782 follow)
1770 define)
1783 define)
1771 * set:
1784 * set:
1772 <filteredset
1785 <filteredset
1773 <spanset- 0:2>,
1786 <spanset- 0:2>,
1774 <baseset [0, 1, 2]>>
1787 <baseset [0, 1, 2]>>
1775 2
1788 2
1776 1
1789 1
1777 0
1790 0
1778
1791
1779 'reverse()' should take effect only if it is the outermost expression:
1792 'reverse()' should take effect only if it is the outermost expression:
1780
1793
1781 $ try --optimize '0:2 & reverse(all())'
1794 $ try --optimize '0:2 & reverse(all())'
1782 (and
1795 (and
1783 (range
1796 (range
1784 ('symbol', '0')
1797 ('symbol', '0')
1785 ('symbol', '2'))
1798 ('symbol', '2'))
1786 (func
1799 (func
1787 ('symbol', 'reverse')
1800 ('symbol', 'reverse')
1788 (func
1801 (func
1789 ('symbol', 'all')
1802 ('symbol', 'all')
1790 None)))
1803 None)))
1791 * optimized:
1804 * optimized:
1792 (and
1805 (and
1793 (range
1806 (range
1794 ('symbol', '0')
1807 ('symbol', '0')
1795 ('symbol', '2')
1808 ('symbol', '2')
1796 define)
1809 define)
1797 (func
1810 (func
1798 ('symbol', 'reverse')
1811 ('symbol', 'reverse')
1799 (func
1812 (func
1800 ('symbol', 'all')
1813 ('symbol', 'all')
1801 None
1814 None
1802 define)
1815 define)
1803 follow)
1816 follow)
1804 define)
1817 define)
1805 * set:
1818 * set:
1806 <filteredset
1819 <filteredset
1807 <spanset+ 0:2>,
1820 <spanset+ 0:2>,
1808 <spanset+ 0:9>>
1821 <spanset+ 0:9>>
1809 0
1822 0
1810 1
1823 1
1811 2
1824 2
1812
1825
1813 'sort()' should take effect only if it is the outermost expression:
1826 'sort()' should take effect only if it is the outermost expression:
1814
1827
1815 $ try --optimize '0:2 & sort(all(), -rev)'
1828 $ try --optimize '0:2 & sort(all(), -rev)'
1816 (and
1829 (and
1817 (range
1830 (range
1818 ('symbol', '0')
1831 ('symbol', '0')
1819 ('symbol', '2'))
1832 ('symbol', '2'))
1820 (func
1833 (func
1821 ('symbol', 'sort')
1834 ('symbol', 'sort')
1822 (list
1835 (list
1823 (func
1836 (func
1824 ('symbol', 'all')
1837 ('symbol', 'all')
1825 None)
1838 None)
1826 (negate
1839 (negate
1827 ('symbol', 'rev')))))
1840 ('symbol', 'rev')))))
1828 * optimized:
1841 * optimized:
1829 (and
1842 (and
1830 (range
1843 (range
1831 ('symbol', '0')
1844 ('symbol', '0')
1832 ('symbol', '2')
1845 ('symbol', '2')
1833 define)
1846 define)
1834 (func
1847 (func
1835 ('symbol', 'sort')
1848 ('symbol', 'sort')
1836 (list
1849 (list
1837 (func
1850 (func
1838 ('symbol', 'all')
1851 ('symbol', 'all')
1839 None
1852 None
1840 define)
1853 define)
1841 ('string', '-rev'))
1854 ('string', '-rev'))
1842 follow)
1855 follow)
1843 define)
1856 define)
1844 * set:
1857 * set:
1845 <filteredset
1858 <filteredset
1846 <spanset+ 0:2>,
1859 <spanset+ 0:2>,
1847 <spanset+ 0:9>>
1860 <spanset+ 0:9>>
1848 0
1861 0
1849 1
1862 1
1850 2
1863 2
1851
1864
1852 invalid argument passed to noop sort():
1865 invalid argument passed to noop sort():
1853
1866
1854 $ log '0:2 & sort()'
1867 $ log '0:2 & sort()'
1855 hg: parse error: sort requires one or two arguments
1868 hg: parse error: sort requires one or two arguments
1856 [255]
1869 [255]
1857 $ log '0:2 & sort(all(), -invalid)'
1870 $ log '0:2 & sort(all(), -invalid)'
1858 hg: parse error: unknown sort key '-invalid'
1871 hg: parse error: unknown sort key '-invalid'
1859 [255]
1872 [255]
1860
1873
1861 for 'A & f(B)', 'B' should not be affected by the order of 'A':
1874 for 'A & f(B)', 'B' should not be affected by the order of 'A':
1862
1875
1863 $ try --optimize '2:0 & first(1 + 0 + 2)'
1876 $ try --optimize '2:0 & first(1 + 0 + 2)'
1864 (and
1877 (and
1865 (range
1878 (range
1866 ('symbol', '2')
1879 ('symbol', '2')
1867 ('symbol', '0'))
1880 ('symbol', '0'))
1868 (func
1881 (func
1869 ('symbol', 'first')
1882 ('symbol', 'first')
1870 (or
1883 (or
1871 (list
1884 (list
1872 ('symbol', '1')
1885 ('symbol', '1')
1873 ('symbol', '0')
1886 ('symbol', '0')
1874 ('symbol', '2')))))
1887 ('symbol', '2')))))
1875 * optimized:
1888 * optimized:
1876 (and
1889 (and
1877 (range
1890 (range
1878 ('symbol', '2')
1891 ('symbol', '2')
1879 ('symbol', '0')
1892 ('symbol', '0')
1880 define)
1893 define)
1881 (func
1894 (func
1882 ('symbol', 'first')
1895 ('symbol', 'first')
1883 (func
1896 (func
1884 ('symbol', '_list')
1897 ('symbol', '_list')
1885 ('string', '1\x000\x002')
1898 ('string', '1\x000\x002')
1886 define)
1899 define)
1887 follow)
1900 follow)
1888 define)
1901 define)
1889 * set:
1902 * set:
1890 <baseset
1903 <baseset
1891 <limit n=1, offset=0,
1904 <limit n=1, offset=0,
1892 <spanset- 0:2>,
1905 <spanset- 0:2>,
1893 <baseset [1, 0, 2]>>>
1906 <baseset [1, 0, 2]>>>
1894 1
1907 1
1895
1908
1896 $ try --optimize '2:0 & not last(0 + 2 + 1)'
1909 $ try --optimize '2:0 & not last(0 + 2 + 1)'
1897 (and
1910 (and
1898 (range
1911 (range
1899 ('symbol', '2')
1912 ('symbol', '2')
1900 ('symbol', '0'))
1913 ('symbol', '0'))
1901 (not
1914 (not
1902 (func
1915 (func
1903 ('symbol', 'last')
1916 ('symbol', 'last')
1904 (or
1917 (or
1905 (list
1918 (list
1906 ('symbol', '0')
1919 ('symbol', '0')
1907 ('symbol', '2')
1920 ('symbol', '2')
1908 ('symbol', '1'))))))
1921 ('symbol', '1'))))))
1909 * optimized:
1922 * optimized:
1910 (difference
1923 (difference
1911 (range
1924 (range
1912 ('symbol', '2')
1925 ('symbol', '2')
1913 ('symbol', '0')
1926 ('symbol', '0')
1914 define)
1927 define)
1915 (func
1928 (func
1916 ('symbol', 'last')
1929 ('symbol', 'last')
1917 (func
1930 (func
1918 ('symbol', '_list')
1931 ('symbol', '_list')
1919 ('string', '0\x002\x001')
1932 ('string', '0\x002\x001')
1920 define)
1933 define)
1921 any)
1934 any)
1922 define)
1935 define)
1923 * set:
1936 * set:
1924 <filteredset
1937 <filteredset
1925 <spanset- 0:2>,
1938 <spanset- 0:2>,
1926 <not
1939 <not
1927 <baseset
1940 <baseset
1928 <last n=1,
1941 <last n=1,
1929 <fullreposet+ 0:9>,
1942 <fullreposet+ 0:9>,
1930 <baseset [1, 2, 0]>>>>>
1943 <baseset [1, 2, 0]>>>>>
1931 2
1944 2
1932 0
1945 0
1933
1946
1934 for 'A & (op)(B)', 'B' should not be affected by the order of 'A':
1947 for 'A & (op)(B)', 'B' should not be affected by the order of 'A':
1935
1948
1936 $ try --optimize '2:0 & (1 + 0 + 2):(0 + 2 + 1)'
1949 $ try --optimize '2:0 & (1 + 0 + 2):(0 + 2 + 1)'
1937 (and
1950 (and
1938 (range
1951 (range
1939 ('symbol', '2')
1952 ('symbol', '2')
1940 ('symbol', '0'))
1953 ('symbol', '0'))
1941 (range
1954 (range
1942 (group
1955 (group
1943 (or
1956 (or
1944 (list
1957 (list
1945 ('symbol', '1')
1958 ('symbol', '1')
1946 ('symbol', '0')
1959 ('symbol', '0')
1947 ('symbol', '2'))))
1960 ('symbol', '2'))))
1948 (group
1961 (group
1949 (or
1962 (or
1950 (list
1963 (list
1951 ('symbol', '0')
1964 ('symbol', '0')
1952 ('symbol', '2')
1965 ('symbol', '2')
1953 ('symbol', '1'))))))
1966 ('symbol', '1'))))))
1954 * optimized:
1967 * optimized:
1955 (and
1968 (and
1956 (range
1969 (range
1957 ('symbol', '2')
1970 ('symbol', '2')
1958 ('symbol', '0')
1971 ('symbol', '0')
1959 define)
1972 define)
1960 (range
1973 (range
1961 (func
1974 (func
1962 ('symbol', '_list')
1975 ('symbol', '_list')
1963 ('string', '1\x000\x002')
1976 ('string', '1\x000\x002')
1964 define)
1977 define)
1965 (func
1978 (func
1966 ('symbol', '_list')
1979 ('symbol', '_list')
1967 ('string', '0\x002\x001')
1980 ('string', '0\x002\x001')
1968 define)
1981 define)
1969 follow)
1982 follow)
1970 define)
1983 define)
1971 * set:
1984 * set:
1972 <filteredset
1985 <filteredset
1973 <spanset- 0:2>,
1986 <spanset- 0:2>,
1974 <baseset [1]>>
1987 <baseset [1]>>
1975 1
1988 1
1976
1989
1977 'A & B' can be rewritten as 'B & A' by weight, but that's fine as long as
1990 'A & B' can be rewritten as 'B & A' by weight, but that's fine as long as
1978 the ordering rule is determined before the rewrite; in this example,
1991 the ordering rule is determined before the rewrite; in this example,
1979 'B' follows the order of the initial set, which is the same order as 'A'
1992 'B' follows the order of the initial set, which is the same order as 'A'
1980 since 'A' also follows the order:
1993 since 'A' also follows the order:
1981
1994
1982 $ try --optimize 'contains("glob:*") & (2 + 0 + 1)'
1995 $ try --optimize 'contains("glob:*") & (2 + 0 + 1)'
1983 (and
1996 (and
1984 (func
1997 (func
1985 ('symbol', 'contains')
1998 ('symbol', 'contains')
1986 ('string', 'glob:*'))
1999 ('string', 'glob:*'))
1987 (group
2000 (group
1988 (or
2001 (or
1989 (list
2002 (list
1990 ('symbol', '2')
2003 ('symbol', '2')
1991 ('symbol', '0')
2004 ('symbol', '0')
1992 ('symbol', '1')))))
2005 ('symbol', '1')))))
1993 * optimized:
2006 * optimized:
1994 (and
2007 (and
1995 (func
2008 (func
1996 ('symbol', '_list')
2009 ('symbol', '_list')
1997 ('string', '2\x000\x001')
2010 ('string', '2\x000\x001')
1998 follow)
2011 follow)
1999 (func
2012 (func
2000 ('symbol', 'contains')
2013 ('symbol', 'contains')
2001 ('string', 'glob:*')
2014 ('string', 'glob:*')
2002 define)
2015 define)
2003 define)
2016 define)
2004 * set:
2017 * set:
2005 <filteredset
2018 <filteredset
2006 <baseset+ [0, 1, 2]>,
2019 <baseset+ [0, 1, 2]>,
2007 <contains 'glob:*'>>
2020 <contains 'glob:*'>>
2008 0
2021 0
2009 1
2022 1
2010 2
2023 2
2011
2024
2012 and in this example, 'A & B' is rewritten as 'B & A', but 'A' overrides
2025 and in this example, 'A & B' is rewritten as 'B & A', but 'A' overrides
2013 the order appropriately:
2026 the order appropriately:
2014
2027
2015 $ try --optimize 'reverse(contains("glob:*")) & (0 + 2 + 1)'
2028 $ try --optimize 'reverse(contains("glob:*")) & (0 + 2 + 1)'
2016 (and
2029 (and
2017 (func
2030 (func
2018 ('symbol', 'reverse')
2031 ('symbol', 'reverse')
2019 (func
2032 (func
2020 ('symbol', 'contains')
2033 ('symbol', 'contains')
2021 ('string', 'glob:*')))
2034 ('string', 'glob:*')))
2022 (group
2035 (group
2023 (or
2036 (or
2024 (list
2037 (list
2025 ('symbol', '0')
2038 ('symbol', '0')
2026 ('symbol', '2')
2039 ('symbol', '2')
2027 ('symbol', '1')))))
2040 ('symbol', '1')))))
2028 * optimized:
2041 * optimized:
2029 (and
2042 (and
2030 (func
2043 (func
2031 ('symbol', '_list')
2044 ('symbol', '_list')
2032 ('string', '0\x002\x001')
2045 ('string', '0\x002\x001')
2033 follow)
2046 follow)
2034 (func
2047 (func
2035 ('symbol', 'reverse')
2048 ('symbol', 'reverse')
2036 (func
2049 (func
2037 ('symbol', 'contains')
2050 ('symbol', 'contains')
2038 ('string', 'glob:*')
2051 ('string', 'glob:*')
2039 define)
2052 define)
2040 define)
2053 define)
2041 define)
2054 define)
2042 * set:
2055 * set:
2043 <filteredset
2056 <filteredset
2044 <baseset- [0, 1, 2]>,
2057 <baseset- [0, 1, 2]>,
2045 <contains 'glob:*'>>
2058 <contains 'glob:*'>>
2046 2
2059 2
2047 1
2060 1
2048 0
2061 0
2049
2062
2050 'A + B' can be rewritten to 'B + A' by weight only when the order doesn't
2063 'A + B' can be rewritten to 'B + A' by weight only when the order doesn't
2051 matter (e.g. 'X & (A + B)' can be 'X & (B + A)', but '(A + B) & X' can't):
2064 matter (e.g. 'X & (A + B)' can be 'X & (B + A)', but '(A + B) & X' can't):
2052
2065
2053 $ try -p optimized '0:2 & (reverse(contains("a")) + 2)'
2066 $ try -p optimized '0:2 & (reverse(contains("a")) + 2)'
2054 * optimized:
2067 * optimized:
2055 (and
2068 (and
2056 (range
2069 (range
2057 ('symbol', '0')
2070 ('symbol', '0')
2058 ('symbol', '2')
2071 ('symbol', '2')
2059 define)
2072 define)
2060 (or
2073 (or
2061 (list
2074 (list
2062 ('symbol', '2')
2075 ('symbol', '2')
2063 (func
2076 (func
2064 ('symbol', 'reverse')
2077 ('symbol', 'reverse')
2065 (func
2078 (func
2066 ('symbol', 'contains')
2079 ('symbol', 'contains')
2067 ('string', 'a')
2080 ('string', 'a')
2068 define)
2081 define)
2069 follow))
2082 follow))
2070 follow)
2083 follow)
2071 define)
2084 define)
2072 * set:
2085 * set:
2073 <filteredset
2086 <filteredset
2074 <spanset+ 0:2>,
2087 <spanset+ 0:2>,
2075 <addset
2088 <addset
2076 <baseset [2]>,
2089 <baseset [2]>,
2077 <filteredset
2090 <filteredset
2078 <fullreposet+ 0:9>,
2091 <fullreposet+ 0:9>,
2079 <contains 'a'>>>>
2092 <contains 'a'>>>>
2080 0
2093 0
2081 1
2094 1
2082 2
2095 2
2083
2096
2084 $ try -p optimized '(reverse(contains("a")) + 2) & 0:2'
2097 $ try -p optimized '(reverse(contains("a")) + 2) & 0:2'
2085 * optimized:
2098 * optimized:
2086 (and
2099 (and
2087 (range
2100 (range
2088 ('symbol', '0')
2101 ('symbol', '0')
2089 ('symbol', '2')
2102 ('symbol', '2')
2090 follow)
2103 follow)
2091 (or
2104 (or
2092 (list
2105 (list
2093 (func
2106 (func
2094 ('symbol', 'reverse')
2107 ('symbol', 'reverse')
2095 (func
2108 (func
2096 ('symbol', 'contains')
2109 ('symbol', 'contains')
2097 ('string', 'a')
2110 ('string', 'a')
2098 define)
2111 define)
2099 define)
2112 define)
2100 ('symbol', '2'))
2113 ('symbol', '2'))
2101 define)
2114 define)
2102 define)
2115 define)
2103 * set:
2116 * set:
2104 <addset
2117 <addset
2105 <filteredset
2118 <filteredset
2106 <spanset- 0:2>,
2119 <spanset- 0:2>,
2107 <contains 'a'>>,
2120 <contains 'a'>>,
2108 <baseset [2]>>
2121 <baseset [2]>>
2109 1
2122 1
2110 0
2123 0
2111 2
2124 2
2112
2125
2113 test sort revset
2126 test sort revset
2114 --------------------------------------------
2127 --------------------------------------------
2115
2128
2116 test when adding two unordered revsets
2129 test when adding two unordered revsets
2117
2130
2118 $ log 'sort(keyword(issue) or modifies(b))'
2131 $ log 'sort(keyword(issue) or modifies(b))'
2119 4
2132 4
2120 6
2133 6
2121
2134
2122 test when sorting a reversed collection in the same way it is
2135 test when sorting a reversed collection in the same way it is
2123
2136
2124 $ log 'sort(reverse(all()), -rev)'
2137 $ log 'sort(reverse(all()), -rev)'
2125 9
2138 9
2126 8
2139 8
2127 7
2140 7
2128 6
2141 6
2129 5
2142 5
2130 4
2143 4
2131 3
2144 3
2132 2
2145 2
2133 1
2146 1
2134 0
2147 0
2135
2148
2136 test when sorting a reversed collection
2149 test when sorting a reversed collection
2137
2150
2138 $ log 'sort(reverse(all()), rev)'
2151 $ log 'sort(reverse(all()), rev)'
2139 0
2152 0
2140 1
2153 1
2141 2
2154 2
2142 3
2155 3
2143 4
2156 4
2144 5
2157 5
2145 6
2158 6
2146 7
2159 7
2147 8
2160 8
2148 9
2161 9
2149
2162
2150
2163
2151 test sorting two sorted collections in different orders
2164 test sorting two sorted collections in different orders
2152
2165
2153 $ log 'sort(outgoing() or reverse(removes(a)), rev)'
2166 $ log 'sort(outgoing() or reverse(removes(a)), rev)'
2154 2
2167 2
2155 6
2168 6
2156 8
2169 8
2157 9
2170 9
2158
2171
2159 test sorting two sorted collections in different orders backwards
2172 test sorting two sorted collections in different orders backwards
2160
2173
2161 $ log 'sort(outgoing() or reverse(removes(a)), -rev)'
2174 $ log 'sort(outgoing() or reverse(removes(a)), -rev)'
2162 9
2175 9
2163 8
2176 8
2164 6
2177 6
2165 2
2178 2
2166
2179
2167 test empty sort key which is noop
2180 test empty sort key which is noop
2168
2181
2169 $ log 'sort(0 + 2 + 1, "")'
2182 $ log 'sort(0 + 2 + 1, "")'
2170 0
2183 0
2171 2
2184 2
2172 1
2185 1
2173
2186
2174 test invalid sort keys
2187 test invalid sort keys
2175
2188
2176 $ log 'sort(all(), -invalid)'
2189 $ log 'sort(all(), -invalid)'
2177 hg: parse error: unknown sort key '-invalid'
2190 hg: parse error: unknown sort key '-invalid'
2178 [255]
2191 [255]
2179
2192
2180 $ cd ..
2193 $ cd ..
2181
2194
2182 test sorting by multiple keys including variable-length strings
2195 test sorting by multiple keys including variable-length strings
2183
2196
2184 $ hg init sorting
2197 $ hg init sorting
2185 $ cd sorting
2198 $ cd sorting
2186 $ cat <<EOF >> .hg/hgrc
2199 $ cat <<EOF >> .hg/hgrc
2187 > [ui]
2200 > [ui]
2188 > logtemplate = '{rev} {branch|p5}{desc|p5}{author|p5}{date|hgdate}\n'
2201 > logtemplate = '{rev} {branch|p5}{desc|p5}{author|p5}{date|hgdate}\n'
2189 > [templatealias]
2202 > [templatealias]
2190 > p5(s) = pad(s, 5)
2203 > p5(s) = pad(s, 5)
2191 > EOF
2204 > EOF
2192 $ hg branch -qf b12
2205 $ hg branch -qf b12
2193 $ hg ci -m m111 -u u112 -d '111 10800'
2206 $ hg ci -m m111 -u u112 -d '111 10800'
2194 $ hg branch -qf b11
2207 $ hg branch -qf b11
2195 $ hg ci -m m12 -u u111 -d '112 7200'
2208 $ hg ci -m m12 -u u111 -d '112 7200'
2196 $ hg branch -qf b111
2209 $ hg branch -qf b111
2197 $ hg ci -m m11 -u u12 -d '111 3600'
2210 $ hg ci -m m11 -u u12 -d '111 3600'
2198 $ hg branch -qf b112
2211 $ hg branch -qf b112
2199 $ hg ci -m m111 -u u11 -d '120 0'
2212 $ hg ci -m m111 -u u11 -d '120 0'
2200 $ hg branch -qf b111
2213 $ hg branch -qf b111
2201 $ hg ci -m m112 -u u111 -d '110 14400'
2214 $ hg ci -m m112 -u u111 -d '110 14400'
2202 created new head
2215 created new head
2203
2216
2204 compare revisions (has fast path):
2217 compare revisions (has fast path):
2205
2218
2206 $ hg log -r 'sort(all(), rev)'
2219 $ hg log -r 'sort(all(), rev)'
2207 0 b12 m111 u112 111 10800
2220 0 b12 m111 u112 111 10800
2208 1 b11 m12 u111 112 7200
2221 1 b11 m12 u111 112 7200
2209 2 b111 m11 u12 111 3600
2222 2 b111 m11 u12 111 3600
2210 3 b112 m111 u11 120 0
2223 3 b112 m111 u11 120 0
2211 4 b111 m112 u111 110 14400
2224 4 b111 m112 u111 110 14400
2212
2225
2213 $ hg log -r 'sort(all(), -rev)'
2226 $ hg log -r 'sort(all(), -rev)'
2214 4 b111 m112 u111 110 14400
2227 4 b111 m112 u111 110 14400
2215 3 b112 m111 u11 120 0
2228 3 b112 m111 u11 120 0
2216 2 b111 m11 u12 111 3600
2229 2 b111 m11 u12 111 3600
2217 1 b11 m12 u111 112 7200
2230 1 b11 m12 u111 112 7200
2218 0 b12 m111 u112 111 10800
2231 0 b12 m111 u112 111 10800
2219
2232
2220 compare variable-length strings (issue5218):
2233 compare variable-length strings (issue5218):
2221
2234
2222 $ hg log -r 'sort(all(), branch)'
2235 $ hg log -r 'sort(all(), branch)'
2223 1 b11 m12 u111 112 7200
2236 1 b11 m12 u111 112 7200
2224 2 b111 m11 u12 111 3600
2237 2 b111 m11 u12 111 3600
2225 4 b111 m112 u111 110 14400
2238 4 b111 m112 u111 110 14400
2226 3 b112 m111 u11 120 0
2239 3 b112 m111 u11 120 0
2227 0 b12 m111 u112 111 10800
2240 0 b12 m111 u112 111 10800
2228
2241
2229 $ hg log -r 'sort(all(), -branch)'
2242 $ hg log -r 'sort(all(), -branch)'
2230 0 b12 m111 u112 111 10800
2243 0 b12 m111 u112 111 10800
2231 3 b112 m111 u11 120 0
2244 3 b112 m111 u11 120 0
2232 2 b111 m11 u12 111 3600
2245 2 b111 m11 u12 111 3600
2233 4 b111 m112 u111 110 14400
2246 4 b111 m112 u111 110 14400
2234 1 b11 m12 u111 112 7200
2247 1 b11 m12 u111 112 7200
2235
2248
2236 $ hg log -r 'sort(all(), desc)'
2249 $ hg log -r 'sort(all(), desc)'
2237 2 b111 m11 u12 111 3600
2250 2 b111 m11 u12 111 3600
2238 0 b12 m111 u112 111 10800
2251 0 b12 m111 u112 111 10800
2239 3 b112 m111 u11 120 0
2252 3 b112 m111 u11 120 0
2240 4 b111 m112 u111 110 14400
2253 4 b111 m112 u111 110 14400
2241 1 b11 m12 u111 112 7200
2254 1 b11 m12 u111 112 7200
2242
2255
2243 $ hg log -r 'sort(all(), -desc)'
2256 $ hg log -r 'sort(all(), -desc)'
2244 1 b11 m12 u111 112 7200
2257 1 b11 m12 u111 112 7200
2245 4 b111 m112 u111 110 14400
2258 4 b111 m112 u111 110 14400
2246 0 b12 m111 u112 111 10800
2259 0 b12 m111 u112 111 10800
2247 3 b112 m111 u11 120 0
2260 3 b112 m111 u11 120 0
2248 2 b111 m11 u12 111 3600
2261 2 b111 m11 u12 111 3600
2249
2262
2250 $ hg log -r 'sort(all(), user)'
2263 $ hg log -r 'sort(all(), user)'
2251 3 b112 m111 u11 120 0
2264 3 b112 m111 u11 120 0
2252 1 b11 m12 u111 112 7200
2265 1 b11 m12 u111 112 7200
2253 4 b111 m112 u111 110 14400
2266 4 b111 m112 u111 110 14400
2254 0 b12 m111 u112 111 10800
2267 0 b12 m111 u112 111 10800
2255 2 b111 m11 u12 111 3600
2268 2 b111 m11 u12 111 3600
2256
2269
2257 $ hg log -r 'sort(all(), -user)'
2270 $ hg log -r 'sort(all(), -user)'
2258 2 b111 m11 u12 111 3600
2271 2 b111 m11 u12 111 3600
2259 0 b12 m111 u112 111 10800
2272 0 b12 m111 u112 111 10800
2260 1 b11 m12 u111 112 7200
2273 1 b11 m12 u111 112 7200
2261 4 b111 m112 u111 110 14400
2274 4 b111 m112 u111 110 14400
2262 3 b112 m111 u11 120 0
2275 3 b112 m111 u11 120 0
2263
2276
2264 compare dates (tz offset should have no effect):
2277 compare dates (tz offset should have no effect):
2265
2278
2266 $ hg log -r 'sort(all(), date)'
2279 $ hg log -r 'sort(all(), date)'
2267 4 b111 m112 u111 110 14400
2280 4 b111 m112 u111 110 14400
2268 0 b12 m111 u112 111 10800
2281 0 b12 m111 u112 111 10800
2269 2 b111 m11 u12 111 3600
2282 2 b111 m11 u12 111 3600
2270 1 b11 m12 u111 112 7200
2283 1 b11 m12 u111 112 7200
2271 3 b112 m111 u11 120 0
2284 3 b112 m111 u11 120 0
2272
2285
2273 $ hg log -r 'sort(all(), -date)'
2286 $ hg log -r 'sort(all(), -date)'
2274 3 b112 m111 u11 120 0
2287 3 b112 m111 u11 120 0
2275 1 b11 m12 u111 112 7200
2288 1 b11 m12 u111 112 7200
2276 0 b12 m111 u112 111 10800
2289 0 b12 m111 u112 111 10800
2277 2 b111 m11 u12 111 3600
2290 2 b111 m11 u12 111 3600
2278 4 b111 m112 u111 110 14400
2291 4 b111 m112 u111 110 14400
2279
2292
2280 be aware that 'sort(x, -k)' is not exactly the same as 'reverse(sort(x, k))'
2293 be aware that 'sort(x, -k)' is not exactly the same as 'reverse(sort(x, k))'
2281 because '-k' reverses the comparison, not the list itself:
2294 because '-k' reverses the comparison, not the list itself:
2282
2295
2283 $ hg log -r 'sort(0 + 2, date)'
2296 $ hg log -r 'sort(0 + 2, date)'
2284 0 b12 m111 u112 111 10800
2297 0 b12 m111 u112 111 10800
2285 2 b111 m11 u12 111 3600
2298 2 b111 m11 u12 111 3600
2286
2299
2287 $ hg log -r 'sort(0 + 2, -date)'
2300 $ hg log -r 'sort(0 + 2, -date)'
2288 0 b12 m111 u112 111 10800
2301 0 b12 m111 u112 111 10800
2289 2 b111 m11 u12 111 3600
2302 2 b111 m11 u12 111 3600
2290
2303
2291 $ hg log -r 'reverse(sort(0 + 2, date))'
2304 $ hg log -r 'reverse(sort(0 + 2, date))'
2292 2 b111 m11 u12 111 3600
2305 2 b111 m11 u12 111 3600
2293 0 b12 m111 u112 111 10800
2306 0 b12 m111 u112 111 10800
2294
2307
2295 sort by multiple keys:
2308 sort by multiple keys:
2296
2309
2297 $ hg log -r 'sort(all(), "branch -rev")'
2310 $ hg log -r 'sort(all(), "branch -rev")'
2298 1 b11 m12 u111 112 7200
2311 1 b11 m12 u111 112 7200
2299 4 b111 m112 u111 110 14400
2312 4 b111 m112 u111 110 14400
2300 2 b111 m11 u12 111 3600
2313 2 b111 m11 u12 111 3600
2301 3 b112 m111 u11 120 0
2314 3 b112 m111 u11 120 0
2302 0 b12 m111 u112 111 10800
2315 0 b12 m111 u112 111 10800
2303
2316
2304 $ hg log -r 'sort(all(), "-desc -date")'
2317 $ hg log -r 'sort(all(), "-desc -date")'
2305 1 b11 m12 u111 112 7200
2318 1 b11 m12 u111 112 7200
2306 4 b111 m112 u111 110 14400
2319 4 b111 m112 u111 110 14400
2307 3 b112 m111 u11 120 0
2320 3 b112 m111 u11 120 0
2308 0 b12 m111 u112 111 10800
2321 0 b12 m111 u112 111 10800
2309 2 b111 m11 u12 111 3600
2322 2 b111 m11 u12 111 3600
2310
2323
2311 $ hg log -r 'sort(all(), "user -branch date rev")'
2324 $ hg log -r 'sort(all(), "user -branch date rev")'
2312 3 b112 m111 u11 120 0
2325 3 b112 m111 u11 120 0
2313 4 b111 m112 u111 110 14400
2326 4 b111 m112 u111 110 14400
2314 1 b11 m12 u111 112 7200
2327 1 b11 m12 u111 112 7200
2315 0 b12 m111 u112 111 10800
2328 0 b12 m111 u112 111 10800
2316 2 b111 m11 u12 111 3600
2329 2 b111 m11 u12 111 3600
2317
2330
2318 toposort prioritises graph branches
2331 toposort prioritises graph branches
2319
2332
2320 $ hg up 2
2333 $ hg up 2
2321 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
2334 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
2322 $ touch a
2335 $ touch a
2323 $ hg addremove
2336 $ hg addremove
2324 adding a
2337 adding a
2325 $ hg ci -m 't1' -u 'tu' -d '130 0'
2338 $ hg ci -m 't1' -u 'tu' -d '130 0'
2326 created new head
2339 created new head
2327 $ echo 'a' >> a
2340 $ echo 'a' >> a
2328 $ hg ci -m 't2' -u 'tu' -d '130 0'
2341 $ hg ci -m 't2' -u 'tu' -d '130 0'
2329 $ hg book book1
2342 $ hg book book1
2330 $ hg up 4
2343 $ hg up 4
2331 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
2344 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
2332 (leaving bookmark book1)
2345 (leaving bookmark book1)
2333 $ touch a
2346 $ touch a
2334 $ hg addremove
2347 $ hg addremove
2335 adding a
2348 adding a
2336 $ hg ci -m 't3' -u 'tu' -d '130 0'
2349 $ hg ci -m 't3' -u 'tu' -d '130 0'
2337
2350
2338 $ hg log -r 'sort(all(), topo)'
2351 $ hg log -r 'sort(all(), topo)'
2339 7 b111 t3 tu 130 0
2352 7 b111 t3 tu 130 0
2340 4 b111 m112 u111 110 14400
2353 4 b111 m112 u111 110 14400
2341 3 b112 m111 u11 120 0
2354 3 b112 m111 u11 120 0
2342 6 b111 t2 tu 130 0
2355 6 b111 t2 tu 130 0
2343 5 b111 t1 tu 130 0
2356 5 b111 t1 tu 130 0
2344 2 b111 m11 u12 111 3600
2357 2 b111 m11 u12 111 3600
2345 1 b11 m12 u111 112 7200
2358 1 b11 m12 u111 112 7200
2346 0 b12 m111 u112 111 10800
2359 0 b12 m111 u112 111 10800
2347
2360
2348 $ hg log -r 'sort(all(), -topo)'
2361 $ hg log -r 'sort(all(), -topo)'
2349 0 b12 m111 u112 111 10800
2362 0 b12 m111 u112 111 10800
2350 1 b11 m12 u111 112 7200
2363 1 b11 m12 u111 112 7200
2351 2 b111 m11 u12 111 3600
2364 2 b111 m11 u12 111 3600
2352 5 b111 t1 tu 130 0
2365 5 b111 t1 tu 130 0
2353 6 b111 t2 tu 130 0
2366 6 b111 t2 tu 130 0
2354 3 b112 m111 u11 120 0
2367 3 b112 m111 u11 120 0
2355 4 b111 m112 u111 110 14400
2368 4 b111 m112 u111 110 14400
2356 7 b111 t3 tu 130 0
2369 7 b111 t3 tu 130 0
2357
2370
2358 $ hg log -r 'sort(all(), topo, topo.firstbranch=book1)'
2371 $ hg log -r 'sort(all(), topo, topo.firstbranch=book1)'
2359 6 b111 t2 tu 130 0
2372 6 b111 t2 tu 130 0
2360 5 b111 t1 tu 130 0
2373 5 b111 t1 tu 130 0
2361 7 b111 t3 tu 130 0
2374 7 b111 t3 tu 130 0
2362 4 b111 m112 u111 110 14400
2375 4 b111 m112 u111 110 14400
2363 3 b112 m111 u11 120 0
2376 3 b112 m111 u11 120 0
2364 2 b111 m11 u12 111 3600
2377 2 b111 m11 u12 111 3600
2365 1 b11 m12 u111 112 7200
2378 1 b11 m12 u111 112 7200
2366 0 b12 m111 u112 111 10800
2379 0 b12 m111 u112 111 10800
2367
2380
2368 topographical sorting can't be combined with other sort keys, and you can't
2381 topographical sorting can't be combined with other sort keys, and you can't
2369 use the topo.firstbranch option when topo sort is not active:
2382 use the topo.firstbranch option when topo sort is not active:
2370
2383
2371 $ hg log -r 'sort(all(), "topo user")'
2384 $ hg log -r 'sort(all(), "topo user")'
2372 hg: parse error: topo sort order cannot be combined with other sort keys
2385 hg: parse error: topo sort order cannot be combined with other sort keys
2373 [255]
2386 [255]
2374
2387
2375 $ hg log -r 'sort(all(), user, topo.firstbranch=book1)'
2388 $ hg log -r 'sort(all(), user, topo.firstbranch=book1)'
2376 hg: parse error: topo.firstbranch can only be used when using the topo sort key
2389 hg: parse error: topo.firstbranch can only be used when using the topo sort key
2377 [255]
2390 [255]
2378
2391
2379 topo.firstbranch should accept any kind of expressions:
2392 topo.firstbranch should accept any kind of expressions:
2380
2393
2381 $ hg log -r 'sort(0, topo, topo.firstbranch=(book1))'
2394 $ hg log -r 'sort(0, topo, topo.firstbranch=(book1))'
2382 0 b12 m111 u112 111 10800
2395 0 b12 m111 u112 111 10800
2383
2396
2384 $ cd ..
2397 $ cd ..
2385 $ cd repo
2398 $ cd repo
2386
2399
2387 test subtracting something from an addset
2400 test subtracting something from an addset
2388
2401
2389 $ log '(outgoing() or removes(a)) - removes(a)'
2402 $ log '(outgoing() or removes(a)) - removes(a)'
2390 8
2403 8
2391 9
2404 9
2392
2405
2393 test intersecting something with an addset
2406 test intersecting something with an addset
2394
2407
2395 $ log 'parents(outgoing() or removes(a))'
2408 $ log 'parents(outgoing() or removes(a))'
2396 1
2409 1
2397 4
2410 4
2398 5
2411 5
2399 8
2412 8
2400
2413
2401 test that `or` operation combines elements in the right order:
2414 test that `or` operation combines elements in the right order:
2402
2415
2403 $ log '3:4 or 2:5'
2416 $ log '3:4 or 2:5'
2404 3
2417 3
2405 4
2418 4
2406 2
2419 2
2407 5
2420 5
2408 $ log '3:4 or 5:2'
2421 $ log '3:4 or 5:2'
2409 3
2422 3
2410 4
2423 4
2411 5
2424 5
2412 2
2425 2
2413 $ log 'sort(3:4 or 2:5)'
2426 $ log 'sort(3:4 or 2:5)'
2414 2
2427 2
2415 3
2428 3
2416 4
2429 4
2417 5
2430 5
2418 $ log 'sort(3:4 or 5:2)'
2431 $ log 'sort(3:4 or 5:2)'
2419 2
2432 2
2420 3
2433 3
2421 4
2434 4
2422 5
2435 5
2423
2436
2424 test that more than one `-r`s are combined in the right order and deduplicated:
2437 test that more than one `-r`s are combined in the right order and deduplicated:
2425
2438
2426 $ hg log -T '{rev}\n' -r 3 -r 3 -r 4 -r 5:2 -r 'ancestors(4)'
2439 $ hg log -T '{rev}\n' -r 3 -r 3 -r 4 -r 5:2 -r 'ancestors(4)'
2427 3
2440 3
2428 4
2441 4
2429 5
2442 5
2430 2
2443 2
2431 0
2444 0
2432 1
2445 1
2433
2446
2434 test that `or` operation skips duplicated revisions from right-hand side
2447 test that `or` operation skips duplicated revisions from right-hand side
2435
2448
2436 $ try 'reverse(1::5) or ancestors(4)'
2449 $ try 'reverse(1::5) or ancestors(4)'
2437 (or
2450 (or
2438 (list
2451 (list
2439 (func
2452 (func
2440 ('symbol', 'reverse')
2453 ('symbol', 'reverse')
2441 (dagrange
2454 (dagrange
2442 ('symbol', '1')
2455 ('symbol', '1')
2443 ('symbol', '5')))
2456 ('symbol', '5')))
2444 (func
2457 (func
2445 ('symbol', 'ancestors')
2458 ('symbol', 'ancestors')
2446 ('symbol', '4'))))
2459 ('symbol', '4'))))
2447 * set:
2460 * set:
2448 <addset
2461 <addset
2449 <baseset- [1, 3, 5]>,
2462 <baseset- [1, 3, 5]>,
2450 <generatorset+>>
2463 <generatorset+>>
2451 5
2464 5
2452 3
2465 3
2453 1
2466 1
2454 0
2467 0
2455 2
2468 2
2456 4
2469 4
2457 $ try 'sort(ancestors(4) or reverse(1::5))'
2470 $ try 'sort(ancestors(4) or reverse(1::5))'
2458 (func
2471 (func
2459 ('symbol', 'sort')
2472 ('symbol', 'sort')
2460 (or
2473 (or
2461 (list
2474 (list
2462 (func
2475 (func
2463 ('symbol', 'ancestors')
2476 ('symbol', 'ancestors')
2464 ('symbol', '4'))
2477 ('symbol', '4'))
2465 (func
2478 (func
2466 ('symbol', 'reverse')
2479 ('symbol', 'reverse')
2467 (dagrange
2480 (dagrange
2468 ('symbol', '1')
2481 ('symbol', '1')
2469 ('symbol', '5'))))))
2482 ('symbol', '5'))))))
2470 * set:
2483 * set:
2471 <addset+
2484 <addset+
2472 <generatorset+>,
2485 <generatorset+>,
2473 <baseset- [1, 3, 5]>>
2486 <baseset- [1, 3, 5]>>
2474 0
2487 0
2475 1
2488 1
2476 2
2489 2
2477 3
2490 3
2478 4
2491 4
2479 5
2492 5
2480
2493
2481 test optimization of trivial `or` operation
2494 test optimization of trivial `or` operation
2482
2495
2483 $ try --optimize '0|(1)|"2"|-2|tip|null'
2496 $ try --optimize '0|(1)|"2"|-2|tip|null'
2484 (or
2497 (or
2485 (list
2498 (list
2486 ('symbol', '0')
2499 ('symbol', '0')
2487 (group
2500 (group
2488 ('symbol', '1'))
2501 ('symbol', '1'))
2489 ('string', '2')
2502 ('string', '2')
2490 (negate
2503 (negate
2491 ('symbol', '2'))
2504 ('symbol', '2'))
2492 ('symbol', 'tip')
2505 ('symbol', 'tip')
2493 ('symbol', 'null')))
2506 ('symbol', 'null')))
2494 * optimized:
2507 * optimized:
2495 (func
2508 (func
2496 ('symbol', '_list')
2509 ('symbol', '_list')
2497 ('string', '0\x001\x002\x00-2\x00tip\x00null')
2510 ('string', '0\x001\x002\x00-2\x00tip\x00null')
2498 define)
2511 define)
2499 * set:
2512 * set:
2500 <baseset [0, 1, 2, 8, 9, -1]>
2513 <baseset [0, 1, 2, 8, 9, -1]>
2501 0
2514 0
2502 1
2515 1
2503 2
2516 2
2504 8
2517 8
2505 9
2518 9
2506 -1
2519 -1
2507
2520
2508 $ try --optimize '0|1|2:3'
2521 $ try --optimize '0|1|2:3'
2509 (or
2522 (or
2510 (list
2523 (list
2511 ('symbol', '0')
2524 ('symbol', '0')
2512 ('symbol', '1')
2525 ('symbol', '1')
2513 (range
2526 (range
2514 ('symbol', '2')
2527 ('symbol', '2')
2515 ('symbol', '3'))))
2528 ('symbol', '3'))))
2516 * optimized:
2529 * optimized:
2517 (or
2530 (or
2518 (list
2531 (list
2519 (func
2532 (func
2520 ('symbol', '_list')
2533 ('symbol', '_list')
2521 ('string', '0\x001')
2534 ('string', '0\x001')
2522 define)
2535 define)
2523 (range
2536 (range
2524 ('symbol', '2')
2537 ('symbol', '2')
2525 ('symbol', '3')
2538 ('symbol', '3')
2526 define))
2539 define))
2527 define)
2540 define)
2528 * set:
2541 * set:
2529 <addset
2542 <addset
2530 <baseset [0, 1]>,
2543 <baseset [0, 1]>,
2531 <spanset+ 2:3>>
2544 <spanset+ 2:3>>
2532 0
2545 0
2533 1
2546 1
2534 2
2547 2
2535 3
2548 3
2536
2549
2537 $ try --optimize '0:1|2|3:4|5|6'
2550 $ try --optimize '0:1|2|3:4|5|6'
2538 (or
2551 (or
2539 (list
2552 (list
2540 (range
2553 (range
2541 ('symbol', '0')
2554 ('symbol', '0')
2542 ('symbol', '1'))
2555 ('symbol', '1'))
2543 ('symbol', '2')
2556 ('symbol', '2')
2544 (range
2557 (range
2545 ('symbol', '3')
2558 ('symbol', '3')
2546 ('symbol', '4'))
2559 ('symbol', '4'))
2547 ('symbol', '5')
2560 ('symbol', '5')
2548 ('symbol', '6')))
2561 ('symbol', '6')))
2549 * optimized:
2562 * optimized:
2550 (or
2563 (or
2551 (list
2564 (list
2552 (range
2565 (range
2553 ('symbol', '0')
2566 ('symbol', '0')
2554 ('symbol', '1')
2567 ('symbol', '1')
2555 define)
2568 define)
2556 ('symbol', '2')
2569 ('symbol', '2')
2557 (range
2570 (range
2558 ('symbol', '3')
2571 ('symbol', '3')
2559 ('symbol', '4')
2572 ('symbol', '4')
2560 define)
2573 define)
2561 (func
2574 (func
2562 ('symbol', '_list')
2575 ('symbol', '_list')
2563 ('string', '5\x006')
2576 ('string', '5\x006')
2564 define))
2577 define))
2565 define)
2578 define)
2566 * set:
2579 * set:
2567 <addset
2580 <addset
2568 <addset
2581 <addset
2569 <spanset+ 0:1>,
2582 <spanset+ 0:1>,
2570 <baseset [2]>>,
2583 <baseset [2]>>,
2571 <addset
2584 <addset
2572 <spanset+ 3:4>,
2585 <spanset+ 3:4>,
2573 <baseset [5, 6]>>>
2586 <baseset [5, 6]>>>
2574 0
2587 0
2575 1
2588 1
2576 2
2589 2
2577 3
2590 3
2578 4
2591 4
2579 5
2592 5
2580 6
2593 6
2581
2594
2582 unoptimized `or` looks like this
2595 unoptimized `or` looks like this
2583
2596
2584 $ try --no-optimized -p analyzed '0|1|2|3|4'
2597 $ try --no-optimized -p analyzed '0|1|2|3|4'
2585 * analyzed:
2598 * analyzed:
2586 (or
2599 (or
2587 (list
2600 (list
2588 ('symbol', '0')
2601 ('symbol', '0')
2589 ('symbol', '1')
2602 ('symbol', '1')
2590 ('symbol', '2')
2603 ('symbol', '2')
2591 ('symbol', '3')
2604 ('symbol', '3')
2592 ('symbol', '4'))
2605 ('symbol', '4'))
2593 define)
2606 define)
2594 * set:
2607 * set:
2595 <addset
2608 <addset
2596 <addset
2609 <addset
2597 <baseset [0]>,
2610 <baseset [0]>,
2598 <baseset [1]>>,
2611 <baseset [1]>>,
2599 <addset
2612 <addset
2600 <baseset [2]>,
2613 <baseset [2]>,
2601 <addset
2614 <addset
2602 <baseset [3]>,
2615 <baseset [3]>,
2603 <baseset [4]>>>>
2616 <baseset [4]>>>>
2604 0
2617 0
2605 1
2618 1
2606 2
2619 2
2607 3
2620 3
2608 4
2621 4
2609
2622
2610 test that `_list` should be narrowed by provided `subset`
2623 test that `_list` should be narrowed by provided `subset`
2611
2624
2612 $ log '0:2 and (null|1|2|3)'
2625 $ log '0:2 and (null|1|2|3)'
2613 1
2626 1
2614 2
2627 2
2615
2628
2616 test that `_list` should remove duplicates
2629 test that `_list` should remove duplicates
2617
2630
2618 $ log '0|1|2|1|2|-1|tip'
2631 $ log '0|1|2|1|2|-1|tip'
2619 0
2632 0
2620 1
2633 1
2621 2
2634 2
2622 9
2635 9
2623
2636
2624 test unknown revision in `_list`
2637 test unknown revision in `_list`
2625
2638
2626 $ log '0|unknown'
2639 $ log '0|unknown'
2627 abort: unknown revision 'unknown'!
2640 abort: unknown revision 'unknown'!
2628 [255]
2641 [255]
2629
2642
2630 test integer range in `_list`
2643 test integer range in `_list`
2631
2644
2632 $ log '-1|-10'
2645 $ log '-1|-10'
2633 9
2646 9
2634 0
2647 0
2635
2648
2636 $ log '-10|-11'
2649 $ log '-10|-11'
2637 abort: unknown revision '-11'!
2650 abort: unknown revision '-11'!
2638 [255]
2651 [255]
2639
2652
2640 $ log '9|10'
2653 $ log '9|10'
2641 abort: unknown revision '10'!
2654 abort: unknown revision '10'!
2642 [255]
2655 [255]
2643
2656
2644 test '0000' != '0' in `_list`
2657 test '0000' != '0' in `_list`
2645
2658
2646 $ log '0|0000'
2659 $ log '0|0000'
2647 0
2660 0
2648 -1
2661 -1
2649
2662
2650 test ',' in `_list`
2663 test ',' in `_list`
2651 $ log '0,1'
2664 $ log '0,1'
2652 hg: parse error: can't use a list in this context
2665 hg: parse error: can't use a list in this context
2653 (see hg help "revsets.x or y")
2666 (see hg help "revsets.x or y")
2654 [255]
2667 [255]
2655 $ try '0,1,2'
2668 $ try '0,1,2'
2656 (list
2669 (list
2657 ('symbol', '0')
2670 ('symbol', '0')
2658 ('symbol', '1')
2671 ('symbol', '1')
2659 ('symbol', '2'))
2672 ('symbol', '2'))
2660 hg: parse error: can't use a list in this context
2673 hg: parse error: can't use a list in this context
2661 (see hg help "revsets.x or y")
2674 (see hg help "revsets.x or y")
2662 [255]
2675 [255]
2663
2676
2664 test that chained `or` operations make balanced addsets
2677 test that chained `or` operations make balanced addsets
2665
2678
2666 $ try '0:1|1:2|2:3|3:4|4:5'
2679 $ try '0:1|1:2|2:3|3:4|4:5'
2667 (or
2680 (or
2668 (list
2681 (list
2669 (range
2682 (range
2670 ('symbol', '0')
2683 ('symbol', '0')
2671 ('symbol', '1'))
2684 ('symbol', '1'))
2672 (range
2685 (range
2673 ('symbol', '1')
2686 ('symbol', '1')
2674 ('symbol', '2'))
2687 ('symbol', '2'))
2675 (range
2688 (range
2676 ('symbol', '2')
2689 ('symbol', '2')
2677 ('symbol', '3'))
2690 ('symbol', '3'))
2678 (range
2691 (range
2679 ('symbol', '3')
2692 ('symbol', '3')
2680 ('symbol', '4'))
2693 ('symbol', '4'))
2681 (range
2694 (range
2682 ('symbol', '4')
2695 ('symbol', '4')
2683 ('symbol', '5'))))
2696 ('symbol', '5'))))
2684 * set:
2697 * set:
2685 <addset
2698 <addset
2686 <addset
2699 <addset
2687 <spanset+ 0:1>,
2700 <spanset+ 0:1>,
2688 <spanset+ 1:2>>,
2701 <spanset+ 1:2>>,
2689 <addset
2702 <addset
2690 <spanset+ 2:3>,
2703 <spanset+ 2:3>,
2691 <addset
2704 <addset
2692 <spanset+ 3:4>,
2705 <spanset+ 3:4>,
2693 <spanset+ 4:5>>>>
2706 <spanset+ 4:5>>>>
2694 0
2707 0
2695 1
2708 1
2696 2
2709 2
2697 3
2710 3
2698 4
2711 4
2699 5
2712 5
2700
2713
2701 no crash by empty group "()" while optimizing `or` operations
2714 no crash by empty group "()" while optimizing `or` operations
2702
2715
2703 $ try --optimize '0|()'
2716 $ try --optimize '0|()'
2704 (or
2717 (or
2705 (list
2718 (list
2706 ('symbol', '0')
2719 ('symbol', '0')
2707 (group
2720 (group
2708 None)))
2721 None)))
2709 * optimized:
2722 * optimized:
2710 (or
2723 (or
2711 (list
2724 (list
2712 ('symbol', '0')
2725 ('symbol', '0')
2713 None)
2726 None)
2714 define)
2727 define)
2715 hg: parse error: missing argument
2728 hg: parse error: missing argument
2716 [255]
2729 [255]
2717
2730
2718 test that chained `or` operations never eat up stack (issue4624)
2731 test that chained `or` operations never eat up stack (issue4624)
2719 (uses `0:1` instead of `0` to avoid future optimization of trivial revisions)
2732 (uses `0:1` instead of `0` to avoid future optimization of trivial revisions)
2720
2733
2721 $ hg log -T '{rev}\n' -r `python -c "print '+'.join(['0:1'] * 500)"`
2734 $ hg log -T '{rev}\n' -r `python -c "print '+'.join(['0:1'] * 500)"`
2722 0
2735 0
2723 1
2736 1
2724
2737
2725 test that repeated `-r` options never eat up stack (issue4565)
2738 test that repeated `-r` options never eat up stack (issue4565)
2726 (uses `-r 0::1` to avoid possible optimization at old-style parser)
2739 (uses `-r 0::1` to avoid possible optimization at old-style parser)
2727
2740
2728 $ hg log -T '{rev}\n' `python -c "for i in xrange(500): print '-r 0::1 ',"`
2741 $ hg log -T '{rev}\n' `python -c "for i in xrange(500): print '-r 0::1 ',"`
2729 0
2742 0
2730 1
2743 1
2731
2744
2732 check that conversion to only works
2745 check that conversion to only works
2733 $ try --optimize '::3 - ::1'
2746 $ try --optimize '::3 - ::1'
2734 (minus
2747 (minus
2735 (dagrangepre
2748 (dagrangepre
2736 ('symbol', '3'))
2749 ('symbol', '3'))
2737 (dagrangepre
2750 (dagrangepre
2738 ('symbol', '1')))
2751 ('symbol', '1')))
2739 * optimized:
2752 * optimized:
2740 (func
2753 (func
2741 ('symbol', 'only')
2754 ('symbol', 'only')
2742 (list
2755 (list
2743 ('symbol', '3')
2756 ('symbol', '3')
2744 ('symbol', '1'))
2757 ('symbol', '1'))
2745 define)
2758 define)
2746 * set:
2759 * set:
2747 <baseset+ [3]>
2760 <baseset+ [3]>
2748 3
2761 3
2749 $ try --optimize 'ancestors(1) - ancestors(3)'
2762 $ try --optimize 'ancestors(1) - ancestors(3)'
2750 (minus
2763 (minus
2751 (func
2764 (func
2752 ('symbol', 'ancestors')
2765 ('symbol', 'ancestors')
2753 ('symbol', '1'))
2766 ('symbol', '1'))
2754 (func
2767 (func
2755 ('symbol', 'ancestors')
2768 ('symbol', 'ancestors')
2756 ('symbol', '3')))
2769 ('symbol', '3')))
2757 * optimized:
2770 * optimized:
2758 (func
2771 (func
2759 ('symbol', 'only')
2772 ('symbol', 'only')
2760 (list
2773 (list
2761 ('symbol', '1')
2774 ('symbol', '1')
2762 ('symbol', '3'))
2775 ('symbol', '3'))
2763 define)
2776 define)
2764 * set:
2777 * set:
2765 <baseset+ []>
2778 <baseset+ []>
2766 $ try --optimize 'not ::2 and ::6'
2779 $ try --optimize 'not ::2 and ::6'
2767 (and
2780 (and
2768 (not
2781 (not
2769 (dagrangepre
2782 (dagrangepre
2770 ('symbol', '2')))
2783 ('symbol', '2')))
2771 (dagrangepre
2784 (dagrangepre
2772 ('symbol', '6')))
2785 ('symbol', '6')))
2773 * optimized:
2786 * optimized:
2774 (func
2787 (func
2775 ('symbol', 'only')
2788 ('symbol', 'only')
2776 (list
2789 (list
2777 ('symbol', '6')
2790 ('symbol', '6')
2778 ('symbol', '2'))
2791 ('symbol', '2'))
2779 define)
2792 define)
2780 * set:
2793 * set:
2781 <baseset+ [3, 4, 5, 6]>
2794 <baseset+ [3, 4, 5, 6]>
2782 3
2795 3
2783 4
2796 4
2784 5
2797 5
2785 6
2798 6
2786 $ try --optimize 'ancestors(6) and not ancestors(4)'
2799 $ try --optimize 'ancestors(6) and not ancestors(4)'
2787 (and
2800 (and
2788 (func
2801 (func
2789 ('symbol', 'ancestors')
2802 ('symbol', 'ancestors')
2790 ('symbol', '6'))
2803 ('symbol', '6'))
2791 (not
2804 (not
2792 (func
2805 (func
2793 ('symbol', 'ancestors')
2806 ('symbol', 'ancestors')
2794 ('symbol', '4'))))
2807 ('symbol', '4'))))
2795 * optimized:
2808 * optimized:
2796 (func
2809 (func
2797 ('symbol', 'only')
2810 ('symbol', 'only')
2798 (list
2811 (list
2799 ('symbol', '6')
2812 ('symbol', '6')
2800 ('symbol', '4'))
2813 ('symbol', '4'))
2801 define)
2814 define)
2802 * set:
2815 * set:
2803 <baseset+ [3, 5, 6]>
2816 <baseset+ [3, 5, 6]>
2804 3
2817 3
2805 5
2818 5
2806 6
2819 6
2807
2820
2808 no crash by empty group "()" while optimizing to "only()"
2821 no crash by empty group "()" while optimizing to "only()"
2809
2822
2810 $ try --optimize '::1 and ()'
2823 $ try --optimize '::1 and ()'
2811 (and
2824 (and
2812 (dagrangepre
2825 (dagrangepre
2813 ('symbol', '1'))
2826 ('symbol', '1'))
2814 (group
2827 (group
2815 None))
2828 None))
2816 * optimized:
2829 * optimized:
2817 (and
2830 (and
2818 None
2831 None
2819 (func
2832 (func
2820 ('symbol', 'ancestors')
2833 ('symbol', 'ancestors')
2821 ('symbol', '1')
2834 ('symbol', '1')
2822 define)
2835 define)
2823 define)
2836 define)
2824 hg: parse error: missing argument
2837 hg: parse error: missing argument
2825 [255]
2838 [255]
2826
2839
2827 invalid function call should not be optimized to only()
2840 invalid function call should not be optimized to only()
2828
2841
2829 $ log '"ancestors"(6) and not ancestors(4)'
2842 $ log '"ancestors"(6) and not ancestors(4)'
2830 hg: parse error: not a symbol
2843 hg: parse error: not a symbol
2831 [255]
2844 [255]
2832
2845
2833 $ log 'ancestors(6) and not "ancestors"(4)'
2846 $ log 'ancestors(6) and not "ancestors"(4)'
2834 hg: parse error: not a symbol
2847 hg: parse error: not a symbol
2835 [255]
2848 [255]
2836
2849
2837 we can use patterns when searching for tags
2850 we can use patterns when searching for tags
2838
2851
2839 $ log 'tag("1..*")'
2852 $ log 'tag("1..*")'
2840 abort: tag '1..*' does not exist!
2853 abort: tag '1..*' does not exist!
2841 [255]
2854 [255]
2842 $ log 'tag("re:1..*")'
2855 $ log 'tag("re:1..*")'
2843 6
2856 6
2844 $ log 'tag("re:[0-9].[0-9]")'
2857 $ log 'tag("re:[0-9].[0-9]")'
2845 6
2858 6
2846 $ log 'tag("literal:1.0")'
2859 $ log 'tag("literal:1.0")'
2847 6
2860 6
2848 $ log 'tag("re:0..*")'
2861 $ log 'tag("re:0..*")'
2849
2862
2850 $ log 'tag(unknown)'
2863 $ log 'tag(unknown)'
2851 abort: tag 'unknown' does not exist!
2864 abort: tag 'unknown' does not exist!
2852 [255]
2865 [255]
2853 $ log 'tag("re:unknown")'
2866 $ log 'tag("re:unknown")'
2854 $ log 'present(tag("unknown"))'
2867 $ log 'present(tag("unknown"))'
2855 $ log 'present(tag("re:unknown"))'
2868 $ log 'present(tag("re:unknown"))'
2856 $ log 'branch(unknown)'
2869 $ log 'branch(unknown)'
2857 abort: unknown revision 'unknown'!
2870 abort: unknown revision 'unknown'!
2858 [255]
2871 [255]
2859 $ log 'branch("literal:unknown")'
2872 $ log 'branch("literal:unknown")'
2860 abort: branch 'unknown' does not exist!
2873 abort: branch 'unknown' does not exist!
2861 [255]
2874 [255]
2862 $ log 'branch("re:unknown")'
2875 $ log 'branch("re:unknown")'
2863 $ log 'present(branch("unknown"))'
2876 $ log 'present(branch("unknown"))'
2864 $ log 'present(branch("re:unknown"))'
2877 $ log 'present(branch("re:unknown"))'
2865 $ log 'user(bob)'
2878 $ log 'user(bob)'
2866 2
2879 2
2867
2880
2868 $ log '4::8'
2881 $ log '4::8'
2869 4
2882 4
2870 8
2883 8
2871 $ log '4:8'
2884 $ log '4:8'
2872 4
2885 4
2873 5
2886 5
2874 6
2887 6
2875 7
2888 7
2876 8
2889 8
2877
2890
2878 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
2891 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
2879 4
2892 4
2880 2
2893 2
2881 5
2894 5
2882
2895
2883 $ log 'not 0 and 0:2'
2896 $ log 'not 0 and 0:2'
2884 1
2897 1
2885 2
2898 2
2886 $ log 'not 1 and 0:2'
2899 $ log 'not 1 and 0:2'
2887 0
2900 0
2888 2
2901 2
2889 $ log 'not 2 and 0:2'
2902 $ log 'not 2 and 0:2'
2890 0
2903 0
2891 1
2904 1
2892 $ log '(1 and 2)::'
2905 $ log '(1 and 2)::'
2893 $ log '(1 and 2):'
2906 $ log '(1 and 2):'
2894 $ log '(1 and 2):3'
2907 $ log '(1 and 2):3'
2895 $ log 'sort(head(), -rev)'
2908 $ log 'sort(head(), -rev)'
2896 9
2909 9
2897 7
2910 7
2898 6
2911 6
2899 5
2912 5
2900 4
2913 4
2901 3
2914 3
2902 2
2915 2
2903 1
2916 1
2904 0
2917 0
2905 $ log '4::8 - 8'
2918 $ log '4::8 - 8'
2906 4
2919 4
2907
2920
2908 matching() should preserve the order of the input set:
2921 matching() should preserve the order of the input set:
2909
2922
2910 $ log '(2 or 3 or 1) and matching(1 or 2 or 3)'
2923 $ log '(2 or 3 or 1) and matching(1 or 2 or 3)'
2911 2
2924 2
2912 3
2925 3
2913 1
2926 1
2914
2927
2915 $ log 'named("unknown")'
2928 $ log 'named("unknown")'
2916 abort: namespace 'unknown' does not exist!
2929 abort: namespace 'unknown' does not exist!
2917 [255]
2930 [255]
2918 $ log 'named("re:unknown")'
2931 $ log 'named("re:unknown")'
2919 abort: no namespace exists that match 'unknown'!
2932 abort: no namespace exists that match 'unknown'!
2920 [255]
2933 [255]
2921 $ log 'present(named("unknown"))'
2934 $ log 'present(named("unknown"))'
2922 $ log 'present(named("re:unknown"))'
2935 $ log 'present(named("re:unknown"))'
2923
2936
2924 $ log 'tag()'
2937 $ log 'tag()'
2925 6
2938 6
2926 $ log 'named("tags")'
2939 $ log 'named("tags")'
2927 6
2940 6
2928
2941
2929 issue2437
2942 issue2437
2930
2943
2931 $ log '3 and p1(5)'
2944 $ log '3 and p1(5)'
2932 3
2945 3
2933 $ log '4 and p2(6)'
2946 $ log '4 and p2(6)'
2934 4
2947 4
2935 $ log '1 and parents(:2)'
2948 $ log '1 and parents(:2)'
2936 1
2949 1
2937 $ log '2 and children(1:)'
2950 $ log '2 and children(1:)'
2938 2
2951 2
2939 $ log 'roots(all()) or roots(all())'
2952 $ log 'roots(all()) or roots(all())'
2940 0
2953 0
2941 $ hg debugrevspec 'roots(all()) or roots(all())'
2954 $ hg debugrevspec 'roots(all()) or roots(all())'
2942 0
2955 0
2943 $ log 'heads(branch(Γ©)) or heads(branch(Γ©))'
2956 $ log 'heads(branch(Γ©)) or heads(branch(Γ©))'
2944 9
2957 9
2945 $ log 'ancestors(8) and (heads(branch("-a-b-c-")) or heads(branch(Γ©)))'
2958 $ log 'ancestors(8) and (heads(branch("-a-b-c-")) or heads(branch(Γ©)))'
2946 4
2959 4
2947
2960
2948 issue2654: report a parse error if the revset was not completely parsed
2961 issue2654: report a parse error if the revset was not completely parsed
2949
2962
2950 $ log '1 OR 2'
2963 $ log '1 OR 2'
2951 hg: parse error at 2: invalid token
2964 hg: parse error at 2: invalid token
2952 [255]
2965 [255]
2953
2966
2954 or operator should preserve ordering:
2967 or operator should preserve ordering:
2955 $ log 'reverse(2::4) or tip'
2968 $ log 'reverse(2::4) or tip'
2956 4
2969 4
2957 2
2970 2
2958 9
2971 9
2959
2972
2960 parentrevspec
2973 parentrevspec
2961
2974
2962 $ log 'merge()^0'
2975 $ log 'merge()^0'
2963 6
2976 6
2964 $ log 'merge()^'
2977 $ log 'merge()^'
2965 5
2978 5
2966 $ log 'merge()^1'
2979 $ log 'merge()^1'
2967 5
2980 5
2968 $ log 'merge()^2'
2981 $ log 'merge()^2'
2969 4
2982 4
2970 $ log '(not merge())^2'
2983 $ log '(not merge())^2'
2971 $ log 'merge()^^'
2984 $ log 'merge()^^'
2972 3
2985 3
2973 $ log 'merge()^1^'
2986 $ log 'merge()^1^'
2974 3
2987 3
2975 $ log 'merge()^^^'
2988 $ log 'merge()^^^'
2976 1
2989 1
2977
2990
2978 $ log '(merge() | 0)~-1'
2991 $ log '(merge() | 0)~-1'
2979 7
2992 7
2980 1
2993 1
2981 $ log 'merge()~-1'
2994 $ log 'merge()~-1'
2982 7
2995 7
2983 $ log 'tip~-1'
2996 $ log 'tip~-1'
2984 $ log '(tip | merge())~-1'
2997 $ log '(tip | merge())~-1'
2985 7
2998 7
2986 $ log 'merge()~0'
2999 $ log 'merge()~0'
2987 6
3000 6
2988 $ log 'merge()~1'
3001 $ log 'merge()~1'
2989 5
3002 5
2990 $ log 'merge()~2'
3003 $ log 'merge()~2'
2991 3
3004 3
2992 $ log 'merge()~2^1'
3005 $ log 'merge()~2^1'
2993 1
3006 1
2994 $ log 'merge()~3'
3007 $ log 'merge()~3'
2995 1
3008 1
2996
3009
2997 $ log '(-3:tip)^'
3010 $ log '(-3:tip)^'
2998 4
3011 4
2999 6
3012 6
3000 8
3013 8
3001
3014
3002 $ log 'tip^foo'
3015 $ log 'tip^foo'
3003 hg: parse error: ^ expects a number 0, 1, or 2
3016 hg: parse error: ^ expects a number 0, 1, or 2
3004 [255]
3017 [255]
3005
3018
3006 $ log 'branchpoint()~-1'
3019 $ log 'branchpoint()~-1'
3007 abort: revision in set has more than one child!
3020 abort: revision in set has more than one child!
3008 [255]
3021 [255]
3009
3022
3010 Bogus function gets suggestions
3023 Bogus function gets suggestions
3011 $ log 'add()'
3024 $ log 'add()'
3012 hg: parse error: unknown identifier: add
3025 hg: parse error: unknown identifier: add
3013 (did you mean adds?)
3026 (did you mean adds?)
3014 [255]
3027 [255]
3015 $ log 'added()'
3028 $ log 'added()'
3016 hg: parse error: unknown identifier: added
3029 hg: parse error: unknown identifier: added
3017 (did you mean adds?)
3030 (did you mean adds?)
3018 [255]
3031 [255]
3019 $ log 'remo()'
3032 $ log 'remo()'
3020 hg: parse error: unknown identifier: remo
3033 hg: parse error: unknown identifier: remo
3021 (did you mean one of remote, removes?)
3034 (did you mean one of remote, removes?)
3022 [255]
3035 [255]
3023 $ log 'babar()'
3036 $ log 'babar()'
3024 hg: parse error: unknown identifier: babar
3037 hg: parse error: unknown identifier: babar
3025 [255]
3038 [255]
3026
3039
3027 Bogus function with a similar internal name doesn't suggest the internal name
3040 Bogus function with a similar internal name doesn't suggest the internal name
3028 $ log 'matches()'
3041 $ log 'matches()'
3029 hg: parse error: unknown identifier: matches
3042 hg: parse error: unknown identifier: matches
3030 (did you mean matching?)
3043 (did you mean matching?)
3031 [255]
3044 [255]
3032
3045
3033 Undocumented functions aren't suggested as similar either
3046 Undocumented functions aren't suggested as similar either
3034 $ log 'tagged2()'
3047 $ log 'tagged2()'
3035 hg: parse error: unknown identifier: tagged2
3048 hg: parse error: unknown identifier: tagged2
3036 [255]
3049 [255]
3037
3050
3038 multiple revspecs
3051 multiple revspecs
3039
3052
3040 $ hg log -r 'tip~1:tip' -r 'tip~2:tip~1' --template '{rev}\n'
3053 $ hg log -r 'tip~1:tip' -r 'tip~2:tip~1' --template '{rev}\n'
3041 8
3054 8
3042 9
3055 9
3043 4
3056 4
3044 5
3057 5
3045 6
3058 6
3046 7
3059 7
3047
3060
3048 test usage in revpair (with "+")
3061 test usage in revpair (with "+")
3049
3062
3050 (real pair)
3063 (real pair)
3051
3064
3052 $ hg diff -r 'tip^^' -r 'tip'
3065 $ hg diff -r 'tip^^' -r 'tip'
3053 diff -r 2326846efdab -r 24286f4ae135 .hgtags
3066 diff -r 2326846efdab -r 24286f4ae135 .hgtags
3054 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3067 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3055 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
3068 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
3056 @@ -0,0 +1,1 @@
3069 @@ -0,0 +1,1 @@
3057 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3070 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3058 $ hg diff -r 'tip^^::tip'
3071 $ hg diff -r 'tip^^::tip'
3059 diff -r 2326846efdab -r 24286f4ae135 .hgtags
3072 diff -r 2326846efdab -r 24286f4ae135 .hgtags
3060 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3073 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3061 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
3074 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
3062 @@ -0,0 +1,1 @@
3075 @@ -0,0 +1,1 @@
3063 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3076 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3064
3077
3065 (single rev)
3078 (single rev)
3066
3079
3067 $ hg diff -r 'tip^' -r 'tip^'
3080 $ hg diff -r 'tip^' -r 'tip^'
3068 $ hg diff -r 'tip^:tip^'
3081 $ hg diff -r 'tip^:tip^'
3069
3082
3070 (single rev that does not looks like a range)
3083 (single rev that does not looks like a range)
3071
3084
3072 $ hg diff -r 'tip^::tip^ or tip^'
3085 $ hg diff -r 'tip^::tip^ or tip^'
3073 diff -r d5d0dcbdc4d9 .hgtags
3086 diff -r d5d0dcbdc4d9 .hgtags
3074 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3087 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3075 +++ b/.hgtags * (glob)
3088 +++ b/.hgtags * (glob)
3076 @@ -0,0 +1,1 @@
3089 @@ -0,0 +1,1 @@
3077 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3090 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3078 $ hg diff -r 'tip^ or tip^'
3091 $ hg diff -r 'tip^ or tip^'
3079 diff -r d5d0dcbdc4d9 .hgtags
3092 diff -r d5d0dcbdc4d9 .hgtags
3080 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3093 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3081 +++ b/.hgtags * (glob)
3094 +++ b/.hgtags * (glob)
3082 @@ -0,0 +1,1 @@
3095 @@ -0,0 +1,1 @@
3083 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3096 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3084
3097
3085 (no rev)
3098 (no rev)
3086
3099
3087 $ hg diff -r 'author("babar") or author("celeste")'
3100 $ hg diff -r 'author("babar") or author("celeste")'
3088 abort: empty revision range
3101 abort: empty revision range
3089 [255]
3102 [255]
3090
3103
3091 aliases:
3104 aliases:
3092
3105
3093 $ echo '[revsetalias]' >> .hg/hgrc
3106 $ echo '[revsetalias]' >> .hg/hgrc
3094 $ echo 'm = merge()' >> .hg/hgrc
3107 $ echo 'm = merge()' >> .hg/hgrc
3095 (revset aliases can override builtin revsets)
3108 (revset aliases can override builtin revsets)
3096 $ echo 'p2($1) = p1($1)' >> .hg/hgrc
3109 $ echo 'p2($1) = p1($1)' >> .hg/hgrc
3097 $ echo 'sincem = descendants(m)' >> .hg/hgrc
3110 $ echo 'sincem = descendants(m)' >> .hg/hgrc
3098 $ echo 'd($1) = reverse(sort($1, date))' >> .hg/hgrc
3111 $ echo 'd($1) = reverse(sort($1, date))' >> .hg/hgrc
3099 $ echo 'rs(ARG1, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
3112 $ echo 'rs(ARG1, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
3100 $ echo 'rs4(ARG1, ARGA, ARGB, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
3113 $ echo 'rs4(ARG1, ARGA, ARGB, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
3101
3114
3102 $ try m
3115 $ try m
3103 ('symbol', 'm')
3116 ('symbol', 'm')
3104 * expanded:
3117 * expanded:
3105 (func
3118 (func
3106 ('symbol', 'merge')
3119 ('symbol', 'merge')
3107 None)
3120 None)
3108 * set:
3121 * set:
3109 <filteredset
3122 <filteredset
3110 <fullreposet+ 0:9>,
3123 <fullreposet+ 0:9>,
3111 <merge>>
3124 <merge>>
3112 6
3125 6
3113
3126
3114 $ HGPLAIN=1
3127 $ HGPLAIN=1
3115 $ export HGPLAIN
3128 $ export HGPLAIN
3116 $ try m
3129 $ try m
3117 ('symbol', 'm')
3130 ('symbol', 'm')
3118 abort: unknown revision 'm'!
3131 abort: unknown revision 'm'!
3119 [255]
3132 [255]
3120
3133
3121 $ HGPLAINEXCEPT=revsetalias
3134 $ HGPLAINEXCEPT=revsetalias
3122 $ export HGPLAINEXCEPT
3135 $ export HGPLAINEXCEPT
3123 $ try m
3136 $ try m
3124 ('symbol', 'm')
3137 ('symbol', 'm')
3125 * expanded:
3138 * expanded:
3126 (func
3139 (func
3127 ('symbol', 'merge')
3140 ('symbol', 'merge')
3128 None)
3141 None)
3129 * set:
3142 * set:
3130 <filteredset
3143 <filteredset
3131 <fullreposet+ 0:9>,
3144 <fullreposet+ 0:9>,
3132 <merge>>
3145 <merge>>
3133 6
3146 6
3134
3147
3135 $ unset HGPLAIN
3148 $ unset HGPLAIN
3136 $ unset HGPLAINEXCEPT
3149 $ unset HGPLAINEXCEPT
3137
3150
3138 $ try 'p2(.)'
3151 $ try 'p2(.)'
3139 (func
3152 (func
3140 ('symbol', 'p2')
3153 ('symbol', 'p2')
3141 ('symbol', '.'))
3154 ('symbol', '.'))
3142 * expanded:
3155 * expanded:
3143 (func
3156 (func
3144 ('symbol', 'p1')
3157 ('symbol', 'p1')
3145 ('symbol', '.'))
3158 ('symbol', '.'))
3146 * set:
3159 * set:
3147 <baseset+ [8]>
3160 <baseset+ [8]>
3148 8
3161 8
3149
3162
3150 $ HGPLAIN=1
3163 $ HGPLAIN=1
3151 $ export HGPLAIN
3164 $ export HGPLAIN
3152 $ try 'p2(.)'
3165 $ try 'p2(.)'
3153 (func
3166 (func
3154 ('symbol', 'p2')
3167 ('symbol', 'p2')
3155 ('symbol', '.'))
3168 ('symbol', '.'))
3156 * set:
3169 * set:
3157 <baseset+ []>
3170 <baseset+ []>
3158
3171
3159 $ HGPLAINEXCEPT=revsetalias
3172 $ HGPLAINEXCEPT=revsetalias
3160 $ export HGPLAINEXCEPT
3173 $ export HGPLAINEXCEPT
3161 $ try 'p2(.)'
3174 $ try 'p2(.)'
3162 (func
3175 (func
3163 ('symbol', 'p2')
3176 ('symbol', 'p2')
3164 ('symbol', '.'))
3177 ('symbol', '.'))
3165 * expanded:
3178 * expanded:
3166 (func
3179 (func
3167 ('symbol', 'p1')
3180 ('symbol', 'p1')
3168 ('symbol', '.'))
3181 ('symbol', '.'))
3169 * set:
3182 * set:
3170 <baseset+ [8]>
3183 <baseset+ [8]>
3171 8
3184 8
3172
3185
3173 $ unset HGPLAIN
3186 $ unset HGPLAIN
3174 $ unset HGPLAINEXCEPT
3187 $ unset HGPLAINEXCEPT
3175
3188
3176 test alias recursion
3189 test alias recursion
3177
3190
3178 $ try sincem
3191 $ try sincem
3179 ('symbol', 'sincem')
3192 ('symbol', 'sincem')
3180 * expanded:
3193 * expanded:
3181 (func
3194 (func
3182 ('symbol', 'descendants')
3195 ('symbol', 'descendants')
3183 (func
3196 (func
3184 ('symbol', 'merge')
3197 ('symbol', 'merge')
3185 None))
3198 None))
3186 * set:
3199 * set:
3187 <addset+
3200 <addset+
3188 <filteredset
3201 <filteredset
3189 <fullreposet+ 0:9>,
3202 <fullreposet+ 0:9>,
3190 <merge>>,
3203 <merge>>,
3191 <generatorset+>>
3204 <generatorset+>>
3192 6
3205 6
3193 7
3206 7
3194
3207
3195 test infinite recursion
3208 test infinite recursion
3196
3209
3197 $ echo 'recurse1 = recurse2' >> .hg/hgrc
3210 $ echo 'recurse1 = recurse2' >> .hg/hgrc
3198 $ echo 'recurse2 = recurse1' >> .hg/hgrc
3211 $ echo 'recurse2 = recurse1' >> .hg/hgrc
3199 $ try recurse1
3212 $ try recurse1
3200 ('symbol', 'recurse1')
3213 ('symbol', 'recurse1')
3201 hg: parse error: infinite expansion of revset alias "recurse1" detected
3214 hg: parse error: infinite expansion of revset alias "recurse1" detected
3202 [255]
3215 [255]
3203
3216
3204 $ echo 'level1($1, $2) = $1 or $2' >> .hg/hgrc
3217 $ echo 'level1($1, $2) = $1 or $2' >> .hg/hgrc
3205 $ echo 'level2($1, $2) = level1($2, $1)' >> .hg/hgrc
3218 $ echo 'level2($1, $2) = level1($2, $1)' >> .hg/hgrc
3206 $ try "level2(level1(1, 2), 3)"
3219 $ try "level2(level1(1, 2), 3)"
3207 (func
3220 (func
3208 ('symbol', 'level2')
3221 ('symbol', 'level2')
3209 (list
3222 (list
3210 (func
3223 (func
3211 ('symbol', 'level1')
3224 ('symbol', 'level1')
3212 (list
3225 (list
3213 ('symbol', '1')
3226 ('symbol', '1')
3214 ('symbol', '2')))
3227 ('symbol', '2')))
3215 ('symbol', '3')))
3228 ('symbol', '3')))
3216 * expanded:
3229 * expanded:
3217 (or
3230 (or
3218 (list
3231 (list
3219 ('symbol', '3')
3232 ('symbol', '3')
3220 (or
3233 (or
3221 (list
3234 (list
3222 ('symbol', '1')
3235 ('symbol', '1')
3223 ('symbol', '2')))))
3236 ('symbol', '2')))))
3224 * set:
3237 * set:
3225 <addset
3238 <addset
3226 <baseset [3]>,
3239 <baseset [3]>,
3227 <baseset [1, 2]>>
3240 <baseset [1, 2]>>
3228 3
3241 3
3229 1
3242 1
3230 2
3243 2
3231
3244
3232 test nesting and variable passing
3245 test nesting and variable passing
3233
3246
3234 $ echo 'nested($1) = nested2($1)' >> .hg/hgrc
3247 $ echo 'nested($1) = nested2($1)' >> .hg/hgrc
3235 $ echo 'nested2($1) = nested3($1)' >> .hg/hgrc
3248 $ echo 'nested2($1) = nested3($1)' >> .hg/hgrc
3236 $ echo 'nested3($1) = max($1)' >> .hg/hgrc
3249 $ echo 'nested3($1) = max($1)' >> .hg/hgrc
3237 $ try 'nested(2:5)'
3250 $ try 'nested(2:5)'
3238 (func
3251 (func
3239 ('symbol', 'nested')
3252 ('symbol', 'nested')
3240 (range
3253 (range
3241 ('symbol', '2')
3254 ('symbol', '2')
3242 ('symbol', '5')))
3255 ('symbol', '5')))
3243 * expanded:
3256 * expanded:
3244 (func
3257 (func
3245 ('symbol', 'max')
3258 ('symbol', 'max')
3246 (range
3259 (range
3247 ('symbol', '2')
3260 ('symbol', '2')
3248 ('symbol', '5')))
3261 ('symbol', '5')))
3249 * set:
3262 * set:
3250 <baseset
3263 <baseset
3251 <max
3264 <max
3252 <fullreposet+ 0:9>,
3265 <fullreposet+ 0:9>,
3253 <spanset+ 2:5>>>
3266 <spanset+ 2:5>>>
3254 5
3267 5
3255
3268
3256 test chained `or` operations are flattened at parsing phase
3269 test chained `or` operations are flattened at parsing phase
3257
3270
3258 $ echo 'chainedorops($1, $2, $3) = $1|$2|$3' >> .hg/hgrc
3271 $ echo 'chainedorops($1, $2, $3) = $1|$2|$3' >> .hg/hgrc
3259 $ try 'chainedorops(0:1, 1:2, 2:3)'
3272 $ try 'chainedorops(0:1, 1:2, 2:3)'
3260 (func
3273 (func
3261 ('symbol', 'chainedorops')
3274 ('symbol', 'chainedorops')
3262 (list
3275 (list
3263 (range
3276 (range
3264 ('symbol', '0')
3277 ('symbol', '0')
3265 ('symbol', '1'))
3278 ('symbol', '1'))
3266 (range
3279 (range
3267 ('symbol', '1')
3280 ('symbol', '1')
3268 ('symbol', '2'))
3281 ('symbol', '2'))
3269 (range
3282 (range
3270 ('symbol', '2')
3283 ('symbol', '2')
3271 ('symbol', '3'))))
3284 ('symbol', '3'))))
3272 * expanded:
3285 * expanded:
3273 (or
3286 (or
3274 (list
3287 (list
3275 (range
3288 (range
3276 ('symbol', '0')
3289 ('symbol', '0')
3277 ('symbol', '1'))
3290 ('symbol', '1'))
3278 (range
3291 (range
3279 ('symbol', '1')
3292 ('symbol', '1')
3280 ('symbol', '2'))
3293 ('symbol', '2'))
3281 (range
3294 (range
3282 ('symbol', '2')
3295 ('symbol', '2')
3283 ('symbol', '3'))))
3296 ('symbol', '3'))))
3284 * set:
3297 * set:
3285 <addset
3298 <addset
3286 <spanset+ 0:1>,
3299 <spanset+ 0:1>,
3287 <addset
3300 <addset
3288 <spanset+ 1:2>,
3301 <spanset+ 1:2>,
3289 <spanset+ 2:3>>>
3302 <spanset+ 2:3>>>
3290 0
3303 0
3291 1
3304 1
3292 2
3305 2
3293 3
3306 3
3294
3307
3295 test variable isolation, variable placeholders are rewritten as string
3308 test variable isolation, variable placeholders are rewritten as string
3296 then parsed and matched again as string. Check they do not leak too
3309 then parsed and matched again as string. Check they do not leak too
3297 far away.
3310 far away.
3298
3311
3299 $ echo 'injectparamasstring = max("$1")' >> .hg/hgrc
3312 $ echo 'injectparamasstring = max("$1")' >> .hg/hgrc
3300 $ echo 'callinjection($1) = descendants(injectparamasstring)' >> .hg/hgrc
3313 $ echo 'callinjection($1) = descendants(injectparamasstring)' >> .hg/hgrc
3301 $ try 'callinjection(2:5)'
3314 $ try 'callinjection(2:5)'
3302 (func
3315 (func
3303 ('symbol', 'callinjection')
3316 ('symbol', 'callinjection')
3304 (range
3317 (range
3305 ('symbol', '2')
3318 ('symbol', '2')
3306 ('symbol', '5')))
3319 ('symbol', '5')))
3307 * expanded:
3320 * expanded:
3308 (func
3321 (func
3309 ('symbol', 'descendants')
3322 ('symbol', 'descendants')
3310 (func
3323 (func
3311 ('symbol', 'max')
3324 ('symbol', 'max')
3312 ('string', '$1')))
3325 ('string', '$1')))
3313 abort: unknown revision '$1'!
3326 abort: unknown revision '$1'!
3314 [255]
3327 [255]
3315
3328
3316 test scope of alias expansion: 'universe' is expanded prior to 'shadowall(0)',
3329 test scope of alias expansion: 'universe' is expanded prior to 'shadowall(0)',
3317 but 'all()' should never be substituted to '0()'.
3330 but 'all()' should never be substituted to '0()'.
3318
3331
3319 $ echo 'universe = all()' >> .hg/hgrc
3332 $ echo 'universe = all()' >> .hg/hgrc
3320 $ echo 'shadowall(all) = all and universe' >> .hg/hgrc
3333 $ echo 'shadowall(all) = all and universe' >> .hg/hgrc
3321 $ try 'shadowall(0)'
3334 $ try 'shadowall(0)'
3322 (func
3335 (func
3323 ('symbol', 'shadowall')
3336 ('symbol', 'shadowall')
3324 ('symbol', '0'))
3337 ('symbol', '0'))
3325 * expanded:
3338 * expanded:
3326 (and
3339 (and
3327 ('symbol', '0')
3340 ('symbol', '0')
3328 (func
3341 (func
3329 ('symbol', 'all')
3342 ('symbol', 'all')
3330 None))
3343 None))
3331 * set:
3344 * set:
3332 <filteredset
3345 <filteredset
3333 <baseset [0]>,
3346 <baseset [0]>,
3334 <spanset+ 0:9>>
3347 <spanset+ 0:9>>
3335 0
3348 0
3336
3349
3337 test unknown reference:
3350 test unknown reference:
3338
3351
3339 $ try "unknownref(0)" --config 'revsetalias.unknownref($1)=$1:$2'
3352 $ try "unknownref(0)" --config 'revsetalias.unknownref($1)=$1:$2'
3340 (func
3353 (func
3341 ('symbol', 'unknownref')
3354 ('symbol', 'unknownref')
3342 ('symbol', '0'))
3355 ('symbol', '0'))
3343 abort: bad definition of revset alias "unknownref": invalid symbol '$2'
3356 abort: bad definition of revset alias "unknownref": invalid symbol '$2'
3344 [255]
3357 [255]
3345
3358
3346 $ hg debugrevspec --debug --config revsetalias.anotherbadone='branch(' "tip"
3359 $ hg debugrevspec --debug --config revsetalias.anotherbadone='branch(' "tip"
3347 ('symbol', 'tip')
3360 ('symbol', 'tip')
3348 warning: bad definition of revset alias "anotherbadone": at 7: not a prefix: end
3361 warning: bad definition of revset alias "anotherbadone": at 7: not a prefix: end
3349 * set:
3362 * set:
3350 <baseset [9]>
3363 <baseset [9]>
3351 9
3364 9
3352
3365
3353 $ try 'tip'
3366 $ try 'tip'
3354 ('symbol', 'tip')
3367 ('symbol', 'tip')
3355 * set:
3368 * set:
3356 <baseset [9]>
3369 <baseset [9]>
3357 9
3370 9
3358
3371
3359 $ hg debugrevspec --debug --config revsetalias.'bad name'='tip' "tip"
3372 $ hg debugrevspec --debug --config revsetalias.'bad name'='tip' "tip"
3360 ('symbol', 'tip')
3373 ('symbol', 'tip')
3361 warning: bad declaration of revset alias "bad name": at 4: invalid token
3374 warning: bad declaration of revset alias "bad name": at 4: invalid token
3362 * set:
3375 * set:
3363 <baseset [9]>
3376 <baseset [9]>
3364 9
3377 9
3365 $ echo 'strictreplacing($1, $10) = $10 or desc("$1")' >> .hg/hgrc
3378 $ echo 'strictreplacing($1, $10) = $10 or desc("$1")' >> .hg/hgrc
3366 $ try 'strictreplacing("foo", tip)'
3379 $ try 'strictreplacing("foo", tip)'
3367 (func
3380 (func
3368 ('symbol', 'strictreplacing')
3381 ('symbol', 'strictreplacing')
3369 (list
3382 (list
3370 ('string', 'foo')
3383 ('string', 'foo')
3371 ('symbol', 'tip')))
3384 ('symbol', 'tip')))
3372 * expanded:
3385 * expanded:
3373 (or
3386 (or
3374 (list
3387 (list
3375 ('symbol', 'tip')
3388 ('symbol', 'tip')
3376 (func
3389 (func
3377 ('symbol', 'desc')
3390 ('symbol', 'desc')
3378 ('string', '$1'))))
3391 ('string', '$1'))))
3379 * set:
3392 * set:
3380 <addset
3393 <addset
3381 <baseset [9]>,
3394 <baseset [9]>,
3382 <filteredset
3395 <filteredset
3383 <fullreposet+ 0:9>,
3396 <fullreposet+ 0:9>,
3384 <desc '$1'>>>
3397 <desc '$1'>>>
3385 9
3398 9
3386
3399
3387 $ try 'd(2:5)'
3400 $ try 'd(2:5)'
3388 (func
3401 (func
3389 ('symbol', 'd')
3402 ('symbol', 'd')
3390 (range
3403 (range
3391 ('symbol', '2')
3404 ('symbol', '2')
3392 ('symbol', '5')))
3405 ('symbol', '5')))
3393 * expanded:
3406 * expanded:
3394 (func
3407 (func
3395 ('symbol', 'reverse')
3408 ('symbol', 'reverse')
3396 (func
3409 (func
3397 ('symbol', 'sort')
3410 ('symbol', 'sort')
3398 (list
3411 (list
3399 (range
3412 (range
3400 ('symbol', '2')
3413 ('symbol', '2')
3401 ('symbol', '5'))
3414 ('symbol', '5'))
3402 ('symbol', 'date'))))
3415 ('symbol', 'date'))))
3403 * set:
3416 * set:
3404 <baseset [4, 5, 3, 2]>
3417 <baseset [4, 5, 3, 2]>
3405 4
3418 4
3406 5
3419 5
3407 3
3420 3
3408 2
3421 2
3409 $ try 'rs(2 or 3, date)'
3422 $ try 'rs(2 or 3, date)'
3410 (func
3423 (func
3411 ('symbol', 'rs')
3424 ('symbol', 'rs')
3412 (list
3425 (list
3413 (or
3426 (or
3414 (list
3427 (list
3415 ('symbol', '2')
3428 ('symbol', '2')
3416 ('symbol', '3')))
3429 ('symbol', '3')))
3417 ('symbol', 'date')))
3430 ('symbol', 'date')))
3418 * expanded:
3431 * expanded:
3419 (func
3432 (func
3420 ('symbol', 'reverse')
3433 ('symbol', 'reverse')
3421 (func
3434 (func
3422 ('symbol', 'sort')
3435 ('symbol', 'sort')
3423 (list
3436 (list
3424 (or
3437 (or
3425 (list
3438 (list
3426 ('symbol', '2')
3439 ('symbol', '2')
3427 ('symbol', '3')))
3440 ('symbol', '3')))
3428 ('symbol', 'date'))))
3441 ('symbol', 'date'))))
3429 * set:
3442 * set:
3430 <baseset [3, 2]>
3443 <baseset [3, 2]>
3431 3
3444 3
3432 2
3445 2
3433 $ try 'rs()'
3446 $ try 'rs()'
3434 (func
3447 (func
3435 ('symbol', 'rs')
3448 ('symbol', 'rs')
3436 None)
3449 None)
3437 hg: parse error: invalid number of arguments: 0
3450 hg: parse error: invalid number of arguments: 0
3438 [255]
3451 [255]
3439 $ try 'rs(2)'
3452 $ try 'rs(2)'
3440 (func
3453 (func
3441 ('symbol', 'rs')
3454 ('symbol', 'rs')
3442 ('symbol', '2'))
3455 ('symbol', '2'))
3443 hg: parse error: invalid number of arguments: 1
3456 hg: parse error: invalid number of arguments: 1
3444 [255]
3457 [255]
3445 $ try 'rs(2, data, 7)'
3458 $ try 'rs(2, data, 7)'
3446 (func
3459 (func
3447 ('symbol', 'rs')
3460 ('symbol', 'rs')
3448 (list
3461 (list
3449 ('symbol', '2')
3462 ('symbol', '2')
3450 ('symbol', 'data')
3463 ('symbol', 'data')
3451 ('symbol', '7')))
3464 ('symbol', '7')))
3452 hg: parse error: invalid number of arguments: 3
3465 hg: parse error: invalid number of arguments: 3
3453 [255]
3466 [255]
3454 $ try 'rs4(2 or 3, x, x, date)'
3467 $ try 'rs4(2 or 3, x, x, date)'
3455 (func
3468 (func
3456 ('symbol', 'rs4')
3469 ('symbol', 'rs4')
3457 (list
3470 (list
3458 (or
3471 (or
3459 (list
3472 (list
3460 ('symbol', '2')
3473 ('symbol', '2')
3461 ('symbol', '3')))
3474 ('symbol', '3')))
3462 ('symbol', 'x')
3475 ('symbol', 'x')
3463 ('symbol', 'x')
3476 ('symbol', 'x')
3464 ('symbol', 'date')))
3477 ('symbol', 'date')))
3465 * expanded:
3478 * expanded:
3466 (func
3479 (func
3467 ('symbol', 'reverse')
3480 ('symbol', 'reverse')
3468 (func
3481 (func
3469 ('symbol', 'sort')
3482 ('symbol', 'sort')
3470 (list
3483 (list
3471 (or
3484 (or
3472 (list
3485 (list
3473 ('symbol', '2')
3486 ('symbol', '2')
3474 ('symbol', '3')))
3487 ('symbol', '3')))
3475 ('symbol', 'date'))))
3488 ('symbol', 'date'))))
3476 * set:
3489 * set:
3477 <baseset [3, 2]>
3490 <baseset [3, 2]>
3478 3
3491 3
3479 2
3492 2
3480
3493
3481 issue4553: check that revset aliases override existing hash prefix
3494 issue4553: check that revset aliases override existing hash prefix
3482
3495
3483 $ hg log -qr e
3496 $ hg log -qr e
3484 6:e0cc66ef77e8
3497 6:e0cc66ef77e8
3485
3498
3486 $ hg log -qr e --config revsetalias.e="all()"
3499 $ hg log -qr e --config revsetalias.e="all()"
3487 0:2785f51eece5
3500 0:2785f51eece5
3488 1:d75937da8da0
3501 1:d75937da8da0
3489 2:5ed5505e9f1c
3502 2:5ed5505e9f1c
3490 3:8528aa5637f2
3503 3:8528aa5637f2
3491 4:2326846efdab
3504 4:2326846efdab
3492 5:904fa392b941
3505 5:904fa392b941
3493 6:e0cc66ef77e8
3506 6:e0cc66ef77e8
3494 7:013af1973af4
3507 7:013af1973af4
3495 8:d5d0dcbdc4d9
3508 8:d5d0dcbdc4d9
3496 9:24286f4ae135
3509 9:24286f4ae135
3497
3510
3498 $ hg log -qr e: --config revsetalias.e="0"
3511 $ hg log -qr e: --config revsetalias.e="0"
3499 0:2785f51eece5
3512 0:2785f51eece5
3500 1:d75937da8da0
3513 1:d75937da8da0
3501 2:5ed5505e9f1c
3514 2:5ed5505e9f1c
3502 3:8528aa5637f2
3515 3:8528aa5637f2
3503 4:2326846efdab
3516 4:2326846efdab
3504 5:904fa392b941
3517 5:904fa392b941
3505 6:e0cc66ef77e8
3518 6:e0cc66ef77e8
3506 7:013af1973af4
3519 7:013af1973af4
3507 8:d5d0dcbdc4d9
3520 8:d5d0dcbdc4d9
3508 9:24286f4ae135
3521 9:24286f4ae135
3509
3522
3510 $ hg log -qr :e --config revsetalias.e="9"
3523 $ hg log -qr :e --config revsetalias.e="9"
3511 0:2785f51eece5
3524 0:2785f51eece5
3512 1:d75937da8da0
3525 1:d75937da8da0
3513 2:5ed5505e9f1c
3526 2:5ed5505e9f1c
3514 3:8528aa5637f2
3527 3:8528aa5637f2
3515 4:2326846efdab
3528 4:2326846efdab
3516 5:904fa392b941
3529 5:904fa392b941
3517 6:e0cc66ef77e8
3530 6:e0cc66ef77e8
3518 7:013af1973af4
3531 7:013af1973af4
3519 8:d5d0dcbdc4d9
3532 8:d5d0dcbdc4d9
3520 9:24286f4ae135
3533 9:24286f4ae135
3521
3534
3522 $ hg log -qr e:
3535 $ hg log -qr e:
3523 6:e0cc66ef77e8
3536 6:e0cc66ef77e8
3524 7:013af1973af4
3537 7:013af1973af4
3525 8:d5d0dcbdc4d9
3538 8:d5d0dcbdc4d9
3526 9:24286f4ae135
3539 9:24286f4ae135
3527
3540
3528 $ hg log -qr :e
3541 $ hg log -qr :e
3529 0:2785f51eece5
3542 0:2785f51eece5
3530 1:d75937da8da0
3543 1:d75937da8da0
3531 2:5ed5505e9f1c
3544 2:5ed5505e9f1c
3532 3:8528aa5637f2
3545 3:8528aa5637f2
3533 4:2326846efdab
3546 4:2326846efdab
3534 5:904fa392b941
3547 5:904fa392b941
3535 6:e0cc66ef77e8
3548 6:e0cc66ef77e8
3536
3549
3537 issue2549 - correct optimizations
3550 issue2549 - correct optimizations
3538
3551
3539 $ try 'limit(1 or 2 or 3, 2) and not 2'
3552 $ try 'limit(1 or 2 or 3, 2) and not 2'
3540 (and
3553 (and
3541 (func
3554 (func
3542 ('symbol', 'limit')
3555 ('symbol', 'limit')
3543 (list
3556 (list
3544 (or
3557 (or
3545 (list
3558 (list
3546 ('symbol', '1')
3559 ('symbol', '1')
3547 ('symbol', '2')
3560 ('symbol', '2')
3548 ('symbol', '3')))
3561 ('symbol', '3')))
3549 ('symbol', '2')))
3562 ('symbol', '2')))
3550 (not
3563 (not
3551 ('symbol', '2')))
3564 ('symbol', '2')))
3552 * set:
3565 * set:
3553 <filteredset
3566 <filteredset
3554 <baseset
3567 <baseset
3555 <limit n=2, offset=0,
3568 <limit n=2, offset=0,
3556 <fullreposet+ 0:9>,
3569 <fullreposet+ 0:9>,
3557 <baseset [1, 2, 3]>>>,
3570 <baseset [1, 2, 3]>>>,
3558 <not
3571 <not
3559 <baseset [2]>>>
3572 <baseset [2]>>>
3560 1
3573 1
3561 $ try 'max(1 or 2) and not 2'
3574 $ try 'max(1 or 2) and not 2'
3562 (and
3575 (and
3563 (func
3576 (func
3564 ('symbol', 'max')
3577 ('symbol', 'max')
3565 (or
3578 (or
3566 (list
3579 (list
3567 ('symbol', '1')
3580 ('symbol', '1')
3568 ('symbol', '2'))))
3581 ('symbol', '2'))))
3569 (not
3582 (not
3570 ('symbol', '2')))
3583 ('symbol', '2')))
3571 * set:
3584 * set:
3572 <filteredset
3585 <filteredset
3573 <baseset
3586 <baseset
3574 <max
3587 <max
3575 <fullreposet+ 0:9>,
3588 <fullreposet+ 0:9>,
3576 <baseset [1, 2]>>>,
3589 <baseset [1, 2]>>>,
3577 <not
3590 <not
3578 <baseset [2]>>>
3591 <baseset [2]>>>
3579 $ try 'min(1 or 2) and not 1'
3592 $ try 'min(1 or 2) and not 1'
3580 (and
3593 (and
3581 (func
3594 (func
3582 ('symbol', 'min')
3595 ('symbol', 'min')
3583 (or
3596 (or
3584 (list
3597 (list
3585 ('symbol', '1')
3598 ('symbol', '1')
3586 ('symbol', '2'))))
3599 ('symbol', '2'))))
3587 (not
3600 (not
3588 ('symbol', '1')))
3601 ('symbol', '1')))
3589 * set:
3602 * set:
3590 <filteredset
3603 <filteredset
3591 <baseset
3604 <baseset
3592 <min
3605 <min
3593 <fullreposet+ 0:9>,
3606 <fullreposet+ 0:9>,
3594 <baseset [1, 2]>>>,
3607 <baseset [1, 2]>>>,
3595 <not
3608 <not
3596 <baseset [1]>>>
3609 <baseset [1]>>>
3597 $ try 'last(1 or 2, 1) and not 2'
3610 $ try 'last(1 or 2, 1) and not 2'
3598 (and
3611 (and
3599 (func
3612 (func
3600 ('symbol', 'last')
3613 ('symbol', 'last')
3601 (list
3614 (list
3602 (or
3615 (or
3603 (list
3616 (list
3604 ('symbol', '1')
3617 ('symbol', '1')
3605 ('symbol', '2')))
3618 ('symbol', '2')))
3606 ('symbol', '1')))
3619 ('symbol', '1')))
3607 (not
3620 (not
3608 ('symbol', '2')))
3621 ('symbol', '2')))
3609 * set:
3622 * set:
3610 <filteredset
3623 <filteredset
3611 <baseset
3624 <baseset
3612 <last n=1,
3625 <last n=1,
3613 <fullreposet+ 0:9>,
3626 <fullreposet+ 0:9>,
3614 <baseset [2, 1]>>>,
3627 <baseset [2, 1]>>>,
3615 <not
3628 <not
3616 <baseset [2]>>>
3629 <baseset [2]>>>
3617
3630
3618 issue4289 - ordering of built-ins
3631 issue4289 - ordering of built-ins
3619 $ hg log -M -q -r 3:2
3632 $ hg log -M -q -r 3:2
3620 3:8528aa5637f2
3633 3:8528aa5637f2
3621 2:5ed5505e9f1c
3634 2:5ed5505e9f1c
3622
3635
3623 test revsets started with 40-chars hash (issue3669)
3636 test revsets started with 40-chars hash (issue3669)
3624
3637
3625 $ ISSUE3669_TIP=`hg tip --template '{node}'`
3638 $ ISSUE3669_TIP=`hg tip --template '{node}'`
3626 $ hg log -r "${ISSUE3669_TIP}" --template '{rev}\n'
3639 $ hg log -r "${ISSUE3669_TIP}" --template '{rev}\n'
3627 9
3640 9
3628 $ hg log -r "${ISSUE3669_TIP}^" --template '{rev}\n'
3641 $ hg log -r "${ISSUE3669_TIP}^" --template '{rev}\n'
3629 8
3642 8
3630
3643
3631 test or-ed indirect predicates (issue3775)
3644 test or-ed indirect predicates (issue3775)
3632
3645
3633 $ log '6 or 6^1' | sort
3646 $ log '6 or 6^1' | sort
3634 5
3647 5
3635 6
3648 6
3636 $ log '6^1 or 6' | sort
3649 $ log '6^1 or 6' | sort
3637 5
3650 5
3638 6
3651 6
3639 $ log '4 or 4~1' | sort
3652 $ log '4 or 4~1' | sort
3640 2
3653 2
3641 4
3654 4
3642 $ log '4~1 or 4' | sort
3655 $ log '4~1 or 4' | sort
3643 2
3656 2
3644 4
3657 4
3645 $ log '(0 or 2):(4 or 6) or 0 or 6' | sort
3658 $ log '(0 or 2):(4 or 6) or 0 or 6' | sort
3646 0
3659 0
3647 1
3660 1
3648 2
3661 2
3649 3
3662 3
3650 4
3663 4
3651 5
3664 5
3652 6
3665 6
3653 $ log '0 or 6 or (0 or 2):(4 or 6)' | sort
3666 $ log '0 or 6 or (0 or 2):(4 or 6)' | sort
3654 0
3667 0
3655 1
3668 1
3656 2
3669 2
3657 3
3670 3
3658 4
3671 4
3659 5
3672 5
3660 6
3673 6
3661
3674
3662 tests for 'remote()' predicate:
3675 tests for 'remote()' predicate:
3663 #. (csets in remote) (id) (remote)
3676 #. (csets in remote) (id) (remote)
3664 1. less than local current branch "default"
3677 1. less than local current branch "default"
3665 2. same with local specified "default"
3678 2. same with local specified "default"
3666 3. more than local specified specified
3679 3. more than local specified specified
3667
3680
3668 $ hg clone --quiet -U . ../remote3
3681 $ hg clone --quiet -U . ../remote3
3669 $ cd ../remote3
3682 $ cd ../remote3
3670 $ hg update -q 7
3683 $ hg update -q 7
3671 $ echo r > r
3684 $ echo r > r
3672 $ hg ci -Aqm 10
3685 $ hg ci -Aqm 10
3673 $ log 'remote()'
3686 $ log 'remote()'
3674 7
3687 7
3675 $ log 'remote("a-b-c-")'
3688 $ log 'remote("a-b-c-")'
3676 2
3689 2
3677 $ cd ../repo
3690 $ cd ../repo
3678 $ log 'remote(".a.b.c.", "../remote3")'
3691 $ log 'remote(".a.b.c.", "../remote3")'
3679
3692
3680 tests for concatenation of strings/symbols by "##"
3693 tests for concatenation of strings/symbols by "##"
3681
3694
3682 $ try "278 ## '5f5' ## 1ee ## 'ce5'"
3695 $ try "278 ## '5f5' ## 1ee ## 'ce5'"
3683 (_concat
3696 (_concat
3684 (_concat
3697 (_concat
3685 (_concat
3698 (_concat
3686 ('symbol', '278')
3699 ('symbol', '278')
3687 ('string', '5f5'))
3700 ('string', '5f5'))
3688 ('symbol', '1ee'))
3701 ('symbol', '1ee'))
3689 ('string', 'ce5'))
3702 ('string', 'ce5'))
3690 * concatenated:
3703 * concatenated:
3691 ('string', '2785f51eece5')
3704 ('string', '2785f51eece5')
3692 * set:
3705 * set:
3693 <baseset [0]>
3706 <baseset [0]>
3694 0
3707 0
3695
3708
3696 $ echo 'cat4($1, $2, $3, $4) = $1 ## $2 ## $3 ## $4' >> .hg/hgrc
3709 $ echo 'cat4($1, $2, $3, $4) = $1 ## $2 ## $3 ## $4' >> .hg/hgrc
3697 $ try "cat4(278, '5f5', 1ee, 'ce5')"
3710 $ try "cat4(278, '5f5', 1ee, 'ce5')"
3698 (func
3711 (func
3699 ('symbol', 'cat4')
3712 ('symbol', 'cat4')
3700 (list
3713 (list
3701 ('symbol', '278')
3714 ('symbol', '278')
3702 ('string', '5f5')
3715 ('string', '5f5')
3703 ('symbol', '1ee')
3716 ('symbol', '1ee')
3704 ('string', 'ce5')))
3717 ('string', 'ce5')))
3705 * expanded:
3718 * expanded:
3706 (_concat
3719 (_concat
3707 (_concat
3720 (_concat
3708 (_concat
3721 (_concat
3709 ('symbol', '278')
3722 ('symbol', '278')
3710 ('string', '5f5'))
3723 ('string', '5f5'))
3711 ('symbol', '1ee'))
3724 ('symbol', '1ee'))
3712 ('string', 'ce5'))
3725 ('string', 'ce5'))
3713 * concatenated:
3726 * concatenated:
3714 ('string', '2785f51eece5')
3727 ('string', '2785f51eece5')
3715 * set:
3728 * set:
3716 <baseset [0]>
3729 <baseset [0]>
3717 0
3730 0
3718
3731
3719 (check concatenation in alias nesting)
3732 (check concatenation in alias nesting)
3720
3733
3721 $ echo 'cat2($1, $2) = $1 ## $2' >> .hg/hgrc
3734 $ echo 'cat2($1, $2) = $1 ## $2' >> .hg/hgrc
3722 $ echo 'cat2x2($1, $2, $3, $4) = cat2($1 ## $2, $3 ## $4)' >> .hg/hgrc
3735 $ echo 'cat2x2($1, $2, $3, $4) = cat2($1 ## $2, $3 ## $4)' >> .hg/hgrc
3723 $ log "cat2x2(278, '5f5', 1ee, 'ce5')"
3736 $ log "cat2x2(278, '5f5', 1ee, 'ce5')"
3724 0
3737 0
3725
3738
3726 (check operator priority)
3739 (check operator priority)
3727
3740
3728 $ echo 'cat2n2($1, $2, $3, $4) = $1 ## $2 or $3 ## $4~2' >> .hg/hgrc
3741 $ echo 'cat2n2($1, $2, $3, $4) = $1 ## $2 or $3 ## $4~2' >> .hg/hgrc
3729 $ log "cat2n2(2785f5, 1eece5, 24286f, 4ae135)"
3742 $ log "cat2n2(2785f5, 1eece5, 24286f, 4ae135)"
3730 0
3743 0
3731 4
3744 4
3732
3745
3733 $ cd ..
3746 $ cd ..
3734
3747
3735 prepare repository that has "default" branches of multiple roots
3748 prepare repository that has "default" branches of multiple roots
3736
3749
3737 $ hg init namedbranch
3750 $ hg init namedbranch
3738 $ cd namedbranch
3751 $ cd namedbranch
3739
3752
3740 $ echo default0 >> a
3753 $ echo default0 >> a
3741 $ hg ci -Aqm0
3754 $ hg ci -Aqm0
3742 $ echo default1 >> a
3755 $ echo default1 >> a
3743 $ hg ci -m1
3756 $ hg ci -m1
3744
3757
3745 $ hg branch -q stable
3758 $ hg branch -q stable
3746 $ echo stable2 >> a
3759 $ echo stable2 >> a
3747 $ hg ci -m2
3760 $ hg ci -m2
3748 $ echo stable3 >> a
3761 $ echo stable3 >> a
3749 $ hg ci -m3
3762 $ hg ci -m3
3750
3763
3751 $ hg update -q null
3764 $ hg update -q null
3752 $ echo default4 >> a
3765 $ echo default4 >> a
3753 $ hg ci -Aqm4
3766 $ hg ci -Aqm4
3754 $ echo default5 >> a
3767 $ echo default5 >> a
3755 $ hg ci -m5
3768 $ hg ci -m5
3756
3769
3757 "null" revision belongs to "default" branch (issue4683)
3770 "null" revision belongs to "default" branch (issue4683)
3758
3771
3759 $ log 'branch(null)'
3772 $ log 'branch(null)'
3760 0
3773 0
3761 1
3774 1
3762 4
3775 4
3763 5
3776 5
3764
3777
3765 "null" revision belongs to "default" branch, but it shouldn't appear in set
3778 "null" revision belongs to "default" branch, but it shouldn't appear in set
3766 unless explicitly specified (issue4682)
3779 unless explicitly specified (issue4682)
3767
3780
3768 $ log 'children(branch(default))'
3781 $ log 'children(branch(default))'
3769 1
3782 1
3770 2
3783 2
3771 5
3784 5
3772
3785
3773 $ cd ..
3786 $ cd ..
3774
3787
3775 test author/desc/keyword in problematic encoding
3788 test author/desc/keyword in problematic encoding
3776 # unicode: cp932:
3789 # unicode: cp932:
3777 # u30A2 0x83 0x41(= 'A')
3790 # u30A2 0x83 0x41(= 'A')
3778 # u30C2 0x83 0x61(= 'a')
3791 # u30C2 0x83 0x61(= 'a')
3779
3792
3780 $ hg init problematicencoding
3793 $ hg init problematicencoding
3781 $ cd problematicencoding
3794 $ cd problematicencoding
3782
3795
3783 $ python > setup.sh <<EOF
3796 $ python > setup.sh <<EOF
3784 > print u'''
3797 > print u'''
3785 > echo a > text
3798 > echo a > text
3786 > hg add text
3799 > hg add text
3787 > hg --encoding utf-8 commit -u '\u30A2' -m none
3800 > hg --encoding utf-8 commit -u '\u30A2' -m none
3788 > echo b > text
3801 > echo b > text
3789 > hg --encoding utf-8 commit -u '\u30C2' -m none
3802 > hg --encoding utf-8 commit -u '\u30C2' -m none
3790 > echo c > text
3803 > echo c > text
3791 > hg --encoding utf-8 commit -u none -m '\u30A2'
3804 > hg --encoding utf-8 commit -u none -m '\u30A2'
3792 > echo d > text
3805 > echo d > text
3793 > hg --encoding utf-8 commit -u none -m '\u30C2'
3806 > hg --encoding utf-8 commit -u none -m '\u30C2'
3794 > '''.encode('utf-8')
3807 > '''.encode('utf-8')
3795 > EOF
3808 > EOF
3796 $ sh < setup.sh
3809 $ sh < setup.sh
3797
3810
3798 test in problematic encoding
3811 test in problematic encoding
3799 $ python > test.sh <<EOF
3812 $ python > test.sh <<EOF
3800 > print u'''
3813 > print u'''
3801 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30A2)'
3814 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30A2)'
3802 > echo ====
3815 > echo ====
3803 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30C2)'
3816 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30C2)'
3804 > echo ====
3817 > echo ====
3805 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30A2)'
3818 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30A2)'
3806 > echo ====
3819 > echo ====
3807 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30C2)'
3820 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30C2)'
3808 > echo ====
3821 > echo ====
3809 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30A2)'
3822 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30A2)'
3810 > echo ====
3823 > echo ====
3811 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30C2)'
3824 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30C2)'
3812 > '''.encode('cp932')
3825 > '''.encode('cp932')
3813 > EOF
3826 > EOF
3814 $ sh < test.sh
3827 $ sh < test.sh
3815 0
3828 0
3816 ====
3829 ====
3817 1
3830 1
3818 ====
3831 ====
3819 2
3832 2
3820 ====
3833 ====
3821 3
3834 3
3822 ====
3835 ====
3823 0
3836 0
3824 2
3837 2
3825 ====
3838 ====
3826 1
3839 1
3827 3
3840 3
3828
3841
3829 test error message of bad revset
3842 test error message of bad revset
3830 $ hg log -r 'foo\\'
3843 $ hg log -r 'foo\\'
3831 hg: parse error at 3: syntax error in revset 'foo\\'
3844 hg: parse error at 3: syntax error in revset 'foo\\'
3832 [255]
3845 [255]
3833
3846
3834 $ cd ..
3847 $ cd ..
3835
3848
3836 Test that revset predicate of extension isn't loaded at failure of
3849 Test that revset predicate of extension isn't loaded at failure of
3837 loading it
3850 loading it
3838
3851
3839 $ cd repo
3852 $ cd repo
3840
3853
3841 $ cat <<EOF > $TESTTMP/custompredicate.py
3854 $ cat <<EOF > $TESTTMP/custompredicate.py
3842 > from mercurial import error, registrar, revset
3855 > from mercurial import error, registrar, revset
3843 >
3856 >
3844 > revsetpredicate = registrar.revsetpredicate()
3857 > revsetpredicate = registrar.revsetpredicate()
3845 >
3858 >
3846 > @revsetpredicate('custom1()')
3859 > @revsetpredicate('custom1()')
3847 > def custom1(repo, subset, x):
3860 > def custom1(repo, subset, x):
3848 > return revset.baseset([1])
3861 > return revset.baseset([1])
3849 >
3862 >
3850 > raise error.Abort('intentional failure of loading extension')
3863 > raise error.Abort('intentional failure of loading extension')
3851 > EOF
3864 > EOF
3852 $ cat <<EOF > .hg/hgrc
3865 $ cat <<EOF > .hg/hgrc
3853 > [extensions]
3866 > [extensions]
3854 > custompredicate = $TESTTMP/custompredicate.py
3867 > custompredicate = $TESTTMP/custompredicate.py
3855 > EOF
3868 > EOF
3856
3869
3857 $ hg debugrevspec "custom1()"
3870 $ hg debugrevspec "custom1()"
3858 *** failed to import extension custompredicate from $TESTTMP/custompredicate.py: intentional failure of loading extension
3871 *** failed to import extension custompredicate from $TESTTMP/custompredicate.py: intentional failure of loading extension
3859 hg: parse error: unknown identifier: custom1
3872 hg: parse error: unknown identifier: custom1
3860 [255]
3873 [255]
3861
3874
3862 $ cd ..
3875 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now