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