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