##// END OF EJS Templates
revset: implement a simple 'foo#generations' expression...
av6 -
r45204:eca82eb9 default
parent child Browse files
Show More
@@ -1,2737 +1,2755 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 re
10 import re
11
11
12 from .i18n import _
12 from .i18n import _
13 from .pycompat import getattr
13 from .pycompat import getattr
14 from . import (
14 from . import (
15 dagop,
15 dagop,
16 destutil,
16 destutil,
17 diffutil,
17 diffutil,
18 encoding,
18 encoding,
19 error,
19 error,
20 hbisect,
20 hbisect,
21 match as matchmod,
21 match as matchmod,
22 node,
22 node,
23 obsolete as obsmod,
23 obsolete as obsmod,
24 obsutil,
24 obsutil,
25 pathutil,
25 pathutil,
26 phases,
26 phases,
27 pycompat,
27 pycompat,
28 registrar,
28 registrar,
29 repoview,
29 repoview,
30 revsetlang,
30 revsetlang,
31 scmutil,
31 scmutil,
32 smartset,
32 smartset,
33 stack as stackmod,
33 stack as stackmod,
34 util,
34 util,
35 )
35 )
36 from .utils import (
36 from .utils import (
37 dateutil,
37 dateutil,
38 stringutil,
38 stringutil,
39 )
39 )
40
40
41 # helpers for processing parsed tree
41 # helpers for processing parsed tree
42 getsymbol = revsetlang.getsymbol
42 getsymbol = revsetlang.getsymbol
43 getstring = revsetlang.getstring
43 getstring = revsetlang.getstring
44 getinteger = revsetlang.getinteger
44 getinteger = revsetlang.getinteger
45 getboolean = revsetlang.getboolean
45 getboolean = revsetlang.getboolean
46 getlist = revsetlang.getlist
46 getlist = revsetlang.getlist
47 getintrange = revsetlang.getintrange
47 getintrange = revsetlang.getintrange
48 getargs = revsetlang.getargs
48 getargs = revsetlang.getargs
49 getargsdict = revsetlang.getargsdict
49 getargsdict = revsetlang.getargsdict
50
50
51 baseset = smartset.baseset
51 baseset = smartset.baseset
52 generatorset = smartset.generatorset
52 generatorset = smartset.generatorset
53 spanset = smartset.spanset
53 spanset = smartset.spanset
54 fullreposet = smartset.fullreposet
54 fullreposet = smartset.fullreposet
55
55
56 # revisions not included in all(), but populated if specified
56 # revisions not included in all(), but populated if specified
57 _virtualrevs = (node.nullrev, node.wdirrev)
57 _virtualrevs = (node.nullrev, node.wdirrev)
58
58
59 # Constants for ordering requirement, used in getset():
59 # Constants for ordering requirement, used in getset():
60 #
60 #
61 # If 'define', any nested functions and operations MAY change the ordering of
61 # If 'define', any nested functions and operations MAY change the ordering of
62 # the entries in the set (but if changes the ordering, it MUST ALWAYS change
62 # the entries in the set (but if changes the ordering, it MUST ALWAYS change
63 # it). If 'follow', any nested functions and operations MUST take the ordering
63 # it). If 'follow', any nested functions and operations MUST take the ordering
64 # specified by the first operand to the '&' operator.
64 # specified by the first operand to the '&' operator.
65 #
65 #
66 # For instance,
66 # For instance,
67 #
67 #
68 # X & (Y | Z)
68 # X & (Y | Z)
69 # ^ ^^^^^^^
69 # ^ ^^^^^^^
70 # | follow
70 # | follow
71 # define
71 # define
72 #
72 #
73 # will be evaluated as 'or(y(x()), z(x()))', where 'x()' can change the order
73 # will be evaluated as 'or(y(x()), z(x()))', where 'x()' can change the order
74 # of the entries in the set, but 'y()', 'z()' and 'or()' shouldn't.
74 # of the entries in the set, but 'y()', 'z()' and 'or()' shouldn't.
75 #
75 #
76 # 'any' means the order doesn't matter. For instance,
76 # 'any' means the order doesn't matter. For instance,
77 #
77 #
78 # (X & !Y) | ancestors(Z)
78 # (X & !Y) | ancestors(Z)
79 # ^ ^
79 # ^ ^
80 # any any
80 # any any
81 #
81 #
82 # For 'X & !Y', 'X' decides the order and 'Y' is subtracted from 'X', so the
82 # For 'X & !Y', 'X' decides the order and 'Y' is subtracted from 'X', so the
83 # order of 'Y' does not matter. For 'ancestors(Z)', Z's order does not matter
83 # order of 'Y' does not matter. For 'ancestors(Z)', Z's order does not matter
84 # since 'ancestors' does not care about the order of its argument.
84 # since 'ancestors' does not care about the order of its argument.
85 #
85 #
86 # Currently, most revsets do not care about the order, so 'define' is
86 # Currently, most revsets do not care about the order, so 'define' is
87 # equivalent to 'follow' for them, and the resulting order is based on the
87 # equivalent to 'follow' for them, and the resulting order is based on the
88 # 'subset' parameter passed down to them:
88 # 'subset' parameter passed down to them:
89 #
89 #
90 # m = revset.match(...)
90 # m = revset.match(...)
91 # m(repo, subset, order=defineorder)
91 # m(repo, subset, order=defineorder)
92 # ^^^^^^
92 # ^^^^^^
93 # For most revsets, 'define' means using the order this subset provides
93 # For most revsets, 'define' means using the order this subset provides
94 #
94 #
95 # There are a few revsets that always redefine the order if 'define' is
95 # There are a few revsets that always redefine the order if 'define' is
96 # specified: 'sort(X)', 'reverse(X)', 'x:y'.
96 # specified: 'sort(X)', 'reverse(X)', 'x:y'.
97 anyorder = b'any' # don't care the order, could be even random-shuffled
97 anyorder = b'any' # don't care the order, could be even random-shuffled
98 defineorder = b'define' # ALWAYS redefine, or ALWAYS follow the current order
98 defineorder = b'define' # ALWAYS redefine, or ALWAYS follow the current order
99 followorder = b'follow' # MUST follow the current order
99 followorder = b'follow' # MUST follow the current order
100
100
101 # helpers
101 # helpers
102
102
103
103
104 def getset(repo, subset, x, order=defineorder):
104 def getset(repo, subset, x, order=defineorder):
105 if not x:
105 if not x:
106 raise error.ParseError(_(b"missing argument"))
106 raise error.ParseError(_(b"missing argument"))
107 return methods[x[0]](repo, subset, *x[1:], order=order)
107 return methods[x[0]](repo, subset, *x[1:], order=order)
108
108
109
109
110 def _getrevsource(repo, r):
110 def _getrevsource(repo, r):
111 extra = repo[r].extra()
111 extra = repo[r].extra()
112 for label in (b'source', b'transplant_source', b'rebase_source'):
112 for label in (b'source', b'transplant_source', b'rebase_source'):
113 if label in extra:
113 if label in extra:
114 try:
114 try:
115 return repo[extra[label]].rev()
115 return repo[extra[label]].rev()
116 except error.RepoLookupError:
116 except error.RepoLookupError:
117 pass
117 pass
118 return None
118 return None
119
119
120
120
121 def _sortedb(xs):
121 def _sortedb(xs):
122 return sorted(pycompat.rapply(pycompat.maybebytestr, xs))
122 return sorted(pycompat.rapply(pycompat.maybebytestr, xs))
123
123
124
124
125 # operator methods
125 # operator methods
126
126
127
127
128 def stringset(repo, subset, x, order):
128 def stringset(repo, subset, x, order):
129 if not x:
129 if not x:
130 raise error.ParseError(_(b"empty string is not a valid revision"))
130 raise error.ParseError(_(b"empty string is not a valid revision"))
131 x = scmutil.intrev(scmutil.revsymbol(repo, x))
131 x = scmutil.intrev(scmutil.revsymbol(repo, x))
132 if x in subset or x in _virtualrevs and isinstance(subset, fullreposet):
132 if x in subset or x in _virtualrevs and isinstance(subset, fullreposet):
133 return baseset([x])
133 return baseset([x])
134 return baseset()
134 return baseset()
135
135
136
136
137 def rawsmartset(repo, subset, x, order):
137 def rawsmartset(repo, subset, x, order):
138 """argument is already a smartset, use that directly"""
138 """argument is already a smartset, use that directly"""
139 if order == followorder:
139 if order == followorder:
140 return subset & x
140 return subset & x
141 else:
141 else:
142 return x & subset
142 return x & subset
143
143
144
144
145 def rangeset(repo, subset, x, y, order):
145 def rangeset(repo, subset, x, y, order):
146 m = getset(repo, fullreposet(repo), x)
146 m = getset(repo, fullreposet(repo), x)
147 n = getset(repo, fullreposet(repo), y)
147 n = getset(repo, fullreposet(repo), y)
148
148
149 if not m or not n:
149 if not m or not n:
150 return baseset()
150 return baseset()
151 return _makerangeset(repo, subset, m.first(), n.last(), order)
151 return _makerangeset(repo, subset, m.first(), n.last(), order)
152
152
153
153
154 def rangeall(repo, subset, x, order):
154 def rangeall(repo, subset, x, order):
155 assert x is None
155 assert x is None
156 return _makerangeset(repo, subset, 0, repo.changelog.tiprev(), order)
156 return _makerangeset(repo, subset, 0, repo.changelog.tiprev(), order)
157
157
158
158
159 def rangepre(repo, subset, y, order):
159 def rangepre(repo, subset, y, order):
160 # ':y' can't be rewritten to '0:y' since '0' may be hidden
160 # ':y' can't be rewritten to '0:y' since '0' may be hidden
161 n = getset(repo, fullreposet(repo), y)
161 n = getset(repo, fullreposet(repo), y)
162 if not n:
162 if not n:
163 return baseset()
163 return baseset()
164 return _makerangeset(repo, subset, 0, n.last(), order)
164 return _makerangeset(repo, subset, 0, n.last(), order)
165
165
166
166
167 def rangepost(repo, subset, x, order):
167 def rangepost(repo, subset, x, order):
168 m = getset(repo, fullreposet(repo), x)
168 m = getset(repo, fullreposet(repo), x)
169 if not m:
169 if not m:
170 return baseset()
170 return baseset()
171 return _makerangeset(
171 return _makerangeset(
172 repo, subset, m.first(), repo.changelog.tiprev(), order
172 repo, subset, m.first(), repo.changelog.tiprev(), order
173 )
173 )
174
174
175
175
176 def _makerangeset(repo, subset, m, n, order):
176 def _makerangeset(repo, subset, m, n, order):
177 if m == n:
177 if m == n:
178 r = baseset([m])
178 r = baseset([m])
179 elif n == node.wdirrev:
179 elif n == node.wdirrev:
180 r = spanset(repo, m, len(repo)) + baseset([n])
180 r = spanset(repo, m, len(repo)) + baseset([n])
181 elif m == node.wdirrev:
181 elif m == node.wdirrev:
182 r = baseset([m]) + spanset(repo, repo.changelog.tiprev(), n - 1)
182 r = baseset([m]) + spanset(repo, repo.changelog.tiprev(), n - 1)
183 elif m < n:
183 elif m < n:
184 r = spanset(repo, m, n + 1)
184 r = spanset(repo, m, n + 1)
185 else:
185 else:
186 r = spanset(repo, m, n - 1)
186 r = spanset(repo, m, n - 1)
187
187
188 if order == defineorder:
188 if order == defineorder:
189 return r & subset
189 return r & subset
190 else:
190 else:
191 # carrying the sorting over when possible would be more efficient
191 # carrying the sorting over when possible would be more efficient
192 return subset & r
192 return subset & r
193
193
194
194
195 def dagrange(repo, subset, x, y, order):
195 def dagrange(repo, subset, x, y, order):
196 r = fullreposet(repo)
196 r = fullreposet(repo)
197 xs = dagop.reachableroots(
197 xs = dagop.reachableroots(
198 repo, getset(repo, r, x), getset(repo, r, y), includepath=True
198 repo, getset(repo, r, x), getset(repo, r, y), includepath=True
199 )
199 )
200 return subset & xs
200 return subset & xs
201
201
202
202
203 def andset(repo, subset, x, y, order):
203 def andset(repo, subset, x, y, order):
204 if order == anyorder:
204 if order == anyorder:
205 yorder = anyorder
205 yorder = anyorder
206 else:
206 else:
207 yorder = followorder
207 yorder = followorder
208 return getset(repo, getset(repo, subset, x, order), y, yorder)
208 return getset(repo, getset(repo, subset, x, order), y, yorder)
209
209
210
210
211 def andsmallyset(repo, subset, x, y, order):
211 def andsmallyset(repo, subset, x, y, order):
212 # 'andsmally(x, y)' is equivalent to 'and(x, y)', but faster when y is small
212 # 'andsmally(x, y)' is equivalent to 'and(x, y)', but faster when y is small
213 if order == anyorder:
213 if order == anyorder:
214 yorder = anyorder
214 yorder = anyorder
215 else:
215 else:
216 yorder = followorder
216 yorder = followorder
217 return getset(repo, getset(repo, subset, y, yorder), x, order)
217 return getset(repo, getset(repo, subset, y, yorder), x, order)
218
218
219
219
220 def differenceset(repo, subset, x, y, order):
220 def differenceset(repo, subset, x, y, order):
221 return getset(repo, subset, x, order) - getset(repo, subset, y, anyorder)
221 return getset(repo, subset, x, order) - getset(repo, subset, y, anyorder)
222
222
223
223
224 def _orsetlist(repo, subset, xs, order):
224 def _orsetlist(repo, subset, xs, order):
225 assert xs
225 assert xs
226 if len(xs) == 1:
226 if len(xs) == 1:
227 return getset(repo, subset, xs[0], order)
227 return getset(repo, subset, xs[0], order)
228 p = len(xs) // 2
228 p = len(xs) // 2
229 a = _orsetlist(repo, subset, xs[:p], order)
229 a = _orsetlist(repo, subset, xs[:p], order)
230 b = _orsetlist(repo, subset, xs[p:], order)
230 b = _orsetlist(repo, subset, xs[p:], order)
231 return a + b
231 return a + b
232
232
233
233
234 def orset(repo, subset, x, order):
234 def orset(repo, subset, x, order):
235 xs = getlist(x)
235 xs = getlist(x)
236 if not xs:
236 if not xs:
237 return baseset()
237 return baseset()
238 if order == followorder:
238 if order == followorder:
239 # slow path to take the subset order
239 # slow path to take the subset order
240 return subset & _orsetlist(repo, fullreposet(repo), xs, anyorder)
240 return subset & _orsetlist(repo, fullreposet(repo), xs, anyorder)
241 else:
241 else:
242 return _orsetlist(repo, subset, xs, order)
242 return _orsetlist(repo, subset, xs, order)
243
243
244
244
245 def notset(repo, subset, x, order):
245 def notset(repo, subset, x, order):
246 return subset - getset(repo, subset, x, anyorder)
246 return subset - getset(repo, subset, x, anyorder)
247
247
248
248
249 def relationset(repo, subset, x, y, order):
249 def relationset(repo, subset, x, y, order):
250 raise error.ParseError(_(b"can't use a relation in this context"))
250 # this is pretty basic implementation of 'x#y' operator, still
251 # experimental so undocumented. see the wiki for further ideas.
252 # https://www.mercurial-scm.org/wiki/RevsetOperatorPlan
253 rel = getsymbol(y)
254 if rel in relations:
255 return relations[rel](repo, subset, x, rel, order)
256
257 relnames = [r for r in relations.keys() if len(r) > 1]
258 raise error.UnknownIdentifier(rel, relnames)
251
259
252
260
253 def _splitrange(a, b):
261 def _splitrange(a, b):
254 """Split range with bounds a and b into two ranges at 0 and return two
262 """Split range with bounds a and b into two ranges at 0 and return two
255 tuples of numbers for use as startdepth and stopdepth arguments of
263 tuples of numbers for use as startdepth and stopdepth arguments of
256 revancestors and revdescendants.
264 revancestors and revdescendants.
257
265
258 >>> _splitrange(-10, -5) # [-10:-5]
266 >>> _splitrange(-10, -5) # [-10:-5]
259 ((5, 11), (None, None))
267 ((5, 11), (None, None))
260 >>> _splitrange(5, 10) # [5:10]
268 >>> _splitrange(5, 10) # [5:10]
261 ((None, None), (5, 11))
269 ((None, None), (5, 11))
262 >>> _splitrange(-10, 10) # [-10:10]
270 >>> _splitrange(-10, 10) # [-10:10]
263 ((0, 11), (0, 11))
271 ((0, 11), (0, 11))
264 >>> _splitrange(-10, 0) # [-10:0]
272 >>> _splitrange(-10, 0) # [-10:0]
265 ((0, 11), (None, None))
273 ((0, 11), (None, None))
266 >>> _splitrange(0, 10) # [0:10]
274 >>> _splitrange(0, 10) # [0:10]
267 ((None, None), (0, 11))
275 ((None, None), (0, 11))
268 >>> _splitrange(0, 0) # [0:0]
276 >>> _splitrange(0, 0) # [0:0]
269 ((0, 1), (None, None))
277 ((0, 1), (None, None))
270 >>> _splitrange(1, -1) # [1:-1]
278 >>> _splitrange(1, -1) # [1:-1]
271 ((None, None), (None, None))
279 ((None, None), (None, None))
272 """
280 """
273 ancdepths = (None, None)
281 ancdepths = (None, None)
274 descdepths = (None, None)
282 descdepths = (None, None)
275 if a == b == 0:
283 if a == b == 0:
276 ancdepths = (0, 1)
284 ancdepths = (0, 1)
277 if a < 0:
285 if a < 0:
278 ancdepths = (-min(b, 0), -a + 1)
286 ancdepths = (-min(b, 0), -a + 1)
279 if b > 0:
287 if b > 0:
280 descdepths = (max(a, 0), b + 1)
288 descdepths = (max(a, 0), b + 1)
281 return ancdepths, descdepths
289 return ancdepths, descdepths
282
290
283
291
292 def generationsrel(repo, subset, x, rel, order):
293 z = (b'rangeall', None)
294 return generationssubrel(repo, subset, x, rel, z, order)
295
296
284 def generationssubrel(repo, subset, x, rel, z, order):
297 def generationssubrel(repo, subset, x, rel, z, order):
285 # TODO: rewrite tests, and drop startdepth argument from ancestors() and
298 # TODO: rewrite tests, and drop startdepth argument from ancestors() and
286 # descendants() predicates
299 # descendants() predicates
287 a, b = getintrange(
300 a, b = getintrange(
288 z,
301 z,
289 _(b'relation subscript must be an integer or a range'),
302 _(b'relation subscript must be an integer or a range'),
290 _(b'relation subscript bounds must be integers'),
303 _(b'relation subscript bounds must be integers'),
291 deffirst=-(dagop.maxlogdepth - 1),
304 deffirst=-(dagop.maxlogdepth - 1),
292 deflast=+(dagop.maxlogdepth - 1),
305 deflast=+(dagop.maxlogdepth - 1),
293 )
306 )
294 (ancstart, ancstop), (descstart, descstop) = _splitrange(a, b)
307 (ancstart, ancstop), (descstart, descstop) = _splitrange(a, b)
295
308
296 if ancstart is None and descstart is None:
309 if ancstart is None and descstart is None:
297 return baseset()
310 return baseset()
298
311
299 revs = getset(repo, fullreposet(repo), x)
312 revs = getset(repo, fullreposet(repo), x)
300 if not revs:
313 if not revs:
301 return baseset()
314 return baseset()
302
315
303 if ancstart is not None and descstart is not None:
316 if ancstart is not None and descstart is not None:
304 s = dagop.revancestors(repo, revs, False, ancstart, ancstop)
317 s = dagop.revancestors(repo, revs, False, ancstart, ancstop)
305 s += dagop.revdescendants(repo, revs, False, descstart, descstop)
318 s += dagop.revdescendants(repo, revs, False, descstart, descstop)
306 elif ancstart is not None:
319 elif ancstart is not None:
307 s = dagop.revancestors(repo, revs, False, ancstart, ancstop)
320 s = dagop.revancestors(repo, revs, False, ancstart, ancstop)
308 elif descstart is not None:
321 elif descstart is not None:
309 s = dagop.revdescendants(repo, revs, False, descstart, descstop)
322 s = dagop.revdescendants(repo, revs, False, descstart, descstop)
310
323
311 return subset & s
324 return subset & s
312
325
313
326
314 def relsubscriptset(repo, subset, x, y, z, order):
327 def relsubscriptset(repo, subset, x, y, z, order):
315 # this is pretty basic implementation of 'x#y[z]' operator, still
328 # this is pretty basic implementation of 'x#y[z]' operator, still
316 # experimental so undocumented. see the wiki for further ideas.
329 # experimental so undocumented. see the wiki for further ideas.
317 # https://www.mercurial-scm.org/wiki/RevsetOperatorPlan
330 # https://www.mercurial-scm.org/wiki/RevsetOperatorPlan
318 rel = getsymbol(y)
331 rel = getsymbol(y)
319 if rel in subscriptrelations:
332 if rel in subscriptrelations:
320 return subscriptrelations[rel](repo, subset, x, rel, z, order)
333 return subscriptrelations[rel](repo, subset, x, rel, z, order)
321
334
322 relnames = [r for r in subscriptrelations.keys() if len(r) > 1]
335 relnames = [r for r in subscriptrelations.keys() if len(r) > 1]
323 raise error.UnknownIdentifier(rel, relnames)
336 raise error.UnknownIdentifier(rel, relnames)
324
337
325
338
326 def subscriptset(repo, subset, x, y, order):
339 def subscriptset(repo, subset, x, y, order):
327 raise error.ParseError(_(b"can't use a subscript in this context"))
340 raise error.ParseError(_(b"can't use a subscript in this context"))
328
341
329
342
330 def listset(repo, subset, *xs, **opts):
343 def listset(repo, subset, *xs, **opts):
331 raise error.ParseError(
344 raise error.ParseError(
332 _(b"can't use a list in this context"),
345 _(b"can't use a list in this context"),
333 hint=_(b'see \'hg help "revsets.x or y"\''),
346 hint=_(b'see \'hg help "revsets.x or y"\''),
334 )
347 )
335
348
336
349
337 def keyvaluepair(repo, subset, k, v, order):
350 def keyvaluepair(repo, subset, k, v, order):
338 raise error.ParseError(_(b"can't use a key-value pair in this context"))
351 raise error.ParseError(_(b"can't use a key-value pair in this context"))
339
352
340
353
341 def func(repo, subset, a, b, order):
354 def func(repo, subset, a, b, order):
342 f = getsymbol(a)
355 f = getsymbol(a)
343 if f in symbols:
356 if f in symbols:
344 func = symbols[f]
357 func = symbols[f]
345 if getattr(func, '_takeorder', False):
358 if getattr(func, '_takeorder', False):
346 return func(repo, subset, b, order)
359 return func(repo, subset, b, order)
347 return func(repo, subset, b)
360 return func(repo, subset, b)
348
361
349 keep = lambda fn: getattr(fn, '__doc__', None) is not None
362 keep = lambda fn: getattr(fn, '__doc__', None) is not None
350
363
351 syms = [s for (s, fn) in symbols.items() if keep(fn)]
364 syms = [s for (s, fn) in symbols.items() if keep(fn)]
352 raise error.UnknownIdentifier(f, syms)
365 raise error.UnknownIdentifier(f, syms)
353
366
354
367
355 # functions
368 # functions
356
369
357 # symbols are callables like:
370 # symbols are callables like:
358 # fn(repo, subset, x)
371 # fn(repo, subset, x)
359 # with:
372 # with:
360 # repo - current repository instance
373 # repo - current repository instance
361 # subset - of revisions to be examined
374 # subset - of revisions to be examined
362 # x - argument in tree form
375 # x - argument in tree form
363 symbols = revsetlang.symbols
376 symbols = revsetlang.symbols
364
377
365 # symbols which can't be used for a DoS attack for any given input
378 # symbols which can't be used for a DoS attack for any given input
366 # (e.g. those which accept regexes as plain strings shouldn't be included)
379 # (e.g. those which accept regexes as plain strings shouldn't be included)
367 # functions that just return a lot of changesets (like all) don't count here
380 # functions that just return a lot of changesets (like all) don't count here
368 safesymbols = set()
381 safesymbols = set()
369
382
370 predicate = registrar.revsetpredicate()
383 predicate = registrar.revsetpredicate()
371
384
372
385
373 @predicate(b'_destupdate')
386 @predicate(b'_destupdate')
374 def _destupdate(repo, subset, x):
387 def _destupdate(repo, subset, x):
375 # experimental revset for update destination
388 # experimental revset for update destination
376 args = getargsdict(x, b'limit', b'clean')
389 args = getargsdict(x, b'limit', b'clean')
377 return subset & baseset(
390 return subset & baseset(
378 [destutil.destupdate(repo, **pycompat.strkwargs(args))[0]]
391 [destutil.destupdate(repo, **pycompat.strkwargs(args))[0]]
379 )
392 )
380
393
381
394
382 @predicate(b'_destmerge')
395 @predicate(b'_destmerge')
383 def _destmerge(repo, subset, x):
396 def _destmerge(repo, subset, x):
384 # experimental revset for merge destination
397 # experimental revset for merge destination
385 sourceset = None
398 sourceset = None
386 if x is not None:
399 if x is not None:
387 sourceset = getset(repo, fullreposet(repo), x)
400 sourceset = getset(repo, fullreposet(repo), x)
388 return subset & baseset([destutil.destmerge(repo, sourceset=sourceset)])
401 return subset & baseset([destutil.destmerge(repo, sourceset=sourceset)])
389
402
390
403
391 @predicate(b'adds(pattern)', safe=True, weight=30)
404 @predicate(b'adds(pattern)', safe=True, weight=30)
392 def adds(repo, subset, x):
405 def adds(repo, subset, x):
393 """Changesets that add a file matching pattern.
406 """Changesets that add a file matching pattern.
394
407
395 The pattern without explicit kind like ``glob:`` is expected to be
408 The pattern without explicit kind like ``glob:`` is expected to be
396 relative to the current directory and match against a file or a
409 relative to the current directory and match against a file or a
397 directory.
410 directory.
398 """
411 """
399 # i18n: "adds" is a keyword
412 # i18n: "adds" is a keyword
400 pat = getstring(x, _(b"adds requires a pattern"))
413 pat = getstring(x, _(b"adds requires a pattern"))
401 return checkstatus(repo, subset, pat, 1)
414 return checkstatus(repo, subset, pat, 1)
402
415
403
416
404 @predicate(b'ancestor(*changeset)', safe=True, weight=0.5)
417 @predicate(b'ancestor(*changeset)', safe=True, weight=0.5)
405 def ancestor(repo, subset, x):
418 def ancestor(repo, subset, x):
406 """A greatest common ancestor of the changesets.
419 """A greatest common ancestor of the changesets.
407
420
408 Accepts 0 or more changesets.
421 Accepts 0 or more changesets.
409 Will return empty list when passed no args.
422 Will return empty list when passed no args.
410 Greatest common ancestor of a single changeset is that changeset.
423 Greatest common ancestor of a single changeset is that changeset.
411 """
424 """
412 reviter = iter(orset(repo, fullreposet(repo), x, order=anyorder))
425 reviter = iter(orset(repo, fullreposet(repo), x, order=anyorder))
413 try:
426 try:
414 anc = repo[next(reviter)]
427 anc = repo[next(reviter)]
415 except StopIteration:
428 except StopIteration:
416 return baseset()
429 return baseset()
417 for r in reviter:
430 for r in reviter:
418 anc = anc.ancestor(repo[r])
431 anc = anc.ancestor(repo[r])
419
432
420 r = scmutil.intrev(anc)
433 r = scmutil.intrev(anc)
421 if r in subset:
434 if r in subset:
422 return baseset([r])
435 return baseset([r])
423 return baseset()
436 return baseset()
424
437
425
438
426 def _ancestors(
439 def _ancestors(
427 repo, subset, x, followfirst=False, startdepth=None, stopdepth=None
440 repo, subset, x, followfirst=False, startdepth=None, stopdepth=None
428 ):
441 ):
429 heads = getset(repo, fullreposet(repo), x)
442 heads = getset(repo, fullreposet(repo), x)
430 if not heads:
443 if not heads:
431 return baseset()
444 return baseset()
432 s = dagop.revancestors(repo, heads, followfirst, startdepth, stopdepth)
445 s = dagop.revancestors(repo, heads, followfirst, startdepth, stopdepth)
433 return subset & s
446 return subset & s
434
447
435
448
436 @predicate(b'ancestors(set[, depth])', safe=True)
449 @predicate(b'ancestors(set[, depth])', safe=True)
437 def ancestors(repo, subset, x):
450 def ancestors(repo, subset, x):
438 """Changesets that are ancestors of changesets in set, including the
451 """Changesets that are ancestors of changesets in set, including the
439 given changesets themselves.
452 given changesets themselves.
440
453
441 If depth is specified, the result only includes changesets up to
454 If depth is specified, the result only includes changesets up to
442 the specified generation.
455 the specified generation.
443 """
456 """
444 # startdepth is for internal use only until we can decide the UI
457 # startdepth is for internal use only until we can decide the UI
445 args = getargsdict(x, b'ancestors', b'set depth startdepth')
458 args = getargsdict(x, b'ancestors', b'set depth startdepth')
446 if b'set' not in args:
459 if b'set' not in args:
447 # i18n: "ancestors" is a keyword
460 # i18n: "ancestors" is a keyword
448 raise error.ParseError(_(b'ancestors takes at least 1 argument'))
461 raise error.ParseError(_(b'ancestors takes at least 1 argument'))
449 startdepth = stopdepth = None
462 startdepth = stopdepth = None
450 if b'startdepth' in args:
463 if b'startdepth' in args:
451 n = getinteger(
464 n = getinteger(
452 args[b'startdepth'], b"ancestors expects an integer startdepth"
465 args[b'startdepth'], b"ancestors expects an integer startdepth"
453 )
466 )
454 if n < 0:
467 if n < 0:
455 raise error.ParseError(b"negative startdepth")
468 raise error.ParseError(b"negative startdepth")
456 startdepth = n
469 startdepth = n
457 if b'depth' in args:
470 if b'depth' in args:
458 # i18n: "ancestors" is a keyword
471 # i18n: "ancestors" is a keyword
459 n = getinteger(args[b'depth'], _(b"ancestors expects an integer depth"))
472 n = getinteger(args[b'depth'], _(b"ancestors expects an integer depth"))
460 if n < 0:
473 if n < 0:
461 raise error.ParseError(_(b"negative depth"))
474 raise error.ParseError(_(b"negative depth"))
462 stopdepth = n + 1
475 stopdepth = n + 1
463 return _ancestors(
476 return _ancestors(
464 repo, subset, args[b'set'], startdepth=startdepth, stopdepth=stopdepth
477 repo, subset, args[b'set'], startdepth=startdepth, stopdepth=stopdepth
465 )
478 )
466
479
467
480
468 @predicate(b'_firstancestors', safe=True)
481 @predicate(b'_firstancestors', safe=True)
469 def _firstancestors(repo, subset, x):
482 def _firstancestors(repo, subset, x):
470 # ``_firstancestors(set)``
483 # ``_firstancestors(set)``
471 # Like ``ancestors(set)`` but follows only the first parents.
484 # Like ``ancestors(set)`` but follows only the first parents.
472 return _ancestors(repo, subset, x, followfirst=True)
485 return _ancestors(repo, subset, x, followfirst=True)
473
486
474
487
475 def _childrenspec(repo, subset, x, n, order):
488 def _childrenspec(repo, subset, x, n, order):
476 """Changesets that are the Nth child of a changeset
489 """Changesets that are the Nth child of a changeset
477 in set.
490 in set.
478 """
491 """
479 cs = set()
492 cs = set()
480 for r in getset(repo, fullreposet(repo), x):
493 for r in getset(repo, fullreposet(repo), x):
481 for i in range(n):
494 for i in range(n):
482 c = repo[r].children()
495 c = repo[r].children()
483 if len(c) == 0:
496 if len(c) == 0:
484 break
497 break
485 if len(c) > 1:
498 if len(c) > 1:
486 raise error.RepoLookupError(
499 raise error.RepoLookupError(
487 _(b"revision in set has more than one child")
500 _(b"revision in set has more than one child")
488 )
501 )
489 r = c[0].rev()
502 r = c[0].rev()
490 else:
503 else:
491 cs.add(r)
504 cs.add(r)
492 return subset & cs
505 return subset & cs
493
506
494
507
495 def ancestorspec(repo, subset, x, n, order):
508 def ancestorspec(repo, subset, x, n, order):
496 """``set~n``
509 """``set~n``
497 Changesets that are the Nth ancestor (first parents only) of a changeset
510 Changesets that are the Nth ancestor (first parents only) of a changeset
498 in set.
511 in set.
499 """
512 """
500 n = getinteger(n, _(b"~ expects a number"))
513 n = getinteger(n, _(b"~ expects a number"))
501 if n < 0:
514 if n < 0:
502 # children lookup
515 # children lookup
503 return _childrenspec(repo, subset, x, -n, order)
516 return _childrenspec(repo, subset, x, -n, order)
504 ps = set()
517 ps = set()
505 cl = repo.changelog
518 cl = repo.changelog
506 for r in getset(repo, fullreposet(repo), x):
519 for r in getset(repo, fullreposet(repo), x):
507 for i in range(n):
520 for i in range(n):
508 try:
521 try:
509 r = cl.parentrevs(r)[0]
522 r = cl.parentrevs(r)[0]
510 except error.WdirUnsupported:
523 except error.WdirUnsupported:
511 r = repo[r].p1().rev()
524 r = repo[r].p1().rev()
512 ps.add(r)
525 ps.add(r)
513 return subset & ps
526 return subset & ps
514
527
515
528
516 @predicate(b'author(string)', safe=True, weight=10)
529 @predicate(b'author(string)', safe=True, weight=10)
517 def author(repo, subset, x):
530 def author(repo, subset, x):
518 """Alias for ``user(string)``.
531 """Alias for ``user(string)``.
519 """
532 """
520 # i18n: "author" is a keyword
533 # i18n: "author" is a keyword
521 n = getstring(x, _(b"author requires a string"))
534 n = getstring(x, _(b"author requires a string"))
522 kind, pattern, matcher = _substringmatcher(n, casesensitive=False)
535 kind, pattern, matcher = _substringmatcher(n, casesensitive=False)
523 return subset.filter(
536 return subset.filter(
524 lambda x: matcher(repo[x].user()), condrepr=(b'<user %r>', n)
537 lambda x: matcher(repo[x].user()), condrepr=(b'<user %r>', n)
525 )
538 )
526
539
527
540
528 @predicate(b'bisect(string)', safe=True)
541 @predicate(b'bisect(string)', safe=True)
529 def bisect(repo, subset, x):
542 def bisect(repo, subset, x):
530 """Changesets marked in the specified bisect status:
543 """Changesets marked in the specified bisect status:
531
544
532 - ``good``, ``bad``, ``skip``: csets explicitly marked as good/bad/skip
545 - ``good``, ``bad``, ``skip``: csets explicitly marked as good/bad/skip
533 - ``goods``, ``bads`` : csets topologically good/bad
546 - ``goods``, ``bads`` : csets topologically good/bad
534 - ``range`` : csets taking part in the bisection
547 - ``range`` : csets taking part in the bisection
535 - ``pruned`` : csets that are goods, bads or skipped
548 - ``pruned`` : csets that are goods, bads or skipped
536 - ``untested`` : csets whose fate is yet unknown
549 - ``untested`` : csets whose fate is yet unknown
537 - ``ignored`` : csets ignored due to DAG topology
550 - ``ignored`` : csets ignored due to DAG topology
538 - ``current`` : the cset currently being bisected
551 - ``current`` : the cset currently being bisected
539 """
552 """
540 # i18n: "bisect" is a keyword
553 # i18n: "bisect" is a keyword
541 status = getstring(x, _(b"bisect requires a string")).lower()
554 status = getstring(x, _(b"bisect requires a string")).lower()
542 state = set(hbisect.get(repo, status))
555 state = set(hbisect.get(repo, status))
543 return subset & state
556 return subset & state
544
557
545
558
546 # Backward-compatibility
559 # Backward-compatibility
547 # - no help entry so that we do not advertise it any more
560 # - no help entry so that we do not advertise it any more
548 @predicate(b'bisected', safe=True)
561 @predicate(b'bisected', safe=True)
549 def bisected(repo, subset, x):
562 def bisected(repo, subset, x):
550 return bisect(repo, subset, x)
563 return bisect(repo, subset, x)
551
564
552
565
553 @predicate(b'bookmark([name])', safe=True)
566 @predicate(b'bookmark([name])', safe=True)
554 def bookmark(repo, subset, x):
567 def bookmark(repo, subset, x):
555 """The named bookmark or all bookmarks.
568 """The named bookmark or all bookmarks.
556
569
557 Pattern matching is supported for `name`. See :hg:`help revisions.patterns`.
570 Pattern matching is supported for `name`. See :hg:`help revisions.patterns`.
558 """
571 """
559 # i18n: "bookmark" is a keyword
572 # i18n: "bookmark" is a keyword
560 args = getargs(x, 0, 1, _(b'bookmark takes one or no arguments'))
573 args = getargs(x, 0, 1, _(b'bookmark takes one or no arguments'))
561 if args:
574 if args:
562 bm = getstring(
575 bm = getstring(
563 args[0],
576 args[0],
564 # i18n: "bookmark" is a keyword
577 # i18n: "bookmark" is a keyword
565 _(b'the argument to bookmark must be a string'),
578 _(b'the argument to bookmark must be a string'),
566 )
579 )
567 kind, pattern, matcher = stringutil.stringmatcher(bm)
580 kind, pattern, matcher = stringutil.stringmatcher(bm)
568 bms = set()
581 bms = set()
569 if kind == b'literal':
582 if kind == b'literal':
570 if bm == pattern:
583 if bm == pattern:
571 pattern = repo._bookmarks.expandname(pattern)
584 pattern = repo._bookmarks.expandname(pattern)
572 bmrev = repo._bookmarks.get(pattern, None)
585 bmrev = repo._bookmarks.get(pattern, None)
573 if not bmrev:
586 if not bmrev:
574 raise error.RepoLookupError(
587 raise error.RepoLookupError(
575 _(b"bookmark '%s' does not exist") % pattern
588 _(b"bookmark '%s' does not exist") % pattern
576 )
589 )
577 bms.add(repo[bmrev].rev())
590 bms.add(repo[bmrev].rev())
578 else:
591 else:
579 matchrevs = set()
592 matchrevs = set()
580 for name, bmrev in pycompat.iteritems(repo._bookmarks):
593 for name, bmrev in pycompat.iteritems(repo._bookmarks):
581 if matcher(name):
594 if matcher(name):
582 matchrevs.add(bmrev)
595 matchrevs.add(bmrev)
583 for bmrev in matchrevs:
596 for bmrev in matchrevs:
584 bms.add(repo[bmrev].rev())
597 bms.add(repo[bmrev].rev())
585 else:
598 else:
586 bms = {repo[r].rev() for r in repo._bookmarks.values()}
599 bms = {repo[r].rev() for r in repo._bookmarks.values()}
587 bms -= {node.nullrev}
600 bms -= {node.nullrev}
588 return subset & bms
601 return subset & bms
589
602
590
603
591 @predicate(b'branch(string or set)', safe=True, weight=10)
604 @predicate(b'branch(string or set)', safe=True, weight=10)
592 def branch(repo, subset, x):
605 def branch(repo, subset, x):
593 """
606 """
594 All changesets belonging to the given branch or the branches of the given
607 All changesets belonging to the given branch or the branches of the given
595 changesets.
608 changesets.
596
609
597 Pattern matching is supported for `string`. See
610 Pattern matching is supported for `string`. See
598 :hg:`help revisions.patterns`.
611 :hg:`help revisions.patterns`.
599 """
612 """
600 getbi = repo.revbranchcache().branchinfo
613 getbi = repo.revbranchcache().branchinfo
601
614
602 def getbranch(r):
615 def getbranch(r):
603 try:
616 try:
604 return getbi(r)[0]
617 return getbi(r)[0]
605 except error.WdirUnsupported:
618 except error.WdirUnsupported:
606 return repo[r].branch()
619 return repo[r].branch()
607
620
608 try:
621 try:
609 b = getstring(x, b'')
622 b = getstring(x, b'')
610 except error.ParseError:
623 except error.ParseError:
611 # not a string, but another revspec, e.g. tip()
624 # not a string, but another revspec, e.g. tip()
612 pass
625 pass
613 else:
626 else:
614 kind, pattern, matcher = stringutil.stringmatcher(b)
627 kind, pattern, matcher = stringutil.stringmatcher(b)
615 if kind == b'literal':
628 if kind == b'literal':
616 # note: falls through to the revspec case if no branch with
629 # note: falls through to the revspec case if no branch with
617 # this name exists and pattern kind is not specified explicitly
630 # this name exists and pattern kind is not specified explicitly
618 if repo.branchmap().hasbranch(pattern):
631 if repo.branchmap().hasbranch(pattern):
619 return subset.filter(
632 return subset.filter(
620 lambda r: matcher(getbranch(r)),
633 lambda r: matcher(getbranch(r)),
621 condrepr=(b'<branch %r>', b),
634 condrepr=(b'<branch %r>', b),
622 )
635 )
623 if b.startswith(b'literal:'):
636 if b.startswith(b'literal:'):
624 raise error.RepoLookupError(
637 raise error.RepoLookupError(
625 _(b"branch '%s' does not exist") % pattern
638 _(b"branch '%s' does not exist") % pattern
626 )
639 )
627 else:
640 else:
628 return subset.filter(
641 return subset.filter(
629 lambda r: matcher(getbranch(r)), condrepr=(b'<branch %r>', b)
642 lambda r: matcher(getbranch(r)), condrepr=(b'<branch %r>', b)
630 )
643 )
631
644
632 s = getset(repo, fullreposet(repo), x)
645 s = getset(repo, fullreposet(repo), x)
633 b = set()
646 b = set()
634 for r in s:
647 for r in s:
635 b.add(getbranch(r))
648 b.add(getbranch(r))
636 c = s.__contains__
649 c = s.__contains__
637 return subset.filter(
650 return subset.filter(
638 lambda r: c(r) or getbranch(r) in b,
651 lambda r: c(r) or getbranch(r) in b,
639 condrepr=lambda: b'<branch %r>' % _sortedb(b),
652 condrepr=lambda: b'<branch %r>' % _sortedb(b),
640 )
653 )
641
654
642
655
643 @predicate(b'phasedivergent()', safe=True)
656 @predicate(b'phasedivergent()', safe=True)
644 def phasedivergent(repo, subset, x):
657 def phasedivergent(repo, subset, x):
645 """Mutable changesets marked as successors of public changesets.
658 """Mutable changesets marked as successors of public changesets.
646
659
647 Only non-public and non-obsolete changesets can be `phasedivergent`.
660 Only non-public and non-obsolete changesets can be `phasedivergent`.
648 (EXPERIMENTAL)
661 (EXPERIMENTAL)
649 """
662 """
650 # i18n: "phasedivergent" is a keyword
663 # i18n: "phasedivergent" is a keyword
651 getargs(x, 0, 0, _(b"phasedivergent takes no arguments"))
664 getargs(x, 0, 0, _(b"phasedivergent takes no arguments"))
652 phasedivergent = obsmod.getrevs(repo, b'phasedivergent')
665 phasedivergent = obsmod.getrevs(repo, b'phasedivergent')
653 return subset & phasedivergent
666 return subset & phasedivergent
654
667
655
668
656 @predicate(b'bundle()', safe=True)
669 @predicate(b'bundle()', safe=True)
657 def bundle(repo, subset, x):
670 def bundle(repo, subset, x):
658 """Changesets in the bundle.
671 """Changesets in the bundle.
659
672
660 Bundle must be specified by the -R option."""
673 Bundle must be specified by the -R option."""
661
674
662 try:
675 try:
663 bundlerevs = repo.changelog.bundlerevs
676 bundlerevs = repo.changelog.bundlerevs
664 except AttributeError:
677 except AttributeError:
665 raise error.Abort(_(b"no bundle provided - specify with -R"))
678 raise error.Abort(_(b"no bundle provided - specify with -R"))
666 return subset & bundlerevs
679 return subset & bundlerevs
667
680
668
681
669 def checkstatus(repo, subset, pat, field):
682 def checkstatus(repo, subset, pat, field):
670 """Helper for status-related revsets (adds, removes, modifies).
683 """Helper for status-related revsets (adds, removes, modifies).
671 The field parameter says which kind is desired:
684 The field parameter says which kind is desired:
672 0: modified
685 0: modified
673 1: added
686 1: added
674 2: removed
687 2: removed
675 """
688 """
676 label = {0: 'modified', 1: 'added', 2: 'removed'}[field]
689 label = {0: 'modified', 1: 'added', 2: 'removed'}[field]
677 hasset = matchmod.patkind(pat) == b'set'
690 hasset = matchmod.patkind(pat) == b'set'
678
691
679 mcache = [None]
692 mcache = [None]
680
693
681 def matches(x):
694 def matches(x):
682 c = repo[x]
695 c = repo[x]
683 if not mcache[0] or hasset:
696 if not mcache[0] or hasset:
684 mcache[0] = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
697 mcache[0] = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
685 m = mcache[0]
698 m = mcache[0]
686 fname = None
699 fname = None
687
700
688 assert m is not None # help pytype
701 assert m is not None # help pytype
689 if not m.anypats() and len(m.files()) == 1:
702 if not m.anypats() and len(m.files()) == 1:
690 fname = m.files()[0]
703 fname = m.files()[0]
691 if fname is not None:
704 if fname is not None:
692 if fname not in c.files():
705 if fname not in c.files():
693 return False
706 return False
694 else:
707 else:
695 if not any(m(f) for f in c.files()):
708 if not any(m(f) for f in c.files()):
696 return False
709 return False
697 files = getattr(repo.status(c.p1().node(), c.node()), label)
710 files = getattr(repo.status(c.p1().node(), c.node()), label)
698 if fname is not None:
711 if fname is not None:
699 if fname in files:
712 if fname in files:
700 return True
713 return True
701 else:
714 else:
702 if any(m(f) for f in files):
715 if any(m(f) for f in files):
703 return True
716 return True
704
717
705 return subset.filter(matches, condrepr=(b'<status[%r] %r>', field, pat))
718 return subset.filter(matches, condrepr=(b'<status[%r] %r>', field, pat))
706
719
707
720
708 def _children(repo, subset, parentset):
721 def _children(repo, subset, parentset):
709 if not parentset:
722 if not parentset:
710 return baseset()
723 return baseset()
711 cs = set()
724 cs = set()
712 pr = repo.changelog.parentrevs
725 pr = repo.changelog.parentrevs
713 minrev = parentset.min()
726 minrev = parentset.min()
714 nullrev = node.nullrev
727 nullrev = node.nullrev
715 for r in subset:
728 for r in subset:
716 if r <= minrev:
729 if r <= minrev:
717 continue
730 continue
718 p1, p2 = pr(r)
731 p1, p2 = pr(r)
719 if p1 in parentset:
732 if p1 in parentset:
720 cs.add(r)
733 cs.add(r)
721 if p2 != nullrev and p2 in parentset:
734 if p2 != nullrev and p2 in parentset:
722 cs.add(r)
735 cs.add(r)
723 return baseset(cs)
736 return baseset(cs)
724
737
725
738
726 @predicate(b'children(set)', safe=True)
739 @predicate(b'children(set)', safe=True)
727 def children(repo, subset, x):
740 def children(repo, subset, x):
728 """Child changesets of changesets in set.
741 """Child changesets of changesets in set.
729 """
742 """
730 s = getset(repo, fullreposet(repo), x)
743 s = getset(repo, fullreposet(repo), x)
731 cs = _children(repo, subset, s)
744 cs = _children(repo, subset, s)
732 return subset & cs
745 return subset & cs
733
746
734
747
735 @predicate(b'closed()', safe=True, weight=10)
748 @predicate(b'closed()', safe=True, weight=10)
736 def closed(repo, subset, x):
749 def closed(repo, subset, x):
737 """Changeset is closed.
750 """Changeset is closed.
738 """
751 """
739 # i18n: "closed" is a keyword
752 # i18n: "closed" is a keyword
740 getargs(x, 0, 0, _(b"closed takes no arguments"))
753 getargs(x, 0, 0, _(b"closed takes no arguments"))
741 return subset.filter(
754 return subset.filter(
742 lambda r: repo[r].closesbranch(), condrepr=b'<branch closed>'
755 lambda r: repo[r].closesbranch(), condrepr=b'<branch closed>'
743 )
756 )
744
757
745
758
746 # for internal use
759 # for internal use
747 @predicate(b'_commonancestorheads(set)', safe=True)
760 @predicate(b'_commonancestorheads(set)', safe=True)
748 def _commonancestorheads(repo, subset, x):
761 def _commonancestorheads(repo, subset, x):
749 # This is an internal method is for quickly calculating "heads(::x and
762 # This is an internal method is for quickly calculating "heads(::x and
750 # ::y)"
763 # ::y)"
751
764
752 # These greatest common ancestors are the same ones that the consensus bid
765 # These greatest common ancestors are the same ones that the consensus bid
753 # merge will find.
766 # merge will find.
754 startrevs = getset(repo, fullreposet(repo), x, order=anyorder)
767 startrevs = getset(repo, fullreposet(repo), x, order=anyorder)
755
768
756 ancs = repo.changelog._commonancestorsheads(*list(startrevs))
769 ancs = repo.changelog._commonancestorsheads(*list(startrevs))
757 return subset & baseset(ancs)
770 return subset & baseset(ancs)
758
771
759
772
760 @predicate(b'commonancestors(set)', safe=True)
773 @predicate(b'commonancestors(set)', safe=True)
761 def commonancestors(repo, subset, x):
774 def commonancestors(repo, subset, x):
762 """Changesets that are ancestors of every changeset in set.
775 """Changesets that are ancestors of every changeset in set.
763 """
776 """
764 startrevs = getset(repo, fullreposet(repo), x, order=anyorder)
777 startrevs = getset(repo, fullreposet(repo), x, order=anyorder)
765 if not startrevs:
778 if not startrevs:
766 return baseset()
779 return baseset()
767 for r in startrevs:
780 for r in startrevs:
768 subset &= dagop.revancestors(repo, baseset([r]))
781 subset &= dagop.revancestors(repo, baseset([r]))
769 return subset
782 return subset
770
783
771
784
772 @predicate(b'conflictlocal()', safe=True)
785 @predicate(b'conflictlocal()', safe=True)
773 def conflictlocal(repo, subset, x):
786 def conflictlocal(repo, subset, x):
774 """The local side of the merge, if currently in an unresolved merge.
787 """The local side of the merge, if currently in an unresolved merge.
775
788
776 "merge" here includes merge conflicts from e.g. 'hg rebase' or 'hg graft'.
789 "merge" here includes merge conflicts from e.g. 'hg rebase' or 'hg graft'.
777 """
790 """
778 getargs(x, 0, 0, _(b"conflictlocal takes no arguments"))
791 getargs(x, 0, 0, _(b"conflictlocal takes no arguments"))
779 from . import merge
792 from . import merge
780
793
781 mergestate = merge.mergestate.read(repo)
794 mergestate = merge.mergestate.read(repo)
782 if mergestate.active() and repo.changelog.hasnode(mergestate.local):
795 if mergestate.active() and repo.changelog.hasnode(mergestate.local):
783 return subset & {repo.changelog.rev(mergestate.local)}
796 return subset & {repo.changelog.rev(mergestate.local)}
784
797
785 return baseset()
798 return baseset()
786
799
787
800
788 @predicate(b'conflictother()', safe=True)
801 @predicate(b'conflictother()', safe=True)
789 def conflictother(repo, subset, x):
802 def conflictother(repo, subset, x):
790 """The other side of the merge, if currently in an unresolved merge.
803 """The other side of the merge, if currently in an unresolved merge.
791
804
792 "merge" here includes merge conflicts from e.g. 'hg rebase' or 'hg graft'.
805 "merge" here includes merge conflicts from e.g. 'hg rebase' or 'hg graft'.
793 """
806 """
794 getargs(x, 0, 0, _(b"conflictother takes no arguments"))
807 getargs(x, 0, 0, _(b"conflictother takes no arguments"))
795 from . import merge
808 from . import merge
796
809
797 mergestate = merge.mergestate.read(repo)
810 mergestate = merge.mergestate.read(repo)
798 if mergestate.active() and repo.changelog.hasnode(mergestate.other):
811 if mergestate.active() and repo.changelog.hasnode(mergestate.other):
799 return subset & {repo.changelog.rev(mergestate.other)}
812 return subset & {repo.changelog.rev(mergestate.other)}
800
813
801 return baseset()
814 return baseset()
802
815
803
816
804 @predicate(b'contains(pattern)', weight=100)
817 @predicate(b'contains(pattern)', weight=100)
805 def contains(repo, subset, x):
818 def contains(repo, subset, x):
806 """The revision's manifest contains a file matching pattern (but might not
819 """The revision's manifest contains a file matching pattern (but might not
807 modify it). See :hg:`help patterns` for information about file patterns.
820 modify it). See :hg:`help patterns` for information about file patterns.
808
821
809 The pattern without explicit kind like ``glob:`` is expected to be
822 The pattern without explicit kind like ``glob:`` is expected to be
810 relative to the current directory and match against a file exactly
823 relative to the current directory and match against a file exactly
811 for efficiency.
824 for efficiency.
812 """
825 """
813 # i18n: "contains" is a keyword
826 # i18n: "contains" is a keyword
814 pat = getstring(x, _(b"contains requires a pattern"))
827 pat = getstring(x, _(b"contains requires a pattern"))
815
828
816 def matches(x):
829 def matches(x):
817 if not matchmod.patkind(pat):
830 if not matchmod.patkind(pat):
818 pats = pathutil.canonpath(repo.root, repo.getcwd(), pat)
831 pats = pathutil.canonpath(repo.root, repo.getcwd(), pat)
819 if pats in repo[x]:
832 if pats in repo[x]:
820 return True
833 return True
821 else:
834 else:
822 c = repo[x]
835 c = repo[x]
823 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
836 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
824 for f in c.manifest():
837 for f in c.manifest():
825 if m(f):
838 if m(f):
826 return True
839 return True
827 return False
840 return False
828
841
829 return subset.filter(matches, condrepr=(b'<contains %r>', pat))
842 return subset.filter(matches, condrepr=(b'<contains %r>', pat))
830
843
831
844
832 @predicate(b'converted([id])', safe=True)
845 @predicate(b'converted([id])', safe=True)
833 def converted(repo, subset, x):
846 def converted(repo, subset, x):
834 """Changesets converted from the given identifier in the old repository if
847 """Changesets converted from the given identifier in the old repository if
835 present, or all converted changesets if no identifier is specified.
848 present, or all converted changesets if no identifier is specified.
836 """
849 """
837
850
838 # There is exactly no chance of resolving the revision, so do a simple
851 # There is exactly no chance of resolving the revision, so do a simple
839 # string compare and hope for the best
852 # string compare and hope for the best
840
853
841 rev = None
854 rev = None
842 # i18n: "converted" is a keyword
855 # i18n: "converted" is a keyword
843 l = getargs(x, 0, 1, _(b'converted takes one or no arguments'))
856 l = getargs(x, 0, 1, _(b'converted takes one or no arguments'))
844 if l:
857 if l:
845 # i18n: "converted" is a keyword
858 # i18n: "converted" is a keyword
846 rev = getstring(l[0], _(b'converted requires a revision'))
859 rev = getstring(l[0], _(b'converted requires a revision'))
847
860
848 def _matchvalue(r):
861 def _matchvalue(r):
849 source = repo[r].extra().get(b'convert_revision', None)
862 source = repo[r].extra().get(b'convert_revision', None)
850 return source is not None and (rev is None or source.startswith(rev))
863 return source is not None and (rev is None or source.startswith(rev))
851
864
852 return subset.filter(
865 return subset.filter(
853 lambda r: _matchvalue(r), condrepr=(b'<converted %r>', rev)
866 lambda r: _matchvalue(r), condrepr=(b'<converted %r>', rev)
854 )
867 )
855
868
856
869
857 @predicate(b'date(interval)', safe=True, weight=10)
870 @predicate(b'date(interval)', safe=True, weight=10)
858 def date(repo, subset, x):
871 def date(repo, subset, x):
859 """Changesets within the interval, see :hg:`help dates`.
872 """Changesets within the interval, see :hg:`help dates`.
860 """
873 """
861 # i18n: "date" is a keyword
874 # i18n: "date" is a keyword
862 ds = getstring(x, _(b"date requires a string"))
875 ds = getstring(x, _(b"date requires a string"))
863 dm = dateutil.matchdate(ds)
876 dm = dateutil.matchdate(ds)
864 return subset.filter(
877 return subset.filter(
865 lambda x: dm(repo[x].date()[0]), condrepr=(b'<date %r>', ds)
878 lambda x: dm(repo[x].date()[0]), condrepr=(b'<date %r>', ds)
866 )
879 )
867
880
868
881
869 @predicate(b'desc(string)', safe=True, weight=10)
882 @predicate(b'desc(string)', safe=True, weight=10)
870 def desc(repo, subset, x):
883 def desc(repo, subset, x):
871 """Search commit message for string. The match is case-insensitive.
884 """Search commit message for string. The match is case-insensitive.
872
885
873 Pattern matching is supported for `string`. See
886 Pattern matching is supported for `string`. See
874 :hg:`help revisions.patterns`.
887 :hg:`help revisions.patterns`.
875 """
888 """
876 # i18n: "desc" is a keyword
889 # i18n: "desc" is a keyword
877 ds = getstring(x, _(b"desc requires a string"))
890 ds = getstring(x, _(b"desc requires a string"))
878
891
879 kind, pattern, matcher = _substringmatcher(ds, casesensitive=False)
892 kind, pattern, matcher = _substringmatcher(ds, casesensitive=False)
880
893
881 return subset.filter(
894 return subset.filter(
882 lambda r: matcher(repo[r].description()), condrepr=(b'<desc %r>', ds)
895 lambda r: matcher(repo[r].description()), condrepr=(b'<desc %r>', ds)
883 )
896 )
884
897
885
898
886 def _descendants(
899 def _descendants(
887 repo, subset, x, followfirst=False, startdepth=None, stopdepth=None
900 repo, subset, x, followfirst=False, startdepth=None, stopdepth=None
888 ):
901 ):
889 roots = getset(repo, fullreposet(repo), x)
902 roots = getset(repo, fullreposet(repo), x)
890 if not roots:
903 if not roots:
891 return baseset()
904 return baseset()
892 s = dagop.revdescendants(repo, roots, followfirst, startdepth, stopdepth)
905 s = dagop.revdescendants(repo, roots, followfirst, startdepth, stopdepth)
893 return subset & s
906 return subset & s
894
907
895
908
896 @predicate(b'descendants(set[, depth])', safe=True)
909 @predicate(b'descendants(set[, depth])', safe=True)
897 def descendants(repo, subset, x):
910 def descendants(repo, subset, x):
898 """Changesets which are descendants of changesets in set, including the
911 """Changesets which are descendants of changesets in set, including the
899 given changesets themselves.
912 given changesets themselves.
900
913
901 If depth is specified, the result only includes changesets up to
914 If depth is specified, the result only includes changesets up to
902 the specified generation.
915 the specified generation.
903 """
916 """
904 # startdepth is for internal use only until we can decide the UI
917 # startdepth is for internal use only until we can decide the UI
905 args = getargsdict(x, b'descendants', b'set depth startdepth')
918 args = getargsdict(x, b'descendants', b'set depth startdepth')
906 if b'set' not in args:
919 if b'set' not in args:
907 # i18n: "descendants" is a keyword
920 # i18n: "descendants" is a keyword
908 raise error.ParseError(_(b'descendants takes at least 1 argument'))
921 raise error.ParseError(_(b'descendants takes at least 1 argument'))
909 startdepth = stopdepth = None
922 startdepth = stopdepth = None
910 if b'startdepth' in args:
923 if b'startdepth' in args:
911 n = getinteger(
924 n = getinteger(
912 args[b'startdepth'], b"descendants expects an integer startdepth"
925 args[b'startdepth'], b"descendants expects an integer startdepth"
913 )
926 )
914 if n < 0:
927 if n < 0:
915 raise error.ParseError(b"negative startdepth")
928 raise error.ParseError(b"negative startdepth")
916 startdepth = n
929 startdepth = n
917 if b'depth' in args:
930 if b'depth' in args:
918 # i18n: "descendants" is a keyword
931 # i18n: "descendants" is a keyword
919 n = getinteger(
932 n = getinteger(
920 args[b'depth'], _(b"descendants expects an integer depth")
933 args[b'depth'], _(b"descendants expects an integer depth")
921 )
934 )
922 if n < 0:
935 if n < 0:
923 raise error.ParseError(_(b"negative depth"))
936 raise error.ParseError(_(b"negative depth"))
924 stopdepth = n + 1
937 stopdepth = n + 1
925 return _descendants(
938 return _descendants(
926 repo, subset, args[b'set'], startdepth=startdepth, stopdepth=stopdepth
939 repo, subset, args[b'set'], startdepth=startdepth, stopdepth=stopdepth
927 )
940 )
928
941
929
942
930 @predicate(b'_firstdescendants', safe=True)
943 @predicate(b'_firstdescendants', safe=True)
931 def _firstdescendants(repo, subset, x):
944 def _firstdescendants(repo, subset, x):
932 # ``_firstdescendants(set)``
945 # ``_firstdescendants(set)``
933 # Like ``descendants(set)`` but follows only the first parents.
946 # Like ``descendants(set)`` but follows only the first parents.
934 return _descendants(repo, subset, x, followfirst=True)
947 return _descendants(repo, subset, x, followfirst=True)
935
948
936
949
937 @predicate(b'destination([set])', safe=True, weight=10)
950 @predicate(b'destination([set])', safe=True, weight=10)
938 def destination(repo, subset, x):
951 def destination(repo, subset, x):
939 """Changesets that were created by a graft, transplant or rebase operation,
952 """Changesets that were created by a graft, transplant or rebase operation,
940 with the given revisions specified as the source. Omitting the optional set
953 with the given revisions specified as the source. Omitting the optional set
941 is the same as passing all().
954 is the same as passing all().
942 """
955 """
943 if x is not None:
956 if x is not None:
944 sources = getset(repo, fullreposet(repo), x)
957 sources = getset(repo, fullreposet(repo), x)
945 else:
958 else:
946 sources = fullreposet(repo)
959 sources = fullreposet(repo)
947
960
948 dests = set()
961 dests = set()
949
962
950 # subset contains all of the possible destinations that can be returned, so
963 # subset contains all of the possible destinations that can be returned, so
951 # iterate over them and see if their source(s) were provided in the arg set.
964 # iterate over them and see if their source(s) were provided in the arg set.
952 # Even if the immediate src of r is not in the arg set, src's source (or
965 # Even if the immediate src of r is not in the arg set, src's source (or
953 # further back) may be. Scanning back further than the immediate src allows
966 # further back) may be. Scanning back further than the immediate src allows
954 # transitive transplants and rebases to yield the same results as transitive
967 # transitive transplants and rebases to yield the same results as transitive
955 # grafts.
968 # grafts.
956 for r in subset:
969 for r in subset:
957 src = _getrevsource(repo, r)
970 src = _getrevsource(repo, r)
958 lineage = None
971 lineage = None
959
972
960 while src is not None:
973 while src is not None:
961 if lineage is None:
974 if lineage is None:
962 lineage = list()
975 lineage = list()
963
976
964 lineage.append(r)
977 lineage.append(r)
965
978
966 # The visited lineage is a match if the current source is in the arg
979 # The visited lineage is a match if the current source is in the arg
967 # set. Since every candidate dest is visited by way of iterating
980 # set. Since every candidate dest is visited by way of iterating
968 # subset, any dests further back in the lineage will be tested by a
981 # subset, any dests further back in the lineage will be tested by a
969 # different iteration over subset. Likewise, if the src was already
982 # different iteration over subset. Likewise, if the src was already
970 # selected, the current lineage can be selected without going back
983 # selected, the current lineage can be selected without going back
971 # further.
984 # further.
972 if src in sources or src in dests:
985 if src in sources or src in dests:
973 dests.update(lineage)
986 dests.update(lineage)
974 break
987 break
975
988
976 r = src
989 r = src
977 src = _getrevsource(repo, r)
990 src = _getrevsource(repo, r)
978
991
979 return subset.filter(
992 return subset.filter(
980 dests.__contains__,
993 dests.__contains__,
981 condrepr=lambda: b'<destination %r>' % _sortedb(dests),
994 condrepr=lambda: b'<destination %r>' % _sortedb(dests),
982 )
995 )
983
996
984
997
985 @predicate(b'contentdivergent()', safe=True)
998 @predicate(b'contentdivergent()', safe=True)
986 def contentdivergent(repo, subset, x):
999 def contentdivergent(repo, subset, x):
987 """
1000 """
988 Final successors of changesets with an alternative set of final
1001 Final successors of changesets with an alternative set of final
989 successors. (EXPERIMENTAL)
1002 successors. (EXPERIMENTAL)
990 """
1003 """
991 # i18n: "contentdivergent" is a keyword
1004 # i18n: "contentdivergent" is a keyword
992 getargs(x, 0, 0, _(b"contentdivergent takes no arguments"))
1005 getargs(x, 0, 0, _(b"contentdivergent takes no arguments"))
993 contentdivergent = obsmod.getrevs(repo, b'contentdivergent')
1006 contentdivergent = obsmod.getrevs(repo, b'contentdivergent')
994 return subset & contentdivergent
1007 return subset & contentdivergent
995
1008
996
1009
997 @predicate(b'expectsize(set[, size])', safe=True, takeorder=True)
1010 @predicate(b'expectsize(set[, size])', safe=True, takeorder=True)
998 def expectsize(repo, subset, x, order):
1011 def expectsize(repo, subset, x, order):
999 """Return the given revset if size matches the revset size.
1012 """Return the given revset if size matches the revset size.
1000 Abort if the revset doesn't expect given size.
1013 Abort if the revset doesn't expect given size.
1001 size can either be an integer range or an integer.
1014 size can either be an integer range or an integer.
1002
1015
1003 For example, ``expectsize(0:1, 3:5)`` will abort as revset size is 2 and
1016 For example, ``expectsize(0:1, 3:5)`` will abort as revset size is 2 and
1004 2 is not between 3 and 5 inclusive."""
1017 2 is not between 3 and 5 inclusive."""
1005
1018
1006 args = getargsdict(x, b'expectsize', b'set size')
1019 args = getargsdict(x, b'expectsize', b'set size')
1007 minsize = 0
1020 minsize = 0
1008 maxsize = len(repo) + 1
1021 maxsize = len(repo) + 1
1009 err = b''
1022 err = b''
1010 if b'size' not in args or b'set' not in args:
1023 if b'size' not in args or b'set' not in args:
1011 raise error.ParseError(_(b'invalid set of arguments'))
1024 raise error.ParseError(_(b'invalid set of arguments'))
1012 minsize, maxsize = getintrange(
1025 minsize, maxsize = getintrange(
1013 args[b'size'],
1026 args[b'size'],
1014 _(b'expectsize requires a size range or a positive integer'),
1027 _(b'expectsize requires a size range or a positive integer'),
1015 _(b'size range bounds must be integers'),
1028 _(b'size range bounds must be integers'),
1016 minsize,
1029 minsize,
1017 maxsize,
1030 maxsize,
1018 )
1031 )
1019 if minsize < 0 or maxsize < 0:
1032 if minsize < 0 or maxsize < 0:
1020 raise error.ParseError(_(b'negative size'))
1033 raise error.ParseError(_(b'negative size'))
1021 rev = getset(repo, fullreposet(repo), args[b'set'], order=order)
1034 rev = getset(repo, fullreposet(repo), args[b'set'], order=order)
1022 if minsize != maxsize and (len(rev) < minsize or len(rev) > maxsize):
1035 if minsize != maxsize and (len(rev) < minsize or len(rev) > maxsize):
1023 err = _(b'revset size mismatch. expected between %d and %d, got %d') % (
1036 err = _(b'revset size mismatch. expected between %d and %d, got %d') % (
1024 minsize,
1037 minsize,
1025 maxsize,
1038 maxsize,
1026 len(rev),
1039 len(rev),
1027 )
1040 )
1028 elif minsize == maxsize and len(rev) != minsize:
1041 elif minsize == maxsize and len(rev) != minsize:
1029 err = _(b'revset size mismatch. expected %d, got %d') % (
1042 err = _(b'revset size mismatch. expected %d, got %d') % (
1030 minsize,
1043 minsize,
1031 len(rev),
1044 len(rev),
1032 )
1045 )
1033 if err:
1046 if err:
1034 raise error.RepoLookupError(err)
1047 raise error.RepoLookupError(err)
1035 if order == followorder:
1048 if order == followorder:
1036 return subset & rev
1049 return subset & rev
1037 else:
1050 else:
1038 return rev & subset
1051 return rev & subset
1039
1052
1040
1053
1041 @predicate(b'extdata(source)', safe=False, weight=100)
1054 @predicate(b'extdata(source)', safe=False, weight=100)
1042 def extdata(repo, subset, x):
1055 def extdata(repo, subset, x):
1043 """Changesets in the specified extdata source. (EXPERIMENTAL)"""
1056 """Changesets in the specified extdata source. (EXPERIMENTAL)"""
1044 # i18n: "extdata" is a keyword
1057 # i18n: "extdata" is a keyword
1045 args = getargsdict(x, b'extdata', b'source')
1058 args = getargsdict(x, b'extdata', b'source')
1046 source = getstring(
1059 source = getstring(
1047 args.get(b'source'),
1060 args.get(b'source'),
1048 # i18n: "extdata" is a keyword
1061 # i18n: "extdata" is a keyword
1049 _(b'extdata takes at least 1 string argument'),
1062 _(b'extdata takes at least 1 string argument'),
1050 )
1063 )
1051 data = scmutil.extdatasource(repo, source)
1064 data = scmutil.extdatasource(repo, source)
1052 return subset & baseset(data)
1065 return subset & baseset(data)
1053
1066
1054
1067
1055 @predicate(b'extinct()', safe=True)
1068 @predicate(b'extinct()', safe=True)
1056 def extinct(repo, subset, x):
1069 def extinct(repo, subset, x):
1057 """Obsolete changesets with obsolete descendants only. (EXPERIMENTAL)
1070 """Obsolete changesets with obsolete descendants only. (EXPERIMENTAL)
1058 """
1071 """
1059 # i18n: "extinct" is a keyword
1072 # i18n: "extinct" is a keyword
1060 getargs(x, 0, 0, _(b"extinct takes no arguments"))
1073 getargs(x, 0, 0, _(b"extinct takes no arguments"))
1061 extincts = obsmod.getrevs(repo, b'extinct')
1074 extincts = obsmod.getrevs(repo, b'extinct')
1062 return subset & extincts
1075 return subset & extincts
1063
1076
1064
1077
1065 @predicate(b'extra(label, [value])', safe=True)
1078 @predicate(b'extra(label, [value])', safe=True)
1066 def extra(repo, subset, x):
1079 def extra(repo, subset, x):
1067 """Changesets with the given label in the extra metadata, with the given
1080 """Changesets with the given label in the extra metadata, with the given
1068 optional value.
1081 optional value.
1069
1082
1070 Pattern matching is supported for `value`. See
1083 Pattern matching is supported for `value`. See
1071 :hg:`help revisions.patterns`.
1084 :hg:`help revisions.patterns`.
1072 """
1085 """
1073 args = getargsdict(x, b'extra', b'label value')
1086 args = getargsdict(x, b'extra', b'label value')
1074 if b'label' not in args:
1087 if b'label' not in args:
1075 # i18n: "extra" is a keyword
1088 # i18n: "extra" is a keyword
1076 raise error.ParseError(_(b'extra takes at least 1 argument'))
1089 raise error.ParseError(_(b'extra takes at least 1 argument'))
1077 # i18n: "extra" is a keyword
1090 # i18n: "extra" is a keyword
1078 label = getstring(
1091 label = getstring(
1079 args[b'label'], _(b'first argument to extra must be a string')
1092 args[b'label'], _(b'first argument to extra must be a string')
1080 )
1093 )
1081 value = None
1094 value = None
1082
1095
1083 if b'value' in args:
1096 if b'value' in args:
1084 # i18n: "extra" is a keyword
1097 # i18n: "extra" is a keyword
1085 value = getstring(
1098 value = getstring(
1086 args[b'value'], _(b'second argument to extra must be a string')
1099 args[b'value'], _(b'second argument to extra must be a string')
1087 )
1100 )
1088 kind, value, matcher = stringutil.stringmatcher(value)
1101 kind, value, matcher = stringutil.stringmatcher(value)
1089
1102
1090 def _matchvalue(r):
1103 def _matchvalue(r):
1091 extra = repo[r].extra()
1104 extra = repo[r].extra()
1092 return label in extra and (value is None or matcher(extra[label]))
1105 return label in extra and (value is None or matcher(extra[label]))
1093
1106
1094 return subset.filter(
1107 return subset.filter(
1095 lambda r: _matchvalue(r), condrepr=(b'<extra[%r] %r>', label, value)
1108 lambda r: _matchvalue(r), condrepr=(b'<extra[%r] %r>', label, value)
1096 )
1109 )
1097
1110
1098
1111
1099 @predicate(b'filelog(pattern)', safe=True)
1112 @predicate(b'filelog(pattern)', safe=True)
1100 def filelog(repo, subset, x):
1113 def filelog(repo, subset, x):
1101 """Changesets connected to the specified filelog.
1114 """Changesets connected to the specified filelog.
1102
1115
1103 For performance reasons, visits only revisions mentioned in the file-level
1116 For performance reasons, visits only revisions mentioned in the file-level
1104 filelog, rather than filtering through all changesets (much faster, but
1117 filelog, rather than filtering through all changesets (much faster, but
1105 doesn't include deletes or duplicate changes). For a slower, more accurate
1118 doesn't include deletes or duplicate changes). For a slower, more accurate
1106 result, use ``file()``.
1119 result, use ``file()``.
1107
1120
1108 The pattern without explicit kind like ``glob:`` is expected to be
1121 The pattern without explicit kind like ``glob:`` is expected to be
1109 relative to the current directory and match against a file exactly
1122 relative to the current directory and match against a file exactly
1110 for efficiency.
1123 for efficiency.
1111 """
1124 """
1112
1125
1113 # i18n: "filelog" is a keyword
1126 # i18n: "filelog" is a keyword
1114 pat = getstring(x, _(b"filelog requires a pattern"))
1127 pat = getstring(x, _(b"filelog requires a pattern"))
1115 s = set()
1128 s = set()
1116 cl = repo.changelog
1129 cl = repo.changelog
1117
1130
1118 if not matchmod.patkind(pat):
1131 if not matchmod.patkind(pat):
1119 f = pathutil.canonpath(repo.root, repo.getcwd(), pat)
1132 f = pathutil.canonpath(repo.root, repo.getcwd(), pat)
1120 files = [f]
1133 files = [f]
1121 else:
1134 else:
1122 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=repo[None])
1135 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=repo[None])
1123 files = (f for f in repo[None] if m(f))
1136 files = (f for f in repo[None] if m(f))
1124
1137
1125 for f in files:
1138 for f in files:
1126 fl = repo.file(f)
1139 fl = repo.file(f)
1127 known = {}
1140 known = {}
1128 scanpos = 0
1141 scanpos = 0
1129 for fr in list(fl):
1142 for fr in list(fl):
1130 fn = fl.node(fr)
1143 fn = fl.node(fr)
1131 if fn in known:
1144 if fn in known:
1132 s.add(known[fn])
1145 s.add(known[fn])
1133 continue
1146 continue
1134
1147
1135 lr = fl.linkrev(fr)
1148 lr = fl.linkrev(fr)
1136 if lr in cl:
1149 if lr in cl:
1137 s.add(lr)
1150 s.add(lr)
1138 elif scanpos is not None:
1151 elif scanpos is not None:
1139 # lowest matching changeset is filtered, scan further
1152 # lowest matching changeset is filtered, scan further
1140 # ahead in changelog
1153 # ahead in changelog
1141 start = max(lr, scanpos) + 1
1154 start = max(lr, scanpos) + 1
1142 scanpos = None
1155 scanpos = None
1143 for r in cl.revs(start):
1156 for r in cl.revs(start):
1144 # minimize parsing of non-matching entries
1157 # minimize parsing of non-matching entries
1145 if f in cl.revision(r) and f in cl.readfiles(r):
1158 if f in cl.revision(r) and f in cl.readfiles(r):
1146 try:
1159 try:
1147 # try to use manifest delta fastpath
1160 # try to use manifest delta fastpath
1148 n = repo[r].filenode(f)
1161 n = repo[r].filenode(f)
1149 if n not in known:
1162 if n not in known:
1150 if n == fn:
1163 if n == fn:
1151 s.add(r)
1164 s.add(r)
1152 scanpos = r
1165 scanpos = r
1153 break
1166 break
1154 else:
1167 else:
1155 known[n] = r
1168 known[n] = r
1156 except error.ManifestLookupError:
1169 except error.ManifestLookupError:
1157 # deletion in changelog
1170 # deletion in changelog
1158 continue
1171 continue
1159
1172
1160 return subset & s
1173 return subset & s
1161
1174
1162
1175
1163 @predicate(b'first(set, [n])', safe=True, takeorder=True, weight=0)
1176 @predicate(b'first(set, [n])', safe=True, takeorder=True, weight=0)
1164 def first(repo, subset, x, order):
1177 def first(repo, subset, x, order):
1165 """An alias for limit().
1178 """An alias for limit().
1166 """
1179 """
1167 return limit(repo, subset, x, order)
1180 return limit(repo, subset, x, order)
1168
1181
1169
1182
1170 def _follow(repo, subset, x, name, followfirst=False):
1183 def _follow(repo, subset, x, name, followfirst=False):
1171 args = getargsdict(x, name, b'file startrev')
1184 args = getargsdict(x, name, b'file startrev')
1172 revs = None
1185 revs = None
1173 if b'startrev' in args:
1186 if b'startrev' in args:
1174 revs = getset(repo, fullreposet(repo), args[b'startrev'])
1187 revs = getset(repo, fullreposet(repo), args[b'startrev'])
1175 if b'file' in args:
1188 if b'file' in args:
1176 x = getstring(args[b'file'], _(b"%s expected a pattern") % name)
1189 x = getstring(args[b'file'], _(b"%s expected a pattern") % name)
1177 if revs is None:
1190 if revs is None:
1178 revs = [None]
1191 revs = [None]
1179 fctxs = []
1192 fctxs = []
1180 for r in revs:
1193 for r in revs:
1181 ctx = mctx = repo[r]
1194 ctx = mctx = repo[r]
1182 if r is None:
1195 if r is None:
1183 ctx = repo[b'.']
1196 ctx = repo[b'.']
1184 m = matchmod.match(
1197 m = matchmod.match(
1185 repo.root, repo.getcwd(), [x], ctx=mctx, default=b'path'
1198 repo.root, repo.getcwd(), [x], ctx=mctx, default=b'path'
1186 )
1199 )
1187 fctxs.extend(ctx[f].introfilectx() for f in ctx.manifest().walk(m))
1200 fctxs.extend(ctx[f].introfilectx() for f in ctx.manifest().walk(m))
1188 s = dagop.filerevancestors(fctxs, followfirst)
1201 s = dagop.filerevancestors(fctxs, followfirst)
1189 else:
1202 else:
1190 if revs is None:
1203 if revs is None:
1191 revs = baseset([repo[b'.'].rev()])
1204 revs = baseset([repo[b'.'].rev()])
1192 s = dagop.revancestors(repo, revs, followfirst)
1205 s = dagop.revancestors(repo, revs, followfirst)
1193
1206
1194 return subset & s
1207 return subset & s
1195
1208
1196
1209
1197 @predicate(b'follow([file[, startrev]])', safe=True)
1210 @predicate(b'follow([file[, startrev]])', safe=True)
1198 def follow(repo, subset, x):
1211 def follow(repo, subset, x):
1199 """
1212 """
1200 An alias for ``::.`` (ancestors of the working directory's first parent).
1213 An alias for ``::.`` (ancestors of the working directory's first parent).
1201 If file pattern is specified, the histories of files matching given
1214 If file pattern is specified, the histories of files matching given
1202 pattern in the revision given by startrev are followed, including copies.
1215 pattern in the revision given by startrev are followed, including copies.
1203 """
1216 """
1204 return _follow(repo, subset, x, b'follow')
1217 return _follow(repo, subset, x, b'follow')
1205
1218
1206
1219
1207 @predicate(b'_followfirst', safe=True)
1220 @predicate(b'_followfirst', safe=True)
1208 def _followfirst(repo, subset, x):
1221 def _followfirst(repo, subset, x):
1209 # ``followfirst([file[, startrev]])``
1222 # ``followfirst([file[, startrev]])``
1210 # Like ``follow([file[, startrev]])`` but follows only the first parent
1223 # Like ``follow([file[, startrev]])`` but follows only the first parent
1211 # of every revisions or files revisions.
1224 # of every revisions or files revisions.
1212 return _follow(repo, subset, x, b'_followfirst', followfirst=True)
1225 return _follow(repo, subset, x, b'_followfirst', followfirst=True)
1213
1226
1214
1227
1215 @predicate(
1228 @predicate(
1216 b'followlines(file, fromline:toline[, startrev=., descend=False])',
1229 b'followlines(file, fromline:toline[, startrev=., descend=False])',
1217 safe=True,
1230 safe=True,
1218 )
1231 )
1219 def followlines(repo, subset, x):
1232 def followlines(repo, subset, x):
1220 """Changesets modifying `file` in line range ('fromline', 'toline').
1233 """Changesets modifying `file` in line range ('fromline', 'toline').
1221
1234
1222 Line range corresponds to 'file' content at 'startrev' and should hence be
1235 Line range corresponds to 'file' content at 'startrev' and should hence be
1223 consistent with file size. If startrev is not specified, working directory's
1236 consistent with file size. If startrev is not specified, working directory's
1224 parent is used.
1237 parent is used.
1225
1238
1226 By default, ancestors of 'startrev' are returned. If 'descend' is True,
1239 By default, ancestors of 'startrev' are returned. If 'descend' is True,
1227 descendants of 'startrev' are returned though renames are (currently) not
1240 descendants of 'startrev' are returned though renames are (currently) not
1228 followed in this direction.
1241 followed in this direction.
1229 """
1242 """
1230 args = getargsdict(x, b'followlines', b'file *lines startrev descend')
1243 args = getargsdict(x, b'followlines', b'file *lines startrev descend')
1231 if len(args[b'lines']) != 1:
1244 if len(args[b'lines']) != 1:
1232 raise error.ParseError(_(b"followlines requires a line range"))
1245 raise error.ParseError(_(b"followlines requires a line range"))
1233
1246
1234 rev = b'.'
1247 rev = b'.'
1235 if b'startrev' in args:
1248 if b'startrev' in args:
1236 revs = getset(repo, fullreposet(repo), args[b'startrev'])
1249 revs = getset(repo, fullreposet(repo), args[b'startrev'])
1237 if len(revs) != 1:
1250 if len(revs) != 1:
1238 raise error.ParseError(
1251 raise error.ParseError(
1239 # i18n: "followlines" is a keyword
1252 # i18n: "followlines" is a keyword
1240 _(b"followlines expects exactly one revision")
1253 _(b"followlines expects exactly one revision")
1241 )
1254 )
1242 rev = revs.last()
1255 rev = revs.last()
1243
1256
1244 pat = getstring(args[b'file'], _(b"followlines requires a pattern"))
1257 pat = getstring(args[b'file'], _(b"followlines requires a pattern"))
1245 # i18n: "followlines" is a keyword
1258 # i18n: "followlines" is a keyword
1246 msg = _(b"followlines expects exactly one file")
1259 msg = _(b"followlines expects exactly one file")
1247 fname = scmutil.parsefollowlinespattern(repo, rev, pat, msg)
1260 fname = scmutil.parsefollowlinespattern(repo, rev, pat, msg)
1248 fromline, toline = util.processlinerange(
1261 fromline, toline = util.processlinerange(
1249 *getintrange(
1262 *getintrange(
1250 args[b'lines'][0],
1263 args[b'lines'][0],
1251 # i18n: "followlines" is a keyword
1264 # i18n: "followlines" is a keyword
1252 _(b"followlines expects a line number or a range"),
1265 _(b"followlines expects a line number or a range"),
1253 _(b"line range bounds must be integers"),
1266 _(b"line range bounds must be integers"),
1254 )
1267 )
1255 )
1268 )
1256
1269
1257 fctx = repo[rev].filectx(fname)
1270 fctx = repo[rev].filectx(fname)
1258 descend = False
1271 descend = False
1259 if b'descend' in args:
1272 if b'descend' in args:
1260 descend = getboolean(
1273 descend = getboolean(
1261 args[b'descend'],
1274 args[b'descend'],
1262 # i18n: "descend" is a keyword
1275 # i18n: "descend" is a keyword
1263 _(b"descend argument must be a boolean"),
1276 _(b"descend argument must be a boolean"),
1264 )
1277 )
1265 if descend:
1278 if descend:
1266 rs = generatorset(
1279 rs = generatorset(
1267 (
1280 (
1268 c.rev()
1281 c.rev()
1269 for c, _linerange in dagop.blockdescendants(
1282 for c, _linerange in dagop.blockdescendants(
1270 fctx, fromline, toline
1283 fctx, fromline, toline
1271 )
1284 )
1272 ),
1285 ),
1273 iterasc=True,
1286 iterasc=True,
1274 )
1287 )
1275 else:
1288 else:
1276 rs = generatorset(
1289 rs = generatorset(
1277 (
1290 (
1278 c.rev()
1291 c.rev()
1279 for c, _linerange in dagop.blockancestors(
1292 for c, _linerange in dagop.blockancestors(
1280 fctx, fromline, toline
1293 fctx, fromline, toline
1281 )
1294 )
1282 ),
1295 ),
1283 iterasc=False,
1296 iterasc=False,
1284 )
1297 )
1285 return subset & rs
1298 return subset & rs
1286
1299
1287
1300
1288 @predicate(b'all()', safe=True)
1301 @predicate(b'all()', safe=True)
1289 def getall(repo, subset, x):
1302 def getall(repo, subset, x):
1290 """All changesets, the same as ``0:tip``.
1303 """All changesets, the same as ``0:tip``.
1291 """
1304 """
1292 # i18n: "all" is a keyword
1305 # i18n: "all" is a keyword
1293 getargs(x, 0, 0, _(b"all takes no arguments"))
1306 getargs(x, 0, 0, _(b"all takes no arguments"))
1294 return subset & spanset(repo) # drop "null" if any
1307 return subset & spanset(repo) # drop "null" if any
1295
1308
1296
1309
1297 @predicate(b'grep(regex)', weight=10)
1310 @predicate(b'grep(regex)', weight=10)
1298 def grep(repo, subset, x):
1311 def grep(repo, subset, x):
1299 """Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
1312 """Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
1300 to ensure special escape characters are handled correctly. Unlike
1313 to ensure special escape characters are handled correctly. Unlike
1301 ``keyword(string)``, the match is case-sensitive.
1314 ``keyword(string)``, the match is case-sensitive.
1302 """
1315 """
1303 try:
1316 try:
1304 # i18n: "grep" is a keyword
1317 # i18n: "grep" is a keyword
1305 gr = re.compile(getstring(x, _(b"grep requires a string")))
1318 gr = re.compile(getstring(x, _(b"grep requires a string")))
1306 except re.error as e:
1319 except re.error as e:
1307 raise error.ParseError(
1320 raise error.ParseError(
1308 _(b'invalid match pattern: %s') % stringutil.forcebytestr(e)
1321 _(b'invalid match pattern: %s') % stringutil.forcebytestr(e)
1309 )
1322 )
1310
1323
1311 def matches(x):
1324 def matches(x):
1312 c = repo[x]
1325 c = repo[x]
1313 for e in c.files() + [c.user(), c.description()]:
1326 for e in c.files() + [c.user(), c.description()]:
1314 if gr.search(e):
1327 if gr.search(e):
1315 return True
1328 return True
1316 return False
1329 return False
1317
1330
1318 return subset.filter(matches, condrepr=(b'<grep %r>', gr.pattern))
1331 return subset.filter(matches, condrepr=(b'<grep %r>', gr.pattern))
1319
1332
1320
1333
1321 @predicate(b'_matchfiles', safe=True)
1334 @predicate(b'_matchfiles', safe=True)
1322 def _matchfiles(repo, subset, x):
1335 def _matchfiles(repo, subset, x):
1323 # _matchfiles takes a revset list of prefixed arguments:
1336 # _matchfiles takes a revset list of prefixed arguments:
1324 #
1337 #
1325 # [p:foo, i:bar, x:baz]
1338 # [p:foo, i:bar, x:baz]
1326 #
1339 #
1327 # builds a match object from them and filters subset. Allowed
1340 # builds a match object from them and filters subset. Allowed
1328 # prefixes are 'p:' for regular patterns, 'i:' for include
1341 # prefixes are 'p:' for regular patterns, 'i:' for include
1329 # patterns and 'x:' for exclude patterns. Use 'r:' prefix to pass
1342 # patterns and 'x:' for exclude patterns. Use 'r:' prefix to pass
1330 # a revision identifier, or the empty string to reference the
1343 # a revision identifier, or the empty string to reference the
1331 # working directory, from which the match object is
1344 # working directory, from which the match object is
1332 # initialized. Use 'd:' to set the default matching mode, default
1345 # initialized. Use 'd:' to set the default matching mode, default
1333 # to 'glob'. At most one 'r:' and 'd:' argument can be passed.
1346 # to 'glob'. At most one 'r:' and 'd:' argument can be passed.
1334
1347
1335 l = getargs(x, 1, -1, b"_matchfiles requires at least one argument")
1348 l = getargs(x, 1, -1, b"_matchfiles requires at least one argument")
1336 pats, inc, exc = [], [], []
1349 pats, inc, exc = [], [], []
1337 rev, default = None, None
1350 rev, default = None, None
1338 for arg in l:
1351 for arg in l:
1339 s = getstring(arg, b"_matchfiles requires string arguments")
1352 s = getstring(arg, b"_matchfiles requires string arguments")
1340 prefix, value = s[:2], s[2:]
1353 prefix, value = s[:2], s[2:]
1341 if prefix == b'p:':
1354 if prefix == b'p:':
1342 pats.append(value)
1355 pats.append(value)
1343 elif prefix == b'i:':
1356 elif prefix == b'i:':
1344 inc.append(value)
1357 inc.append(value)
1345 elif prefix == b'x:':
1358 elif prefix == b'x:':
1346 exc.append(value)
1359 exc.append(value)
1347 elif prefix == b'r:':
1360 elif prefix == b'r:':
1348 if rev is not None:
1361 if rev is not None:
1349 raise error.ParseError(
1362 raise error.ParseError(
1350 b'_matchfiles expected at most one revision'
1363 b'_matchfiles expected at most one revision'
1351 )
1364 )
1352 if value == b'': # empty means working directory
1365 if value == b'': # empty means working directory
1353 rev = node.wdirrev
1366 rev = node.wdirrev
1354 else:
1367 else:
1355 rev = value
1368 rev = value
1356 elif prefix == b'd:':
1369 elif prefix == b'd:':
1357 if default is not None:
1370 if default is not None:
1358 raise error.ParseError(
1371 raise error.ParseError(
1359 b'_matchfiles expected at most one default mode'
1372 b'_matchfiles expected at most one default mode'
1360 )
1373 )
1361 default = value
1374 default = value
1362 else:
1375 else:
1363 raise error.ParseError(b'invalid _matchfiles prefix: %s' % prefix)
1376 raise error.ParseError(b'invalid _matchfiles prefix: %s' % prefix)
1364 if not default:
1377 if not default:
1365 default = b'glob'
1378 default = b'glob'
1366 hasset = any(matchmod.patkind(p) == b'set' for p in pats + inc + exc)
1379 hasset = any(matchmod.patkind(p) == b'set' for p in pats + inc + exc)
1367
1380
1368 mcache = [None]
1381 mcache = [None]
1369
1382
1370 # This directly read the changelog data as creating changectx for all
1383 # This directly read the changelog data as creating changectx for all
1371 # revisions is quite expensive.
1384 # revisions is quite expensive.
1372 getfiles = repo.changelog.readfiles
1385 getfiles = repo.changelog.readfiles
1373 wdirrev = node.wdirrev
1386 wdirrev = node.wdirrev
1374
1387
1375 def matches(x):
1388 def matches(x):
1376 if x == wdirrev:
1389 if x == wdirrev:
1377 files = repo[x].files()
1390 files = repo[x].files()
1378 else:
1391 else:
1379 files = getfiles(x)
1392 files = getfiles(x)
1380
1393
1381 if not mcache[0] or (hasset and rev is None):
1394 if not mcache[0] or (hasset and rev is None):
1382 r = x if rev is None else rev
1395 r = x if rev is None else rev
1383 mcache[0] = matchmod.match(
1396 mcache[0] = matchmod.match(
1384 repo.root,
1397 repo.root,
1385 repo.getcwd(),
1398 repo.getcwd(),
1386 pats,
1399 pats,
1387 include=inc,
1400 include=inc,
1388 exclude=exc,
1401 exclude=exc,
1389 ctx=repo[r],
1402 ctx=repo[r],
1390 default=default,
1403 default=default,
1391 )
1404 )
1392 m = mcache[0]
1405 m = mcache[0]
1393
1406
1394 for f in files:
1407 for f in files:
1395 if m(f):
1408 if m(f):
1396 return True
1409 return True
1397 return False
1410 return False
1398
1411
1399 return subset.filter(
1412 return subset.filter(
1400 matches,
1413 matches,
1401 condrepr=(
1414 condrepr=(
1402 b'<matchfiles patterns=%r, include=%r '
1415 b'<matchfiles patterns=%r, include=%r '
1403 b'exclude=%r, default=%r, rev=%r>',
1416 b'exclude=%r, default=%r, rev=%r>',
1404 pats,
1417 pats,
1405 inc,
1418 inc,
1406 exc,
1419 exc,
1407 default,
1420 default,
1408 rev,
1421 rev,
1409 ),
1422 ),
1410 )
1423 )
1411
1424
1412
1425
1413 @predicate(b'file(pattern)', safe=True, weight=10)
1426 @predicate(b'file(pattern)', safe=True, weight=10)
1414 def hasfile(repo, subset, x):
1427 def hasfile(repo, subset, x):
1415 """Changesets affecting files matched by pattern.
1428 """Changesets affecting files matched by pattern.
1416
1429
1417 For a faster but less accurate result, consider using ``filelog()``
1430 For a faster but less accurate result, consider using ``filelog()``
1418 instead.
1431 instead.
1419
1432
1420 This predicate uses ``glob:`` as the default kind of pattern.
1433 This predicate uses ``glob:`` as the default kind of pattern.
1421 """
1434 """
1422 # i18n: "file" is a keyword
1435 # i18n: "file" is a keyword
1423 pat = getstring(x, _(b"file requires a pattern"))
1436 pat = getstring(x, _(b"file requires a pattern"))
1424 return _matchfiles(repo, subset, (b'string', b'p:' + pat))
1437 return _matchfiles(repo, subset, (b'string', b'p:' + pat))
1425
1438
1426
1439
1427 @predicate(b'head()', safe=True)
1440 @predicate(b'head()', safe=True)
1428 def head(repo, subset, x):
1441 def head(repo, subset, x):
1429 """Changeset is a named branch head.
1442 """Changeset is a named branch head.
1430 """
1443 """
1431 # i18n: "head" is a keyword
1444 # i18n: "head" is a keyword
1432 getargs(x, 0, 0, _(b"head takes no arguments"))
1445 getargs(x, 0, 0, _(b"head takes no arguments"))
1433 hs = set()
1446 hs = set()
1434 cl = repo.changelog
1447 cl = repo.changelog
1435 for ls in repo.branchmap().iterheads():
1448 for ls in repo.branchmap().iterheads():
1436 hs.update(cl.rev(h) for h in ls)
1449 hs.update(cl.rev(h) for h in ls)
1437 return subset & baseset(hs)
1450 return subset & baseset(hs)
1438
1451
1439
1452
1440 @predicate(b'heads(set)', safe=True, takeorder=True)
1453 @predicate(b'heads(set)', safe=True, takeorder=True)
1441 def heads(repo, subset, x, order):
1454 def heads(repo, subset, x, order):
1442 """Members of set with no children in set.
1455 """Members of set with no children in set.
1443 """
1456 """
1444 # argument set should never define order
1457 # argument set should never define order
1445 if order == defineorder:
1458 if order == defineorder:
1446 order = followorder
1459 order = followorder
1447 inputset = getset(repo, fullreposet(repo), x, order=order)
1460 inputset = getset(repo, fullreposet(repo), x, order=order)
1448 wdirparents = None
1461 wdirparents = None
1449 if node.wdirrev in inputset:
1462 if node.wdirrev in inputset:
1450 # a bit slower, but not common so good enough for now
1463 # a bit slower, but not common so good enough for now
1451 wdirparents = [p.rev() for p in repo[None].parents()]
1464 wdirparents = [p.rev() for p in repo[None].parents()]
1452 inputset = set(inputset)
1465 inputset = set(inputset)
1453 inputset.discard(node.wdirrev)
1466 inputset.discard(node.wdirrev)
1454 heads = repo.changelog.headrevs(inputset)
1467 heads = repo.changelog.headrevs(inputset)
1455 if wdirparents is not None:
1468 if wdirparents is not None:
1456 heads.difference_update(wdirparents)
1469 heads.difference_update(wdirparents)
1457 heads.add(node.wdirrev)
1470 heads.add(node.wdirrev)
1458 heads = baseset(heads)
1471 heads = baseset(heads)
1459 return subset & heads
1472 return subset & heads
1460
1473
1461
1474
1462 @predicate(b'hidden()', safe=True)
1475 @predicate(b'hidden()', safe=True)
1463 def hidden(repo, subset, x):
1476 def hidden(repo, subset, x):
1464 """Hidden changesets.
1477 """Hidden changesets.
1465 """
1478 """
1466 # i18n: "hidden" is a keyword
1479 # i18n: "hidden" is a keyword
1467 getargs(x, 0, 0, _(b"hidden takes no arguments"))
1480 getargs(x, 0, 0, _(b"hidden takes no arguments"))
1468 hiddenrevs = repoview.filterrevs(repo, b'visible')
1481 hiddenrevs = repoview.filterrevs(repo, b'visible')
1469 return subset & hiddenrevs
1482 return subset & hiddenrevs
1470
1483
1471
1484
1472 @predicate(b'keyword(string)', safe=True, weight=10)
1485 @predicate(b'keyword(string)', safe=True, weight=10)
1473 def keyword(repo, subset, x):
1486 def keyword(repo, subset, x):
1474 """Search commit message, user name, and names of changed files for
1487 """Search commit message, user name, and names of changed files for
1475 string. The match is case-insensitive.
1488 string. The match is case-insensitive.
1476
1489
1477 For a regular expression or case sensitive search of these fields, use
1490 For a regular expression or case sensitive search of these fields, use
1478 ``grep(regex)``.
1491 ``grep(regex)``.
1479 """
1492 """
1480 # i18n: "keyword" is a keyword
1493 # i18n: "keyword" is a keyword
1481 kw = encoding.lower(getstring(x, _(b"keyword requires a string")))
1494 kw = encoding.lower(getstring(x, _(b"keyword requires a string")))
1482
1495
1483 def matches(r):
1496 def matches(r):
1484 c = repo[r]
1497 c = repo[r]
1485 return any(
1498 return any(
1486 kw in encoding.lower(t)
1499 kw in encoding.lower(t)
1487 for t in c.files() + [c.user(), c.description()]
1500 for t in c.files() + [c.user(), c.description()]
1488 )
1501 )
1489
1502
1490 return subset.filter(matches, condrepr=(b'<keyword %r>', kw))
1503 return subset.filter(matches, condrepr=(b'<keyword %r>', kw))
1491
1504
1492
1505
1493 @predicate(b'limit(set[, n[, offset]])', safe=True, takeorder=True, weight=0)
1506 @predicate(b'limit(set[, n[, offset]])', safe=True, takeorder=True, weight=0)
1494 def limit(repo, subset, x, order):
1507 def limit(repo, subset, x, order):
1495 """First n members of set, defaulting to 1, starting from offset.
1508 """First n members of set, defaulting to 1, starting from offset.
1496 """
1509 """
1497 args = getargsdict(x, b'limit', b'set n offset')
1510 args = getargsdict(x, b'limit', b'set n offset')
1498 if b'set' not in args:
1511 if b'set' not in args:
1499 # i18n: "limit" is a keyword
1512 # i18n: "limit" is a keyword
1500 raise error.ParseError(_(b"limit requires one to three arguments"))
1513 raise error.ParseError(_(b"limit requires one to three arguments"))
1501 # i18n: "limit" is a keyword
1514 # i18n: "limit" is a keyword
1502 lim = getinteger(args.get(b'n'), _(b"limit expects a number"), default=1)
1515 lim = getinteger(args.get(b'n'), _(b"limit expects a number"), default=1)
1503 if lim < 0:
1516 if lim < 0:
1504 raise error.ParseError(_(b"negative number to select"))
1517 raise error.ParseError(_(b"negative number to select"))
1505 # i18n: "limit" is a keyword
1518 # i18n: "limit" is a keyword
1506 ofs = getinteger(
1519 ofs = getinteger(
1507 args.get(b'offset'), _(b"limit expects a number"), default=0
1520 args.get(b'offset'), _(b"limit expects a number"), default=0
1508 )
1521 )
1509 if ofs < 0:
1522 if ofs < 0:
1510 raise error.ParseError(_(b"negative offset"))
1523 raise error.ParseError(_(b"negative offset"))
1511 os = getset(repo, fullreposet(repo), args[b'set'])
1524 os = getset(repo, fullreposet(repo), args[b'set'])
1512 ls = os.slice(ofs, ofs + lim)
1525 ls = os.slice(ofs, ofs + lim)
1513 if order == followorder and lim > 1:
1526 if order == followorder and lim > 1:
1514 return subset & ls
1527 return subset & ls
1515 return ls & subset
1528 return ls & subset
1516
1529
1517
1530
1518 @predicate(b'last(set, [n])', safe=True, takeorder=True)
1531 @predicate(b'last(set, [n])', safe=True, takeorder=True)
1519 def last(repo, subset, x, order):
1532 def last(repo, subset, x, order):
1520 """Last n members of set, defaulting to 1.
1533 """Last n members of set, defaulting to 1.
1521 """
1534 """
1522 # i18n: "last" is a keyword
1535 # i18n: "last" is a keyword
1523 l = getargs(x, 1, 2, _(b"last requires one or two arguments"))
1536 l = getargs(x, 1, 2, _(b"last requires one or two arguments"))
1524 lim = 1
1537 lim = 1
1525 if len(l) == 2:
1538 if len(l) == 2:
1526 # i18n: "last" is a keyword
1539 # i18n: "last" is a keyword
1527 lim = getinteger(l[1], _(b"last expects a number"))
1540 lim = getinteger(l[1], _(b"last expects a number"))
1528 if lim < 0:
1541 if lim < 0:
1529 raise error.ParseError(_(b"negative number to select"))
1542 raise error.ParseError(_(b"negative number to select"))
1530 os = getset(repo, fullreposet(repo), l[0])
1543 os = getset(repo, fullreposet(repo), l[0])
1531 os.reverse()
1544 os.reverse()
1532 ls = os.slice(0, lim)
1545 ls = os.slice(0, lim)
1533 if order == followorder and lim > 1:
1546 if order == followorder and lim > 1:
1534 return subset & ls
1547 return subset & ls
1535 ls.reverse()
1548 ls.reverse()
1536 return ls & subset
1549 return ls & subset
1537
1550
1538
1551
1539 @predicate(b'max(set)', safe=True)
1552 @predicate(b'max(set)', safe=True)
1540 def maxrev(repo, subset, x):
1553 def maxrev(repo, subset, x):
1541 """Changeset with highest revision number in set.
1554 """Changeset with highest revision number in set.
1542 """
1555 """
1543 os = getset(repo, fullreposet(repo), x)
1556 os = getset(repo, fullreposet(repo), x)
1544 try:
1557 try:
1545 m = os.max()
1558 m = os.max()
1546 if m in subset:
1559 if m in subset:
1547 return baseset([m], datarepr=(b'<max %r, %r>', subset, os))
1560 return baseset([m], datarepr=(b'<max %r, %r>', subset, os))
1548 except ValueError:
1561 except ValueError:
1549 # os.max() throws a ValueError when the collection is empty.
1562 # os.max() throws a ValueError when the collection is empty.
1550 # Same as python's max().
1563 # Same as python's max().
1551 pass
1564 pass
1552 return baseset(datarepr=(b'<max %r, %r>', subset, os))
1565 return baseset(datarepr=(b'<max %r, %r>', subset, os))
1553
1566
1554
1567
1555 @predicate(b'merge()', safe=True)
1568 @predicate(b'merge()', safe=True)
1556 def merge(repo, subset, x):
1569 def merge(repo, subset, x):
1557 """Changeset is a merge changeset.
1570 """Changeset is a merge changeset.
1558 """
1571 """
1559 # i18n: "merge" is a keyword
1572 # i18n: "merge" is a keyword
1560 getargs(x, 0, 0, _(b"merge takes no arguments"))
1573 getargs(x, 0, 0, _(b"merge takes no arguments"))
1561 cl = repo.changelog
1574 cl = repo.changelog
1562 nullrev = node.nullrev
1575 nullrev = node.nullrev
1563
1576
1564 def ismerge(r):
1577 def ismerge(r):
1565 try:
1578 try:
1566 return cl.parentrevs(r)[1] != nullrev
1579 return cl.parentrevs(r)[1] != nullrev
1567 except error.WdirUnsupported:
1580 except error.WdirUnsupported:
1568 return bool(repo[r].p2())
1581 return bool(repo[r].p2())
1569
1582
1570 return subset.filter(ismerge, condrepr=b'<merge>')
1583 return subset.filter(ismerge, condrepr=b'<merge>')
1571
1584
1572
1585
1573 @predicate(b'branchpoint()', safe=True)
1586 @predicate(b'branchpoint()', safe=True)
1574 def branchpoint(repo, subset, x):
1587 def branchpoint(repo, subset, x):
1575 """Changesets with more than one child.
1588 """Changesets with more than one child.
1576 """
1589 """
1577 # i18n: "branchpoint" is a keyword
1590 # i18n: "branchpoint" is a keyword
1578 getargs(x, 0, 0, _(b"branchpoint takes no arguments"))
1591 getargs(x, 0, 0, _(b"branchpoint takes no arguments"))
1579 cl = repo.changelog
1592 cl = repo.changelog
1580 if not subset:
1593 if not subset:
1581 return baseset()
1594 return baseset()
1582 # XXX this should be 'parentset.min()' assuming 'parentset' is a smartset
1595 # XXX this should be 'parentset.min()' assuming 'parentset' is a smartset
1583 # (and if it is not, it should.)
1596 # (and if it is not, it should.)
1584 baserev = min(subset)
1597 baserev = min(subset)
1585 parentscount = [0] * (len(repo) - baserev)
1598 parentscount = [0] * (len(repo) - baserev)
1586 for r in cl.revs(start=baserev + 1):
1599 for r in cl.revs(start=baserev + 1):
1587 for p in cl.parentrevs(r):
1600 for p in cl.parentrevs(r):
1588 if p >= baserev:
1601 if p >= baserev:
1589 parentscount[p - baserev] += 1
1602 parentscount[p - baserev] += 1
1590 return subset.filter(
1603 return subset.filter(
1591 lambda r: parentscount[r - baserev] > 1, condrepr=b'<branchpoint>'
1604 lambda r: parentscount[r - baserev] > 1, condrepr=b'<branchpoint>'
1592 )
1605 )
1593
1606
1594
1607
1595 @predicate(b'min(set)', safe=True)
1608 @predicate(b'min(set)', safe=True)
1596 def minrev(repo, subset, x):
1609 def minrev(repo, subset, x):
1597 """Changeset with lowest revision number in set.
1610 """Changeset with lowest revision number in set.
1598 """
1611 """
1599 os = getset(repo, fullreposet(repo), x)
1612 os = getset(repo, fullreposet(repo), x)
1600 try:
1613 try:
1601 m = os.min()
1614 m = os.min()
1602 if m in subset:
1615 if m in subset:
1603 return baseset([m], datarepr=(b'<min %r, %r>', subset, os))
1616 return baseset([m], datarepr=(b'<min %r, %r>', subset, os))
1604 except ValueError:
1617 except ValueError:
1605 # os.min() throws a ValueError when the collection is empty.
1618 # os.min() throws a ValueError when the collection is empty.
1606 # Same as python's min().
1619 # Same as python's min().
1607 pass
1620 pass
1608 return baseset(datarepr=(b'<min %r, %r>', subset, os))
1621 return baseset(datarepr=(b'<min %r, %r>', subset, os))
1609
1622
1610
1623
1611 @predicate(b'modifies(pattern)', safe=True, weight=30)
1624 @predicate(b'modifies(pattern)', safe=True, weight=30)
1612 def modifies(repo, subset, x):
1625 def modifies(repo, subset, x):
1613 """Changesets modifying files matched by pattern.
1626 """Changesets modifying files matched by pattern.
1614
1627
1615 The pattern without explicit kind like ``glob:`` is expected to be
1628 The pattern without explicit kind like ``glob:`` is expected to be
1616 relative to the current directory and match against a file or a
1629 relative to the current directory and match against a file or a
1617 directory.
1630 directory.
1618 """
1631 """
1619 # i18n: "modifies" is a keyword
1632 # i18n: "modifies" is a keyword
1620 pat = getstring(x, _(b"modifies requires a pattern"))
1633 pat = getstring(x, _(b"modifies requires a pattern"))
1621 return checkstatus(repo, subset, pat, 0)
1634 return checkstatus(repo, subset, pat, 0)
1622
1635
1623
1636
1624 @predicate(b'named(namespace)')
1637 @predicate(b'named(namespace)')
1625 def named(repo, subset, x):
1638 def named(repo, subset, x):
1626 """The changesets in a given namespace.
1639 """The changesets in a given namespace.
1627
1640
1628 Pattern matching is supported for `namespace`. See
1641 Pattern matching is supported for `namespace`. See
1629 :hg:`help revisions.patterns`.
1642 :hg:`help revisions.patterns`.
1630 """
1643 """
1631 # i18n: "named" is a keyword
1644 # i18n: "named" is a keyword
1632 args = getargs(x, 1, 1, _(b'named requires a namespace argument'))
1645 args = getargs(x, 1, 1, _(b'named requires a namespace argument'))
1633
1646
1634 ns = getstring(
1647 ns = getstring(
1635 args[0],
1648 args[0],
1636 # i18n: "named" is a keyword
1649 # i18n: "named" is a keyword
1637 _(b'the argument to named must be a string'),
1650 _(b'the argument to named must be a string'),
1638 )
1651 )
1639 kind, pattern, matcher = stringutil.stringmatcher(ns)
1652 kind, pattern, matcher = stringutil.stringmatcher(ns)
1640 namespaces = set()
1653 namespaces = set()
1641 if kind == b'literal':
1654 if kind == b'literal':
1642 if pattern not in repo.names:
1655 if pattern not in repo.names:
1643 raise error.RepoLookupError(
1656 raise error.RepoLookupError(
1644 _(b"namespace '%s' does not exist") % ns
1657 _(b"namespace '%s' does not exist") % ns
1645 )
1658 )
1646 namespaces.add(repo.names[pattern])
1659 namespaces.add(repo.names[pattern])
1647 else:
1660 else:
1648 for name, ns in pycompat.iteritems(repo.names):
1661 for name, ns in pycompat.iteritems(repo.names):
1649 if matcher(name):
1662 if matcher(name):
1650 namespaces.add(ns)
1663 namespaces.add(ns)
1651
1664
1652 names = set()
1665 names = set()
1653 for ns in namespaces:
1666 for ns in namespaces:
1654 for name in ns.listnames(repo):
1667 for name in ns.listnames(repo):
1655 if name not in ns.deprecated:
1668 if name not in ns.deprecated:
1656 names.update(repo[n].rev() for n in ns.nodes(repo, name))
1669 names.update(repo[n].rev() for n in ns.nodes(repo, name))
1657
1670
1658 names -= {node.nullrev}
1671 names -= {node.nullrev}
1659 return subset & names
1672 return subset & names
1660
1673
1661
1674
1662 @predicate(b'id(string)', safe=True)
1675 @predicate(b'id(string)', safe=True)
1663 def node_(repo, subset, x):
1676 def node_(repo, subset, x):
1664 """Revision non-ambiguously specified by the given hex string prefix.
1677 """Revision non-ambiguously specified by the given hex string prefix.
1665 """
1678 """
1666 # i18n: "id" is a keyword
1679 # i18n: "id" is a keyword
1667 l = getargs(x, 1, 1, _(b"id requires one argument"))
1680 l = getargs(x, 1, 1, _(b"id requires one argument"))
1668 # i18n: "id" is a keyword
1681 # i18n: "id" is a keyword
1669 n = getstring(l[0], _(b"id requires a string"))
1682 n = getstring(l[0], _(b"id requires a string"))
1670 if len(n) == 40:
1683 if len(n) == 40:
1671 try:
1684 try:
1672 rn = repo.changelog.rev(node.bin(n))
1685 rn = repo.changelog.rev(node.bin(n))
1673 except error.WdirUnsupported:
1686 except error.WdirUnsupported:
1674 rn = node.wdirrev
1687 rn = node.wdirrev
1675 except (LookupError, TypeError):
1688 except (LookupError, TypeError):
1676 rn = None
1689 rn = None
1677 else:
1690 else:
1678 rn = None
1691 rn = None
1679 try:
1692 try:
1680 pm = scmutil.resolvehexnodeidprefix(repo, n)
1693 pm = scmutil.resolvehexnodeidprefix(repo, n)
1681 if pm is not None:
1694 if pm is not None:
1682 rn = repo.changelog.rev(pm)
1695 rn = repo.changelog.rev(pm)
1683 except LookupError:
1696 except LookupError:
1684 pass
1697 pass
1685 except error.WdirUnsupported:
1698 except error.WdirUnsupported:
1686 rn = node.wdirrev
1699 rn = node.wdirrev
1687
1700
1688 if rn is None:
1701 if rn is None:
1689 return baseset()
1702 return baseset()
1690 result = baseset([rn])
1703 result = baseset([rn])
1691 return result & subset
1704 return result & subset
1692
1705
1693
1706
1694 @predicate(b'none()', safe=True)
1707 @predicate(b'none()', safe=True)
1695 def none(repo, subset, x):
1708 def none(repo, subset, x):
1696 """No changesets.
1709 """No changesets.
1697 """
1710 """
1698 # i18n: "none" is a keyword
1711 # i18n: "none" is a keyword
1699 getargs(x, 0, 0, _(b"none takes no arguments"))
1712 getargs(x, 0, 0, _(b"none takes no arguments"))
1700 return baseset()
1713 return baseset()
1701
1714
1702
1715
1703 @predicate(b'obsolete()', safe=True)
1716 @predicate(b'obsolete()', safe=True)
1704 def obsolete(repo, subset, x):
1717 def obsolete(repo, subset, x):
1705 """Mutable changeset with a newer version. (EXPERIMENTAL)"""
1718 """Mutable changeset with a newer version. (EXPERIMENTAL)"""
1706 # i18n: "obsolete" is a keyword
1719 # i18n: "obsolete" is a keyword
1707 getargs(x, 0, 0, _(b"obsolete takes no arguments"))
1720 getargs(x, 0, 0, _(b"obsolete takes no arguments"))
1708 obsoletes = obsmod.getrevs(repo, b'obsolete')
1721 obsoletes = obsmod.getrevs(repo, b'obsolete')
1709 return subset & obsoletes
1722 return subset & obsoletes
1710
1723
1711
1724
1712 @predicate(b'only(set, [set])', safe=True)
1725 @predicate(b'only(set, [set])', safe=True)
1713 def only(repo, subset, x):
1726 def only(repo, subset, x):
1714 """Changesets that are ancestors of the first set that are not ancestors
1727 """Changesets that are ancestors of the first set that are not ancestors
1715 of any other head in the repo. If a second set is specified, the result
1728 of any other head in the repo. If a second set is specified, the result
1716 is ancestors of the first set that are not ancestors of the second set
1729 is ancestors of the first set that are not ancestors of the second set
1717 (i.e. ::<set1> - ::<set2>).
1730 (i.e. ::<set1> - ::<set2>).
1718 """
1731 """
1719 cl = repo.changelog
1732 cl = repo.changelog
1720 # i18n: "only" is a keyword
1733 # i18n: "only" is a keyword
1721 args = getargs(x, 1, 2, _(b'only takes one or two arguments'))
1734 args = getargs(x, 1, 2, _(b'only takes one or two arguments'))
1722 include = getset(repo, fullreposet(repo), args[0])
1735 include = getset(repo, fullreposet(repo), args[0])
1723 if len(args) == 1:
1736 if len(args) == 1:
1724 if not include:
1737 if not include:
1725 return baseset()
1738 return baseset()
1726
1739
1727 descendants = set(dagop.revdescendants(repo, include, False))
1740 descendants = set(dagop.revdescendants(repo, include, False))
1728 exclude = [
1741 exclude = [
1729 rev
1742 rev
1730 for rev in cl.headrevs()
1743 for rev in cl.headrevs()
1731 if not rev in descendants and not rev in include
1744 if not rev in descendants and not rev in include
1732 ]
1745 ]
1733 else:
1746 else:
1734 exclude = getset(repo, fullreposet(repo), args[1])
1747 exclude = getset(repo, fullreposet(repo), args[1])
1735
1748
1736 results = set(cl.findmissingrevs(common=exclude, heads=include))
1749 results = set(cl.findmissingrevs(common=exclude, heads=include))
1737 # XXX we should turn this into a baseset instead of a set, smartset may do
1750 # XXX we should turn this into a baseset instead of a set, smartset may do
1738 # some optimizations from the fact this is a baseset.
1751 # some optimizations from the fact this is a baseset.
1739 return subset & results
1752 return subset & results
1740
1753
1741
1754
1742 @predicate(b'origin([set])', safe=True)
1755 @predicate(b'origin([set])', safe=True)
1743 def origin(repo, subset, x):
1756 def origin(repo, subset, x):
1744 """
1757 """
1745 Changesets that were specified as a source for the grafts, transplants or
1758 Changesets that were specified as a source for the grafts, transplants or
1746 rebases that created the given revisions. Omitting the optional set is the
1759 rebases that created the given revisions. Omitting the optional set is the
1747 same as passing all(). If a changeset created by these operations is itself
1760 same as passing all(). If a changeset created by these operations is itself
1748 specified as a source for one of these operations, only the source changeset
1761 specified as a source for one of these operations, only the source changeset
1749 for the first operation is selected.
1762 for the first operation is selected.
1750 """
1763 """
1751 if x is not None:
1764 if x is not None:
1752 dests = getset(repo, fullreposet(repo), x)
1765 dests = getset(repo, fullreposet(repo), x)
1753 else:
1766 else:
1754 dests = fullreposet(repo)
1767 dests = fullreposet(repo)
1755
1768
1756 def _firstsrc(rev):
1769 def _firstsrc(rev):
1757 src = _getrevsource(repo, rev)
1770 src = _getrevsource(repo, rev)
1758 if src is None:
1771 if src is None:
1759 return None
1772 return None
1760
1773
1761 while True:
1774 while True:
1762 prev = _getrevsource(repo, src)
1775 prev = _getrevsource(repo, src)
1763
1776
1764 if prev is None:
1777 if prev is None:
1765 return src
1778 return src
1766 src = prev
1779 src = prev
1767
1780
1768 o = {_firstsrc(r) for r in dests}
1781 o = {_firstsrc(r) for r in dests}
1769 o -= {None}
1782 o -= {None}
1770 # XXX we should turn this into a baseset instead of a set, smartset may do
1783 # XXX we should turn this into a baseset instead of a set, smartset may do
1771 # some optimizations from the fact this is a baseset.
1784 # some optimizations from the fact this is a baseset.
1772 return subset & o
1785 return subset & o
1773
1786
1774
1787
1775 @predicate(b'outgoing([path])', safe=False, weight=10)
1788 @predicate(b'outgoing([path])', safe=False, weight=10)
1776 def outgoing(repo, subset, x):
1789 def outgoing(repo, subset, x):
1777 """Changesets not found in the specified destination repository, or the
1790 """Changesets not found in the specified destination repository, or the
1778 default push location.
1791 default push location.
1779 """
1792 """
1780 # Avoid cycles.
1793 # Avoid cycles.
1781 from . import (
1794 from . import (
1782 discovery,
1795 discovery,
1783 hg,
1796 hg,
1784 )
1797 )
1785
1798
1786 # i18n: "outgoing" is a keyword
1799 # i18n: "outgoing" is a keyword
1787 l = getargs(x, 0, 1, _(b"outgoing takes one or no arguments"))
1800 l = getargs(x, 0, 1, _(b"outgoing takes one or no arguments"))
1788 # i18n: "outgoing" is a keyword
1801 # i18n: "outgoing" is a keyword
1789 dest = (
1802 dest = (
1790 l and getstring(l[0], _(b"outgoing requires a repository path")) or b''
1803 l and getstring(l[0], _(b"outgoing requires a repository path")) or b''
1791 )
1804 )
1792 if not dest:
1805 if not dest:
1793 # ui.paths.getpath() explicitly tests for None, not just a boolean
1806 # ui.paths.getpath() explicitly tests for None, not just a boolean
1794 dest = None
1807 dest = None
1795 path = repo.ui.paths.getpath(dest, default=(b'default-push', b'default'))
1808 path = repo.ui.paths.getpath(dest, default=(b'default-push', b'default'))
1796 if not path:
1809 if not path:
1797 raise error.Abort(
1810 raise error.Abort(
1798 _(b'default repository not configured!'),
1811 _(b'default repository not configured!'),
1799 hint=_(b"see 'hg help config.paths'"),
1812 hint=_(b"see 'hg help config.paths'"),
1800 )
1813 )
1801 dest = path.pushloc or path.loc
1814 dest = path.pushloc or path.loc
1802 branches = path.branch, []
1815 branches = path.branch, []
1803
1816
1804 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1817 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1805 if revs:
1818 if revs:
1806 revs = [repo.lookup(rev) for rev in revs]
1819 revs = [repo.lookup(rev) for rev in revs]
1807 other = hg.peer(repo, {}, dest)
1820 other = hg.peer(repo, {}, dest)
1808 repo.ui.pushbuffer()
1821 repo.ui.pushbuffer()
1809 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs)
1822 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs)
1810 repo.ui.popbuffer()
1823 repo.ui.popbuffer()
1811 cl = repo.changelog
1824 cl = repo.changelog
1812 o = {cl.rev(r) for r in outgoing.missing}
1825 o = {cl.rev(r) for r in outgoing.missing}
1813 return subset & o
1826 return subset & o
1814
1827
1815
1828
1816 @predicate(b'p1([set])', safe=True)
1829 @predicate(b'p1([set])', safe=True)
1817 def p1(repo, subset, x):
1830 def p1(repo, subset, x):
1818 """First parent of changesets in set, or the working directory.
1831 """First parent of changesets in set, or the working directory.
1819 """
1832 """
1820 if x is None:
1833 if x is None:
1821 p = repo[x].p1().rev()
1834 p = repo[x].p1().rev()
1822 if p >= 0:
1835 if p >= 0:
1823 return subset & baseset([p])
1836 return subset & baseset([p])
1824 return baseset()
1837 return baseset()
1825
1838
1826 ps = set()
1839 ps = set()
1827 cl = repo.changelog
1840 cl = repo.changelog
1828 for r in getset(repo, fullreposet(repo), x):
1841 for r in getset(repo, fullreposet(repo), x):
1829 try:
1842 try:
1830 ps.add(cl.parentrevs(r)[0])
1843 ps.add(cl.parentrevs(r)[0])
1831 except error.WdirUnsupported:
1844 except error.WdirUnsupported:
1832 ps.add(repo[r].p1().rev())
1845 ps.add(repo[r].p1().rev())
1833 ps -= {node.nullrev}
1846 ps -= {node.nullrev}
1834 # XXX we should turn this into a baseset instead of a set, smartset may do
1847 # XXX we should turn this into a baseset instead of a set, smartset may do
1835 # some optimizations from the fact this is a baseset.
1848 # some optimizations from the fact this is a baseset.
1836 return subset & ps
1849 return subset & ps
1837
1850
1838
1851
1839 @predicate(b'p2([set])', safe=True)
1852 @predicate(b'p2([set])', safe=True)
1840 def p2(repo, subset, x):
1853 def p2(repo, subset, x):
1841 """Second parent of changesets in set, or the working directory.
1854 """Second parent of changesets in set, or the working directory.
1842 """
1855 """
1843 if x is None:
1856 if x is None:
1844 ps = repo[x].parents()
1857 ps = repo[x].parents()
1845 try:
1858 try:
1846 p = ps[1].rev()
1859 p = ps[1].rev()
1847 if p >= 0:
1860 if p >= 0:
1848 return subset & baseset([p])
1861 return subset & baseset([p])
1849 return baseset()
1862 return baseset()
1850 except IndexError:
1863 except IndexError:
1851 return baseset()
1864 return baseset()
1852
1865
1853 ps = set()
1866 ps = set()
1854 cl = repo.changelog
1867 cl = repo.changelog
1855 for r in getset(repo, fullreposet(repo), x):
1868 for r in getset(repo, fullreposet(repo), x):
1856 try:
1869 try:
1857 ps.add(cl.parentrevs(r)[1])
1870 ps.add(cl.parentrevs(r)[1])
1858 except error.WdirUnsupported:
1871 except error.WdirUnsupported:
1859 parents = repo[r].parents()
1872 parents = repo[r].parents()
1860 if len(parents) == 2:
1873 if len(parents) == 2:
1861 ps.add(parents[1])
1874 ps.add(parents[1])
1862 ps -= {node.nullrev}
1875 ps -= {node.nullrev}
1863 # XXX we should turn this into a baseset instead of a set, smartset may do
1876 # XXX we should turn this into a baseset instead of a set, smartset may do
1864 # some optimizations from the fact this is a baseset.
1877 # some optimizations from the fact this is a baseset.
1865 return subset & ps
1878 return subset & ps
1866
1879
1867
1880
1868 def parentpost(repo, subset, x, order):
1881 def parentpost(repo, subset, x, order):
1869 return p1(repo, subset, x)
1882 return p1(repo, subset, x)
1870
1883
1871
1884
1872 @predicate(b'parents([set])', safe=True)
1885 @predicate(b'parents([set])', safe=True)
1873 def parents(repo, subset, x):
1886 def parents(repo, subset, x):
1874 """
1887 """
1875 The set of all parents for all changesets in set, or the working directory.
1888 The set of all parents for all changesets in set, or the working directory.
1876 """
1889 """
1877 if x is None:
1890 if x is None:
1878 ps = {p.rev() for p in repo[x].parents()}
1891 ps = {p.rev() for p in repo[x].parents()}
1879 else:
1892 else:
1880 ps = set()
1893 ps = set()
1881 cl = repo.changelog
1894 cl = repo.changelog
1882 up = ps.update
1895 up = ps.update
1883 parentrevs = cl.parentrevs
1896 parentrevs = cl.parentrevs
1884 for r in getset(repo, fullreposet(repo), x):
1897 for r in getset(repo, fullreposet(repo), x):
1885 try:
1898 try:
1886 up(parentrevs(r))
1899 up(parentrevs(r))
1887 except error.WdirUnsupported:
1900 except error.WdirUnsupported:
1888 up(p.rev() for p in repo[r].parents())
1901 up(p.rev() for p in repo[r].parents())
1889 ps -= {node.nullrev}
1902 ps -= {node.nullrev}
1890 return subset & ps
1903 return subset & ps
1891
1904
1892
1905
1893 def _phase(repo, subset, *targets):
1906 def _phase(repo, subset, *targets):
1894 """helper to select all rev in <targets> phases"""
1907 """helper to select all rev in <targets> phases"""
1895 return repo._phasecache.getrevset(repo, targets, subset)
1908 return repo._phasecache.getrevset(repo, targets, subset)
1896
1909
1897
1910
1898 @predicate(b'_phase(idx)', safe=True)
1911 @predicate(b'_phase(idx)', safe=True)
1899 def phase(repo, subset, x):
1912 def phase(repo, subset, x):
1900 l = getargs(x, 1, 1, b"_phase requires one argument")
1913 l = getargs(x, 1, 1, b"_phase requires one argument")
1901 target = getinteger(l[0], b"_phase expects a number")
1914 target = getinteger(l[0], b"_phase expects a number")
1902 return _phase(repo, subset, target)
1915 return _phase(repo, subset, target)
1903
1916
1904
1917
1905 @predicate(b'draft()', safe=True)
1918 @predicate(b'draft()', safe=True)
1906 def draft(repo, subset, x):
1919 def draft(repo, subset, x):
1907 """Changeset in draft phase."""
1920 """Changeset in draft phase."""
1908 # i18n: "draft" is a keyword
1921 # i18n: "draft" is a keyword
1909 getargs(x, 0, 0, _(b"draft takes no arguments"))
1922 getargs(x, 0, 0, _(b"draft takes no arguments"))
1910 target = phases.draft
1923 target = phases.draft
1911 return _phase(repo, subset, target)
1924 return _phase(repo, subset, target)
1912
1925
1913
1926
1914 @predicate(b'secret()', safe=True)
1927 @predicate(b'secret()', safe=True)
1915 def secret(repo, subset, x):
1928 def secret(repo, subset, x):
1916 """Changeset in secret phase."""
1929 """Changeset in secret phase."""
1917 # i18n: "secret" is a keyword
1930 # i18n: "secret" is a keyword
1918 getargs(x, 0, 0, _(b"secret takes no arguments"))
1931 getargs(x, 0, 0, _(b"secret takes no arguments"))
1919 target = phases.secret
1932 target = phases.secret
1920 return _phase(repo, subset, target)
1933 return _phase(repo, subset, target)
1921
1934
1922
1935
1923 @predicate(b'stack([revs])', safe=True)
1936 @predicate(b'stack([revs])', safe=True)
1924 def stack(repo, subset, x):
1937 def stack(repo, subset, x):
1925 """Experimental revset for the stack of changesets or working directory
1938 """Experimental revset for the stack of changesets or working directory
1926 parent. (EXPERIMENTAL)
1939 parent. (EXPERIMENTAL)
1927 """
1940 """
1928 if x is None:
1941 if x is None:
1929 stacks = stackmod.getstack(repo)
1942 stacks = stackmod.getstack(repo)
1930 else:
1943 else:
1931 stacks = smartset.baseset([])
1944 stacks = smartset.baseset([])
1932 for revision in getset(repo, fullreposet(repo), x):
1945 for revision in getset(repo, fullreposet(repo), x):
1933 currentstack = stackmod.getstack(repo, revision)
1946 currentstack = stackmod.getstack(repo, revision)
1934 stacks = stacks + currentstack
1947 stacks = stacks + currentstack
1935
1948
1936 return subset & stacks
1949 return subset & stacks
1937
1950
1938
1951
1939 def parentspec(repo, subset, x, n, order):
1952 def parentspec(repo, subset, x, n, order):
1940 """``set^0``
1953 """``set^0``
1941 The set.
1954 The set.
1942 ``set^1`` (or ``set^``), ``set^2``
1955 ``set^1`` (or ``set^``), ``set^2``
1943 First or second parent, respectively, of all changesets in set.
1956 First or second parent, respectively, of all changesets in set.
1944 """
1957 """
1945 try:
1958 try:
1946 n = int(n[1])
1959 n = int(n[1])
1947 if n not in (0, 1, 2):
1960 if n not in (0, 1, 2):
1948 raise ValueError
1961 raise ValueError
1949 except (TypeError, ValueError):
1962 except (TypeError, ValueError):
1950 raise error.ParseError(_(b"^ expects a number 0, 1, or 2"))
1963 raise error.ParseError(_(b"^ expects a number 0, 1, or 2"))
1951 ps = set()
1964 ps = set()
1952 cl = repo.changelog
1965 cl = repo.changelog
1953 for r in getset(repo, fullreposet(repo), x):
1966 for r in getset(repo, fullreposet(repo), x):
1954 if n == 0:
1967 if n == 0:
1955 ps.add(r)
1968 ps.add(r)
1956 elif n == 1:
1969 elif n == 1:
1957 try:
1970 try:
1958 ps.add(cl.parentrevs(r)[0])
1971 ps.add(cl.parentrevs(r)[0])
1959 except error.WdirUnsupported:
1972 except error.WdirUnsupported:
1960 ps.add(repo[r].p1().rev())
1973 ps.add(repo[r].p1().rev())
1961 else:
1974 else:
1962 try:
1975 try:
1963 parents = cl.parentrevs(r)
1976 parents = cl.parentrevs(r)
1964 if parents[1] != node.nullrev:
1977 if parents[1] != node.nullrev:
1965 ps.add(parents[1])
1978 ps.add(parents[1])
1966 except error.WdirUnsupported:
1979 except error.WdirUnsupported:
1967 parents = repo[r].parents()
1980 parents = repo[r].parents()
1968 if len(parents) == 2:
1981 if len(parents) == 2:
1969 ps.add(parents[1].rev())
1982 ps.add(parents[1].rev())
1970 return subset & ps
1983 return subset & ps
1971
1984
1972
1985
1973 @predicate(b'present(set)', safe=True, takeorder=True)
1986 @predicate(b'present(set)', safe=True, takeorder=True)
1974 def present(repo, subset, x, order):
1987 def present(repo, subset, x, order):
1975 """An empty set, if any revision in set isn't found; otherwise,
1988 """An empty set, if any revision in set isn't found; otherwise,
1976 all revisions in set.
1989 all revisions in set.
1977
1990
1978 If any of specified revisions is not present in the local repository,
1991 If any of specified revisions is not present in the local repository,
1979 the query is normally aborted. But this predicate allows the query
1992 the query is normally aborted. But this predicate allows the query
1980 to continue even in such cases.
1993 to continue even in such cases.
1981 """
1994 """
1982 try:
1995 try:
1983 return getset(repo, subset, x, order)
1996 return getset(repo, subset, x, order)
1984 except error.RepoLookupError:
1997 except error.RepoLookupError:
1985 return baseset()
1998 return baseset()
1986
1999
1987
2000
1988 # for internal use
2001 # for internal use
1989 @predicate(b'_notpublic', safe=True)
2002 @predicate(b'_notpublic', safe=True)
1990 def _notpublic(repo, subset, x):
2003 def _notpublic(repo, subset, x):
1991 getargs(x, 0, 0, b"_notpublic takes no arguments")
2004 getargs(x, 0, 0, b"_notpublic takes no arguments")
1992 return _phase(repo, subset, phases.draft, phases.secret)
2005 return _phase(repo, subset, phases.draft, phases.secret)
1993
2006
1994
2007
1995 # for internal use
2008 # for internal use
1996 @predicate(b'_phaseandancestors(phasename, set)', safe=True)
2009 @predicate(b'_phaseandancestors(phasename, set)', safe=True)
1997 def _phaseandancestors(repo, subset, x):
2010 def _phaseandancestors(repo, subset, x):
1998 # equivalent to (phasename() & ancestors(set)) but more efficient
2011 # equivalent to (phasename() & ancestors(set)) but more efficient
1999 # phasename could be one of 'draft', 'secret', or '_notpublic'
2012 # phasename could be one of 'draft', 'secret', or '_notpublic'
2000 args = getargs(x, 2, 2, b"_phaseandancestors requires two arguments")
2013 args = getargs(x, 2, 2, b"_phaseandancestors requires two arguments")
2001 phasename = getsymbol(args[0])
2014 phasename = getsymbol(args[0])
2002 s = getset(repo, fullreposet(repo), args[1])
2015 s = getset(repo, fullreposet(repo), args[1])
2003
2016
2004 draft = phases.draft
2017 draft = phases.draft
2005 secret = phases.secret
2018 secret = phases.secret
2006 phasenamemap = {
2019 phasenamemap = {
2007 b'_notpublic': draft,
2020 b'_notpublic': draft,
2008 b'draft': draft, # follow secret's ancestors
2021 b'draft': draft, # follow secret's ancestors
2009 b'secret': secret,
2022 b'secret': secret,
2010 }
2023 }
2011 if phasename not in phasenamemap:
2024 if phasename not in phasenamemap:
2012 raise error.ParseError(b'%r is not a valid phasename' % phasename)
2025 raise error.ParseError(b'%r is not a valid phasename' % phasename)
2013
2026
2014 minimalphase = phasenamemap[phasename]
2027 minimalphase = phasenamemap[phasename]
2015 getphase = repo._phasecache.phase
2028 getphase = repo._phasecache.phase
2016
2029
2017 def cutfunc(rev):
2030 def cutfunc(rev):
2018 return getphase(repo, rev) < minimalphase
2031 return getphase(repo, rev) < minimalphase
2019
2032
2020 revs = dagop.revancestors(repo, s, cutfunc=cutfunc)
2033 revs = dagop.revancestors(repo, s, cutfunc=cutfunc)
2021
2034
2022 if phasename == b'draft': # need to remove secret changesets
2035 if phasename == b'draft': # need to remove secret changesets
2023 revs = revs.filter(lambda r: getphase(repo, r) == draft)
2036 revs = revs.filter(lambda r: getphase(repo, r) == draft)
2024 return subset & revs
2037 return subset & revs
2025
2038
2026
2039
2027 @predicate(b'public()', safe=True)
2040 @predicate(b'public()', safe=True)
2028 def public(repo, subset, x):
2041 def public(repo, subset, x):
2029 """Changeset in public phase."""
2042 """Changeset in public phase."""
2030 # i18n: "public" is a keyword
2043 # i18n: "public" is a keyword
2031 getargs(x, 0, 0, _(b"public takes no arguments"))
2044 getargs(x, 0, 0, _(b"public takes no arguments"))
2032 return _phase(repo, subset, phases.public)
2045 return _phase(repo, subset, phases.public)
2033
2046
2034
2047
2035 @predicate(b'remote([id [,path]])', safe=False)
2048 @predicate(b'remote([id [,path]])', safe=False)
2036 def remote(repo, subset, x):
2049 def remote(repo, subset, x):
2037 """Local revision that corresponds to the given identifier in a
2050 """Local revision that corresponds to the given identifier in a
2038 remote repository, if present. Here, the '.' identifier is a
2051 remote repository, if present. Here, the '.' identifier is a
2039 synonym for the current local branch.
2052 synonym for the current local branch.
2040 """
2053 """
2041
2054
2042 from . import hg # avoid start-up nasties
2055 from . import hg # avoid start-up nasties
2043
2056
2044 # i18n: "remote" is a keyword
2057 # i18n: "remote" is a keyword
2045 l = getargs(x, 0, 2, _(b"remote takes zero, one, or two arguments"))
2058 l = getargs(x, 0, 2, _(b"remote takes zero, one, or two arguments"))
2046
2059
2047 q = b'.'
2060 q = b'.'
2048 if len(l) > 0:
2061 if len(l) > 0:
2049 # i18n: "remote" is a keyword
2062 # i18n: "remote" is a keyword
2050 q = getstring(l[0], _(b"remote requires a string id"))
2063 q = getstring(l[0], _(b"remote requires a string id"))
2051 if q == b'.':
2064 if q == b'.':
2052 q = repo[b'.'].branch()
2065 q = repo[b'.'].branch()
2053
2066
2054 dest = b''
2067 dest = b''
2055 if len(l) > 1:
2068 if len(l) > 1:
2056 # i18n: "remote" is a keyword
2069 # i18n: "remote" is a keyword
2057 dest = getstring(l[1], _(b"remote requires a repository path"))
2070 dest = getstring(l[1], _(b"remote requires a repository path"))
2058 dest = repo.ui.expandpath(dest or b'default')
2071 dest = repo.ui.expandpath(dest or b'default')
2059 dest, branches = hg.parseurl(dest)
2072 dest, branches = hg.parseurl(dest)
2060
2073
2061 other = hg.peer(repo, {}, dest)
2074 other = hg.peer(repo, {}, dest)
2062 n = other.lookup(q)
2075 n = other.lookup(q)
2063 if n in repo:
2076 if n in repo:
2064 r = repo[n].rev()
2077 r = repo[n].rev()
2065 if r in subset:
2078 if r in subset:
2066 return baseset([r])
2079 return baseset([r])
2067 return baseset()
2080 return baseset()
2068
2081
2069
2082
2070 @predicate(b'removes(pattern)', safe=True, weight=30)
2083 @predicate(b'removes(pattern)', safe=True, weight=30)
2071 def removes(repo, subset, x):
2084 def removes(repo, subset, x):
2072 """Changesets which remove files matching pattern.
2085 """Changesets which remove files matching pattern.
2073
2086
2074 The pattern without explicit kind like ``glob:`` is expected to be
2087 The pattern without explicit kind like ``glob:`` is expected to be
2075 relative to the current directory and match against a file or a
2088 relative to the current directory and match against a file or a
2076 directory.
2089 directory.
2077 """
2090 """
2078 # i18n: "removes" is a keyword
2091 # i18n: "removes" is a keyword
2079 pat = getstring(x, _(b"removes requires a pattern"))
2092 pat = getstring(x, _(b"removes requires a pattern"))
2080 return checkstatus(repo, subset, pat, 2)
2093 return checkstatus(repo, subset, pat, 2)
2081
2094
2082
2095
2083 @predicate(b'rev(number)', safe=True)
2096 @predicate(b'rev(number)', safe=True)
2084 def rev(repo, subset, x):
2097 def rev(repo, subset, x):
2085 """Revision with the given numeric identifier."""
2098 """Revision with the given numeric identifier."""
2086 try:
2099 try:
2087 return _rev(repo, subset, x)
2100 return _rev(repo, subset, x)
2088 except error.RepoLookupError:
2101 except error.RepoLookupError:
2089 return baseset()
2102 return baseset()
2090
2103
2091
2104
2092 @predicate(b'_rev(number)', safe=True)
2105 @predicate(b'_rev(number)', safe=True)
2093 def _rev(repo, subset, x):
2106 def _rev(repo, subset, x):
2094 # internal version of "rev(x)" that raise error if "x" is invalid
2107 # internal version of "rev(x)" that raise error if "x" is invalid
2095 # i18n: "rev" is a keyword
2108 # i18n: "rev" is a keyword
2096 l = getargs(x, 1, 1, _(b"rev requires one argument"))
2109 l = getargs(x, 1, 1, _(b"rev requires one argument"))
2097 try:
2110 try:
2098 # i18n: "rev" is a keyword
2111 # i18n: "rev" is a keyword
2099 l = int(getstring(l[0], _(b"rev requires a number")))
2112 l = int(getstring(l[0], _(b"rev requires a number")))
2100 except (TypeError, ValueError):
2113 except (TypeError, ValueError):
2101 # i18n: "rev" is a keyword
2114 # i18n: "rev" is a keyword
2102 raise error.ParseError(_(b"rev expects a number"))
2115 raise error.ParseError(_(b"rev expects a number"))
2103 if l not in _virtualrevs:
2116 if l not in _virtualrevs:
2104 try:
2117 try:
2105 repo.changelog.node(l) # check that the rev exists
2118 repo.changelog.node(l) # check that the rev exists
2106 except IndexError:
2119 except IndexError:
2107 raise error.RepoLookupError(_(b"unknown revision '%d'") % l)
2120 raise error.RepoLookupError(_(b"unknown revision '%d'") % l)
2108 return subset & baseset([l])
2121 return subset & baseset([l])
2109
2122
2110
2123
2111 @predicate(b'revset(set)', safe=True, takeorder=True)
2124 @predicate(b'revset(set)', safe=True, takeorder=True)
2112 def revsetpredicate(repo, subset, x, order):
2125 def revsetpredicate(repo, subset, x, order):
2113 """Strictly interpret the content as a revset.
2126 """Strictly interpret the content as a revset.
2114
2127
2115 The content of this special predicate will be strictly interpreted as a
2128 The content of this special predicate will be strictly interpreted as a
2116 revset. For example, ``revset(id(0))`` will be interpreted as "id(0)"
2129 revset. For example, ``revset(id(0))`` will be interpreted as "id(0)"
2117 without possible ambiguity with a "id(0)" bookmark or tag.
2130 without possible ambiguity with a "id(0)" bookmark or tag.
2118 """
2131 """
2119 return getset(repo, subset, x, order)
2132 return getset(repo, subset, x, order)
2120
2133
2121
2134
2122 @predicate(b'matching(revision [, field])', safe=True)
2135 @predicate(b'matching(revision [, field])', safe=True)
2123 def matching(repo, subset, x):
2136 def matching(repo, subset, x):
2124 """Changesets in which a given set of fields match the set of fields in the
2137 """Changesets in which a given set of fields match the set of fields in the
2125 selected revision or set.
2138 selected revision or set.
2126
2139
2127 To match more than one field pass the list of fields to match separated
2140 To match more than one field pass the list of fields to match separated
2128 by spaces (e.g. ``author description``).
2141 by spaces (e.g. ``author description``).
2129
2142
2130 Valid fields are most regular revision fields and some special fields.
2143 Valid fields are most regular revision fields and some special fields.
2131
2144
2132 Regular revision fields are ``description``, ``author``, ``branch``,
2145 Regular revision fields are ``description``, ``author``, ``branch``,
2133 ``date``, ``files``, ``phase``, ``parents``, ``substate``, ``user``
2146 ``date``, ``files``, ``phase``, ``parents``, ``substate``, ``user``
2134 and ``diff``.
2147 and ``diff``.
2135 Note that ``author`` and ``user`` are synonyms. ``diff`` refers to the
2148 Note that ``author`` and ``user`` are synonyms. ``diff`` refers to the
2136 contents of the revision. Two revisions matching their ``diff`` will
2149 contents of the revision. Two revisions matching their ``diff`` will
2137 also match their ``files``.
2150 also match their ``files``.
2138
2151
2139 Special fields are ``summary`` and ``metadata``:
2152 Special fields are ``summary`` and ``metadata``:
2140 ``summary`` matches the first line of the description.
2153 ``summary`` matches the first line of the description.
2141 ``metadata`` is equivalent to matching ``description user date``
2154 ``metadata`` is equivalent to matching ``description user date``
2142 (i.e. it matches the main metadata fields).
2155 (i.e. it matches the main metadata fields).
2143
2156
2144 ``metadata`` is the default field which is used when no fields are
2157 ``metadata`` is the default field which is used when no fields are
2145 specified. You can match more than one field at a time.
2158 specified. You can match more than one field at a time.
2146 """
2159 """
2147 # i18n: "matching" is a keyword
2160 # i18n: "matching" is a keyword
2148 l = getargs(x, 1, 2, _(b"matching takes 1 or 2 arguments"))
2161 l = getargs(x, 1, 2, _(b"matching takes 1 or 2 arguments"))
2149
2162
2150 revs = getset(repo, fullreposet(repo), l[0])
2163 revs = getset(repo, fullreposet(repo), l[0])
2151
2164
2152 fieldlist = [b'metadata']
2165 fieldlist = [b'metadata']
2153 if len(l) > 1:
2166 if len(l) > 1:
2154 fieldlist = getstring(
2167 fieldlist = getstring(
2155 l[1],
2168 l[1],
2156 # i18n: "matching" is a keyword
2169 # i18n: "matching" is a keyword
2157 _(b"matching requires a string as its second argument"),
2170 _(b"matching requires a string as its second argument"),
2158 ).split()
2171 ).split()
2159
2172
2160 # Make sure that there are no repeated fields,
2173 # Make sure that there are no repeated fields,
2161 # expand the 'special' 'metadata' field type
2174 # expand the 'special' 'metadata' field type
2162 # and check the 'files' whenever we check the 'diff'
2175 # and check the 'files' whenever we check the 'diff'
2163 fields = []
2176 fields = []
2164 for field in fieldlist:
2177 for field in fieldlist:
2165 if field == b'metadata':
2178 if field == b'metadata':
2166 fields += [b'user', b'description', b'date']
2179 fields += [b'user', b'description', b'date']
2167 elif field == b'diff':
2180 elif field == b'diff':
2168 # a revision matching the diff must also match the files
2181 # a revision matching the diff must also match the files
2169 # since matching the diff is very costly, make sure to
2182 # since matching the diff is very costly, make sure to
2170 # also match the files first
2183 # also match the files first
2171 fields += [b'files', b'diff']
2184 fields += [b'files', b'diff']
2172 else:
2185 else:
2173 if field == b'author':
2186 if field == b'author':
2174 field = b'user'
2187 field = b'user'
2175 fields.append(field)
2188 fields.append(field)
2176 fields = set(fields)
2189 fields = set(fields)
2177 if b'summary' in fields and b'description' in fields:
2190 if b'summary' in fields and b'description' in fields:
2178 # If a revision matches its description it also matches its summary
2191 # If a revision matches its description it also matches its summary
2179 fields.discard(b'summary')
2192 fields.discard(b'summary')
2180
2193
2181 # We may want to match more than one field
2194 # We may want to match more than one field
2182 # Not all fields take the same amount of time to be matched
2195 # Not all fields take the same amount of time to be matched
2183 # Sort the selected fields in order of increasing matching cost
2196 # Sort the selected fields in order of increasing matching cost
2184 fieldorder = [
2197 fieldorder = [
2185 b'phase',
2198 b'phase',
2186 b'parents',
2199 b'parents',
2187 b'user',
2200 b'user',
2188 b'date',
2201 b'date',
2189 b'branch',
2202 b'branch',
2190 b'summary',
2203 b'summary',
2191 b'files',
2204 b'files',
2192 b'description',
2205 b'description',
2193 b'substate',
2206 b'substate',
2194 b'diff',
2207 b'diff',
2195 ]
2208 ]
2196
2209
2197 def fieldkeyfunc(f):
2210 def fieldkeyfunc(f):
2198 try:
2211 try:
2199 return fieldorder.index(f)
2212 return fieldorder.index(f)
2200 except ValueError:
2213 except ValueError:
2201 # assume an unknown field is very costly
2214 # assume an unknown field is very costly
2202 return len(fieldorder)
2215 return len(fieldorder)
2203
2216
2204 fields = list(fields)
2217 fields = list(fields)
2205 fields.sort(key=fieldkeyfunc)
2218 fields.sort(key=fieldkeyfunc)
2206
2219
2207 # Each field will be matched with its own "getfield" function
2220 # Each field will be matched with its own "getfield" function
2208 # which will be added to the getfieldfuncs array of functions
2221 # which will be added to the getfieldfuncs array of functions
2209 getfieldfuncs = []
2222 getfieldfuncs = []
2210 _funcs = {
2223 _funcs = {
2211 b'user': lambda r: repo[r].user(),
2224 b'user': lambda r: repo[r].user(),
2212 b'branch': lambda r: repo[r].branch(),
2225 b'branch': lambda r: repo[r].branch(),
2213 b'date': lambda r: repo[r].date(),
2226 b'date': lambda r: repo[r].date(),
2214 b'description': lambda r: repo[r].description(),
2227 b'description': lambda r: repo[r].description(),
2215 b'files': lambda r: repo[r].files(),
2228 b'files': lambda r: repo[r].files(),
2216 b'parents': lambda r: repo[r].parents(),
2229 b'parents': lambda r: repo[r].parents(),
2217 b'phase': lambda r: repo[r].phase(),
2230 b'phase': lambda r: repo[r].phase(),
2218 b'substate': lambda r: repo[r].substate,
2231 b'substate': lambda r: repo[r].substate,
2219 b'summary': lambda r: repo[r].description().splitlines()[0],
2232 b'summary': lambda r: repo[r].description().splitlines()[0],
2220 b'diff': lambda r: list(
2233 b'diff': lambda r: list(
2221 repo[r].diff(opts=diffutil.diffallopts(repo.ui, {b'git': True}))
2234 repo[r].diff(opts=diffutil.diffallopts(repo.ui, {b'git': True}))
2222 ),
2235 ),
2223 }
2236 }
2224 for info in fields:
2237 for info in fields:
2225 getfield = _funcs.get(info, None)
2238 getfield = _funcs.get(info, None)
2226 if getfield is None:
2239 if getfield is None:
2227 raise error.ParseError(
2240 raise error.ParseError(
2228 # i18n: "matching" is a keyword
2241 # i18n: "matching" is a keyword
2229 _(b"unexpected field name passed to matching: %s")
2242 _(b"unexpected field name passed to matching: %s")
2230 % info
2243 % info
2231 )
2244 )
2232 getfieldfuncs.append(getfield)
2245 getfieldfuncs.append(getfield)
2233 # convert the getfield array of functions into a "getinfo" function
2246 # convert the getfield array of functions into a "getinfo" function
2234 # which returns an array of field values (or a single value if there
2247 # which returns an array of field values (or a single value if there
2235 # is only one field to match)
2248 # is only one field to match)
2236 getinfo = lambda r: [f(r) for f in getfieldfuncs]
2249 getinfo = lambda r: [f(r) for f in getfieldfuncs]
2237
2250
2238 def matches(x):
2251 def matches(x):
2239 for rev in revs:
2252 for rev in revs:
2240 target = getinfo(rev)
2253 target = getinfo(rev)
2241 match = True
2254 match = True
2242 for n, f in enumerate(getfieldfuncs):
2255 for n, f in enumerate(getfieldfuncs):
2243 if target[n] != f(x):
2256 if target[n] != f(x):
2244 match = False
2257 match = False
2245 if match:
2258 if match:
2246 return True
2259 return True
2247 return False
2260 return False
2248
2261
2249 return subset.filter(matches, condrepr=(b'<matching%r %r>', fields, revs))
2262 return subset.filter(matches, condrepr=(b'<matching%r %r>', fields, revs))
2250
2263
2251
2264
2252 @predicate(b'reverse(set)', safe=True, takeorder=True, weight=0)
2265 @predicate(b'reverse(set)', safe=True, takeorder=True, weight=0)
2253 def reverse(repo, subset, x, order):
2266 def reverse(repo, subset, x, order):
2254 """Reverse order of set.
2267 """Reverse order of set.
2255 """
2268 """
2256 l = getset(repo, subset, x, order)
2269 l = getset(repo, subset, x, order)
2257 if order == defineorder:
2270 if order == defineorder:
2258 l.reverse()
2271 l.reverse()
2259 return l
2272 return l
2260
2273
2261
2274
2262 @predicate(b'roots(set)', safe=True)
2275 @predicate(b'roots(set)', safe=True)
2263 def roots(repo, subset, x):
2276 def roots(repo, subset, x):
2264 """Changesets in set with no parent changeset in set.
2277 """Changesets in set with no parent changeset in set.
2265 """
2278 """
2266 s = getset(repo, fullreposet(repo), x)
2279 s = getset(repo, fullreposet(repo), x)
2267 parents = repo.changelog.parentrevs
2280 parents = repo.changelog.parentrevs
2268
2281
2269 def filter(r):
2282 def filter(r):
2270 for p in parents(r):
2283 for p in parents(r):
2271 if 0 <= p and p in s:
2284 if 0 <= p and p in s:
2272 return False
2285 return False
2273 return True
2286 return True
2274
2287
2275 return subset & s.filter(filter, condrepr=b'<roots>')
2288 return subset & s.filter(filter, condrepr=b'<roots>')
2276
2289
2277
2290
2278 _sortkeyfuncs = {
2291 _sortkeyfuncs = {
2279 b'rev': lambda c: c.rev(),
2292 b'rev': lambda c: c.rev(),
2280 b'branch': lambda c: c.branch(),
2293 b'branch': lambda c: c.branch(),
2281 b'desc': lambda c: c.description(),
2294 b'desc': lambda c: c.description(),
2282 b'user': lambda c: c.user(),
2295 b'user': lambda c: c.user(),
2283 b'author': lambda c: c.user(),
2296 b'author': lambda c: c.user(),
2284 b'date': lambda c: c.date()[0],
2297 b'date': lambda c: c.date()[0],
2285 }
2298 }
2286
2299
2287
2300
2288 def _getsortargs(x):
2301 def _getsortargs(x):
2289 """Parse sort options into (set, [(key, reverse)], opts)"""
2302 """Parse sort options into (set, [(key, reverse)], opts)"""
2290 args = getargsdict(x, b'sort', b'set keys topo.firstbranch')
2303 args = getargsdict(x, b'sort', b'set keys topo.firstbranch')
2291 if b'set' not in args:
2304 if b'set' not in args:
2292 # i18n: "sort" is a keyword
2305 # i18n: "sort" is a keyword
2293 raise error.ParseError(_(b'sort requires one or two arguments'))
2306 raise error.ParseError(_(b'sort requires one or two arguments'))
2294 keys = b"rev"
2307 keys = b"rev"
2295 if b'keys' in args:
2308 if b'keys' in args:
2296 # i18n: "sort" is a keyword
2309 # i18n: "sort" is a keyword
2297 keys = getstring(args[b'keys'], _(b"sort spec must be a string"))
2310 keys = getstring(args[b'keys'], _(b"sort spec must be a string"))
2298
2311
2299 keyflags = []
2312 keyflags = []
2300 for k in keys.split():
2313 for k in keys.split():
2301 fk = k
2314 fk = k
2302 reverse = k.startswith(b'-')
2315 reverse = k.startswith(b'-')
2303 if reverse:
2316 if reverse:
2304 k = k[1:]
2317 k = k[1:]
2305 if k not in _sortkeyfuncs and k != b'topo':
2318 if k not in _sortkeyfuncs and k != b'topo':
2306 raise error.ParseError(
2319 raise error.ParseError(
2307 _(b"unknown sort key %r") % pycompat.bytestr(fk)
2320 _(b"unknown sort key %r") % pycompat.bytestr(fk)
2308 )
2321 )
2309 keyflags.append((k, reverse))
2322 keyflags.append((k, reverse))
2310
2323
2311 if len(keyflags) > 1 and any(k == b'topo' for k, reverse in keyflags):
2324 if len(keyflags) > 1 and any(k == b'topo' for k, reverse in keyflags):
2312 # i18n: "topo" is a keyword
2325 # i18n: "topo" is a keyword
2313 raise error.ParseError(
2326 raise error.ParseError(
2314 _(b'topo sort order cannot be combined with other sort keys')
2327 _(b'topo sort order cannot be combined with other sort keys')
2315 )
2328 )
2316
2329
2317 opts = {}
2330 opts = {}
2318 if b'topo.firstbranch' in args:
2331 if b'topo.firstbranch' in args:
2319 if any(k == b'topo' for k, reverse in keyflags):
2332 if any(k == b'topo' for k, reverse in keyflags):
2320 opts[b'topo.firstbranch'] = args[b'topo.firstbranch']
2333 opts[b'topo.firstbranch'] = args[b'topo.firstbranch']
2321 else:
2334 else:
2322 # i18n: "topo" and "topo.firstbranch" are keywords
2335 # i18n: "topo" and "topo.firstbranch" are keywords
2323 raise error.ParseError(
2336 raise error.ParseError(
2324 _(
2337 _(
2325 b'topo.firstbranch can only be used '
2338 b'topo.firstbranch can only be used '
2326 b'when using the topo sort key'
2339 b'when using the topo sort key'
2327 )
2340 )
2328 )
2341 )
2329
2342
2330 return args[b'set'], keyflags, opts
2343 return args[b'set'], keyflags, opts
2331
2344
2332
2345
2333 @predicate(
2346 @predicate(
2334 b'sort(set[, [-]key... [, ...]])', safe=True, takeorder=True, weight=10
2347 b'sort(set[, [-]key... [, ...]])', safe=True, takeorder=True, weight=10
2335 )
2348 )
2336 def sort(repo, subset, x, order):
2349 def sort(repo, subset, x, order):
2337 """Sort set by keys. The default sort order is ascending, specify a key
2350 """Sort set by keys. The default sort order is ascending, specify a key
2338 as ``-key`` to sort in descending order.
2351 as ``-key`` to sort in descending order.
2339
2352
2340 The keys can be:
2353 The keys can be:
2341
2354
2342 - ``rev`` for the revision number,
2355 - ``rev`` for the revision number,
2343 - ``branch`` for the branch name,
2356 - ``branch`` for the branch name,
2344 - ``desc`` for the commit message (description),
2357 - ``desc`` for the commit message (description),
2345 - ``user`` for user name (``author`` can be used as an alias),
2358 - ``user`` for user name (``author`` can be used as an alias),
2346 - ``date`` for the commit date
2359 - ``date`` for the commit date
2347 - ``topo`` for a reverse topographical sort
2360 - ``topo`` for a reverse topographical sort
2348
2361
2349 The ``topo`` sort order cannot be combined with other sort keys. This sort
2362 The ``topo`` sort order cannot be combined with other sort keys. This sort
2350 takes one optional argument, ``topo.firstbranch``, which takes a revset that
2363 takes one optional argument, ``topo.firstbranch``, which takes a revset that
2351 specifies what topographical branches to prioritize in the sort.
2364 specifies what topographical branches to prioritize in the sort.
2352
2365
2353 """
2366 """
2354 s, keyflags, opts = _getsortargs(x)
2367 s, keyflags, opts = _getsortargs(x)
2355 revs = getset(repo, subset, s, order)
2368 revs = getset(repo, subset, s, order)
2356
2369
2357 if not keyflags or order != defineorder:
2370 if not keyflags or order != defineorder:
2358 return revs
2371 return revs
2359 if len(keyflags) == 1 and keyflags[0][0] == b"rev":
2372 if len(keyflags) == 1 and keyflags[0][0] == b"rev":
2360 revs.sort(reverse=keyflags[0][1])
2373 revs.sort(reverse=keyflags[0][1])
2361 return revs
2374 return revs
2362 elif keyflags[0][0] == b"topo":
2375 elif keyflags[0][0] == b"topo":
2363 firstbranch = ()
2376 firstbranch = ()
2364 if b'topo.firstbranch' in opts:
2377 if b'topo.firstbranch' in opts:
2365 firstbranch = getset(repo, subset, opts[b'topo.firstbranch'])
2378 firstbranch = getset(repo, subset, opts[b'topo.firstbranch'])
2366 revs = baseset(
2379 revs = baseset(
2367 dagop.toposort(revs, repo.changelog.parentrevs, firstbranch),
2380 dagop.toposort(revs, repo.changelog.parentrevs, firstbranch),
2368 istopo=True,
2381 istopo=True,
2369 )
2382 )
2370 if keyflags[0][1]:
2383 if keyflags[0][1]:
2371 revs.reverse()
2384 revs.reverse()
2372 return revs
2385 return revs
2373
2386
2374 # sort() is guaranteed to be stable
2387 # sort() is guaranteed to be stable
2375 ctxs = [repo[r] for r in revs]
2388 ctxs = [repo[r] for r in revs]
2376 for k, reverse in reversed(keyflags):
2389 for k, reverse in reversed(keyflags):
2377 ctxs.sort(key=_sortkeyfuncs[k], reverse=reverse)
2390 ctxs.sort(key=_sortkeyfuncs[k], reverse=reverse)
2378 return baseset([c.rev() for c in ctxs])
2391 return baseset([c.rev() for c in ctxs])
2379
2392
2380
2393
2381 @predicate(b'subrepo([pattern])')
2394 @predicate(b'subrepo([pattern])')
2382 def subrepo(repo, subset, x):
2395 def subrepo(repo, subset, x):
2383 """Changesets that add, modify or remove the given subrepo. If no subrepo
2396 """Changesets that add, modify or remove the given subrepo. If no subrepo
2384 pattern is named, any subrepo changes are returned.
2397 pattern is named, any subrepo changes are returned.
2385 """
2398 """
2386 # i18n: "subrepo" is a keyword
2399 # i18n: "subrepo" is a keyword
2387 args = getargs(x, 0, 1, _(b'subrepo takes at most one argument'))
2400 args = getargs(x, 0, 1, _(b'subrepo takes at most one argument'))
2388 pat = None
2401 pat = None
2389 if len(args) != 0:
2402 if len(args) != 0:
2390 pat = getstring(args[0], _(b"subrepo requires a pattern"))
2403 pat = getstring(args[0], _(b"subrepo requires a pattern"))
2391
2404
2392 m = matchmod.exact([b'.hgsubstate'])
2405 m = matchmod.exact([b'.hgsubstate'])
2393
2406
2394 def submatches(names):
2407 def submatches(names):
2395 k, p, m = stringutil.stringmatcher(pat)
2408 k, p, m = stringutil.stringmatcher(pat)
2396 for name in names:
2409 for name in names:
2397 if m(name):
2410 if m(name):
2398 yield name
2411 yield name
2399
2412
2400 def matches(x):
2413 def matches(x):
2401 c = repo[x]
2414 c = repo[x]
2402 s = repo.status(c.p1().node(), c.node(), match=m)
2415 s = repo.status(c.p1().node(), c.node(), match=m)
2403
2416
2404 if pat is None:
2417 if pat is None:
2405 return s.added or s.modified or s.removed
2418 return s.added or s.modified or s.removed
2406
2419
2407 if s.added:
2420 if s.added:
2408 return any(submatches(c.substate.keys()))
2421 return any(submatches(c.substate.keys()))
2409
2422
2410 if s.modified:
2423 if s.modified:
2411 subs = set(c.p1().substate.keys())
2424 subs = set(c.p1().substate.keys())
2412 subs.update(c.substate.keys())
2425 subs.update(c.substate.keys())
2413
2426
2414 for path in submatches(subs):
2427 for path in submatches(subs):
2415 if c.p1().substate.get(path) != c.substate.get(path):
2428 if c.p1().substate.get(path) != c.substate.get(path):
2416 return True
2429 return True
2417
2430
2418 if s.removed:
2431 if s.removed:
2419 return any(submatches(c.p1().substate.keys()))
2432 return any(submatches(c.p1().substate.keys()))
2420
2433
2421 return False
2434 return False
2422
2435
2423 return subset.filter(matches, condrepr=(b'<subrepo %r>', pat))
2436 return subset.filter(matches, condrepr=(b'<subrepo %r>', pat))
2424
2437
2425
2438
2426 def _mapbynodefunc(repo, s, f):
2439 def _mapbynodefunc(repo, s, f):
2427 """(repo, smartset, [node] -> [node]) -> smartset
2440 """(repo, smartset, [node] -> [node]) -> smartset
2428
2441
2429 Helper method to map a smartset to another smartset given a function only
2442 Helper method to map a smartset to another smartset given a function only
2430 talking about nodes. Handles converting between rev numbers and nodes, and
2443 talking about nodes. Handles converting between rev numbers and nodes, and
2431 filtering.
2444 filtering.
2432 """
2445 """
2433 cl = repo.unfiltered().changelog
2446 cl = repo.unfiltered().changelog
2434 torev = cl.index.get_rev
2447 torev = cl.index.get_rev
2435 tonode = cl.node
2448 tonode = cl.node
2436 result = {torev(n) for n in f(tonode(r) for r in s)}
2449 result = {torev(n) for n in f(tonode(r) for r in s)}
2437 result.discard(None)
2450 result.discard(None)
2438 return smartset.baseset(result - repo.changelog.filteredrevs)
2451 return smartset.baseset(result - repo.changelog.filteredrevs)
2439
2452
2440
2453
2441 @predicate(b'successors(set)', safe=True)
2454 @predicate(b'successors(set)', safe=True)
2442 def successors(repo, subset, x):
2455 def successors(repo, subset, x):
2443 """All successors for set, including the given set themselves.
2456 """All successors for set, including the given set themselves.
2444 (EXPERIMENTAL)"""
2457 (EXPERIMENTAL)"""
2445 s = getset(repo, fullreposet(repo), x)
2458 s = getset(repo, fullreposet(repo), x)
2446 f = lambda nodes: obsutil.allsuccessors(repo.obsstore, nodes)
2459 f = lambda nodes: obsutil.allsuccessors(repo.obsstore, nodes)
2447 d = _mapbynodefunc(repo, s, f)
2460 d = _mapbynodefunc(repo, s, f)
2448 return subset & d
2461 return subset & d
2449
2462
2450
2463
2451 def _substringmatcher(pattern, casesensitive=True):
2464 def _substringmatcher(pattern, casesensitive=True):
2452 kind, pattern, matcher = stringutil.stringmatcher(
2465 kind, pattern, matcher = stringutil.stringmatcher(
2453 pattern, casesensitive=casesensitive
2466 pattern, casesensitive=casesensitive
2454 )
2467 )
2455 if kind == b'literal':
2468 if kind == b'literal':
2456 if not casesensitive:
2469 if not casesensitive:
2457 pattern = encoding.lower(pattern)
2470 pattern = encoding.lower(pattern)
2458 matcher = lambda s: pattern in encoding.lower(s)
2471 matcher = lambda s: pattern in encoding.lower(s)
2459 else:
2472 else:
2460 matcher = lambda s: pattern in s
2473 matcher = lambda s: pattern in s
2461 return kind, pattern, matcher
2474 return kind, pattern, matcher
2462
2475
2463
2476
2464 @predicate(b'tag([name])', safe=True)
2477 @predicate(b'tag([name])', safe=True)
2465 def tag(repo, subset, x):
2478 def tag(repo, subset, x):
2466 """The specified tag by name, or all tagged revisions if no name is given.
2479 """The specified tag by name, or all tagged revisions if no name is given.
2467
2480
2468 Pattern matching is supported for `name`. See
2481 Pattern matching is supported for `name`. See
2469 :hg:`help revisions.patterns`.
2482 :hg:`help revisions.patterns`.
2470 """
2483 """
2471 # i18n: "tag" is a keyword
2484 # i18n: "tag" is a keyword
2472 args = getargs(x, 0, 1, _(b"tag takes one or no arguments"))
2485 args = getargs(x, 0, 1, _(b"tag takes one or no arguments"))
2473 cl = repo.changelog
2486 cl = repo.changelog
2474 if args:
2487 if args:
2475 pattern = getstring(
2488 pattern = getstring(
2476 args[0],
2489 args[0],
2477 # i18n: "tag" is a keyword
2490 # i18n: "tag" is a keyword
2478 _(b'the argument to tag must be a string'),
2491 _(b'the argument to tag must be a string'),
2479 )
2492 )
2480 kind, pattern, matcher = stringutil.stringmatcher(pattern)
2493 kind, pattern, matcher = stringutil.stringmatcher(pattern)
2481 if kind == b'literal':
2494 if kind == b'literal':
2482 # avoid resolving all tags
2495 # avoid resolving all tags
2483 tn = repo._tagscache.tags.get(pattern, None)
2496 tn = repo._tagscache.tags.get(pattern, None)
2484 if tn is None:
2497 if tn is None:
2485 raise error.RepoLookupError(
2498 raise error.RepoLookupError(
2486 _(b"tag '%s' does not exist") % pattern
2499 _(b"tag '%s' does not exist") % pattern
2487 )
2500 )
2488 s = {repo[tn].rev()}
2501 s = {repo[tn].rev()}
2489 else:
2502 else:
2490 s = {cl.rev(n) for t, n in repo.tagslist() if matcher(t)}
2503 s = {cl.rev(n) for t, n in repo.tagslist() if matcher(t)}
2491 else:
2504 else:
2492 s = {cl.rev(n) for t, n in repo.tagslist() if t != b'tip'}
2505 s = {cl.rev(n) for t, n in repo.tagslist() if t != b'tip'}
2493 return subset & s
2506 return subset & s
2494
2507
2495
2508
2496 @predicate(b'tagged', safe=True)
2509 @predicate(b'tagged', safe=True)
2497 def tagged(repo, subset, x):
2510 def tagged(repo, subset, x):
2498 return tag(repo, subset, x)
2511 return tag(repo, subset, x)
2499
2512
2500
2513
2501 @predicate(b'orphan()', safe=True)
2514 @predicate(b'orphan()', safe=True)
2502 def orphan(repo, subset, x):
2515 def orphan(repo, subset, x):
2503 """Non-obsolete changesets with obsolete ancestors. (EXPERIMENTAL)
2516 """Non-obsolete changesets with obsolete ancestors. (EXPERIMENTAL)
2504 """
2517 """
2505 # i18n: "orphan" is a keyword
2518 # i18n: "orphan" is a keyword
2506 getargs(x, 0, 0, _(b"orphan takes no arguments"))
2519 getargs(x, 0, 0, _(b"orphan takes no arguments"))
2507 orphan = obsmod.getrevs(repo, b'orphan')
2520 orphan = obsmod.getrevs(repo, b'orphan')
2508 return subset & orphan
2521 return subset & orphan
2509
2522
2510
2523
2511 @predicate(b'unstable()', safe=True)
2524 @predicate(b'unstable()', safe=True)
2512 def unstable(repo, subset, x):
2525 def unstable(repo, subset, x):
2513 """Changesets with instabilities. (EXPERIMENTAL)
2526 """Changesets with instabilities. (EXPERIMENTAL)
2514 """
2527 """
2515 # i18n: "unstable" is a keyword
2528 # i18n: "unstable" is a keyword
2516 getargs(x, 0, 0, b'unstable takes no arguments')
2529 getargs(x, 0, 0, b'unstable takes no arguments')
2517 _unstable = set()
2530 _unstable = set()
2518 _unstable.update(obsmod.getrevs(repo, b'orphan'))
2531 _unstable.update(obsmod.getrevs(repo, b'orphan'))
2519 _unstable.update(obsmod.getrevs(repo, b'phasedivergent'))
2532 _unstable.update(obsmod.getrevs(repo, b'phasedivergent'))
2520 _unstable.update(obsmod.getrevs(repo, b'contentdivergent'))
2533 _unstable.update(obsmod.getrevs(repo, b'contentdivergent'))
2521 _unstable = baseset(_unstable)
2534 _unstable = baseset(_unstable)
2522 _unstable.sort() # set is non-ordered, enforce order
2535 _unstable.sort() # set is non-ordered, enforce order
2523 return subset & _unstable
2536 return subset & _unstable
2524
2537
2525
2538
2526 @predicate(b'user(string)', safe=True, weight=10)
2539 @predicate(b'user(string)', safe=True, weight=10)
2527 def user(repo, subset, x):
2540 def user(repo, subset, x):
2528 """User name contains string. The match is case-insensitive.
2541 """User name contains string. The match is case-insensitive.
2529
2542
2530 Pattern matching is supported for `string`. See
2543 Pattern matching is supported for `string`. See
2531 :hg:`help revisions.patterns`.
2544 :hg:`help revisions.patterns`.
2532 """
2545 """
2533 return author(repo, subset, x)
2546 return author(repo, subset, x)
2534
2547
2535
2548
2536 @predicate(b'wdir()', safe=True, weight=0)
2549 @predicate(b'wdir()', safe=True, weight=0)
2537 def wdir(repo, subset, x):
2550 def wdir(repo, subset, x):
2538 """Working directory. (EXPERIMENTAL)"""
2551 """Working directory. (EXPERIMENTAL)"""
2539 # i18n: "wdir" is a keyword
2552 # i18n: "wdir" is a keyword
2540 getargs(x, 0, 0, _(b"wdir takes no arguments"))
2553 getargs(x, 0, 0, _(b"wdir takes no arguments"))
2541 if node.wdirrev in subset or isinstance(subset, fullreposet):
2554 if node.wdirrev in subset or isinstance(subset, fullreposet):
2542 return baseset([node.wdirrev])
2555 return baseset([node.wdirrev])
2543 return baseset()
2556 return baseset()
2544
2557
2545
2558
2546 def _orderedlist(repo, subset, x):
2559 def _orderedlist(repo, subset, x):
2547 s = getstring(x, b"internal error")
2560 s = getstring(x, b"internal error")
2548 if not s:
2561 if not s:
2549 return baseset()
2562 return baseset()
2550 # remove duplicates here. it's difficult for caller to deduplicate sets
2563 # remove duplicates here. it's difficult for caller to deduplicate sets
2551 # because different symbols can point to the same rev.
2564 # because different symbols can point to the same rev.
2552 cl = repo.changelog
2565 cl = repo.changelog
2553 ls = []
2566 ls = []
2554 seen = set()
2567 seen = set()
2555 for t in s.split(b'\0'):
2568 for t in s.split(b'\0'):
2556 try:
2569 try:
2557 # fast path for integer revision
2570 # fast path for integer revision
2558 r = int(t)
2571 r = int(t)
2559 if (b'%d' % r) != t or r not in cl:
2572 if (b'%d' % r) != t or r not in cl:
2560 raise ValueError
2573 raise ValueError
2561 revs = [r]
2574 revs = [r]
2562 except ValueError:
2575 except ValueError:
2563 revs = stringset(repo, subset, t, defineorder)
2576 revs = stringset(repo, subset, t, defineorder)
2564
2577
2565 for r in revs:
2578 for r in revs:
2566 if r in seen:
2579 if r in seen:
2567 continue
2580 continue
2568 if (
2581 if (
2569 r in subset
2582 r in subset
2570 or r in _virtualrevs
2583 or r in _virtualrevs
2571 and isinstance(subset, fullreposet)
2584 and isinstance(subset, fullreposet)
2572 ):
2585 ):
2573 ls.append(r)
2586 ls.append(r)
2574 seen.add(r)
2587 seen.add(r)
2575 return baseset(ls)
2588 return baseset(ls)
2576
2589
2577
2590
2578 # for internal use
2591 # for internal use
2579 @predicate(b'_list', safe=True, takeorder=True)
2592 @predicate(b'_list', safe=True, takeorder=True)
2580 def _list(repo, subset, x, order):
2593 def _list(repo, subset, x, order):
2581 if order == followorder:
2594 if order == followorder:
2582 # slow path to take the subset order
2595 # slow path to take the subset order
2583 return subset & _orderedlist(repo, fullreposet(repo), x)
2596 return subset & _orderedlist(repo, fullreposet(repo), x)
2584 else:
2597 else:
2585 return _orderedlist(repo, subset, x)
2598 return _orderedlist(repo, subset, x)
2586
2599
2587
2600
2588 def _orderedintlist(repo, subset, x):
2601 def _orderedintlist(repo, subset, x):
2589 s = getstring(x, b"internal error")
2602 s = getstring(x, b"internal error")
2590 if not s:
2603 if not s:
2591 return baseset()
2604 return baseset()
2592 ls = [int(r) for r in s.split(b'\0')]
2605 ls = [int(r) for r in s.split(b'\0')]
2593 s = subset
2606 s = subset
2594 return baseset([r for r in ls if r in s])
2607 return baseset([r for r in ls if r in s])
2595
2608
2596
2609
2597 # for internal use
2610 # for internal use
2598 @predicate(b'_intlist', safe=True, takeorder=True, weight=0)
2611 @predicate(b'_intlist', safe=True, takeorder=True, weight=0)
2599 def _intlist(repo, subset, x, order):
2612 def _intlist(repo, subset, x, order):
2600 if order == followorder:
2613 if order == followorder:
2601 # slow path to take the subset order
2614 # slow path to take the subset order
2602 return subset & _orderedintlist(repo, fullreposet(repo), x)
2615 return subset & _orderedintlist(repo, fullreposet(repo), x)
2603 else:
2616 else:
2604 return _orderedintlist(repo, subset, x)
2617 return _orderedintlist(repo, subset, x)
2605
2618
2606
2619
2607 def _orderedhexlist(repo, subset, x):
2620 def _orderedhexlist(repo, subset, x):
2608 s = getstring(x, b"internal error")
2621 s = getstring(x, b"internal error")
2609 if not s:
2622 if not s:
2610 return baseset()
2623 return baseset()
2611 cl = repo.changelog
2624 cl = repo.changelog
2612 ls = [cl.rev(node.bin(r)) for r in s.split(b'\0')]
2625 ls = [cl.rev(node.bin(r)) for r in s.split(b'\0')]
2613 s = subset
2626 s = subset
2614 return baseset([r for r in ls if r in s])
2627 return baseset([r for r in ls if r in s])
2615
2628
2616
2629
2617 # for internal use
2630 # for internal use
2618 @predicate(b'_hexlist', safe=True, takeorder=True)
2631 @predicate(b'_hexlist', safe=True, takeorder=True)
2619 def _hexlist(repo, subset, x, order):
2632 def _hexlist(repo, subset, x, order):
2620 if order == followorder:
2633 if order == followorder:
2621 # slow path to take the subset order
2634 # slow path to take the subset order
2622 return subset & _orderedhexlist(repo, fullreposet(repo), x)
2635 return subset & _orderedhexlist(repo, fullreposet(repo), x)
2623 else:
2636 else:
2624 return _orderedhexlist(repo, subset, x)
2637 return _orderedhexlist(repo, subset, x)
2625
2638
2626
2639
2627 methods = {
2640 methods = {
2628 b"range": rangeset,
2641 b"range": rangeset,
2629 b"rangeall": rangeall,
2642 b"rangeall": rangeall,
2630 b"rangepre": rangepre,
2643 b"rangepre": rangepre,
2631 b"rangepost": rangepost,
2644 b"rangepost": rangepost,
2632 b"dagrange": dagrange,
2645 b"dagrange": dagrange,
2633 b"string": stringset,
2646 b"string": stringset,
2634 b"symbol": stringset,
2647 b"symbol": stringset,
2635 b"and": andset,
2648 b"and": andset,
2636 b"andsmally": andsmallyset,
2649 b"andsmally": andsmallyset,
2637 b"or": orset,
2650 b"or": orset,
2638 b"not": notset,
2651 b"not": notset,
2639 b"difference": differenceset,
2652 b"difference": differenceset,
2640 b"relation": relationset,
2653 b"relation": relationset,
2641 b"relsubscript": relsubscriptset,
2654 b"relsubscript": relsubscriptset,
2642 b"subscript": subscriptset,
2655 b"subscript": subscriptset,
2643 b"list": listset,
2656 b"list": listset,
2644 b"keyvalue": keyvaluepair,
2657 b"keyvalue": keyvaluepair,
2645 b"func": func,
2658 b"func": func,
2646 b"ancestor": ancestorspec,
2659 b"ancestor": ancestorspec,
2647 b"parent": parentspec,
2660 b"parent": parentspec,
2648 b"parentpost": parentpost,
2661 b"parentpost": parentpost,
2649 b"smartset": rawsmartset,
2662 b"smartset": rawsmartset,
2650 }
2663 }
2651
2664
2665 relations = {
2666 b"g": generationsrel,
2667 b"generations": generationsrel,
2668 }
2669
2652 subscriptrelations = {
2670 subscriptrelations = {
2653 b"g": generationssubrel,
2671 b"g": generationssubrel,
2654 b"generations": generationssubrel,
2672 b"generations": generationssubrel,
2655 }
2673 }
2656
2674
2657
2675
2658 def lookupfn(repo):
2676 def lookupfn(repo):
2659 return lambda symbol: scmutil.isrevsymbol(repo, symbol)
2677 return lambda symbol: scmutil.isrevsymbol(repo, symbol)
2660
2678
2661
2679
2662 def match(ui, spec, lookup=None):
2680 def match(ui, spec, lookup=None):
2663 """Create a matcher for a single revision spec"""
2681 """Create a matcher for a single revision spec"""
2664 return matchany(ui, [spec], lookup=lookup)
2682 return matchany(ui, [spec], lookup=lookup)
2665
2683
2666
2684
2667 def matchany(ui, specs, lookup=None, localalias=None):
2685 def matchany(ui, specs, lookup=None, localalias=None):
2668 """Create a matcher that will include any revisions matching one of the
2686 """Create a matcher that will include any revisions matching one of the
2669 given specs
2687 given specs
2670
2688
2671 If lookup function is not None, the parser will first attempt to handle
2689 If lookup function is not None, the parser will first attempt to handle
2672 old-style ranges, which may contain operator characters.
2690 old-style ranges, which may contain operator characters.
2673
2691
2674 If localalias is not None, it is a dict {name: definitionstring}. It takes
2692 If localalias is not None, it is a dict {name: definitionstring}. It takes
2675 precedence over [revsetalias] config section.
2693 precedence over [revsetalias] config section.
2676 """
2694 """
2677 if not specs:
2695 if not specs:
2678
2696
2679 def mfunc(repo, subset=None):
2697 def mfunc(repo, subset=None):
2680 return baseset()
2698 return baseset()
2681
2699
2682 return mfunc
2700 return mfunc
2683 if not all(specs):
2701 if not all(specs):
2684 raise error.ParseError(_(b"empty query"))
2702 raise error.ParseError(_(b"empty query"))
2685 if len(specs) == 1:
2703 if len(specs) == 1:
2686 tree = revsetlang.parse(specs[0], lookup)
2704 tree = revsetlang.parse(specs[0], lookup)
2687 else:
2705 else:
2688 tree = (
2706 tree = (
2689 b'or',
2707 b'or',
2690 (b'list',) + tuple(revsetlang.parse(s, lookup) for s in specs),
2708 (b'list',) + tuple(revsetlang.parse(s, lookup) for s in specs),
2691 )
2709 )
2692
2710
2693 aliases = []
2711 aliases = []
2694 warn = None
2712 warn = None
2695 if ui:
2713 if ui:
2696 aliases.extend(ui.configitems(b'revsetalias'))
2714 aliases.extend(ui.configitems(b'revsetalias'))
2697 warn = ui.warn
2715 warn = ui.warn
2698 if localalias:
2716 if localalias:
2699 aliases.extend(localalias.items())
2717 aliases.extend(localalias.items())
2700 if aliases:
2718 if aliases:
2701 tree = revsetlang.expandaliases(tree, aliases, warn=warn)
2719 tree = revsetlang.expandaliases(tree, aliases, warn=warn)
2702 tree = revsetlang.foldconcat(tree)
2720 tree = revsetlang.foldconcat(tree)
2703 tree = revsetlang.analyze(tree)
2721 tree = revsetlang.analyze(tree)
2704 tree = revsetlang.optimize(tree)
2722 tree = revsetlang.optimize(tree)
2705 return makematcher(tree)
2723 return makematcher(tree)
2706
2724
2707
2725
2708 def makematcher(tree):
2726 def makematcher(tree):
2709 """Create a matcher from an evaluatable tree"""
2727 """Create a matcher from an evaluatable tree"""
2710
2728
2711 def mfunc(repo, subset=None, order=None):
2729 def mfunc(repo, subset=None, order=None):
2712 if order is None:
2730 if order is None:
2713 if subset is None:
2731 if subset is None:
2714 order = defineorder # 'x'
2732 order = defineorder # 'x'
2715 else:
2733 else:
2716 order = followorder # 'subset & x'
2734 order = followorder # 'subset & x'
2717 if subset is None:
2735 if subset is None:
2718 subset = fullreposet(repo)
2736 subset = fullreposet(repo)
2719 return getset(repo, subset, tree, order)
2737 return getset(repo, subset, tree, order)
2720
2738
2721 return mfunc
2739 return mfunc
2722
2740
2723
2741
2724 def loadpredicate(ui, extname, registrarobj):
2742 def loadpredicate(ui, extname, registrarobj):
2725 """Load revset predicates from specified registrarobj
2743 """Load revset predicates from specified registrarobj
2726 """
2744 """
2727 for name, func in pycompat.iteritems(registrarobj._table):
2745 for name, func in pycompat.iteritems(registrarobj._table):
2728 symbols[name] = func
2746 symbols[name] = func
2729 if func._safe:
2747 if func._safe:
2730 safesymbols.add(name)
2748 safesymbols.add(name)
2731
2749
2732
2750
2733 # load built-in predicates explicitly to setup safesymbols
2751 # load built-in predicates explicitly to setup safesymbols
2734 loadpredicate(None, None, predicate)
2752 loadpredicate(None, None, predicate)
2735
2753
2736 # tell hggettext to extract docstrings from these functions:
2754 # tell hggettext to extract docstrings from these functions:
2737 i18nfunctions = symbols.values()
2755 i18nfunctions = symbols.values()
@@ -1,3054 +1,3084 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[b'r3232'] = r3232
19 > mercurial.revset.symbols[b'r3232'] = r3232
20 > EOF
20 > EOF
21 $ cat >> $HGRCPATH << EOF
21 $ cat >> $HGRCPATH << EOF
22 > [extensions]
22 > [extensions]
23 > drawdag=$TESTDIR/drawdag.py
23 > drawdag=$TESTDIR/drawdag.py
24 > testrevset=$TESTTMP/testrevset.py
24 > testrevset=$TESTTMP/testrevset.py
25 > EOF
25 > EOF
26
26
27 $ try() {
27 $ try() {
28 > hg debugrevspec --debug "$@"
28 > hg debugrevspec --debug "$@"
29 > }
29 > }
30
30
31 $ log() {
31 $ log() {
32 > hg log --template '{rev}\n' -r "$1"
32 > hg log --template '{rev}\n' -r "$1"
33 > }
33 > }
34
34
35 extension to build '_intlist()' and '_hexlist()', which is necessary because
35 extension to build '_intlist()' and '_hexlist()', which is necessary because
36 these predicates use '\0' as a separator:
36 these predicates use '\0' as a separator:
37
37
38 $ cat <<EOF > debugrevlistspec.py
38 $ cat <<EOF > debugrevlistspec.py
39 > from __future__ import absolute_import
39 > from __future__ import absolute_import
40 > from mercurial import (
40 > from mercurial import (
41 > node as nodemod,
41 > node as nodemod,
42 > registrar,
42 > registrar,
43 > revset,
43 > revset,
44 > revsetlang,
44 > revsetlang,
45 > )
45 > )
46 > from mercurial.utils import stringutil
46 > from mercurial.utils import stringutil
47 > cmdtable = {}
47 > cmdtable = {}
48 > command = registrar.command(cmdtable)
48 > command = registrar.command(cmdtable)
49 > @command(b'debugrevlistspec',
49 > @command(b'debugrevlistspec',
50 > [(b'', b'optimize', None, b'print parsed tree after optimizing'),
50 > [(b'', b'optimize', None, b'print parsed tree after optimizing'),
51 > (b'', b'bin', None, b'unhexlify arguments')])
51 > (b'', b'bin', None, b'unhexlify arguments')])
52 > def debugrevlistspec(ui, repo, fmt, *args, **opts):
52 > def debugrevlistspec(ui, repo, fmt, *args, **opts):
53 > if opts['bin']:
53 > if opts['bin']:
54 > args = map(nodemod.bin, args)
54 > args = map(nodemod.bin, args)
55 > expr = revsetlang.formatspec(fmt, list(args))
55 > expr = revsetlang.formatspec(fmt, list(args))
56 > if ui.verbose:
56 > if ui.verbose:
57 > tree = revsetlang.parse(expr, lookup=revset.lookupfn(repo))
57 > tree = revsetlang.parse(expr, lookup=revset.lookupfn(repo))
58 > ui.note(revsetlang.prettyformat(tree), b"\n")
58 > ui.note(revsetlang.prettyformat(tree), b"\n")
59 > if opts["optimize"]:
59 > if opts["optimize"]:
60 > opttree = revsetlang.optimize(revsetlang.analyze(tree))
60 > opttree = revsetlang.optimize(revsetlang.analyze(tree))
61 > ui.note(b"* optimized:\n", revsetlang.prettyformat(opttree),
61 > ui.note(b"* optimized:\n", revsetlang.prettyformat(opttree),
62 > b"\n")
62 > b"\n")
63 > func = revset.match(ui, expr, lookup=revset.lookupfn(repo))
63 > func = revset.match(ui, expr, lookup=revset.lookupfn(repo))
64 > revs = func(repo)
64 > revs = func(repo)
65 > if ui.verbose:
65 > if ui.verbose:
66 > ui.note(b"* set:\n", stringutil.prettyrepr(revs), b"\n")
66 > ui.note(b"* set:\n", stringutil.prettyrepr(revs), b"\n")
67 > for c in revs:
67 > for c in revs:
68 > ui.write(b"%d\n" % c)
68 > ui.write(b"%d\n" % c)
69 > EOF
69 > EOF
70 $ cat <<EOF >> $HGRCPATH
70 $ cat <<EOF >> $HGRCPATH
71 > [extensions]
71 > [extensions]
72 > debugrevlistspec = $TESTTMP/debugrevlistspec.py
72 > debugrevlistspec = $TESTTMP/debugrevlistspec.py
73 > EOF
73 > EOF
74 $ trylist() {
74 $ trylist() {
75 > hg debugrevlistspec --debug "$@"
75 > hg debugrevlistspec --debug "$@"
76 > }
76 > }
77
77
78 $ hg init repo
78 $ hg init repo
79 $ cd repo
79 $ cd repo
80
80
81 $ echo a > a
81 $ echo a > a
82 $ hg branch a
82 $ hg branch a
83 marked working directory as branch a
83 marked working directory as branch a
84 (branches are permanent and global, did you want a bookmark?)
84 (branches are permanent and global, did you want a bookmark?)
85 $ hg ci -Aqm0
85 $ hg ci -Aqm0
86
86
87 $ echo b > b
87 $ echo b > b
88 $ hg branch b
88 $ hg branch b
89 marked working directory as branch b
89 marked working directory as branch b
90 $ hg ci -Aqm1
90 $ hg ci -Aqm1
91
91
92 $ rm a
92 $ rm a
93 $ hg branch a-b-c-
93 $ hg branch a-b-c-
94 marked working directory as branch a-b-c-
94 marked working directory as branch a-b-c-
95 $ hg ci -Aqm2 -u Bob
95 $ hg ci -Aqm2 -u Bob
96
96
97 $ hg log -r "extra('branch', 'a-b-c-')" --template '{rev}\n'
97 $ hg log -r "extra('branch', 'a-b-c-')" --template '{rev}\n'
98 2
98 2
99 $ hg log -r "extra('branch')" --template '{rev}\n'
99 $ hg log -r "extra('branch')" --template '{rev}\n'
100 0
100 0
101 1
101 1
102 2
102 2
103 $ hg log -r "extra('branch', 're:a')" --template '{rev} {branch}\n'
103 $ hg log -r "extra('branch', 're:a')" --template '{rev} {branch}\n'
104 0 a
104 0 a
105 2 a-b-c-
105 2 a-b-c-
106
106
107 $ hg co 1
107 $ hg co 1
108 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
108 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
109 $ hg branch +a+b+c+
109 $ hg branch +a+b+c+
110 marked working directory as branch +a+b+c+
110 marked working directory as branch +a+b+c+
111 $ hg ci -Aqm3
111 $ hg ci -Aqm3
112
112
113 $ hg co 2 # interleave
113 $ hg co 2 # interleave
114 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
114 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
115 $ echo bb > b
115 $ echo bb > b
116 $ hg branch -- -a-b-c-
116 $ hg branch -- -a-b-c-
117 marked working directory as branch -a-b-c-
117 marked working directory as branch -a-b-c-
118 $ hg ci -Aqm4 -d "May 12 2005"
118 $ hg ci -Aqm4 -d "May 12 2005"
119
119
120 $ hg co 3
120 $ hg co 3
121 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
121 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
122 $ hg branch !a/b/c/
122 $ hg branch !a/b/c/
123 marked working directory as branch !a/b/c/
123 marked working directory as branch !a/b/c/
124 $ hg ci -Aqm"5 bug"
124 $ hg ci -Aqm"5 bug"
125
125
126 $ hg merge 4
126 $ hg merge 4
127 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
127 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
128 (branch merge, don't forget to commit)
128 (branch merge, don't forget to commit)
129 $ hg branch _a_b_c_
129 $ hg branch _a_b_c_
130 marked working directory as branch _a_b_c_
130 marked working directory as branch _a_b_c_
131 $ hg ci -Aqm"6 issue619"
131 $ hg ci -Aqm"6 issue619"
132
132
133 $ hg branch .a.b.c.
133 $ hg branch .a.b.c.
134 marked working directory as branch .a.b.c.
134 marked working directory as branch .a.b.c.
135 $ hg ci -Aqm7
135 $ hg ci -Aqm7
136
136
137 $ hg branch all
137 $ hg branch all
138 marked working directory as branch all
138 marked working directory as branch all
139
139
140 $ hg co 4
140 $ hg co 4
141 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
141 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
142 $ hg branch Γ©
142 $ hg branch Γ©
143 marked working directory as branch \xc3\xa9 (esc)
143 marked working directory as branch \xc3\xa9 (esc)
144 $ hg ci -Aqm9
144 $ hg ci -Aqm9
145
145
146 $ hg tag -r6 1.0
146 $ hg tag -r6 1.0
147 $ hg bookmark -r6 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
147 $ hg bookmark -r6 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
148
148
149 $ hg clone --quiet -U -r 7 . ../remote1
149 $ hg clone --quiet -U -r 7 . ../remote1
150 $ hg clone --quiet -U -r 8 . ../remote2
150 $ hg clone --quiet -U -r 8 . ../remote2
151 $ echo "[paths]" >> .hg/hgrc
151 $ echo "[paths]" >> .hg/hgrc
152 $ echo "default = ../remote1" >> .hg/hgrc
152 $ echo "default = ../remote1" >> .hg/hgrc
153
153
154 trivial
154 trivial
155
155
156 $ try 0:1
156 $ try 0:1
157 (range
157 (range
158 (symbol '0')
158 (symbol '0')
159 (symbol '1'))
159 (symbol '1'))
160 * set:
160 * set:
161 <spanset+ 0:2>
161 <spanset+ 0:2>
162 0
162 0
163 1
163 1
164 $ try --optimize :
164 $ try --optimize :
165 (rangeall
165 (rangeall
166 None)
166 None)
167 * optimized:
167 * optimized:
168 (rangeall
168 (rangeall
169 None)
169 None)
170 * set:
170 * set:
171 <spanset+ 0:10>
171 <spanset+ 0:10>
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:10>
269 <spanset+ 3:10>
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:4>
281 <spanset+ 0:4>
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:5>
291 <spanset- 3:5>
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 (date(this is a test)
402 (date(this is a test)
403 ^ here)
403 ^ here)
404 [255]
404 [255]
405 $ log 'date()'
405 $ log 'date()'
406 hg: parse error: date requires a string
406 hg: parse error: date requires a string
407 [255]
407 [255]
408 $ log 'date'
408 $ log 'date'
409 abort: unknown revision 'date'!
409 abort: unknown revision 'date'!
410 [255]
410 [255]
411 $ log 'date('
411 $ log 'date('
412 hg: parse error at 5: not a prefix: end
412 hg: parse error at 5: not a prefix: end
413 (date(
413 (date(
414 ^ here)
414 ^ here)
415 [255]
415 [255]
416 $ log 'date("\xy")'
416 $ log 'date("\xy")'
417 hg: parse error: invalid \x escape* (glob)
417 hg: parse error: invalid \x escape* (glob)
418 [255]
418 [255]
419 $ log 'date(tip)'
419 $ log 'date(tip)'
420 hg: parse error: invalid date: 'tip'
420 hg: parse error: invalid date: 'tip'
421 [255]
421 [255]
422 $ log '0:date'
422 $ log '0:date'
423 abort: unknown revision 'date'!
423 abort: unknown revision 'date'!
424 [255]
424 [255]
425 $ log '::"date"'
425 $ log '::"date"'
426 abort: unknown revision 'date'!
426 abort: unknown revision 'date'!
427 [255]
427 [255]
428 $ hg book date -r 4
428 $ hg book date -r 4
429 $ log '0:date'
429 $ log '0:date'
430 0
430 0
431 1
431 1
432 2
432 2
433 3
433 3
434 4
434 4
435 $ log '::date'
435 $ log '::date'
436 0
436 0
437 1
437 1
438 2
438 2
439 4
439 4
440 $ log '::"date"'
440 $ log '::"date"'
441 0
441 0
442 1
442 1
443 2
443 2
444 4
444 4
445 $ log 'date(2005) and 1::'
445 $ log 'date(2005) and 1::'
446 4
446 4
447 $ hg book -d date
447 $ hg book -d date
448
448
449 function name should be a symbol
449 function name should be a symbol
450
450
451 $ log '"date"(2005)'
451 $ log '"date"(2005)'
452 hg: parse error: not a symbol
452 hg: parse error: not a symbol
453 [255]
453 [255]
454
454
455 keyword arguments
455 keyword arguments
456
456
457 $ log 'extra(branch, value=a)'
457 $ log 'extra(branch, value=a)'
458 0
458 0
459
459
460 $ log 'extra(branch, a, b)'
460 $ log 'extra(branch, a, b)'
461 hg: parse error: extra takes at most 2 positional arguments
461 hg: parse error: extra takes at most 2 positional arguments
462 [255]
462 [255]
463 $ log 'extra(a, label=b)'
463 $ log 'extra(a, label=b)'
464 hg: parse error: extra got multiple values for keyword argument 'label'
464 hg: parse error: extra got multiple values for keyword argument 'label'
465 [255]
465 [255]
466 $ log 'extra(label=branch, default)'
466 $ log 'extra(label=branch, default)'
467 hg: parse error: extra got an invalid argument
467 hg: parse error: extra got an invalid argument
468 [255]
468 [255]
469 $ log 'extra(branch, foo+bar=baz)'
469 $ log 'extra(branch, foo+bar=baz)'
470 hg: parse error: extra got an invalid argument
470 hg: parse error: extra got an invalid argument
471 [255]
471 [255]
472 $ log 'extra(unknown=branch)'
472 $ log 'extra(unknown=branch)'
473 hg: parse error: extra got an unexpected keyword argument 'unknown'
473 hg: parse error: extra got an unexpected keyword argument 'unknown'
474 [255]
474 [255]
475 $ log 'extra((), x)'
475 $ log 'extra((), x)'
476 hg: parse error: first argument to extra must be a string
476 hg: parse error: first argument to extra must be a string
477 [255]
477 [255]
478 $ log 'extra(label=x, ())'
478 $ log 'extra(label=x, ())'
479 hg: parse error: extra got an invalid argument
479 hg: parse error: extra got an invalid argument
480 [255]
480 [255]
481
481
482 $ try 'foo=bar|baz'
482 $ try 'foo=bar|baz'
483 (keyvalue
483 (keyvalue
484 (symbol 'foo')
484 (symbol 'foo')
485 (or
485 (or
486 (list
486 (list
487 (symbol 'bar')
487 (symbol 'bar')
488 (symbol 'baz'))))
488 (symbol 'baz'))))
489 hg: parse error: can't use a key-value pair in this context
489 hg: parse error: can't use a key-value pair in this context
490 [255]
490 [255]
491
491
492 right-hand side should be optimized recursively
492 right-hand side should be optimized recursively
493
493
494 $ try --optimize 'foo=(not public())'
494 $ try --optimize 'foo=(not public())'
495 (keyvalue
495 (keyvalue
496 (symbol 'foo')
496 (symbol 'foo')
497 (group
497 (group
498 (not
498 (not
499 (func
499 (func
500 (symbol 'public')
500 (symbol 'public')
501 None))))
501 None))))
502 * optimized:
502 * optimized:
503 (keyvalue
503 (keyvalue
504 (symbol 'foo')
504 (symbol 'foo')
505 (func
505 (func
506 (symbol '_notpublic')
506 (symbol '_notpublic')
507 None))
507 None))
508 hg: parse error: can't use a key-value pair in this context
508 hg: parse error: can't use a key-value pair in this context
509 [255]
509 [255]
510
510
511 relation-subscript operator has the highest binding strength (as function call):
511 relation-subscript operator has the highest binding strength (as function call):
512
512
513 $ hg debugrevspec -p parsed 'tip:tip^#generations[-1]'
513 $ hg debugrevspec -p parsed 'tip:tip^#generations[-1]'
514 * parsed:
514 * parsed:
515 (range
515 (range
516 (symbol 'tip')
516 (symbol 'tip')
517 (relsubscript
517 (relsubscript
518 (parentpost
518 (parentpost
519 (symbol 'tip'))
519 (symbol 'tip'))
520 (symbol 'generations')
520 (symbol 'generations')
521 (negate
521 (negate
522 (symbol '1'))))
522 (symbol '1'))))
523 9
523 9
524 8
524 8
525 7
525 7
526 6
526 6
527 5
527 5
528 4
528 4
529
529
530 $ hg debugrevspec -p parsed --no-show-revs 'not public()#generations[0]'
530 $ hg debugrevspec -p parsed --no-show-revs 'not public()#generations[0]'
531 * parsed:
531 * parsed:
532 (not
532 (not
533 (relsubscript
533 (relsubscript
534 (func
534 (func
535 (symbol 'public')
535 (symbol 'public')
536 None)
536 None)
537 (symbol 'generations')
537 (symbol 'generations')
538 (symbol '0')))
538 (symbol '0')))
539
539
540 left-hand side of relation-subscript operator should be optimized recursively:
540 left-hand side of relation-subscript operator should be optimized recursively:
541
541
542 $ hg debugrevspec -p analyzed -p optimized --no-show-revs \
542 $ hg debugrevspec -p analyzed -p optimized --no-show-revs \
543 > '(not public())#generations[0]'
543 > '(not public())#generations[0]'
544 * analyzed:
544 * analyzed:
545 (relsubscript
545 (relsubscript
546 (not
546 (not
547 (func
547 (func
548 (symbol 'public')
548 (symbol 'public')
549 None))
549 None))
550 (symbol 'generations')
550 (symbol 'generations')
551 (symbol '0'))
551 (symbol '0'))
552 * optimized:
552 * optimized:
553 (relsubscript
553 (relsubscript
554 (func
554 (func
555 (symbol '_notpublic')
555 (symbol '_notpublic')
556 None)
556 None)
557 (symbol 'generations')
557 (symbol 'generations')
558 (symbol '0'))
558 (symbol '0'))
559
559
560 resolution of subscript and relation-subscript ternary operators:
560 resolution of subscript and relation-subscript ternary operators:
561
561
562 $ hg debugrevspec -p analyzed 'tip[0]'
562 $ hg debugrevspec -p analyzed 'tip[0]'
563 * analyzed:
563 * analyzed:
564 (subscript
564 (subscript
565 (symbol 'tip')
565 (symbol 'tip')
566 (symbol '0'))
566 (symbol '0'))
567 hg: parse error: can't use a subscript in this context
567 hg: parse error: can't use a subscript in this context
568 [255]
568 [255]
569
569
570 $ hg debugrevspec -p analyzed 'tip#rel[0]'
570 $ hg debugrevspec -p analyzed 'tip#rel[0]'
571 * analyzed:
571 * analyzed:
572 (relsubscript
572 (relsubscript
573 (symbol 'tip')
573 (symbol 'tip')
574 (symbol 'rel')
574 (symbol 'rel')
575 (symbol '0'))
575 (symbol '0'))
576 hg: parse error: unknown identifier: rel
576 hg: parse error: unknown identifier: rel
577 [255]
577 [255]
578
578
579 $ hg debugrevspec -p analyzed '(tip#rel)[0]'
579 $ hg debugrevspec -p analyzed '(tip#rel)[0]'
580 * analyzed:
580 * analyzed:
581 (subscript
581 (subscript
582 (relation
582 (relation
583 (symbol 'tip')
583 (symbol 'tip')
584 (symbol 'rel'))
584 (symbol 'rel'))
585 (symbol '0'))
585 (symbol '0'))
586 hg: parse error: can't use a subscript in this context
586 hg: parse error: can't use a subscript in this context
587 [255]
587 [255]
588
588
589 $ hg debugrevspec -p analyzed 'tip#rel[0][1]'
589 $ hg debugrevspec -p analyzed 'tip#rel[0][1]'
590 * analyzed:
590 * analyzed:
591 (subscript
591 (subscript
592 (relsubscript
592 (relsubscript
593 (symbol 'tip')
593 (symbol 'tip')
594 (symbol 'rel')
594 (symbol 'rel')
595 (symbol '0'))
595 (symbol '0'))
596 (symbol '1'))
596 (symbol '1'))
597 hg: parse error: can't use a subscript in this context
597 hg: parse error: can't use a subscript in this context
598 [255]
598 [255]
599
599
600 $ hg debugrevspec -p analyzed 'tip#rel0#rel1[1]'
600 $ hg debugrevspec -p analyzed 'tip#rel0#rel1[1]'
601 * analyzed:
601 * analyzed:
602 (relsubscript
602 (relsubscript
603 (relation
603 (relation
604 (symbol 'tip')
604 (symbol 'tip')
605 (symbol 'rel0'))
605 (symbol 'rel0'))
606 (symbol 'rel1')
606 (symbol 'rel1')
607 (symbol '1'))
607 (symbol '1'))
608 hg: parse error: unknown identifier: rel1
608 hg: parse error: unknown identifier: rel1
609 [255]
609 [255]
610
610
611 $ hg debugrevspec -p analyzed 'tip#rel0[0]#rel1[1]'
611 $ hg debugrevspec -p analyzed 'tip#rel0[0]#rel1[1]'
612 * analyzed:
612 * analyzed:
613 (relsubscript
613 (relsubscript
614 (relsubscript
614 (relsubscript
615 (symbol 'tip')
615 (symbol 'tip')
616 (symbol 'rel0')
616 (symbol 'rel0')
617 (symbol '0'))
617 (symbol '0'))
618 (symbol 'rel1')
618 (symbol 'rel1')
619 (symbol '1'))
619 (symbol '1'))
620 hg: parse error: unknown identifier: rel1
620 hg: parse error: unknown identifier: rel1
621 [255]
621 [255]
622
622
623 parse errors of relation, subscript and relation-subscript operators:
623 parse errors of relation, subscript and relation-subscript operators:
624
624
625 $ hg debugrevspec '[0]'
625 $ hg debugrevspec '[0]'
626 hg: parse error at 0: not a prefix: [
626 hg: parse error at 0: not a prefix: [
627 ([0]
627 ([0]
628 ^ here)
628 ^ here)
629 [255]
629 [255]
630 $ hg debugrevspec '.#'
630 $ hg debugrevspec '.#'
631 hg: parse error at 2: not a prefix: end
631 hg: parse error at 2: not a prefix: end
632 (.#
632 (.#
633 ^ here)
633 ^ here)
634 [255]
634 [255]
635 $ hg debugrevspec '#rel'
635 $ hg debugrevspec '#rel'
636 hg: parse error at 0: not a prefix: #
636 hg: parse error at 0: not a prefix: #
637 (#rel
637 (#rel
638 ^ here)
638 ^ here)
639 [255]
639 [255]
640 $ hg debugrevspec '.#rel[0'
640 $ hg debugrevspec '.#rel[0'
641 hg: parse error at 7: unexpected token: end
641 hg: parse error at 7: unexpected token: end
642 (.#rel[0
642 (.#rel[0
643 ^ here)
643 ^ here)
644 [255]
644 [255]
645 $ hg debugrevspec '.]'
645 $ hg debugrevspec '.]'
646 hg: parse error at 1: invalid token
646 hg: parse error at 1: invalid token
647 (.]
647 (.]
648 ^ here)
648 ^ here)
649 [255]
649 [255]
650
650
651 $ hg debugrevspec '.#generations[a]'
651 $ hg debugrevspec '.#generations[a]'
652 hg: parse error: relation subscript must be an integer or a range
652 hg: parse error: relation subscript must be an integer or a range
653 [255]
653 [255]
654 $ hg debugrevspec '.#generations[1-2]'
654 $ hg debugrevspec '.#generations[1-2]'
655 hg: parse error: relation subscript must be an integer or a range
655 hg: parse error: relation subscript must be an integer or a range
656 [255]
656 [255]
657 $ hg debugrevspec '.#generations[foo:bar]'
657 $ hg debugrevspec '.#generations[foo:bar]'
658 hg: parse error: relation subscript bounds must be integers
658 hg: parse error: relation subscript bounds must be integers
659 [255]
659 [255]
660
660
661 suggested relations
661 suggested relations
662
662
663 $ hg debugrevspec '.#generafions[0]'
663 $ hg debugrevspec '.#generafions[0]'
664 hg: parse error: unknown identifier: generafions
664 hg: parse error: unknown identifier: generafions
665 (did you mean generations?)
665 (did you mean generations?)
666 [255]
666 [255]
667
667
668 $ hg debugrevspec '.#f[0]'
668 $ hg debugrevspec '.#f[0]'
669 hg: parse error: unknown identifier: f
669 hg: parse error: unknown identifier: f
670 [255]
670 [255]
671
671
672 parsed tree at stages:
672 parsed tree at stages:
673
673
674 $ hg debugrevspec -p all '()'
674 $ hg debugrevspec -p all '()'
675 * parsed:
675 * parsed:
676 (group
676 (group
677 None)
677 None)
678 * expanded:
678 * expanded:
679 (group
679 (group
680 None)
680 None)
681 * concatenated:
681 * concatenated:
682 (group
682 (group
683 None)
683 None)
684 * analyzed:
684 * analyzed:
685 None
685 None
686 * optimized:
686 * optimized:
687 None
687 None
688 hg: parse error: missing argument
688 hg: parse error: missing argument
689 [255]
689 [255]
690
690
691 $ hg debugrevspec --no-optimized -p all '()'
691 $ hg debugrevspec --no-optimized -p all '()'
692 * parsed:
692 * parsed:
693 (group
693 (group
694 None)
694 None)
695 * expanded:
695 * expanded:
696 (group
696 (group
697 None)
697 None)
698 * concatenated:
698 * concatenated:
699 (group
699 (group
700 None)
700 None)
701 * analyzed:
701 * analyzed:
702 None
702 None
703 hg: parse error: missing argument
703 hg: parse error: missing argument
704 [255]
704 [255]
705
705
706 $ hg debugrevspec -p parsed -p analyzed -p optimized '(0|1)-1'
706 $ hg debugrevspec -p parsed -p analyzed -p optimized '(0|1)-1'
707 * parsed:
707 * parsed:
708 (minus
708 (minus
709 (group
709 (group
710 (or
710 (or
711 (list
711 (list
712 (symbol '0')
712 (symbol '0')
713 (symbol '1'))))
713 (symbol '1'))))
714 (symbol '1'))
714 (symbol '1'))
715 * analyzed:
715 * analyzed:
716 (and
716 (and
717 (or
717 (or
718 (list
718 (list
719 (symbol '0')
719 (symbol '0')
720 (symbol '1')))
720 (symbol '1')))
721 (not
721 (not
722 (symbol '1')))
722 (symbol '1')))
723 * optimized:
723 * optimized:
724 (difference
724 (difference
725 (func
725 (func
726 (symbol '_list')
726 (symbol '_list')
727 (string '0\x001'))
727 (string '0\x001'))
728 (symbol '1'))
728 (symbol '1'))
729 0
729 0
730
730
731 $ hg debugrevspec -p unknown '0'
731 $ hg debugrevspec -p unknown '0'
732 abort: invalid stage name: unknown
732 abort: invalid stage name: unknown
733 [255]
733 [255]
734
734
735 $ hg debugrevspec -p all --optimize '0'
735 $ hg debugrevspec -p all --optimize '0'
736 abort: cannot use --optimize with --show-stage
736 abort: cannot use --optimize with --show-stage
737 [255]
737 [255]
738
738
739 verify optimized tree:
739 verify optimized tree:
740
740
741 $ hg debugrevspec --verify '0|1'
741 $ hg debugrevspec --verify '0|1'
742
742
743 $ hg debugrevspec --verify -v -p analyzed -p optimized 'r3232() & 2'
743 $ hg debugrevspec --verify -v -p analyzed -p optimized 'r3232() & 2'
744 * analyzed:
744 * analyzed:
745 (and
745 (and
746 (func
746 (func
747 (symbol 'r3232')
747 (symbol 'r3232')
748 None)
748 None)
749 (symbol '2'))
749 (symbol '2'))
750 * optimized:
750 * optimized:
751 (andsmally
751 (andsmally
752 (func
752 (func
753 (symbol 'r3232')
753 (symbol 'r3232')
754 None)
754 None)
755 (symbol '2'))
755 (symbol '2'))
756 * analyzed set:
756 * analyzed set:
757 <baseset [2]>
757 <baseset [2]>
758 * optimized set:
758 * optimized set:
759 <baseset [2, 2]>
759 <baseset [2, 2]>
760 --- analyzed
760 --- analyzed
761 +++ optimized
761 +++ optimized
762 2
762 2
763 +2
763 +2
764 [1]
764 [1]
765
765
766 $ hg debugrevspec --no-optimized --verify-optimized '0'
766 $ hg debugrevspec --no-optimized --verify-optimized '0'
767 abort: cannot use --verify-optimized with --no-optimized
767 abort: cannot use --verify-optimized with --no-optimized
768 [255]
768 [255]
769
769
770 Test that symbols only get parsed as functions if there's an opening
770 Test that symbols only get parsed as functions if there's an opening
771 parenthesis.
771 parenthesis.
772
772
773 $ hg book only -r 9
773 $ hg book only -r 9
774 $ log 'only(only)' # Outer "only" is a function, inner "only" is the bookmark
774 $ log 'only(only)' # Outer "only" is a function, inner "only" is the bookmark
775 8
775 8
776 9
776 9
777
777
778 ':y' behaves like '0:y', but can't be rewritten as such since the revision '0'
778 ':y' behaves like '0:y', but can't be rewritten as such since the revision '0'
779 may be hidden (issue5385)
779 may be hidden (issue5385)
780
780
781 $ try -p parsed -p analyzed ':'
781 $ try -p parsed -p analyzed ':'
782 * parsed:
782 * parsed:
783 (rangeall
783 (rangeall
784 None)
784 None)
785 * analyzed:
785 * analyzed:
786 (rangeall
786 (rangeall
787 None)
787 None)
788 * set:
788 * set:
789 <spanset+ 0:10>
789 <spanset+ 0:10>
790 0
790 0
791 1
791 1
792 2
792 2
793 3
793 3
794 4
794 4
795 5
795 5
796 6
796 6
797 7
797 7
798 8
798 8
799 9
799 9
800 $ try -p analyzed ':1'
800 $ try -p analyzed ':1'
801 * analyzed:
801 * analyzed:
802 (rangepre
802 (rangepre
803 (symbol '1'))
803 (symbol '1'))
804 * set:
804 * set:
805 <spanset+ 0:2>
805 <spanset+ 0:2>
806 0
806 0
807 1
807 1
808 $ try -p analyzed ':(1|2)'
808 $ try -p analyzed ':(1|2)'
809 * analyzed:
809 * analyzed:
810 (rangepre
810 (rangepre
811 (or
811 (or
812 (list
812 (list
813 (symbol '1')
813 (symbol '1')
814 (symbol '2'))))
814 (symbol '2'))))
815 * set:
815 * set:
816 <spanset+ 0:3>
816 <spanset+ 0:3>
817 0
817 0
818 1
818 1
819 2
819 2
820 $ try -p analyzed ':(1&2)'
820 $ try -p analyzed ':(1&2)'
821 * analyzed:
821 * analyzed:
822 (rangepre
822 (rangepre
823 (and
823 (and
824 (symbol '1')
824 (symbol '1')
825 (symbol '2')))
825 (symbol '2')))
826 * set:
826 * set:
827 <baseset []>
827 <baseset []>
828
828
829 infix/suffix resolution of ^ operator (issue2884, issue5764):
829 infix/suffix resolution of ^ operator (issue2884, issue5764):
830
830
831 x^:y means (x^):y
831 x^:y means (x^):y
832
832
833 $ try '1^:2'
833 $ try '1^:2'
834 (range
834 (range
835 (parentpost
835 (parentpost
836 (symbol '1'))
836 (symbol '1'))
837 (symbol '2'))
837 (symbol '2'))
838 * set:
838 * set:
839 <spanset+ 0:3>
839 <spanset+ 0:3>
840 0
840 0
841 1
841 1
842 2
842 2
843
843
844 $ try '1^::2'
844 $ try '1^::2'
845 (dagrange
845 (dagrange
846 (parentpost
846 (parentpost
847 (symbol '1'))
847 (symbol '1'))
848 (symbol '2'))
848 (symbol '2'))
849 * set:
849 * set:
850 <baseset+ [0, 1, 2]>
850 <baseset+ [0, 1, 2]>
851 0
851 0
852 1
852 1
853 2
853 2
854
854
855 $ try '1^..2'
855 $ try '1^..2'
856 (dagrange
856 (dagrange
857 (parentpost
857 (parentpost
858 (symbol '1'))
858 (symbol '1'))
859 (symbol '2'))
859 (symbol '2'))
860 * set:
860 * set:
861 <baseset+ [0, 1, 2]>
861 <baseset+ [0, 1, 2]>
862 0
862 0
863 1
863 1
864 2
864 2
865
865
866 $ try '9^:'
866 $ try '9^:'
867 (rangepost
867 (rangepost
868 (parentpost
868 (parentpost
869 (symbol '9')))
869 (symbol '9')))
870 * set:
870 * set:
871 <spanset+ 8:10>
871 <spanset+ 8:10>
872 8
872 8
873 9
873 9
874
874
875 $ try '9^::'
875 $ try '9^::'
876 (dagrangepost
876 (dagrangepost
877 (parentpost
877 (parentpost
878 (symbol '9')))
878 (symbol '9')))
879 * set:
879 * set:
880 <generatorsetasc+>
880 <generatorsetasc+>
881 8
881 8
882 9
882 9
883
883
884 $ try '9^..'
884 $ try '9^..'
885 (dagrangepost
885 (dagrangepost
886 (parentpost
886 (parentpost
887 (symbol '9')))
887 (symbol '9')))
888 * set:
888 * set:
889 <generatorsetasc+>
889 <generatorsetasc+>
890 8
890 8
891 9
891 9
892
892
893 x^:y should be resolved before omitting group operators
893 x^:y should be resolved before omitting group operators
894
894
895 $ try '1^(:2)'
895 $ try '1^(:2)'
896 (parent
896 (parent
897 (symbol '1')
897 (symbol '1')
898 (group
898 (group
899 (rangepre
899 (rangepre
900 (symbol '2'))))
900 (symbol '2'))))
901 hg: parse error: ^ expects a number 0, 1, or 2
901 hg: parse error: ^ expects a number 0, 1, or 2
902 [255]
902 [255]
903
903
904 x^:y should be resolved recursively
904 x^:y should be resolved recursively
905
905
906 $ try 'sort(1^:2)'
906 $ try 'sort(1^:2)'
907 (func
907 (func
908 (symbol 'sort')
908 (symbol 'sort')
909 (range
909 (range
910 (parentpost
910 (parentpost
911 (symbol '1'))
911 (symbol '1'))
912 (symbol '2')))
912 (symbol '2')))
913 * set:
913 * set:
914 <spanset+ 0:3>
914 <spanset+ 0:3>
915 0
915 0
916 1
916 1
917 2
917 2
918
918
919 $ try '(3^:4)^:2'
919 $ try '(3^:4)^:2'
920 (range
920 (range
921 (parentpost
921 (parentpost
922 (group
922 (group
923 (range
923 (range
924 (parentpost
924 (parentpost
925 (symbol '3'))
925 (symbol '3'))
926 (symbol '4'))))
926 (symbol '4'))))
927 (symbol '2'))
927 (symbol '2'))
928 * set:
928 * set:
929 <spanset+ 0:3>
929 <spanset+ 0:3>
930 0
930 0
931 1
931 1
932 2
932 2
933
933
934 $ try '(3^::4)^::2'
934 $ try '(3^::4)^::2'
935 (dagrange
935 (dagrange
936 (parentpost
936 (parentpost
937 (group
937 (group
938 (dagrange
938 (dagrange
939 (parentpost
939 (parentpost
940 (symbol '3'))
940 (symbol '3'))
941 (symbol '4'))))
941 (symbol '4'))))
942 (symbol '2'))
942 (symbol '2'))
943 * set:
943 * set:
944 <baseset+ [0, 1, 2]>
944 <baseset+ [0, 1, 2]>
945 0
945 0
946 1
946 1
947 2
947 2
948
948
949 $ try '(9^:)^:'
949 $ try '(9^:)^:'
950 (rangepost
950 (rangepost
951 (parentpost
951 (parentpost
952 (group
952 (group
953 (rangepost
953 (rangepost
954 (parentpost
954 (parentpost
955 (symbol '9'))))))
955 (symbol '9'))))))
956 * set:
956 * set:
957 <spanset+ 4:10>
957 <spanset+ 4:10>
958 4
958 4
959 5
959 5
960 6
960 6
961 7
961 7
962 8
962 8
963 9
963 9
964
964
965 x^ in alias should also be resolved
965 x^ in alias should also be resolved
966
966
967 $ try 'A' --config 'revsetalias.A=1^:2'
967 $ try 'A' --config 'revsetalias.A=1^:2'
968 (symbol 'A')
968 (symbol 'A')
969 * expanded:
969 * expanded:
970 (range
970 (range
971 (parentpost
971 (parentpost
972 (symbol '1'))
972 (symbol '1'))
973 (symbol '2'))
973 (symbol '2'))
974 * set:
974 * set:
975 <spanset+ 0:3>
975 <spanset+ 0:3>
976 0
976 0
977 1
977 1
978 2
978 2
979
979
980 $ try 'A:2' --config 'revsetalias.A=1^'
980 $ try 'A:2' --config 'revsetalias.A=1^'
981 (range
981 (range
982 (symbol 'A')
982 (symbol 'A')
983 (symbol '2'))
983 (symbol '2'))
984 * expanded:
984 * expanded:
985 (range
985 (range
986 (parentpost
986 (parentpost
987 (symbol '1'))
987 (symbol '1'))
988 (symbol '2'))
988 (symbol '2'))
989 * set:
989 * set:
990 <spanset+ 0:3>
990 <spanset+ 0:3>
991 0
991 0
992 1
992 1
993 2
993 2
994
994
995 but not beyond the boundary of alias expansion, because the resolution should
995 but not beyond the boundary of alias expansion, because the resolution should
996 be made at the parsing stage
996 be made at the parsing stage
997
997
998 $ try '1^A' --config 'revsetalias.A=:2'
998 $ try '1^A' --config 'revsetalias.A=:2'
999 (parent
999 (parent
1000 (symbol '1')
1000 (symbol '1')
1001 (symbol 'A'))
1001 (symbol 'A'))
1002 * expanded:
1002 * expanded:
1003 (parent
1003 (parent
1004 (symbol '1')
1004 (symbol '1')
1005 (rangepre
1005 (rangepre
1006 (symbol '2')))
1006 (symbol '2')))
1007 hg: parse error: ^ expects a number 0, 1, or 2
1007 hg: parse error: ^ expects a number 0, 1, or 2
1008 [255]
1008 [255]
1009
1009
1010 '::' itself isn't a valid expression
1010 '::' itself isn't a valid expression
1011
1011
1012 $ try '::'
1012 $ try '::'
1013 (dagrangeall
1013 (dagrangeall
1014 None)
1014 None)
1015 hg: parse error: can't use '::' in this context
1015 hg: parse error: can't use '::' in this context
1016 [255]
1016 [255]
1017
1017
1018 ancestor can accept 0 or more arguments
1018 ancestor can accept 0 or more arguments
1019
1019
1020 $ log 'ancestor()'
1020 $ log 'ancestor()'
1021 $ log 'ancestor(1)'
1021 $ log 'ancestor(1)'
1022 1
1022 1
1023 $ log 'ancestor(4,5)'
1023 $ log 'ancestor(4,5)'
1024 1
1024 1
1025 $ log 'ancestor(4,5) and 4'
1025 $ log 'ancestor(4,5) and 4'
1026 $ log 'ancestor(0,0,1,3)'
1026 $ log 'ancestor(0,0,1,3)'
1027 0
1027 0
1028 $ log 'ancestor(3,1,5,3,5,1)'
1028 $ log 'ancestor(3,1,5,3,5,1)'
1029 1
1029 1
1030 $ log 'ancestor(0,1,3,5)'
1030 $ log 'ancestor(0,1,3,5)'
1031 0
1031 0
1032 $ log 'ancestor(1,2,3,4,5)'
1032 $ log 'ancestor(1,2,3,4,5)'
1033 1
1033 1
1034
1034
1035 test ancestors
1035 test ancestors
1036
1036
1037 $ hg log -G -T '{rev}\n' --config experimental.graphshorten=True
1037 $ hg log -G -T '{rev}\n' --config experimental.graphshorten=True
1038 @ 9
1038 @ 9
1039 o 8
1039 o 8
1040 | o 7
1040 | o 7
1041 | o 6
1041 | o 6
1042 |/|
1042 |/|
1043 | o 5
1043 | o 5
1044 o | 4
1044 o | 4
1045 | o 3
1045 | o 3
1046 o | 2
1046 o | 2
1047 |/
1047 |/
1048 o 1
1048 o 1
1049 o 0
1049 o 0
1050
1050
1051 $ log 'ancestors(5)'
1051 $ log 'ancestors(5)'
1052 0
1052 0
1053 1
1053 1
1054 3
1054 3
1055 5
1055 5
1056 $ log 'ancestor(ancestors(5))'
1056 $ log 'ancestor(ancestors(5))'
1057 0
1057 0
1058 $ log '::r3232()'
1058 $ log '::r3232()'
1059 0
1059 0
1060 1
1060 1
1061 2
1061 2
1062 3
1062 3
1063
1063
1064 test common ancestors
1064 test common ancestors
1065
1065
1066 $ hg log -T '{rev}\n' -r 'commonancestors(7 + 9)'
1066 $ hg log -T '{rev}\n' -r 'commonancestors(7 + 9)'
1067 0
1067 0
1068 1
1068 1
1069 2
1069 2
1070 4
1070 4
1071
1071
1072 $ hg log -T '{rev}\n' -r 'commonancestors(heads(all()))'
1072 $ hg log -T '{rev}\n' -r 'commonancestors(heads(all()))'
1073 0
1073 0
1074 1
1074 1
1075 2
1075 2
1076 4
1076 4
1077
1077
1078 $ hg log -T '{rev}\n' -r 'commonancestors(9)'
1078 $ hg log -T '{rev}\n' -r 'commonancestors(9)'
1079 0
1079 0
1080 1
1080 1
1081 2
1081 2
1082 4
1082 4
1083 8
1083 8
1084 9
1084 9
1085
1085
1086 $ hg log -T '{rev}\n' -r 'commonancestors(8 + 9)'
1086 $ hg log -T '{rev}\n' -r 'commonancestors(8 + 9)'
1087 0
1087 0
1088 1
1088 1
1089 2
1089 2
1090 4
1090 4
1091 8
1091 8
1092
1092
1093 test the specialized implementation of heads(commonancestors(..))
1093 test the specialized implementation of heads(commonancestors(..))
1094 (2 gcas is tested in test-merge-criss-cross.t)
1094 (2 gcas is tested in test-merge-criss-cross.t)
1095
1095
1096 $ hg log -T '{rev}\n' -r 'heads(commonancestors(7 + 9))'
1096 $ hg log -T '{rev}\n' -r 'heads(commonancestors(7 + 9))'
1097 4
1097 4
1098 $ hg log -T '{rev}\n' -r 'heads(commonancestors(heads(all())))'
1098 $ hg log -T '{rev}\n' -r 'heads(commonancestors(heads(all())))'
1099 4
1099 4
1100 $ hg log -T '{rev}\n' -r 'heads(commonancestors(9))'
1100 $ hg log -T '{rev}\n' -r 'heads(commonancestors(9))'
1101 9
1101 9
1102 $ hg log -T '{rev}\n' -r 'heads(commonancestors(8 + 9))'
1102 $ hg log -T '{rev}\n' -r 'heads(commonancestors(8 + 9))'
1103 8
1103 8
1104
1104
1105 test ancestor variants of empty revision
1105 test ancestor variants of empty revision
1106
1106
1107 $ log 'ancestor(none())'
1107 $ log 'ancestor(none())'
1108 $ log 'ancestors(none())'
1108 $ log 'ancestors(none())'
1109 $ log 'commonancestors(none())'
1109 $ log 'commonancestors(none())'
1110 $ log 'heads(commonancestors(none()))'
1110 $ log 'heads(commonancestors(none()))'
1111
1111
1112 test ancestors with depth limit
1112 test ancestors with depth limit
1113
1113
1114 (depth=0 selects the node itself)
1114 (depth=0 selects the node itself)
1115
1115
1116 $ log 'reverse(ancestors(9, depth=0))'
1116 $ log 'reverse(ancestors(9, depth=0))'
1117 9
1117 9
1118
1118
1119 (interleaved: '4' would be missing if heap queue were higher depth first)
1119 (interleaved: '4' would be missing if heap queue were higher depth first)
1120
1120
1121 $ log 'reverse(ancestors(8:9, depth=1))'
1121 $ log 'reverse(ancestors(8:9, depth=1))'
1122 9
1122 9
1123 8
1123 8
1124 4
1124 4
1125
1125
1126 (interleaved: '2' would be missing if heap queue were higher depth first)
1126 (interleaved: '2' would be missing if heap queue were higher depth first)
1127
1127
1128 $ log 'reverse(ancestors(7+8, depth=2))'
1128 $ log 'reverse(ancestors(7+8, depth=2))'
1129 8
1129 8
1130 7
1130 7
1131 6
1131 6
1132 5
1132 5
1133 4
1133 4
1134 2
1134 2
1135
1135
1136 (walk example above by separate queries)
1136 (walk example above by separate queries)
1137
1137
1138 $ log 'reverse(ancestors(8, depth=2)) + reverse(ancestors(7, depth=2))'
1138 $ log 'reverse(ancestors(8, depth=2)) + reverse(ancestors(7, depth=2))'
1139 8
1139 8
1140 4
1140 4
1141 2
1141 2
1142 7
1142 7
1143 6
1143 6
1144 5
1144 5
1145
1145
1146 (walk 2nd and 3rd ancestors)
1146 (walk 2nd and 3rd ancestors)
1147
1147
1148 $ log 'reverse(ancestors(7, depth=3, startdepth=2))'
1148 $ log 'reverse(ancestors(7, depth=3, startdepth=2))'
1149 5
1149 5
1150 4
1150 4
1151 3
1151 3
1152 2
1152 2
1153
1153
1154 (interleaved: '4' would be missing if higher-depth ancestors weren't scanned)
1154 (interleaved: '4' would be missing if higher-depth ancestors weren't scanned)
1155
1155
1156 $ log 'reverse(ancestors(7+8, depth=2, startdepth=2))'
1156 $ log 'reverse(ancestors(7+8, depth=2, startdepth=2))'
1157 5
1157 5
1158 4
1158 4
1159 2
1159 2
1160
1160
1161 (note that 'ancestors(x, depth=y, startdepth=z)' does not identical to
1161 (note that 'ancestors(x, depth=y, startdepth=z)' does not identical to
1162 'ancestors(x, depth=y) - ancestors(x, depth=z-1)' because a node may have
1162 'ancestors(x, depth=y) - ancestors(x, depth=z-1)' because a node may have
1163 multiple depths)
1163 multiple depths)
1164
1164
1165 $ log 'reverse(ancestors(7+8, depth=2) - ancestors(7+8, depth=1))'
1165 $ log 'reverse(ancestors(7+8, depth=2) - ancestors(7+8, depth=1))'
1166 5
1166 5
1167 2
1167 2
1168
1168
1169 test bad arguments passed to ancestors()
1169 test bad arguments passed to ancestors()
1170
1170
1171 $ log 'ancestors(., depth=-1)'
1171 $ log 'ancestors(., depth=-1)'
1172 hg: parse error: negative depth
1172 hg: parse error: negative depth
1173 [255]
1173 [255]
1174 $ log 'ancestors(., depth=foo)'
1174 $ log 'ancestors(., depth=foo)'
1175 hg: parse error: ancestors expects an integer depth
1175 hg: parse error: ancestors expects an integer depth
1176 [255]
1176 [255]
1177
1177
1178 test descendants
1178 test descendants
1179
1179
1180 $ hg log -G -T '{rev}\n' --config experimental.graphshorten=True
1180 $ hg log -G -T '{rev}\n' --config experimental.graphshorten=True
1181 @ 9
1181 @ 9
1182 o 8
1182 o 8
1183 | o 7
1183 | o 7
1184 | o 6
1184 | o 6
1185 |/|
1185 |/|
1186 | o 5
1186 | o 5
1187 o | 4
1187 o | 4
1188 | o 3
1188 | o 3
1189 o | 2
1189 o | 2
1190 |/
1190 |/
1191 o 1
1191 o 1
1192 o 0
1192 o 0
1193
1193
1194 (null is ultimate root and has optimized path)
1194 (null is ultimate root and has optimized path)
1195
1195
1196 $ log 'null:4 & descendants(null)'
1196 $ log 'null:4 & descendants(null)'
1197 -1
1197 -1
1198 0
1198 0
1199 1
1199 1
1200 2
1200 2
1201 3
1201 3
1202 4
1202 4
1203
1203
1204 (including merge)
1204 (including merge)
1205
1205
1206 $ log ':8 & descendants(2)'
1206 $ log ':8 & descendants(2)'
1207 2
1207 2
1208 4
1208 4
1209 6
1209 6
1210 7
1210 7
1211 8
1211 8
1212
1212
1213 (multiple roots)
1213 (multiple roots)
1214
1214
1215 $ log ':8 & descendants(2+5)'
1215 $ log ':8 & descendants(2+5)'
1216 2
1216 2
1217 4
1217 4
1218 5
1218 5
1219 6
1219 6
1220 7
1220 7
1221 8
1221 8
1222
1222
1223 test descendants with depth limit
1223 test descendants with depth limit
1224
1224
1225 (depth=0 selects the node itself)
1225 (depth=0 selects the node itself)
1226
1226
1227 $ log 'descendants(0, depth=0)'
1227 $ log 'descendants(0, depth=0)'
1228 0
1228 0
1229 $ log 'null: & descendants(null, depth=0)'
1229 $ log 'null: & descendants(null, depth=0)'
1230 -1
1230 -1
1231
1231
1232 (p2 = null should be ignored)
1232 (p2 = null should be ignored)
1233
1233
1234 $ log 'null: & descendants(null, depth=2)'
1234 $ log 'null: & descendants(null, depth=2)'
1235 -1
1235 -1
1236 0
1236 0
1237 1
1237 1
1238
1238
1239 (multiple paths: depth(6) = (2, 3))
1239 (multiple paths: depth(6) = (2, 3))
1240
1240
1241 $ log 'descendants(1+3, depth=2)'
1241 $ log 'descendants(1+3, depth=2)'
1242 1
1242 1
1243 2
1243 2
1244 3
1244 3
1245 4
1245 4
1246 5
1246 5
1247 6
1247 6
1248
1248
1249 (multiple paths: depth(5) = (1, 2), depth(6) = (2, 3))
1249 (multiple paths: depth(5) = (1, 2), depth(6) = (2, 3))
1250
1250
1251 $ log 'descendants(3+1, depth=2, startdepth=2)'
1251 $ log 'descendants(3+1, depth=2, startdepth=2)'
1252 4
1252 4
1253 5
1253 5
1254 6
1254 6
1255
1255
1256 (multiple depths: depth(6) = (0, 2, 4), search for depth=2)
1256 (multiple depths: depth(6) = (0, 2, 4), search for depth=2)
1257
1257
1258 $ log 'descendants(0+3+6, depth=3, startdepth=1)'
1258 $ log 'descendants(0+3+6, depth=3, startdepth=1)'
1259 1
1259 1
1260 2
1260 2
1261 3
1261 3
1262 4
1262 4
1263 5
1263 5
1264 6
1264 6
1265 7
1265 7
1266
1266
1267 (multiple depths: depth(6) = (0, 4), no match)
1267 (multiple depths: depth(6) = (0, 4), no match)
1268
1268
1269 $ log 'descendants(0+6, depth=3, startdepth=1)'
1269 $ log 'descendants(0+6, depth=3, startdepth=1)'
1270 1
1270 1
1271 2
1271 2
1272 3
1272 3
1273 4
1273 4
1274 5
1274 5
1275 7
1275 7
1276
1276
1277 test ancestors/descendants relation:
1278
1279 $ log 'tip#generations'
1280 0
1281 1
1282 2
1283 4
1284 8
1285 9
1286
1287 $ log '3#g'
1288 0
1289 1
1290 3
1291 5
1292 6
1293 7
1294
1295 $ hg debugrevspec -p parsed 'tip#g'
1296 * parsed:
1297 (relation
1298 (symbol 'tip')
1299 (symbol 'g'))
1300 0
1301 1
1302 2
1303 4
1304 8
1305 9
1306
1277 test ancestors/descendants relation subscript:
1307 test ancestors/descendants relation subscript:
1278
1308
1279 $ log 'tip#generations[0]'
1309 $ log 'tip#generations[0]'
1280 9
1310 9
1281 $ log '.#generations[-1]'
1311 $ log '.#generations[-1]'
1282 8
1312 8
1283 $ log '.#g[(-1)]'
1313 $ log '.#g[(-1)]'
1284 8
1314 8
1285
1315
1286 $ log '6#generations[0:1]'
1316 $ log '6#generations[0:1]'
1287 6
1317 6
1288 7
1318 7
1289 $ log '6#generations[-1:1]'
1319 $ log '6#generations[-1:1]'
1290 4
1320 4
1291 5
1321 5
1292 6
1322 6
1293 7
1323 7
1294 $ log '6#generations[0:]'
1324 $ log '6#generations[0:]'
1295 6
1325 6
1296 7
1326 7
1297 $ log '5#generations[:0]'
1327 $ log '5#generations[:0]'
1298 0
1328 0
1299 1
1329 1
1300 3
1330 3
1301 5
1331 5
1302 $ log '3#generations[:]'
1332 $ log '3#generations[:]'
1303 0
1333 0
1304 1
1334 1
1305 3
1335 3
1306 5
1336 5
1307 6
1337 6
1308 7
1338 7
1309 $ log 'tip#generations[1:-1]'
1339 $ log 'tip#generations[1:-1]'
1310
1340
1311 $ hg debugrevspec -p parsed 'roots(:)#g[2]'
1341 $ hg debugrevspec -p parsed 'roots(:)#g[2]'
1312 * parsed:
1342 * parsed:
1313 (relsubscript
1343 (relsubscript
1314 (func
1344 (func
1315 (symbol 'roots')
1345 (symbol 'roots')
1316 (rangeall
1346 (rangeall
1317 None))
1347 None))
1318 (symbol 'g')
1348 (symbol 'g')
1319 (symbol '2'))
1349 (symbol '2'))
1320 2
1350 2
1321 3
1351 3
1322
1352
1323 test author
1353 test author
1324
1354
1325 $ log 'author(bob)'
1355 $ log 'author(bob)'
1326 2
1356 2
1327 $ log 'author("re:bob|test")'
1357 $ log 'author("re:bob|test")'
1328 0
1358 0
1329 1
1359 1
1330 2
1360 2
1331 3
1361 3
1332 4
1362 4
1333 5
1363 5
1334 6
1364 6
1335 7
1365 7
1336 8
1366 8
1337 9
1367 9
1338 $ log 'author(r"re:\S")'
1368 $ log 'author(r"re:\S")'
1339 0
1369 0
1340 1
1370 1
1341 2
1371 2
1342 3
1372 3
1343 4
1373 4
1344 5
1374 5
1345 6
1375 6
1346 7
1376 7
1347 8
1377 8
1348 9
1378 9
1349 $ log 'branch(Γ©)'
1379 $ log 'branch(Γ©)'
1350 8
1380 8
1351 9
1381 9
1352 $ log 'branch(a)'
1382 $ log 'branch(a)'
1353 0
1383 0
1354 $ hg log -r 'branch("re:a")' --template '{rev} {branch}\n'
1384 $ hg log -r 'branch("re:a")' --template '{rev} {branch}\n'
1355 0 a
1385 0 a
1356 2 a-b-c-
1386 2 a-b-c-
1357 3 +a+b+c+
1387 3 +a+b+c+
1358 4 -a-b-c-
1388 4 -a-b-c-
1359 5 !a/b/c/
1389 5 !a/b/c/
1360 6 _a_b_c_
1390 6 _a_b_c_
1361 7 .a.b.c.
1391 7 .a.b.c.
1362 $ log 'children(ancestor(4,5))'
1392 $ log 'children(ancestor(4,5))'
1363 2
1393 2
1364 3
1394 3
1365
1395
1366 $ log 'children(4)'
1396 $ log 'children(4)'
1367 6
1397 6
1368 8
1398 8
1369 $ log 'children(null)'
1399 $ log 'children(null)'
1370 0
1400 0
1371
1401
1372 $ log 'closed()'
1402 $ log 'closed()'
1373 $ log 'contains(a)'
1403 $ log 'contains(a)'
1374 0
1404 0
1375 1
1405 1
1376 3
1406 3
1377 5
1407 5
1378 $ log 'contains("../repo/a")'
1408 $ log 'contains("../repo/a")'
1379 0
1409 0
1380 1
1410 1
1381 3
1411 3
1382 5
1412 5
1383 $ log 'desc(B)'
1413 $ log 'desc(B)'
1384 5
1414 5
1385 $ hg log -r 'desc(r"re:S?u")' --template "{rev} {desc|firstline}\n"
1415 $ hg log -r 'desc(r"re:S?u")' --template "{rev} {desc|firstline}\n"
1386 5 5 bug
1416 5 5 bug
1387 6 6 issue619
1417 6 6 issue619
1388 $ log 'descendants(2 or 3)'
1418 $ log 'descendants(2 or 3)'
1389 2
1419 2
1390 3
1420 3
1391 4
1421 4
1392 5
1422 5
1393 6
1423 6
1394 7
1424 7
1395 8
1425 8
1396 9
1426 9
1397 $ log 'file("b*")'
1427 $ log 'file("b*")'
1398 1
1428 1
1399 4
1429 4
1400 $ log 'filelog("b")'
1430 $ log 'filelog("b")'
1401 1
1431 1
1402 4
1432 4
1403 $ log 'filelog("../repo/b")'
1433 $ log 'filelog("../repo/b")'
1404 1
1434 1
1405 4
1435 4
1406 $ log 'follow()'
1436 $ log 'follow()'
1407 0
1437 0
1408 1
1438 1
1409 2
1439 2
1410 4
1440 4
1411 8
1441 8
1412 9
1442 9
1413 $ log 'grep("issue\d+")'
1443 $ log 'grep("issue\d+")'
1414 6
1444 6
1415 $ try 'grep("(")' # invalid regular expression
1445 $ try 'grep("(")' # invalid regular expression
1416 (func
1446 (func
1417 (symbol 'grep')
1447 (symbol 'grep')
1418 (string '('))
1448 (string '('))
1419 hg: parse error: invalid match pattern: (unbalanced parenthesis|missing \),.*) (re)
1449 hg: parse error: invalid match pattern: (unbalanced parenthesis|missing \),.*) (re)
1420 [255]
1450 [255]
1421 $ try 'grep("\bissue\d+")'
1451 $ try 'grep("\bissue\d+")'
1422 (func
1452 (func
1423 (symbol 'grep')
1453 (symbol 'grep')
1424 (string '\x08issue\\d+'))
1454 (string '\x08issue\\d+'))
1425 * set:
1455 * set:
1426 <filteredset
1456 <filteredset
1427 <fullreposet+ 0:10>,
1457 <fullreposet+ 0:10>,
1428 <grep '\x08issue\\d+'>>
1458 <grep '\x08issue\\d+'>>
1429 $ try 'grep(r"\bissue\d+")'
1459 $ try 'grep(r"\bissue\d+")'
1430 (func
1460 (func
1431 (symbol 'grep')
1461 (symbol 'grep')
1432 (string '\\bissue\\d+'))
1462 (string '\\bissue\\d+'))
1433 * set:
1463 * set:
1434 <filteredset
1464 <filteredset
1435 <fullreposet+ 0:10>,
1465 <fullreposet+ 0:10>,
1436 <grep '\\bissue\\d+'>>
1466 <grep '\\bissue\\d+'>>
1437 6
1467 6
1438 $ try 'grep(r"\")'
1468 $ try 'grep(r"\")'
1439 hg: parse error at 7: unterminated string
1469 hg: parse error at 7: unterminated string
1440 (grep(r"\")
1470 (grep(r"\")
1441 ^ here)
1471 ^ here)
1442 [255]
1472 [255]
1443 $ log 'head()'
1473 $ log 'head()'
1444 0
1474 0
1445 1
1475 1
1446 2
1476 2
1447 3
1477 3
1448 4
1478 4
1449 5
1479 5
1450 6
1480 6
1451 7
1481 7
1452 9
1482 9
1453
1483
1454 Test heads
1484 Test heads
1455
1485
1456 $ log 'heads(6::)'
1486 $ log 'heads(6::)'
1457 7
1487 7
1458
1488
1459 heads() can be computed in subset '9:'
1489 heads() can be computed in subset '9:'
1460
1490
1461 $ hg debugrevspec -s '9: & heads(all())'
1491 $ hg debugrevspec -s '9: & heads(all())'
1462 * set:
1492 * set:
1463 <filteredset
1493 <filteredset
1464 <baseset [9]>,
1494 <baseset [9]>,
1465 <baseset+ [7, 9]>>
1495 <baseset+ [7, 9]>>
1466 9
1496 9
1467
1497
1468 but should follow the order of the subset
1498 but should follow the order of the subset
1469
1499
1470 $ log 'heads(all())'
1500 $ log 'heads(all())'
1471 7
1501 7
1472 9
1502 9
1473 $ log 'heads(tip:0)'
1503 $ log 'heads(tip:0)'
1474 7
1504 7
1475 9
1505 9
1476 $ log 'tip:0 & heads(all())'
1506 $ log 'tip:0 & heads(all())'
1477 9
1507 9
1478 7
1508 7
1479 $ log 'tip:0 & heads(0:tip)'
1509 $ log 'tip:0 & heads(0:tip)'
1480 9
1510 9
1481 7
1511 7
1482
1512
1483 $ log 'keyword(issue)'
1513 $ log 'keyword(issue)'
1484 6
1514 6
1485 $ log 'keyword("test a")'
1515 $ log 'keyword("test a")'
1486
1516
1487 Test first (=limit) and last
1517 Test first (=limit) and last
1488
1518
1489 $ log 'limit(head(), 1)'
1519 $ log 'limit(head(), 1)'
1490 0
1520 0
1491 $ log 'limit(author("re:bob|test"), 3, 5)'
1521 $ log 'limit(author("re:bob|test"), 3, 5)'
1492 5
1522 5
1493 6
1523 6
1494 7
1524 7
1495 $ log 'limit(author("re:bob|test"), offset=6)'
1525 $ log 'limit(author("re:bob|test"), offset=6)'
1496 6
1526 6
1497 $ log 'limit(author("re:bob|test"), offset=10)'
1527 $ log 'limit(author("re:bob|test"), offset=10)'
1498 $ log 'limit(all(), 1, -1)'
1528 $ log 'limit(all(), 1, -1)'
1499 hg: parse error: negative offset
1529 hg: parse error: negative offset
1500 [255]
1530 [255]
1501 $ log 'limit(all(), -1)'
1531 $ log 'limit(all(), -1)'
1502 hg: parse error: negative number to select
1532 hg: parse error: negative number to select
1503 [255]
1533 [255]
1504 $ log 'limit(all(), 0)'
1534 $ log 'limit(all(), 0)'
1505
1535
1506 $ log 'last(all(), -1)'
1536 $ log 'last(all(), -1)'
1507 hg: parse error: negative number to select
1537 hg: parse error: negative number to select
1508 [255]
1538 [255]
1509 $ log 'last(all(), 0)'
1539 $ log 'last(all(), 0)'
1510 $ log 'last(all(), 1)'
1540 $ log 'last(all(), 1)'
1511 9
1541 9
1512 $ log 'last(all(), 2)'
1542 $ log 'last(all(), 2)'
1513 8
1543 8
1514 9
1544 9
1515
1545
1516 Test smartset.slice() by first/last()
1546 Test smartset.slice() by first/last()
1517
1547
1518 (using unoptimized set, filteredset as example)
1548 (using unoptimized set, filteredset as example)
1519
1549
1520 $ hg debugrevspec --no-show-revs -s '0:7 & branch("re:")'
1550 $ hg debugrevspec --no-show-revs -s '0:7 & branch("re:")'
1521 * set:
1551 * set:
1522 <filteredset
1552 <filteredset
1523 <spanset+ 0:8>,
1553 <spanset+ 0:8>,
1524 <branch 're:'>>
1554 <branch 're:'>>
1525 $ log 'limit(0:7 & branch("re:"), 3, 4)'
1555 $ log 'limit(0:7 & branch("re:"), 3, 4)'
1526 4
1556 4
1527 5
1557 5
1528 6
1558 6
1529 $ log 'limit(7:0 & branch("re:"), 3, 4)'
1559 $ log 'limit(7:0 & branch("re:"), 3, 4)'
1530 3
1560 3
1531 2
1561 2
1532 1
1562 1
1533 $ log 'last(0:7 & branch("re:"), 2)'
1563 $ log 'last(0:7 & branch("re:"), 2)'
1534 6
1564 6
1535 7
1565 7
1536
1566
1537 (using baseset)
1567 (using baseset)
1538
1568
1539 $ hg debugrevspec --no-show-revs -s 0+1+2+3+4+5+6+7
1569 $ hg debugrevspec --no-show-revs -s 0+1+2+3+4+5+6+7
1540 * set:
1570 * set:
1541 <baseset [0, 1, 2, 3, 4, 5, 6, 7]>
1571 <baseset [0, 1, 2, 3, 4, 5, 6, 7]>
1542 $ hg debugrevspec --no-show-revs -s 0::7
1572 $ hg debugrevspec --no-show-revs -s 0::7
1543 * set:
1573 * set:
1544 <baseset+ [0, 1, 2, 3, 4, 5, 6, 7]>
1574 <baseset+ [0, 1, 2, 3, 4, 5, 6, 7]>
1545 $ log 'limit(0+1+2+3+4+5+6+7, 3, 4)'
1575 $ log 'limit(0+1+2+3+4+5+6+7, 3, 4)'
1546 4
1576 4
1547 5
1577 5
1548 6
1578 6
1549 $ log 'limit(sort(0::7, rev), 3, 4)'
1579 $ log 'limit(sort(0::7, rev), 3, 4)'
1550 4
1580 4
1551 5
1581 5
1552 6
1582 6
1553 $ log 'limit(sort(0::7, -rev), 3, 4)'
1583 $ log 'limit(sort(0::7, -rev), 3, 4)'
1554 3
1584 3
1555 2
1585 2
1556 1
1586 1
1557 $ log 'last(sort(0::7, rev), 2)'
1587 $ log 'last(sort(0::7, rev), 2)'
1558 6
1588 6
1559 7
1589 7
1560 $ hg debugrevspec -s 'limit(sort(0::7, rev), 3, 6)'
1590 $ hg debugrevspec -s 'limit(sort(0::7, rev), 3, 6)'
1561 * set:
1591 * set:
1562 <baseset+ [6, 7]>
1592 <baseset+ [6, 7]>
1563 6
1593 6
1564 7
1594 7
1565 $ hg debugrevspec -s 'limit(sort(0::7, rev), 3, 9)'
1595 $ hg debugrevspec -s 'limit(sort(0::7, rev), 3, 9)'
1566 * set:
1596 * set:
1567 <baseset+ []>
1597 <baseset+ []>
1568 $ hg debugrevspec -s 'limit(sort(0::7, -rev), 3, 6)'
1598 $ hg debugrevspec -s 'limit(sort(0::7, -rev), 3, 6)'
1569 * set:
1599 * set:
1570 <baseset- [0, 1]>
1600 <baseset- [0, 1]>
1571 1
1601 1
1572 0
1602 0
1573 $ hg debugrevspec -s 'limit(sort(0::7, -rev), 3, 9)'
1603 $ hg debugrevspec -s 'limit(sort(0::7, -rev), 3, 9)'
1574 * set:
1604 * set:
1575 <baseset- []>
1605 <baseset- []>
1576 $ hg debugrevspec -s 'limit(0::7, 0)'
1606 $ hg debugrevspec -s 'limit(0::7, 0)'
1577 * set:
1607 * set:
1578 <baseset+ []>
1608 <baseset+ []>
1579
1609
1580 (using spanset)
1610 (using spanset)
1581
1611
1582 $ hg debugrevspec --no-show-revs -s 0:7
1612 $ hg debugrevspec --no-show-revs -s 0:7
1583 * set:
1613 * set:
1584 <spanset+ 0:8>
1614 <spanset+ 0:8>
1585 $ log 'limit(0:7, 3, 4)'
1615 $ log 'limit(0:7, 3, 4)'
1586 4
1616 4
1587 5
1617 5
1588 6
1618 6
1589 $ log 'limit(7:0, 3, 4)'
1619 $ log 'limit(7:0, 3, 4)'
1590 3
1620 3
1591 2
1621 2
1592 1
1622 1
1593 $ log 'limit(0:7, 3, 6)'
1623 $ log 'limit(0:7, 3, 6)'
1594 6
1624 6
1595 7
1625 7
1596 $ log 'limit(7:0, 3, 6)'
1626 $ log 'limit(7:0, 3, 6)'
1597 1
1627 1
1598 0
1628 0
1599 $ log 'last(0:7, 2)'
1629 $ log 'last(0:7, 2)'
1600 6
1630 6
1601 7
1631 7
1602 $ hg debugrevspec -s 'limit(0:7, 3, 6)'
1632 $ hg debugrevspec -s 'limit(0:7, 3, 6)'
1603 * set:
1633 * set:
1604 <spanset+ 6:8>
1634 <spanset+ 6:8>
1605 6
1635 6
1606 7
1636 7
1607 $ hg debugrevspec -s 'limit(0:7, 3, 9)'
1637 $ hg debugrevspec -s 'limit(0:7, 3, 9)'
1608 * set:
1638 * set:
1609 <spanset+ 8:8>
1639 <spanset+ 8:8>
1610 $ hg debugrevspec -s 'limit(7:0, 3, 6)'
1640 $ hg debugrevspec -s 'limit(7:0, 3, 6)'
1611 * set:
1641 * set:
1612 <spanset- 0:2>
1642 <spanset- 0:2>
1613 1
1643 1
1614 0
1644 0
1615 $ hg debugrevspec -s 'limit(7:0, 3, 9)'
1645 $ hg debugrevspec -s 'limit(7:0, 3, 9)'
1616 * set:
1646 * set:
1617 <spanset- 0:0>
1647 <spanset- 0:0>
1618 $ hg debugrevspec -s 'limit(0:7, 0)'
1648 $ hg debugrevspec -s 'limit(0:7, 0)'
1619 * set:
1649 * set:
1620 <spanset+ 0:0>
1650 <spanset+ 0:0>
1621
1651
1622 Test order of first/last revisions
1652 Test order of first/last revisions
1623
1653
1624 $ hg debugrevspec -s 'first(4:0, 3) & 3:'
1654 $ hg debugrevspec -s 'first(4:0, 3) & 3:'
1625 * set:
1655 * set:
1626 <filteredset
1656 <filteredset
1627 <spanset- 2:5>,
1657 <spanset- 2:5>,
1628 <spanset+ 3:10>>
1658 <spanset+ 3:10>>
1629 4
1659 4
1630 3
1660 3
1631
1661
1632 $ hg debugrevspec -s '3: & first(4:0, 3)'
1662 $ hg debugrevspec -s '3: & first(4:0, 3)'
1633 * set:
1663 * set:
1634 <filteredset
1664 <filteredset
1635 <spanset+ 3:10>,
1665 <spanset+ 3:10>,
1636 <spanset- 2:5>>
1666 <spanset- 2:5>>
1637 3
1667 3
1638 4
1668 4
1639
1669
1640 $ hg debugrevspec -s 'last(4:0, 3) & :1'
1670 $ hg debugrevspec -s 'last(4:0, 3) & :1'
1641 * set:
1671 * set:
1642 <filteredset
1672 <filteredset
1643 <spanset- 0:3>,
1673 <spanset- 0:3>,
1644 <spanset+ 0:2>>
1674 <spanset+ 0:2>>
1645 1
1675 1
1646 0
1676 0
1647
1677
1648 $ hg debugrevspec -s ':1 & last(4:0, 3)'
1678 $ hg debugrevspec -s ':1 & last(4:0, 3)'
1649 * set:
1679 * set:
1650 <filteredset
1680 <filteredset
1651 <spanset+ 0:2>,
1681 <spanset+ 0:2>,
1652 <spanset+ 0:3>>
1682 <spanset+ 0:3>>
1653 0
1683 0
1654 1
1684 1
1655
1685
1656 Test scmutil.revsingle() should return the last revision
1686 Test scmutil.revsingle() should return the last revision
1657
1687
1658 $ hg debugrevspec -s 'last(0::)'
1688 $ hg debugrevspec -s 'last(0::)'
1659 * set:
1689 * set:
1660 <baseset slice=0:1
1690 <baseset slice=0:1
1661 <generatorsetasc->>
1691 <generatorsetasc->>
1662 9
1692 9
1663 $ hg identify -r '0::' --num
1693 $ hg identify -r '0::' --num
1664 9
1694 9
1665
1695
1666 Test matching
1696 Test matching
1667
1697
1668 $ log 'matching(6)'
1698 $ log 'matching(6)'
1669 6
1699 6
1670 $ log 'matching(6:7, "phase parents user date branch summary files description substate")'
1700 $ log 'matching(6:7, "phase parents user date branch summary files description substate")'
1671 6
1701 6
1672 7
1702 7
1673
1703
1674 Testing min and max
1704 Testing min and max
1675
1705
1676 max: simple
1706 max: simple
1677
1707
1678 $ log 'max(contains(a))'
1708 $ log 'max(contains(a))'
1679 5
1709 5
1680
1710
1681 max: simple on unordered set)
1711 max: simple on unordered set)
1682
1712
1683 $ log 'max((4+0+2+5+7) and contains(a))'
1713 $ log 'max((4+0+2+5+7) and contains(a))'
1684 5
1714 5
1685
1715
1686 max: no result
1716 max: no result
1687
1717
1688 $ log 'max(contains(stringthatdoesnotappearanywhere))'
1718 $ log 'max(contains(stringthatdoesnotappearanywhere))'
1689
1719
1690 max: no result on unordered set
1720 max: no result on unordered set
1691
1721
1692 $ log 'max((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
1722 $ log 'max((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
1693
1723
1694 min: simple
1724 min: simple
1695
1725
1696 $ log 'min(contains(a))'
1726 $ log 'min(contains(a))'
1697 0
1727 0
1698
1728
1699 min: simple on unordered set
1729 min: simple on unordered set
1700
1730
1701 $ log 'min((4+0+2+5+7) and contains(a))'
1731 $ log 'min((4+0+2+5+7) and contains(a))'
1702 0
1732 0
1703
1733
1704 min: empty
1734 min: empty
1705
1735
1706 $ log 'min(contains(stringthatdoesnotappearanywhere))'
1736 $ log 'min(contains(stringthatdoesnotappearanywhere))'
1707
1737
1708 min: empty on unordered set
1738 min: empty on unordered set
1709
1739
1710 $ log 'min((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
1740 $ log 'min((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
1711
1741
1712
1742
1713 $ log 'merge()'
1743 $ log 'merge()'
1714 6
1744 6
1715 $ log 'branchpoint()'
1745 $ log 'branchpoint()'
1716 1
1746 1
1717 4
1747 4
1718 $ log 'modifies(b)'
1748 $ log 'modifies(b)'
1719 4
1749 4
1720 $ log 'modifies("path:b")'
1750 $ log 'modifies("path:b")'
1721 4
1751 4
1722 $ log 'modifies("*")'
1752 $ log 'modifies("*")'
1723 4
1753 4
1724 $ log 'modifies("set:modified()")'
1754 $ log 'modifies("set:modified()")'
1725 4
1755 4
1726 $ log 'id(5)'
1756 $ log 'id(5)'
1727 $ log 'only(9)'
1757 $ log 'only(9)'
1728 8
1758 8
1729 9
1759 9
1730 $ log 'only(8)'
1760 $ log 'only(8)'
1731 8
1761 8
1732 $ log 'only(9, 5)'
1762 $ log 'only(9, 5)'
1733 2
1763 2
1734 4
1764 4
1735 8
1765 8
1736 9
1766 9
1737 $ log 'only(7 + 9, 5 + 2)'
1767 $ log 'only(7 + 9, 5 + 2)'
1738 4
1768 4
1739 6
1769 6
1740 7
1770 7
1741 8
1771 8
1742 9
1772 9
1743
1773
1744 Test empty set input
1774 Test empty set input
1745 $ log 'only(p2())'
1775 $ log 'only(p2())'
1746 $ log 'only(p1(), p2())'
1776 $ log 'only(p1(), p2())'
1747 0
1777 0
1748 1
1778 1
1749 2
1779 2
1750 4
1780 4
1751 8
1781 8
1752 9
1782 9
1753
1783
1754 Test '%' operator
1784 Test '%' operator
1755
1785
1756 $ log '9%'
1786 $ log '9%'
1757 8
1787 8
1758 9
1788 9
1759 $ log '9%5'
1789 $ log '9%5'
1760 2
1790 2
1761 4
1791 4
1762 8
1792 8
1763 9
1793 9
1764 $ log '(7 + 9)%(5 + 2)'
1794 $ log '(7 + 9)%(5 + 2)'
1765 4
1795 4
1766 6
1796 6
1767 7
1797 7
1768 8
1798 8
1769 9
1799 9
1770
1800
1771 Test operand of '%' is optimized recursively (issue4670)
1801 Test operand of '%' is optimized recursively (issue4670)
1772
1802
1773 $ try --optimize '8:9-8%'
1803 $ try --optimize '8:9-8%'
1774 (onlypost
1804 (onlypost
1775 (minus
1805 (minus
1776 (range
1806 (range
1777 (symbol '8')
1807 (symbol '8')
1778 (symbol '9'))
1808 (symbol '9'))
1779 (symbol '8')))
1809 (symbol '8')))
1780 * optimized:
1810 * optimized:
1781 (func
1811 (func
1782 (symbol 'only')
1812 (symbol 'only')
1783 (difference
1813 (difference
1784 (range
1814 (range
1785 (symbol '8')
1815 (symbol '8')
1786 (symbol '9'))
1816 (symbol '9'))
1787 (symbol '8')))
1817 (symbol '8')))
1788 * set:
1818 * set:
1789 <baseset+ [8, 9]>
1819 <baseset+ [8, 9]>
1790 8
1820 8
1791 9
1821 9
1792 $ try --optimize '(9)%(5)'
1822 $ try --optimize '(9)%(5)'
1793 (only
1823 (only
1794 (group
1824 (group
1795 (symbol '9'))
1825 (symbol '9'))
1796 (group
1826 (group
1797 (symbol '5')))
1827 (symbol '5')))
1798 * optimized:
1828 * optimized:
1799 (func
1829 (func
1800 (symbol 'only')
1830 (symbol 'only')
1801 (list
1831 (list
1802 (symbol '9')
1832 (symbol '9')
1803 (symbol '5')))
1833 (symbol '5')))
1804 * set:
1834 * set:
1805 <baseset+ [2, 4, 8, 9]>
1835 <baseset+ [2, 4, 8, 9]>
1806 2
1836 2
1807 4
1837 4
1808 8
1838 8
1809 9
1839 9
1810
1840
1811 Test the order of operations
1841 Test the order of operations
1812
1842
1813 $ log '7 + 9%5 + 2'
1843 $ log '7 + 9%5 + 2'
1814 7
1844 7
1815 2
1845 2
1816 4
1846 4
1817 8
1847 8
1818 9
1848 9
1819
1849
1820 Test explicit numeric revision
1850 Test explicit numeric revision
1821 $ log 'rev(-2)'
1851 $ log 'rev(-2)'
1822 $ log 'rev(-1)'
1852 $ log 'rev(-1)'
1823 -1
1853 -1
1824 $ log 'rev(0)'
1854 $ log 'rev(0)'
1825 0
1855 0
1826 $ log 'rev(9)'
1856 $ log 'rev(9)'
1827 9
1857 9
1828 $ log 'rev(10)'
1858 $ log 'rev(10)'
1829 $ log 'rev(tip)'
1859 $ log 'rev(tip)'
1830 hg: parse error: rev expects a number
1860 hg: parse error: rev expects a number
1831 [255]
1861 [255]
1832
1862
1833 Test hexadecimal revision
1863 Test hexadecimal revision
1834 $ log 'id(2)'
1864 $ log 'id(2)'
1835 $ log 'id(8)'
1865 $ log 'id(8)'
1836 3
1866 3
1837 $ hg --config experimental.revisions.prefixhexnode=yes log --template '{rev}\n' -r 'id(x8)'
1867 $ hg --config experimental.revisions.prefixhexnode=yes log --template '{rev}\n' -r 'id(x8)'
1838 3
1868 3
1839 $ hg --config experimental.revisions.prefixhexnode=yes log --template '{rev}\n' -r 'x8'
1869 $ hg --config experimental.revisions.prefixhexnode=yes log --template '{rev}\n' -r 'x8'
1840 3
1870 3
1841 $ hg --config experimental.revisions.prefixhexnode=yes log --template '{rev}\n' -r 'id(x)'
1871 $ hg --config experimental.revisions.prefixhexnode=yes log --template '{rev}\n' -r 'id(x)'
1842 $ hg --config experimental.revisions.prefixhexnode=yes log --template '{rev}\n' -r 'x'
1872 $ hg --config experimental.revisions.prefixhexnode=yes log --template '{rev}\n' -r 'x'
1843 abort: 00changelog.i@: ambiguous identifier!
1873 abort: 00changelog.i@: ambiguous identifier!
1844 [255]
1874 [255]
1845 $ log 'id(23268)'
1875 $ log 'id(23268)'
1846 4
1876 4
1847 $ log 'id(2785f51eece)'
1877 $ log 'id(2785f51eece)'
1848 0
1878 0
1849 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532c)'
1879 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532c)'
1850 8
1880 8
1851 $ log 'id(d5d0dcbdc4a)'
1881 $ log 'id(d5d0dcbdc4a)'
1852 $ log 'id(d5d0dcbdc4w)'
1882 $ log 'id(d5d0dcbdc4w)'
1853 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532d)'
1883 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532d)'
1854 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532q)'
1884 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532q)'
1855 $ log 'id(1.0)'
1885 $ log 'id(1.0)'
1856 $ log 'id(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)'
1886 $ log 'id(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)'
1857
1887
1858 Test null revision
1888 Test null revision
1859 $ log '(null)'
1889 $ log '(null)'
1860 -1
1890 -1
1861 $ log '(null:0)'
1891 $ log '(null:0)'
1862 -1
1892 -1
1863 0
1893 0
1864 $ log '(0:null)'
1894 $ log '(0:null)'
1865 0
1895 0
1866 -1
1896 -1
1867 $ log 'null::0'
1897 $ log 'null::0'
1868 -1
1898 -1
1869 0
1899 0
1870 $ log 'null:tip - 0:'
1900 $ log 'null:tip - 0:'
1871 -1
1901 -1
1872 $ log 'null: and null::' | head -1
1902 $ log 'null: and null::' | head -1
1873 -1
1903 -1
1874 $ log 'null: or 0:' | head -2
1904 $ log 'null: or 0:' | head -2
1875 -1
1905 -1
1876 0
1906 0
1877 $ log 'ancestors(null)'
1907 $ log 'ancestors(null)'
1878 -1
1908 -1
1879 $ log 'reverse(null:)' | tail -2
1909 $ log 'reverse(null:)' | tail -2
1880 0
1910 0
1881 -1
1911 -1
1882 $ log 'first(null:)'
1912 $ log 'first(null:)'
1883 -1
1913 -1
1884 $ log 'min(null:)'
1914 $ log 'min(null:)'
1885 BROKEN: should be '-1'
1915 BROKEN: should be '-1'
1886 $ log 'tip:null and all()' | tail -2
1916 $ log 'tip:null and all()' | tail -2
1887 1
1917 1
1888 0
1918 0
1889
1919
1890 Test working-directory revision
1920 Test working-directory revision
1891 $ hg debugrevspec 'wdir()'
1921 $ hg debugrevspec 'wdir()'
1892 2147483647
1922 2147483647
1893 $ hg debugrevspec 'wdir()^'
1923 $ hg debugrevspec 'wdir()^'
1894 9
1924 9
1895 $ hg up 7
1925 $ hg up 7
1896 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1926 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1897 $ hg debugrevspec 'wdir()^'
1927 $ hg debugrevspec 'wdir()^'
1898 7
1928 7
1899 $ hg debugrevspec 'wdir()^0'
1929 $ hg debugrevspec 'wdir()^0'
1900 2147483647
1930 2147483647
1901 $ hg debugrevspec 'wdir()~3'
1931 $ hg debugrevspec 'wdir()~3'
1902 5
1932 5
1903 $ hg debugrevspec 'ancestors(wdir())'
1933 $ hg debugrevspec 'ancestors(wdir())'
1904 0
1934 0
1905 1
1935 1
1906 2
1936 2
1907 3
1937 3
1908 4
1938 4
1909 5
1939 5
1910 6
1940 6
1911 7
1941 7
1912 2147483647
1942 2147483647
1913 $ hg debugrevspec '0:wdir() & ancestor(wdir())'
1943 $ hg debugrevspec '0:wdir() & ancestor(wdir())'
1914 2147483647
1944 2147483647
1915 $ hg debugrevspec '0:wdir() & ancestor(.:wdir())'
1945 $ hg debugrevspec '0:wdir() & ancestor(.:wdir())'
1916 4
1946 4
1917 $ hg debugrevspec '0:wdir() & ancestor(wdir(), wdir())'
1947 $ hg debugrevspec '0:wdir() & ancestor(wdir(), wdir())'
1918 2147483647
1948 2147483647
1919 $ hg debugrevspec '0:wdir() & ancestor(wdir(), tip)'
1949 $ hg debugrevspec '0:wdir() & ancestor(wdir(), tip)'
1920 4
1950 4
1921 $ hg debugrevspec 'null:wdir() & ancestor(wdir(), null)'
1951 $ hg debugrevspec 'null:wdir() & ancestor(wdir(), null)'
1922 -1
1952 -1
1923 $ hg debugrevspec 'wdir()~0'
1953 $ hg debugrevspec 'wdir()~0'
1924 2147483647
1954 2147483647
1925 $ hg debugrevspec 'p1(wdir())'
1955 $ hg debugrevspec 'p1(wdir())'
1926 7
1956 7
1927 $ hg debugrevspec 'p2(wdir())'
1957 $ hg debugrevspec 'p2(wdir())'
1928 $ hg debugrevspec 'parents(wdir())'
1958 $ hg debugrevspec 'parents(wdir())'
1929 7
1959 7
1930 $ hg debugrevspec 'wdir()^1'
1960 $ hg debugrevspec 'wdir()^1'
1931 7
1961 7
1932 $ hg debugrevspec 'wdir()^2'
1962 $ hg debugrevspec 'wdir()^2'
1933 $ hg debugrevspec 'wdir()^3'
1963 $ hg debugrevspec 'wdir()^3'
1934 hg: parse error: ^ expects a number 0, 1, or 2
1964 hg: parse error: ^ expects a number 0, 1, or 2
1935 [255]
1965 [255]
1936 For tests consistency
1966 For tests consistency
1937 $ hg up 9
1967 $ hg up 9
1938 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1968 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1939 $ hg debugrevspec 'tip or wdir()'
1969 $ hg debugrevspec 'tip or wdir()'
1940 9
1970 9
1941 2147483647
1971 2147483647
1942 $ hg debugrevspec '0:tip and wdir()'
1972 $ hg debugrevspec '0:tip and wdir()'
1943 $ log '0:wdir()' | tail -3
1973 $ log '0:wdir()' | tail -3
1944 8
1974 8
1945 9
1975 9
1946 2147483647
1976 2147483647
1947 $ log 'wdir():0' | head -3
1977 $ log 'wdir():0' | head -3
1948 2147483647
1978 2147483647
1949 9
1979 9
1950 8
1980 8
1951 $ log 'wdir():wdir()'
1981 $ log 'wdir():wdir()'
1952 2147483647
1982 2147483647
1953 $ log '(all() + wdir()) & min(. + wdir())'
1983 $ log '(all() + wdir()) & min(. + wdir())'
1954 9
1984 9
1955 $ log '(all() + wdir()) & max(. + wdir())'
1985 $ log '(all() + wdir()) & max(. + wdir())'
1956 2147483647
1986 2147483647
1957 $ log 'first(wdir() + .)'
1987 $ log 'first(wdir() + .)'
1958 2147483647
1988 2147483647
1959 $ log 'last(. + wdir())'
1989 $ log 'last(. + wdir())'
1960 2147483647
1990 2147483647
1961
1991
1962 Test working-directory integer revision and node id
1992 Test working-directory integer revision and node id
1963
1993
1964 $ hg debugrevspec '2147483647'
1994 $ hg debugrevspec '2147483647'
1965 2147483647
1995 2147483647
1966 $ hg debugrevspec 'rev(2147483647)'
1996 $ hg debugrevspec 'rev(2147483647)'
1967 2147483647
1997 2147483647
1968 $ hg debugrevspec 'ffffffffffffffffffffffffffffffffffffffff'
1998 $ hg debugrevspec 'ffffffffffffffffffffffffffffffffffffffff'
1969 2147483647
1999 2147483647
1970 $ hg debugrevspec 'ffffffffffff'
2000 $ hg debugrevspec 'ffffffffffff'
1971 2147483647
2001 2147483647
1972 $ hg debugrevspec 'id(ffffffffffffffffffffffffffffffffffffffff)'
2002 $ hg debugrevspec 'id(ffffffffffffffffffffffffffffffffffffffff)'
1973 2147483647
2003 2147483647
1974 $ hg debugrevspec 'id(ffffffffffff)'
2004 $ hg debugrevspec 'id(ffffffffffff)'
1975 2147483647
2005 2147483647
1976 $ hg debugrevspec 'ffffffffffff+000000000000'
2006 $ hg debugrevspec 'ffffffffffff+000000000000'
1977 2147483647
2007 2147483647
1978 -1
2008 -1
1979
2009
1980 $ cd ..
2010 $ cd ..
1981
2011
1982 Test short 'ff...' hash collision
2012 Test short 'ff...' hash collision
1983
2013
1984 $ hg init wdir-hashcollision
2014 $ hg init wdir-hashcollision
1985 $ cd wdir-hashcollision
2015 $ cd wdir-hashcollision
1986 $ cat <<EOF >> .hg/hgrc
2016 $ cat <<EOF >> .hg/hgrc
1987 > [experimental]
2017 > [experimental]
1988 > evolution.createmarkers=True
2018 > evolution.createmarkers=True
1989 > EOF
2019 > EOF
1990 $ echo 0 > a
2020 $ echo 0 > a
1991 $ hg ci -qAm 0
2021 $ hg ci -qAm 0
1992 $ for i in 2463 2961 6726 78127; do
2022 $ for i in 2463 2961 6726 78127; do
1993 > hg up -q 0
2023 > hg up -q 0
1994 > echo $i > a
2024 > echo $i > a
1995 > hg ci -qm $i
2025 > hg ci -qm $i
1996 > done
2026 > done
1997 $ hg up -q null
2027 $ hg up -q null
1998 $ hg log -r '0:wdir()' -T '{rev}:{node} {shortest(node, 3)}\n'
2028 $ hg log -r '0:wdir()' -T '{rev}:{node} {shortest(node, 3)}\n'
1999 0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a b4e
2029 0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a b4e
2000 1:fffbae3886c8fbb2114296380d276fd37715d571 fffba
2030 1:fffbae3886c8fbb2114296380d276fd37715d571 fffba
2001 2:fffb6093b00943f91034b9bdad069402c834e572 fffb6
2031 2:fffb6093b00943f91034b9bdad069402c834e572 fffb6
2002 3:fff48a9b9de34a4d64120c29548214c67980ade3 fff4
2032 3:fff48a9b9de34a4d64120c29548214c67980ade3 fff4
2003 4:ffff85cff0ff78504fcdc3c0bc10de0c65379249 ffff8
2033 4:ffff85cff0ff78504fcdc3c0bc10de0c65379249 ffff8
2004 2147483647:ffffffffffffffffffffffffffffffffffffffff fffff
2034 2147483647:ffffffffffffffffffffffffffffffffffffffff fffff
2005 $ hg debugobsolete fffbae3886c8fbb2114296380d276fd37715d571
2035 $ hg debugobsolete fffbae3886c8fbb2114296380d276fd37715d571
2006 1 new obsolescence markers
2036 1 new obsolescence markers
2007 obsoleted 1 changesets
2037 obsoleted 1 changesets
2008
2038
2009 $ hg debugrevspec 'fff'
2039 $ hg debugrevspec 'fff'
2010 abort: 00changelog.i@fff: ambiguous identifier!
2040 abort: 00changelog.i@fff: ambiguous identifier!
2011 [255]
2041 [255]
2012 $ hg debugrevspec 'ffff'
2042 $ hg debugrevspec 'ffff'
2013 abort: 00changelog.i@ffff: ambiguous identifier!
2043 abort: 00changelog.i@ffff: ambiguous identifier!
2014 [255]
2044 [255]
2015 $ hg debugrevspec 'fffb'
2045 $ hg debugrevspec 'fffb'
2016 abort: 00changelog.i@fffb: ambiguous identifier!
2046 abort: 00changelog.i@fffb: ambiguous identifier!
2017 [255]
2047 [255]
2018 BROKEN should be '2' (node lookup uses unfiltered repo)
2048 BROKEN should be '2' (node lookup uses unfiltered repo)
2019 $ hg debugrevspec 'id(fffb)'
2049 $ hg debugrevspec 'id(fffb)'
2020 BROKEN should be '2' (node lookup uses unfiltered repo)
2050 BROKEN should be '2' (node lookup uses unfiltered repo)
2021 $ hg debugrevspec 'ffff8'
2051 $ hg debugrevspec 'ffff8'
2022 4
2052 4
2023 $ hg debugrevspec 'fffff'
2053 $ hg debugrevspec 'fffff'
2024 2147483647
2054 2147483647
2025
2055
2026 $ cd ..
2056 $ cd ..
2027
2057
2028 Test branch() with wdir()
2058 Test branch() with wdir()
2029
2059
2030 $ cd repo
2060 $ cd repo
2031
2061
2032 $ log '0:wdir() & branch("literal:Γ©")'
2062 $ log '0:wdir() & branch("literal:Γ©")'
2033 8
2063 8
2034 9
2064 9
2035 2147483647
2065 2147483647
2036 $ log '0:wdir() & branch("re:Γ©")'
2066 $ log '0:wdir() & branch("re:Γ©")'
2037 8
2067 8
2038 9
2068 9
2039 2147483647
2069 2147483647
2040 $ log '0:wdir() & branch("re:^a")'
2070 $ log '0:wdir() & branch("re:^a")'
2041 0
2071 0
2042 2
2072 2
2043 $ log '0:wdir() & branch(8)'
2073 $ log '0:wdir() & branch(8)'
2044 8
2074 8
2045 9
2075 9
2046 2147483647
2076 2147483647
2047
2077
2048 branch(wdir()) returns all revisions belonging to the working branch. The wdir
2078 branch(wdir()) returns all revisions belonging to the working branch. The wdir
2049 itself isn't returned unless it is explicitly populated.
2079 itself isn't returned unless it is explicitly populated.
2050
2080
2051 $ log 'branch(wdir())'
2081 $ log 'branch(wdir())'
2052 8
2082 8
2053 9
2083 9
2054 $ log '0:wdir() & branch(wdir())'
2084 $ log '0:wdir() & branch(wdir())'
2055 8
2085 8
2056 9
2086 9
2057 2147483647
2087 2147483647
2058
2088
2059 $ log 'outgoing()'
2089 $ log 'outgoing()'
2060 8
2090 8
2061 9
2091 9
2062 $ log 'outgoing("../remote1")'
2092 $ log 'outgoing("../remote1")'
2063 8
2093 8
2064 9
2094 9
2065 $ log 'outgoing("../remote2")'
2095 $ log 'outgoing("../remote2")'
2066 3
2096 3
2067 5
2097 5
2068 6
2098 6
2069 7
2099 7
2070 9
2100 9
2071 $ log 'p1(merge())'
2101 $ log 'p1(merge())'
2072 5
2102 5
2073 $ log 'p2(merge())'
2103 $ log 'p2(merge())'
2074 4
2104 4
2075 $ log 'parents(merge())'
2105 $ log 'parents(merge())'
2076 4
2106 4
2077 5
2107 5
2078
2108
2079 $ hg merge 7
2109 $ hg merge 7
2080 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
2110 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
2081 (branch merge, don't forget to commit)
2111 (branch merge, don't forget to commit)
2082 $ log '0:wdir() & merge()'
2112 $ log '0:wdir() & merge()'
2083 6
2113 6
2084 2147483647
2114 2147483647
2085 $ hg update -qC .
2115 $ hg update -qC .
2086 $ log '0:wdir() & merge()'
2116 $ log '0:wdir() & merge()'
2087 6
2117 6
2088
2118
2089 $ log 'p1(branchpoint())'
2119 $ log 'p1(branchpoint())'
2090 0
2120 0
2091 2
2121 2
2092 $ log 'p2(branchpoint())'
2122 $ log 'p2(branchpoint())'
2093 $ log 'parents(branchpoint())'
2123 $ log 'parents(branchpoint())'
2094 0
2124 0
2095 2
2125 2
2096 $ log 'removes(a)'
2126 $ log 'removes(a)'
2097 2
2127 2
2098 $ log 'roots(all())'
2128 $ log 'roots(all())'
2099 0
2129 0
2100 $ log 'reverse(2 or 3 or 4 or 5)'
2130 $ log 'reverse(2 or 3 or 4 or 5)'
2101 5
2131 5
2102 4
2132 4
2103 3
2133 3
2104 2
2134 2
2105 $ log 'reverse(all())'
2135 $ log 'reverse(all())'
2106 9
2136 9
2107 8
2137 8
2108 7
2138 7
2109 6
2139 6
2110 5
2140 5
2111 4
2141 4
2112 3
2142 3
2113 2
2143 2
2114 1
2144 1
2115 0
2145 0
2116 $ log 'reverse(all()) & filelog(b)'
2146 $ log 'reverse(all()) & filelog(b)'
2117 4
2147 4
2118 1
2148 1
2119 $ log 'rev(5)'
2149 $ log 'rev(5)'
2120 5
2150 5
2121 $ log 'sort(limit(reverse(all()), 3))'
2151 $ log 'sort(limit(reverse(all()), 3))'
2122 7
2152 7
2123 8
2153 8
2124 9
2154 9
2125 $ log 'sort(2 or 3 or 4 or 5, date)'
2155 $ log 'sort(2 or 3 or 4 or 5, date)'
2126 2
2156 2
2127 3
2157 3
2128 5
2158 5
2129 4
2159 4
2130 $ log 'tagged()'
2160 $ log 'tagged()'
2131 6
2161 6
2132 $ log 'tag()'
2162 $ log 'tag()'
2133 6
2163 6
2134 $ log 'tag(1.0)'
2164 $ log 'tag(1.0)'
2135 6
2165 6
2136 $ log 'tag(tip)'
2166 $ log 'tag(tip)'
2137 9
2167 9
2138
2168
2139 Test order of revisions in compound expression
2169 Test order of revisions in compound expression
2140 ----------------------------------------------
2170 ----------------------------------------------
2141
2171
2142 The general rule is that only the outermost (= leftmost) predicate can
2172 The general rule is that only the outermost (= leftmost) predicate can
2143 enforce its ordering requirement. The other predicates should take the
2173 enforce its ordering requirement. The other predicates should take the
2144 ordering defined by it.
2174 ordering defined by it.
2145
2175
2146 'A & B' should follow the order of 'A':
2176 'A & B' should follow the order of 'A':
2147
2177
2148 $ log '2:0 & 0::2'
2178 $ log '2:0 & 0::2'
2149 2
2179 2
2150 1
2180 1
2151 0
2181 0
2152
2182
2153 'head()' combines sets in right order:
2183 'head()' combines sets in right order:
2154
2184
2155 $ log '2:0 & head()'
2185 $ log '2:0 & head()'
2156 2
2186 2
2157 1
2187 1
2158 0
2188 0
2159
2189
2160 'x:y' takes ordering parameter into account:
2190 'x:y' takes ordering parameter into account:
2161
2191
2162 $ try -p optimized '3:0 & 0:3 & not 2:1'
2192 $ try -p optimized '3:0 & 0:3 & not 2:1'
2163 * optimized:
2193 * optimized:
2164 (difference
2194 (difference
2165 (and
2195 (and
2166 (range
2196 (range
2167 (symbol '3')
2197 (symbol '3')
2168 (symbol '0'))
2198 (symbol '0'))
2169 (range
2199 (range
2170 (symbol '0')
2200 (symbol '0')
2171 (symbol '3')))
2201 (symbol '3')))
2172 (range
2202 (range
2173 (symbol '2')
2203 (symbol '2')
2174 (symbol '1')))
2204 (symbol '1')))
2175 * set:
2205 * set:
2176 <filteredset
2206 <filteredset
2177 <filteredset
2207 <filteredset
2178 <spanset- 0:4>,
2208 <spanset- 0:4>,
2179 <spanset+ 0:4>>,
2209 <spanset+ 0:4>>,
2180 <not
2210 <not
2181 <spanset+ 1:3>>>
2211 <spanset+ 1:3>>>
2182 3
2212 3
2183 0
2213 0
2184
2214
2185 'a + b', which is optimized to '_list(a b)', should take the ordering of
2215 'a + b', which is optimized to '_list(a b)', should take the ordering of
2186 the left expression:
2216 the left expression:
2187
2217
2188 $ try --optimize '2:0 & (0 + 1 + 2)'
2218 $ try --optimize '2:0 & (0 + 1 + 2)'
2189 (and
2219 (and
2190 (range
2220 (range
2191 (symbol '2')
2221 (symbol '2')
2192 (symbol '0'))
2222 (symbol '0'))
2193 (group
2223 (group
2194 (or
2224 (or
2195 (list
2225 (list
2196 (symbol '0')
2226 (symbol '0')
2197 (symbol '1')
2227 (symbol '1')
2198 (symbol '2')))))
2228 (symbol '2')))))
2199 * optimized:
2229 * optimized:
2200 (and
2230 (and
2201 (range
2231 (range
2202 (symbol '2')
2232 (symbol '2')
2203 (symbol '0'))
2233 (symbol '0'))
2204 (func
2234 (func
2205 (symbol '_list')
2235 (symbol '_list')
2206 (string '0\x001\x002')))
2236 (string '0\x001\x002')))
2207 * set:
2237 * set:
2208 <filteredset
2238 <filteredset
2209 <spanset- 0:3>,
2239 <spanset- 0:3>,
2210 <baseset [0, 1, 2]>>
2240 <baseset [0, 1, 2]>>
2211 2
2241 2
2212 1
2242 1
2213 0
2243 0
2214
2244
2215 'A + B' should take the ordering of the left expression:
2245 'A + B' should take the ordering of the left expression:
2216
2246
2217 $ try --optimize '2:0 & (0:1 + 2)'
2247 $ try --optimize '2:0 & (0:1 + 2)'
2218 (and
2248 (and
2219 (range
2249 (range
2220 (symbol '2')
2250 (symbol '2')
2221 (symbol '0'))
2251 (symbol '0'))
2222 (group
2252 (group
2223 (or
2253 (or
2224 (list
2254 (list
2225 (range
2255 (range
2226 (symbol '0')
2256 (symbol '0')
2227 (symbol '1'))
2257 (symbol '1'))
2228 (symbol '2')))))
2258 (symbol '2')))))
2229 * optimized:
2259 * optimized:
2230 (and
2260 (and
2231 (range
2261 (range
2232 (symbol '2')
2262 (symbol '2')
2233 (symbol '0'))
2263 (symbol '0'))
2234 (or
2264 (or
2235 (list
2265 (list
2236 (range
2266 (range
2237 (symbol '0')
2267 (symbol '0')
2238 (symbol '1'))
2268 (symbol '1'))
2239 (symbol '2'))))
2269 (symbol '2'))))
2240 * set:
2270 * set:
2241 <filteredset
2271 <filteredset
2242 <spanset- 0:3>,
2272 <spanset- 0:3>,
2243 <addset
2273 <addset
2244 <spanset+ 0:2>,
2274 <spanset+ 0:2>,
2245 <baseset [2]>>>
2275 <baseset [2]>>>
2246 2
2276 2
2247 1
2277 1
2248 0
2278 0
2249
2279
2250 '_intlist(a b)' should behave like 'a + b':
2280 '_intlist(a b)' should behave like 'a + b':
2251
2281
2252 $ trylist --optimize '2:0 & %ld' 0 1 2
2282 $ trylist --optimize '2:0 & %ld' 0 1 2
2253 (and
2283 (and
2254 (range
2284 (range
2255 (symbol '2')
2285 (symbol '2')
2256 (symbol '0'))
2286 (symbol '0'))
2257 (func
2287 (func
2258 (symbol '_intlist')
2288 (symbol '_intlist')
2259 (string '0\x001\x002')))
2289 (string '0\x001\x002')))
2260 * optimized:
2290 * optimized:
2261 (andsmally
2291 (andsmally
2262 (range
2292 (range
2263 (symbol '2')
2293 (symbol '2')
2264 (symbol '0'))
2294 (symbol '0'))
2265 (func
2295 (func
2266 (symbol '_intlist')
2296 (symbol '_intlist')
2267 (string '0\x001\x002')))
2297 (string '0\x001\x002')))
2268 * set:
2298 * set:
2269 <filteredset
2299 <filteredset
2270 <spanset- 0:3>,
2300 <spanset- 0:3>,
2271 <baseset+ [0, 1, 2]>>
2301 <baseset+ [0, 1, 2]>>
2272 2
2302 2
2273 1
2303 1
2274 0
2304 0
2275
2305
2276 $ trylist --optimize '%ld & 2:0' 0 2 1
2306 $ trylist --optimize '%ld & 2:0' 0 2 1
2277 (and
2307 (and
2278 (func
2308 (func
2279 (symbol '_intlist')
2309 (symbol '_intlist')
2280 (string '0\x002\x001'))
2310 (string '0\x002\x001'))
2281 (range
2311 (range
2282 (symbol '2')
2312 (symbol '2')
2283 (symbol '0')))
2313 (symbol '0')))
2284 * optimized:
2314 * optimized:
2285 (and
2315 (and
2286 (func
2316 (func
2287 (symbol '_intlist')
2317 (symbol '_intlist')
2288 (string '0\x002\x001'))
2318 (string '0\x002\x001'))
2289 (range
2319 (range
2290 (symbol '2')
2320 (symbol '2')
2291 (symbol '0')))
2321 (symbol '0')))
2292 * set:
2322 * set:
2293 <filteredset
2323 <filteredset
2294 <baseset [0, 2, 1]>,
2324 <baseset [0, 2, 1]>,
2295 <spanset- 0:3>>
2325 <spanset- 0:3>>
2296 0
2326 0
2297 2
2327 2
2298 1
2328 1
2299
2329
2300 '_hexlist(a b)' should behave like 'a + b':
2330 '_hexlist(a b)' should behave like 'a + b':
2301
2331
2302 $ trylist --optimize --bin '2:0 & %ln' `hg log -T '{node} ' -r0:2`
2332 $ trylist --optimize --bin '2:0 & %ln' `hg log -T '{node} ' -r0:2`
2303 (and
2333 (and
2304 (range
2334 (range
2305 (symbol '2')
2335 (symbol '2')
2306 (symbol '0'))
2336 (symbol '0'))
2307 (func
2337 (func
2308 (symbol '_hexlist')
2338 (symbol '_hexlist')
2309 (string '*'))) (glob)
2339 (string '*'))) (glob)
2310 * optimized:
2340 * optimized:
2311 (and
2341 (and
2312 (range
2342 (range
2313 (symbol '2')
2343 (symbol '2')
2314 (symbol '0'))
2344 (symbol '0'))
2315 (func
2345 (func
2316 (symbol '_hexlist')
2346 (symbol '_hexlist')
2317 (string '*'))) (glob)
2347 (string '*'))) (glob)
2318 * set:
2348 * set:
2319 <filteredset
2349 <filteredset
2320 <spanset- 0:3>,
2350 <spanset- 0:3>,
2321 <baseset [0, 1, 2]>>
2351 <baseset [0, 1, 2]>>
2322 2
2352 2
2323 1
2353 1
2324 0
2354 0
2325
2355
2326 $ trylist --optimize --bin '%ln & 2:0' `hg log -T '{node} ' -r0+2+1`
2356 $ trylist --optimize --bin '%ln & 2:0' `hg log -T '{node} ' -r0+2+1`
2327 (and
2357 (and
2328 (func
2358 (func
2329 (symbol '_hexlist')
2359 (symbol '_hexlist')
2330 (string '*')) (glob)
2360 (string '*')) (glob)
2331 (range
2361 (range
2332 (symbol '2')
2362 (symbol '2')
2333 (symbol '0')))
2363 (symbol '0')))
2334 * optimized:
2364 * optimized:
2335 (andsmally
2365 (andsmally
2336 (func
2366 (func
2337 (symbol '_hexlist')
2367 (symbol '_hexlist')
2338 (string '*')) (glob)
2368 (string '*')) (glob)
2339 (range
2369 (range
2340 (symbol '2')
2370 (symbol '2')
2341 (symbol '0')))
2371 (symbol '0')))
2342 * set:
2372 * set:
2343 <baseset [0, 2, 1]>
2373 <baseset [0, 2, 1]>
2344 0
2374 0
2345 2
2375 2
2346 1
2376 1
2347
2377
2348 '_list' should not go through the slow follow-order path if order doesn't
2378 '_list' should not go through the slow follow-order path if order doesn't
2349 matter:
2379 matter:
2350
2380
2351 $ try -p optimized '2:0 & not (0 + 1)'
2381 $ try -p optimized '2:0 & not (0 + 1)'
2352 * optimized:
2382 * optimized:
2353 (difference
2383 (difference
2354 (range
2384 (range
2355 (symbol '2')
2385 (symbol '2')
2356 (symbol '0'))
2386 (symbol '0'))
2357 (func
2387 (func
2358 (symbol '_list')
2388 (symbol '_list')
2359 (string '0\x001')))
2389 (string '0\x001')))
2360 * set:
2390 * set:
2361 <filteredset
2391 <filteredset
2362 <spanset- 0:3>,
2392 <spanset- 0:3>,
2363 <not
2393 <not
2364 <baseset [0, 1]>>>
2394 <baseset [0, 1]>>>
2365 2
2395 2
2366
2396
2367 $ try -p optimized '2:0 & not (0:2 & (0 + 1))'
2397 $ try -p optimized '2:0 & not (0:2 & (0 + 1))'
2368 * optimized:
2398 * optimized:
2369 (difference
2399 (difference
2370 (range
2400 (range
2371 (symbol '2')
2401 (symbol '2')
2372 (symbol '0'))
2402 (symbol '0'))
2373 (and
2403 (and
2374 (range
2404 (range
2375 (symbol '0')
2405 (symbol '0')
2376 (symbol '2'))
2406 (symbol '2'))
2377 (func
2407 (func
2378 (symbol '_list')
2408 (symbol '_list')
2379 (string '0\x001'))))
2409 (string '0\x001'))))
2380 * set:
2410 * set:
2381 <filteredset
2411 <filteredset
2382 <spanset- 0:3>,
2412 <spanset- 0:3>,
2383 <not
2413 <not
2384 <baseset [0, 1]>>>
2414 <baseset [0, 1]>>>
2385 2
2415 2
2386
2416
2387 because 'present()' does nothing other than suppressing an error, the
2417 because 'present()' does nothing other than suppressing an error, the
2388 ordering requirement should be forwarded to the nested expression
2418 ordering requirement should be forwarded to the nested expression
2389
2419
2390 $ try -p optimized 'present(2 + 0 + 1)'
2420 $ try -p optimized 'present(2 + 0 + 1)'
2391 * optimized:
2421 * optimized:
2392 (func
2422 (func
2393 (symbol 'present')
2423 (symbol 'present')
2394 (func
2424 (func
2395 (symbol '_list')
2425 (symbol '_list')
2396 (string '2\x000\x001')))
2426 (string '2\x000\x001')))
2397 * set:
2427 * set:
2398 <baseset [2, 0, 1]>
2428 <baseset [2, 0, 1]>
2399 2
2429 2
2400 0
2430 0
2401 1
2431 1
2402
2432
2403 $ try --optimize '2:0 & present(0 + 1 + 2)'
2433 $ try --optimize '2:0 & present(0 + 1 + 2)'
2404 (and
2434 (and
2405 (range
2435 (range
2406 (symbol '2')
2436 (symbol '2')
2407 (symbol '0'))
2437 (symbol '0'))
2408 (func
2438 (func
2409 (symbol 'present')
2439 (symbol 'present')
2410 (or
2440 (or
2411 (list
2441 (list
2412 (symbol '0')
2442 (symbol '0')
2413 (symbol '1')
2443 (symbol '1')
2414 (symbol '2')))))
2444 (symbol '2')))))
2415 * optimized:
2445 * optimized:
2416 (and
2446 (and
2417 (range
2447 (range
2418 (symbol '2')
2448 (symbol '2')
2419 (symbol '0'))
2449 (symbol '0'))
2420 (func
2450 (func
2421 (symbol 'present')
2451 (symbol 'present')
2422 (func
2452 (func
2423 (symbol '_list')
2453 (symbol '_list')
2424 (string '0\x001\x002'))))
2454 (string '0\x001\x002'))))
2425 * set:
2455 * set:
2426 <filteredset
2456 <filteredset
2427 <spanset- 0:3>,
2457 <spanset- 0:3>,
2428 <baseset [0, 1, 2]>>
2458 <baseset [0, 1, 2]>>
2429 2
2459 2
2430 1
2460 1
2431 0
2461 0
2432
2462
2433 'reverse()' should take effect only if it is the outermost expression:
2463 'reverse()' should take effect only if it is the outermost expression:
2434
2464
2435 $ try --optimize '0:2 & reverse(all())'
2465 $ try --optimize '0:2 & reverse(all())'
2436 (and
2466 (and
2437 (range
2467 (range
2438 (symbol '0')
2468 (symbol '0')
2439 (symbol '2'))
2469 (symbol '2'))
2440 (func
2470 (func
2441 (symbol 'reverse')
2471 (symbol 'reverse')
2442 (func
2472 (func
2443 (symbol 'all')
2473 (symbol 'all')
2444 None)))
2474 None)))
2445 * optimized:
2475 * optimized:
2446 (and
2476 (and
2447 (range
2477 (range
2448 (symbol '0')
2478 (symbol '0')
2449 (symbol '2'))
2479 (symbol '2'))
2450 (func
2480 (func
2451 (symbol 'reverse')
2481 (symbol 'reverse')
2452 (func
2482 (func
2453 (symbol 'all')
2483 (symbol 'all')
2454 None)))
2484 None)))
2455 * set:
2485 * set:
2456 <filteredset
2486 <filteredset
2457 <spanset+ 0:3>,
2487 <spanset+ 0:3>,
2458 <spanset+ 0:10>>
2488 <spanset+ 0:10>>
2459 0
2489 0
2460 1
2490 1
2461 2
2491 2
2462
2492
2463 'sort()' should take effect only if it is the outermost expression:
2493 'sort()' should take effect only if it is the outermost expression:
2464
2494
2465 $ try --optimize '0:2 & sort(all(), -rev)'
2495 $ try --optimize '0:2 & sort(all(), -rev)'
2466 (and
2496 (and
2467 (range
2497 (range
2468 (symbol '0')
2498 (symbol '0')
2469 (symbol '2'))
2499 (symbol '2'))
2470 (func
2500 (func
2471 (symbol 'sort')
2501 (symbol 'sort')
2472 (list
2502 (list
2473 (func
2503 (func
2474 (symbol 'all')
2504 (symbol 'all')
2475 None)
2505 None)
2476 (negate
2506 (negate
2477 (symbol 'rev')))))
2507 (symbol 'rev')))))
2478 * optimized:
2508 * optimized:
2479 (and
2509 (and
2480 (range
2510 (range
2481 (symbol '0')
2511 (symbol '0')
2482 (symbol '2'))
2512 (symbol '2'))
2483 (func
2513 (func
2484 (symbol 'sort')
2514 (symbol 'sort')
2485 (list
2515 (list
2486 (func
2516 (func
2487 (symbol 'all')
2517 (symbol 'all')
2488 None)
2518 None)
2489 (string '-rev'))))
2519 (string '-rev'))))
2490 * set:
2520 * set:
2491 <filteredset
2521 <filteredset
2492 <spanset+ 0:3>,
2522 <spanset+ 0:3>,
2493 <spanset+ 0:10>>
2523 <spanset+ 0:10>>
2494 0
2524 0
2495 1
2525 1
2496 2
2526 2
2497
2527
2498 invalid argument passed to noop sort():
2528 invalid argument passed to noop sort():
2499
2529
2500 $ log '0:2 & sort()'
2530 $ log '0:2 & sort()'
2501 hg: parse error: sort requires one or two arguments
2531 hg: parse error: sort requires one or two arguments
2502 [255]
2532 [255]
2503 $ log '0:2 & sort(all(), -invalid)'
2533 $ log '0:2 & sort(all(), -invalid)'
2504 hg: parse error: unknown sort key '-invalid'
2534 hg: parse error: unknown sort key '-invalid'
2505 [255]
2535 [255]
2506
2536
2507 for 'A & f(B)', 'B' should not be affected by the order of 'A':
2537 for 'A & f(B)', 'B' should not be affected by the order of 'A':
2508
2538
2509 $ try --optimize '2:0 & first(1 + 0 + 2)'
2539 $ try --optimize '2:0 & first(1 + 0 + 2)'
2510 (and
2540 (and
2511 (range
2541 (range
2512 (symbol '2')
2542 (symbol '2')
2513 (symbol '0'))
2543 (symbol '0'))
2514 (func
2544 (func
2515 (symbol 'first')
2545 (symbol 'first')
2516 (or
2546 (or
2517 (list
2547 (list
2518 (symbol '1')
2548 (symbol '1')
2519 (symbol '0')
2549 (symbol '0')
2520 (symbol '2')))))
2550 (symbol '2')))))
2521 * optimized:
2551 * optimized:
2522 (and
2552 (and
2523 (range
2553 (range
2524 (symbol '2')
2554 (symbol '2')
2525 (symbol '0'))
2555 (symbol '0'))
2526 (func
2556 (func
2527 (symbol 'first')
2557 (symbol 'first')
2528 (func
2558 (func
2529 (symbol '_list')
2559 (symbol '_list')
2530 (string '1\x000\x002'))))
2560 (string '1\x000\x002'))))
2531 * set:
2561 * set:
2532 <filteredset
2562 <filteredset
2533 <baseset [1]>,
2563 <baseset [1]>,
2534 <spanset- 0:3>>
2564 <spanset- 0:3>>
2535 1
2565 1
2536
2566
2537 $ try --optimize '2:0 & not last(0 + 2 + 1)'
2567 $ try --optimize '2:0 & not last(0 + 2 + 1)'
2538 (and
2568 (and
2539 (range
2569 (range
2540 (symbol '2')
2570 (symbol '2')
2541 (symbol '0'))
2571 (symbol '0'))
2542 (not
2572 (not
2543 (func
2573 (func
2544 (symbol 'last')
2574 (symbol 'last')
2545 (or
2575 (or
2546 (list
2576 (list
2547 (symbol '0')
2577 (symbol '0')
2548 (symbol '2')
2578 (symbol '2')
2549 (symbol '1'))))))
2579 (symbol '1'))))))
2550 * optimized:
2580 * optimized:
2551 (difference
2581 (difference
2552 (range
2582 (range
2553 (symbol '2')
2583 (symbol '2')
2554 (symbol '0'))
2584 (symbol '0'))
2555 (func
2585 (func
2556 (symbol 'last')
2586 (symbol 'last')
2557 (func
2587 (func
2558 (symbol '_list')
2588 (symbol '_list')
2559 (string '0\x002\x001'))))
2589 (string '0\x002\x001'))))
2560 * set:
2590 * set:
2561 <filteredset
2591 <filteredset
2562 <spanset- 0:3>,
2592 <spanset- 0:3>,
2563 <not
2593 <not
2564 <baseset [1]>>>
2594 <baseset [1]>>>
2565 2
2595 2
2566 0
2596 0
2567
2597
2568 for 'A & (op)(B)', 'B' should not be affected by the order of 'A':
2598 for 'A & (op)(B)', 'B' should not be affected by the order of 'A':
2569
2599
2570 $ try --optimize '2:0 & (1 + 0 + 2):(0 + 2 + 1)'
2600 $ try --optimize '2:0 & (1 + 0 + 2):(0 + 2 + 1)'
2571 (and
2601 (and
2572 (range
2602 (range
2573 (symbol '2')
2603 (symbol '2')
2574 (symbol '0'))
2604 (symbol '0'))
2575 (range
2605 (range
2576 (group
2606 (group
2577 (or
2607 (or
2578 (list
2608 (list
2579 (symbol '1')
2609 (symbol '1')
2580 (symbol '0')
2610 (symbol '0')
2581 (symbol '2'))))
2611 (symbol '2'))))
2582 (group
2612 (group
2583 (or
2613 (or
2584 (list
2614 (list
2585 (symbol '0')
2615 (symbol '0')
2586 (symbol '2')
2616 (symbol '2')
2587 (symbol '1'))))))
2617 (symbol '1'))))))
2588 * optimized:
2618 * optimized:
2589 (and
2619 (and
2590 (range
2620 (range
2591 (symbol '2')
2621 (symbol '2')
2592 (symbol '0'))
2622 (symbol '0'))
2593 (range
2623 (range
2594 (func
2624 (func
2595 (symbol '_list')
2625 (symbol '_list')
2596 (string '1\x000\x002'))
2626 (string '1\x000\x002'))
2597 (func
2627 (func
2598 (symbol '_list')
2628 (symbol '_list')
2599 (string '0\x002\x001'))))
2629 (string '0\x002\x001'))))
2600 * set:
2630 * set:
2601 <filteredset
2631 <filteredset
2602 <spanset- 0:3>,
2632 <spanset- 0:3>,
2603 <baseset [1]>>
2633 <baseset [1]>>
2604 1
2634 1
2605
2635
2606 'A & B' can be rewritten as 'flipand(B, A)' by weight.
2636 'A & B' can be rewritten as 'flipand(B, A)' by weight.
2607
2637
2608 $ try --optimize 'contains("glob:*") & (2 + 0 + 1)'
2638 $ try --optimize 'contains("glob:*") & (2 + 0 + 1)'
2609 (and
2639 (and
2610 (func
2640 (func
2611 (symbol 'contains')
2641 (symbol 'contains')
2612 (string 'glob:*'))
2642 (string 'glob:*'))
2613 (group
2643 (group
2614 (or
2644 (or
2615 (list
2645 (list
2616 (symbol '2')
2646 (symbol '2')
2617 (symbol '0')
2647 (symbol '0')
2618 (symbol '1')))))
2648 (symbol '1')))))
2619 * optimized:
2649 * optimized:
2620 (andsmally
2650 (andsmally
2621 (func
2651 (func
2622 (symbol 'contains')
2652 (symbol 'contains')
2623 (string 'glob:*'))
2653 (string 'glob:*'))
2624 (func
2654 (func
2625 (symbol '_list')
2655 (symbol '_list')
2626 (string '2\x000\x001')))
2656 (string '2\x000\x001')))
2627 * set:
2657 * set:
2628 <filteredset
2658 <filteredset
2629 <baseset+ [0, 1, 2]>,
2659 <baseset+ [0, 1, 2]>,
2630 <contains 'glob:*'>>
2660 <contains 'glob:*'>>
2631 0
2661 0
2632 1
2662 1
2633 2
2663 2
2634
2664
2635 and in this example, 'A & B' is rewritten as 'B & A', but 'A' overrides
2665 and in this example, 'A & B' is rewritten as 'B & A', but 'A' overrides
2636 the order appropriately:
2666 the order appropriately:
2637
2667
2638 $ try --optimize 'reverse(contains("glob:*")) & (0 + 2 + 1)'
2668 $ try --optimize 'reverse(contains("glob:*")) & (0 + 2 + 1)'
2639 (and
2669 (and
2640 (func
2670 (func
2641 (symbol 'reverse')
2671 (symbol 'reverse')
2642 (func
2672 (func
2643 (symbol 'contains')
2673 (symbol 'contains')
2644 (string 'glob:*')))
2674 (string 'glob:*')))
2645 (group
2675 (group
2646 (or
2676 (or
2647 (list
2677 (list
2648 (symbol '0')
2678 (symbol '0')
2649 (symbol '2')
2679 (symbol '2')
2650 (symbol '1')))))
2680 (symbol '1')))))
2651 * optimized:
2681 * optimized:
2652 (andsmally
2682 (andsmally
2653 (func
2683 (func
2654 (symbol 'reverse')
2684 (symbol 'reverse')
2655 (func
2685 (func
2656 (symbol 'contains')
2686 (symbol 'contains')
2657 (string 'glob:*')))
2687 (string 'glob:*')))
2658 (func
2688 (func
2659 (symbol '_list')
2689 (symbol '_list')
2660 (string '0\x002\x001')))
2690 (string '0\x002\x001')))
2661 * set:
2691 * set:
2662 <filteredset
2692 <filteredset
2663 <baseset- [0, 1, 2]>,
2693 <baseset- [0, 1, 2]>,
2664 <contains 'glob:*'>>
2694 <contains 'glob:*'>>
2665 2
2695 2
2666 1
2696 1
2667 0
2697 0
2668
2698
2669 test sort revset
2699 test sort revset
2670 --------------------------------------------
2700 --------------------------------------------
2671
2701
2672 test when adding two unordered revsets
2702 test when adding two unordered revsets
2673
2703
2674 $ log 'sort(keyword(issue) or modifies(b))'
2704 $ log 'sort(keyword(issue) or modifies(b))'
2675 4
2705 4
2676 6
2706 6
2677
2707
2678 test when sorting a reversed collection in the same way it is
2708 test when sorting a reversed collection in the same way it is
2679
2709
2680 $ log 'sort(reverse(all()), -rev)'
2710 $ log 'sort(reverse(all()), -rev)'
2681 9
2711 9
2682 8
2712 8
2683 7
2713 7
2684 6
2714 6
2685 5
2715 5
2686 4
2716 4
2687 3
2717 3
2688 2
2718 2
2689 1
2719 1
2690 0
2720 0
2691
2721
2692 test when sorting a reversed collection
2722 test when sorting a reversed collection
2693
2723
2694 $ log 'sort(reverse(all()), rev)'
2724 $ log 'sort(reverse(all()), rev)'
2695 0
2725 0
2696 1
2726 1
2697 2
2727 2
2698 3
2728 3
2699 4
2729 4
2700 5
2730 5
2701 6
2731 6
2702 7
2732 7
2703 8
2733 8
2704 9
2734 9
2705
2735
2706
2736
2707 test sorting two sorted collections in different orders
2737 test sorting two sorted collections in different orders
2708
2738
2709 $ log 'sort(outgoing() or reverse(removes(a)), rev)'
2739 $ log 'sort(outgoing() or reverse(removes(a)), rev)'
2710 2
2740 2
2711 8
2741 8
2712 9
2742 9
2713
2743
2714 test sorting two sorted collections in different orders backwards
2744 test sorting two sorted collections in different orders backwards
2715
2745
2716 $ log 'sort(outgoing() or reverse(removes(a)), -rev)'
2746 $ log 'sort(outgoing() or reverse(removes(a)), -rev)'
2717 9
2747 9
2718 8
2748 8
2719 2
2749 2
2720
2750
2721 test empty sort key which is noop
2751 test empty sort key which is noop
2722
2752
2723 $ log 'sort(0 + 2 + 1, "")'
2753 $ log 'sort(0 + 2 + 1, "")'
2724 0
2754 0
2725 2
2755 2
2726 1
2756 1
2727
2757
2728 test invalid sort keys
2758 test invalid sort keys
2729
2759
2730 $ log 'sort(all(), -invalid)'
2760 $ log 'sort(all(), -invalid)'
2731 hg: parse error: unknown sort key '-invalid'
2761 hg: parse error: unknown sort key '-invalid'
2732 [255]
2762 [255]
2733
2763
2734 $ cd ..
2764 $ cd ..
2735
2765
2736 test sorting by multiple keys including variable-length strings
2766 test sorting by multiple keys including variable-length strings
2737
2767
2738 $ hg init sorting
2768 $ hg init sorting
2739 $ cd sorting
2769 $ cd sorting
2740 $ cat <<EOF >> .hg/hgrc
2770 $ cat <<EOF >> .hg/hgrc
2741 > [ui]
2771 > [ui]
2742 > logtemplate = '{rev} {branch|p5}{desc|p5}{author|p5}{date|hgdate}\n'
2772 > logtemplate = '{rev} {branch|p5}{desc|p5}{author|p5}{date|hgdate}\n'
2743 > [templatealias]
2773 > [templatealias]
2744 > p5(s) = pad(s, 5)
2774 > p5(s) = pad(s, 5)
2745 > EOF
2775 > EOF
2746 $ hg branch -qf b12
2776 $ hg branch -qf b12
2747 $ hg ci -m m111 -u u112 -d '111 10800'
2777 $ hg ci -m m111 -u u112 -d '111 10800'
2748 $ hg branch -qf b11
2778 $ hg branch -qf b11
2749 $ hg ci -m m12 -u u111 -d '112 7200'
2779 $ hg ci -m m12 -u u111 -d '112 7200'
2750 $ hg branch -qf b111
2780 $ hg branch -qf b111
2751 $ hg ci -m m11 -u u12 -d '111 3600'
2781 $ hg ci -m m11 -u u12 -d '111 3600'
2752 $ hg branch -qf b112
2782 $ hg branch -qf b112
2753 $ hg ci -m m111 -u u11 -d '120 0'
2783 $ hg ci -m m111 -u u11 -d '120 0'
2754 $ hg branch -qf b111
2784 $ hg branch -qf b111
2755 $ hg ci -m m112 -u u111 -d '110 14400'
2785 $ hg ci -m m112 -u u111 -d '110 14400'
2756 created new head
2786 created new head
2757
2787
2758 compare revisions (has fast path):
2788 compare revisions (has fast path):
2759
2789
2760 $ hg log -r 'sort(all(), rev)'
2790 $ hg log -r 'sort(all(), rev)'
2761 0 b12 m111 u112 111 10800
2791 0 b12 m111 u112 111 10800
2762 1 b11 m12 u111 112 7200
2792 1 b11 m12 u111 112 7200
2763 2 b111 m11 u12 111 3600
2793 2 b111 m11 u12 111 3600
2764 3 b112 m111 u11 120 0
2794 3 b112 m111 u11 120 0
2765 4 b111 m112 u111 110 14400
2795 4 b111 m112 u111 110 14400
2766
2796
2767 $ hg log -r 'sort(all(), -rev)'
2797 $ hg log -r 'sort(all(), -rev)'
2768 4 b111 m112 u111 110 14400
2798 4 b111 m112 u111 110 14400
2769 3 b112 m111 u11 120 0
2799 3 b112 m111 u11 120 0
2770 2 b111 m11 u12 111 3600
2800 2 b111 m11 u12 111 3600
2771 1 b11 m12 u111 112 7200
2801 1 b11 m12 u111 112 7200
2772 0 b12 m111 u112 111 10800
2802 0 b12 m111 u112 111 10800
2773
2803
2774 compare variable-length strings (issue5218):
2804 compare variable-length strings (issue5218):
2775
2805
2776 $ hg log -r 'sort(all(), branch)'
2806 $ hg log -r 'sort(all(), branch)'
2777 1 b11 m12 u111 112 7200
2807 1 b11 m12 u111 112 7200
2778 2 b111 m11 u12 111 3600
2808 2 b111 m11 u12 111 3600
2779 4 b111 m112 u111 110 14400
2809 4 b111 m112 u111 110 14400
2780 3 b112 m111 u11 120 0
2810 3 b112 m111 u11 120 0
2781 0 b12 m111 u112 111 10800
2811 0 b12 m111 u112 111 10800
2782
2812
2783 $ hg log -r 'sort(all(), -branch)'
2813 $ hg log -r 'sort(all(), -branch)'
2784 0 b12 m111 u112 111 10800
2814 0 b12 m111 u112 111 10800
2785 3 b112 m111 u11 120 0
2815 3 b112 m111 u11 120 0
2786 2 b111 m11 u12 111 3600
2816 2 b111 m11 u12 111 3600
2787 4 b111 m112 u111 110 14400
2817 4 b111 m112 u111 110 14400
2788 1 b11 m12 u111 112 7200
2818 1 b11 m12 u111 112 7200
2789
2819
2790 $ hg log -r 'sort(all(), desc)'
2820 $ hg log -r 'sort(all(), desc)'
2791 2 b111 m11 u12 111 3600
2821 2 b111 m11 u12 111 3600
2792 0 b12 m111 u112 111 10800
2822 0 b12 m111 u112 111 10800
2793 3 b112 m111 u11 120 0
2823 3 b112 m111 u11 120 0
2794 4 b111 m112 u111 110 14400
2824 4 b111 m112 u111 110 14400
2795 1 b11 m12 u111 112 7200
2825 1 b11 m12 u111 112 7200
2796
2826
2797 $ hg log -r 'sort(all(), -desc)'
2827 $ hg log -r 'sort(all(), -desc)'
2798 1 b11 m12 u111 112 7200
2828 1 b11 m12 u111 112 7200
2799 4 b111 m112 u111 110 14400
2829 4 b111 m112 u111 110 14400
2800 0 b12 m111 u112 111 10800
2830 0 b12 m111 u112 111 10800
2801 3 b112 m111 u11 120 0
2831 3 b112 m111 u11 120 0
2802 2 b111 m11 u12 111 3600
2832 2 b111 m11 u12 111 3600
2803
2833
2804 $ hg log -r 'sort(all(), user)'
2834 $ hg log -r 'sort(all(), user)'
2805 3 b112 m111 u11 120 0
2835 3 b112 m111 u11 120 0
2806 1 b11 m12 u111 112 7200
2836 1 b11 m12 u111 112 7200
2807 4 b111 m112 u111 110 14400
2837 4 b111 m112 u111 110 14400
2808 0 b12 m111 u112 111 10800
2838 0 b12 m111 u112 111 10800
2809 2 b111 m11 u12 111 3600
2839 2 b111 m11 u12 111 3600
2810
2840
2811 $ hg log -r 'sort(all(), -user)'
2841 $ hg log -r 'sort(all(), -user)'
2812 2 b111 m11 u12 111 3600
2842 2 b111 m11 u12 111 3600
2813 0 b12 m111 u112 111 10800
2843 0 b12 m111 u112 111 10800
2814 1 b11 m12 u111 112 7200
2844 1 b11 m12 u111 112 7200
2815 4 b111 m112 u111 110 14400
2845 4 b111 m112 u111 110 14400
2816 3 b112 m111 u11 120 0
2846 3 b112 m111 u11 120 0
2817
2847
2818 compare dates (tz offset should have no effect):
2848 compare dates (tz offset should have no effect):
2819
2849
2820 $ hg log -r 'sort(all(), date)'
2850 $ hg log -r 'sort(all(), date)'
2821 4 b111 m112 u111 110 14400
2851 4 b111 m112 u111 110 14400
2822 0 b12 m111 u112 111 10800
2852 0 b12 m111 u112 111 10800
2823 2 b111 m11 u12 111 3600
2853 2 b111 m11 u12 111 3600
2824 1 b11 m12 u111 112 7200
2854 1 b11 m12 u111 112 7200
2825 3 b112 m111 u11 120 0
2855 3 b112 m111 u11 120 0
2826
2856
2827 $ hg log -r 'sort(all(), -date)'
2857 $ hg log -r 'sort(all(), -date)'
2828 3 b112 m111 u11 120 0
2858 3 b112 m111 u11 120 0
2829 1 b11 m12 u111 112 7200
2859 1 b11 m12 u111 112 7200
2830 0 b12 m111 u112 111 10800
2860 0 b12 m111 u112 111 10800
2831 2 b111 m11 u12 111 3600
2861 2 b111 m11 u12 111 3600
2832 4 b111 m112 u111 110 14400
2862 4 b111 m112 u111 110 14400
2833
2863
2834 be aware that 'sort(x, -k)' is not exactly the same as 'reverse(sort(x, k))'
2864 be aware that 'sort(x, -k)' is not exactly the same as 'reverse(sort(x, k))'
2835 because '-k' reverses the comparison, not the list itself:
2865 because '-k' reverses the comparison, not the list itself:
2836
2866
2837 $ hg log -r 'sort(0 + 2, date)'
2867 $ hg log -r 'sort(0 + 2, date)'
2838 0 b12 m111 u112 111 10800
2868 0 b12 m111 u112 111 10800
2839 2 b111 m11 u12 111 3600
2869 2 b111 m11 u12 111 3600
2840
2870
2841 $ hg log -r 'sort(0 + 2, -date)'
2871 $ hg log -r 'sort(0 + 2, -date)'
2842 0 b12 m111 u112 111 10800
2872 0 b12 m111 u112 111 10800
2843 2 b111 m11 u12 111 3600
2873 2 b111 m11 u12 111 3600
2844
2874
2845 $ hg log -r 'reverse(sort(0 + 2, date))'
2875 $ hg log -r 'reverse(sort(0 + 2, date))'
2846 2 b111 m11 u12 111 3600
2876 2 b111 m11 u12 111 3600
2847 0 b12 m111 u112 111 10800
2877 0 b12 m111 u112 111 10800
2848
2878
2849 sort by multiple keys:
2879 sort by multiple keys:
2850
2880
2851 $ hg log -r 'sort(all(), "branch -rev")'
2881 $ hg log -r 'sort(all(), "branch -rev")'
2852 1 b11 m12 u111 112 7200
2882 1 b11 m12 u111 112 7200
2853 4 b111 m112 u111 110 14400
2883 4 b111 m112 u111 110 14400
2854 2 b111 m11 u12 111 3600
2884 2 b111 m11 u12 111 3600
2855 3 b112 m111 u11 120 0
2885 3 b112 m111 u11 120 0
2856 0 b12 m111 u112 111 10800
2886 0 b12 m111 u112 111 10800
2857
2887
2858 $ hg log -r 'sort(all(), "-desc -date")'
2888 $ hg log -r 'sort(all(), "-desc -date")'
2859 1 b11 m12 u111 112 7200
2889 1 b11 m12 u111 112 7200
2860 4 b111 m112 u111 110 14400
2890 4 b111 m112 u111 110 14400
2861 3 b112 m111 u11 120 0
2891 3 b112 m111 u11 120 0
2862 0 b12 m111 u112 111 10800
2892 0 b12 m111 u112 111 10800
2863 2 b111 m11 u12 111 3600
2893 2 b111 m11 u12 111 3600
2864
2894
2865 $ hg log -r 'sort(all(), "user -branch date rev")'
2895 $ hg log -r 'sort(all(), "user -branch date rev")'
2866 3 b112 m111 u11 120 0
2896 3 b112 m111 u11 120 0
2867 4 b111 m112 u111 110 14400
2897 4 b111 m112 u111 110 14400
2868 1 b11 m12 u111 112 7200
2898 1 b11 m12 u111 112 7200
2869 0 b12 m111 u112 111 10800
2899 0 b12 m111 u112 111 10800
2870 2 b111 m11 u12 111 3600
2900 2 b111 m11 u12 111 3600
2871
2901
2872 toposort prioritises graph branches
2902 toposort prioritises graph branches
2873
2903
2874 $ hg up 2
2904 $ hg up 2
2875 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
2905 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
2876 $ touch a
2906 $ touch a
2877 $ hg addremove
2907 $ hg addremove
2878 adding a
2908 adding a
2879 $ hg ci -m 't1' -u 'tu' -d '130 0'
2909 $ hg ci -m 't1' -u 'tu' -d '130 0'
2880 created new head
2910 created new head
2881 $ echo 'a' >> a
2911 $ echo 'a' >> a
2882 $ hg ci -m 't2' -u 'tu' -d '130 0'
2912 $ hg ci -m 't2' -u 'tu' -d '130 0'
2883 $ hg book book1
2913 $ hg book book1
2884 $ hg up 4
2914 $ hg up 4
2885 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
2915 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
2886 (leaving bookmark book1)
2916 (leaving bookmark book1)
2887 $ touch a
2917 $ touch a
2888 $ hg addremove
2918 $ hg addremove
2889 adding a
2919 adding a
2890 $ hg ci -m 't3' -u 'tu' -d '130 0'
2920 $ hg ci -m 't3' -u 'tu' -d '130 0'
2891
2921
2892 $ hg log -r 'sort(all(), topo)'
2922 $ hg log -r 'sort(all(), topo)'
2893 7 b111 t3 tu 130 0
2923 7 b111 t3 tu 130 0
2894 4 b111 m112 u111 110 14400
2924 4 b111 m112 u111 110 14400
2895 3 b112 m111 u11 120 0
2925 3 b112 m111 u11 120 0
2896 6 b111 t2 tu 130 0
2926 6 b111 t2 tu 130 0
2897 5 b111 t1 tu 130 0
2927 5 b111 t1 tu 130 0
2898 2 b111 m11 u12 111 3600
2928 2 b111 m11 u12 111 3600
2899 1 b11 m12 u111 112 7200
2929 1 b11 m12 u111 112 7200
2900 0 b12 m111 u112 111 10800
2930 0 b12 m111 u112 111 10800
2901
2931
2902 $ hg log -r 'sort(all(), -topo)'
2932 $ hg log -r 'sort(all(), -topo)'
2903 0 b12 m111 u112 111 10800
2933 0 b12 m111 u112 111 10800
2904 1 b11 m12 u111 112 7200
2934 1 b11 m12 u111 112 7200
2905 2 b111 m11 u12 111 3600
2935 2 b111 m11 u12 111 3600
2906 5 b111 t1 tu 130 0
2936 5 b111 t1 tu 130 0
2907 6 b111 t2 tu 130 0
2937 6 b111 t2 tu 130 0
2908 3 b112 m111 u11 120 0
2938 3 b112 m111 u11 120 0
2909 4 b111 m112 u111 110 14400
2939 4 b111 m112 u111 110 14400
2910 7 b111 t3 tu 130 0
2940 7 b111 t3 tu 130 0
2911
2941
2912 $ hg log -r 'sort(all(), topo, topo.firstbranch=book1)'
2942 $ hg log -r 'sort(all(), topo, topo.firstbranch=book1)'
2913 6 b111 t2 tu 130 0
2943 6 b111 t2 tu 130 0
2914 5 b111 t1 tu 130 0
2944 5 b111 t1 tu 130 0
2915 7 b111 t3 tu 130 0
2945 7 b111 t3 tu 130 0
2916 4 b111 m112 u111 110 14400
2946 4 b111 m112 u111 110 14400
2917 3 b112 m111 u11 120 0
2947 3 b112 m111 u11 120 0
2918 2 b111 m11 u12 111 3600
2948 2 b111 m11 u12 111 3600
2919 1 b11 m12 u111 112 7200
2949 1 b11 m12 u111 112 7200
2920 0 b12 m111 u112 111 10800
2950 0 b12 m111 u112 111 10800
2921
2951
2922 topographical sorting can't be combined with other sort keys, and you can't
2952 topographical sorting can't be combined with other sort keys, and you can't
2923 use the topo.firstbranch option when topo sort is not active:
2953 use the topo.firstbranch option when topo sort is not active:
2924
2954
2925 $ hg log -r 'sort(all(), "topo user")'
2955 $ hg log -r 'sort(all(), "topo user")'
2926 hg: parse error: topo sort order cannot be combined with other sort keys
2956 hg: parse error: topo sort order cannot be combined with other sort keys
2927 [255]
2957 [255]
2928
2958
2929 $ hg log -r 'sort(all(), user, topo.firstbranch=book1)'
2959 $ hg log -r 'sort(all(), user, topo.firstbranch=book1)'
2930 hg: parse error: topo.firstbranch can only be used when using the topo sort key
2960 hg: parse error: topo.firstbranch can only be used when using the topo sort key
2931 [255]
2961 [255]
2932
2962
2933 topo.firstbranch should accept any kind of expressions:
2963 topo.firstbranch should accept any kind of expressions:
2934
2964
2935 $ hg log -r 'sort(0, topo, topo.firstbranch=(book1))'
2965 $ hg log -r 'sort(0, topo, topo.firstbranch=(book1))'
2936 0 b12 m111 u112 111 10800
2966 0 b12 m111 u112 111 10800
2937
2967
2938 $ cd ..
2968 $ cd ..
2939 $ cd repo
2969 $ cd repo
2940
2970
2941 test multiline revset with errors
2971 test multiline revset with errors
2942
2972
2943 $ echo > multiline-revset
2973 $ echo > multiline-revset
2944 $ echo '. +' >> multiline-revset
2974 $ echo '. +' >> multiline-revset
2945 $ echo '.^ +' >> multiline-revset
2975 $ echo '.^ +' >> multiline-revset
2946 $ hg log -r "`cat multiline-revset`"
2976 $ hg log -r "`cat multiline-revset`"
2947 hg: parse error at 9: not a prefix: end
2977 hg: parse error at 9: not a prefix: end
2948 ( . + .^ +
2978 ( . + .^ +
2949 ^ here)
2979 ^ here)
2950 [255]
2980 [255]
2951 $ hg debugrevspec -v 'revset(first(rev(0)))' -p all
2981 $ hg debugrevspec -v 'revset(first(rev(0)))' -p all
2952 * parsed:
2982 * parsed:
2953 (func
2983 (func
2954 (symbol 'revset')
2984 (symbol 'revset')
2955 (func
2985 (func
2956 (symbol 'first')
2986 (symbol 'first')
2957 (func
2987 (func
2958 (symbol 'rev')
2988 (symbol 'rev')
2959 (symbol '0'))))
2989 (symbol '0'))))
2960 * expanded:
2990 * expanded:
2961 (func
2991 (func
2962 (symbol 'revset')
2992 (symbol 'revset')
2963 (func
2993 (func
2964 (symbol 'first')
2994 (symbol 'first')
2965 (func
2995 (func
2966 (symbol 'rev')
2996 (symbol 'rev')
2967 (symbol '0'))))
2997 (symbol '0'))))
2968 * concatenated:
2998 * concatenated:
2969 (func
2999 (func
2970 (symbol 'revset')
3000 (symbol 'revset')
2971 (func
3001 (func
2972 (symbol 'first')
3002 (symbol 'first')
2973 (func
3003 (func
2974 (symbol 'rev')
3004 (symbol 'rev')
2975 (symbol '0'))))
3005 (symbol '0'))))
2976 * analyzed:
3006 * analyzed:
2977 (func
3007 (func
2978 (symbol 'revset')
3008 (symbol 'revset')
2979 (func
3009 (func
2980 (symbol 'first')
3010 (symbol 'first')
2981 (func
3011 (func
2982 (symbol 'rev')
3012 (symbol 'rev')
2983 (symbol '0'))))
3013 (symbol '0'))))
2984 * optimized:
3014 * optimized:
2985 (func
3015 (func
2986 (symbol 'revset')
3016 (symbol 'revset')
2987 (func
3017 (func
2988 (symbol 'first')
3018 (symbol 'first')
2989 (func
3019 (func
2990 (symbol 'rev')
3020 (symbol 'rev')
2991 (symbol '0'))))
3021 (symbol '0'))))
2992 * set:
3022 * set:
2993 <baseset+ [0]>
3023 <baseset+ [0]>
2994 0
3024 0
2995
3025
2996 abort if the revset doesn't expect given size
3026 abort if the revset doesn't expect given size
2997 $ log 'expectsize()'
3027 $ log 'expectsize()'
2998 hg: parse error: invalid set of arguments
3028 hg: parse error: invalid set of arguments
2999 [255]
3029 [255]
3000 $ log 'expectsize(0:2, a)'
3030 $ log 'expectsize(0:2, a)'
3001 hg: parse error: expectsize requires a size range or a positive integer
3031 hg: parse error: expectsize requires a size range or a positive integer
3002 [255]
3032 [255]
3003 $ log 'expectsize(0:2, 3)'
3033 $ log 'expectsize(0:2, 3)'
3004 0
3034 0
3005 1
3035 1
3006 2
3036 2
3007
3037
3008 $ log 'expectsize(2:0, 3)'
3038 $ log 'expectsize(2:0, 3)'
3009 2
3039 2
3010 1
3040 1
3011 0
3041 0
3012 $ log 'expectsize(0:1, 1)'
3042 $ log 'expectsize(0:1, 1)'
3013 abort: revset size mismatch. expected 1, got 2!
3043 abort: revset size mismatch. expected 1, got 2!
3014 [255]
3044 [255]
3015 $ log 'expectsize(0:4, -1)'
3045 $ log 'expectsize(0:4, -1)'
3016 hg: parse error: negative size
3046 hg: parse error: negative size
3017 [255]
3047 [255]
3018 $ log 'expectsize(0:2, 2:4)'
3048 $ log 'expectsize(0:2, 2:4)'
3019 0
3049 0
3020 1
3050 1
3021 2
3051 2
3022 $ log 'expectsize(0:1, 3:5)'
3052 $ log 'expectsize(0:1, 3:5)'
3023 abort: revset size mismatch. expected between 3 and 5, got 2!
3053 abort: revset size mismatch. expected between 3 and 5, got 2!
3024 [255]
3054 [255]
3025 $ log 'expectsize(0:1, -1:2)'
3055 $ log 'expectsize(0:1, -1:2)'
3026 hg: parse error: negative size
3056 hg: parse error: negative size
3027 [255]
3057 [255]
3028 $ log 'expectsize(0:1, 1:-2)'
3058 $ log 'expectsize(0:1, 1:-2)'
3029 hg: parse error: negative size
3059 hg: parse error: negative size
3030 [255]
3060 [255]
3031 $ log 'expectsize(0:2, a:4)'
3061 $ log 'expectsize(0:2, a:4)'
3032 hg: parse error: size range bounds must be integers
3062 hg: parse error: size range bounds must be integers
3033 [255]
3063 [255]
3034 $ log 'expectsize(0:2, 2:b)'
3064 $ log 'expectsize(0:2, 2:b)'
3035 hg: parse error: size range bounds must be integers
3065 hg: parse error: size range bounds must be integers
3036 [255]
3066 [255]
3037 $ log 'expectsize(0:2, 2:)'
3067 $ log 'expectsize(0:2, 2:)'
3038 0
3068 0
3039 1
3069 1
3040 2
3070 2
3041 $ log 'expectsize(0:2, :5)'
3071 $ log 'expectsize(0:2, :5)'
3042 0
3072 0
3043 1
3073 1
3044 2
3074 2
3045 $ log 'expectsize(0:2, :)'
3075 $ log 'expectsize(0:2, :)'
3046 0
3076 0
3047 1
3077 1
3048 2
3078 2
3049 $ log 'expectsize(0:2, 4:)'
3079 $ log 'expectsize(0:2, 4:)'
3050 abort: revset size mismatch. expected between 4 and 11, got 3!
3080 abort: revset size mismatch. expected between 4 and 11, got 3!
3051 [255]
3081 [255]
3052 $ log 'expectsize(0:2, :2)'
3082 $ log 'expectsize(0:2, :2)'
3053 abort: revset size mismatch. expected between 0 and 2, got 3!
3083 abort: revset size mismatch. expected between 0 and 2, got 3!
3054 [255]
3084 [255]
General Comments 0
You need to be logged in to leave comments. Login now