##// END OF EJS Templates
revset: add support for "wdir()^n"...
Pulkit Goyal -
r32436:f064e2f7 default
parent child Browse files
Show More
@@ -1,2296 +1,2304 b''
1 # revset.py - revision set queries for mercurial
1 # revset.py - revision set queries for mercurial
2 #
2 #
3 # Copyright 2010 Matt Mackall <mpm@selenic.com>
3 # Copyright 2010 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import heapq
10 import heapq
11 import re
11 import re
12
12
13 from .i18n import _
13 from .i18n import _
14 from . import (
14 from . import (
15 destutil,
15 destutil,
16 encoding,
16 encoding,
17 error,
17 error,
18 hbisect,
18 hbisect,
19 match as matchmod,
19 match as matchmod,
20 node,
20 node,
21 obsolete as obsmod,
21 obsolete as obsmod,
22 pathutil,
22 pathutil,
23 phases,
23 phases,
24 registrar,
24 registrar,
25 repoview,
25 repoview,
26 revsetlang,
26 revsetlang,
27 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 ps.add(cl.parentrevs(r)[1])
1438 ps -= {node.nullrev}
1438 ps -= {node.nullrev}
1439 # XXX we should turn this into a baseset instead of a set, smartset may do
1439 # 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.
1440 # some optimizations from the fact this is a baseset.
1441 return subset & ps
1441 return subset & ps
1442
1442
1443 def parentpost(repo, subset, x, order):
1443 def parentpost(repo, subset, x, order):
1444 return p1(repo, subset, x)
1444 return p1(repo, subset, x)
1445
1445
1446 @predicate('parents([set])', safe=True)
1446 @predicate('parents([set])', safe=True)
1447 def parents(repo, subset, x):
1447 def parents(repo, subset, x):
1448 """
1448 """
1449 The set of all parents for all changesets in set, or the working directory.
1449 The set of all parents for all changesets in set, or the working directory.
1450 """
1450 """
1451 if x is None:
1451 if x is None:
1452 ps = set(p.rev() for p in repo[x].parents())
1452 ps = set(p.rev() for p in repo[x].parents())
1453 else:
1453 else:
1454 ps = set()
1454 ps = set()
1455 cl = repo.changelog
1455 cl = repo.changelog
1456 up = ps.update
1456 up = ps.update
1457 parentrevs = cl.parentrevs
1457 parentrevs = cl.parentrevs
1458 for r in getset(repo, fullreposet(repo), x):
1458 for r in getset(repo, fullreposet(repo), x):
1459 if r == node.wdirrev:
1459 if r == node.wdirrev:
1460 up(p.rev() for p in repo[r].parents())
1460 up(p.rev() for p in repo[r].parents())
1461 else:
1461 else:
1462 up(parentrevs(r))
1462 up(parentrevs(r))
1463 ps -= {node.nullrev}
1463 ps -= {node.nullrev}
1464 return subset & ps
1464 return subset & ps
1465
1465
1466 def _phase(repo, subset, *targets):
1466 def _phase(repo, subset, *targets):
1467 """helper to select all rev in <targets> phases"""
1467 """helper to select all rev in <targets> phases"""
1468 s = repo._phasecache.getrevset(repo, targets)
1468 s = repo._phasecache.getrevset(repo, targets)
1469 return subset & s
1469 return subset & s
1470
1470
1471 @predicate('draft()', safe=True)
1471 @predicate('draft()', safe=True)
1472 def draft(repo, subset, x):
1472 def draft(repo, subset, x):
1473 """Changeset in draft phase."""
1473 """Changeset in draft phase."""
1474 # i18n: "draft" is a keyword
1474 # i18n: "draft" is a keyword
1475 getargs(x, 0, 0, _("draft takes no arguments"))
1475 getargs(x, 0, 0, _("draft takes no arguments"))
1476 target = phases.draft
1476 target = phases.draft
1477 return _phase(repo, subset, target)
1477 return _phase(repo, subset, target)
1478
1478
1479 @predicate('secret()', safe=True)
1479 @predicate('secret()', safe=True)
1480 def secret(repo, subset, x):
1480 def secret(repo, subset, x):
1481 """Changeset in secret phase."""
1481 """Changeset in secret phase."""
1482 # i18n: "secret" is a keyword
1482 # i18n: "secret" is a keyword
1483 getargs(x, 0, 0, _("secret takes no arguments"))
1483 getargs(x, 0, 0, _("secret takes no arguments"))
1484 target = phases.secret
1484 target = phases.secret
1485 return _phase(repo, subset, target)
1485 return _phase(repo, subset, target)
1486
1486
1487 def parentspec(repo, subset, x, n, order):
1487 def parentspec(repo, subset, x, n, order):
1488 """``set^0``
1488 """``set^0``
1489 The set.
1489 The set.
1490 ``set^1`` (or ``set^``), ``set^2``
1490 ``set^1`` (or ``set^``), ``set^2``
1491 First or second parent, respectively, of all changesets in set.
1491 First or second parent, respectively, of all changesets in set.
1492 """
1492 """
1493 try:
1493 try:
1494 n = int(n[1])
1494 n = int(n[1])
1495 if n not in (0, 1, 2):
1495 if n not in (0, 1, 2):
1496 raise ValueError
1496 raise ValueError
1497 except (TypeError, ValueError):
1497 except (TypeError, ValueError):
1498 raise error.ParseError(_("^ expects a number 0, 1, or 2"))
1498 raise error.ParseError(_("^ expects a number 0, 1, or 2"))
1499 ps = set()
1499 ps = set()
1500 cl = repo.changelog
1500 cl = repo.changelog
1501 for r in getset(repo, fullreposet(repo), x):
1501 for r in getset(repo, fullreposet(repo), x):
1502 if n == 0:
1502 if n == 0:
1503 ps.add(r)
1503 ps.add(r)
1504 elif n == 1:
1504 elif n == 1:
1505 ps.add(cl.parentrevs(r)[0])
1505 try:
1506 ps.add(cl.parentrevs(r)[0])
1507 except error.WdirUnsupported:
1508 ps.add(repo[r].parents()[0].rev())
1506 elif n == 2:
1509 elif n == 2:
1507 parents = cl.parentrevs(r)
1510 try:
1508 if parents[1] != node.nullrev:
1511 parents = cl.parentrevs(r)
1509 ps.add(parents[1])
1512 if parents[1] != node.nullrev:
1513 ps.add(parents[1])
1514 except error.WdirUnsupported:
1515 parents = repo[r].parents()
1516 if len(parents) == 2:
1517 ps.add(parents[1].rev())
1510 return subset & ps
1518 return subset & ps
1511
1519
1512 @predicate('present(set)', safe=True)
1520 @predicate('present(set)', safe=True)
1513 def present(repo, subset, x):
1521 def present(repo, subset, x):
1514 """An empty set, if any revision in set isn't found; otherwise,
1522 """An empty set, if any revision in set isn't found; otherwise,
1515 all revisions in set.
1523 all revisions in set.
1516
1524
1517 If any of specified revisions is not present in the local repository,
1525 If any of specified revisions is not present in the local repository,
1518 the query is normally aborted. But this predicate allows the query
1526 the query is normally aborted. But this predicate allows the query
1519 to continue even in such cases.
1527 to continue even in such cases.
1520 """
1528 """
1521 try:
1529 try:
1522 return getset(repo, subset, x)
1530 return getset(repo, subset, x)
1523 except error.RepoLookupError:
1531 except error.RepoLookupError:
1524 return baseset()
1532 return baseset()
1525
1533
1526 # for internal use
1534 # for internal use
1527 @predicate('_notpublic', safe=True)
1535 @predicate('_notpublic', safe=True)
1528 def _notpublic(repo, subset, x):
1536 def _notpublic(repo, subset, x):
1529 getargs(x, 0, 0, "_notpublic takes no arguments")
1537 getargs(x, 0, 0, "_notpublic takes no arguments")
1530 return _phase(repo, subset, phases.draft, phases.secret)
1538 return _phase(repo, subset, phases.draft, phases.secret)
1531
1539
1532 @predicate('public()', safe=True)
1540 @predicate('public()', safe=True)
1533 def public(repo, subset, x):
1541 def public(repo, subset, x):
1534 """Changeset in public phase."""
1542 """Changeset in public phase."""
1535 # i18n: "public" is a keyword
1543 # i18n: "public" is a keyword
1536 getargs(x, 0, 0, _("public takes no arguments"))
1544 getargs(x, 0, 0, _("public takes no arguments"))
1537 phase = repo._phasecache.phase
1545 phase = repo._phasecache.phase
1538 target = phases.public
1546 target = phases.public
1539 condition = lambda r: phase(repo, r) == target
1547 condition = lambda r: phase(repo, r) == target
1540 return subset.filter(condition, condrepr=('<phase %r>', target),
1548 return subset.filter(condition, condrepr=('<phase %r>', target),
1541 cache=False)
1549 cache=False)
1542
1550
1543 @predicate('remote([id [,path]])', safe=False)
1551 @predicate('remote([id [,path]])', safe=False)
1544 def remote(repo, subset, x):
1552 def remote(repo, subset, x):
1545 """Local revision that corresponds to the given identifier in a
1553 """Local revision that corresponds to the given identifier in a
1546 remote repository, if present. Here, the '.' identifier is a
1554 remote repository, if present. Here, the '.' identifier is a
1547 synonym for the current local branch.
1555 synonym for the current local branch.
1548 """
1556 """
1549
1557
1550 from . import hg # avoid start-up nasties
1558 from . import hg # avoid start-up nasties
1551 # i18n: "remote" is a keyword
1559 # i18n: "remote" is a keyword
1552 l = getargs(x, 0, 2, _("remote takes zero, one, or two arguments"))
1560 l = getargs(x, 0, 2, _("remote takes zero, one, or two arguments"))
1553
1561
1554 q = '.'
1562 q = '.'
1555 if len(l) > 0:
1563 if len(l) > 0:
1556 # i18n: "remote" is a keyword
1564 # i18n: "remote" is a keyword
1557 q = getstring(l[0], _("remote requires a string id"))
1565 q = getstring(l[0], _("remote requires a string id"))
1558 if q == '.':
1566 if q == '.':
1559 q = repo['.'].branch()
1567 q = repo['.'].branch()
1560
1568
1561 dest = ''
1569 dest = ''
1562 if len(l) > 1:
1570 if len(l) > 1:
1563 # i18n: "remote" is a keyword
1571 # i18n: "remote" is a keyword
1564 dest = getstring(l[1], _("remote requires a repository path"))
1572 dest = getstring(l[1], _("remote requires a repository path"))
1565 dest = repo.ui.expandpath(dest or 'default')
1573 dest = repo.ui.expandpath(dest or 'default')
1566 dest, branches = hg.parseurl(dest)
1574 dest, branches = hg.parseurl(dest)
1567 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1575 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1568 if revs:
1576 if revs:
1569 revs = [repo.lookup(rev) for rev in revs]
1577 revs = [repo.lookup(rev) for rev in revs]
1570 other = hg.peer(repo, {}, dest)
1578 other = hg.peer(repo, {}, dest)
1571 n = other.lookup(q)
1579 n = other.lookup(q)
1572 if n in repo:
1580 if n in repo:
1573 r = repo[n].rev()
1581 r = repo[n].rev()
1574 if r in subset:
1582 if r in subset:
1575 return baseset([r])
1583 return baseset([r])
1576 return baseset()
1584 return baseset()
1577
1585
1578 @predicate('removes(pattern)', safe=True)
1586 @predicate('removes(pattern)', safe=True)
1579 def removes(repo, subset, x):
1587 def removes(repo, subset, x):
1580 """Changesets which remove files matching pattern.
1588 """Changesets which remove files matching pattern.
1581
1589
1582 The pattern without explicit kind like ``glob:`` is expected to be
1590 The pattern without explicit kind like ``glob:`` is expected to be
1583 relative to the current directory and match against a file or a
1591 relative to the current directory and match against a file or a
1584 directory.
1592 directory.
1585 """
1593 """
1586 # i18n: "removes" is a keyword
1594 # i18n: "removes" is a keyword
1587 pat = getstring(x, _("removes requires a pattern"))
1595 pat = getstring(x, _("removes requires a pattern"))
1588 return checkstatus(repo, subset, pat, 2)
1596 return checkstatus(repo, subset, pat, 2)
1589
1597
1590 @predicate('rev(number)', safe=True)
1598 @predicate('rev(number)', safe=True)
1591 def rev(repo, subset, x):
1599 def rev(repo, subset, x):
1592 """Revision with the given numeric identifier.
1600 """Revision with the given numeric identifier.
1593 """
1601 """
1594 # i18n: "rev" is a keyword
1602 # i18n: "rev" is a keyword
1595 l = getargs(x, 1, 1, _("rev requires one argument"))
1603 l = getargs(x, 1, 1, _("rev requires one argument"))
1596 try:
1604 try:
1597 # i18n: "rev" is a keyword
1605 # i18n: "rev" is a keyword
1598 l = int(getstring(l[0], _("rev requires a number")))
1606 l = int(getstring(l[0], _("rev requires a number")))
1599 except (TypeError, ValueError):
1607 except (TypeError, ValueError):
1600 # i18n: "rev" is a keyword
1608 # i18n: "rev" is a keyword
1601 raise error.ParseError(_("rev expects a number"))
1609 raise error.ParseError(_("rev expects a number"))
1602 if l not in repo.changelog and l != node.nullrev:
1610 if l not in repo.changelog and l != node.nullrev:
1603 return baseset()
1611 return baseset()
1604 return subset & baseset([l])
1612 return subset & baseset([l])
1605
1613
1606 @predicate('matching(revision [, field])', safe=True)
1614 @predicate('matching(revision [, field])', safe=True)
1607 def matching(repo, subset, x):
1615 def matching(repo, subset, x):
1608 """Changesets in which a given set of fields match the set of fields in the
1616 """Changesets in which a given set of fields match the set of fields in the
1609 selected revision or set.
1617 selected revision or set.
1610
1618
1611 To match more than one field pass the list of fields to match separated
1619 To match more than one field pass the list of fields to match separated
1612 by spaces (e.g. ``author description``).
1620 by spaces (e.g. ``author description``).
1613
1621
1614 Valid fields are most regular revision fields and some special fields.
1622 Valid fields are most regular revision fields and some special fields.
1615
1623
1616 Regular revision fields are ``description``, ``author``, ``branch``,
1624 Regular revision fields are ``description``, ``author``, ``branch``,
1617 ``date``, ``files``, ``phase``, ``parents``, ``substate``, ``user``
1625 ``date``, ``files``, ``phase``, ``parents``, ``substate``, ``user``
1618 and ``diff``.
1626 and ``diff``.
1619 Note that ``author`` and ``user`` are synonyms. ``diff`` refers to the
1627 Note that ``author`` and ``user`` are synonyms. ``diff`` refers to the
1620 contents of the revision. Two revisions matching their ``diff`` will
1628 contents of the revision. Two revisions matching their ``diff`` will
1621 also match their ``files``.
1629 also match their ``files``.
1622
1630
1623 Special fields are ``summary`` and ``metadata``:
1631 Special fields are ``summary`` and ``metadata``:
1624 ``summary`` matches the first line of the description.
1632 ``summary`` matches the first line of the description.
1625 ``metadata`` is equivalent to matching ``description user date``
1633 ``metadata`` is equivalent to matching ``description user date``
1626 (i.e. it matches the main metadata fields).
1634 (i.e. it matches the main metadata fields).
1627
1635
1628 ``metadata`` is the default field which is used when no fields are
1636 ``metadata`` is the default field which is used when no fields are
1629 specified. You can match more than one field at a time.
1637 specified. You can match more than one field at a time.
1630 """
1638 """
1631 # i18n: "matching" is a keyword
1639 # i18n: "matching" is a keyword
1632 l = getargs(x, 1, 2, _("matching takes 1 or 2 arguments"))
1640 l = getargs(x, 1, 2, _("matching takes 1 or 2 arguments"))
1633
1641
1634 revs = getset(repo, fullreposet(repo), l[0])
1642 revs = getset(repo, fullreposet(repo), l[0])
1635
1643
1636 fieldlist = ['metadata']
1644 fieldlist = ['metadata']
1637 if len(l) > 1:
1645 if len(l) > 1:
1638 fieldlist = getstring(l[1],
1646 fieldlist = getstring(l[1],
1639 # i18n: "matching" is a keyword
1647 # i18n: "matching" is a keyword
1640 _("matching requires a string "
1648 _("matching requires a string "
1641 "as its second argument")).split()
1649 "as its second argument")).split()
1642
1650
1643 # Make sure that there are no repeated fields,
1651 # Make sure that there are no repeated fields,
1644 # expand the 'special' 'metadata' field type
1652 # expand the 'special' 'metadata' field type
1645 # and check the 'files' whenever we check the 'diff'
1653 # and check the 'files' whenever we check the 'diff'
1646 fields = []
1654 fields = []
1647 for field in fieldlist:
1655 for field in fieldlist:
1648 if field == 'metadata':
1656 if field == 'metadata':
1649 fields += ['user', 'description', 'date']
1657 fields += ['user', 'description', 'date']
1650 elif field == 'diff':
1658 elif field == 'diff':
1651 # a revision matching the diff must also match the files
1659 # a revision matching the diff must also match the files
1652 # since matching the diff is very costly, make sure to
1660 # since matching the diff is very costly, make sure to
1653 # also match the files first
1661 # also match the files first
1654 fields += ['files', 'diff']
1662 fields += ['files', 'diff']
1655 else:
1663 else:
1656 if field == 'author':
1664 if field == 'author':
1657 field = 'user'
1665 field = 'user'
1658 fields.append(field)
1666 fields.append(field)
1659 fields = set(fields)
1667 fields = set(fields)
1660 if 'summary' in fields and 'description' in fields:
1668 if 'summary' in fields and 'description' in fields:
1661 # If a revision matches its description it also matches its summary
1669 # If a revision matches its description it also matches its summary
1662 fields.discard('summary')
1670 fields.discard('summary')
1663
1671
1664 # We may want to match more than one field
1672 # We may want to match more than one field
1665 # Not all fields take the same amount of time to be matched
1673 # Not all fields take the same amount of time to be matched
1666 # Sort the selected fields in order of increasing matching cost
1674 # Sort the selected fields in order of increasing matching cost
1667 fieldorder = ['phase', 'parents', 'user', 'date', 'branch', 'summary',
1675 fieldorder = ['phase', 'parents', 'user', 'date', 'branch', 'summary',
1668 'files', 'description', 'substate', 'diff']
1676 'files', 'description', 'substate', 'diff']
1669 def fieldkeyfunc(f):
1677 def fieldkeyfunc(f):
1670 try:
1678 try:
1671 return fieldorder.index(f)
1679 return fieldorder.index(f)
1672 except ValueError:
1680 except ValueError:
1673 # assume an unknown field is very costly
1681 # assume an unknown field is very costly
1674 return len(fieldorder)
1682 return len(fieldorder)
1675 fields = list(fields)
1683 fields = list(fields)
1676 fields.sort(key=fieldkeyfunc)
1684 fields.sort(key=fieldkeyfunc)
1677
1685
1678 # Each field will be matched with its own "getfield" function
1686 # Each field will be matched with its own "getfield" function
1679 # which will be added to the getfieldfuncs array of functions
1687 # which will be added to the getfieldfuncs array of functions
1680 getfieldfuncs = []
1688 getfieldfuncs = []
1681 _funcs = {
1689 _funcs = {
1682 'user': lambda r: repo[r].user(),
1690 'user': lambda r: repo[r].user(),
1683 'branch': lambda r: repo[r].branch(),
1691 'branch': lambda r: repo[r].branch(),
1684 'date': lambda r: repo[r].date(),
1692 'date': lambda r: repo[r].date(),
1685 'description': lambda r: repo[r].description(),
1693 'description': lambda r: repo[r].description(),
1686 'files': lambda r: repo[r].files(),
1694 'files': lambda r: repo[r].files(),
1687 'parents': lambda r: repo[r].parents(),
1695 'parents': lambda r: repo[r].parents(),
1688 'phase': lambda r: repo[r].phase(),
1696 'phase': lambda r: repo[r].phase(),
1689 'substate': lambda r: repo[r].substate,
1697 'substate': lambda r: repo[r].substate,
1690 'summary': lambda r: repo[r].description().splitlines()[0],
1698 'summary': lambda r: repo[r].description().splitlines()[0],
1691 'diff': lambda r: list(repo[r].diff(git=True),)
1699 'diff': lambda r: list(repo[r].diff(git=True),)
1692 }
1700 }
1693 for info in fields:
1701 for info in fields:
1694 getfield = _funcs.get(info, None)
1702 getfield = _funcs.get(info, None)
1695 if getfield is None:
1703 if getfield is None:
1696 raise error.ParseError(
1704 raise error.ParseError(
1697 # i18n: "matching" is a keyword
1705 # i18n: "matching" is a keyword
1698 _("unexpected field name passed to matching: %s") % info)
1706 _("unexpected field name passed to matching: %s") % info)
1699 getfieldfuncs.append(getfield)
1707 getfieldfuncs.append(getfield)
1700 # convert the getfield array of functions into a "getinfo" function
1708 # convert the getfield array of functions into a "getinfo" function
1701 # which returns an array of field values (or a single value if there
1709 # which returns an array of field values (or a single value if there
1702 # is only one field to match)
1710 # is only one field to match)
1703 getinfo = lambda r: [f(r) for f in getfieldfuncs]
1711 getinfo = lambda r: [f(r) for f in getfieldfuncs]
1704
1712
1705 def matches(x):
1713 def matches(x):
1706 for rev in revs:
1714 for rev in revs:
1707 target = getinfo(rev)
1715 target = getinfo(rev)
1708 match = True
1716 match = True
1709 for n, f in enumerate(getfieldfuncs):
1717 for n, f in enumerate(getfieldfuncs):
1710 if target[n] != f(x):
1718 if target[n] != f(x):
1711 match = False
1719 match = False
1712 if match:
1720 if match:
1713 return True
1721 return True
1714 return False
1722 return False
1715
1723
1716 return subset.filter(matches, condrepr=('<matching%r %r>', fields, revs))
1724 return subset.filter(matches, condrepr=('<matching%r %r>', fields, revs))
1717
1725
1718 @predicate('reverse(set)', safe=True, takeorder=True)
1726 @predicate('reverse(set)', safe=True, takeorder=True)
1719 def reverse(repo, subset, x, order):
1727 def reverse(repo, subset, x, order):
1720 """Reverse order of set.
1728 """Reverse order of set.
1721 """
1729 """
1722 l = getset(repo, subset, x)
1730 l = getset(repo, subset, x)
1723 if order == defineorder:
1731 if order == defineorder:
1724 l.reverse()
1732 l.reverse()
1725 return l
1733 return l
1726
1734
1727 @predicate('roots(set)', safe=True)
1735 @predicate('roots(set)', safe=True)
1728 def roots(repo, subset, x):
1736 def roots(repo, subset, x):
1729 """Changesets in set with no parent changeset in set.
1737 """Changesets in set with no parent changeset in set.
1730 """
1738 """
1731 s = getset(repo, fullreposet(repo), x)
1739 s = getset(repo, fullreposet(repo), x)
1732 parents = repo.changelog.parentrevs
1740 parents = repo.changelog.parentrevs
1733 def filter(r):
1741 def filter(r):
1734 for p in parents(r):
1742 for p in parents(r):
1735 if 0 <= p and p in s:
1743 if 0 <= p and p in s:
1736 return False
1744 return False
1737 return True
1745 return True
1738 return subset & s.filter(filter, condrepr='<roots>')
1746 return subset & s.filter(filter, condrepr='<roots>')
1739
1747
1740 _sortkeyfuncs = {
1748 _sortkeyfuncs = {
1741 'rev': lambda c: c.rev(),
1749 'rev': lambda c: c.rev(),
1742 'branch': lambda c: c.branch(),
1750 'branch': lambda c: c.branch(),
1743 'desc': lambda c: c.description(),
1751 'desc': lambda c: c.description(),
1744 'user': lambda c: c.user(),
1752 'user': lambda c: c.user(),
1745 'author': lambda c: c.user(),
1753 'author': lambda c: c.user(),
1746 'date': lambda c: c.date()[0],
1754 'date': lambda c: c.date()[0],
1747 }
1755 }
1748
1756
1749 def _getsortargs(x):
1757 def _getsortargs(x):
1750 """Parse sort options into (set, [(key, reverse)], opts)"""
1758 """Parse sort options into (set, [(key, reverse)], opts)"""
1751 args = getargsdict(x, 'sort', 'set keys topo.firstbranch')
1759 args = getargsdict(x, 'sort', 'set keys topo.firstbranch')
1752 if 'set' not in args:
1760 if 'set' not in args:
1753 # i18n: "sort" is a keyword
1761 # i18n: "sort" is a keyword
1754 raise error.ParseError(_('sort requires one or two arguments'))
1762 raise error.ParseError(_('sort requires one or two arguments'))
1755 keys = "rev"
1763 keys = "rev"
1756 if 'keys' in args:
1764 if 'keys' in args:
1757 # i18n: "sort" is a keyword
1765 # i18n: "sort" is a keyword
1758 keys = getstring(args['keys'], _("sort spec must be a string"))
1766 keys = getstring(args['keys'], _("sort spec must be a string"))
1759
1767
1760 keyflags = []
1768 keyflags = []
1761 for k in keys.split():
1769 for k in keys.split():
1762 fk = k
1770 fk = k
1763 reverse = (k[0] == '-')
1771 reverse = (k[0] == '-')
1764 if reverse:
1772 if reverse:
1765 k = k[1:]
1773 k = k[1:]
1766 if k not in _sortkeyfuncs and k != 'topo':
1774 if k not in _sortkeyfuncs and k != 'topo':
1767 raise error.ParseError(_("unknown sort key %r") % fk)
1775 raise error.ParseError(_("unknown sort key %r") % fk)
1768 keyflags.append((k, reverse))
1776 keyflags.append((k, reverse))
1769
1777
1770 if len(keyflags) > 1 and any(k == 'topo' for k, reverse in keyflags):
1778 if len(keyflags) > 1 and any(k == 'topo' for k, reverse in keyflags):
1771 # i18n: "topo" is a keyword
1779 # i18n: "topo" is a keyword
1772 raise error.ParseError(_('topo sort order cannot be combined '
1780 raise error.ParseError(_('topo sort order cannot be combined '
1773 'with other sort keys'))
1781 'with other sort keys'))
1774
1782
1775 opts = {}
1783 opts = {}
1776 if 'topo.firstbranch' in args:
1784 if 'topo.firstbranch' in args:
1777 if any(k == 'topo' for k, reverse in keyflags):
1785 if any(k == 'topo' for k, reverse in keyflags):
1778 opts['topo.firstbranch'] = args['topo.firstbranch']
1786 opts['topo.firstbranch'] = args['topo.firstbranch']
1779 else:
1787 else:
1780 # i18n: "topo" and "topo.firstbranch" are keywords
1788 # i18n: "topo" and "topo.firstbranch" are keywords
1781 raise error.ParseError(_('topo.firstbranch can only be used '
1789 raise error.ParseError(_('topo.firstbranch can only be used '
1782 'when using the topo sort key'))
1790 'when using the topo sort key'))
1783
1791
1784 return args['set'], keyflags, opts
1792 return args['set'], keyflags, opts
1785
1793
1786 @predicate('sort(set[, [-]key... [, ...]])', safe=True, takeorder=True)
1794 @predicate('sort(set[, [-]key... [, ...]])', safe=True, takeorder=True)
1787 def sort(repo, subset, x, order):
1795 def sort(repo, subset, x, order):
1788 """Sort set by keys. The default sort order is ascending, specify a key
1796 """Sort set by keys. The default sort order is ascending, specify a key
1789 as ``-key`` to sort in descending order.
1797 as ``-key`` to sort in descending order.
1790
1798
1791 The keys can be:
1799 The keys can be:
1792
1800
1793 - ``rev`` for the revision number,
1801 - ``rev`` for the revision number,
1794 - ``branch`` for the branch name,
1802 - ``branch`` for the branch name,
1795 - ``desc`` for the commit message (description),
1803 - ``desc`` for the commit message (description),
1796 - ``user`` for user name (``author`` can be used as an alias),
1804 - ``user`` for user name (``author`` can be used as an alias),
1797 - ``date`` for the commit date
1805 - ``date`` for the commit date
1798 - ``topo`` for a reverse topographical sort
1806 - ``topo`` for a reverse topographical sort
1799
1807
1800 The ``topo`` sort order cannot be combined with other sort keys. This sort
1808 The ``topo`` sort order cannot be combined with other sort keys. This sort
1801 takes one optional argument, ``topo.firstbranch``, which takes a revset that
1809 takes one optional argument, ``topo.firstbranch``, which takes a revset that
1802 specifies what topographical branches to prioritize in the sort.
1810 specifies what topographical branches to prioritize in the sort.
1803
1811
1804 """
1812 """
1805 s, keyflags, opts = _getsortargs(x)
1813 s, keyflags, opts = _getsortargs(x)
1806 revs = getset(repo, subset, s)
1814 revs = getset(repo, subset, s)
1807
1815
1808 if not keyflags or order != defineorder:
1816 if not keyflags or order != defineorder:
1809 return revs
1817 return revs
1810 if len(keyflags) == 1 and keyflags[0][0] == "rev":
1818 if len(keyflags) == 1 and keyflags[0][0] == "rev":
1811 revs.sort(reverse=keyflags[0][1])
1819 revs.sort(reverse=keyflags[0][1])
1812 return revs
1820 return revs
1813 elif keyflags[0][0] == "topo":
1821 elif keyflags[0][0] == "topo":
1814 firstbranch = ()
1822 firstbranch = ()
1815 if 'topo.firstbranch' in opts:
1823 if 'topo.firstbranch' in opts:
1816 firstbranch = getset(repo, subset, opts['topo.firstbranch'])
1824 firstbranch = getset(repo, subset, opts['topo.firstbranch'])
1817 revs = baseset(_toposort(revs, repo.changelog.parentrevs, firstbranch),
1825 revs = baseset(_toposort(revs, repo.changelog.parentrevs, firstbranch),
1818 istopo=True)
1826 istopo=True)
1819 if keyflags[0][1]:
1827 if keyflags[0][1]:
1820 revs.reverse()
1828 revs.reverse()
1821 return revs
1829 return revs
1822
1830
1823 # sort() is guaranteed to be stable
1831 # sort() is guaranteed to be stable
1824 ctxs = [repo[r] for r in revs]
1832 ctxs = [repo[r] for r in revs]
1825 for k, reverse in reversed(keyflags):
1833 for k, reverse in reversed(keyflags):
1826 ctxs.sort(key=_sortkeyfuncs[k], reverse=reverse)
1834 ctxs.sort(key=_sortkeyfuncs[k], reverse=reverse)
1827 return baseset([c.rev() for c in ctxs])
1835 return baseset([c.rev() for c in ctxs])
1828
1836
1829 def _toposort(revs, parentsfunc, firstbranch=()):
1837 def _toposort(revs, parentsfunc, firstbranch=()):
1830 """Yield revisions from heads to roots one (topo) branch at a time.
1838 """Yield revisions from heads to roots one (topo) branch at a time.
1831
1839
1832 This function aims to be used by a graph generator that wishes to minimize
1840 This function aims to be used by a graph generator that wishes to minimize
1833 the number of parallel branches and their interleaving.
1841 the number of parallel branches and their interleaving.
1834
1842
1835 Example iteration order (numbers show the "true" order in a changelog):
1843 Example iteration order (numbers show the "true" order in a changelog):
1836
1844
1837 o 4
1845 o 4
1838 |
1846 |
1839 o 1
1847 o 1
1840 |
1848 |
1841 | o 3
1849 | o 3
1842 | |
1850 | |
1843 | o 2
1851 | o 2
1844 |/
1852 |/
1845 o 0
1853 o 0
1846
1854
1847 Note that the ancestors of merges are understood by the current
1855 Note that the ancestors of merges are understood by the current
1848 algorithm to be on the same branch. This means no reordering will
1856 algorithm to be on the same branch. This means no reordering will
1849 occur behind a merge.
1857 occur behind a merge.
1850 """
1858 """
1851
1859
1852 ### Quick summary of the algorithm
1860 ### Quick summary of the algorithm
1853 #
1861 #
1854 # This function is based around a "retention" principle. We keep revisions
1862 # This function is based around a "retention" principle. We keep revisions
1855 # in memory until we are ready to emit a whole branch that immediately
1863 # in memory until we are ready to emit a whole branch that immediately
1856 # "merges" into an existing one. This reduces the number of parallel
1864 # "merges" into an existing one. This reduces the number of parallel
1857 # branches with interleaved revisions.
1865 # branches with interleaved revisions.
1858 #
1866 #
1859 # During iteration revs are split into two groups:
1867 # During iteration revs are split into two groups:
1860 # A) revision already emitted
1868 # A) revision already emitted
1861 # B) revision in "retention". They are stored as different subgroups.
1869 # B) revision in "retention". They are stored as different subgroups.
1862 #
1870 #
1863 # for each REV, we do the following logic:
1871 # for each REV, we do the following logic:
1864 #
1872 #
1865 # 1) if REV is a parent of (A), we will emit it. If there is a
1873 # 1) if REV is a parent of (A), we will emit it. If there is a
1866 # retention group ((B) above) that is blocked on REV being
1874 # retention group ((B) above) that is blocked on REV being
1867 # available, we emit all the revisions out of that retention
1875 # available, we emit all the revisions out of that retention
1868 # group first.
1876 # group first.
1869 #
1877 #
1870 # 2) else, we'll search for a subgroup in (B) awaiting for REV to be
1878 # 2) else, we'll search for a subgroup in (B) awaiting for REV to be
1871 # available, if such subgroup exist, we add REV to it and the subgroup is
1879 # available, if such subgroup exist, we add REV to it and the subgroup is
1872 # now awaiting for REV.parents() to be available.
1880 # now awaiting for REV.parents() to be available.
1873 #
1881 #
1874 # 3) finally if no such group existed in (B), we create a new subgroup.
1882 # 3) finally if no such group existed in (B), we create a new subgroup.
1875 #
1883 #
1876 #
1884 #
1877 # To bootstrap the algorithm, we emit the tipmost revision (which
1885 # To bootstrap the algorithm, we emit the tipmost revision (which
1878 # puts it in group (A) from above).
1886 # puts it in group (A) from above).
1879
1887
1880 revs.sort(reverse=True)
1888 revs.sort(reverse=True)
1881
1889
1882 # Set of parents of revision that have been emitted. They can be considered
1890 # Set of parents of revision that have been emitted. They can be considered
1883 # unblocked as the graph generator is already aware of them so there is no
1891 # unblocked as the graph generator is already aware of them so there is no
1884 # need to delay the revisions that reference them.
1892 # need to delay the revisions that reference them.
1885 #
1893 #
1886 # If someone wants to prioritize a branch over the others, pre-filling this
1894 # If someone wants to prioritize a branch over the others, pre-filling this
1887 # set will force all other branches to wait until this branch is ready to be
1895 # set will force all other branches to wait until this branch is ready to be
1888 # emitted.
1896 # emitted.
1889 unblocked = set(firstbranch)
1897 unblocked = set(firstbranch)
1890
1898
1891 # list of groups waiting to be displayed, each group is defined by:
1899 # list of groups waiting to be displayed, each group is defined by:
1892 #
1900 #
1893 # (revs: lists of revs waiting to be displayed,
1901 # (revs: lists of revs waiting to be displayed,
1894 # blocked: set of that cannot be displayed before those in 'revs')
1902 # blocked: set of that cannot be displayed before those in 'revs')
1895 #
1903 #
1896 # The second value ('blocked') correspond to parents of any revision in the
1904 # The second value ('blocked') correspond to parents of any revision in the
1897 # group ('revs') that is not itself contained in the group. The main idea
1905 # group ('revs') that is not itself contained in the group. The main idea
1898 # of this algorithm is to delay as much as possible the emission of any
1906 # of this algorithm is to delay as much as possible the emission of any
1899 # revision. This means waiting for the moment we are about to display
1907 # revision. This means waiting for the moment we are about to display
1900 # these parents to display the revs in a group.
1908 # these parents to display the revs in a group.
1901 #
1909 #
1902 # This first implementation is smart until it encounters a merge: it will
1910 # This first implementation is smart until it encounters a merge: it will
1903 # emit revs as soon as any parent is about to be emitted and can grow an
1911 # emit revs as soon as any parent is about to be emitted and can grow an
1904 # arbitrary number of revs in 'blocked'. In practice this mean we properly
1912 # arbitrary number of revs in 'blocked'. In practice this mean we properly
1905 # retains new branches but gives up on any special ordering for ancestors
1913 # retains new branches but gives up on any special ordering for ancestors
1906 # of merges. The implementation can be improved to handle this better.
1914 # of merges. The implementation can be improved to handle this better.
1907 #
1915 #
1908 # The first subgroup is special. It corresponds to all the revision that
1916 # The first subgroup is special. It corresponds to all the revision that
1909 # were already emitted. The 'revs' lists is expected to be empty and the
1917 # were already emitted. The 'revs' lists is expected to be empty and the
1910 # 'blocked' set contains the parents revisions of already emitted revision.
1918 # 'blocked' set contains the parents revisions of already emitted revision.
1911 #
1919 #
1912 # You could pre-seed the <parents> set of groups[0] to a specific
1920 # You could pre-seed the <parents> set of groups[0] to a specific
1913 # changesets to select what the first emitted branch should be.
1921 # changesets to select what the first emitted branch should be.
1914 groups = [([], unblocked)]
1922 groups = [([], unblocked)]
1915 pendingheap = []
1923 pendingheap = []
1916 pendingset = set()
1924 pendingset = set()
1917
1925
1918 heapq.heapify(pendingheap)
1926 heapq.heapify(pendingheap)
1919 heappop = heapq.heappop
1927 heappop = heapq.heappop
1920 heappush = heapq.heappush
1928 heappush = heapq.heappush
1921 for currentrev in revs:
1929 for currentrev in revs:
1922 # Heap works with smallest element, we want highest so we invert
1930 # Heap works with smallest element, we want highest so we invert
1923 if currentrev not in pendingset:
1931 if currentrev not in pendingset:
1924 heappush(pendingheap, -currentrev)
1932 heappush(pendingheap, -currentrev)
1925 pendingset.add(currentrev)
1933 pendingset.add(currentrev)
1926 # iterates on pending rev until after the current rev have been
1934 # iterates on pending rev until after the current rev have been
1927 # processed.
1935 # processed.
1928 rev = None
1936 rev = None
1929 while rev != currentrev:
1937 while rev != currentrev:
1930 rev = -heappop(pendingheap)
1938 rev = -heappop(pendingheap)
1931 pendingset.remove(rev)
1939 pendingset.remove(rev)
1932
1940
1933 # Seek for a subgroup blocked, waiting for the current revision.
1941 # Seek for a subgroup blocked, waiting for the current revision.
1934 matching = [i for i, g in enumerate(groups) if rev in g[1]]
1942 matching = [i for i, g in enumerate(groups) if rev in g[1]]
1935
1943
1936 if matching:
1944 if matching:
1937 # The main idea is to gather together all sets that are blocked
1945 # The main idea is to gather together all sets that are blocked
1938 # on the same revision.
1946 # on the same revision.
1939 #
1947 #
1940 # Groups are merged when a common blocking ancestor is
1948 # Groups are merged when a common blocking ancestor is
1941 # observed. For example, given two groups:
1949 # observed. For example, given two groups:
1942 #
1950 #
1943 # revs [5, 4] waiting for 1
1951 # revs [5, 4] waiting for 1
1944 # revs [3, 2] waiting for 1
1952 # revs [3, 2] waiting for 1
1945 #
1953 #
1946 # These two groups will be merged when we process
1954 # These two groups will be merged when we process
1947 # 1. In theory, we could have merged the groups when
1955 # 1. In theory, we could have merged the groups when
1948 # we added 2 to the group it is now in (we could have
1956 # we added 2 to the group it is now in (we could have
1949 # noticed the groups were both blocked on 1 then), but
1957 # noticed the groups were both blocked on 1 then), but
1950 # the way it works now makes the algorithm simpler.
1958 # the way it works now makes the algorithm simpler.
1951 #
1959 #
1952 # We also always keep the oldest subgroup first. We can
1960 # We also always keep the oldest subgroup first. We can
1953 # probably improve the behavior by having the longest set
1961 # probably improve the behavior by having the longest set
1954 # first. That way, graph algorithms could minimise the length
1962 # first. That way, graph algorithms could minimise the length
1955 # of parallel lines their drawing. This is currently not done.
1963 # of parallel lines their drawing. This is currently not done.
1956 targetidx = matching.pop(0)
1964 targetidx = matching.pop(0)
1957 trevs, tparents = groups[targetidx]
1965 trevs, tparents = groups[targetidx]
1958 for i in matching:
1966 for i in matching:
1959 gr = groups[i]
1967 gr = groups[i]
1960 trevs.extend(gr[0])
1968 trevs.extend(gr[0])
1961 tparents |= gr[1]
1969 tparents |= gr[1]
1962 # delete all merged subgroups (except the one we kept)
1970 # delete all merged subgroups (except the one we kept)
1963 # (starting from the last subgroup for performance and
1971 # (starting from the last subgroup for performance and
1964 # sanity reasons)
1972 # sanity reasons)
1965 for i in reversed(matching):
1973 for i in reversed(matching):
1966 del groups[i]
1974 del groups[i]
1967 else:
1975 else:
1968 # This is a new head. We create a new subgroup for it.
1976 # This is a new head. We create a new subgroup for it.
1969 targetidx = len(groups)
1977 targetidx = len(groups)
1970 groups.append(([], {rev}))
1978 groups.append(([], {rev}))
1971
1979
1972 gr = groups[targetidx]
1980 gr = groups[targetidx]
1973
1981
1974 # We now add the current nodes to this subgroups. This is done
1982 # We now add the current nodes to this subgroups. This is done
1975 # after the subgroup merging because all elements from a subgroup
1983 # after the subgroup merging because all elements from a subgroup
1976 # that relied on this rev must precede it.
1984 # that relied on this rev must precede it.
1977 #
1985 #
1978 # we also update the <parents> set to include the parents of the
1986 # we also update the <parents> set to include the parents of the
1979 # new nodes.
1987 # new nodes.
1980 if rev == currentrev: # only display stuff in rev
1988 if rev == currentrev: # only display stuff in rev
1981 gr[0].append(rev)
1989 gr[0].append(rev)
1982 gr[1].remove(rev)
1990 gr[1].remove(rev)
1983 parents = [p for p in parentsfunc(rev) if p > node.nullrev]
1991 parents = [p for p in parentsfunc(rev) if p > node.nullrev]
1984 gr[1].update(parents)
1992 gr[1].update(parents)
1985 for p in parents:
1993 for p in parents:
1986 if p not in pendingset:
1994 if p not in pendingset:
1987 pendingset.add(p)
1995 pendingset.add(p)
1988 heappush(pendingheap, -p)
1996 heappush(pendingheap, -p)
1989
1997
1990 # Look for a subgroup to display
1998 # Look for a subgroup to display
1991 #
1999 #
1992 # When unblocked is empty (if clause), we were not waiting for any
2000 # When unblocked is empty (if clause), we were not waiting for any
1993 # revisions during the first iteration (if no priority was given) or
2001 # revisions during the first iteration (if no priority was given) or
1994 # if we emitted a whole disconnected set of the graph (reached a
2002 # if we emitted a whole disconnected set of the graph (reached a
1995 # root). In that case we arbitrarily take the oldest known
2003 # root). In that case we arbitrarily take the oldest known
1996 # subgroup. The heuristic could probably be better.
2004 # subgroup. The heuristic could probably be better.
1997 #
2005 #
1998 # Otherwise (elif clause) if the subgroup is blocked on
2006 # Otherwise (elif clause) if the subgroup is blocked on
1999 # a revision we just emitted, we can safely emit it as
2007 # a revision we just emitted, we can safely emit it as
2000 # well.
2008 # well.
2001 if not unblocked:
2009 if not unblocked:
2002 if len(groups) > 1: # display other subset
2010 if len(groups) > 1: # display other subset
2003 targetidx = 1
2011 targetidx = 1
2004 gr = groups[1]
2012 gr = groups[1]
2005 elif not gr[1] & unblocked:
2013 elif not gr[1] & unblocked:
2006 gr = None
2014 gr = None
2007
2015
2008 if gr is not None:
2016 if gr is not None:
2009 # update the set of awaited revisions with the one from the
2017 # update the set of awaited revisions with the one from the
2010 # subgroup
2018 # subgroup
2011 unblocked |= gr[1]
2019 unblocked |= gr[1]
2012 # output all revisions in the subgroup
2020 # output all revisions in the subgroup
2013 for r in gr[0]:
2021 for r in gr[0]:
2014 yield r
2022 yield r
2015 # delete the subgroup that you just output
2023 # delete the subgroup that you just output
2016 # unless it is groups[0] in which case you just empty it.
2024 # unless it is groups[0] in which case you just empty it.
2017 if targetidx:
2025 if targetidx:
2018 del groups[targetidx]
2026 del groups[targetidx]
2019 else:
2027 else:
2020 gr[0][:] = []
2028 gr[0][:] = []
2021 # Check if we have some subgroup waiting for revisions we are not going to
2029 # Check if we have some subgroup waiting for revisions we are not going to
2022 # iterate over
2030 # iterate over
2023 for g in groups:
2031 for g in groups:
2024 for r in g[0]:
2032 for r in g[0]:
2025 yield r
2033 yield r
2026
2034
2027 @predicate('subrepo([pattern])')
2035 @predicate('subrepo([pattern])')
2028 def subrepo(repo, subset, x):
2036 def subrepo(repo, subset, x):
2029 """Changesets that add, modify or remove the given subrepo. If no subrepo
2037 """Changesets that add, modify or remove the given subrepo. If no subrepo
2030 pattern is named, any subrepo changes are returned.
2038 pattern is named, any subrepo changes are returned.
2031 """
2039 """
2032 # i18n: "subrepo" is a keyword
2040 # i18n: "subrepo" is a keyword
2033 args = getargs(x, 0, 1, _('subrepo takes at most one argument'))
2041 args = getargs(x, 0, 1, _('subrepo takes at most one argument'))
2034 pat = None
2042 pat = None
2035 if len(args) != 0:
2043 if len(args) != 0:
2036 pat = getstring(args[0], _("subrepo requires a pattern"))
2044 pat = getstring(args[0], _("subrepo requires a pattern"))
2037
2045
2038 m = matchmod.exact(repo.root, repo.root, ['.hgsubstate'])
2046 m = matchmod.exact(repo.root, repo.root, ['.hgsubstate'])
2039
2047
2040 def submatches(names):
2048 def submatches(names):
2041 k, p, m = util.stringmatcher(pat)
2049 k, p, m = util.stringmatcher(pat)
2042 for name in names:
2050 for name in names:
2043 if m(name):
2051 if m(name):
2044 yield name
2052 yield name
2045
2053
2046 def matches(x):
2054 def matches(x):
2047 c = repo[x]
2055 c = repo[x]
2048 s = repo.status(c.p1().node(), c.node(), match=m)
2056 s = repo.status(c.p1().node(), c.node(), match=m)
2049
2057
2050 if pat is None:
2058 if pat is None:
2051 return s.added or s.modified or s.removed
2059 return s.added or s.modified or s.removed
2052
2060
2053 if s.added:
2061 if s.added:
2054 return any(submatches(c.substate.keys()))
2062 return any(submatches(c.substate.keys()))
2055
2063
2056 if s.modified:
2064 if s.modified:
2057 subs = set(c.p1().substate.keys())
2065 subs = set(c.p1().substate.keys())
2058 subs.update(c.substate.keys())
2066 subs.update(c.substate.keys())
2059
2067
2060 for path in submatches(subs):
2068 for path in submatches(subs):
2061 if c.p1().substate.get(path) != c.substate.get(path):
2069 if c.p1().substate.get(path) != c.substate.get(path):
2062 return True
2070 return True
2063
2071
2064 if s.removed:
2072 if s.removed:
2065 return any(submatches(c.p1().substate.keys()))
2073 return any(submatches(c.p1().substate.keys()))
2066
2074
2067 return False
2075 return False
2068
2076
2069 return subset.filter(matches, condrepr=('<subrepo %r>', pat))
2077 return subset.filter(matches, condrepr=('<subrepo %r>', pat))
2070
2078
2071 def _substringmatcher(pattern, casesensitive=True):
2079 def _substringmatcher(pattern, casesensitive=True):
2072 kind, pattern, matcher = util.stringmatcher(pattern,
2080 kind, pattern, matcher = util.stringmatcher(pattern,
2073 casesensitive=casesensitive)
2081 casesensitive=casesensitive)
2074 if kind == 'literal':
2082 if kind == 'literal':
2075 if not casesensitive:
2083 if not casesensitive:
2076 pattern = encoding.lower(pattern)
2084 pattern = encoding.lower(pattern)
2077 matcher = lambda s: pattern in encoding.lower(s)
2085 matcher = lambda s: pattern in encoding.lower(s)
2078 else:
2086 else:
2079 matcher = lambda s: pattern in s
2087 matcher = lambda s: pattern in s
2080 return kind, pattern, matcher
2088 return kind, pattern, matcher
2081
2089
2082 @predicate('tag([name])', safe=True)
2090 @predicate('tag([name])', safe=True)
2083 def tag(repo, subset, x):
2091 def tag(repo, subset, x):
2084 """The specified tag by name, or all tagged revisions if no name is given.
2092 """The specified tag by name, or all tagged revisions if no name is given.
2085
2093
2086 Pattern matching is supported for `name`. See
2094 Pattern matching is supported for `name`. See
2087 :hg:`help revisions.patterns`.
2095 :hg:`help revisions.patterns`.
2088 """
2096 """
2089 # i18n: "tag" is a keyword
2097 # i18n: "tag" is a keyword
2090 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
2098 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
2091 cl = repo.changelog
2099 cl = repo.changelog
2092 if args:
2100 if args:
2093 pattern = getstring(args[0],
2101 pattern = getstring(args[0],
2094 # i18n: "tag" is a keyword
2102 # i18n: "tag" is a keyword
2095 _('the argument to tag must be a string'))
2103 _('the argument to tag must be a string'))
2096 kind, pattern, matcher = util.stringmatcher(pattern)
2104 kind, pattern, matcher = util.stringmatcher(pattern)
2097 if kind == 'literal':
2105 if kind == 'literal':
2098 # avoid resolving all tags
2106 # avoid resolving all tags
2099 tn = repo._tagscache.tags.get(pattern, None)
2107 tn = repo._tagscache.tags.get(pattern, None)
2100 if tn is None:
2108 if tn is None:
2101 raise error.RepoLookupError(_("tag '%s' does not exist")
2109 raise error.RepoLookupError(_("tag '%s' does not exist")
2102 % pattern)
2110 % pattern)
2103 s = {repo[tn].rev()}
2111 s = {repo[tn].rev()}
2104 else:
2112 else:
2105 s = {cl.rev(n) for t, n in repo.tagslist() if matcher(t)}
2113 s = {cl.rev(n) for t, n in repo.tagslist() if matcher(t)}
2106 else:
2114 else:
2107 s = {cl.rev(n) for t, n in repo.tagslist() if t != 'tip'}
2115 s = {cl.rev(n) for t, n in repo.tagslist() if t != 'tip'}
2108 return subset & s
2116 return subset & s
2109
2117
2110 @predicate('tagged', safe=True)
2118 @predicate('tagged', safe=True)
2111 def tagged(repo, subset, x):
2119 def tagged(repo, subset, x):
2112 return tag(repo, subset, x)
2120 return tag(repo, subset, x)
2113
2121
2114 @predicate('unstable()', safe=True)
2122 @predicate('unstable()', safe=True)
2115 def unstable(repo, subset, x):
2123 def unstable(repo, subset, x):
2116 """Non-obsolete changesets with obsolete ancestors.
2124 """Non-obsolete changesets with obsolete ancestors.
2117 """
2125 """
2118 # i18n: "unstable" is a keyword
2126 # i18n: "unstable" is a keyword
2119 getargs(x, 0, 0, _("unstable takes no arguments"))
2127 getargs(x, 0, 0, _("unstable takes no arguments"))
2120 unstables = obsmod.getrevs(repo, 'unstable')
2128 unstables = obsmod.getrevs(repo, 'unstable')
2121 return subset & unstables
2129 return subset & unstables
2122
2130
2123
2131
2124 @predicate('user(string)', safe=True)
2132 @predicate('user(string)', safe=True)
2125 def user(repo, subset, x):
2133 def user(repo, subset, x):
2126 """User name contains string. The match is case-insensitive.
2134 """User name contains string. The match is case-insensitive.
2127
2135
2128 Pattern matching is supported for `string`. See
2136 Pattern matching is supported for `string`. See
2129 :hg:`help revisions.patterns`.
2137 :hg:`help revisions.patterns`.
2130 """
2138 """
2131 return author(repo, subset, x)
2139 return author(repo, subset, x)
2132
2140
2133 @predicate('wdir()', safe=True)
2141 @predicate('wdir()', safe=True)
2134 def wdir(repo, subset, x):
2142 def wdir(repo, subset, x):
2135 """Working directory. (EXPERIMENTAL)"""
2143 """Working directory. (EXPERIMENTAL)"""
2136 # i18n: "wdir" is a keyword
2144 # i18n: "wdir" is a keyword
2137 getargs(x, 0, 0, _("wdir takes no arguments"))
2145 getargs(x, 0, 0, _("wdir takes no arguments"))
2138 if node.wdirrev in subset or isinstance(subset, fullreposet):
2146 if node.wdirrev in subset or isinstance(subset, fullreposet):
2139 return baseset([node.wdirrev])
2147 return baseset([node.wdirrev])
2140 return baseset()
2148 return baseset()
2141
2149
2142 def _orderedlist(repo, subset, x):
2150 def _orderedlist(repo, subset, x):
2143 s = getstring(x, "internal error")
2151 s = getstring(x, "internal error")
2144 if not s:
2152 if not s:
2145 return baseset()
2153 return baseset()
2146 # remove duplicates here. it's difficult for caller to deduplicate sets
2154 # remove duplicates here. it's difficult for caller to deduplicate sets
2147 # because different symbols can point to the same rev.
2155 # because different symbols can point to the same rev.
2148 cl = repo.changelog
2156 cl = repo.changelog
2149 ls = []
2157 ls = []
2150 seen = set()
2158 seen = set()
2151 for t in s.split('\0'):
2159 for t in s.split('\0'):
2152 try:
2160 try:
2153 # fast path for integer revision
2161 # fast path for integer revision
2154 r = int(t)
2162 r = int(t)
2155 if str(r) != t or r not in cl:
2163 if str(r) != t or r not in cl:
2156 raise ValueError
2164 raise ValueError
2157 revs = [r]
2165 revs = [r]
2158 except ValueError:
2166 except ValueError:
2159 revs = stringset(repo, subset, t)
2167 revs = stringset(repo, subset, t)
2160
2168
2161 for r in revs:
2169 for r in revs:
2162 if r in seen:
2170 if r in seen:
2163 continue
2171 continue
2164 if (r in subset
2172 if (r in subset
2165 or r == node.nullrev and isinstance(subset, fullreposet)):
2173 or r == node.nullrev and isinstance(subset, fullreposet)):
2166 ls.append(r)
2174 ls.append(r)
2167 seen.add(r)
2175 seen.add(r)
2168 return baseset(ls)
2176 return baseset(ls)
2169
2177
2170 # for internal use
2178 # for internal use
2171 @predicate('_list', safe=True, takeorder=True)
2179 @predicate('_list', safe=True, takeorder=True)
2172 def _list(repo, subset, x, order):
2180 def _list(repo, subset, x, order):
2173 if order == followorder:
2181 if order == followorder:
2174 # slow path to take the subset order
2182 # slow path to take the subset order
2175 return subset & _orderedlist(repo, fullreposet(repo), x)
2183 return subset & _orderedlist(repo, fullreposet(repo), x)
2176 else:
2184 else:
2177 return _orderedlist(repo, subset, x)
2185 return _orderedlist(repo, subset, x)
2178
2186
2179 def _orderedintlist(repo, subset, x):
2187 def _orderedintlist(repo, subset, x):
2180 s = getstring(x, "internal error")
2188 s = getstring(x, "internal error")
2181 if not s:
2189 if not s:
2182 return baseset()
2190 return baseset()
2183 ls = [int(r) for r in s.split('\0')]
2191 ls = [int(r) for r in s.split('\0')]
2184 s = subset
2192 s = subset
2185 return baseset([r for r in ls if r in s])
2193 return baseset([r for r in ls if r in s])
2186
2194
2187 # for internal use
2195 # for internal use
2188 @predicate('_intlist', safe=True, takeorder=True)
2196 @predicate('_intlist', safe=True, takeorder=True)
2189 def _intlist(repo, subset, x, order):
2197 def _intlist(repo, subset, x, order):
2190 if order == followorder:
2198 if order == followorder:
2191 # slow path to take the subset order
2199 # slow path to take the subset order
2192 return subset & _orderedintlist(repo, fullreposet(repo), x)
2200 return subset & _orderedintlist(repo, fullreposet(repo), x)
2193 else:
2201 else:
2194 return _orderedintlist(repo, subset, x)
2202 return _orderedintlist(repo, subset, x)
2195
2203
2196 def _orderedhexlist(repo, subset, x):
2204 def _orderedhexlist(repo, subset, x):
2197 s = getstring(x, "internal error")
2205 s = getstring(x, "internal error")
2198 if not s:
2206 if not s:
2199 return baseset()
2207 return baseset()
2200 cl = repo.changelog
2208 cl = repo.changelog
2201 ls = [cl.rev(node.bin(r)) for r in s.split('\0')]
2209 ls = [cl.rev(node.bin(r)) for r in s.split('\0')]
2202 s = subset
2210 s = subset
2203 return baseset([r for r in ls if r in s])
2211 return baseset([r for r in ls if r in s])
2204
2212
2205 # for internal use
2213 # for internal use
2206 @predicate('_hexlist', safe=True, takeorder=True)
2214 @predicate('_hexlist', safe=True, takeorder=True)
2207 def _hexlist(repo, subset, x, order):
2215 def _hexlist(repo, subset, x, order):
2208 if order == followorder:
2216 if order == followorder:
2209 # slow path to take the subset order
2217 # slow path to take the subset order
2210 return subset & _orderedhexlist(repo, fullreposet(repo), x)
2218 return subset & _orderedhexlist(repo, fullreposet(repo), x)
2211 else:
2219 else:
2212 return _orderedhexlist(repo, subset, x)
2220 return _orderedhexlist(repo, subset, x)
2213
2221
2214 methods = {
2222 methods = {
2215 "range": rangeset,
2223 "range": rangeset,
2216 "rangeall": rangeall,
2224 "rangeall": rangeall,
2217 "rangepre": rangepre,
2225 "rangepre": rangepre,
2218 "rangepost": rangepost,
2226 "rangepost": rangepost,
2219 "dagrange": dagrange,
2227 "dagrange": dagrange,
2220 "string": stringset,
2228 "string": stringset,
2221 "symbol": stringset,
2229 "symbol": stringset,
2222 "and": andset,
2230 "and": andset,
2223 "or": orset,
2231 "or": orset,
2224 "not": notset,
2232 "not": notset,
2225 "difference": differenceset,
2233 "difference": differenceset,
2226 "list": listset,
2234 "list": listset,
2227 "keyvalue": keyvaluepair,
2235 "keyvalue": keyvaluepair,
2228 "func": func,
2236 "func": func,
2229 "ancestor": ancestorspec,
2237 "ancestor": ancestorspec,
2230 "parent": parentspec,
2238 "parent": parentspec,
2231 "parentpost": parentpost,
2239 "parentpost": parentpost,
2232 }
2240 }
2233
2241
2234 def posttreebuilthook(tree, repo):
2242 def posttreebuilthook(tree, repo):
2235 # hook for extensions to execute code on the optimized tree
2243 # hook for extensions to execute code on the optimized tree
2236 pass
2244 pass
2237
2245
2238 def match(ui, spec, repo=None, order=defineorder):
2246 def match(ui, spec, repo=None, order=defineorder):
2239 """Create a matcher for a single revision spec
2247 """Create a matcher for a single revision spec
2240
2248
2241 If order=followorder, a matcher takes the ordering specified by the input
2249 If order=followorder, a matcher takes the ordering specified by the input
2242 set.
2250 set.
2243 """
2251 """
2244 return matchany(ui, [spec], repo=repo, order=order)
2252 return matchany(ui, [spec], repo=repo, order=order)
2245
2253
2246 def matchany(ui, specs, repo=None, order=defineorder):
2254 def matchany(ui, specs, repo=None, order=defineorder):
2247 """Create a matcher that will include any revisions matching one of the
2255 """Create a matcher that will include any revisions matching one of the
2248 given specs
2256 given specs
2249
2257
2250 If order=followorder, a matcher takes the ordering specified by the input
2258 If order=followorder, a matcher takes the ordering specified by the input
2251 set.
2259 set.
2252 """
2260 """
2253 if not specs:
2261 if not specs:
2254 def mfunc(repo, subset=None):
2262 def mfunc(repo, subset=None):
2255 return baseset()
2263 return baseset()
2256 return mfunc
2264 return mfunc
2257 if not all(specs):
2265 if not all(specs):
2258 raise error.ParseError(_("empty query"))
2266 raise error.ParseError(_("empty query"))
2259 lookup = None
2267 lookup = None
2260 if repo:
2268 if repo:
2261 lookup = repo.__contains__
2269 lookup = repo.__contains__
2262 if len(specs) == 1:
2270 if len(specs) == 1:
2263 tree = revsetlang.parse(specs[0], lookup)
2271 tree = revsetlang.parse(specs[0], lookup)
2264 else:
2272 else:
2265 tree = ('or',
2273 tree = ('or',
2266 ('list',) + tuple(revsetlang.parse(s, lookup) for s in specs))
2274 ('list',) + tuple(revsetlang.parse(s, lookup) for s in specs))
2267
2275
2268 if ui:
2276 if ui:
2269 tree = revsetlang.expandaliases(ui, tree)
2277 tree = revsetlang.expandaliases(ui, tree)
2270 tree = revsetlang.foldconcat(tree)
2278 tree = revsetlang.foldconcat(tree)
2271 tree = revsetlang.analyze(tree, order)
2279 tree = revsetlang.analyze(tree, order)
2272 tree = revsetlang.optimize(tree)
2280 tree = revsetlang.optimize(tree)
2273 posttreebuilthook(tree, repo)
2281 posttreebuilthook(tree, repo)
2274 return makematcher(tree)
2282 return makematcher(tree)
2275
2283
2276 def makematcher(tree):
2284 def makematcher(tree):
2277 """Create a matcher from an evaluatable tree"""
2285 """Create a matcher from an evaluatable tree"""
2278 def mfunc(repo, subset=None):
2286 def mfunc(repo, subset=None):
2279 if subset is None:
2287 if subset is None:
2280 subset = fullreposet(repo)
2288 subset = fullreposet(repo)
2281 return getset(repo, subset, tree)
2289 return getset(repo, subset, tree)
2282 return mfunc
2290 return mfunc
2283
2291
2284 def loadpredicate(ui, extname, registrarobj):
2292 def loadpredicate(ui, extname, registrarobj):
2285 """Load revset predicates from specified registrarobj
2293 """Load revset predicates from specified registrarobj
2286 """
2294 """
2287 for name, func in registrarobj._table.iteritems():
2295 for name, func in registrarobj._table.iteritems():
2288 symbols[name] = func
2296 symbols[name] = func
2289 if func._safe:
2297 if func._safe:
2290 safesymbols.add(name)
2298 safesymbols.add(name)
2291
2299
2292 # load built-in predicates explicitly to setup safesymbols
2300 # load built-in predicates explicitly to setup safesymbols
2293 loadpredicate(None, None, predicate)
2301 loadpredicate(None, None, predicate)
2294
2302
2295 # tell hggettext to extract docstrings from these functions:
2303 # tell hggettext to extract docstrings from these functions:
2296 i18nfunctions = symbols.values()
2304 i18nfunctions = symbols.values()
@@ -1,3729 +1,3735 b''
1 $ HGENCODING=utf-8
1 $ HGENCODING=utf-8
2 $ export HGENCODING
2 $ export HGENCODING
3 $ cat > testrevset.py << EOF
3 $ cat > testrevset.py << EOF
4 > import mercurial.revset
4 > import mercurial.revset
5 >
5 >
6 > baseset = mercurial.revset.baseset
6 > baseset = mercurial.revset.baseset
7 >
7 >
8 > def r3232(repo, subset, x):
8 > def r3232(repo, subset, x):
9 > """"simple revset that return [3,2,3,2]
9 > """"simple revset that return [3,2,3,2]
10 >
10 >
11 > revisions duplicated on purpose.
11 > revisions duplicated on purpose.
12 > """
12 > """
13 > if 3 not in subset:
13 > if 3 not in subset:
14 > if 2 in subset:
14 > if 2 in subset:
15 > return baseset([2,2])
15 > return baseset([2,2])
16 > return baseset()
16 > return baseset()
17 > return baseset([3,3,2,2])
17 > return baseset([3,3,2,2])
18 >
18 >
19 > mercurial.revset.symbols['r3232'] = r3232
19 > mercurial.revset.symbols['r3232'] = r3232
20 > EOF
20 > EOF
21 $ cat >> $HGRCPATH << EOF
21 $ cat >> $HGRCPATH << EOF
22 > [extensions]
22 > [extensions]
23 > testrevset=$TESTTMP/testrevset.py
23 > testrevset=$TESTTMP/testrevset.py
24 > EOF
24 > EOF
25
25
26 $ try() {
26 $ try() {
27 > hg debugrevspec --debug "$@"
27 > hg debugrevspec --debug "$@"
28 > }
28 > }
29
29
30 $ log() {
30 $ log() {
31 > hg log --template '{rev}\n' -r "$1"
31 > hg log --template '{rev}\n' -r "$1"
32 > }
32 > }
33
33
34 extension to build '_intlist()' and '_hexlist()', which is necessary because
34 extension to build '_intlist()' and '_hexlist()', which is necessary because
35 these predicates use '\0' as a separator:
35 these predicates use '\0' as a separator:
36
36
37 $ cat <<EOF > debugrevlistspec.py
37 $ cat <<EOF > debugrevlistspec.py
38 > from __future__ import absolute_import
38 > from __future__ import absolute_import
39 > from mercurial import (
39 > from mercurial import (
40 > node as nodemod,
40 > node as nodemod,
41 > registrar,
41 > registrar,
42 > revset,
42 > revset,
43 > revsetlang,
43 > revsetlang,
44 > smartset,
44 > smartset,
45 > )
45 > )
46 > cmdtable = {}
46 > cmdtable = {}
47 > command = registrar.command(cmdtable)
47 > command = registrar.command(cmdtable)
48 > @command('debugrevlistspec',
48 > @command('debugrevlistspec',
49 > [('', 'optimize', None, 'print parsed tree after optimizing'),
49 > [('', 'optimize', None, 'print parsed tree after optimizing'),
50 > ('', 'bin', None, 'unhexlify arguments')])
50 > ('', 'bin', None, 'unhexlify arguments')])
51 > def debugrevlistspec(ui, repo, fmt, *args, **opts):
51 > def debugrevlistspec(ui, repo, fmt, *args, **opts):
52 > if opts['bin']:
52 > if opts['bin']:
53 > args = map(nodemod.bin, args)
53 > args = map(nodemod.bin, args)
54 > expr = revsetlang.formatspec(fmt, list(args))
54 > expr = revsetlang.formatspec(fmt, list(args))
55 > if ui.verbose:
55 > if ui.verbose:
56 > tree = revsetlang.parse(expr, lookup=repo.__contains__)
56 > tree = revsetlang.parse(expr, lookup=repo.__contains__)
57 > ui.note(revsetlang.prettyformat(tree), "\n")
57 > ui.note(revsetlang.prettyformat(tree), "\n")
58 > if opts["optimize"]:
58 > if opts["optimize"]:
59 > opttree = revsetlang.optimize(revsetlang.analyze(tree))
59 > opttree = revsetlang.optimize(revsetlang.analyze(tree))
60 > ui.note("* optimized:\n", revsetlang.prettyformat(opttree),
60 > ui.note("* optimized:\n", revsetlang.prettyformat(opttree),
61 > "\n")
61 > "\n")
62 > func = revset.match(ui, expr, repo)
62 > func = revset.match(ui, expr, repo)
63 > revs = func(repo)
63 > revs = func(repo)
64 > if ui.verbose:
64 > if ui.verbose:
65 > ui.note("* set:\n", smartset.prettyformat(revs), "\n")
65 > ui.note("* set:\n", smartset.prettyformat(revs), "\n")
66 > for c in revs:
66 > for c in revs:
67 > ui.write("%s\n" % c)
67 > ui.write("%s\n" % c)
68 > EOF
68 > EOF
69 $ cat <<EOF >> $HGRCPATH
69 $ cat <<EOF >> $HGRCPATH
70 > [extensions]
70 > [extensions]
71 > debugrevlistspec = $TESTTMP/debugrevlistspec.py
71 > debugrevlistspec = $TESTTMP/debugrevlistspec.py
72 > EOF
72 > EOF
73 $ trylist() {
73 $ trylist() {
74 > hg debugrevlistspec --debug "$@"
74 > hg debugrevlistspec --debug "$@"
75 > }
75 > }
76
76
77 $ hg init repo
77 $ hg init repo
78 $ cd repo
78 $ cd repo
79
79
80 $ echo a > a
80 $ echo a > a
81 $ hg branch a
81 $ hg branch a
82 marked working directory as branch a
82 marked working directory as branch a
83 (branches are permanent and global, did you want a bookmark?)
83 (branches are permanent and global, did you want a bookmark?)
84 $ hg ci -Aqm0
84 $ hg ci -Aqm0
85
85
86 $ echo b > b
86 $ echo b > b
87 $ hg branch b
87 $ hg branch b
88 marked working directory as branch b
88 marked working directory as branch b
89 $ hg ci -Aqm1
89 $ hg ci -Aqm1
90
90
91 $ rm a
91 $ rm a
92 $ hg branch a-b-c-
92 $ hg branch a-b-c-
93 marked working directory as branch a-b-c-
93 marked working directory as branch a-b-c-
94 $ hg ci -Aqm2 -u Bob
94 $ hg ci -Aqm2 -u Bob
95
95
96 $ hg log -r "extra('branch', 'a-b-c-')" --template '{rev}\n'
96 $ hg log -r "extra('branch', 'a-b-c-')" --template '{rev}\n'
97 2
97 2
98 $ hg log -r "extra('branch')" --template '{rev}\n'
98 $ hg log -r "extra('branch')" --template '{rev}\n'
99 0
99 0
100 1
100 1
101 2
101 2
102 $ hg log -r "extra('branch', 're:a')" --template '{rev} {branch}\n'
102 $ hg log -r "extra('branch', 're:a')" --template '{rev} {branch}\n'
103 0 a
103 0 a
104 2 a-b-c-
104 2 a-b-c-
105
105
106 $ hg co 1
106 $ hg co 1
107 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
107 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
108 $ hg branch +a+b+c+
108 $ hg branch +a+b+c+
109 marked working directory as branch +a+b+c+
109 marked working directory as branch +a+b+c+
110 $ hg ci -Aqm3
110 $ hg ci -Aqm3
111
111
112 $ hg co 2 # interleave
112 $ hg co 2 # interleave
113 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
113 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
114 $ echo bb > b
114 $ echo bb > b
115 $ hg branch -- -a-b-c-
115 $ hg branch -- -a-b-c-
116 marked working directory as branch -a-b-c-
116 marked working directory as branch -a-b-c-
117 $ hg ci -Aqm4 -d "May 12 2005"
117 $ hg ci -Aqm4 -d "May 12 2005"
118
118
119 $ hg co 3
119 $ hg co 3
120 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
120 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
121 $ hg branch !a/b/c/
121 $ hg branch !a/b/c/
122 marked working directory as branch !a/b/c/
122 marked working directory as branch !a/b/c/
123 $ hg ci -Aqm"5 bug"
123 $ hg ci -Aqm"5 bug"
124
124
125 $ hg merge 4
125 $ hg merge 4
126 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
126 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
127 (branch merge, don't forget to commit)
127 (branch merge, don't forget to commit)
128 $ hg branch _a_b_c_
128 $ hg branch _a_b_c_
129 marked working directory as branch _a_b_c_
129 marked working directory as branch _a_b_c_
130 $ hg ci -Aqm"6 issue619"
130 $ hg ci -Aqm"6 issue619"
131
131
132 $ hg branch .a.b.c.
132 $ hg branch .a.b.c.
133 marked working directory as branch .a.b.c.
133 marked working directory as branch .a.b.c.
134 $ hg ci -Aqm7
134 $ hg ci -Aqm7
135
135
136 $ hg branch all
136 $ hg branch all
137 marked working directory as branch all
137 marked working directory as branch all
138
138
139 $ hg co 4
139 $ hg co 4
140 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
140 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
141 $ hg branch Γ©
141 $ hg branch Γ©
142 marked working directory as branch \xc3\xa9 (esc)
142 marked working directory as branch \xc3\xa9 (esc)
143 $ hg ci -Aqm9
143 $ hg ci -Aqm9
144
144
145 $ hg tag -r6 1.0
145 $ hg tag -r6 1.0
146 $ hg bookmark -r6 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
146 $ hg bookmark -r6 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
147
147
148 $ hg clone --quiet -U -r 7 . ../remote1
148 $ hg clone --quiet -U -r 7 . ../remote1
149 $ hg clone --quiet -U -r 8 . ../remote2
149 $ hg clone --quiet -U -r 8 . ../remote2
150 $ echo "[paths]" >> .hg/hgrc
150 $ echo "[paths]" >> .hg/hgrc
151 $ echo "default = ../remote1" >> .hg/hgrc
151 $ echo "default = ../remote1" >> .hg/hgrc
152
152
153 trivial
153 trivial
154
154
155 $ try 0:1
155 $ try 0:1
156 (range
156 (range
157 ('symbol', '0')
157 ('symbol', '0')
158 ('symbol', '1'))
158 ('symbol', '1'))
159 * set:
159 * set:
160 <spanset+ 0:1>
160 <spanset+ 0:1>
161 0
161 0
162 1
162 1
163 $ try --optimize :
163 $ try --optimize :
164 (rangeall
164 (rangeall
165 None)
165 None)
166 * optimized:
166 * optimized:
167 (rangeall
167 (rangeall
168 None
168 None
169 define)
169 define)
170 * set:
170 * set:
171 <spanset+ 0:9>
171 <spanset+ 0:9>
172 0
172 0
173 1
173 1
174 2
174 2
175 3
175 3
176 4
176 4
177 5
177 5
178 6
178 6
179 7
179 7
180 8
180 8
181 9
181 9
182 $ try 3::6
182 $ try 3::6
183 (dagrange
183 (dagrange
184 ('symbol', '3')
184 ('symbol', '3')
185 ('symbol', '6'))
185 ('symbol', '6'))
186 * set:
186 * set:
187 <baseset+ [3, 5, 6]>
187 <baseset+ [3, 5, 6]>
188 3
188 3
189 5
189 5
190 6
190 6
191 $ try '0|1|2'
191 $ try '0|1|2'
192 (or
192 (or
193 (list
193 (list
194 ('symbol', '0')
194 ('symbol', '0')
195 ('symbol', '1')
195 ('symbol', '1')
196 ('symbol', '2')))
196 ('symbol', '2')))
197 * set:
197 * set:
198 <baseset [0, 1, 2]>
198 <baseset [0, 1, 2]>
199 0
199 0
200 1
200 1
201 2
201 2
202
202
203 names that should work without quoting
203 names that should work without quoting
204
204
205 $ try a
205 $ try a
206 ('symbol', 'a')
206 ('symbol', 'a')
207 * set:
207 * set:
208 <baseset [0]>
208 <baseset [0]>
209 0
209 0
210 $ try b-a
210 $ try b-a
211 (minus
211 (minus
212 ('symbol', 'b')
212 ('symbol', 'b')
213 ('symbol', 'a'))
213 ('symbol', 'a'))
214 * set:
214 * set:
215 <filteredset
215 <filteredset
216 <baseset [1]>,
216 <baseset [1]>,
217 <not
217 <not
218 <baseset [0]>>>
218 <baseset [0]>>>
219 1
219 1
220 $ try _a_b_c_
220 $ try _a_b_c_
221 ('symbol', '_a_b_c_')
221 ('symbol', '_a_b_c_')
222 * set:
222 * set:
223 <baseset [6]>
223 <baseset [6]>
224 6
224 6
225 $ try _a_b_c_-a
225 $ try _a_b_c_-a
226 (minus
226 (minus
227 ('symbol', '_a_b_c_')
227 ('symbol', '_a_b_c_')
228 ('symbol', 'a'))
228 ('symbol', 'a'))
229 * set:
229 * set:
230 <filteredset
230 <filteredset
231 <baseset [6]>,
231 <baseset [6]>,
232 <not
232 <not
233 <baseset [0]>>>
233 <baseset [0]>>>
234 6
234 6
235 $ try .a.b.c.
235 $ try .a.b.c.
236 ('symbol', '.a.b.c.')
236 ('symbol', '.a.b.c.')
237 * set:
237 * set:
238 <baseset [7]>
238 <baseset [7]>
239 7
239 7
240 $ try .a.b.c.-a
240 $ try .a.b.c.-a
241 (minus
241 (minus
242 ('symbol', '.a.b.c.')
242 ('symbol', '.a.b.c.')
243 ('symbol', 'a'))
243 ('symbol', 'a'))
244 * set:
244 * set:
245 <filteredset
245 <filteredset
246 <baseset [7]>,
246 <baseset [7]>,
247 <not
247 <not
248 <baseset [0]>>>
248 <baseset [0]>>>
249 7
249 7
250
250
251 names that should be caught by fallback mechanism
251 names that should be caught by fallback mechanism
252
252
253 $ try -- '-a-b-c-'
253 $ try -- '-a-b-c-'
254 ('symbol', '-a-b-c-')
254 ('symbol', '-a-b-c-')
255 * set:
255 * set:
256 <baseset [4]>
256 <baseset [4]>
257 4
257 4
258 $ log -a-b-c-
258 $ log -a-b-c-
259 4
259 4
260 $ try '+a+b+c+'
260 $ try '+a+b+c+'
261 ('symbol', '+a+b+c+')
261 ('symbol', '+a+b+c+')
262 * set:
262 * set:
263 <baseset [3]>
263 <baseset [3]>
264 3
264 3
265 $ try '+a+b+c+:'
265 $ try '+a+b+c+:'
266 (rangepost
266 (rangepost
267 ('symbol', '+a+b+c+'))
267 ('symbol', '+a+b+c+'))
268 * set:
268 * set:
269 <spanset+ 3:9>
269 <spanset+ 3:9>
270 3
270 3
271 4
271 4
272 5
272 5
273 6
273 6
274 7
274 7
275 8
275 8
276 9
276 9
277 $ try ':+a+b+c+'
277 $ try ':+a+b+c+'
278 (rangepre
278 (rangepre
279 ('symbol', '+a+b+c+'))
279 ('symbol', '+a+b+c+'))
280 * set:
280 * set:
281 <spanset+ 0:3>
281 <spanset+ 0:3>
282 0
282 0
283 1
283 1
284 2
284 2
285 3
285 3
286 $ try -- '-a-b-c-:+a+b+c+'
286 $ try -- '-a-b-c-:+a+b+c+'
287 (range
287 (range
288 ('symbol', '-a-b-c-')
288 ('symbol', '-a-b-c-')
289 ('symbol', '+a+b+c+'))
289 ('symbol', '+a+b+c+'))
290 * set:
290 * set:
291 <spanset- 3:4>
291 <spanset- 3:4>
292 4
292 4
293 3
293 3
294 $ log '-a-b-c-:+a+b+c+'
294 $ log '-a-b-c-:+a+b+c+'
295 4
295 4
296 3
296 3
297
297
298 $ try -- -a-b-c--a # complains
298 $ try -- -a-b-c--a # complains
299 (minus
299 (minus
300 (minus
300 (minus
301 (minus
301 (minus
302 (negate
302 (negate
303 ('symbol', 'a'))
303 ('symbol', 'a'))
304 ('symbol', 'b'))
304 ('symbol', 'b'))
305 ('symbol', 'c'))
305 ('symbol', 'c'))
306 (negate
306 (negate
307 ('symbol', 'a')))
307 ('symbol', 'a')))
308 abort: unknown revision '-a'!
308 abort: unknown revision '-a'!
309 [255]
309 [255]
310 $ try Γ©
310 $ try Γ©
311 ('symbol', '\xc3\xa9')
311 ('symbol', '\xc3\xa9')
312 * set:
312 * set:
313 <baseset [9]>
313 <baseset [9]>
314 9
314 9
315
315
316 no quoting needed
316 no quoting needed
317
317
318 $ log ::a-b-c-
318 $ log ::a-b-c-
319 0
319 0
320 1
320 1
321 2
321 2
322
322
323 quoting needed
323 quoting needed
324
324
325 $ try '"-a-b-c-"-a'
325 $ try '"-a-b-c-"-a'
326 (minus
326 (minus
327 ('string', '-a-b-c-')
327 ('string', '-a-b-c-')
328 ('symbol', 'a'))
328 ('symbol', 'a'))
329 * set:
329 * set:
330 <filteredset
330 <filteredset
331 <baseset [4]>,
331 <baseset [4]>,
332 <not
332 <not
333 <baseset [0]>>>
333 <baseset [0]>>>
334 4
334 4
335
335
336 $ log '1 or 2'
336 $ log '1 or 2'
337 1
337 1
338 2
338 2
339 $ log '1|2'
339 $ log '1|2'
340 1
340 1
341 2
341 2
342 $ log '1 and 2'
342 $ log '1 and 2'
343 $ log '1&2'
343 $ log '1&2'
344 $ try '1&2|3' # precedence - and is higher
344 $ try '1&2|3' # precedence - and is higher
345 (or
345 (or
346 (list
346 (list
347 (and
347 (and
348 ('symbol', '1')
348 ('symbol', '1')
349 ('symbol', '2'))
349 ('symbol', '2'))
350 ('symbol', '3')))
350 ('symbol', '3')))
351 * set:
351 * set:
352 <addset
352 <addset
353 <baseset []>,
353 <baseset []>,
354 <baseset [3]>>
354 <baseset [3]>>
355 3
355 3
356 $ try '1|2&3'
356 $ try '1|2&3'
357 (or
357 (or
358 (list
358 (list
359 ('symbol', '1')
359 ('symbol', '1')
360 (and
360 (and
361 ('symbol', '2')
361 ('symbol', '2')
362 ('symbol', '3'))))
362 ('symbol', '3'))))
363 * set:
363 * set:
364 <addset
364 <addset
365 <baseset [1]>,
365 <baseset [1]>,
366 <baseset []>>
366 <baseset []>>
367 1
367 1
368 $ try '1&2&3' # associativity
368 $ try '1&2&3' # associativity
369 (and
369 (and
370 (and
370 (and
371 ('symbol', '1')
371 ('symbol', '1')
372 ('symbol', '2'))
372 ('symbol', '2'))
373 ('symbol', '3'))
373 ('symbol', '3'))
374 * set:
374 * set:
375 <baseset []>
375 <baseset []>
376 $ try '1|(2|3)'
376 $ try '1|(2|3)'
377 (or
377 (or
378 (list
378 (list
379 ('symbol', '1')
379 ('symbol', '1')
380 (group
380 (group
381 (or
381 (or
382 (list
382 (list
383 ('symbol', '2')
383 ('symbol', '2')
384 ('symbol', '3'))))))
384 ('symbol', '3'))))))
385 * set:
385 * set:
386 <addset
386 <addset
387 <baseset [1]>,
387 <baseset [1]>,
388 <baseset [2, 3]>>
388 <baseset [2, 3]>>
389 1
389 1
390 2
390 2
391 3
391 3
392 $ log '1.0' # tag
392 $ log '1.0' # tag
393 6
393 6
394 $ log 'a' # branch
394 $ log 'a' # branch
395 0
395 0
396 $ log '2785f51ee'
396 $ log '2785f51ee'
397 0
397 0
398 $ log 'date(2005)'
398 $ log 'date(2005)'
399 4
399 4
400 $ log 'date(this is a test)'
400 $ log 'date(this is a test)'
401 hg: parse error at 10: unexpected token: symbol
401 hg: parse error at 10: unexpected token: symbol
402 [255]
402 [255]
403 $ log 'date()'
403 $ log 'date()'
404 hg: parse error: date requires a string
404 hg: parse error: date requires a string
405 [255]
405 [255]
406 $ log 'date'
406 $ log 'date'
407 abort: unknown revision 'date'!
407 abort: unknown revision 'date'!
408 [255]
408 [255]
409 $ log 'date('
409 $ log 'date('
410 hg: parse error at 5: not a prefix: end
410 hg: parse error at 5: not a prefix: end
411 [255]
411 [255]
412 $ log 'date("\xy")'
412 $ log 'date("\xy")'
413 hg: parse error: invalid \x escape
413 hg: parse error: invalid \x escape
414 [255]
414 [255]
415 $ log 'date(tip)'
415 $ log 'date(tip)'
416 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()^1'
1231 7
1232 $ hg debugrevspec 'wdir()^2'
1233 $ hg debugrevspec 'wdir()^3'
1234 hg: parse error: ^ expects a number 0, 1, or 2
1235 [255]
1230 For tests consistency
1236 For tests consistency
1231 $ hg up 9
1237 $ hg up 9
1232 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1238 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1233 $ hg debugrevspec 'tip or wdir()'
1239 $ hg debugrevspec 'tip or wdir()'
1234 9
1240 9
1235 2147483647
1241 2147483647
1236 $ hg debugrevspec '0:tip and wdir()'
1242 $ hg debugrevspec '0:tip and wdir()'
1237 $ log '0:wdir()' | tail -3
1243 $ log '0:wdir()' | tail -3
1238 8
1244 8
1239 9
1245 9
1240 2147483647
1246 2147483647
1241 $ log 'wdir():0' | head -3
1247 $ log 'wdir():0' | head -3
1242 2147483647
1248 2147483647
1243 9
1249 9
1244 8
1250 8
1245 $ log 'wdir():wdir()'
1251 $ log 'wdir():wdir()'
1246 2147483647
1252 2147483647
1247 $ log '(all() + wdir()) & min(. + wdir())'
1253 $ log '(all() + wdir()) & min(. + wdir())'
1248 9
1254 9
1249 $ log '(all() + wdir()) & max(. + wdir())'
1255 $ log '(all() + wdir()) & max(. + wdir())'
1250 2147483647
1256 2147483647
1251 $ log '(all() + wdir()) & first(wdir() + .)'
1257 $ log '(all() + wdir()) & first(wdir() + .)'
1252 2147483647
1258 2147483647
1253 $ log '(all() + wdir()) & last(. + wdir())'
1259 $ log '(all() + wdir()) & last(. + wdir())'
1254 2147483647
1260 2147483647
1255
1261
1256 $ log 'outgoing()'
1262 $ log 'outgoing()'
1257 8
1263 8
1258 9
1264 9
1259 $ log 'outgoing("../remote1")'
1265 $ log 'outgoing("../remote1")'
1260 8
1266 8
1261 9
1267 9
1262 $ log 'outgoing("../remote2")'
1268 $ log 'outgoing("../remote2")'
1263 3
1269 3
1264 5
1270 5
1265 6
1271 6
1266 7
1272 7
1267 9
1273 9
1268 $ log 'p1(merge())'
1274 $ log 'p1(merge())'
1269 5
1275 5
1270 $ log 'p2(merge())'
1276 $ log 'p2(merge())'
1271 4
1277 4
1272 $ log 'parents(merge())'
1278 $ log 'parents(merge())'
1273 4
1279 4
1274 5
1280 5
1275 $ log 'p1(branchpoint())'
1281 $ log 'p1(branchpoint())'
1276 0
1282 0
1277 2
1283 2
1278 $ log 'p2(branchpoint())'
1284 $ log 'p2(branchpoint())'
1279 $ log 'parents(branchpoint())'
1285 $ log 'parents(branchpoint())'
1280 0
1286 0
1281 2
1287 2
1282 $ log 'removes(a)'
1288 $ log 'removes(a)'
1283 2
1289 2
1284 6
1290 6
1285 $ log 'roots(all())'
1291 $ log 'roots(all())'
1286 0
1292 0
1287 $ log 'reverse(2 or 3 or 4 or 5)'
1293 $ log 'reverse(2 or 3 or 4 or 5)'
1288 5
1294 5
1289 4
1295 4
1290 3
1296 3
1291 2
1297 2
1292 $ log 'reverse(all())'
1298 $ log 'reverse(all())'
1293 9
1299 9
1294 8
1300 8
1295 7
1301 7
1296 6
1302 6
1297 5
1303 5
1298 4
1304 4
1299 3
1305 3
1300 2
1306 2
1301 1
1307 1
1302 0
1308 0
1303 $ log 'reverse(all()) & filelog(b)'
1309 $ log 'reverse(all()) & filelog(b)'
1304 4
1310 4
1305 1
1311 1
1306 $ log 'rev(5)'
1312 $ log 'rev(5)'
1307 5
1313 5
1308 $ log 'sort(limit(reverse(all()), 3))'
1314 $ log 'sort(limit(reverse(all()), 3))'
1309 7
1315 7
1310 8
1316 8
1311 9
1317 9
1312 $ log 'sort(2 or 3 or 4 or 5, date)'
1318 $ log 'sort(2 or 3 or 4 or 5, date)'
1313 2
1319 2
1314 3
1320 3
1315 5
1321 5
1316 4
1322 4
1317 $ log 'tagged()'
1323 $ log 'tagged()'
1318 6
1324 6
1319 $ log 'tag()'
1325 $ log 'tag()'
1320 6
1326 6
1321 $ log 'tag(1.0)'
1327 $ log 'tag(1.0)'
1322 6
1328 6
1323 $ log 'tag(tip)'
1329 $ log 'tag(tip)'
1324 9
1330 9
1325
1331
1326 Test order of revisions in compound expression
1332 Test order of revisions in compound expression
1327 ----------------------------------------------
1333 ----------------------------------------------
1328
1334
1329 The general rule is that only the outermost (= leftmost) predicate can
1335 The general rule is that only the outermost (= leftmost) predicate can
1330 enforce its ordering requirement. The other predicates should take the
1336 enforce its ordering requirement. The other predicates should take the
1331 ordering defined by it.
1337 ordering defined by it.
1332
1338
1333 'A & B' should follow the order of 'A':
1339 'A & B' should follow the order of 'A':
1334
1340
1335 $ log '2:0 & 0::2'
1341 $ log '2:0 & 0::2'
1336 2
1342 2
1337 1
1343 1
1338 0
1344 0
1339
1345
1340 'head()' combines sets in right order:
1346 'head()' combines sets in right order:
1341
1347
1342 $ log '2:0 & head()'
1348 $ log '2:0 & head()'
1343 2
1349 2
1344 1
1350 1
1345 0
1351 0
1346
1352
1347 'x:y' takes ordering parameter into account:
1353 'x:y' takes ordering parameter into account:
1348
1354
1349 $ try -p optimized '3:0 & 0:3 & not 2:1'
1355 $ try -p optimized '3:0 & 0:3 & not 2:1'
1350 * optimized:
1356 * optimized:
1351 (difference
1357 (difference
1352 (and
1358 (and
1353 (range
1359 (range
1354 ('symbol', '3')
1360 ('symbol', '3')
1355 ('symbol', '0')
1361 ('symbol', '0')
1356 define)
1362 define)
1357 (range
1363 (range
1358 ('symbol', '0')
1364 ('symbol', '0')
1359 ('symbol', '3')
1365 ('symbol', '3')
1360 follow)
1366 follow)
1361 define)
1367 define)
1362 (range
1368 (range
1363 ('symbol', '2')
1369 ('symbol', '2')
1364 ('symbol', '1')
1370 ('symbol', '1')
1365 any)
1371 any)
1366 define)
1372 define)
1367 * set:
1373 * set:
1368 <filteredset
1374 <filteredset
1369 <filteredset
1375 <filteredset
1370 <spanset- 0:3>,
1376 <spanset- 0:3>,
1371 <spanset+ 0:3>>,
1377 <spanset+ 0:3>>,
1372 <not
1378 <not
1373 <spanset+ 1:2>>>
1379 <spanset+ 1:2>>>
1374 3
1380 3
1375 0
1381 0
1376
1382
1377 'a + b', which is optimized to '_list(a b)', should take the ordering of
1383 'a + b', which is optimized to '_list(a b)', should take the ordering of
1378 the left expression:
1384 the left expression:
1379
1385
1380 $ try --optimize '2:0 & (0 + 1 + 2)'
1386 $ try --optimize '2:0 & (0 + 1 + 2)'
1381 (and
1387 (and
1382 (range
1388 (range
1383 ('symbol', '2')
1389 ('symbol', '2')
1384 ('symbol', '0'))
1390 ('symbol', '0'))
1385 (group
1391 (group
1386 (or
1392 (or
1387 (list
1393 (list
1388 ('symbol', '0')
1394 ('symbol', '0')
1389 ('symbol', '1')
1395 ('symbol', '1')
1390 ('symbol', '2')))))
1396 ('symbol', '2')))))
1391 * optimized:
1397 * optimized:
1392 (and
1398 (and
1393 (range
1399 (range
1394 ('symbol', '2')
1400 ('symbol', '2')
1395 ('symbol', '0')
1401 ('symbol', '0')
1396 define)
1402 define)
1397 (func
1403 (func
1398 ('symbol', '_list')
1404 ('symbol', '_list')
1399 ('string', '0\x001\x002')
1405 ('string', '0\x001\x002')
1400 follow)
1406 follow)
1401 define)
1407 define)
1402 * set:
1408 * set:
1403 <filteredset
1409 <filteredset
1404 <spanset- 0:2>,
1410 <spanset- 0:2>,
1405 <baseset [0, 1, 2]>>
1411 <baseset [0, 1, 2]>>
1406 2
1412 2
1407 1
1413 1
1408 0
1414 0
1409
1415
1410 'A + B' should take the ordering of the left expression:
1416 'A + B' should take the ordering of the left expression:
1411
1417
1412 $ try --optimize '2:0 & (0:1 + 2)'
1418 $ try --optimize '2:0 & (0:1 + 2)'
1413 (and
1419 (and
1414 (range
1420 (range
1415 ('symbol', '2')
1421 ('symbol', '2')
1416 ('symbol', '0'))
1422 ('symbol', '0'))
1417 (group
1423 (group
1418 (or
1424 (or
1419 (list
1425 (list
1420 (range
1426 (range
1421 ('symbol', '0')
1427 ('symbol', '0')
1422 ('symbol', '1'))
1428 ('symbol', '1'))
1423 ('symbol', '2')))))
1429 ('symbol', '2')))))
1424 * optimized:
1430 * optimized:
1425 (and
1431 (and
1426 (range
1432 (range
1427 ('symbol', '2')
1433 ('symbol', '2')
1428 ('symbol', '0')
1434 ('symbol', '0')
1429 define)
1435 define)
1430 (or
1436 (or
1431 (list
1437 (list
1432 ('symbol', '2')
1438 ('symbol', '2')
1433 (range
1439 (range
1434 ('symbol', '0')
1440 ('symbol', '0')
1435 ('symbol', '1')
1441 ('symbol', '1')
1436 follow))
1442 follow))
1437 follow)
1443 follow)
1438 define)
1444 define)
1439 * set:
1445 * set:
1440 <filteredset
1446 <filteredset
1441 <spanset- 0:2>,
1447 <spanset- 0:2>,
1442 <addset
1448 <addset
1443 <baseset [2]>,
1449 <baseset [2]>,
1444 <spanset+ 0:1>>>
1450 <spanset+ 0:1>>>
1445 2
1451 2
1446 1
1452 1
1447 0
1453 0
1448
1454
1449 '_intlist(a b)' should behave like 'a + b':
1455 '_intlist(a b)' should behave like 'a + b':
1450
1456
1451 $ trylist --optimize '2:0 & %ld' 0 1 2
1457 $ trylist --optimize '2:0 & %ld' 0 1 2
1452 (and
1458 (and
1453 (range
1459 (range
1454 ('symbol', '2')
1460 ('symbol', '2')
1455 ('symbol', '0'))
1461 ('symbol', '0'))
1456 (func
1462 (func
1457 ('symbol', '_intlist')
1463 ('symbol', '_intlist')
1458 ('string', '0\x001\x002')))
1464 ('string', '0\x001\x002')))
1459 * optimized:
1465 * optimized:
1460 (and
1466 (and
1461 (func
1467 (func
1462 ('symbol', '_intlist')
1468 ('symbol', '_intlist')
1463 ('string', '0\x001\x002')
1469 ('string', '0\x001\x002')
1464 follow)
1470 follow)
1465 (range
1471 (range
1466 ('symbol', '2')
1472 ('symbol', '2')
1467 ('symbol', '0')
1473 ('symbol', '0')
1468 define)
1474 define)
1469 define)
1475 define)
1470 * set:
1476 * set:
1471 <filteredset
1477 <filteredset
1472 <spanset- 0:2>,
1478 <spanset- 0:2>,
1473 <baseset+ [0, 1, 2]>>
1479 <baseset+ [0, 1, 2]>>
1474 2
1480 2
1475 1
1481 1
1476 0
1482 0
1477
1483
1478 $ trylist --optimize '%ld & 2:0' 0 2 1
1484 $ trylist --optimize '%ld & 2:0' 0 2 1
1479 (and
1485 (and
1480 (func
1486 (func
1481 ('symbol', '_intlist')
1487 ('symbol', '_intlist')
1482 ('string', '0\x002\x001'))
1488 ('string', '0\x002\x001'))
1483 (range
1489 (range
1484 ('symbol', '2')
1490 ('symbol', '2')
1485 ('symbol', '0')))
1491 ('symbol', '0')))
1486 * optimized:
1492 * optimized:
1487 (and
1493 (and
1488 (func
1494 (func
1489 ('symbol', '_intlist')
1495 ('symbol', '_intlist')
1490 ('string', '0\x002\x001')
1496 ('string', '0\x002\x001')
1491 define)
1497 define)
1492 (range
1498 (range
1493 ('symbol', '2')
1499 ('symbol', '2')
1494 ('symbol', '0')
1500 ('symbol', '0')
1495 follow)
1501 follow)
1496 define)
1502 define)
1497 * set:
1503 * set:
1498 <filteredset
1504 <filteredset
1499 <baseset [0, 2, 1]>,
1505 <baseset [0, 2, 1]>,
1500 <spanset- 0:2>>
1506 <spanset- 0:2>>
1501 0
1507 0
1502 2
1508 2
1503 1
1509 1
1504
1510
1505 '_hexlist(a b)' should behave like 'a + b':
1511 '_hexlist(a b)' should behave like 'a + b':
1506
1512
1507 $ trylist --optimize --bin '2:0 & %ln' `hg log -T '{node} ' -r0:2`
1513 $ trylist --optimize --bin '2:0 & %ln' `hg log -T '{node} ' -r0:2`
1508 (and
1514 (and
1509 (range
1515 (range
1510 ('symbol', '2')
1516 ('symbol', '2')
1511 ('symbol', '0'))
1517 ('symbol', '0'))
1512 (func
1518 (func
1513 ('symbol', '_hexlist')
1519 ('symbol', '_hexlist')
1514 ('string', '*'))) (glob)
1520 ('string', '*'))) (glob)
1515 * optimized:
1521 * optimized:
1516 (and
1522 (and
1517 (range
1523 (range
1518 ('symbol', '2')
1524 ('symbol', '2')
1519 ('symbol', '0')
1525 ('symbol', '0')
1520 define)
1526 define)
1521 (func
1527 (func
1522 ('symbol', '_hexlist')
1528 ('symbol', '_hexlist')
1523 ('string', '*') (glob)
1529 ('string', '*') (glob)
1524 follow)
1530 follow)
1525 define)
1531 define)
1526 * set:
1532 * set:
1527 <filteredset
1533 <filteredset
1528 <spanset- 0:2>,
1534 <spanset- 0:2>,
1529 <baseset [0, 1, 2]>>
1535 <baseset [0, 1, 2]>>
1530 2
1536 2
1531 1
1537 1
1532 0
1538 0
1533
1539
1534 $ trylist --optimize --bin '%ln & 2:0' `hg log -T '{node} ' -r0+2+1`
1540 $ trylist --optimize --bin '%ln & 2:0' `hg log -T '{node} ' -r0+2+1`
1535 (and
1541 (and
1536 (func
1542 (func
1537 ('symbol', '_hexlist')
1543 ('symbol', '_hexlist')
1538 ('string', '*')) (glob)
1544 ('string', '*')) (glob)
1539 (range
1545 (range
1540 ('symbol', '2')
1546 ('symbol', '2')
1541 ('symbol', '0')))
1547 ('symbol', '0')))
1542 * optimized:
1548 * optimized:
1543 (and
1549 (and
1544 (range
1550 (range
1545 ('symbol', '2')
1551 ('symbol', '2')
1546 ('symbol', '0')
1552 ('symbol', '0')
1547 follow)
1553 follow)
1548 (func
1554 (func
1549 ('symbol', '_hexlist')
1555 ('symbol', '_hexlist')
1550 ('string', '*') (glob)
1556 ('string', '*') (glob)
1551 define)
1557 define)
1552 define)
1558 define)
1553 * set:
1559 * set:
1554 <baseset [0, 2, 1]>
1560 <baseset [0, 2, 1]>
1555 0
1561 0
1556 2
1562 2
1557 1
1563 1
1558
1564
1559 '_list' should not go through the slow follow-order path if order doesn't
1565 '_list' should not go through the slow follow-order path if order doesn't
1560 matter:
1566 matter:
1561
1567
1562 $ try -p optimized '2:0 & not (0 + 1)'
1568 $ try -p optimized '2:0 & not (0 + 1)'
1563 * optimized:
1569 * optimized:
1564 (difference
1570 (difference
1565 (range
1571 (range
1566 ('symbol', '2')
1572 ('symbol', '2')
1567 ('symbol', '0')
1573 ('symbol', '0')
1568 define)
1574 define)
1569 (func
1575 (func
1570 ('symbol', '_list')
1576 ('symbol', '_list')
1571 ('string', '0\x001')
1577 ('string', '0\x001')
1572 any)
1578 any)
1573 define)
1579 define)
1574 * set:
1580 * set:
1575 <filteredset
1581 <filteredset
1576 <spanset- 0:2>,
1582 <spanset- 0:2>,
1577 <not
1583 <not
1578 <baseset [0, 1]>>>
1584 <baseset [0, 1]>>>
1579 2
1585 2
1580
1586
1581 $ try -p optimized '2:0 & not (0:2 & (0 + 1))'
1587 $ try -p optimized '2:0 & not (0:2 & (0 + 1))'
1582 * optimized:
1588 * optimized:
1583 (difference
1589 (difference
1584 (range
1590 (range
1585 ('symbol', '2')
1591 ('symbol', '2')
1586 ('symbol', '0')
1592 ('symbol', '0')
1587 define)
1593 define)
1588 (and
1594 (and
1589 (range
1595 (range
1590 ('symbol', '0')
1596 ('symbol', '0')
1591 ('symbol', '2')
1597 ('symbol', '2')
1592 any)
1598 any)
1593 (func
1599 (func
1594 ('symbol', '_list')
1600 ('symbol', '_list')
1595 ('string', '0\x001')
1601 ('string', '0\x001')
1596 any)
1602 any)
1597 any)
1603 any)
1598 define)
1604 define)
1599 * set:
1605 * set:
1600 <filteredset
1606 <filteredset
1601 <spanset- 0:2>,
1607 <spanset- 0:2>,
1602 <not
1608 <not
1603 <baseset [0, 1]>>>
1609 <baseset [0, 1]>>>
1604 2
1610 2
1605
1611
1606 because 'present()' does nothing other than suppressing an error, the
1612 because 'present()' does nothing other than suppressing an error, the
1607 ordering requirement should be forwarded to the nested expression
1613 ordering requirement should be forwarded to the nested expression
1608
1614
1609 $ try -p optimized 'present(2 + 0 + 1)'
1615 $ try -p optimized 'present(2 + 0 + 1)'
1610 * optimized:
1616 * optimized:
1611 (func
1617 (func
1612 ('symbol', 'present')
1618 ('symbol', 'present')
1613 (func
1619 (func
1614 ('symbol', '_list')
1620 ('symbol', '_list')
1615 ('string', '2\x000\x001')
1621 ('string', '2\x000\x001')
1616 define)
1622 define)
1617 define)
1623 define)
1618 * set:
1624 * set:
1619 <baseset [2, 0, 1]>
1625 <baseset [2, 0, 1]>
1620 2
1626 2
1621 0
1627 0
1622 1
1628 1
1623
1629
1624 $ try --optimize '2:0 & present(0 + 1 + 2)'
1630 $ try --optimize '2:0 & present(0 + 1 + 2)'
1625 (and
1631 (and
1626 (range
1632 (range
1627 ('symbol', '2')
1633 ('symbol', '2')
1628 ('symbol', '0'))
1634 ('symbol', '0'))
1629 (func
1635 (func
1630 ('symbol', 'present')
1636 ('symbol', 'present')
1631 (or
1637 (or
1632 (list
1638 (list
1633 ('symbol', '0')
1639 ('symbol', '0')
1634 ('symbol', '1')
1640 ('symbol', '1')
1635 ('symbol', '2')))))
1641 ('symbol', '2')))))
1636 * optimized:
1642 * optimized:
1637 (and
1643 (and
1638 (range
1644 (range
1639 ('symbol', '2')
1645 ('symbol', '2')
1640 ('symbol', '0')
1646 ('symbol', '0')
1641 define)
1647 define)
1642 (func
1648 (func
1643 ('symbol', 'present')
1649 ('symbol', 'present')
1644 (func
1650 (func
1645 ('symbol', '_list')
1651 ('symbol', '_list')
1646 ('string', '0\x001\x002')
1652 ('string', '0\x001\x002')
1647 follow)
1653 follow)
1648 follow)
1654 follow)
1649 define)
1655 define)
1650 * set:
1656 * set:
1651 <filteredset
1657 <filteredset
1652 <spanset- 0:2>,
1658 <spanset- 0:2>,
1653 <baseset [0, 1, 2]>>
1659 <baseset [0, 1, 2]>>
1654 2
1660 2
1655 1
1661 1
1656 0
1662 0
1657
1663
1658 'reverse()' should take effect only if it is the outermost expression:
1664 'reverse()' should take effect only if it is the outermost expression:
1659
1665
1660 $ try --optimize '0:2 & reverse(all())'
1666 $ try --optimize '0:2 & reverse(all())'
1661 (and
1667 (and
1662 (range
1668 (range
1663 ('symbol', '0')
1669 ('symbol', '0')
1664 ('symbol', '2'))
1670 ('symbol', '2'))
1665 (func
1671 (func
1666 ('symbol', 'reverse')
1672 ('symbol', 'reverse')
1667 (func
1673 (func
1668 ('symbol', 'all')
1674 ('symbol', 'all')
1669 None)))
1675 None)))
1670 * optimized:
1676 * optimized:
1671 (and
1677 (and
1672 (range
1678 (range
1673 ('symbol', '0')
1679 ('symbol', '0')
1674 ('symbol', '2')
1680 ('symbol', '2')
1675 define)
1681 define)
1676 (func
1682 (func
1677 ('symbol', 'reverse')
1683 ('symbol', 'reverse')
1678 (func
1684 (func
1679 ('symbol', 'all')
1685 ('symbol', 'all')
1680 None
1686 None
1681 define)
1687 define)
1682 follow)
1688 follow)
1683 define)
1689 define)
1684 * set:
1690 * set:
1685 <filteredset
1691 <filteredset
1686 <spanset+ 0:2>,
1692 <spanset+ 0:2>,
1687 <spanset+ 0:9>>
1693 <spanset+ 0:9>>
1688 0
1694 0
1689 1
1695 1
1690 2
1696 2
1691
1697
1692 'sort()' should take effect only if it is the outermost expression:
1698 'sort()' should take effect only if it is the outermost expression:
1693
1699
1694 $ try --optimize '0:2 & sort(all(), -rev)'
1700 $ try --optimize '0:2 & sort(all(), -rev)'
1695 (and
1701 (and
1696 (range
1702 (range
1697 ('symbol', '0')
1703 ('symbol', '0')
1698 ('symbol', '2'))
1704 ('symbol', '2'))
1699 (func
1705 (func
1700 ('symbol', 'sort')
1706 ('symbol', 'sort')
1701 (list
1707 (list
1702 (func
1708 (func
1703 ('symbol', 'all')
1709 ('symbol', 'all')
1704 None)
1710 None)
1705 (negate
1711 (negate
1706 ('symbol', 'rev')))))
1712 ('symbol', 'rev')))))
1707 * optimized:
1713 * optimized:
1708 (and
1714 (and
1709 (range
1715 (range
1710 ('symbol', '0')
1716 ('symbol', '0')
1711 ('symbol', '2')
1717 ('symbol', '2')
1712 define)
1718 define)
1713 (func
1719 (func
1714 ('symbol', 'sort')
1720 ('symbol', 'sort')
1715 (list
1721 (list
1716 (func
1722 (func
1717 ('symbol', 'all')
1723 ('symbol', 'all')
1718 None
1724 None
1719 define)
1725 define)
1720 ('string', '-rev'))
1726 ('string', '-rev'))
1721 follow)
1727 follow)
1722 define)
1728 define)
1723 * set:
1729 * set:
1724 <filteredset
1730 <filteredset
1725 <spanset+ 0:2>,
1731 <spanset+ 0:2>,
1726 <spanset+ 0:9>>
1732 <spanset+ 0:9>>
1727 0
1733 0
1728 1
1734 1
1729 2
1735 2
1730
1736
1731 invalid argument passed to noop sort():
1737 invalid argument passed to noop sort():
1732
1738
1733 $ log '0:2 & sort()'
1739 $ log '0:2 & sort()'
1734 hg: parse error: sort requires one or two arguments
1740 hg: parse error: sort requires one or two arguments
1735 [255]
1741 [255]
1736 $ log '0:2 & sort(all(), -invalid)'
1742 $ log '0:2 & sort(all(), -invalid)'
1737 hg: parse error: unknown sort key '-invalid'
1743 hg: parse error: unknown sort key '-invalid'
1738 [255]
1744 [255]
1739
1745
1740 for 'A & f(B)', 'B' should not be affected by the order of 'A':
1746 for 'A & f(B)', 'B' should not be affected by the order of 'A':
1741
1747
1742 $ try --optimize '2:0 & first(1 + 0 + 2)'
1748 $ try --optimize '2:0 & first(1 + 0 + 2)'
1743 (and
1749 (and
1744 (range
1750 (range
1745 ('symbol', '2')
1751 ('symbol', '2')
1746 ('symbol', '0'))
1752 ('symbol', '0'))
1747 (func
1753 (func
1748 ('symbol', 'first')
1754 ('symbol', 'first')
1749 (or
1755 (or
1750 (list
1756 (list
1751 ('symbol', '1')
1757 ('symbol', '1')
1752 ('symbol', '0')
1758 ('symbol', '0')
1753 ('symbol', '2')))))
1759 ('symbol', '2')))))
1754 * optimized:
1760 * optimized:
1755 (and
1761 (and
1756 (range
1762 (range
1757 ('symbol', '2')
1763 ('symbol', '2')
1758 ('symbol', '0')
1764 ('symbol', '0')
1759 define)
1765 define)
1760 (func
1766 (func
1761 ('symbol', 'first')
1767 ('symbol', 'first')
1762 (func
1768 (func
1763 ('symbol', '_list')
1769 ('symbol', '_list')
1764 ('string', '1\x000\x002')
1770 ('string', '1\x000\x002')
1765 define)
1771 define)
1766 follow)
1772 follow)
1767 define)
1773 define)
1768 * set:
1774 * set:
1769 <baseset
1775 <baseset
1770 <limit n=1, offset=0,
1776 <limit n=1, offset=0,
1771 <spanset- 0:2>,
1777 <spanset- 0:2>,
1772 <baseset [1, 0, 2]>>>
1778 <baseset [1, 0, 2]>>>
1773 1
1779 1
1774
1780
1775 $ try --optimize '2:0 & not last(0 + 2 + 1)'
1781 $ try --optimize '2:0 & not last(0 + 2 + 1)'
1776 (and
1782 (and
1777 (range
1783 (range
1778 ('symbol', '2')
1784 ('symbol', '2')
1779 ('symbol', '0'))
1785 ('symbol', '0'))
1780 (not
1786 (not
1781 (func
1787 (func
1782 ('symbol', 'last')
1788 ('symbol', 'last')
1783 (or
1789 (or
1784 (list
1790 (list
1785 ('symbol', '0')
1791 ('symbol', '0')
1786 ('symbol', '2')
1792 ('symbol', '2')
1787 ('symbol', '1'))))))
1793 ('symbol', '1'))))))
1788 * optimized:
1794 * optimized:
1789 (difference
1795 (difference
1790 (range
1796 (range
1791 ('symbol', '2')
1797 ('symbol', '2')
1792 ('symbol', '0')
1798 ('symbol', '0')
1793 define)
1799 define)
1794 (func
1800 (func
1795 ('symbol', 'last')
1801 ('symbol', 'last')
1796 (func
1802 (func
1797 ('symbol', '_list')
1803 ('symbol', '_list')
1798 ('string', '0\x002\x001')
1804 ('string', '0\x002\x001')
1799 define)
1805 define)
1800 any)
1806 any)
1801 define)
1807 define)
1802 * set:
1808 * set:
1803 <filteredset
1809 <filteredset
1804 <spanset- 0:2>,
1810 <spanset- 0:2>,
1805 <not
1811 <not
1806 <baseset
1812 <baseset
1807 <last n=1,
1813 <last n=1,
1808 <fullreposet+ 0:9>,
1814 <fullreposet+ 0:9>,
1809 <baseset [1, 2, 0]>>>>>
1815 <baseset [1, 2, 0]>>>>>
1810 2
1816 2
1811 0
1817 0
1812
1818
1813 for 'A & (op)(B)', 'B' should not be affected by the order of 'A':
1819 for 'A & (op)(B)', 'B' should not be affected by the order of 'A':
1814
1820
1815 $ try --optimize '2:0 & (1 + 0 + 2):(0 + 2 + 1)'
1821 $ try --optimize '2:0 & (1 + 0 + 2):(0 + 2 + 1)'
1816 (and
1822 (and
1817 (range
1823 (range
1818 ('symbol', '2')
1824 ('symbol', '2')
1819 ('symbol', '0'))
1825 ('symbol', '0'))
1820 (range
1826 (range
1821 (group
1827 (group
1822 (or
1828 (or
1823 (list
1829 (list
1824 ('symbol', '1')
1830 ('symbol', '1')
1825 ('symbol', '0')
1831 ('symbol', '0')
1826 ('symbol', '2'))))
1832 ('symbol', '2'))))
1827 (group
1833 (group
1828 (or
1834 (or
1829 (list
1835 (list
1830 ('symbol', '0')
1836 ('symbol', '0')
1831 ('symbol', '2')
1837 ('symbol', '2')
1832 ('symbol', '1'))))))
1838 ('symbol', '1'))))))
1833 * optimized:
1839 * optimized:
1834 (and
1840 (and
1835 (range
1841 (range
1836 ('symbol', '2')
1842 ('symbol', '2')
1837 ('symbol', '0')
1843 ('symbol', '0')
1838 define)
1844 define)
1839 (range
1845 (range
1840 (func
1846 (func
1841 ('symbol', '_list')
1847 ('symbol', '_list')
1842 ('string', '1\x000\x002')
1848 ('string', '1\x000\x002')
1843 define)
1849 define)
1844 (func
1850 (func
1845 ('symbol', '_list')
1851 ('symbol', '_list')
1846 ('string', '0\x002\x001')
1852 ('string', '0\x002\x001')
1847 define)
1853 define)
1848 follow)
1854 follow)
1849 define)
1855 define)
1850 * set:
1856 * set:
1851 <filteredset
1857 <filteredset
1852 <spanset- 0:2>,
1858 <spanset- 0:2>,
1853 <baseset [1]>>
1859 <baseset [1]>>
1854 1
1860 1
1855
1861
1856 'A & B' can be rewritten as 'B & A' by weight, but that's fine as long as
1862 'A & B' can be rewritten as 'B & A' by weight, but that's fine as long as
1857 the ordering rule is determined before the rewrite; in this example,
1863 the ordering rule is determined before the rewrite; in this example,
1858 'B' follows the order of the initial set, which is the same order as 'A'
1864 'B' follows the order of the initial set, which is the same order as 'A'
1859 since 'A' also follows the order:
1865 since 'A' also follows the order:
1860
1866
1861 $ try --optimize 'contains("glob:*") & (2 + 0 + 1)'
1867 $ try --optimize 'contains("glob:*") & (2 + 0 + 1)'
1862 (and
1868 (and
1863 (func
1869 (func
1864 ('symbol', 'contains')
1870 ('symbol', 'contains')
1865 ('string', 'glob:*'))
1871 ('string', 'glob:*'))
1866 (group
1872 (group
1867 (or
1873 (or
1868 (list
1874 (list
1869 ('symbol', '2')
1875 ('symbol', '2')
1870 ('symbol', '0')
1876 ('symbol', '0')
1871 ('symbol', '1')))))
1877 ('symbol', '1')))))
1872 * optimized:
1878 * optimized:
1873 (and
1879 (and
1874 (func
1880 (func
1875 ('symbol', '_list')
1881 ('symbol', '_list')
1876 ('string', '2\x000\x001')
1882 ('string', '2\x000\x001')
1877 follow)
1883 follow)
1878 (func
1884 (func
1879 ('symbol', 'contains')
1885 ('symbol', 'contains')
1880 ('string', 'glob:*')
1886 ('string', 'glob:*')
1881 define)
1887 define)
1882 define)
1888 define)
1883 * set:
1889 * set:
1884 <filteredset
1890 <filteredset
1885 <baseset+ [0, 1, 2]>,
1891 <baseset+ [0, 1, 2]>,
1886 <contains 'glob:*'>>
1892 <contains 'glob:*'>>
1887 0
1893 0
1888 1
1894 1
1889 2
1895 2
1890
1896
1891 and in this example, 'A & B' is rewritten as 'B & A', but 'A' overrides
1897 and in this example, 'A & B' is rewritten as 'B & A', but 'A' overrides
1892 the order appropriately:
1898 the order appropriately:
1893
1899
1894 $ try --optimize 'reverse(contains("glob:*")) & (0 + 2 + 1)'
1900 $ try --optimize 'reverse(contains("glob:*")) & (0 + 2 + 1)'
1895 (and
1901 (and
1896 (func
1902 (func
1897 ('symbol', 'reverse')
1903 ('symbol', 'reverse')
1898 (func
1904 (func
1899 ('symbol', 'contains')
1905 ('symbol', 'contains')
1900 ('string', 'glob:*')))
1906 ('string', 'glob:*')))
1901 (group
1907 (group
1902 (or
1908 (or
1903 (list
1909 (list
1904 ('symbol', '0')
1910 ('symbol', '0')
1905 ('symbol', '2')
1911 ('symbol', '2')
1906 ('symbol', '1')))))
1912 ('symbol', '1')))))
1907 * optimized:
1913 * optimized:
1908 (and
1914 (and
1909 (func
1915 (func
1910 ('symbol', '_list')
1916 ('symbol', '_list')
1911 ('string', '0\x002\x001')
1917 ('string', '0\x002\x001')
1912 follow)
1918 follow)
1913 (func
1919 (func
1914 ('symbol', 'reverse')
1920 ('symbol', 'reverse')
1915 (func
1921 (func
1916 ('symbol', 'contains')
1922 ('symbol', 'contains')
1917 ('string', 'glob:*')
1923 ('string', 'glob:*')
1918 define)
1924 define)
1919 define)
1925 define)
1920 define)
1926 define)
1921 * set:
1927 * set:
1922 <filteredset
1928 <filteredset
1923 <baseset- [0, 1, 2]>,
1929 <baseset- [0, 1, 2]>,
1924 <contains 'glob:*'>>
1930 <contains 'glob:*'>>
1925 2
1931 2
1926 1
1932 1
1927 0
1933 0
1928
1934
1929 'A + B' can be rewritten to 'B + A' by weight only when the order doesn't
1935 'A + B' can be rewritten to 'B + A' by weight only when the order doesn't
1930 matter (e.g. 'X & (A + B)' can be 'X & (B + A)', but '(A + B) & X' can't):
1936 matter (e.g. 'X & (A + B)' can be 'X & (B + A)', but '(A + B) & X' can't):
1931
1937
1932 $ try -p optimized '0:2 & (reverse(contains("a")) + 2)'
1938 $ try -p optimized '0:2 & (reverse(contains("a")) + 2)'
1933 * optimized:
1939 * optimized:
1934 (and
1940 (and
1935 (range
1941 (range
1936 ('symbol', '0')
1942 ('symbol', '0')
1937 ('symbol', '2')
1943 ('symbol', '2')
1938 define)
1944 define)
1939 (or
1945 (or
1940 (list
1946 (list
1941 ('symbol', '2')
1947 ('symbol', '2')
1942 (func
1948 (func
1943 ('symbol', 'reverse')
1949 ('symbol', 'reverse')
1944 (func
1950 (func
1945 ('symbol', 'contains')
1951 ('symbol', 'contains')
1946 ('string', 'a')
1952 ('string', 'a')
1947 define)
1953 define)
1948 follow))
1954 follow))
1949 follow)
1955 follow)
1950 define)
1956 define)
1951 * set:
1957 * set:
1952 <filteredset
1958 <filteredset
1953 <spanset+ 0:2>,
1959 <spanset+ 0:2>,
1954 <addset
1960 <addset
1955 <baseset [2]>,
1961 <baseset [2]>,
1956 <filteredset
1962 <filteredset
1957 <fullreposet+ 0:9>,
1963 <fullreposet+ 0:9>,
1958 <contains 'a'>>>>
1964 <contains 'a'>>>>
1959 0
1965 0
1960 1
1966 1
1961 2
1967 2
1962
1968
1963 $ try -p optimized '(reverse(contains("a")) + 2) & 0:2'
1969 $ try -p optimized '(reverse(contains("a")) + 2) & 0:2'
1964 * optimized:
1970 * optimized:
1965 (and
1971 (and
1966 (range
1972 (range
1967 ('symbol', '0')
1973 ('symbol', '0')
1968 ('symbol', '2')
1974 ('symbol', '2')
1969 follow)
1975 follow)
1970 (or
1976 (or
1971 (list
1977 (list
1972 (func
1978 (func
1973 ('symbol', 'reverse')
1979 ('symbol', 'reverse')
1974 (func
1980 (func
1975 ('symbol', 'contains')
1981 ('symbol', 'contains')
1976 ('string', 'a')
1982 ('string', 'a')
1977 define)
1983 define)
1978 define)
1984 define)
1979 ('symbol', '2'))
1985 ('symbol', '2'))
1980 define)
1986 define)
1981 define)
1987 define)
1982 * set:
1988 * set:
1983 <addset
1989 <addset
1984 <filteredset
1990 <filteredset
1985 <spanset- 0:2>,
1991 <spanset- 0:2>,
1986 <contains 'a'>>,
1992 <contains 'a'>>,
1987 <baseset [2]>>
1993 <baseset [2]>>
1988 1
1994 1
1989 0
1995 0
1990 2
1996 2
1991
1997
1992 test sort revset
1998 test sort revset
1993 --------------------------------------------
1999 --------------------------------------------
1994
2000
1995 test when adding two unordered revsets
2001 test when adding two unordered revsets
1996
2002
1997 $ log 'sort(keyword(issue) or modifies(b))'
2003 $ log 'sort(keyword(issue) or modifies(b))'
1998 4
2004 4
1999 6
2005 6
2000
2006
2001 test when sorting a reversed collection in the same way it is
2007 test when sorting a reversed collection in the same way it is
2002
2008
2003 $ log 'sort(reverse(all()), -rev)'
2009 $ log 'sort(reverse(all()), -rev)'
2004 9
2010 9
2005 8
2011 8
2006 7
2012 7
2007 6
2013 6
2008 5
2014 5
2009 4
2015 4
2010 3
2016 3
2011 2
2017 2
2012 1
2018 1
2013 0
2019 0
2014
2020
2015 test when sorting a reversed collection
2021 test when sorting a reversed collection
2016
2022
2017 $ log 'sort(reverse(all()), rev)'
2023 $ log 'sort(reverse(all()), rev)'
2018 0
2024 0
2019 1
2025 1
2020 2
2026 2
2021 3
2027 3
2022 4
2028 4
2023 5
2029 5
2024 6
2030 6
2025 7
2031 7
2026 8
2032 8
2027 9
2033 9
2028
2034
2029
2035
2030 test sorting two sorted collections in different orders
2036 test sorting two sorted collections in different orders
2031
2037
2032 $ log 'sort(outgoing() or reverse(removes(a)), rev)'
2038 $ log 'sort(outgoing() or reverse(removes(a)), rev)'
2033 2
2039 2
2034 6
2040 6
2035 8
2041 8
2036 9
2042 9
2037
2043
2038 test sorting two sorted collections in different orders backwards
2044 test sorting two sorted collections in different orders backwards
2039
2045
2040 $ log 'sort(outgoing() or reverse(removes(a)), -rev)'
2046 $ log 'sort(outgoing() or reverse(removes(a)), -rev)'
2041 9
2047 9
2042 8
2048 8
2043 6
2049 6
2044 2
2050 2
2045
2051
2046 test empty sort key which is noop
2052 test empty sort key which is noop
2047
2053
2048 $ log 'sort(0 + 2 + 1, "")'
2054 $ log 'sort(0 + 2 + 1, "")'
2049 0
2055 0
2050 2
2056 2
2051 1
2057 1
2052
2058
2053 test invalid sort keys
2059 test invalid sort keys
2054
2060
2055 $ log 'sort(all(), -invalid)'
2061 $ log 'sort(all(), -invalid)'
2056 hg: parse error: unknown sort key '-invalid'
2062 hg: parse error: unknown sort key '-invalid'
2057 [255]
2063 [255]
2058
2064
2059 $ cd ..
2065 $ cd ..
2060
2066
2061 test sorting by multiple keys including variable-length strings
2067 test sorting by multiple keys including variable-length strings
2062
2068
2063 $ hg init sorting
2069 $ hg init sorting
2064 $ cd sorting
2070 $ cd sorting
2065 $ cat <<EOF >> .hg/hgrc
2071 $ cat <<EOF >> .hg/hgrc
2066 > [ui]
2072 > [ui]
2067 > logtemplate = '{rev} {branch|p5}{desc|p5}{author|p5}{date|hgdate}\n'
2073 > logtemplate = '{rev} {branch|p5}{desc|p5}{author|p5}{date|hgdate}\n'
2068 > [templatealias]
2074 > [templatealias]
2069 > p5(s) = pad(s, 5)
2075 > p5(s) = pad(s, 5)
2070 > EOF
2076 > EOF
2071 $ hg branch -qf b12
2077 $ hg branch -qf b12
2072 $ hg ci -m m111 -u u112 -d '111 10800'
2078 $ hg ci -m m111 -u u112 -d '111 10800'
2073 $ hg branch -qf b11
2079 $ hg branch -qf b11
2074 $ hg ci -m m12 -u u111 -d '112 7200'
2080 $ hg ci -m m12 -u u111 -d '112 7200'
2075 $ hg branch -qf b111
2081 $ hg branch -qf b111
2076 $ hg ci -m m11 -u u12 -d '111 3600'
2082 $ hg ci -m m11 -u u12 -d '111 3600'
2077 $ hg branch -qf b112
2083 $ hg branch -qf b112
2078 $ hg ci -m m111 -u u11 -d '120 0'
2084 $ hg ci -m m111 -u u11 -d '120 0'
2079 $ hg branch -qf b111
2085 $ hg branch -qf b111
2080 $ hg ci -m m112 -u u111 -d '110 14400'
2086 $ hg ci -m m112 -u u111 -d '110 14400'
2081 created new head
2087 created new head
2082
2088
2083 compare revisions (has fast path):
2089 compare revisions (has fast path):
2084
2090
2085 $ hg log -r 'sort(all(), rev)'
2091 $ hg log -r 'sort(all(), rev)'
2086 0 b12 m111 u112 111 10800
2092 0 b12 m111 u112 111 10800
2087 1 b11 m12 u111 112 7200
2093 1 b11 m12 u111 112 7200
2088 2 b111 m11 u12 111 3600
2094 2 b111 m11 u12 111 3600
2089 3 b112 m111 u11 120 0
2095 3 b112 m111 u11 120 0
2090 4 b111 m112 u111 110 14400
2096 4 b111 m112 u111 110 14400
2091
2097
2092 $ hg log -r 'sort(all(), -rev)'
2098 $ hg log -r 'sort(all(), -rev)'
2093 4 b111 m112 u111 110 14400
2099 4 b111 m112 u111 110 14400
2094 3 b112 m111 u11 120 0
2100 3 b112 m111 u11 120 0
2095 2 b111 m11 u12 111 3600
2101 2 b111 m11 u12 111 3600
2096 1 b11 m12 u111 112 7200
2102 1 b11 m12 u111 112 7200
2097 0 b12 m111 u112 111 10800
2103 0 b12 m111 u112 111 10800
2098
2104
2099 compare variable-length strings (issue5218):
2105 compare variable-length strings (issue5218):
2100
2106
2101 $ hg log -r 'sort(all(), branch)'
2107 $ hg log -r 'sort(all(), branch)'
2102 1 b11 m12 u111 112 7200
2108 1 b11 m12 u111 112 7200
2103 2 b111 m11 u12 111 3600
2109 2 b111 m11 u12 111 3600
2104 4 b111 m112 u111 110 14400
2110 4 b111 m112 u111 110 14400
2105 3 b112 m111 u11 120 0
2111 3 b112 m111 u11 120 0
2106 0 b12 m111 u112 111 10800
2112 0 b12 m111 u112 111 10800
2107
2113
2108 $ hg log -r 'sort(all(), -branch)'
2114 $ hg log -r 'sort(all(), -branch)'
2109 0 b12 m111 u112 111 10800
2115 0 b12 m111 u112 111 10800
2110 3 b112 m111 u11 120 0
2116 3 b112 m111 u11 120 0
2111 2 b111 m11 u12 111 3600
2117 2 b111 m11 u12 111 3600
2112 4 b111 m112 u111 110 14400
2118 4 b111 m112 u111 110 14400
2113 1 b11 m12 u111 112 7200
2119 1 b11 m12 u111 112 7200
2114
2120
2115 $ hg log -r 'sort(all(), desc)'
2121 $ hg log -r 'sort(all(), desc)'
2116 2 b111 m11 u12 111 3600
2122 2 b111 m11 u12 111 3600
2117 0 b12 m111 u112 111 10800
2123 0 b12 m111 u112 111 10800
2118 3 b112 m111 u11 120 0
2124 3 b112 m111 u11 120 0
2119 4 b111 m112 u111 110 14400
2125 4 b111 m112 u111 110 14400
2120 1 b11 m12 u111 112 7200
2126 1 b11 m12 u111 112 7200
2121
2127
2122 $ hg log -r 'sort(all(), -desc)'
2128 $ hg log -r 'sort(all(), -desc)'
2123 1 b11 m12 u111 112 7200
2129 1 b11 m12 u111 112 7200
2124 4 b111 m112 u111 110 14400
2130 4 b111 m112 u111 110 14400
2125 0 b12 m111 u112 111 10800
2131 0 b12 m111 u112 111 10800
2126 3 b112 m111 u11 120 0
2132 3 b112 m111 u11 120 0
2127 2 b111 m11 u12 111 3600
2133 2 b111 m11 u12 111 3600
2128
2134
2129 $ hg log -r 'sort(all(), user)'
2135 $ hg log -r 'sort(all(), user)'
2130 3 b112 m111 u11 120 0
2136 3 b112 m111 u11 120 0
2131 1 b11 m12 u111 112 7200
2137 1 b11 m12 u111 112 7200
2132 4 b111 m112 u111 110 14400
2138 4 b111 m112 u111 110 14400
2133 0 b12 m111 u112 111 10800
2139 0 b12 m111 u112 111 10800
2134 2 b111 m11 u12 111 3600
2140 2 b111 m11 u12 111 3600
2135
2141
2136 $ hg log -r 'sort(all(), -user)'
2142 $ hg log -r 'sort(all(), -user)'
2137 2 b111 m11 u12 111 3600
2143 2 b111 m11 u12 111 3600
2138 0 b12 m111 u112 111 10800
2144 0 b12 m111 u112 111 10800
2139 1 b11 m12 u111 112 7200
2145 1 b11 m12 u111 112 7200
2140 4 b111 m112 u111 110 14400
2146 4 b111 m112 u111 110 14400
2141 3 b112 m111 u11 120 0
2147 3 b112 m111 u11 120 0
2142
2148
2143 compare dates (tz offset should have no effect):
2149 compare dates (tz offset should have no effect):
2144
2150
2145 $ hg log -r 'sort(all(), date)'
2151 $ hg log -r 'sort(all(), date)'
2146 4 b111 m112 u111 110 14400
2152 4 b111 m112 u111 110 14400
2147 0 b12 m111 u112 111 10800
2153 0 b12 m111 u112 111 10800
2148 2 b111 m11 u12 111 3600
2154 2 b111 m11 u12 111 3600
2149 1 b11 m12 u111 112 7200
2155 1 b11 m12 u111 112 7200
2150 3 b112 m111 u11 120 0
2156 3 b112 m111 u11 120 0
2151
2157
2152 $ hg log -r 'sort(all(), -date)'
2158 $ hg log -r 'sort(all(), -date)'
2153 3 b112 m111 u11 120 0
2159 3 b112 m111 u11 120 0
2154 1 b11 m12 u111 112 7200
2160 1 b11 m12 u111 112 7200
2155 0 b12 m111 u112 111 10800
2161 0 b12 m111 u112 111 10800
2156 2 b111 m11 u12 111 3600
2162 2 b111 m11 u12 111 3600
2157 4 b111 m112 u111 110 14400
2163 4 b111 m112 u111 110 14400
2158
2164
2159 be aware that 'sort(x, -k)' is not exactly the same as 'reverse(sort(x, k))'
2165 be aware that 'sort(x, -k)' is not exactly the same as 'reverse(sort(x, k))'
2160 because '-k' reverses the comparison, not the list itself:
2166 because '-k' reverses the comparison, not the list itself:
2161
2167
2162 $ hg log -r 'sort(0 + 2, date)'
2168 $ hg log -r 'sort(0 + 2, date)'
2163 0 b12 m111 u112 111 10800
2169 0 b12 m111 u112 111 10800
2164 2 b111 m11 u12 111 3600
2170 2 b111 m11 u12 111 3600
2165
2171
2166 $ hg log -r 'sort(0 + 2, -date)'
2172 $ hg log -r 'sort(0 + 2, -date)'
2167 0 b12 m111 u112 111 10800
2173 0 b12 m111 u112 111 10800
2168 2 b111 m11 u12 111 3600
2174 2 b111 m11 u12 111 3600
2169
2175
2170 $ hg log -r 'reverse(sort(0 + 2, date))'
2176 $ hg log -r 'reverse(sort(0 + 2, date))'
2171 2 b111 m11 u12 111 3600
2177 2 b111 m11 u12 111 3600
2172 0 b12 m111 u112 111 10800
2178 0 b12 m111 u112 111 10800
2173
2179
2174 sort by multiple keys:
2180 sort by multiple keys:
2175
2181
2176 $ hg log -r 'sort(all(), "branch -rev")'
2182 $ hg log -r 'sort(all(), "branch -rev")'
2177 1 b11 m12 u111 112 7200
2183 1 b11 m12 u111 112 7200
2178 4 b111 m112 u111 110 14400
2184 4 b111 m112 u111 110 14400
2179 2 b111 m11 u12 111 3600
2185 2 b111 m11 u12 111 3600
2180 3 b112 m111 u11 120 0
2186 3 b112 m111 u11 120 0
2181 0 b12 m111 u112 111 10800
2187 0 b12 m111 u112 111 10800
2182
2188
2183 $ hg log -r 'sort(all(), "-desc -date")'
2189 $ hg log -r 'sort(all(), "-desc -date")'
2184 1 b11 m12 u111 112 7200
2190 1 b11 m12 u111 112 7200
2185 4 b111 m112 u111 110 14400
2191 4 b111 m112 u111 110 14400
2186 3 b112 m111 u11 120 0
2192 3 b112 m111 u11 120 0
2187 0 b12 m111 u112 111 10800
2193 0 b12 m111 u112 111 10800
2188 2 b111 m11 u12 111 3600
2194 2 b111 m11 u12 111 3600
2189
2195
2190 $ hg log -r 'sort(all(), "user -branch date rev")'
2196 $ hg log -r 'sort(all(), "user -branch date rev")'
2191 3 b112 m111 u11 120 0
2197 3 b112 m111 u11 120 0
2192 4 b111 m112 u111 110 14400
2198 4 b111 m112 u111 110 14400
2193 1 b11 m12 u111 112 7200
2199 1 b11 m12 u111 112 7200
2194 0 b12 m111 u112 111 10800
2200 0 b12 m111 u112 111 10800
2195 2 b111 m11 u12 111 3600
2201 2 b111 m11 u12 111 3600
2196
2202
2197 toposort prioritises graph branches
2203 toposort prioritises graph branches
2198
2204
2199 $ hg up 2
2205 $ hg up 2
2200 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
2206 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
2201 $ touch a
2207 $ touch a
2202 $ hg addremove
2208 $ hg addremove
2203 adding a
2209 adding a
2204 $ hg ci -m 't1' -u 'tu' -d '130 0'
2210 $ hg ci -m 't1' -u 'tu' -d '130 0'
2205 created new head
2211 created new head
2206 $ echo 'a' >> a
2212 $ echo 'a' >> a
2207 $ hg ci -m 't2' -u 'tu' -d '130 0'
2213 $ hg ci -m 't2' -u 'tu' -d '130 0'
2208 $ hg book book1
2214 $ hg book book1
2209 $ hg up 4
2215 $ hg up 4
2210 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
2216 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
2211 (leaving bookmark book1)
2217 (leaving bookmark book1)
2212 $ touch a
2218 $ touch a
2213 $ hg addremove
2219 $ hg addremove
2214 adding a
2220 adding a
2215 $ hg ci -m 't3' -u 'tu' -d '130 0'
2221 $ hg ci -m 't3' -u 'tu' -d '130 0'
2216
2222
2217 $ hg log -r 'sort(all(), topo)'
2223 $ hg log -r 'sort(all(), topo)'
2218 7 b111 t3 tu 130 0
2224 7 b111 t3 tu 130 0
2219 4 b111 m112 u111 110 14400
2225 4 b111 m112 u111 110 14400
2220 3 b112 m111 u11 120 0
2226 3 b112 m111 u11 120 0
2221 6 b111 t2 tu 130 0
2227 6 b111 t2 tu 130 0
2222 5 b111 t1 tu 130 0
2228 5 b111 t1 tu 130 0
2223 2 b111 m11 u12 111 3600
2229 2 b111 m11 u12 111 3600
2224 1 b11 m12 u111 112 7200
2230 1 b11 m12 u111 112 7200
2225 0 b12 m111 u112 111 10800
2231 0 b12 m111 u112 111 10800
2226
2232
2227 $ hg log -r 'sort(all(), -topo)'
2233 $ hg log -r 'sort(all(), -topo)'
2228 0 b12 m111 u112 111 10800
2234 0 b12 m111 u112 111 10800
2229 1 b11 m12 u111 112 7200
2235 1 b11 m12 u111 112 7200
2230 2 b111 m11 u12 111 3600
2236 2 b111 m11 u12 111 3600
2231 5 b111 t1 tu 130 0
2237 5 b111 t1 tu 130 0
2232 6 b111 t2 tu 130 0
2238 6 b111 t2 tu 130 0
2233 3 b112 m111 u11 120 0
2239 3 b112 m111 u11 120 0
2234 4 b111 m112 u111 110 14400
2240 4 b111 m112 u111 110 14400
2235 7 b111 t3 tu 130 0
2241 7 b111 t3 tu 130 0
2236
2242
2237 $ hg log -r 'sort(all(), topo, topo.firstbranch=book1)'
2243 $ hg log -r 'sort(all(), topo, topo.firstbranch=book1)'
2238 6 b111 t2 tu 130 0
2244 6 b111 t2 tu 130 0
2239 5 b111 t1 tu 130 0
2245 5 b111 t1 tu 130 0
2240 7 b111 t3 tu 130 0
2246 7 b111 t3 tu 130 0
2241 4 b111 m112 u111 110 14400
2247 4 b111 m112 u111 110 14400
2242 3 b112 m111 u11 120 0
2248 3 b112 m111 u11 120 0
2243 2 b111 m11 u12 111 3600
2249 2 b111 m11 u12 111 3600
2244 1 b11 m12 u111 112 7200
2250 1 b11 m12 u111 112 7200
2245 0 b12 m111 u112 111 10800
2251 0 b12 m111 u112 111 10800
2246
2252
2247 topographical sorting can't be combined with other sort keys, and you can't
2253 topographical sorting can't be combined with other sort keys, and you can't
2248 use the topo.firstbranch option when topo sort is not active:
2254 use the topo.firstbranch option when topo sort is not active:
2249
2255
2250 $ hg log -r 'sort(all(), "topo user")'
2256 $ hg log -r 'sort(all(), "topo user")'
2251 hg: parse error: topo sort order cannot be combined with other sort keys
2257 hg: parse error: topo sort order cannot be combined with other sort keys
2252 [255]
2258 [255]
2253
2259
2254 $ hg log -r 'sort(all(), user, topo.firstbranch=book1)'
2260 $ hg log -r 'sort(all(), user, topo.firstbranch=book1)'
2255 hg: parse error: topo.firstbranch can only be used when using the topo sort key
2261 hg: parse error: topo.firstbranch can only be used when using the topo sort key
2256 [255]
2262 [255]
2257
2263
2258 topo.firstbranch should accept any kind of expressions:
2264 topo.firstbranch should accept any kind of expressions:
2259
2265
2260 $ hg log -r 'sort(0, topo, topo.firstbranch=(book1))'
2266 $ hg log -r 'sort(0, topo, topo.firstbranch=(book1))'
2261 0 b12 m111 u112 111 10800
2267 0 b12 m111 u112 111 10800
2262
2268
2263 $ cd ..
2269 $ cd ..
2264 $ cd repo
2270 $ cd repo
2265
2271
2266 test subtracting something from an addset
2272 test subtracting something from an addset
2267
2273
2268 $ log '(outgoing() or removes(a)) - removes(a)'
2274 $ log '(outgoing() or removes(a)) - removes(a)'
2269 8
2275 8
2270 9
2276 9
2271
2277
2272 test intersecting something with an addset
2278 test intersecting something with an addset
2273
2279
2274 $ log 'parents(outgoing() or removes(a))'
2280 $ log 'parents(outgoing() or removes(a))'
2275 1
2281 1
2276 4
2282 4
2277 5
2283 5
2278 8
2284 8
2279
2285
2280 test that `or` operation combines elements in the right order:
2286 test that `or` operation combines elements in the right order:
2281
2287
2282 $ log '3:4 or 2:5'
2288 $ log '3:4 or 2:5'
2283 3
2289 3
2284 4
2290 4
2285 2
2291 2
2286 5
2292 5
2287 $ log '3:4 or 5:2'
2293 $ log '3:4 or 5:2'
2288 3
2294 3
2289 4
2295 4
2290 5
2296 5
2291 2
2297 2
2292 $ log 'sort(3:4 or 2:5)'
2298 $ log 'sort(3:4 or 2:5)'
2293 2
2299 2
2294 3
2300 3
2295 4
2301 4
2296 5
2302 5
2297 $ log 'sort(3:4 or 5:2)'
2303 $ log 'sort(3:4 or 5:2)'
2298 2
2304 2
2299 3
2305 3
2300 4
2306 4
2301 5
2307 5
2302
2308
2303 test that more than one `-r`s are combined in the right order and deduplicated:
2309 test that more than one `-r`s are combined in the right order and deduplicated:
2304
2310
2305 $ hg log -T '{rev}\n' -r 3 -r 3 -r 4 -r 5:2 -r 'ancestors(4)'
2311 $ hg log -T '{rev}\n' -r 3 -r 3 -r 4 -r 5:2 -r 'ancestors(4)'
2306 3
2312 3
2307 4
2313 4
2308 5
2314 5
2309 2
2315 2
2310 0
2316 0
2311 1
2317 1
2312
2318
2313 test that `or` operation skips duplicated revisions from right-hand side
2319 test that `or` operation skips duplicated revisions from right-hand side
2314
2320
2315 $ try 'reverse(1::5) or ancestors(4)'
2321 $ try 'reverse(1::5) or ancestors(4)'
2316 (or
2322 (or
2317 (list
2323 (list
2318 (func
2324 (func
2319 ('symbol', 'reverse')
2325 ('symbol', 'reverse')
2320 (dagrange
2326 (dagrange
2321 ('symbol', '1')
2327 ('symbol', '1')
2322 ('symbol', '5')))
2328 ('symbol', '5')))
2323 (func
2329 (func
2324 ('symbol', 'ancestors')
2330 ('symbol', 'ancestors')
2325 ('symbol', '4'))))
2331 ('symbol', '4'))))
2326 * set:
2332 * set:
2327 <addset
2333 <addset
2328 <baseset- [1, 3, 5]>,
2334 <baseset- [1, 3, 5]>,
2329 <generatorset+>>
2335 <generatorset+>>
2330 5
2336 5
2331 3
2337 3
2332 1
2338 1
2333 0
2339 0
2334 2
2340 2
2335 4
2341 4
2336 $ try 'sort(ancestors(4) or reverse(1::5))'
2342 $ try 'sort(ancestors(4) or reverse(1::5))'
2337 (func
2343 (func
2338 ('symbol', 'sort')
2344 ('symbol', 'sort')
2339 (or
2345 (or
2340 (list
2346 (list
2341 (func
2347 (func
2342 ('symbol', 'ancestors')
2348 ('symbol', 'ancestors')
2343 ('symbol', '4'))
2349 ('symbol', '4'))
2344 (func
2350 (func
2345 ('symbol', 'reverse')
2351 ('symbol', 'reverse')
2346 (dagrange
2352 (dagrange
2347 ('symbol', '1')
2353 ('symbol', '1')
2348 ('symbol', '5'))))))
2354 ('symbol', '5'))))))
2349 * set:
2355 * set:
2350 <addset+
2356 <addset+
2351 <generatorset+>,
2357 <generatorset+>,
2352 <baseset- [1, 3, 5]>>
2358 <baseset- [1, 3, 5]>>
2353 0
2359 0
2354 1
2360 1
2355 2
2361 2
2356 3
2362 3
2357 4
2363 4
2358 5
2364 5
2359
2365
2360 test optimization of trivial `or` operation
2366 test optimization of trivial `or` operation
2361
2367
2362 $ try --optimize '0|(1)|"2"|-2|tip|null'
2368 $ try --optimize '0|(1)|"2"|-2|tip|null'
2363 (or
2369 (or
2364 (list
2370 (list
2365 ('symbol', '0')
2371 ('symbol', '0')
2366 (group
2372 (group
2367 ('symbol', '1'))
2373 ('symbol', '1'))
2368 ('string', '2')
2374 ('string', '2')
2369 (negate
2375 (negate
2370 ('symbol', '2'))
2376 ('symbol', '2'))
2371 ('symbol', 'tip')
2377 ('symbol', 'tip')
2372 ('symbol', 'null')))
2378 ('symbol', 'null')))
2373 * optimized:
2379 * optimized:
2374 (func
2380 (func
2375 ('symbol', '_list')
2381 ('symbol', '_list')
2376 ('string', '0\x001\x002\x00-2\x00tip\x00null')
2382 ('string', '0\x001\x002\x00-2\x00tip\x00null')
2377 define)
2383 define)
2378 * set:
2384 * set:
2379 <baseset [0, 1, 2, 8, 9, -1]>
2385 <baseset [0, 1, 2, 8, 9, -1]>
2380 0
2386 0
2381 1
2387 1
2382 2
2388 2
2383 8
2389 8
2384 9
2390 9
2385 -1
2391 -1
2386
2392
2387 $ try --optimize '0|1|2:3'
2393 $ try --optimize '0|1|2:3'
2388 (or
2394 (or
2389 (list
2395 (list
2390 ('symbol', '0')
2396 ('symbol', '0')
2391 ('symbol', '1')
2397 ('symbol', '1')
2392 (range
2398 (range
2393 ('symbol', '2')
2399 ('symbol', '2')
2394 ('symbol', '3'))))
2400 ('symbol', '3'))))
2395 * optimized:
2401 * optimized:
2396 (or
2402 (or
2397 (list
2403 (list
2398 (func
2404 (func
2399 ('symbol', '_list')
2405 ('symbol', '_list')
2400 ('string', '0\x001')
2406 ('string', '0\x001')
2401 define)
2407 define)
2402 (range
2408 (range
2403 ('symbol', '2')
2409 ('symbol', '2')
2404 ('symbol', '3')
2410 ('symbol', '3')
2405 define))
2411 define))
2406 define)
2412 define)
2407 * set:
2413 * set:
2408 <addset
2414 <addset
2409 <baseset [0, 1]>,
2415 <baseset [0, 1]>,
2410 <spanset+ 2:3>>
2416 <spanset+ 2:3>>
2411 0
2417 0
2412 1
2418 1
2413 2
2419 2
2414 3
2420 3
2415
2421
2416 $ try --optimize '0:1|2|3:4|5|6'
2422 $ try --optimize '0:1|2|3:4|5|6'
2417 (or
2423 (or
2418 (list
2424 (list
2419 (range
2425 (range
2420 ('symbol', '0')
2426 ('symbol', '0')
2421 ('symbol', '1'))
2427 ('symbol', '1'))
2422 ('symbol', '2')
2428 ('symbol', '2')
2423 (range
2429 (range
2424 ('symbol', '3')
2430 ('symbol', '3')
2425 ('symbol', '4'))
2431 ('symbol', '4'))
2426 ('symbol', '5')
2432 ('symbol', '5')
2427 ('symbol', '6')))
2433 ('symbol', '6')))
2428 * optimized:
2434 * optimized:
2429 (or
2435 (or
2430 (list
2436 (list
2431 (range
2437 (range
2432 ('symbol', '0')
2438 ('symbol', '0')
2433 ('symbol', '1')
2439 ('symbol', '1')
2434 define)
2440 define)
2435 ('symbol', '2')
2441 ('symbol', '2')
2436 (range
2442 (range
2437 ('symbol', '3')
2443 ('symbol', '3')
2438 ('symbol', '4')
2444 ('symbol', '4')
2439 define)
2445 define)
2440 (func
2446 (func
2441 ('symbol', '_list')
2447 ('symbol', '_list')
2442 ('string', '5\x006')
2448 ('string', '5\x006')
2443 define))
2449 define))
2444 define)
2450 define)
2445 * set:
2451 * set:
2446 <addset
2452 <addset
2447 <addset
2453 <addset
2448 <spanset+ 0:1>,
2454 <spanset+ 0:1>,
2449 <baseset [2]>>,
2455 <baseset [2]>>,
2450 <addset
2456 <addset
2451 <spanset+ 3:4>,
2457 <spanset+ 3:4>,
2452 <baseset [5, 6]>>>
2458 <baseset [5, 6]>>>
2453 0
2459 0
2454 1
2460 1
2455 2
2461 2
2456 3
2462 3
2457 4
2463 4
2458 5
2464 5
2459 6
2465 6
2460
2466
2461 unoptimized `or` looks like this
2467 unoptimized `or` looks like this
2462
2468
2463 $ try --no-optimized -p analyzed '0|1|2|3|4'
2469 $ try --no-optimized -p analyzed '0|1|2|3|4'
2464 * analyzed:
2470 * analyzed:
2465 (or
2471 (or
2466 (list
2472 (list
2467 ('symbol', '0')
2473 ('symbol', '0')
2468 ('symbol', '1')
2474 ('symbol', '1')
2469 ('symbol', '2')
2475 ('symbol', '2')
2470 ('symbol', '3')
2476 ('symbol', '3')
2471 ('symbol', '4'))
2477 ('symbol', '4'))
2472 define)
2478 define)
2473 * set:
2479 * set:
2474 <addset
2480 <addset
2475 <addset
2481 <addset
2476 <baseset [0]>,
2482 <baseset [0]>,
2477 <baseset [1]>>,
2483 <baseset [1]>>,
2478 <addset
2484 <addset
2479 <baseset [2]>,
2485 <baseset [2]>,
2480 <addset
2486 <addset
2481 <baseset [3]>,
2487 <baseset [3]>,
2482 <baseset [4]>>>>
2488 <baseset [4]>>>>
2483 0
2489 0
2484 1
2490 1
2485 2
2491 2
2486 3
2492 3
2487 4
2493 4
2488
2494
2489 test that `_list` should be narrowed by provided `subset`
2495 test that `_list` should be narrowed by provided `subset`
2490
2496
2491 $ log '0:2 and (null|1|2|3)'
2497 $ log '0:2 and (null|1|2|3)'
2492 1
2498 1
2493 2
2499 2
2494
2500
2495 test that `_list` should remove duplicates
2501 test that `_list` should remove duplicates
2496
2502
2497 $ log '0|1|2|1|2|-1|tip'
2503 $ log '0|1|2|1|2|-1|tip'
2498 0
2504 0
2499 1
2505 1
2500 2
2506 2
2501 9
2507 9
2502
2508
2503 test unknown revision in `_list`
2509 test unknown revision in `_list`
2504
2510
2505 $ log '0|unknown'
2511 $ log '0|unknown'
2506 abort: unknown revision 'unknown'!
2512 abort: unknown revision 'unknown'!
2507 [255]
2513 [255]
2508
2514
2509 test integer range in `_list`
2515 test integer range in `_list`
2510
2516
2511 $ log '-1|-10'
2517 $ log '-1|-10'
2512 9
2518 9
2513 0
2519 0
2514
2520
2515 $ log '-10|-11'
2521 $ log '-10|-11'
2516 abort: unknown revision '-11'!
2522 abort: unknown revision '-11'!
2517 [255]
2523 [255]
2518
2524
2519 $ log '9|10'
2525 $ log '9|10'
2520 abort: unknown revision '10'!
2526 abort: unknown revision '10'!
2521 [255]
2527 [255]
2522
2528
2523 test '0000' != '0' in `_list`
2529 test '0000' != '0' in `_list`
2524
2530
2525 $ log '0|0000'
2531 $ log '0|0000'
2526 0
2532 0
2527 -1
2533 -1
2528
2534
2529 test ',' in `_list`
2535 test ',' in `_list`
2530 $ log '0,1'
2536 $ log '0,1'
2531 hg: parse error: can't use a list in this context
2537 hg: parse error: can't use a list in this context
2532 (see hg help "revsets.x or y")
2538 (see hg help "revsets.x or y")
2533 [255]
2539 [255]
2534 $ try '0,1,2'
2540 $ try '0,1,2'
2535 (list
2541 (list
2536 ('symbol', '0')
2542 ('symbol', '0')
2537 ('symbol', '1')
2543 ('symbol', '1')
2538 ('symbol', '2'))
2544 ('symbol', '2'))
2539 hg: parse error: can't use a list in this context
2545 hg: parse error: can't use a list in this context
2540 (see hg help "revsets.x or y")
2546 (see hg help "revsets.x or y")
2541 [255]
2547 [255]
2542
2548
2543 test that chained `or` operations make balanced addsets
2549 test that chained `or` operations make balanced addsets
2544
2550
2545 $ try '0:1|1:2|2:3|3:4|4:5'
2551 $ try '0:1|1:2|2:3|3:4|4:5'
2546 (or
2552 (or
2547 (list
2553 (list
2548 (range
2554 (range
2549 ('symbol', '0')
2555 ('symbol', '0')
2550 ('symbol', '1'))
2556 ('symbol', '1'))
2551 (range
2557 (range
2552 ('symbol', '1')
2558 ('symbol', '1')
2553 ('symbol', '2'))
2559 ('symbol', '2'))
2554 (range
2560 (range
2555 ('symbol', '2')
2561 ('symbol', '2')
2556 ('symbol', '3'))
2562 ('symbol', '3'))
2557 (range
2563 (range
2558 ('symbol', '3')
2564 ('symbol', '3')
2559 ('symbol', '4'))
2565 ('symbol', '4'))
2560 (range
2566 (range
2561 ('symbol', '4')
2567 ('symbol', '4')
2562 ('symbol', '5'))))
2568 ('symbol', '5'))))
2563 * set:
2569 * set:
2564 <addset
2570 <addset
2565 <addset
2571 <addset
2566 <spanset+ 0:1>,
2572 <spanset+ 0:1>,
2567 <spanset+ 1:2>>,
2573 <spanset+ 1:2>>,
2568 <addset
2574 <addset
2569 <spanset+ 2:3>,
2575 <spanset+ 2:3>,
2570 <addset
2576 <addset
2571 <spanset+ 3:4>,
2577 <spanset+ 3:4>,
2572 <spanset+ 4:5>>>>
2578 <spanset+ 4:5>>>>
2573 0
2579 0
2574 1
2580 1
2575 2
2581 2
2576 3
2582 3
2577 4
2583 4
2578 5
2584 5
2579
2585
2580 no crash by empty group "()" while optimizing `or` operations
2586 no crash by empty group "()" while optimizing `or` operations
2581
2587
2582 $ try --optimize '0|()'
2588 $ try --optimize '0|()'
2583 (or
2589 (or
2584 (list
2590 (list
2585 ('symbol', '0')
2591 ('symbol', '0')
2586 (group
2592 (group
2587 None)))
2593 None)))
2588 * optimized:
2594 * optimized:
2589 (or
2595 (or
2590 (list
2596 (list
2591 ('symbol', '0')
2597 ('symbol', '0')
2592 None)
2598 None)
2593 define)
2599 define)
2594 hg: parse error: missing argument
2600 hg: parse error: missing argument
2595 [255]
2601 [255]
2596
2602
2597 test that chained `or` operations never eat up stack (issue4624)
2603 test that chained `or` operations never eat up stack (issue4624)
2598 (uses `0:1` instead of `0` to avoid future optimization of trivial revisions)
2604 (uses `0:1` instead of `0` to avoid future optimization of trivial revisions)
2599
2605
2600 $ hg log -T '{rev}\n' -r `python -c "print '+'.join(['0:1'] * 500)"`
2606 $ hg log -T '{rev}\n' -r `python -c "print '+'.join(['0:1'] * 500)"`
2601 0
2607 0
2602 1
2608 1
2603
2609
2604 test that repeated `-r` options never eat up stack (issue4565)
2610 test that repeated `-r` options never eat up stack (issue4565)
2605 (uses `-r 0::1` to avoid possible optimization at old-style parser)
2611 (uses `-r 0::1` to avoid possible optimization at old-style parser)
2606
2612
2607 $ hg log -T '{rev}\n' `python -c "for i in xrange(500): print '-r 0::1 ',"`
2613 $ hg log -T '{rev}\n' `python -c "for i in xrange(500): print '-r 0::1 ',"`
2608 0
2614 0
2609 1
2615 1
2610
2616
2611 check that conversion to only works
2617 check that conversion to only works
2612 $ try --optimize '::3 - ::1'
2618 $ try --optimize '::3 - ::1'
2613 (minus
2619 (minus
2614 (dagrangepre
2620 (dagrangepre
2615 ('symbol', '3'))
2621 ('symbol', '3'))
2616 (dagrangepre
2622 (dagrangepre
2617 ('symbol', '1')))
2623 ('symbol', '1')))
2618 * optimized:
2624 * optimized:
2619 (func
2625 (func
2620 ('symbol', 'only')
2626 ('symbol', 'only')
2621 (list
2627 (list
2622 ('symbol', '3')
2628 ('symbol', '3')
2623 ('symbol', '1'))
2629 ('symbol', '1'))
2624 define)
2630 define)
2625 * set:
2631 * set:
2626 <baseset+ [3]>
2632 <baseset+ [3]>
2627 3
2633 3
2628 $ try --optimize 'ancestors(1) - ancestors(3)'
2634 $ try --optimize 'ancestors(1) - ancestors(3)'
2629 (minus
2635 (minus
2630 (func
2636 (func
2631 ('symbol', 'ancestors')
2637 ('symbol', 'ancestors')
2632 ('symbol', '1'))
2638 ('symbol', '1'))
2633 (func
2639 (func
2634 ('symbol', 'ancestors')
2640 ('symbol', 'ancestors')
2635 ('symbol', '3')))
2641 ('symbol', '3')))
2636 * optimized:
2642 * optimized:
2637 (func
2643 (func
2638 ('symbol', 'only')
2644 ('symbol', 'only')
2639 (list
2645 (list
2640 ('symbol', '1')
2646 ('symbol', '1')
2641 ('symbol', '3'))
2647 ('symbol', '3'))
2642 define)
2648 define)
2643 * set:
2649 * set:
2644 <baseset+ []>
2650 <baseset+ []>
2645 $ try --optimize 'not ::2 and ::6'
2651 $ try --optimize 'not ::2 and ::6'
2646 (and
2652 (and
2647 (not
2653 (not
2648 (dagrangepre
2654 (dagrangepre
2649 ('symbol', '2')))
2655 ('symbol', '2')))
2650 (dagrangepre
2656 (dagrangepre
2651 ('symbol', '6')))
2657 ('symbol', '6')))
2652 * optimized:
2658 * optimized:
2653 (func
2659 (func
2654 ('symbol', 'only')
2660 ('symbol', 'only')
2655 (list
2661 (list
2656 ('symbol', '6')
2662 ('symbol', '6')
2657 ('symbol', '2'))
2663 ('symbol', '2'))
2658 define)
2664 define)
2659 * set:
2665 * set:
2660 <baseset+ [3, 4, 5, 6]>
2666 <baseset+ [3, 4, 5, 6]>
2661 3
2667 3
2662 4
2668 4
2663 5
2669 5
2664 6
2670 6
2665 $ try --optimize 'ancestors(6) and not ancestors(4)'
2671 $ try --optimize 'ancestors(6) and not ancestors(4)'
2666 (and
2672 (and
2667 (func
2673 (func
2668 ('symbol', 'ancestors')
2674 ('symbol', 'ancestors')
2669 ('symbol', '6'))
2675 ('symbol', '6'))
2670 (not
2676 (not
2671 (func
2677 (func
2672 ('symbol', 'ancestors')
2678 ('symbol', 'ancestors')
2673 ('symbol', '4'))))
2679 ('symbol', '4'))))
2674 * optimized:
2680 * optimized:
2675 (func
2681 (func
2676 ('symbol', 'only')
2682 ('symbol', 'only')
2677 (list
2683 (list
2678 ('symbol', '6')
2684 ('symbol', '6')
2679 ('symbol', '4'))
2685 ('symbol', '4'))
2680 define)
2686 define)
2681 * set:
2687 * set:
2682 <baseset+ [3, 5, 6]>
2688 <baseset+ [3, 5, 6]>
2683 3
2689 3
2684 5
2690 5
2685 6
2691 6
2686
2692
2687 no crash by empty group "()" while optimizing to "only()"
2693 no crash by empty group "()" while optimizing to "only()"
2688
2694
2689 $ try --optimize '::1 and ()'
2695 $ try --optimize '::1 and ()'
2690 (and
2696 (and
2691 (dagrangepre
2697 (dagrangepre
2692 ('symbol', '1'))
2698 ('symbol', '1'))
2693 (group
2699 (group
2694 None))
2700 None))
2695 * optimized:
2701 * optimized:
2696 (and
2702 (and
2697 None
2703 None
2698 (func
2704 (func
2699 ('symbol', 'ancestors')
2705 ('symbol', 'ancestors')
2700 ('symbol', '1')
2706 ('symbol', '1')
2701 define)
2707 define)
2702 define)
2708 define)
2703 hg: parse error: missing argument
2709 hg: parse error: missing argument
2704 [255]
2710 [255]
2705
2711
2706 invalid function call should not be optimized to only()
2712 invalid function call should not be optimized to only()
2707
2713
2708 $ log '"ancestors"(6) and not ancestors(4)'
2714 $ log '"ancestors"(6) and not ancestors(4)'
2709 hg: parse error: not a symbol
2715 hg: parse error: not a symbol
2710 [255]
2716 [255]
2711
2717
2712 $ log 'ancestors(6) and not "ancestors"(4)'
2718 $ log 'ancestors(6) and not "ancestors"(4)'
2713 hg: parse error: not a symbol
2719 hg: parse error: not a symbol
2714 [255]
2720 [255]
2715
2721
2716 we can use patterns when searching for tags
2722 we can use patterns when searching for tags
2717
2723
2718 $ log 'tag("1..*")'
2724 $ log 'tag("1..*")'
2719 abort: tag '1..*' does not exist!
2725 abort: tag '1..*' does not exist!
2720 [255]
2726 [255]
2721 $ log 'tag("re:1..*")'
2727 $ log 'tag("re:1..*")'
2722 6
2728 6
2723 $ log 'tag("re:[0-9].[0-9]")'
2729 $ log 'tag("re:[0-9].[0-9]")'
2724 6
2730 6
2725 $ log 'tag("literal:1.0")'
2731 $ log 'tag("literal:1.0")'
2726 6
2732 6
2727 $ log 'tag("re:0..*")'
2733 $ log 'tag("re:0..*")'
2728
2734
2729 $ log 'tag(unknown)'
2735 $ log 'tag(unknown)'
2730 abort: tag 'unknown' does not exist!
2736 abort: tag 'unknown' does not exist!
2731 [255]
2737 [255]
2732 $ log 'tag("re:unknown")'
2738 $ log 'tag("re:unknown")'
2733 $ log 'present(tag("unknown"))'
2739 $ log 'present(tag("unknown"))'
2734 $ log 'present(tag("re:unknown"))'
2740 $ log 'present(tag("re:unknown"))'
2735 $ log 'branch(unknown)'
2741 $ log 'branch(unknown)'
2736 abort: unknown revision 'unknown'!
2742 abort: unknown revision 'unknown'!
2737 [255]
2743 [255]
2738 $ log 'branch("literal:unknown")'
2744 $ log 'branch("literal:unknown")'
2739 abort: branch 'unknown' does not exist!
2745 abort: branch 'unknown' does not exist!
2740 [255]
2746 [255]
2741 $ log 'branch("re:unknown")'
2747 $ log 'branch("re:unknown")'
2742 $ log 'present(branch("unknown"))'
2748 $ log 'present(branch("unknown"))'
2743 $ log 'present(branch("re:unknown"))'
2749 $ log 'present(branch("re:unknown"))'
2744 $ log 'user(bob)'
2750 $ log 'user(bob)'
2745 2
2751 2
2746
2752
2747 $ log '4::8'
2753 $ log '4::8'
2748 4
2754 4
2749 8
2755 8
2750 $ log '4:8'
2756 $ log '4:8'
2751 4
2757 4
2752 5
2758 5
2753 6
2759 6
2754 7
2760 7
2755 8
2761 8
2756
2762
2757 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
2763 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
2758 4
2764 4
2759 2
2765 2
2760 5
2766 5
2761
2767
2762 $ log 'not 0 and 0:2'
2768 $ log 'not 0 and 0:2'
2763 1
2769 1
2764 2
2770 2
2765 $ log 'not 1 and 0:2'
2771 $ log 'not 1 and 0:2'
2766 0
2772 0
2767 2
2773 2
2768 $ log 'not 2 and 0:2'
2774 $ log 'not 2 and 0:2'
2769 0
2775 0
2770 1
2776 1
2771 $ log '(1 and 2)::'
2777 $ log '(1 and 2)::'
2772 $ log '(1 and 2):'
2778 $ log '(1 and 2):'
2773 $ log '(1 and 2):3'
2779 $ log '(1 and 2):3'
2774 $ log 'sort(head(), -rev)'
2780 $ log 'sort(head(), -rev)'
2775 9
2781 9
2776 7
2782 7
2777 6
2783 6
2778 5
2784 5
2779 4
2785 4
2780 3
2786 3
2781 2
2787 2
2782 1
2788 1
2783 0
2789 0
2784 $ log '4::8 - 8'
2790 $ log '4::8 - 8'
2785 4
2791 4
2786
2792
2787 matching() should preserve the order of the input set:
2793 matching() should preserve the order of the input set:
2788
2794
2789 $ log '(2 or 3 or 1) and matching(1 or 2 or 3)'
2795 $ log '(2 or 3 or 1) and matching(1 or 2 or 3)'
2790 2
2796 2
2791 3
2797 3
2792 1
2798 1
2793
2799
2794 $ log 'named("unknown")'
2800 $ log 'named("unknown")'
2795 abort: namespace 'unknown' does not exist!
2801 abort: namespace 'unknown' does not exist!
2796 [255]
2802 [255]
2797 $ log 'named("re:unknown")'
2803 $ log 'named("re:unknown")'
2798 abort: no namespace exists that match 'unknown'!
2804 abort: no namespace exists that match 'unknown'!
2799 [255]
2805 [255]
2800 $ log 'present(named("unknown"))'
2806 $ log 'present(named("unknown"))'
2801 $ log 'present(named("re:unknown"))'
2807 $ log 'present(named("re:unknown"))'
2802
2808
2803 $ log 'tag()'
2809 $ log 'tag()'
2804 6
2810 6
2805 $ log 'named("tags")'
2811 $ log 'named("tags")'
2806 6
2812 6
2807
2813
2808 issue2437
2814 issue2437
2809
2815
2810 $ log '3 and p1(5)'
2816 $ log '3 and p1(5)'
2811 3
2817 3
2812 $ log '4 and p2(6)'
2818 $ log '4 and p2(6)'
2813 4
2819 4
2814 $ log '1 and parents(:2)'
2820 $ log '1 and parents(:2)'
2815 1
2821 1
2816 $ log '2 and children(1:)'
2822 $ log '2 and children(1:)'
2817 2
2823 2
2818 $ log 'roots(all()) or roots(all())'
2824 $ log 'roots(all()) or roots(all())'
2819 0
2825 0
2820 $ hg debugrevspec 'roots(all()) or roots(all())'
2826 $ hg debugrevspec 'roots(all()) or roots(all())'
2821 0
2827 0
2822 $ log 'heads(branch(Γ©)) or heads(branch(Γ©))'
2828 $ log 'heads(branch(Γ©)) or heads(branch(Γ©))'
2823 9
2829 9
2824 $ log 'ancestors(8) and (heads(branch("-a-b-c-")) or heads(branch(Γ©)))'
2830 $ log 'ancestors(8) and (heads(branch("-a-b-c-")) or heads(branch(Γ©)))'
2825 4
2831 4
2826
2832
2827 issue2654: report a parse error if the revset was not completely parsed
2833 issue2654: report a parse error if the revset was not completely parsed
2828
2834
2829 $ log '1 OR 2'
2835 $ log '1 OR 2'
2830 hg: parse error at 2: invalid token
2836 hg: parse error at 2: invalid token
2831 [255]
2837 [255]
2832
2838
2833 or operator should preserve ordering:
2839 or operator should preserve ordering:
2834 $ log 'reverse(2::4) or tip'
2840 $ log 'reverse(2::4) or tip'
2835 4
2841 4
2836 2
2842 2
2837 9
2843 9
2838
2844
2839 parentrevspec
2845 parentrevspec
2840
2846
2841 $ log 'merge()^0'
2847 $ log 'merge()^0'
2842 6
2848 6
2843 $ log 'merge()^'
2849 $ log 'merge()^'
2844 5
2850 5
2845 $ log 'merge()^1'
2851 $ log 'merge()^1'
2846 5
2852 5
2847 $ log 'merge()^2'
2853 $ log 'merge()^2'
2848 4
2854 4
2849 $ log '(not merge())^2'
2855 $ log '(not merge())^2'
2850 $ log 'merge()^^'
2856 $ log 'merge()^^'
2851 3
2857 3
2852 $ log 'merge()^1^'
2858 $ log 'merge()^1^'
2853 3
2859 3
2854 $ log 'merge()^^^'
2860 $ log 'merge()^^^'
2855 1
2861 1
2856
2862
2857 $ log 'merge()~0'
2863 $ log 'merge()~0'
2858 6
2864 6
2859 $ log 'merge()~1'
2865 $ log 'merge()~1'
2860 5
2866 5
2861 $ log 'merge()~2'
2867 $ log 'merge()~2'
2862 3
2868 3
2863 $ log 'merge()~2^1'
2869 $ log 'merge()~2^1'
2864 1
2870 1
2865 $ log 'merge()~3'
2871 $ log 'merge()~3'
2866 1
2872 1
2867
2873
2868 $ log '(-3:tip)^'
2874 $ log '(-3:tip)^'
2869 4
2875 4
2870 6
2876 6
2871 8
2877 8
2872
2878
2873 $ log 'tip^foo'
2879 $ log 'tip^foo'
2874 hg: parse error: ^ expects a number 0, 1, or 2
2880 hg: parse error: ^ expects a number 0, 1, or 2
2875 [255]
2881 [255]
2876
2882
2877 Bogus function gets suggestions
2883 Bogus function gets suggestions
2878 $ log 'add()'
2884 $ log 'add()'
2879 hg: parse error: unknown identifier: add
2885 hg: parse error: unknown identifier: add
2880 (did you mean adds?)
2886 (did you mean adds?)
2881 [255]
2887 [255]
2882 $ log 'added()'
2888 $ log 'added()'
2883 hg: parse error: unknown identifier: added
2889 hg: parse error: unknown identifier: added
2884 (did you mean adds?)
2890 (did you mean adds?)
2885 [255]
2891 [255]
2886 $ log 'remo()'
2892 $ log 'remo()'
2887 hg: parse error: unknown identifier: remo
2893 hg: parse error: unknown identifier: remo
2888 (did you mean one of remote, removes?)
2894 (did you mean one of remote, removes?)
2889 [255]
2895 [255]
2890 $ log 'babar()'
2896 $ log 'babar()'
2891 hg: parse error: unknown identifier: babar
2897 hg: parse error: unknown identifier: babar
2892 [255]
2898 [255]
2893
2899
2894 Bogus function with a similar internal name doesn't suggest the internal name
2900 Bogus function with a similar internal name doesn't suggest the internal name
2895 $ log 'matches()'
2901 $ log 'matches()'
2896 hg: parse error: unknown identifier: matches
2902 hg: parse error: unknown identifier: matches
2897 (did you mean matching?)
2903 (did you mean matching?)
2898 [255]
2904 [255]
2899
2905
2900 Undocumented functions aren't suggested as similar either
2906 Undocumented functions aren't suggested as similar either
2901 $ log 'tagged2()'
2907 $ log 'tagged2()'
2902 hg: parse error: unknown identifier: tagged2
2908 hg: parse error: unknown identifier: tagged2
2903 [255]
2909 [255]
2904
2910
2905 multiple revspecs
2911 multiple revspecs
2906
2912
2907 $ hg log -r 'tip~1:tip' -r 'tip~2:tip~1' --template '{rev}\n'
2913 $ hg log -r 'tip~1:tip' -r 'tip~2:tip~1' --template '{rev}\n'
2908 8
2914 8
2909 9
2915 9
2910 4
2916 4
2911 5
2917 5
2912 6
2918 6
2913 7
2919 7
2914
2920
2915 test usage in revpair (with "+")
2921 test usage in revpair (with "+")
2916
2922
2917 (real pair)
2923 (real pair)
2918
2924
2919 $ hg diff -r 'tip^^' -r 'tip'
2925 $ hg diff -r 'tip^^' -r 'tip'
2920 diff -r 2326846efdab -r 24286f4ae135 .hgtags
2926 diff -r 2326846efdab -r 24286f4ae135 .hgtags
2921 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2927 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2922 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
2928 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
2923 @@ -0,0 +1,1 @@
2929 @@ -0,0 +1,1 @@
2924 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
2930 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
2925 $ hg diff -r 'tip^^::tip'
2931 $ hg diff -r 'tip^^::tip'
2926 diff -r 2326846efdab -r 24286f4ae135 .hgtags
2932 diff -r 2326846efdab -r 24286f4ae135 .hgtags
2927 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2933 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2928 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
2934 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
2929 @@ -0,0 +1,1 @@
2935 @@ -0,0 +1,1 @@
2930 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
2936 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
2931
2937
2932 (single rev)
2938 (single rev)
2933
2939
2934 $ hg diff -r 'tip^' -r 'tip^'
2940 $ hg diff -r 'tip^' -r 'tip^'
2935 $ hg diff -r 'tip^:tip^'
2941 $ hg diff -r 'tip^:tip^'
2936
2942
2937 (single rev that does not looks like a range)
2943 (single rev that does not looks like a range)
2938
2944
2939 $ hg diff -r 'tip^::tip^ or tip^'
2945 $ hg diff -r 'tip^::tip^ or tip^'
2940 diff -r d5d0dcbdc4d9 .hgtags
2946 diff -r d5d0dcbdc4d9 .hgtags
2941 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2947 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2942 +++ b/.hgtags * (glob)
2948 +++ b/.hgtags * (glob)
2943 @@ -0,0 +1,1 @@
2949 @@ -0,0 +1,1 @@
2944 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
2950 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
2945 $ hg diff -r 'tip^ or tip^'
2951 $ hg diff -r 'tip^ or tip^'
2946 diff -r d5d0dcbdc4d9 .hgtags
2952 diff -r d5d0dcbdc4d9 .hgtags
2947 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2953 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2948 +++ b/.hgtags * (glob)
2954 +++ b/.hgtags * (glob)
2949 @@ -0,0 +1,1 @@
2955 @@ -0,0 +1,1 @@
2950 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
2956 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
2951
2957
2952 (no rev)
2958 (no rev)
2953
2959
2954 $ hg diff -r 'author("babar") or author("celeste")'
2960 $ hg diff -r 'author("babar") or author("celeste")'
2955 abort: empty revision range
2961 abort: empty revision range
2956 [255]
2962 [255]
2957
2963
2958 aliases:
2964 aliases:
2959
2965
2960 $ echo '[revsetalias]' >> .hg/hgrc
2966 $ echo '[revsetalias]' >> .hg/hgrc
2961 $ echo 'm = merge()' >> .hg/hgrc
2967 $ echo 'm = merge()' >> .hg/hgrc
2962 (revset aliases can override builtin revsets)
2968 (revset aliases can override builtin revsets)
2963 $ echo 'p2($1) = p1($1)' >> .hg/hgrc
2969 $ echo 'p2($1) = p1($1)' >> .hg/hgrc
2964 $ echo 'sincem = descendants(m)' >> .hg/hgrc
2970 $ echo 'sincem = descendants(m)' >> .hg/hgrc
2965 $ echo 'd($1) = reverse(sort($1, date))' >> .hg/hgrc
2971 $ echo 'd($1) = reverse(sort($1, date))' >> .hg/hgrc
2966 $ echo 'rs(ARG1, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
2972 $ echo 'rs(ARG1, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
2967 $ echo 'rs4(ARG1, ARGA, ARGB, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
2973 $ echo 'rs4(ARG1, ARGA, ARGB, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
2968
2974
2969 $ try m
2975 $ try m
2970 ('symbol', 'm')
2976 ('symbol', 'm')
2971 * expanded:
2977 * expanded:
2972 (func
2978 (func
2973 ('symbol', 'merge')
2979 ('symbol', 'merge')
2974 None)
2980 None)
2975 * set:
2981 * set:
2976 <filteredset
2982 <filteredset
2977 <fullreposet+ 0:9>,
2983 <fullreposet+ 0:9>,
2978 <merge>>
2984 <merge>>
2979 6
2985 6
2980
2986
2981 $ HGPLAIN=1
2987 $ HGPLAIN=1
2982 $ export HGPLAIN
2988 $ export HGPLAIN
2983 $ try m
2989 $ try m
2984 ('symbol', 'm')
2990 ('symbol', 'm')
2985 abort: unknown revision 'm'!
2991 abort: unknown revision 'm'!
2986 [255]
2992 [255]
2987
2993
2988 $ HGPLAINEXCEPT=revsetalias
2994 $ HGPLAINEXCEPT=revsetalias
2989 $ export HGPLAINEXCEPT
2995 $ export HGPLAINEXCEPT
2990 $ try m
2996 $ try m
2991 ('symbol', 'm')
2997 ('symbol', 'm')
2992 * expanded:
2998 * expanded:
2993 (func
2999 (func
2994 ('symbol', 'merge')
3000 ('symbol', 'merge')
2995 None)
3001 None)
2996 * set:
3002 * set:
2997 <filteredset
3003 <filteredset
2998 <fullreposet+ 0:9>,
3004 <fullreposet+ 0:9>,
2999 <merge>>
3005 <merge>>
3000 6
3006 6
3001
3007
3002 $ unset HGPLAIN
3008 $ unset HGPLAIN
3003 $ unset HGPLAINEXCEPT
3009 $ unset HGPLAINEXCEPT
3004
3010
3005 $ try 'p2(.)'
3011 $ try 'p2(.)'
3006 (func
3012 (func
3007 ('symbol', 'p2')
3013 ('symbol', 'p2')
3008 ('symbol', '.'))
3014 ('symbol', '.'))
3009 * expanded:
3015 * expanded:
3010 (func
3016 (func
3011 ('symbol', 'p1')
3017 ('symbol', 'p1')
3012 ('symbol', '.'))
3018 ('symbol', '.'))
3013 * set:
3019 * set:
3014 <baseset+ [8]>
3020 <baseset+ [8]>
3015 8
3021 8
3016
3022
3017 $ HGPLAIN=1
3023 $ HGPLAIN=1
3018 $ export HGPLAIN
3024 $ export HGPLAIN
3019 $ try 'p2(.)'
3025 $ try 'p2(.)'
3020 (func
3026 (func
3021 ('symbol', 'p2')
3027 ('symbol', 'p2')
3022 ('symbol', '.'))
3028 ('symbol', '.'))
3023 * set:
3029 * set:
3024 <baseset+ []>
3030 <baseset+ []>
3025
3031
3026 $ HGPLAINEXCEPT=revsetalias
3032 $ HGPLAINEXCEPT=revsetalias
3027 $ export HGPLAINEXCEPT
3033 $ export HGPLAINEXCEPT
3028 $ try 'p2(.)'
3034 $ try 'p2(.)'
3029 (func
3035 (func
3030 ('symbol', 'p2')
3036 ('symbol', 'p2')
3031 ('symbol', '.'))
3037 ('symbol', '.'))
3032 * expanded:
3038 * expanded:
3033 (func
3039 (func
3034 ('symbol', 'p1')
3040 ('symbol', 'p1')
3035 ('symbol', '.'))
3041 ('symbol', '.'))
3036 * set:
3042 * set:
3037 <baseset+ [8]>
3043 <baseset+ [8]>
3038 8
3044 8
3039
3045
3040 $ unset HGPLAIN
3046 $ unset HGPLAIN
3041 $ unset HGPLAINEXCEPT
3047 $ unset HGPLAINEXCEPT
3042
3048
3043 test alias recursion
3049 test alias recursion
3044
3050
3045 $ try sincem
3051 $ try sincem
3046 ('symbol', 'sincem')
3052 ('symbol', 'sincem')
3047 * expanded:
3053 * expanded:
3048 (func
3054 (func
3049 ('symbol', 'descendants')
3055 ('symbol', 'descendants')
3050 (func
3056 (func
3051 ('symbol', 'merge')
3057 ('symbol', 'merge')
3052 None))
3058 None))
3053 * set:
3059 * set:
3054 <addset+
3060 <addset+
3055 <filteredset
3061 <filteredset
3056 <fullreposet+ 0:9>,
3062 <fullreposet+ 0:9>,
3057 <merge>>,
3063 <merge>>,
3058 <generatorset+>>
3064 <generatorset+>>
3059 6
3065 6
3060 7
3066 7
3061
3067
3062 test infinite recursion
3068 test infinite recursion
3063
3069
3064 $ echo 'recurse1 = recurse2' >> .hg/hgrc
3070 $ echo 'recurse1 = recurse2' >> .hg/hgrc
3065 $ echo 'recurse2 = recurse1' >> .hg/hgrc
3071 $ echo 'recurse2 = recurse1' >> .hg/hgrc
3066 $ try recurse1
3072 $ try recurse1
3067 ('symbol', 'recurse1')
3073 ('symbol', 'recurse1')
3068 hg: parse error: infinite expansion of revset alias "recurse1" detected
3074 hg: parse error: infinite expansion of revset alias "recurse1" detected
3069 [255]
3075 [255]
3070
3076
3071 $ echo 'level1($1, $2) = $1 or $2' >> .hg/hgrc
3077 $ echo 'level1($1, $2) = $1 or $2' >> .hg/hgrc
3072 $ echo 'level2($1, $2) = level1($2, $1)' >> .hg/hgrc
3078 $ echo 'level2($1, $2) = level1($2, $1)' >> .hg/hgrc
3073 $ try "level2(level1(1, 2), 3)"
3079 $ try "level2(level1(1, 2), 3)"
3074 (func
3080 (func
3075 ('symbol', 'level2')
3081 ('symbol', 'level2')
3076 (list
3082 (list
3077 (func
3083 (func
3078 ('symbol', 'level1')
3084 ('symbol', 'level1')
3079 (list
3085 (list
3080 ('symbol', '1')
3086 ('symbol', '1')
3081 ('symbol', '2')))
3087 ('symbol', '2')))
3082 ('symbol', '3')))
3088 ('symbol', '3')))
3083 * expanded:
3089 * expanded:
3084 (or
3090 (or
3085 (list
3091 (list
3086 ('symbol', '3')
3092 ('symbol', '3')
3087 (or
3093 (or
3088 (list
3094 (list
3089 ('symbol', '1')
3095 ('symbol', '1')
3090 ('symbol', '2')))))
3096 ('symbol', '2')))))
3091 * set:
3097 * set:
3092 <addset
3098 <addset
3093 <baseset [3]>,
3099 <baseset [3]>,
3094 <baseset [1, 2]>>
3100 <baseset [1, 2]>>
3095 3
3101 3
3096 1
3102 1
3097 2
3103 2
3098
3104
3099 test nesting and variable passing
3105 test nesting and variable passing
3100
3106
3101 $ echo 'nested($1) = nested2($1)' >> .hg/hgrc
3107 $ echo 'nested($1) = nested2($1)' >> .hg/hgrc
3102 $ echo 'nested2($1) = nested3($1)' >> .hg/hgrc
3108 $ echo 'nested2($1) = nested3($1)' >> .hg/hgrc
3103 $ echo 'nested3($1) = max($1)' >> .hg/hgrc
3109 $ echo 'nested3($1) = max($1)' >> .hg/hgrc
3104 $ try 'nested(2:5)'
3110 $ try 'nested(2:5)'
3105 (func
3111 (func
3106 ('symbol', 'nested')
3112 ('symbol', 'nested')
3107 (range
3113 (range
3108 ('symbol', '2')
3114 ('symbol', '2')
3109 ('symbol', '5')))
3115 ('symbol', '5')))
3110 * expanded:
3116 * expanded:
3111 (func
3117 (func
3112 ('symbol', 'max')
3118 ('symbol', 'max')
3113 (range
3119 (range
3114 ('symbol', '2')
3120 ('symbol', '2')
3115 ('symbol', '5')))
3121 ('symbol', '5')))
3116 * set:
3122 * set:
3117 <baseset
3123 <baseset
3118 <max
3124 <max
3119 <fullreposet+ 0:9>,
3125 <fullreposet+ 0:9>,
3120 <spanset+ 2:5>>>
3126 <spanset+ 2:5>>>
3121 5
3127 5
3122
3128
3123 test chained `or` operations are flattened at parsing phase
3129 test chained `or` operations are flattened at parsing phase
3124
3130
3125 $ echo 'chainedorops($1, $2, $3) = $1|$2|$3' >> .hg/hgrc
3131 $ echo 'chainedorops($1, $2, $3) = $1|$2|$3' >> .hg/hgrc
3126 $ try 'chainedorops(0:1, 1:2, 2:3)'
3132 $ try 'chainedorops(0:1, 1:2, 2:3)'
3127 (func
3133 (func
3128 ('symbol', 'chainedorops')
3134 ('symbol', 'chainedorops')
3129 (list
3135 (list
3130 (range
3136 (range
3131 ('symbol', '0')
3137 ('symbol', '0')
3132 ('symbol', '1'))
3138 ('symbol', '1'))
3133 (range
3139 (range
3134 ('symbol', '1')
3140 ('symbol', '1')
3135 ('symbol', '2'))
3141 ('symbol', '2'))
3136 (range
3142 (range
3137 ('symbol', '2')
3143 ('symbol', '2')
3138 ('symbol', '3'))))
3144 ('symbol', '3'))))
3139 * expanded:
3145 * expanded:
3140 (or
3146 (or
3141 (list
3147 (list
3142 (range
3148 (range
3143 ('symbol', '0')
3149 ('symbol', '0')
3144 ('symbol', '1'))
3150 ('symbol', '1'))
3145 (range
3151 (range
3146 ('symbol', '1')
3152 ('symbol', '1')
3147 ('symbol', '2'))
3153 ('symbol', '2'))
3148 (range
3154 (range
3149 ('symbol', '2')
3155 ('symbol', '2')
3150 ('symbol', '3'))))
3156 ('symbol', '3'))))
3151 * set:
3157 * set:
3152 <addset
3158 <addset
3153 <spanset+ 0:1>,
3159 <spanset+ 0:1>,
3154 <addset
3160 <addset
3155 <spanset+ 1:2>,
3161 <spanset+ 1:2>,
3156 <spanset+ 2:3>>>
3162 <spanset+ 2:3>>>
3157 0
3163 0
3158 1
3164 1
3159 2
3165 2
3160 3
3166 3
3161
3167
3162 test variable isolation, variable placeholders are rewritten as string
3168 test variable isolation, variable placeholders are rewritten as string
3163 then parsed and matched again as string. Check they do not leak too
3169 then parsed and matched again as string. Check they do not leak too
3164 far away.
3170 far away.
3165
3171
3166 $ echo 'injectparamasstring = max("$1")' >> .hg/hgrc
3172 $ echo 'injectparamasstring = max("$1")' >> .hg/hgrc
3167 $ echo 'callinjection($1) = descendants(injectparamasstring)' >> .hg/hgrc
3173 $ echo 'callinjection($1) = descendants(injectparamasstring)' >> .hg/hgrc
3168 $ try 'callinjection(2:5)'
3174 $ try 'callinjection(2:5)'
3169 (func
3175 (func
3170 ('symbol', 'callinjection')
3176 ('symbol', 'callinjection')
3171 (range
3177 (range
3172 ('symbol', '2')
3178 ('symbol', '2')
3173 ('symbol', '5')))
3179 ('symbol', '5')))
3174 * expanded:
3180 * expanded:
3175 (func
3181 (func
3176 ('symbol', 'descendants')
3182 ('symbol', 'descendants')
3177 (func
3183 (func
3178 ('symbol', 'max')
3184 ('symbol', 'max')
3179 ('string', '$1')))
3185 ('string', '$1')))
3180 abort: unknown revision '$1'!
3186 abort: unknown revision '$1'!
3181 [255]
3187 [255]
3182
3188
3183 test scope of alias expansion: 'universe' is expanded prior to 'shadowall(0)',
3189 test scope of alias expansion: 'universe' is expanded prior to 'shadowall(0)',
3184 but 'all()' should never be substituted to '0()'.
3190 but 'all()' should never be substituted to '0()'.
3185
3191
3186 $ echo 'universe = all()' >> .hg/hgrc
3192 $ echo 'universe = all()' >> .hg/hgrc
3187 $ echo 'shadowall(all) = all and universe' >> .hg/hgrc
3193 $ echo 'shadowall(all) = all and universe' >> .hg/hgrc
3188 $ try 'shadowall(0)'
3194 $ try 'shadowall(0)'
3189 (func
3195 (func
3190 ('symbol', 'shadowall')
3196 ('symbol', 'shadowall')
3191 ('symbol', '0'))
3197 ('symbol', '0'))
3192 * expanded:
3198 * expanded:
3193 (and
3199 (and
3194 ('symbol', '0')
3200 ('symbol', '0')
3195 (func
3201 (func
3196 ('symbol', 'all')
3202 ('symbol', 'all')
3197 None))
3203 None))
3198 * set:
3204 * set:
3199 <filteredset
3205 <filteredset
3200 <baseset [0]>,
3206 <baseset [0]>,
3201 <spanset+ 0:9>>
3207 <spanset+ 0:9>>
3202 0
3208 0
3203
3209
3204 test unknown reference:
3210 test unknown reference:
3205
3211
3206 $ try "unknownref(0)" --config 'revsetalias.unknownref($1)=$1:$2'
3212 $ try "unknownref(0)" --config 'revsetalias.unknownref($1)=$1:$2'
3207 (func
3213 (func
3208 ('symbol', 'unknownref')
3214 ('symbol', 'unknownref')
3209 ('symbol', '0'))
3215 ('symbol', '0'))
3210 abort: bad definition of revset alias "unknownref": invalid symbol '$2'
3216 abort: bad definition of revset alias "unknownref": invalid symbol '$2'
3211 [255]
3217 [255]
3212
3218
3213 $ hg debugrevspec --debug --config revsetalias.anotherbadone='branch(' "tip"
3219 $ hg debugrevspec --debug --config revsetalias.anotherbadone='branch(' "tip"
3214 ('symbol', 'tip')
3220 ('symbol', 'tip')
3215 warning: bad definition of revset alias "anotherbadone": at 7: not a prefix: end
3221 warning: bad definition of revset alias "anotherbadone": at 7: not a prefix: end
3216 * set:
3222 * set:
3217 <baseset [9]>
3223 <baseset [9]>
3218 9
3224 9
3219
3225
3220 $ try 'tip'
3226 $ try 'tip'
3221 ('symbol', 'tip')
3227 ('symbol', 'tip')
3222 * set:
3228 * set:
3223 <baseset [9]>
3229 <baseset [9]>
3224 9
3230 9
3225
3231
3226 $ hg debugrevspec --debug --config revsetalias.'bad name'='tip' "tip"
3232 $ hg debugrevspec --debug --config revsetalias.'bad name'='tip' "tip"
3227 ('symbol', 'tip')
3233 ('symbol', 'tip')
3228 warning: bad declaration of revset alias "bad name": at 4: invalid token
3234 warning: bad declaration of revset alias "bad name": at 4: invalid token
3229 * set:
3235 * set:
3230 <baseset [9]>
3236 <baseset [9]>
3231 9
3237 9
3232 $ echo 'strictreplacing($1, $10) = $10 or desc("$1")' >> .hg/hgrc
3238 $ echo 'strictreplacing($1, $10) = $10 or desc("$1")' >> .hg/hgrc
3233 $ try 'strictreplacing("foo", tip)'
3239 $ try 'strictreplacing("foo", tip)'
3234 (func
3240 (func
3235 ('symbol', 'strictreplacing')
3241 ('symbol', 'strictreplacing')
3236 (list
3242 (list
3237 ('string', 'foo')
3243 ('string', 'foo')
3238 ('symbol', 'tip')))
3244 ('symbol', 'tip')))
3239 * expanded:
3245 * expanded:
3240 (or
3246 (or
3241 (list
3247 (list
3242 ('symbol', 'tip')
3248 ('symbol', 'tip')
3243 (func
3249 (func
3244 ('symbol', 'desc')
3250 ('symbol', 'desc')
3245 ('string', '$1'))))
3251 ('string', '$1'))))
3246 * set:
3252 * set:
3247 <addset
3253 <addset
3248 <baseset [9]>,
3254 <baseset [9]>,
3249 <filteredset
3255 <filteredset
3250 <fullreposet+ 0:9>,
3256 <fullreposet+ 0:9>,
3251 <desc '$1'>>>
3257 <desc '$1'>>>
3252 9
3258 9
3253
3259
3254 $ try 'd(2:5)'
3260 $ try 'd(2:5)'
3255 (func
3261 (func
3256 ('symbol', 'd')
3262 ('symbol', 'd')
3257 (range
3263 (range
3258 ('symbol', '2')
3264 ('symbol', '2')
3259 ('symbol', '5')))
3265 ('symbol', '5')))
3260 * expanded:
3266 * expanded:
3261 (func
3267 (func
3262 ('symbol', 'reverse')
3268 ('symbol', 'reverse')
3263 (func
3269 (func
3264 ('symbol', 'sort')
3270 ('symbol', 'sort')
3265 (list
3271 (list
3266 (range
3272 (range
3267 ('symbol', '2')
3273 ('symbol', '2')
3268 ('symbol', '5'))
3274 ('symbol', '5'))
3269 ('symbol', 'date'))))
3275 ('symbol', 'date'))))
3270 * set:
3276 * set:
3271 <baseset [4, 5, 3, 2]>
3277 <baseset [4, 5, 3, 2]>
3272 4
3278 4
3273 5
3279 5
3274 3
3280 3
3275 2
3281 2
3276 $ try 'rs(2 or 3, date)'
3282 $ try 'rs(2 or 3, date)'
3277 (func
3283 (func
3278 ('symbol', 'rs')
3284 ('symbol', 'rs')
3279 (list
3285 (list
3280 (or
3286 (or
3281 (list
3287 (list
3282 ('symbol', '2')
3288 ('symbol', '2')
3283 ('symbol', '3')))
3289 ('symbol', '3')))
3284 ('symbol', 'date')))
3290 ('symbol', 'date')))
3285 * expanded:
3291 * expanded:
3286 (func
3292 (func
3287 ('symbol', 'reverse')
3293 ('symbol', 'reverse')
3288 (func
3294 (func
3289 ('symbol', 'sort')
3295 ('symbol', 'sort')
3290 (list
3296 (list
3291 (or
3297 (or
3292 (list
3298 (list
3293 ('symbol', '2')
3299 ('symbol', '2')
3294 ('symbol', '3')))
3300 ('symbol', '3')))
3295 ('symbol', 'date'))))
3301 ('symbol', 'date'))))
3296 * set:
3302 * set:
3297 <baseset [3, 2]>
3303 <baseset [3, 2]>
3298 3
3304 3
3299 2
3305 2
3300 $ try 'rs()'
3306 $ try 'rs()'
3301 (func
3307 (func
3302 ('symbol', 'rs')
3308 ('symbol', 'rs')
3303 None)
3309 None)
3304 hg: parse error: invalid number of arguments: 0
3310 hg: parse error: invalid number of arguments: 0
3305 [255]
3311 [255]
3306 $ try 'rs(2)'
3312 $ try 'rs(2)'
3307 (func
3313 (func
3308 ('symbol', 'rs')
3314 ('symbol', 'rs')
3309 ('symbol', '2'))
3315 ('symbol', '2'))
3310 hg: parse error: invalid number of arguments: 1
3316 hg: parse error: invalid number of arguments: 1
3311 [255]
3317 [255]
3312 $ try 'rs(2, data, 7)'
3318 $ try 'rs(2, data, 7)'
3313 (func
3319 (func
3314 ('symbol', 'rs')
3320 ('symbol', 'rs')
3315 (list
3321 (list
3316 ('symbol', '2')
3322 ('symbol', '2')
3317 ('symbol', 'data')
3323 ('symbol', 'data')
3318 ('symbol', '7')))
3324 ('symbol', '7')))
3319 hg: parse error: invalid number of arguments: 3
3325 hg: parse error: invalid number of arguments: 3
3320 [255]
3326 [255]
3321 $ try 'rs4(2 or 3, x, x, date)'
3327 $ try 'rs4(2 or 3, x, x, date)'
3322 (func
3328 (func
3323 ('symbol', 'rs4')
3329 ('symbol', 'rs4')
3324 (list
3330 (list
3325 (or
3331 (or
3326 (list
3332 (list
3327 ('symbol', '2')
3333 ('symbol', '2')
3328 ('symbol', '3')))
3334 ('symbol', '3')))
3329 ('symbol', 'x')
3335 ('symbol', 'x')
3330 ('symbol', 'x')
3336 ('symbol', 'x')
3331 ('symbol', 'date')))
3337 ('symbol', 'date')))
3332 * expanded:
3338 * expanded:
3333 (func
3339 (func
3334 ('symbol', 'reverse')
3340 ('symbol', 'reverse')
3335 (func
3341 (func
3336 ('symbol', 'sort')
3342 ('symbol', 'sort')
3337 (list
3343 (list
3338 (or
3344 (or
3339 (list
3345 (list
3340 ('symbol', '2')
3346 ('symbol', '2')
3341 ('symbol', '3')))
3347 ('symbol', '3')))
3342 ('symbol', 'date'))))
3348 ('symbol', 'date'))))
3343 * set:
3349 * set:
3344 <baseset [3, 2]>
3350 <baseset [3, 2]>
3345 3
3351 3
3346 2
3352 2
3347
3353
3348 issue4553: check that revset aliases override existing hash prefix
3354 issue4553: check that revset aliases override existing hash prefix
3349
3355
3350 $ hg log -qr e
3356 $ hg log -qr e
3351 6:e0cc66ef77e8
3357 6:e0cc66ef77e8
3352
3358
3353 $ hg log -qr e --config revsetalias.e="all()"
3359 $ hg log -qr e --config revsetalias.e="all()"
3354 0:2785f51eece5
3360 0:2785f51eece5
3355 1:d75937da8da0
3361 1:d75937da8da0
3356 2:5ed5505e9f1c
3362 2:5ed5505e9f1c
3357 3:8528aa5637f2
3363 3:8528aa5637f2
3358 4:2326846efdab
3364 4:2326846efdab
3359 5:904fa392b941
3365 5:904fa392b941
3360 6:e0cc66ef77e8
3366 6:e0cc66ef77e8
3361 7:013af1973af4
3367 7:013af1973af4
3362 8:d5d0dcbdc4d9
3368 8:d5d0dcbdc4d9
3363 9:24286f4ae135
3369 9:24286f4ae135
3364
3370
3365 $ hg log -qr e: --config revsetalias.e="0"
3371 $ hg log -qr e: --config revsetalias.e="0"
3366 0:2785f51eece5
3372 0:2785f51eece5
3367 1:d75937da8da0
3373 1:d75937da8da0
3368 2:5ed5505e9f1c
3374 2:5ed5505e9f1c
3369 3:8528aa5637f2
3375 3:8528aa5637f2
3370 4:2326846efdab
3376 4:2326846efdab
3371 5:904fa392b941
3377 5:904fa392b941
3372 6:e0cc66ef77e8
3378 6:e0cc66ef77e8
3373 7:013af1973af4
3379 7:013af1973af4
3374 8:d5d0dcbdc4d9
3380 8:d5d0dcbdc4d9
3375 9:24286f4ae135
3381 9:24286f4ae135
3376
3382
3377 $ hg log -qr :e --config revsetalias.e="9"
3383 $ hg log -qr :e --config revsetalias.e="9"
3378 0:2785f51eece5
3384 0:2785f51eece5
3379 1:d75937da8da0
3385 1:d75937da8da0
3380 2:5ed5505e9f1c
3386 2:5ed5505e9f1c
3381 3:8528aa5637f2
3387 3:8528aa5637f2
3382 4:2326846efdab
3388 4:2326846efdab
3383 5:904fa392b941
3389 5:904fa392b941
3384 6:e0cc66ef77e8
3390 6:e0cc66ef77e8
3385 7:013af1973af4
3391 7:013af1973af4
3386 8:d5d0dcbdc4d9
3392 8:d5d0dcbdc4d9
3387 9:24286f4ae135
3393 9:24286f4ae135
3388
3394
3389 $ hg log -qr e:
3395 $ hg log -qr e:
3390 6:e0cc66ef77e8
3396 6:e0cc66ef77e8
3391 7:013af1973af4
3397 7:013af1973af4
3392 8:d5d0dcbdc4d9
3398 8:d5d0dcbdc4d9
3393 9:24286f4ae135
3399 9:24286f4ae135
3394
3400
3395 $ hg log -qr :e
3401 $ hg log -qr :e
3396 0:2785f51eece5
3402 0:2785f51eece5
3397 1:d75937da8da0
3403 1:d75937da8da0
3398 2:5ed5505e9f1c
3404 2:5ed5505e9f1c
3399 3:8528aa5637f2
3405 3:8528aa5637f2
3400 4:2326846efdab
3406 4:2326846efdab
3401 5:904fa392b941
3407 5:904fa392b941
3402 6:e0cc66ef77e8
3408 6:e0cc66ef77e8
3403
3409
3404 issue2549 - correct optimizations
3410 issue2549 - correct optimizations
3405
3411
3406 $ try 'limit(1 or 2 or 3, 2) and not 2'
3412 $ try 'limit(1 or 2 or 3, 2) and not 2'
3407 (and
3413 (and
3408 (func
3414 (func
3409 ('symbol', 'limit')
3415 ('symbol', 'limit')
3410 (list
3416 (list
3411 (or
3417 (or
3412 (list
3418 (list
3413 ('symbol', '1')
3419 ('symbol', '1')
3414 ('symbol', '2')
3420 ('symbol', '2')
3415 ('symbol', '3')))
3421 ('symbol', '3')))
3416 ('symbol', '2')))
3422 ('symbol', '2')))
3417 (not
3423 (not
3418 ('symbol', '2')))
3424 ('symbol', '2')))
3419 * set:
3425 * set:
3420 <filteredset
3426 <filteredset
3421 <baseset
3427 <baseset
3422 <limit n=2, offset=0,
3428 <limit n=2, offset=0,
3423 <fullreposet+ 0:9>,
3429 <fullreposet+ 0:9>,
3424 <baseset [1, 2, 3]>>>,
3430 <baseset [1, 2, 3]>>>,
3425 <not
3431 <not
3426 <baseset [2]>>>
3432 <baseset [2]>>>
3427 1
3433 1
3428 $ try 'max(1 or 2) and not 2'
3434 $ try 'max(1 or 2) and not 2'
3429 (and
3435 (and
3430 (func
3436 (func
3431 ('symbol', 'max')
3437 ('symbol', 'max')
3432 (or
3438 (or
3433 (list
3439 (list
3434 ('symbol', '1')
3440 ('symbol', '1')
3435 ('symbol', '2'))))
3441 ('symbol', '2'))))
3436 (not
3442 (not
3437 ('symbol', '2')))
3443 ('symbol', '2')))
3438 * set:
3444 * set:
3439 <filteredset
3445 <filteredset
3440 <baseset
3446 <baseset
3441 <max
3447 <max
3442 <fullreposet+ 0:9>,
3448 <fullreposet+ 0:9>,
3443 <baseset [1, 2]>>>,
3449 <baseset [1, 2]>>>,
3444 <not
3450 <not
3445 <baseset [2]>>>
3451 <baseset [2]>>>
3446 $ try 'min(1 or 2) and not 1'
3452 $ try 'min(1 or 2) and not 1'
3447 (and
3453 (and
3448 (func
3454 (func
3449 ('symbol', 'min')
3455 ('symbol', 'min')
3450 (or
3456 (or
3451 (list
3457 (list
3452 ('symbol', '1')
3458 ('symbol', '1')
3453 ('symbol', '2'))))
3459 ('symbol', '2'))))
3454 (not
3460 (not
3455 ('symbol', '1')))
3461 ('symbol', '1')))
3456 * set:
3462 * set:
3457 <filteredset
3463 <filteredset
3458 <baseset
3464 <baseset
3459 <min
3465 <min
3460 <fullreposet+ 0:9>,
3466 <fullreposet+ 0:9>,
3461 <baseset [1, 2]>>>,
3467 <baseset [1, 2]>>>,
3462 <not
3468 <not
3463 <baseset [1]>>>
3469 <baseset [1]>>>
3464 $ try 'last(1 or 2, 1) and not 2'
3470 $ try 'last(1 or 2, 1) and not 2'
3465 (and
3471 (and
3466 (func
3472 (func
3467 ('symbol', 'last')
3473 ('symbol', 'last')
3468 (list
3474 (list
3469 (or
3475 (or
3470 (list
3476 (list
3471 ('symbol', '1')
3477 ('symbol', '1')
3472 ('symbol', '2')))
3478 ('symbol', '2')))
3473 ('symbol', '1')))
3479 ('symbol', '1')))
3474 (not
3480 (not
3475 ('symbol', '2')))
3481 ('symbol', '2')))
3476 * set:
3482 * set:
3477 <filteredset
3483 <filteredset
3478 <baseset
3484 <baseset
3479 <last n=1,
3485 <last n=1,
3480 <fullreposet+ 0:9>,
3486 <fullreposet+ 0:9>,
3481 <baseset [2, 1]>>>,
3487 <baseset [2, 1]>>>,
3482 <not
3488 <not
3483 <baseset [2]>>>
3489 <baseset [2]>>>
3484
3490
3485 issue4289 - ordering of built-ins
3491 issue4289 - ordering of built-ins
3486 $ hg log -M -q -r 3:2
3492 $ hg log -M -q -r 3:2
3487 3:8528aa5637f2
3493 3:8528aa5637f2
3488 2:5ed5505e9f1c
3494 2:5ed5505e9f1c
3489
3495
3490 test revsets started with 40-chars hash (issue3669)
3496 test revsets started with 40-chars hash (issue3669)
3491
3497
3492 $ ISSUE3669_TIP=`hg tip --template '{node}'`
3498 $ ISSUE3669_TIP=`hg tip --template '{node}'`
3493 $ hg log -r "${ISSUE3669_TIP}" --template '{rev}\n'
3499 $ hg log -r "${ISSUE3669_TIP}" --template '{rev}\n'
3494 9
3500 9
3495 $ hg log -r "${ISSUE3669_TIP}^" --template '{rev}\n'
3501 $ hg log -r "${ISSUE3669_TIP}^" --template '{rev}\n'
3496 8
3502 8
3497
3503
3498 test or-ed indirect predicates (issue3775)
3504 test or-ed indirect predicates (issue3775)
3499
3505
3500 $ log '6 or 6^1' | sort
3506 $ log '6 or 6^1' | sort
3501 5
3507 5
3502 6
3508 6
3503 $ log '6^1 or 6' | sort
3509 $ log '6^1 or 6' | sort
3504 5
3510 5
3505 6
3511 6
3506 $ log '4 or 4~1' | sort
3512 $ log '4 or 4~1' | sort
3507 2
3513 2
3508 4
3514 4
3509 $ log '4~1 or 4' | sort
3515 $ log '4~1 or 4' | sort
3510 2
3516 2
3511 4
3517 4
3512 $ log '(0 or 2):(4 or 6) or 0 or 6' | sort
3518 $ log '(0 or 2):(4 or 6) or 0 or 6' | sort
3513 0
3519 0
3514 1
3520 1
3515 2
3521 2
3516 3
3522 3
3517 4
3523 4
3518 5
3524 5
3519 6
3525 6
3520 $ log '0 or 6 or (0 or 2):(4 or 6)' | sort
3526 $ log '0 or 6 or (0 or 2):(4 or 6)' | sort
3521 0
3527 0
3522 1
3528 1
3523 2
3529 2
3524 3
3530 3
3525 4
3531 4
3526 5
3532 5
3527 6
3533 6
3528
3534
3529 tests for 'remote()' predicate:
3535 tests for 'remote()' predicate:
3530 #. (csets in remote) (id) (remote)
3536 #. (csets in remote) (id) (remote)
3531 1. less than local current branch "default"
3537 1. less than local current branch "default"
3532 2. same with local specified "default"
3538 2. same with local specified "default"
3533 3. more than local specified specified
3539 3. more than local specified specified
3534
3540
3535 $ hg clone --quiet -U . ../remote3
3541 $ hg clone --quiet -U . ../remote3
3536 $ cd ../remote3
3542 $ cd ../remote3
3537 $ hg update -q 7
3543 $ hg update -q 7
3538 $ echo r > r
3544 $ echo r > r
3539 $ hg ci -Aqm 10
3545 $ hg ci -Aqm 10
3540 $ log 'remote()'
3546 $ log 'remote()'
3541 7
3547 7
3542 $ log 'remote("a-b-c-")'
3548 $ log 'remote("a-b-c-")'
3543 2
3549 2
3544 $ cd ../repo
3550 $ cd ../repo
3545 $ log 'remote(".a.b.c.", "../remote3")'
3551 $ log 'remote(".a.b.c.", "../remote3")'
3546
3552
3547 tests for concatenation of strings/symbols by "##"
3553 tests for concatenation of strings/symbols by "##"
3548
3554
3549 $ try "278 ## '5f5' ## 1ee ## 'ce5'"
3555 $ try "278 ## '5f5' ## 1ee ## 'ce5'"
3550 (_concat
3556 (_concat
3551 (_concat
3557 (_concat
3552 (_concat
3558 (_concat
3553 ('symbol', '278')
3559 ('symbol', '278')
3554 ('string', '5f5'))
3560 ('string', '5f5'))
3555 ('symbol', '1ee'))
3561 ('symbol', '1ee'))
3556 ('string', 'ce5'))
3562 ('string', 'ce5'))
3557 * concatenated:
3563 * concatenated:
3558 ('string', '2785f51eece5')
3564 ('string', '2785f51eece5')
3559 * set:
3565 * set:
3560 <baseset [0]>
3566 <baseset [0]>
3561 0
3567 0
3562
3568
3563 $ echo 'cat4($1, $2, $3, $4) = $1 ## $2 ## $3 ## $4' >> .hg/hgrc
3569 $ echo 'cat4($1, $2, $3, $4) = $1 ## $2 ## $3 ## $4' >> .hg/hgrc
3564 $ try "cat4(278, '5f5', 1ee, 'ce5')"
3570 $ try "cat4(278, '5f5', 1ee, 'ce5')"
3565 (func
3571 (func
3566 ('symbol', 'cat4')
3572 ('symbol', 'cat4')
3567 (list
3573 (list
3568 ('symbol', '278')
3574 ('symbol', '278')
3569 ('string', '5f5')
3575 ('string', '5f5')
3570 ('symbol', '1ee')
3576 ('symbol', '1ee')
3571 ('string', 'ce5')))
3577 ('string', 'ce5')))
3572 * expanded:
3578 * expanded:
3573 (_concat
3579 (_concat
3574 (_concat
3580 (_concat
3575 (_concat
3581 (_concat
3576 ('symbol', '278')
3582 ('symbol', '278')
3577 ('string', '5f5'))
3583 ('string', '5f5'))
3578 ('symbol', '1ee'))
3584 ('symbol', '1ee'))
3579 ('string', 'ce5'))
3585 ('string', 'ce5'))
3580 * concatenated:
3586 * concatenated:
3581 ('string', '2785f51eece5')
3587 ('string', '2785f51eece5')
3582 * set:
3588 * set:
3583 <baseset [0]>
3589 <baseset [0]>
3584 0
3590 0
3585
3591
3586 (check concatenation in alias nesting)
3592 (check concatenation in alias nesting)
3587
3593
3588 $ echo 'cat2($1, $2) = $1 ## $2' >> .hg/hgrc
3594 $ echo 'cat2($1, $2) = $1 ## $2' >> .hg/hgrc
3589 $ echo 'cat2x2($1, $2, $3, $4) = cat2($1 ## $2, $3 ## $4)' >> .hg/hgrc
3595 $ echo 'cat2x2($1, $2, $3, $4) = cat2($1 ## $2, $3 ## $4)' >> .hg/hgrc
3590 $ log "cat2x2(278, '5f5', 1ee, 'ce5')"
3596 $ log "cat2x2(278, '5f5', 1ee, 'ce5')"
3591 0
3597 0
3592
3598
3593 (check operator priority)
3599 (check operator priority)
3594
3600
3595 $ echo 'cat2n2($1, $2, $3, $4) = $1 ## $2 or $3 ## $4~2' >> .hg/hgrc
3601 $ echo 'cat2n2($1, $2, $3, $4) = $1 ## $2 or $3 ## $4~2' >> .hg/hgrc
3596 $ log "cat2n2(2785f5, 1eece5, 24286f, 4ae135)"
3602 $ log "cat2n2(2785f5, 1eece5, 24286f, 4ae135)"
3597 0
3603 0
3598 4
3604 4
3599
3605
3600 $ cd ..
3606 $ cd ..
3601
3607
3602 prepare repository that has "default" branches of multiple roots
3608 prepare repository that has "default" branches of multiple roots
3603
3609
3604 $ hg init namedbranch
3610 $ hg init namedbranch
3605 $ cd namedbranch
3611 $ cd namedbranch
3606
3612
3607 $ echo default0 >> a
3613 $ echo default0 >> a
3608 $ hg ci -Aqm0
3614 $ hg ci -Aqm0
3609 $ echo default1 >> a
3615 $ echo default1 >> a
3610 $ hg ci -m1
3616 $ hg ci -m1
3611
3617
3612 $ hg branch -q stable
3618 $ hg branch -q stable
3613 $ echo stable2 >> a
3619 $ echo stable2 >> a
3614 $ hg ci -m2
3620 $ hg ci -m2
3615 $ echo stable3 >> a
3621 $ echo stable3 >> a
3616 $ hg ci -m3
3622 $ hg ci -m3
3617
3623
3618 $ hg update -q null
3624 $ hg update -q null
3619 $ echo default4 >> a
3625 $ echo default4 >> a
3620 $ hg ci -Aqm4
3626 $ hg ci -Aqm4
3621 $ echo default5 >> a
3627 $ echo default5 >> a
3622 $ hg ci -m5
3628 $ hg ci -m5
3623
3629
3624 "null" revision belongs to "default" branch (issue4683)
3630 "null" revision belongs to "default" branch (issue4683)
3625
3631
3626 $ log 'branch(null)'
3632 $ log 'branch(null)'
3627 0
3633 0
3628 1
3634 1
3629 4
3635 4
3630 5
3636 5
3631
3637
3632 "null" revision belongs to "default" branch, but it shouldn't appear in set
3638 "null" revision belongs to "default" branch, but it shouldn't appear in set
3633 unless explicitly specified (issue4682)
3639 unless explicitly specified (issue4682)
3634
3640
3635 $ log 'children(branch(default))'
3641 $ log 'children(branch(default))'
3636 1
3642 1
3637 2
3643 2
3638 5
3644 5
3639
3645
3640 $ cd ..
3646 $ cd ..
3641
3647
3642 test author/desc/keyword in problematic encoding
3648 test author/desc/keyword in problematic encoding
3643 # unicode: cp932:
3649 # unicode: cp932:
3644 # u30A2 0x83 0x41(= 'A')
3650 # u30A2 0x83 0x41(= 'A')
3645 # u30C2 0x83 0x61(= 'a')
3651 # u30C2 0x83 0x61(= 'a')
3646
3652
3647 $ hg init problematicencoding
3653 $ hg init problematicencoding
3648 $ cd problematicencoding
3654 $ cd problematicencoding
3649
3655
3650 $ python > setup.sh <<EOF
3656 $ python > setup.sh <<EOF
3651 > print u'''
3657 > print u'''
3652 > echo a > text
3658 > echo a > text
3653 > hg add text
3659 > hg add text
3654 > hg --encoding utf-8 commit -u '\u30A2' -m none
3660 > hg --encoding utf-8 commit -u '\u30A2' -m none
3655 > echo b > text
3661 > echo b > text
3656 > hg --encoding utf-8 commit -u '\u30C2' -m none
3662 > hg --encoding utf-8 commit -u '\u30C2' -m none
3657 > echo c > text
3663 > echo c > text
3658 > hg --encoding utf-8 commit -u none -m '\u30A2'
3664 > hg --encoding utf-8 commit -u none -m '\u30A2'
3659 > echo d > text
3665 > echo d > text
3660 > hg --encoding utf-8 commit -u none -m '\u30C2'
3666 > hg --encoding utf-8 commit -u none -m '\u30C2'
3661 > '''.encode('utf-8')
3667 > '''.encode('utf-8')
3662 > EOF
3668 > EOF
3663 $ sh < setup.sh
3669 $ sh < setup.sh
3664
3670
3665 test in problematic encoding
3671 test in problematic encoding
3666 $ python > test.sh <<EOF
3672 $ python > test.sh <<EOF
3667 > print u'''
3673 > print u'''
3668 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30A2)'
3674 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30A2)'
3669 > echo ====
3675 > echo ====
3670 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30C2)'
3676 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30C2)'
3671 > echo ====
3677 > echo ====
3672 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30A2)'
3678 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30A2)'
3673 > echo ====
3679 > echo ====
3674 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30C2)'
3680 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30C2)'
3675 > echo ====
3681 > echo ====
3676 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30A2)'
3682 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30A2)'
3677 > echo ====
3683 > echo ====
3678 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30C2)'
3684 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30C2)'
3679 > '''.encode('cp932')
3685 > '''.encode('cp932')
3680 > EOF
3686 > EOF
3681 $ sh < test.sh
3687 $ sh < test.sh
3682 0
3688 0
3683 ====
3689 ====
3684 1
3690 1
3685 ====
3691 ====
3686 2
3692 2
3687 ====
3693 ====
3688 3
3694 3
3689 ====
3695 ====
3690 0
3696 0
3691 2
3697 2
3692 ====
3698 ====
3693 1
3699 1
3694 3
3700 3
3695
3701
3696 test error message of bad revset
3702 test error message of bad revset
3697 $ hg log -r 'foo\\'
3703 $ hg log -r 'foo\\'
3698 hg: parse error at 3: syntax error in revset 'foo\\'
3704 hg: parse error at 3: syntax error in revset 'foo\\'
3699 [255]
3705 [255]
3700
3706
3701 $ cd ..
3707 $ cd ..
3702
3708
3703 Test that revset predicate of extension isn't loaded at failure of
3709 Test that revset predicate of extension isn't loaded at failure of
3704 loading it
3710 loading it
3705
3711
3706 $ cd repo
3712 $ cd repo
3707
3713
3708 $ cat <<EOF > $TESTTMP/custompredicate.py
3714 $ cat <<EOF > $TESTTMP/custompredicate.py
3709 > from mercurial import error, registrar, revset
3715 > from mercurial import error, registrar, revset
3710 >
3716 >
3711 > revsetpredicate = registrar.revsetpredicate()
3717 > revsetpredicate = registrar.revsetpredicate()
3712 >
3718 >
3713 > @revsetpredicate('custom1()')
3719 > @revsetpredicate('custom1()')
3714 > def custom1(repo, subset, x):
3720 > def custom1(repo, subset, x):
3715 > return revset.baseset([1])
3721 > return revset.baseset([1])
3716 >
3722 >
3717 > raise error.Abort('intentional failure of loading extension')
3723 > raise error.Abort('intentional failure of loading extension')
3718 > EOF
3724 > EOF
3719 $ cat <<EOF > .hg/hgrc
3725 $ cat <<EOF > .hg/hgrc
3720 > [extensions]
3726 > [extensions]
3721 > custompredicate = $TESTTMP/custompredicate.py
3727 > custompredicate = $TESTTMP/custompredicate.py
3722 > EOF
3728 > EOF
3723
3729
3724 $ hg debugrevspec "custom1()"
3730 $ hg debugrevspec "custom1()"
3725 *** failed to import extension custompredicate from $TESTTMP/custompredicate.py: intentional failure of loading extension
3731 *** failed to import extension custompredicate from $TESTTMP/custompredicate.py: intentional failure of loading extension
3726 hg: parse error: unknown identifier: custom1
3732 hg: parse error: unknown identifier: custom1
3727 [255]
3733 [255]
3728
3734
3729 $ cd ..
3735 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now