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