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