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