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