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