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