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