##// END OF EJS Templates
revset: remove order information from tree (API)...
Jun Wu -
r34013:1b28525e default
parent child Browse files
Show More
@@ -1,2141 +1,2154
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 encoding,
16 encoding,
17 error,
17 error,
18 hbisect,
18 hbisect,
19 match as matchmod,
19 match as matchmod,
20 node,
20 node,
21 obsolete as obsmod,
21 obsolete as obsmod,
22 obsutil,
22 obsutil,
23 pathutil,
23 pathutil,
24 phases,
24 phases,
25 registrar,
25 registrar,
26 repoview,
26 repoview,
27 revsetlang,
27 revsetlang,
28 scmutil,
28 scmutil,
29 smartset,
29 smartset,
30 util,
30 util,
31 )
31 )
32
32
33 # helpers for processing parsed tree
33 # helpers for processing parsed tree
34 getsymbol = revsetlang.getsymbol
34 getsymbol = revsetlang.getsymbol
35 getstring = revsetlang.getstring
35 getstring = revsetlang.getstring
36 getinteger = revsetlang.getinteger
36 getinteger = revsetlang.getinteger
37 getboolean = revsetlang.getboolean
37 getboolean = revsetlang.getboolean
38 getlist = revsetlang.getlist
38 getlist = revsetlang.getlist
39 getrange = revsetlang.getrange
39 getrange = revsetlang.getrange
40 getargs = revsetlang.getargs
40 getargs = revsetlang.getargs
41 getargsdict = revsetlang.getargsdict
41 getargsdict = revsetlang.getargsdict
42
42
43 # constants used as an argument of match() and matchany()
43 # constants used as an argument of match() and matchany()
44 anyorder = revsetlang.anyorder
44 anyorder = revsetlang.anyorder
45 defineorder = revsetlang.defineorder
45 defineorder = revsetlang.defineorder
46 followorder = revsetlang.followorder
46 followorder = revsetlang.followorder
47
47
48 baseset = smartset.baseset
48 baseset = smartset.baseset
49 generatorset = smartset.generatorset
49 generatorset = smartset.generatorset
50 spanset = smartset.spanset
50 spanset = smartset.spanset
51 fullreposet = smartset.fullreposet
51 fullreposet = smartset.fullreposet
52
52
53 # helpers
53 # helpers
54
54
55 def getset(repo, subset, x):
55 def getset(repo, subset, x, order=defineorder):
56 if not x:
56 if not x:
57 raise error.ParseError(_("missing argument"))
57 raise error.ParseError(_("missing argument"))
58 return methods[x[0]](repo, subset, *x[1:])
58 return methods[x[0]](repo, subset, *x[1:], order=order)
59
59
60 def _getrevsource(repo, r):
60 def _getrevsource(repo, r):
61 extra = repo[r].extra()
61 extra = repo[r].extra()
62 for label in ('source', 'transplant_source', 'rebase_source'):
62 for label in ('source', 'transplant_source', 'rebase_source'):
63 if label in extra:
63 if label in extra:
64 try:
64 try:
65 return repo[extra[label]].rev()
65 return repo[extra[label]].rev()
66 except error.RepoLookupError:
66 except error.RepoLookupError:
67 pass
67 pass
68 return None
68 return None
69
69
70 # operator methods
70 # operator methods
71
71
72 def stringset(repo, subset, x):
72 def stringset(repo, subset, x, order):
73 x = scmutil.intrev(repo[x])
73 x = scmutil.intrev(repo[x])
74 if (x in subset
74 if (x in subset
75 or x == node.nullrev and isinstance(subset, fullreposet)):
75 or x == node.nullrev and isinstance(subset, fullreposet)):
76 return baseset([x])
76 return baseset([x])
77 return baseset()
77 return baseset()
78
78
79 def rangeset(repo, subset, x, y, order):
79 def rangeset(repo, subset, x, y, order):
80 m = getset(repo, fullreposet(repo), x)
80 m = getset(repo, fullreposet(repo), x)
81 n = getset(repo, fullreposet(repo), y)
81 n = getset(repo, fullreposet(repo), y)
82
82
83 if not m or not n:
83 if not m or not n:
84 return baseset()
84 return baseset()
85 return _makerangeset(repo, subset, m.first(), n.last(), order)
85 return _makerangeset(repo, subset, m.first(), n.last(), order)
86
86
87 def rangeall(repo, subset, x, order):
87 def rangeall(repo, subset, x, order):
88 assert x is None
88 assert x is None
89 return _makerangeset(repo, subset, 0, len(repo) - 1, order)
89 return _makerangeset(repo, subset, 0, len(repo) - 1, order)
90
90
91 def rangepre(repo, subset, y, order):
91 def rangepre(repo, subset, y, order):
92 # ':y' can't be rewritten to '0:y' since '0' may be hidden
92 # ':y' can't be rewritten to '0:y' since '0' may be hidden
93 n = getset(repo, fullreposet(repo), y)
93 n = getset(repo, fullreposet(repo), y)
94 if not n:
94 if not n:
95 return baseset()
95 return baseset()
96 return _makerangeset(repo, subset, 0, n.last(), order)
96 return _makerangeset(repo, subset, 0, n.last(), order)
97
97
98 def rangepost(repo, subset, x, order):
98 def rangepost(repo, subset, x, order):
99 m = getset(repo, fullreposet(repo), x)
99 m = getset(repo, fullreposet(repo), x)
100 if not m:
100 if not m:
101 return baseset()
101 return baseset()
102 return _makerangeset(repo, subset, m.first(), len(repo) - 1, order)
102 return _makerangeset(repo, subset, m.first(), len(repo) - 1, order)
103
103
104 def _makerangeset(repo, subset, m, n, order):
104 def _makerangeset(repo, subset, m, n, order):
105 if m == n:
105 if m == n:
106 r = baseset([m])
106 r = baseset([m])
107 elif n == node.wdirrev:
107 elif n == node.wdirrev:
108 r = spanset(repo, m, len(repo)) + baseset([n])
108 r = spanset(repo, m, len(repo)) + baseset([n])
109 elif m == node.wdirrev:
109 elif m == node.wdirrev:
110 r = baseset([m]) + spanset(repo, len(repo) - 1, n - 1)
110 r = baseset([m]) + spanset(repo, len(repo) - 1, n - 1)
111 elif m < n:
111 elif m < n:
112 r = spanset(repo, m, n + 1)
112 r = spanset(repo, m, n + 1)
113 else:
113 else:
114 r = spanset(repo, m, n - 1)
114 r = spanset(repo, m, n - 1)
115
115
116 if order == defineorder:
116 if order == defineorder:
117 return r & subset
117 return r & subset
118 else:
118 else:
119 # carrying the sorting over when possible would be more efficient
119 # carrying the sorting over when possible would be more efficient
120 return subset & r
120 return subset & r
121
121
122 def dagrange(repo, subset, x, y, order):
122 def dagrange(repo, subset, x, y, order):
123 r = fullreposet(repo)
123 r = fullreposet(repo)
124 xs = dagop.reachableroots(repo, getset(repo, r, x), getset(repo, r, y),
124 xs = dagop.reachableroots(repo, getset(repo, r, x), getset(repo, r, y),
125 includepath=True)
125 includepath=True)
126 return subset & xs
126 return subset & xs
127
127
128 def andset(repo, subset, x, y, order):
128 def andset(repo, subset, x, y, order):
129 return getset(repo, getset(repo, subset, x), y)
129 if order == anyorder:
130 yorder = anyorder
131 else:
132 yorder = followorder
133 return getset(repo, getset(repo, subset, x, order), y, yorder)
134
135 def flipandset(repo, subset, y, x, order):
136 # 'flipand(y, x)' is equivalent to 'and(x, y)', but faster when y is small
137 if order == anyorder:
138 yorder = anyorder
139 else:
140 yorder = followorder
141 return getset(repo, getset(repo, subset, y, yorder), x, order)
130
142
131 def differenceset(repo, subset, x, y, order):
143 def differenceset(repo, subset, x, y, order):
132 return getset(repo, subset, x) - getset(repo, subset, y)
144 return getset(repo, subset, x, order) - getset(repo, subset, y, anyorder)
133
145
134 def _orsetlist(repo, subset, xs):
146 def _orsetlist(repo, subset, xs, order):
135 assert xs
147 assert xs
136 if len(xs) == 1:
148 if len(xs) == 1:
137 return getset(repo, subset, xs[0])
149 return getset(repo, subset, xs[0], order)
138 p = len(xs) // 2
150 p = len(xs) // 2
139 a = _orsetlist(repo, subset, xs[:p])
151 a = _orsetlist(repo, subset, xs[:p], order)
140 b = _orsetlist(repo, subset, xs[p:])
152 b = _orsetlist(repo, subset, xs[p:], order)
141 return a + b
153 return a + b
142
154
143 def orset(repo, subset, x, order):
155 def orset(repo, subset, x, order):
144 xs = getlist(x)
156 xs = getlist(x)
145 if order == followorder:
157 if order == followorder:
146 # slow path to take the subset order
158 # slow path to take the subset order
147 return subset & _orsetlist(repo, fullreposet(repo), xs)
159 return subset & _orsetlist(repo, fullreposet(repo), xs, anyorder)
148 else:
160 else:
149 return _orsetlist(repo, subset, xs)
161 return _orsetlist(repo, subset, xs, order)
150
162
151 def notset(repo, subset, x, order):
163 def notset(repo, subset, x, order):
152 return subset - getset(repo, subset, x)
164 return subset - getset(repo, subset, x, anyorder)
153
165
154 def relationset(repo, subset, x, y, order):
166 def relationset(repo, subset, x, y, order):
155 raise error.ParseError(_("can't use a relation in this context"))
167 raise error.ParseError(_("can't use a relation in this context"))
156
168
157 def relsubscriptset(repo, subset, x, y, z, order):
169 def relsubscriptset(repo, subset, x, y, z, order):
158 # this is pretty basic implementation of 'x#y[z]' operator, still
170 # this is pretty basic implementation of 'x#y[z]' operator, still
159 # experimental so undocumented. see the wiki for further ideas.
171 # experimental so undocumented. see the wiki for further ideas.
160 # https://www.mercurial-scm.org/wiki/RevsetOperatorPlan
172 # https://www.mercurial-scm.org/wiki/RevsetOperatorPlan
161 rel = getsymbol(y)
173 rel = getsymbol(y)
162 n = getinteger(z, _("relation subscript must be an integer"))
174 n = getinteger(z, _("relation subscript must be an integer"))
163
175
164 # TODO: perhaps this should be a table of relation functions
176 # TODO: perhaps this should be a table of relation functions
165 if rel in ('g', 'generations'):
177 if rel in ('g', 'generations'):
166 # TODO: support range, rewrite tests, and drop startdepth argument
178 # TODO: support range, rewrite tests, and drop startdepth argument
167 # from ancestors() and descendants() predicates
179 # from ancestors() and descendants() predicates
168 if n <= 0:
180 if n <= 0:
169 n = -n
181 n = -n
170 return _ancestors(repo, subset, x, startdepth=n, stopdepth=n + 1)
182 return _ancestors(repo, subset, x, startdepth=n, stopdepth=n + 1)
171 else:
183 else:
172 return _descendants(repo, subset, x, startdepth=n, stopdepth=n + 1)
184 return _descendants(repo, subset, x, startdepth=n, stopdepth=n + 1)
173
185
174 raise error.UnknownIdentifier(rel, ['generations'])
186 raise error.UnknownIdentifier(rel, ['generations'])
175
187
176 def subscriptset(repo, subset, x, y, order):
188 def subscriptset(repo, subset, x, y, order):
177 raise error.ParseError(_("can't use a subscript in this context"))
189 raise error.ParseError(_("can't use a subscript in this context"))
178
190
179 def listset(repo, subset, *xs):
191 def listset(repo, subset, *xs, **opts):
180 raise error.ParseError(_("can't use a list in this context"),
192 raise error.ParseError(_("can't use a list in this context"),
181 hint=_('see hg help "revsets.x or y"'))
193 hint=_('see hg help "revsets.x or y"'))
182
194
183 def keyvaluepair(repo, subset, k, v):
195 def keyvaluepair(repo, subset, k, v, order):
184 raise error.ParseError(_("can't use a key-value pair in this context"))
196 raise error.ParseError(_("can't use a key-value pair in this context"))
185
197
186 def func(repo, subset, a, b, order):
198 def func(repo, subset, a, b, order):
187 f = getsymbol(a)
199 f = getsymbol(a)
188 if f in symbols:
200 if f in symbols:
189 func = symbols[f]
201 func = symbols[f]
190 if getattr(func, '_takeorder', False):
202 if getattr(func, '_takeorder', False):
191 return func(repo, subset, b, order)
203 return func(repo, subset, b, order)
192 return func(repo, subset, b)
204 return func(repo, subset, b)
193
205
194 keep = lambda fn: getattr(fn, '__doc__', None) is not None
206 keep = lambda fn: getattr(fn, '__doc__', None) is not None
195
207
196 syms = [s for (s, fn) in symbols.items() if keep(fn)]
208 syms = [s for (s, fn) in symbols.items() if keep(fn)]
197 raise error.UnknownIdentifier(f, syms)
209 raise error.UnknownIdentifier(f, syms)
198
210
199 # functions
211 # functions
200
212
201 # symbols are callables like:
213 # symbols are callables like:
202 # fn(repo, subset, x)
214 # fn(repo, subset, x)
203 # with:
215 # with:
204 # repo - current repository instance
216 # repo - current repository instance
205 # subset - of revisions to be examined
217 # subset - of revisions to be examined
206 # x - argument in tree form
218 # x - argument in tree form
207 symbols = {}
219 symbols = {}
208
220
209 # symbols which can't be used for a DoS attack for any given input
221 # symbols which can't be used for a DoS attack for any given input
210 # (e.g. those which accept regexes as plain strings shouldn't be included)
222 # (e.g. those which accept regexes as plain strings shouldn't be included)
211 # functions that just return a lot of changesets (like all) don't count here
223 # functions that just return a lot of changesets (like all) don't count here
212 safesymbols = set()
224 safesymbols = set()
213
225
214 predicate = registrar.revsetpredicate()
226 predicate = registrar.revsetpredicate()
215
227
216 @predicate('_destupdate')
228 @predicate('_destupdate')
217 def _destupdate(repo, subset, x):
229 def _destupdate(repo, subset, x):
218 # experimental revset for update destination
230 # experimental revset for update destination
219 args = getargsdict(x, 'limit', 'clean')
231 args = getargsdict(x, 'limit', 'clean')
220 return subset & baseset([destutil.destupdate(repo, **args)[0]])
232 return subset & baseset([destutil.destupdate(repo, **args)[0]])
221
233
222 @predicate('_destmerge')
234 @predicate('_destmerge')
223 def _destmerge(repo, subset, x):
235 def _destmerge(repo, subset, x):
224 # experimental revset for merge destination
236 # experimental revset for merge destination
225 sourceset = None
237 sourceset = None
226 if x is not None:
238 if x is not None:
227 sourceset = getset(repo, fullreposet(repo), x)
239 sourceset = getset(repo, fullreposet(repo), x)
228 return subset & baseset([destutil.destmerge(repo, sourceset=sourceset)])
240 return subset & baseset([destutil.destmerge(repo, sourceset=sourceset)])
229
241
230 @predicate('adds(pattern)', safe=True)
242 @predicate('adds(pattern)', safe=True)
231 def adds(repo, subset, x):
243 def adds(repo, subset, x):
232 """Changesets that add a file matching pattern.
244 """Changesets that add a file matching pattern.
233
245
234 The pattern without explicit kind like ``glob:`` is expected to be
246 The pattern without explicit kind like ``glob:`` is expected to be
235 relative to the current directory and match against a file or a
247 relative to the current directory and match against a file or a
236 directory.
248 directory.
237 """
249 """
238 # i18n: "adds" is a keyword
250 # i18n: "adds" is a keyword
239 pat = getstring(x, _("adds requires a pattern"))
251 pat = getstring(x, _("adds requires a pattern"))
240 return checkstatus(repo, subset, pat, 1)
252 return checkstatus(repo, subset, pat, 1)
241
253
242 @predicate('ancestor(*changeset)', safe=True)
254 @predicate('ancestor(*changeset)', safe=True)
243 def ancestor(repo, subset, x):
255 def ancestor(repo, subset, x):
244 """A greatest common ancestor of the changesets.
256 """A greatest common ancestor of the changesets.
245
257
246 Accepts 0 or more changesets.
258 Accepts 0 or more changesets.
247 Will return empty list when passed no args.
259 Will return empty list when passed no args.
248 Greatest common ancestor of a single changeset is that changeset.
260 Greatest common ancestor of a single changeset is that changeset.
249 """
261 """
250 # i18n: "ancestor" is a keyword
262 # i18n: "ancestor" is a keyword
251 l = getlist(x)
263 l = getlist(x)
252 rl = fullreposet(repo)
264 rl = fullreposet(repo)
253 anc = None
265 anc = None
254
266
255 # (getset(repo, rl, i) for i in l) generates a list of lists
267 # (getset(repo, rl, i) for i in l) generates a list of lists
256 for revs in (getset(repo, rl, i) for i in l):
268 for revs in (getset(repo, rl, i) for i in l):
257 for r in revs:
269 for r in revs:
258 if anc is None:
270 if anc is None:
259 anc = repo[r]
271 anc = repo[r]
260 else:
272 else:
261 anc = anc.ancestor(repo[r])
273 anc = anc.ancestor(repo[r])
262
274
263 if anc is not None and anc.rev() in subset:
275 if anc is not None and anc.rev() in subset:
264 return baseset([anc.rev()])
276 return baseset([anc.rev()])
265 return baseset()
277 return baseset()
266
278
267 def _ancestors(repo, subset, x, followfirst=False, startdepth=None,
279 def _ancestors(repo, subset, x, followfirst=False, startdepth=None,
268 stopdepth=None):
280 stopdepth=None):
269 heads = getset(repo, fullreposet(repo), x)
281 heads = getset(repo, fullreposet(repo), x)
270 if not heads:
282 if not heads:
271 return baseset()
283 return baseset()
272 s = dagop.revancestors(repo, heads, followfirst, startdepth, stopdepth)
284 s = dagop.revancestors(repo, heads, followfirst, startdepth, stopdepth)
273 return subset & s
285 return subset & s
274
286
275 @predicate('ancestors(set[, depth])', safe=True)
287 @predicate('ancestors(set[, depth])', safe=True)
276 def ancestors(repo, subset, x):
288 def ancestors(repo, subset, x):
277 """Changesets that are ancestors of changesets in set, including the
289 """Changesets that are ancestors of changesets in set, including the
278 given changesets themselves.
290 given changesets themselves.
279
291
280 If depth is specified, the result only includes changesets up to
292 If depth is specified, the result only includes changesets up to
281 the specified generation.
293 the specified generation.
282 """
294 """
283 # startdepth is for internal use only until we can decide the UI
295 # startdepth is for internal use only until we can decide the UI
284 args = getargsdict(x, 'ancestors', 'set depth startdepth')
296 args = getargsdict(x, 'ancestors', 'set depth startdepth')
285 if 'set' not in args:
297 if 'set' not in args:
286 # i18n: "ancestors" is a keyword
298 # i18n: "ancestors" is a keyword
287 raise error.ParseError(_('ancestors takes at least 1 argument'))
299 raise error.ParseError(_('ancestors takes at least 1 argument'))
288 startdepth = stopdepth = None
300 startdepth = stopdepth = None
289 if 'startdepth' in args:
301 if 'startdepth' in args:
290 n = getinteger(args['startdepth'],
302 n = getinteger(args['startdepth'],
291 "ancestors expects an integer startdepth")
303 "ancestors expects an integer startdepth")
292 if n < 0:
304 if n < 0:
293 raise error.ParseError("negative startdepth")
305 raise error.ParseError("negative startdepth")
294 startdepth = n
306 startdepth = n
295 if 'depth' in args:
307 if 'depth' in args:
296 # i18n: "ancestors" is a keyword
308 # i18n: "ancestors" is a keyword
297 n = getinteger(args['depth'], _("ancestors expects an integer depth"))
309 n = getinteger(args['depth'], _("ancestors expects an integer depth"))
298 if n < 0:
310 if n < 0:
299 raise error.ParseError(_("negative depth"))
311 raise error.ParseError(_("negative depth"))
300 stopdepth = n + 1
312 stopdepth = n + 1
301 return _ancestors(repo, subset, args['set'],
313 return _ancestors(repo, subset, args['set'],
302 startdepth=startdepth, stopdepth=stopdepth)
314 startdepth=startdepth, stopdepth=stopdepth)
303
315
304 @predicate('_firstancestors', safe=True)
316 @predicate('_firstancestors', safe=True)
305 def _firstancestors(repo, subset, x):
317 def _firstancestors(repo, subset, x):
306 # ``_firstancestors(set)``
318 # ``_firstancestors(set)``
307 # Like ``ancestors(set)`` but follows only the first parents.
319 # Like ``ancestors(set)`` but follows only the first parents.
308 return _ancestors(repo, subset, x, followfirst=True)
320 return _ancestors(repo, subset, x, followfirst=True)
309
321
310 def _childrenspec(repo, subset, x, n, order):
322 def _childrenspec(repo, subset, x, n, order):
311 """Changesets that are the Nth child of a changeset
323 """Changesets that are the Nth child of a changeset
312 in set.
324 in set.
313 """
325 """
314 cs = set()
326 cs = set()
315 for r in getset(repo, fullreposet(repo), x):
327 for r in getset(repo, fullreposet(repo), x):
316 for i in range(n):
328 for i in range(n):
317 c = repo[r].children()
329 c = repo[r].children()
318 if len(c) == 0:
330 if len(c) == 0:
319 break
331 break
320 if len(c) > 1:
332 if len(c) > 1:
321 raise error.RepoLookupError(
333 raise error.RepoLookupError(
322 _("revision in set has more than one child"))
334 _("revision in set has more than one child"))
323 r = c[0].rev()
335 r = c[0].rev()
324 else:
336 else:
325 cs.add(r)
337 cs.add(r)
326 return subset & cs
338 return subset & cs
327
339
328 def ancestorspec(repo, subset, x, n, order):
340 def ancestorspec(repo, subset, x, n, order):
329 """``set~n``
341 """``set~n``
330 Changesets that are the Nth ancestor (first parents only) of a changeset
342 Changesets that are the Nth ancestor (first parents only) of a changeset
331 in set.
343 in set.
332 """
344 """
333 n = getinteger(n, _("~ expects a number"))
345 n = getinteger(n, _("~ expects a number"))
334 if n < 0:
346 if n < 0:
335 # children lookup
347 # children lookup
336 return _childrenspec(repo, subset, x, -n, order)
348 return _childrenspec(repo, subset, x, -n, order)
337 ps = set()
349 ps = set()
338 cl = repo.changelog
350 cl = repo.changelog
339 for r in getset(repo, fullreposet(repo), x):
351 for r in getset(repo, fullreposet(repo), x):
340 for i in range(n):
352 for i in range(n):
341 try:
353 try:
342 r = cl.parentrevs(r)[0]
354 r = cl.parentrevs(r)[0]
343 except error.WdirUnsupported:
355 except error.WdirUnsupported:
344 r = repo[r].parents()[0].rev()
356 r = repo[r].parents()[0].rev()
345 ps.add(r)
357 ps.add(r)
346 return subset & ps
358 return subset & ps
347
359
348 @predicate('author(string)', safe=True)
360 @predicate('author(string)', safe=True)
349 def author(repo, subset, x):
361 def author(repo, subset, x):
350 """Alias for ``user(string)``.
362 """Alias for ``user(string)``.
351 """
363 """
352 # i18n: "author" is a keyword
364 # i18n: "author" is a keyword
353 n = getstring(x, _("author requires a string"))
365 n = getstring(x, _("author requires a string"))
354 kind, pattern, matcher = _substringmatcher(n, casesensitive=False)
366 kind, pattern, matcher = _substringmatcher(n, casesensitive=False)
355 return subset.filter(lambda x: matcher(repo[x].user()),
367 return subset.filter(lambda x: matcher(repo[x].user()),
356 condrepr=('<user %r>', n))
368 condrepr=('<user %r>', n))
357
369
358 @predicate('bisect(string)', safe=True)
370 @predicate('bisect(string)', safe=True)
359 def bisect(repo, subset, x):
371 def bisect(repo, subset, x):
360 """Changesets marked in the specified bisect status:
372 """Changesets marked in the specified bisect status:
361
373
362 - ``good``, ``bad``, ``skip``: csets explicitly marked as good/bad/skip
374 - ``good``, ``bad``, ``skip``: csets explicitly marked as good/bad/skip
363 - ``goods``, ``bads`` : csets topologically good/bad
375 - ``goods``, ``bads`` : csets topologically good/bad
364 - ``range`` : csets taking part in the bisection
376 - ``range`` : csets taking part in the bisection
365 - ``pruned`` : csets that are goods, bads or skipped
377 - ``pruned`` : csets that are goods, bads or skipped
366 - ``untested`` : csets whose fate is yet unknown
378 - ``untested`` : csets whose fate is yet unknown
367 - ``ignored`` : csets ignored due to DAG topology
379 - ``ignored`` : csets ignored due to DAG topology
368 - ``current`` : the cset currently being bisected
380 - ``current`` : the cset currently being bisected
369 """
381 """
370 # i18n: "bisect" is a keyword
382 # i18n: "bisect" is a keyword
371 status = getstring(x, _("bisect requires a string")).lower()
383 status = getstring(x, _("bisect requires a string")).lower()
372 state = set(hbisect.get(repo, status))
384 state = set(hbisect.get(repo, status))
373 return subset & state
385 return subset & state
374
386
375 # Backward-compatibility
387 # Backward-compatibility
376 # - no help entry so that we do not advertise it any more
388 # - no help entry so that we do not advertise it any more
377 @predicate('bisected', safe=True)
389 @predicate('bisected', safe=True)
378 def bisected(repo, subset, x):
390 def bisected(repo, subset, x):
379 return bisect(repo, subset, x)
391 return bisect(repo, subset, x)
380
392
381 @predicate('bookmark([name])', safe=True)
393 @predicate('bookmark([name])', safe=True)
382 def bookmark(repo, subset, x):
394 def bookmark(repo, subset, x):
383 """The named bookmark or all bookmarks.
395 """The named bookmark or all bookmarks.
384
396
385 Pattern matching is supported for `name`. See :hg:`help revisions.patterns`.
397 Pattern matching is supported for `name`. See :hg:`help revisions.patterns`.
386 """
398 """
387 # i18n: "bookmark" is a keyword
399 # i18n: "bookmark" is a keyword
388 args = getargs(x, 0, 1, _('bookmark takes one or no arguments'))
400 args = getargs(x, 0, 1, _('bookmark takes one or no arguments'))
389 if args:
401 if args:
390 bm = getstring(args[0],
402 bm = getstring(args[0],
391 # i18n: "bookmark" is a keyword
403 # i18n: "bookmark" is a keyword
392 _('the argument to bookmark must be a string'))
404 _('the argument to bookmark must be a string'))
393 kind, pattern, matcher = util.stringmatcher(bm)
405 kind, pattern, matcher = util.stringmatcher(bm)
394 bms = set()
406 bms = set()
395 if kind == 'literal':
407 if kind == 'literal':
396 bmrev = repo._bookmarks.get(pattern, None)
408 bmrev = repo._bookmarks.get(pattern, None)
397 if not bmrev:
409 if not bmrev:
398 raise error.RepoLookupError(_("bookmark '%s' does not exist")
410 raise error.RepoLookupError(_("bookmark '%s' does not exist")
399 % pattern)
411 % pattern)
400 bms.add(repo[bmrev].rev())
412 bms.add(repo[bmrev].rev())
401 else:
413 else:
402 matchrevs = set()
414 matchrevs = set()
403 for name, bmrev in repo._bookmarks.iteritems():
415 for name, bmrev in repo._bookmarks.iteritems():
404 if matcher(name):
416 if matcher(name):
405 matchrevs.add(bmrev)
417 matchrevs.add(bmrev)
406 if not matchrevs:
418 if not matchrevs:
407 raise error.RepoLookupError(_("no bookmarks exist"
419 raise error.RepoLookupError(_("no bookmarks exist"
408 " that match '%s'") % pattern)
420 " that match '%s'") % pattern)
409 for bmrev in matchrevs:
421 for bmrev in matchrevs:
410 bms.add(repo[bmrev].rev())
422 bms.add(repo[bmrev].rev())
411 else:
423 else:
412 bms = {repo[r].rev() for r in repo._bookmarks.values()}
424 bms = {repo[r].rev() for r in repo._bookmarks.values()}
413 bms -= {node.nullrev}
425 bms -= {node.nullrev}
414 return subset & bms
426 return subset & bms
415
427
416 @predicate('branch(string or set)', safe=True)
428 @predicate('branch(string or set)', safe=True)
417 def branch(repo, subset, x):
429 def branch(repo, subset, x):
418 """
430 """
419 All changesets belonging to the given branch or the branches of the given
431 All changesets belonging to the given branch or the branches of the given
420 changesets.
432 changesets.
421
433
422 Pattern matching is supported for `string`. See
434 Pattern matching is supported for `string`. See
423 :hg:`help revisions.patterns`.
435 :hg:`help revisions.patterns`.
424 """
436 """
425 getbi = repo.revbranchcache().branchinfo
437 getbi = repo.revbranchcache().branchinfo
426 def getbranch(r):
438 def getbranch(r):
427 try:
439 try:
428 return getbi(r)[0]
440 return getbi(r)[0]
429 except error.WdirUnsupported:
441 except error.WdirUnsupported:
430 return repo[r].branch()
442 return repo[r].branch()
431
443
432 try:
444 try:
433 b = getstring(x, '')
445 b = getstring(x, '')
434 except error.ParseError:
446 except error.ParseError:
435 # not a string, but another revspec, e.g. tip()
447 # not a string, but another revspec, e.g. tip()
436 pass
448 pass
437 else:
449 else:
438 kind, pattern, matcher = util.stringmatcher(b)
450 kind, pattern, matcher = util.stringmatcher(b)
439 if kind == 'literal':
451 if kind == 'literal':
440 # note: falls through to the revspec case if no branch with
452 # note: falls through to the revspec case if no branch with
441 # this name exists and pattern kind is not specified explicitly
453 # this name exists and pattern kind is not specified explicitly
442 if pattern in repo.branchmap():
454 if pattern in repo.branchmap():
443 return subset.filter(lambda r: matcher(getbranch(r)),
455 return subset.filter(lambda r: matcher(getbranch(r)),
444 condrepr=('<branch %r>', b))
456 condrepr=('<branch %r>', b))
445 if b.startswith('literal:'):
457 if b.startswith('literal:'):
446 raise error.RepoLookupError(_("branch '%s' does not exist")
458 raise error.RepoLookupError(_("branch '%s' does not exist")
447 % pattern)
459 % pattern)
448 else:
460 else:
449 return subset.filter(lambda r: matcher(getbranch(r)),
461 return subset.filter(lambda r: matcher(getbranch(r)),
450 condrepr=('<branch %r>', b))
462 condrepr=('<branch %r>', b))
451
463
452 s = getset(repo, fullreposet(repo), x)
464 s = getset(repo, fullreposet(repo), x)
453 b = set()
465 b = set()
454 for r in s:
466 for r in s:
455 b.add(getbranch(r))
467 b.add(getbranch(r))
456 c = s.__contains__
468 c = s.__contains__
457 return subset.filter(lambda r: c(r) or getbranch(r) in b,
469 return subset.filter(lambda r: c(r) or getbranch(r) in b,
458 condrepr=lambda: '<branch %r>' % sorted(b))
470 condrepr=lambda: '<branch %r>' % sorted(b))
459
471
460 @predicate('bumped()', safe=True)
472 @predicate('bumped()', safe=True)
461 def bumped(repo, subset, x):
473 def bumped(repo, subset, x):
462 msg = ("'bumped()' is deprecated, "
474 msg = ("'bumped()' is deprecated, "
463 "use 'phasedivergent()'")
475 "use 'phasedivergent()'")
464 repo.ui.deprecwarn(msg, '4.4')
476 repo.ui.deprecwarn(msg, '4.4')
465
477
466 return phasedivergent(repo, subset, x)
478 return phasedivergent(repo, subset, x)
467
479
468 @predicate('phasedivergent()', safe=True)
480 @predicate('phasedivergent()', safe=True)
469 def phasedivergent(repo, subset, x):
481 def phasedivergent(repo, subset, x):
470 """Mutable changesets marked as successors of public changesets.
482 """Mutable changesets marked as successors of public changesets.
471
483
472 Only non-public and non-obsolete changesets can be `phasedivergent`.
484 Only non-public and non-obsolete changesets can be `phasedivergent`.
473 (EXPERIMENTAL)
485 (EXPERIMENTAL)
474 """
486 """
475 # i18n: "phasedivergent" is a keyword
487 # i18n: "phasedivergent" is a keyword
476 getargs(x, 0, 0, _("phasedivergent takes no arguments"))
488 getargs(x, 0, 0, _("phasedivergent takes no arguments"))
477 phasedivergent = obsmod.getrevs(repo, 'phasedivergent')
489 phasedivergent = obsmod.getrevs(repo, 'phasedivergent')
478 return subset & phasedivergent
490 return subset & phasedivergent
479
491
480 @predicate('bundle()', safe=True)
492 @predicate('bundle()', safe=True)
481 def bundle(repo, subset, x):
493 def bundle(repo, subset, x):
482 """Changesets in the bundle.
494 """Changesets in the bundle.
483
495
484 Bundle must be specified by the -R option."""
496 Bundle must be specified by the -R option."""
485
497
486 try:
498 try:
487 bundlerevs = repo.changelog.bundlerevs
499 bundlerevs = repo.changelog.bundlerevs
488 except AttributeError:
500 except AttributeError:
489 raise error.Abort(_("no bundle provided - specify with -R"))
501 raise error.Abort(_("no bundle provided - specify with -R"))
490 return subset & bundlerevs
502 return subset & bundlerevs
491
503
492 def checkstatus(repo, subset, pat, field):
504 def checkstatus(repo, subset, pat, field):
493 hasset = matchmod.patkind(pat) == 'set'
505 hasset = matchmod.patkind(pat) == 'set'
494
506
495 mcache = [None]
507 mcache = [None]
496 def matches(x):
508 def matches(x):
497 c = repo[x]
509 c = repo[x]
498 if not mcache[0] or hasset:
510 if not mcache[0] or hasset:
499 mcache[0] = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
511 mcache[0] = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
500 m = mcache[0]
512 m = mcache[0]
501 fname = None
513 fname = None
502 if not m.anypats() and len(m.files()) == 1:
514 if not m.anypats() and len(m.files()) == 1:
503 fname = m.files()[0]
515 fname = m.files()[0]
504 if fname is not None:
516 if fname is not None:
505 if fname not in c.files():
517 if fname not in c.files():
506 return False
518 return False
507 else:
519 else:
508 for f in c.files():
520 for f in c.files():
509 if m(f):
521 if m(f):
510 break
522 break
511 else:
523 else:
512 return False
524 return False
513 files = repo.status(c.p1().node(), c.node())[field]
525 files = repo.status(c.p1().node(), c.node())[field]
514 if fname is not None:
526 if fname is not None:
515 if fname in files:
527 if fname in files:
516 return True
528 return True
517 else:
529 else:
518 for f in files:
530 for f in files:
519 if m(f):
531 if m(f):
520 return True
532 return True
521
533
522 return subset.filter(matches, condrepr=('<status[%r] %r>', field, pat))
534 return subset.filter(matches, condrepr=('<status[%r] %r>', field, pat))
523
535
524 def _children(repo, subset, parentset):
536 def _children(repo, subset, parentset):
525 if not parentset:
537 if not parentset:
526 return baseset()
538 return baseset()
527 cs = set()
539 cs = set()
528 pr = repo.changelog.parentrevs
540 pr = repo.changelog.parentrevs
529 minrev = parentset.min()
541 minrev = parentset.min()
530 nullrev = node.nullrev
542 nullrev = node.nullrev
531 for r in subset:
543 for r in subset:
532 if r <= minrev:
544 if r <= minrev:
533 continue
545 continue
534 p1, p2 = pr(r)
546 p1, p2 = pr(r)
535 if p1 in parentset:
547 if p1 in parentset:
536 cs.add(r)
548 cs.add(r)
537 if p2 != nullrev and p2 in parentset:
549 if p2 != nullrev and p2 in parentset:
538 cs.add(r)
550 cs.add(r)
539 return baseset(cs)
551 return baseset(cs)
540
552
541 @predicate('children(set)', safe=True)
553 @predicate('children(set)', safe=True)
542 def children(repo, subset, x):
554 def children(repo, subset, x):
543 """Child changesets of changesets in set.
555 """Child changesets of changesets in set.
544 """
556 """
545 s = getset(repo, fullreposet(repo), x)
557 s = getset(repo, fullreposet(repo), x)
546 cs = _children(repo, subset, s)
558 cs = _children(repo, subset, s)
547 return subset & cs
559 return subset & cs
548
560
549 @predicate('closed()', safe=True)
561 @predicate('closed()', safe=True)
550 def closed(repo, subset, x):
562 def closed(repo, subset, x):
551 """Changeset is closed.
563 """Changeset is closed.
552 """
564 """
553 # i18n: "closed" is a keyword
565 # i18n: "closed" is a keyword
554 getargs(x, 0, 0, _("closed takes no arguments"))
566 getargs(x, 0, 0, _("closed takes no arguments"))
555 return subset.filter(lambda r: repo[r].closesbranch(),
567 return subset.filter(lambda r: repo[r].closesbranch(),
556 condrepr='<branch closed>')
568 condrepr='<branch closed>')
557
569
558 @predicate('contains(pattern)')
570 @predicate('contains(pattern)')
559 def contains(repo, subset, x):
571 def contains(repo, subset, x):
560 """The revision's manifest contains a file matching pattern (but might not
572 """The revision's manifest contains a file matching pattern (but might not
561 modify it). See :hg:`help patterns` for information about file patterns.
573 modify it). See :hg:`help patterns` for information about file patterns.
562
574
563 The pattern without explicit kind like ``glob:`` is expected to be
575 The pattern without explicit kind like ``glob:`` is expected to be
564 relative to the current directory and match against a file exactly
576 relative to the current directory and match against a file exactly
565 for efficiency.
577 for efficiency.
566 """
578 """
567 # i18n: "contains" is a keyword
579 # i18n: "contains" is a keyword
568 pat = getstring(x, _("contains requires a pattern"))
580 pat = getstring(x, _("contains requires a pattern"))
569
581
570 def matches(x):
582 def matches(x):
571 if not matchmod.patkind(pat):
583 if not matchmod.patkind(pat):
572 pats = pathutil.canonpath(repo.root, repo.getcwd(), pat)
584 pats = pathutil.canonpath(repo.root, repo.getcwd(), pat)
573 if pats in repo[x]:
585 if pats in repo[x]:
574 return True
586 return True
575 else:
587 else:
576 c = repo[x]
588 c = repo[x]
577 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
589 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
578 for f in c.manifest():
590 for f in c.manifest():
579 if m(f):
591 if m(f):
580 return True
592 return True
581 return False
593 return False
582
594
583 return subset.filter(matches, condrepr=('<contains %r>', pat))
595 return subset.filter(matches, condrepr=('<contains %r>', pat))
584
596
585 @predicate('converted([id])', safe=True)
597 @predicate('converted([id])', safe=True)
586 def converted(repo, subset, x):
598 def converted(repo, subset, x):
587 """Changesets converted from the given identifier in the old repository if
599 """Changesets converted from the given identifier in the old repository if
588 present, or all converted changesets if no identifier is specified.
600 present, or all converted changesets if no identifier is specified.
589 """
601 """
590
602
591 # There is exactly no chance of resolving the revision, so do a simple
603 # There is exactly no chance of resolving the revision, so do a simple
592 # string compare and hope for the best
604 # string compare and hope for the best
593
605
594 rev = None
606 rev = None
595 # i18n: "converted" is a keyword
607 # i18n: "converted" is a keyword
596 l = getargs(x, 0, 1, _('converted takes one or no arguments'))
608 l = getargs(x, 0, 1, _('converted takes one or no arguments'))
597 if l:
609 if l:
598 # i18n: "converted" is a keyword
610 # i18n: "converted" is a keyword
599 rev = getstring(l[0], _('converted requires a revision'))
611 rev = getstring(l[0], _('converted requires a revision'))
600
612
601 def _matchvalue(r):
613 def _matchvalue(r):
602 source = repo[r].extra().get('convert_revision', None)
614 source = repo[r].extra().get('convert_revision', None)
603 return source is not None and (rev is None or source.startswith(rev))
615 return source is not None and (rev is None or source.startswith(rev))
604
616
605 return subset.filter(lambda r: _matchvalue(r),
617 return subset.filter(lambda r: _matchvalue(r),
606 condrepr=('<converted %r>', rev))
618 condrepr=('<converted %r>', rev))
607
619
608 @predicate('date(interval)', safe=True)
620 @predicate('date(interval)', safe=True)
609 def date(repo, subset, x):
621 def date(repo, subset, x):
610 """Changesets within the interval, see :hg:`help dates`.
622 """Changesets within the interval, see :hg:`help dates`.
611 """
623 """
612 # i18n: "date" is a keyword
624 # i18n: "date" is a keyword
613 ds = getstring(x, _("date requires a string"))
625 ds = getstring(x, _("date requires a string"))
614 dm = util.matchdate(ds)
626 dm = util.matchdate(ds)
615 return subset.filter(lambda x: dm(repo[x].date()[0]),
627 return subset.filter(lambda x: dm(repo[x].date()[0]),
616 condrepr=('<date %r>', ds))
628 condrepr=('<date %r>', ds))
617
629
618 @predicate('desc(string)', safe=True)
630 @predicate('desc(string)', safe=True)
619 def desc(repo, subset, x):
631 def desc(repo, subset, x):
620 """Search commit message for string. The match is case-insensitive.
632 """Search commit message for string. The match is case-insensitive.
621
633
622 Pattern matching is supported for `string`. See
634 Pattern matching is supported for `string`. See
623 :hg:`help revisions.patterns`.
635 :hg:`help revisions.patterns`.
624 """
636 """
625 # i18n: "desc" is a keyword
637 # i18n: "desc" is a keyword
626 ds = getstring(x, _("desc requires a string"))
638 ds = getstring(x, _("desc requires a string"))
627
639
628 kind, pattern, matcher = _substringmatcher(ds, casesensitive=False)
640 kind, pattern, matcher = _substringmatcher(ds, casesensitive=False)
629
641
630 return subset.filter(lambda r: matcher(repo[r].description()),
642 return subset.filter(lambda r: matcher(repo[r].description()),
631 condrepr=('<desc %r>', ds))
643 condrepr=('<desc %r>', ds))
632
644
633 def _descendants(repo, subset, x, followfirst=False, startdepth=None,
645 def _descendants(repo, subset, x, followfirst=False, startdepth=None,
634 stopdepth=None):
646 stopdepth=None):
635 roots = getset(repo, fullreposet(repo), x)
647 roots = getset(repo, fullreposet(repo), x)
636 if not roots:
648 if not roots:
637 return baseset()
649 return baseset()
638 s = dagop.revdescendants(repo, roots, followfirst, startdepth, stopdepth)
650 s = dagop.revdescendants(repo, roots, followfirst, startdepth, stopdepth)
639 return subset & s
651 return subset & s
640
652
641 @predicate('descendants(set[, depth])', safe=True)
653 @predicate('descendants(set[, depth])', safe=True)
642 def descendants(repo, subset, x):
654 def descendants(repo, subset, x):
643 """Changesets which are descendants of changesets in set, including the
655 """Changesets which are descendants of changesets in set, including the
644 given changesets themselves.
656 given changesets themselves.
645
657
646 If depth is specified, the result only includes changesets up to
658 If depth is specified, the result only includes changesets up to
647 the specified generation.
659 the specified generation.
648 """
660 """
649 # startdepth is for internal use only until we can decide the UI
661 # startdepth is for internal use only until we can decide the UI
650 args = getargsdict(x, 'descendants', 'set depth startdepth')
662 args = getargsdict(x, 'descendants', 'set depth startdepth')
651 if 'set' not in args:
663 if 'set' not in args:
652 # i18n: "descendants" is a keyword
664 # i18n: "descendants" is a keyword
653 raise error.ParseError(_('descendants takes at least 1 argument'))
665 raise error.ParseError(_('descendants takes at least 1 argument'))
654 startdepth = stopdepth = None
666 startdepth = stopdepth = None
655 if 'startdepth' in args:
667 if 'startdepth' in args:
656 n = getinteger(args['startdepth'],
668 n = getinteger(args['startdepth'],
657 "descendants expects an integer startdepth")
669 "descendants expects an integer startdepth")
658 if n < 0:
670 if n < 0:
659 raise error.ParseError("negative startdepth")
671 raise error.ParseError("negative startdepth")
660 startdepth = n
672 startdepth = n
661 if 'depth' in args:
673 if 'depth' in args:
662 # i18n: "descendants" is a keyword
674 # i18n: "descendants" is a keyword
663 n = getinteger(args['depth'], _("descendants expects an integer depth"))
675 n = getinteger(args['depth'], _("descendants expects an integer depth"))
664 if n < 0:
676 if n < 0:
665 raise error.ParseError(_("negative depth"))
677 raise error.ParseError(_("negative depth"))
666 stopdepth = n + 1
678 stopdepth = n + 1
667 return _descendants(repo, subset, args['set'],
679 return _descendants(repo, subset, args['set'],
668 startdepth=startdepth, stopdepth=stopdepth)
680 startdepth=startdepth, stopdepth=stopdepth)
669
681
670 @predicate('_firstdescendants', safe=True)
682 @predicate('_firstdescendants', safe=True)
671 def _firstdescendants(repo, subset, x):
683 def _firstdescendants(repo, subset, x):
672 # ``_firstdescendants(set)``
684 # ``_firstdescendants(set)``
673 # Like ``descendants(set)`` but follows only the first parents.
685 # Like ``descendants(set)`` but follows only the first parents.
674 return _descendants(repo, subset, x, followfirst=True)
686 return _descendants(repo, subset, x, followfirst=True)
675
687
676 @predicate('destination([set])', safe=True)
688 @predicate('destination([set])', safe=True)
677 def destination(repo, subset, x):
689 def destination(repo, subset, x):
678 """Changesets that were created by a graft, transplant or rebase operation,
690 """Changesets that were created by a graft, transplant or rebase operation,
679 with the given revisions specified as the source. Omitting the optional set
691 with the given revisions specified as the source. Omitting the optional set
680 is the same as passing all().
692 is the same as passing all().
681 """
693 """
682 if x is not None:
694 if x is not None:
683 sources = getset(repo, fullreposet(repo), x)
695 sources = getset(repo, fullreposet(repo), x)
684 else:
696 else:
685 sources = fullreposet(repo)
697 sources = fullreposet(repo)
686
698
687 dests = set()
699 dests = set()
688
700
689 # subset contains all of the possible destinations that can be returned, so
701 # subset contains all of the possible destinations that can be returned, so
690 # iterate over them and see if their source(s) were provided in the arg set.
702 # iterate over them and see if their source(s) were provided in the arg set.
691 # Even if the immediate src of r is not in the arg set, src's source (or
703 # Even if the immediate src of r is not in the arg set, src's source (or
692 # further back) may be. Scanning back further than the immediate src allows
704 # further back) may be. Scanning back further than the immediate src allows
693 # transitive transplants and rebases to yield the same results as transitive
705 # transitive transplants and rebases to yield the same results as transitive
694 # grafts.
706 # grafts.
695 for r in subset:
707 for r in subset:
696 src = _getrevsource(repo, r)
708 src = _getrevsource(repo, r)
697 lineage = None
709 lineage = None
698
710
699 while src is not None:
711 while src is not None:
700 if lineage is None:
712 if lineage is None:
701 lineage = list()
713 lineage = list()
702
714
703 lineage.append(r)
715 lineage.append(r)
704
716
705 # The visited lineage is a match if the current source is in the arg
717 # The visited lineage is a match if the current source is in the arg
706 # set. Since every candidate dest is visited by way of iterating
718 # set. Since every candidate dest is visited by way of iterating
707 # subset, any dests further back in the lineage will be tested by a
719 # subset, any dests further back in the lineage will be tested by a
708 # different iteration over subset. Likewise, if the src was already
720 # different iteration over subset. Likewise, if the src was already
709 # selected, the current lineage can be selected without going back
721 # selected, the current lineage can be selected without going back
710 # further.
722 # further.
711 if src in sources or src in dests:
723 if src in sources or src in dests:
712 dests.update(lineage)
724 dests.update(lineage)
713 break
725 break
714
726
715 r = src
727 r = src
716 src = _getrevsource(repo, r)
728 src = _getrevsource(repo, r)
717
729
718 return subset.filter(dests.__contains__,
730 return subset.filter(dests.__contains__,
719 condrepr=lambda: '<destination %r>' % sorted(dests))
731 condrepr=lambda: '<destination %r>' % sorted(dests))
720
732
721 @predicate('divergent()', safe=True)
733 @predicate('divergent()', safe=True)
722 def divergent(repo, subset, x):
734 def divergent(repo, subset, x):
723 msg = ("'divergent()' is deprecated, "
735 msg = ("'divergent()' is deprecated, "
724 "use 'contentdivergent()'")
736 "use 'contentdivergent()'")
725 repo.ui.deprecwarn(msg, '4.4')
737 repo.ui.deprecwarn(msg, '4.4')
726
738
727 return contentdivergent(repo, subset, x)
739 return contentdivergent(repo, subset, x)
728
740
729 @predicate('contentdivergent()', safe=True)
741 @predicate('contentdivergent()', safe=True)
730 def contentdivergent(repo, subset, x):
742 def contentdivergent(repo, subset, x):
731 """
743 """
732 Final successors of changesets with an alternative set of final
744 Final successors of changesets with an alternative set of final
733 successors. (EXPERIMENTAL)
745 successors. (EXPERIMENTAL)
734 """
746 """
735 # i18n: "contentdivergent" is a keyword
747 # i18n: "contentdivergent" is a keyword
736 getargs(x, 0, 0, _("contentdivergent takes no arguments"))
748 getargs(x, 0, 0, _("contentdivergent takes no arguments"))
737 contentdivergent = obsmod.getrevs(repo, 'contentdivergent')
749 contentdivergent = obsmod.getrevs(repo, 'contentdivergent')
738 return subset & contentdivergent
750 return subset & contentdivergent
739
751
740 @predicate('extinct()', safe=True)
752 @predicate('extinct()', safe=True)
741 def extinct(repo, subset, x):
753 def extinct(repo, subset, x):
742 """Obsolete changesets with obsolete descendants only.
754 """Obsolete changesets with obsolete descendants only.
743 """
755 """
744 # i18n: "extinct" is a keyword
756 # i18n: "extinct" is a keyword
745 getargs(x, 0, 0, _("extinct takes no arguments"))
757 getargs(x, 0, 0, _("extinct takes no arguments"))
746 extincts = obsmod.getrevs(repo, 'extinct')
758 extincts = obsmod.getrevs(repo, 'extinct')
747 return subset & extincts
759 return subset & extincts
748
760
749 @predicate('extra(label, [value])', safe=True)
761 @predicate('extra(label, [value])', safe=True)
750 def extra(repo, subset, x):
762 def extra(repo, subset, x):
751 """Changesets with the given label in the extra metadata, with the given
763 """Changesets with the given label in the extra metadata, with the given
752 optional value.
764 optional value.
753
765
754 Pattern matching is supported for `value`. See
766 Pattern matching is supported for `value`. See
755 :hg:`help revisions.patterns`.
767 :hg:`help revisions.patterns`.
756 """
768 """
757 args = getargsdict(x, 'extra', 'label value')
769 args = getargsdict(x, 'extra', 'label value')
758 if 'label' not in args:
770 if 'label' not in args:
759 # i18n: "extra" is a keyword
771 # i18n: "extra" is a keyword
760 raise error.ParseError(_('extra takes at least 1 argument'))
772 raise error.ParseError(_('extra takes at least 1 argument'))
761 # i18n: "extra" is a keyword
773 # i18n: "extra" is a keyword
762 label = getstring(args['label'], _('first argument to extra must be '
774 label = getstring(args['label'], _('first argument to extra must be '
763 'a string'))
775 'a string'))
764 value = None
776 value = None
765
777
766 if 'value' in args:
778 if 'value' in args:
767 # i18n: "extra" is a keyword
779 # i18n: "extra" is a keyword
768 value = getstring(args['value'], _('second argument to extra must be '
780 value = getstring(args['value'], _('second argument to extra must be '
769 'a string'))
781 'a string'))
770 kind, value, matcher = util.stringmatcher(value)
782 kind, value, matcher = util.stringmatcher(value)
771
783
772 def _matchvalue(r):
784 def _matchvalue(r):
773 extra = repo[r].extra()
785 extra = repo[r].extra()
774 return label in extra and (value is None or matcher(extra[label]))
786 return label in extra and (value is None or matcher(extra[label]))
775
787
776 return subset.filter(lambda r: _matchvalue(r),
788 return subset.filter(lambda r: _matchvalue(r),
777 condrepr=('<extra[%r] %r>', label, value))
789 condrepr=('<extra[%r] %r>', label, value))
778
790
779 @predicate('filelog(pattern)', safe=True)
791 @predicate('filelog(pattern)', safe=True)
780 def filelog(repo, subset, x):
792 def filelog(repo, subset, x):
781 """Changesets connected to the specified filelog.
793 """Changesets connected to the specified filelog.
782
794
783 For performance reasons, visits only revisions mentioned in the file-level
795 For performance reasons, visits only revisions mentioned in the file-level
784 filelog, rather than filtering through all changesets (much faster, but
796 filelog, rather than filtering through all changesets (much faster, but
785 doesn't include deletes or duplicate changes). For a slower, more accurate
797 doesn't include deletes or duplicate changes). For a slower, more accurate
786 result, use ``file()``.
798 result, use ``file()``.
787
799
788 The pattern without explicit kind like ``glob:`` is expected to be
800 The pattern without explicit kind like ``glob:`` is expected to be
789 relative to the current directory and match against a file exactly
801 relative to the current directory and match against a file exactly
790 for efficiency.
802 for efficiency.
791
803
792 If some linkrev points to revisions filtered by the current repoview, we'll
804 If some linkrev points to revisions filtered by the current repoview, we'll
793 work around it to return a non-filtered value.
805 work around it to return a non-filtered value.
794 """
806 """
795
807
796 # i18n: "filelog" is a keyword
808 # i18n: "filelog" is a keyword
797 pat = getstring(x, _("filelog requires a pattern"))
809 pat = getstring(x, _("filelog requires a pattern"))
798 s = set()
810 s = set()
799 cl = repo.changelog
811 cl = repo.changelog
800
812
801 if not matchmod.patkind(pat):
813 if not matchmod.patkind(pat):
802 f = pathutil.canonpath(repo.root, repo.getcwd(), pat)
814 f = pathutil.canonpath(repo.root, repo.getcwd(), pat)
803 files = [f]
815 files = [f]
804 else:
816 else:
805 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=repo[None])
817 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=repo[None])
806 files = (f for f in repo[None] if m(f))
818 files = (f for f in repo[None] if m(f))
807
819
808 for f in files:
820 for f in files:
809 fl = repo.file(f)
821 fl = repo.file(f)
810 known = {}
822 known = {}
811 scanpos = 0
823 scanpos = 0
812 for fr in list(fl):
824 for fr in list(fl):
813 fn = fl.node(fr)
825 fn = fl.node(fr)
814 if fn in known:
826 if fn in known:
815 s.add(known[fn])
827 s.add(known[fn])
816 continue
828 continue
817
829
818 lr = fl.linkrev(fr)
830 lr = fl.linkrev(fr)
819 if lr in cl:
831 if lr in cl:
820 s.add(lr)
832 s.add(lr)
821 elif scanpos is not None:
833 elif scanpos is not None:
822 # lowest matching changeset is filtered, scan further
834 # lowest matching changeset is filtered, scan further
823 # ahead in changelog
835 # ahead in changelog
824 start = max(lr, scanpos) + 1
836 start = max(lr, scanpos) + 1
825 scanpos = None
837 scanpos = None
826 for r in cl.revs(start):
838 for r in cl.revs(start):
827 # minimize parsing of non-matching entries
839 # minimize parsing of non-matching entries
828 if f in cl.revision(r) and f in cl.readfiles(r):
840 if f in cl.revision(r) and f in cl.readfiles(r):
829 try:
841 try:
830 # try to use manifest delta fastpath
842 # try to use manifest delta fastpath
831 n = repo[r].filenode(f)
843 n = repo[r].filenode(f)
832 if n not in known:
844 if n not in known:
833 if n == fn:
845 if n == fn:
834 s.add(r)
846 s.add(r)
835 scanpos = r
847 scanpos = r
836 break
848 break
837 else:
849 else:
838 known[n] = r
850 known[n] = r
839 except error.ManifestLookupError:
851 except error.ManifestLookupError:
840 # deletion in changelog
852 # deletion in changelog
841 continue
853 continue
842
854
843 return subset & s
855 return subset & s
844
856
845 @predicate('first(set, [n])', safe=True, takeorder=True)
857 @predicate('first(set, [n])', safe=True, takeorder=True)
846 def first(repo, subset, x, order):
858 def first(repo, subset, x, order):
847 """An alias for limit().
859 """An alias for limit().
848 """
860 """
849 return limit(repo, subset, x, order)
861 return limit(repo, subset, x, order)
850
862
851 def _follow(repo, subset, x, name, followfirst=False):
863 def _follow(repo, subset, x, name, followfirst=False):
852 l = getargs(x, 0, 2, _("%s takes no arguments or a pattern "
864 l = getargs(x, 0, 2, _("%s takes no arguments or a pattern "
853 "and an optional revset") % name)
865 "and an optional revset") % name)
854 c = repo['.']
866 c = repo['.']
855 if l:
867 if l:
856 x = getstring(l[0], _("%s expected a pattern") % name)
868 x = getstring(l[0], _("%s expected a pattern") % name)
857 rev = None
869 rev = None
858 if len(l) >= 2:
870 if len(l) >= 2:
859 revs = getset(repo, fullreposet(repo), l[1])
871 revs = getset(repo, fullreposet(repo), l[1])
860 if len(revs) != 1:
872 if len(revs) != 1:
861 raise error.RepoLookupError(
873 raise error.RepoLookupError(
862 _("%s expected one starting revision") % name)
874 _("%s expected one starting revision") % name)
863 rev = revs.last()
875 rev = revs.last()
864 c = repo[rev]
876 c = repo[rev]
865 matcher = matchmod.match(repo.root, repo.getcwd(), [x],
877 matcher = matchmod.match(repo.root, repo.getcwd(), [x],
866 ctx=repo[rev], default='path')
878 ctx=repo[rev], default='path')
867
879
868 files = c.manifest().walk(matcher)
880 files = c.manifest().walk(matcher)
869
881
870 s = set()
882 s = set()
871 for fname in files:
883 for fname in files:
872 fctx = c[fname]
884 fctx = c[fname]
873 s = s.union(set(c.rev() for c in fctx.ancestors(followfirst)))
885 s = s.union(set(c.rev() for c in fctx.ancestors(followfirst)))
874 # include the revision responsible for the most recent version
886 # include the revision responsible for the most recent version
875 s.add(fctx.introrev())
887 s.add(fctx.introrev())
876 else:
888 else:
877 s = dagop.revancestors(repo, baseset([c.rev()]), followfirst)
889 s = dagop.revancestors(repo, baseset([c.rev()]), followfirst)
878
890
879 return subset & s
891 return subset & s
880
892
881 @predicate('follow([pattern[, startrev]])', safe=True)
893 @predicate('follow([pattern[, startrev]])', safe=True)
882 def follow(repo, subset, x):
894 def follow(repo, subset, x):
883 """
895 """
884 An alias for ``::.`` (ancestors of the working directory's first parent).
896 An alias for ``::.`` (ancestors of the working directory's first parent).
885 If pattern is specified, the histories of files matching given
897 If pattern is specified, the histories of files matching given
886 pattern in the revision given by startrev are followed, including copies.
898 pattern in the revision given by startrev are followed, including copies.
887 """
899 """
888 return _follow(repo, subset, x, 'follow')
900 return _follow(repo, subset, x, 'follow')
889
901
890 @predicate('_followfirst', safe=True)
902 @predicate('_followfirst', safe=True)
891 def _followfirst(repo, subset, x):
903 def _followfirst(repo, subset, x):
892 # ``followfirst([pattern[, startrev]])``
904 # ``followfirst([pattern[, startrev]])``
893 # Like ``follow([pattern[, startrev]])`` but follows only the first parent
905 # Like ``follow([pattern[, startrev]])`` but follows only the first parent
894 # of every revisions or files revisions.
906 # of every revisions or files revisions.
895 return _follow(repo, subset, x, '_followfirst', followfirst=True)
907 return _follow(repo, subset, x, '_followfirst', followfirst=True)
896
908
897 @predicate('followlines(file, fromline:toline[, startrev=., descend=False])',
909 @predicate('followlines(file, fromline:toline[, startrev=., descend=False])',
898 safe=True)
910 safe=True)
899 def followlines(repo, subset, x):
911 def followlines(repo, subset, x):
900 """Changesets modifying `file` in line range ('fromline', 'toline').
912 """Changesets modifying `file` in line range ('fromline', 'toline').
901
913
902 Line range corresponds to 'file' content at 'startrev' and should hence be
914 Line range corresponds to 'file' content at 'startrev' and should hence be
903 consistent with file size. If startrev is not specified, working directory's
915 consistent with file size. If startrev is not specified, working directory's
904 parent is used.
916 parent is used.
905
917
906 By default, ancestors of 'startrev' are returned. If 'descend' is True,
918 By default, ancestors of 'startrev' are returned. If 'descend' is True,
907 descendants of 'startrev' are returned though renames are (currently) not
919 descendants of 'startrev' are returned though renames are (currently) not
908 followed in this direction.
920 followed in this direction.
909 """
921 """
910 args = getargsdict(x, 'followlines', 'file *lines startrev descend')
922 args = getargsdict(x, 'followlines', 'file *lines startrev descend')
911 if len(args['lines']) != 1:
923 if len(args['lines']) != 1:
912 raise error.ParseError(_("followlines requires a line range"))
924 raise error.ParseError(_("followlines requires a line range"))
913
925
914 rev = '.'
926 rev = '.'
915 if 'startrev' in args:
927 if 'startrev' in args:
916 revs = getset(repo, fullreposet(repo), args['startrev'])
928 revs = getset(repo, fullreposet(repo), args['startrev'])
917 if len(revs) != 1:
929 if len(revs) != 1:
918 raise error.ParseError(
930 raise error.ParseError(
919 # i18n: "followlines" is a keyword
931 # i18n: "followlines" is a keyword
920 _("followlines expects exactly one revision"))
932 _("followlines expects exactly one revision"))
921 rev = revs.last()
933 rev = revs.last()
922
934
923 pat = getstring(args['file'], _("followlines requires a pattern"))
935 pat = getstring(args['file'], _("followlines requires a pattern"))
924 if not matchmod.patkind(pat):
936 if not matchmod.patkind(pat):
925 fname = pathutil.canonpath(repo.root, repo.getcwd(), pat)
937 fname = pathutil.canonpath(repo.root, repo.getcwd(), pat)
926 else:
938 else:
927 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=repo[rev])
939 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=repo[rev])
928 files = [f for f in repo[rev] if m(f)]
940 files = [f for f in repo[rev] if m(f)]
929 if len(files) != 1:
941 if len(files) != 1:
930 # i18n: "followlines" is a keyword
942 # i18n: "followlines" is a keyword
931 raise error.ParseError(_("followlines expects exactly one file"))
943 raise error.ParseError(_("followlines expects exactly one file"))
932 fname = files[0]
944 fname = files[0]
933
945
934 # i18n: "followlines" is a keyword
946 # i18n: "followlines" is a keyword
935 lr = getrange(args['lines'][0], _("followlines expects a line range"))
947 lr = getrange(args['lines'][0], _("followlines expects a line range"))
936 fromline, toline = [getinteger(a, _("line range bounds must be integers"))
948 fromline, toline = [getinteger(a, _("line range bounds must be integers"))
937 for a in lr]
949 for a in lr]
938 fromline, toline = util.processlinerange(fromline, toline)
950 fromline, toline = util.processlinerange(fromline, toline)
939
951
940 fctx = repo[rev].filectx(fname)
952 fctx = repo[rev].filectx(fname)
941 descend = False
953 descend = False
942 if 'descend' in args:
954 if 'descend' in args:
943 descend = getboolean(args['descend'],
955 descend = getboolean(args['descend'],
944 # i18n: "descend" is a keyword
956 # i18n: "descend" is a keyword
945 _("descend argument must be a boolean"))
957 _("descend argument must be a boolean"))
946 if descend:
958 if descend:
947 rs = generatorset(
959 rs = generatorset(
948 (c.rev() for c, _linerange
960 (c.rev() for c, _linerange
949 in dagop.blockdescendants(fctx, fromline, toline)),
961 in dagop.blockdescendants(fctx, fromline, toline)),
950 iterasc=True)
962 iterasc=True)
951 else:
963 else:
952 rs = generatorset(
964 rs = generatorset(
953 (c.rev() for c, _linerange
965 (c.rev() for c, _linerange
954 in dagop.blockancestors(fctx, fromline, toline)),
966 in dagop.blockancestors(fctx, fromline, toline)),
955 iterasc=False)
967 iterasc=False)
956 return subset & rs
968 return subset & rs
957
969
958 @predicate('all()', safe=True)
970 @predicate('all()', safe=True)
959 def getall(repo, subset, x):
971 def getall(repo, subset, x):
960 """All changesets, the same as ``0:tip``.
972 """All changesets, the same as ``0:tip``.
961 """
973 """
962 # i18n: "all" is a keyword
974 # i18n: "all" is a keyword
963 getargs(x, 0, 0, _("all takes no arguments"))
975 getargs(x, 0, 0, _("all takes no arguments"))
964 return subset & spanset(repo) # drop "null" if any
976 return subset & spanset(repo) # drop "null" if any
965
977
966 @predicate('grep(regex)')
978 @predicate('grep(regex)')
967 def grep(repo, subset, x):
979 def grep(repo, subset, x):
968 """Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
980 """Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
969 to ensure special escape characters are handled correctly. Unlike
981 to ensure special escape characters are handled correctly. Unlike
970 ``keyword(string)``, the match is case-sensitive.
982 ``keyword(string)``, the match is case-sensitive.
971 """
983 """
972 try:
984 try:
973 # i18n: "grep" is a keyword
985 # i18n: "grep" is a keyword
974 gr = re.compile(getstring(x, _("grep requires a string")))
986 gr = re.compile(getstring(x, _("grep requires a string")))
975 except re.error as e:
987 except re.error as e:
976 raise error.ParseError(_('invalid match pattern: %s') % e)
988 raise error.ParseError(_('invalid match pattern: %s') % e)
977
989
978 def matches(x):
990 def matches(x):
979 c = repo[x]
991 c = repo[x]
980 for e in c.files() + [c.user(), c.description()]:
992 for e in c.files() + [c.user(), c.description()]:
981 if gr.search(e):
993 if gr.search(e):
982 return True
994 return True
983 return False
995 return False
984
996
985 return subset.filter(matches, condrepr=('<grep %r>', gr.pattern))
997 return subset.filter(matches, condrepr=('<grep %r>', gr.pattern))
986
998
987 @predicate('_matchfiles', safe=True)
999 @predicate('_matchfiles', safe=True)
988 def _matchfiles(repo, subset, x):
1000 def _matchfiles(repo, subset, x):
989 # _matchfiles takes a revset list of prefixed arguments:
1001 # _matchfiles takes a revset list of prefixed arguments:
990 #
1002 #
991 # [p:foo, i:bar, x:baz]
1003 # [p:foo, i:bar, x:baz]
992 #
1004 #
993 # builds a match object from them and filters subset. Allowed
1005 # builds a match object from them and filters subset. Allowed
994 # prefixes are 'p:' for regular patterns, 'i:' for include
1006 # prefixes are 'p:' for regular patterns, 'i:' for include
995 # patterns and 'x:' for exclude patterns. Use 'r:' prefix to pass
1007 # patterns and 'x:' for exclude patterns. Use 'r:' prefix to pass
996 # a revision identifier, or the empty string to reference the
1008 # a revision identifier, or the empty string to reference the
997 # working directory, from which the match object is
1009 # working directory, from which the match object is
998 # initialized. Use 'd:' to set the default matching mode, default
1010 # initialized. Use 'd:' to set the default matching mode, default
999 # to 'glob'. At most one 'r:' and 'd:' argument can be passed.
1011 # to 'glob'. At most one 'r:' and 'd:' argument can be passed.
1000
1012
1001 l = getargs(x, 1, -1, "_matchfiles requires at least one argument")
1013 l = getargs(x, 1, -1, "_matchfiles requires at least one argument")
1002 pats, inc, exc = [], [], []
1014 pats, inc, exc = [], [], []
1003 rev, default = None, None
1015 rev, default = None, None
1004 for arg in l:
1016 for arg in l:
1005 s = getstring(arg, "_matchfiles requires string arguments")
1017 s = getstring(arg, "_matchfiles requires string arguments")
1006 prefix, value = s[:2], s[2:]
1018 prefix, value = s[:2], s[2:]
1007 if prefix == 'p:':
1019 if prefix == 'p:':
1008 pats.append(value)
1020 pats.append(value)
1009 elif prefix == 'i:':
1021 elif prefix == 'i:':
1010 inc.append(value)
1022 inc.append(value)
1011 elif prefix == 'x:':
1023 elif prefix == 'x:':
1012 exc.append(value)
1024 exc.append(value)
1013 elif prefix == 'r:':
1025 elif prefix == 'r:':
1014 if rev is not None:
1026 if rev is not None:
1015 raise error.ParseError('_matchfiles expected at most one '
1027 raise error.ParseError('_matchfiles expected at most one '
1016 'revision')
1028 'revision')
1017 if value != '': # empty means working directory; leave rev as None
1029 if value != '': # empty means working directory; leave rev as None
1018 rev = value
1030 rev = value
1019 elif prefix == 'd:':
1031 elif prefix == 'd:':
1020 if default is not None:
1032 if default is not None:
1021 raise error.ParseError('_matchfiles expected at most one '
1033 raise error.ParseError('_matchfiles expected at most one '
1022 'default mode')
1034 'default mode')
1023 default = value
1035 default = value
1024 else:
1036 else:
1025 raise error.ParseError('invalid _matchfiles prefix: %s' % prefix)
1037 raise error.ParseError('invalid _matchfiles prefix: %s' % prefix)
1026 if not default:
1038 if not default:
1027 default = 'glob'
1039 default = 'glob'
1028
1040
1029 m = matchmod.match(repo.root, repo.getcwd(), pats, include=inc,
1041 m = matchmod.match(repo.root, repo.getcwd(), pats, include=inc,
1030 exclude=exc, ctx=repo[rev], default=default)
1042 exclude=exc, ctx=repo[rev], default=default)
1031
1043
1032 # This directly read the changelog data as creating changectx for all
1044 # This directly read the changelog data as creating changectx for all
1033 # revisions is quite expensive.
1045 # revisions is quite expensive.
1034 getfiles = repo.changelog.readfiles
1046 getfiles = repo.changelog.readfiles
1035 wdirrev = node.wdirrev
1047 wdirrev = node.wdirrev
1036 def matches(x):
1048 def matches(x):
1037 if x == wdirrev:
1049 if x == wdirrev:
1038 files = repo[x].files()
1050 files = repo[x].files()
1039 else:
1051 else:
1040 files = getfiles(x)
1052 files = getfiles(x)
1041 for f in files:
1053 for f in files:
1042 if m(f):
1054 if m(f):
1043 return True
1055 return True
1044 return False
1056 return False
1045
1057
1046 return subset.filter(matches,
1058 return subset.filter(matches,
1047 condrepr=('<matchfiles patterns=%r, include=%r '
1059 condrepr=('<matchfiles patterns=%r, include=%r '
1048 'exclude=%r, default=%r, rev=%r>',
1060 'exclude=%r, default=%r, rev=%r>',
1049 pats, inc, exc, default, rev))
1061 pats, inc, exc, default, rev))
1050
1062
1051 @predicate('file(pattern)', safe=True)
1063 @predicate('file(pattern)', safe=True)
1052 def hasfile(repo, subset, x):
1064 def hasfile(repo, subset, x):
1053 """Changesets affecting files matched by pattern.
1065 """Changesets affecting files matched by pattern.
1054
1066
1055 For a faster but less accurate result, consider using ``filelog()``
1067 For a faster but less accurate result, consider using ``filelog()``
1056 instead.
1068 instead.
1057
1069
1058 This predicate uses ``glob:`` as the default kind of pattern.
1070 This predicate uses ``glob:`` as the default kind of pattern.
1059 """
1071 """
1060 # i18n: "file" is a keyword
1072 # i18n: "file" is a keyword
1061 pat = getstring(x, _("file requires a pattern"))
1073 pat = getstring(x, _("file requires a pattern"))
1062 return _matchfiles(repo, subset, ('string', 'p:' + pat))
1074 return _matchfiles(repo, subset, ('string', 'p:' + pat))
1063
1075
1064 @predicate('head()', safe=True)
1076 @predicate('head()', safe=True)
1065 def head(repo, subset, x):
1077 def head(repo, subset, x):
1066 """Changeset is a named branch head.
1078 """Changeset is a named branch head.
1067 """
1079 """
1068 # i18n: "head" is a keyword
1080 # i18n: "head" is a keyword
1069 getargs(x, 0, 0, _("head takes no arguments"))
1081 getargs(x, 0, 0, _("head takes no arguments"))
1070 hs = set()
1082 hs = set()
1071 cl = repo.changelog
1083 cl = repo.changelog
1072 for ls in repo.branchmap().itervalues():
1084 for ls in repo.branchmap().itervalues():
1073 hs.update(cl.rev(h) for h in ls)
1085 hs.update(cl.rev(h) for h in ls)
1074 return subset & baseset(hs)
1086 return subset & baseset(hs)
1075
1087
1076 @predicate('heads(set)', safe=True)
1088 @predicate('heads(set)', safe=True)
1077 def heads(repo, subset, x):
1089 def heads(repo, subset, x):
1078 """Members of set with no children in set.
1090 """Members of set with no children in set.
1079 """
1091 """
1080 s = getset(repo, subset, x)
1092 s = getset(repo, subset, x)
1081 ps = parents(repo, subset, x)
1093 ps = parents(repo, subset, x)
1082 return s - ps
1094 return s - ps
1083
1095
1084 @predicate('hidden()', safe=True)
1096 @predicate('hidden()', safe=True)
1085 def hidden(repo, subset, x):
1097 def hidden(repo, subset, x):
1086 """Hidden changesets.
1098 """Hidden changesets.
1087 """
1099 """
1088 # i18n: "hidden" is a keyword
1100 # i18n: "hidden" is a keyword
1089 getargs(x, 0, 0, _("hidden takes no arguments"))
1101 getargs(x, 0, 0, _("hidden takes no arguments"))
1090 hiddenrevs = repoview.filterrevs(repo, 'visible')
1102 hiddenrevs = repoview.filterrevs(repo, 'visible')
1091 return subset & hiddenrevs
1103 return subset & hiddenrevs
1092
1104
1093 @predicate('keyword(string)', safe=True)
1105 @predicate('keyword(string)', safe=True)
1094 def keyword(repo, subset, x):
1106 def keyword(repo, subset, x):
1095 """Search commit message, user name, and names of changed files for
1107 """Search commit message, user name, and names of changed files for
1096 string. The match is case-insensitive.
1108 string. The match is case-insensitive.
1097
1109
1098 For a regular expression or case sensitive search of these fields, use
1110 For a regular expression or case sensitive search of these fields, use
1099 ``grep(regex)``.
1111 ``grep(regex)``.
1100 """
1112 """
1101 # i18n: "keyword" is a keyword
1113 # i18n: "keyword" is a keyword
1102 kw = encoding.lower(getstring(x, _("keyword requires a string")))
1114 kw = encoding.lower(getstring(x, _("keyword requires a string")))
1103
1115
1104 def matches(r):
1116 def matches(r):
1105 c = repo[r]
1117 c = repo[r]
1106 return any(kw in encoding.lower(t)
1118 return any(kw in encoding.lower(t)
1107 for t in c.files() + [c.user(), c.description()])
1119 for t in c.files() + [c.user(), c.description()])
1108
1120
1109 return subset.filter(matches, condrepr=('<keyword %r>', kw))
1121 return subset.filter(matches, condrepr=('<keyword %r>', kw))
1110
1122
1111 @predicate('limit(set[, n[, offset]])', safe=True, takeorder=True)
1123 @predicate('limit(set[, n[, offset]])', safe=True, takeorder=True)
1112 def limit(repo, subset, x, order):
1124 def limit(repo, subset, x, order):
1113 """First n members of set, defaulting to 1, starting from offset.
1125 """First n members of set, defaulting to 1, starting from offset.
1114 """
1126 """
1115 args = getargsdict(x, 'limit', 'set n offset')
1127 args = getargsdict(x, 'limit', 'set n offset')
1116 if 'set' not in args:
1128 if 'set' not in args:
1117 # i18n: "limit" is a keyword
1129 # i18n: "limit" is a keyword
1118 raise error.ParseError(_("limit requires one to three arguments"))
1130 raise error.ParseError(_("limit requires one to three arguments"))
1119 # i18n: "limit" is a keyword
1131 # i18n: "limit" is a keyword
1120 lim = getinteger(args.get('n'), _("limit expects a number"), default=1)
1132 lim = getinteger(args.get('n'), _("limit expects a number"), default=1)
1121 if lim < 0:
1133 if lim < 0:
1122 raise error.ParseError(_("negative number to select"))
1134 raise error.ParseError(_("negative number to select"))
1123 # i18n: "limit" is a keyword
1135 # i18n: "limit" is a keyword
1124 ofs = getinteger(args.get('offset'), _("limit expects a number"), default=0)
1136 ofs = getinteger(args.get('offset'), _("limit expects a number"), default=0)
1125 if ofs < 0:
1137 if ofs < 0:
1126 raise error.ParseError(_("negative offset"))
1138 raise error.ParseError(_("negative offset"))
1127 os = getset(repo, fullreposet(repo), args['set'])
1139 os = getset(repo, fullreposet(repo), args['set'])
1128 ls = os.slice(ofs, ofs + lim)
1140 ls = os.slice(ofs, ofs + lim)
1129 if order == followorder and lim > 1:
1141 if order == followorder and lim > 1:
1130 return subset & ls
1142 return subset & ls
1131 return ls & subset
1143 return ls & subset
1132
1144
1133 @predicate('last(set, [n])', safe=True, takeorder=True)
1145 @predicate('last(set, [n])', safe=True, takeorder=True)
1134 def last(repo, subset, x, order):
1146 def last(repo, subset, x, order):
1135 """Last n members of set, defaulting to 1.
1147 """Last n members of set, defaulting to 1.
1136 """
1148 """
1137 # i18n: "last" is a keyword
1149 # i18n: "last" is a keyword
1138 l = getargs(x, 1, 2, _("last requires one or two arguments"))
1150 l = getargs(x, 1, 2, _("last requires one or two arguments"))
1139 lim = 1
1151 lim = 1
1140 if len(l) == 2:
1152 if len(l) == 2:
1141 # i18n: "last" is a keyword
1153 # i18n: "last" is a keyword
1142 lim = getinteger(l[1], _("last expects a number"))
1154 lim = getinteger(l[1], _("last expects a number"))
1143 if lim < 0:
1155 if lim < 0:
1144 raise error.ParseError(_("negative number to select"))
1156 raise error.ParseError(_("negative number to select"))
1145 os = getset(repo, fullreposet(repo), l[0])
1157 os = getset(repo, fullreposet(repo), l[0])
1146 os.reverse()
1158 os.reverse()
1147 ls = os.slice(0, lim)
1159 ls = os.slice(0, lim)
1148 if order == followorder and lim > 1:
1160 if order == followorder and lim > 1:
1149 return subset & ls
1161 return subset & ls
1150 ls.reverse()
1162 ls.reverse()
1151 return ls & subset
1163 return ls & subset
1152
1164
1153 @predicate('max(set)', safe=True)
1165 @predicate('max(set)', safe=True)
1154 def maxrev(repo, subset, x):
1166 def maxrev(repo, subset, x):
1155 """Changeset with highest revision number in set.
1167 """Changeset with highest revision number in set.
1156 """
1168 """
1157 os = getset(repo, fullreposet(repo), x)
1169 os = getset(repo, fullreposet(repo), x)
1158 try:
1170 try:
1159 m = os.max()
1171 m = os.max()
1160 if m in subset:
1172 if m in subset:
1161 return baseset([m], datarepr=('<max %r, %r>', subset, os))
1173 return baseset([m], datarepr=('<max %r, %r>', subset, os))
1162 except ValueError:
1174 except ValueError:
1163 # os.max() throws a ValueError when the collection is empty.
1175 # os.max() throws a ValueError when the collection is empty.
1164 # Same as python's max().
1176 # Same as python's max().
1165 pass
1177 pass
1166 return baseset(datarepr=('<max %r, %r>', subset, os))
1178 return baseset(datarepr=('<max %r, %r>', subset, os))
1167
1179
1168 @predicate('merge()', safe=True)
1180 @predicate('merge()', safe=True)
1169 def merge(repo, subset, x):
1181 def merge(repo, subset, x):
1170 """Changeset is a merge changeset.
1182 """Changeset is a merge changeset.
1171 """
1183 """
1172 # i18n: "merge" is a keyword
1184 # i18n: "merge" is a keyword
1173 getargs(x, 0, 0, _("merge takes no arguments"))
1185 getargs(x, 0, 0, _("merge takes no arguments"))
1174 cl = repo.changelog
1186 cl = repo.changelog
1175 return subset.filter(lambda r: cl.parentrevs(r)[1] != -1,
1187 return subset.filter(lambda r: cl.parentrevs(r)[1] != -1,
1176 condrepr='<merge>')
1188 condrepr='<merge>')
1177
1189
1178 @predicate('branchpoint()', safe=True)
1190 @predicate('branchpoint()', safe=True)
1179 def branchpoint(repo, subset, x):
1191 def branchpoint(repo, subset, x):
1180 """Changesets with more than one child.
1192 """Changesets with more than one child.
1181 """
1193 """
1182 # i18n: "branchpoint" is a keyword
1194 # i18n: "branchpoint" is a keyword
1183 getargs(x, 0, 0, _("branchpoint takes no arguments"))
1195 getargs(x, 0, 0, _("branchpoint takes no arguments"))
1184 cl = repo.changelog
1196 cl = repo.changelog
1185 if not subset:
1197 if not subset:
1186 return baseset()
1198 return baseset()
1187 # XXX this should be 'parentset.min()' assuming 'parentset' is a smartset
1199 # XXX this should be 'parentset.min()' assuming 'parentset' is a smartset
1188 # (and if it is not, it should.)
1200 # (and if it is not, it should.)
1189 baserev = min(subset)
1201 baserev = min(subset)
1190 parentscount = [0]*(len(repo) - baserev)
1202 parentscount = [0]*(len(repo) - baserev)
1191 for r in cl.revs(start=baserev + 1):
1203 for r in cl.revs(start=baserev + 1):
1192 for p in cl.parentrevs(r):
1204 for p in cl.parentrevs(r):
1193 if p >= baserev:
1205 if p >= baserev:
1194 parentscount[p - baserev] += 1
1206 parentscount[p - baserev] += 1
1195 return subset.filter(lambda r: parentscount[r - baserev] > 1,
1207 return subset.filter(lambda r: parentscount[r - baserev] > 1,
1196 condrepr='<branchpoint>')
1208 condrepr='<branchpoint>')
1197
1209
1198 @predicate('min(set)', safe=True)
1210 @predicate('min(set)', safe=True)
1199 def minrev(repo, subset, x):
1211 def minrev(repo, subset, x):
1200 """Changeset with lowest revision number in set.
1212 """Changeset with lowest revision number in set.
1201 """
1213 """
1202 os = getset(repo, fullreposet(repo), x)
1214 os = getset(repo, fullreposet(repo), x)
1203 try:
1215 try:
1204 m = os.min()
1216 m = os.min()
1205 if m in subset:
1217 if m in subset:
1206 return baseset([m], datarepr=('<min %r, %r>', subset, os))
1218 return baseset([m], datarepr=('<min %r, %r>', subset, os))
1207 except ValueError:
1219 except ValueError:
1208 # os.min() throws a ValueError when the collection is empty.
1220 # os.min() throws a ValueError when the collection is empty.
1209 # Same as python's min().
1221 # Same as python's min().
1210 pass
1222 pass
1211 return baseset(datarepr=('<min %r, %r>', subset, os))
1223 return baseset(datarepr=('<min %r, %r>', subset, os))
1212
1224
1213 @predicate('modifies(pattern)', safe=True)
1225 @predicate('modifies(pattern)', safe=True)
1214 def modifies(repo, subset, x):
1226 def modifies(repo, subset, x):
1215 """Changesets modifying files matched by pattern.
1227 """Changesets modifying files matched by pattern.
1216
1228
1217 The pattern without explicit kind like ``glob:`` is expected to be
1229 The pattern without explicit kind like ``glob:`` is expected to be
1218 relative to the current directory and match against a file or a
1230 relative to the current directory and match against a file or a
1219 directory.
1231 directory.
1220 """
1232 """
1221 # i18n: "modifies" is a keyword
1233 # i18n: "modifies" is a keyword
1222 pat = getstring(x, _("modifies requires a pattern"))
1234 pat = getstring(x, _("modifies requires a pattern"))
1223 return checkstatus(repo, subset, pat, 0)
1235 return checkstatus(repo, subset, pat, 0)
1224
1236
1225 @predicate('named(namespace)')
1237 @predicate('named(namespace)')
1226 def named(repo, subset, x):
1238 def named(repo, subset, x):
1227 """The changesets in a given namespace.
1239 """The changesets in a given namespace.
1228
1240
1229 Pattern matching is supported for `namespace`. See
1241 Pattern matching is supported for `namespace`. See
1230 :hg:`help revisions.patterns`.
1242 :hg:`help revisions.patterns`.
1231 """
1243 """
1232 # i18n: "named" is a keyword
1244 # i18n: "named" is a keyword
1233 args = getargs(x, 1, 1, _('named requires a namespace argument'))
1245 args = getargs(x, 1, 1, _('named requires a namespace argument'))
1234
1246
1235 ns = getstring(args[0],
1247 ns = getstring(args[0],
1236 # i18n: "named" is a keyword
1248 # i18n: "named" is a keyword
1237 _('the argument to named must be a string'))
1249 _('the argument to named must be a string'))
1238 kind, pattern, matcher = util.stringmatcher(ns)
1250 kind, pattern, matcher = util.stringmatcher(ns)
1239 namespaces = set()
1251 namespaces = set()
1240 if kind == 'literal':
1252 if kind == 'literal':
1241 if pattern not in repo.names:
1253 if pattern not in repo.names:
1242 raise error.RepoLookupError(_("namespace '%s' does not exist")
1254 raise error.RepoLookupError(_("namespace '%s' does not exist")
1243 % ns)
1255 % ns)
1244 namespaces.add(repo.names[pattern])
1256 namespaces.add(repo.names[pattern])
1245 else:
1257 else:
1246 for name, ns in repo.names.iteritems():
1258 for name, ns in repo.names.iteritems():
1247 if matcher(name):
1259 if matcher(name):
1248 namespaces.add(ns)
1260 namespaces.add(ns)
1249 if not namespaces:
1261 if not namespaces:
1250 raise error.RepoLookupError(_("no namespace exists"
1262 raise error.RepoLookupError(_("no namespace exists"
1251 " that match '%s'") % pattern)
1263 " that match '%s'") % pattern)
1252
1264
1253 names = set()
1265 names = set()
1254 for ns in namespaces:
1266 for ns in namespaces:
1255 for name in ns.listnames(repo):
1267 for name in ns.listnames(repo):
1256 if name not in ns.deprecated:
1268 if name not in ns.deprecated:
1257 names.update(repo[n].rev() for n in ns.nodes(repo, name))
1269 names.update(repo[n].rev() for n in ns.nodes(repo, name))
1258
1270
1259 names -= {node.nullrev}
1271 names -= {node.nullrev}
1260 return subset & names
1272 return subset & names
1261
1273
1262 @predicate('id(string)', safe=True)
1274 @predicate('id(string)', safe=True)
1263 def node_(repo, subset, x):
1275 def node_(repo, subset, x):
1264 """Revision non-ambiguously specified by the given hex string prefix.
1276 """Revision non-ambiguously specified by the given hex string prefix.
1265 """
1277 """
1266 # i18n: "id" is a keyword
1278 # i18n: "id" is a keyword
1267 l = getargs(x, 1, 1, _("id requires one argument"))
1279 l = getargs(x, 1, 1, _("id requires one argument"))
1268 # i18n: "id" is a keyword
1280 # i18n: "id" is a keyword
1269 n = getstring(l[0], _("id requires a string"))
1281 n = getstring(l[0], _("id requires a string"))
1270 if len(n) == 40:
1282 if len(n) == 40:
1271 try:
1283 try:
1272 rn = repo.changelog.rev(node.bin(n))
1284 rn = repo.changelog.rev(node.bin(n))
1273 except error.WdirUnsupported:
1285 except error.WdirUnsupported:
1274 rn = node.wdirrev
1286 rn = node.wdirrev
1275 except (LookupError, TypeError):
1287 except (LookupError, TypeError):
1276 rn = None
1288 rn = None
1277 else:
1289 else:
1278 rn = None
1290 rn = None
1279 try:
1291 try:
1280 pm = repo.changelog._partialmatch(n)
1292 pm = repo.changelog._partialmatch(n)
1281 if pm is not None:
1293 if pm is not None:
1282 rn = repo.changelog.rev(pm)
1294 rn = repo.changelog.rev(pm)
1283 except error.WdirUnsupported:
1295 except error.WdirUnsupported:
1284 rn = node.wdirrev
1296 rn = node.wdirrev
1285
1297
1286 if rn is None:
1298 if rn is None:
1287 return baseset()
1299 return baseset()
1288 result = baseset([rn])
1300 result = baseset([rn])
1289 return result & subset
1301 return result & subset
1290
1302
1291 @predicate('obsolete()', safe=True)
1303 @predicate('obsolete()', safe=True)
1292 def obsolete(repo, subset, x):
1304 def obsolete(repo, subset, x):
1293 """Mutable changeset with a newer version."""
1305 """Mutable changeset with a newer version."""
1294 # i18n: "obsolete" is a keyword
1306 # i18n: "obsolete" is a keyword
1295 getargs(x, 0, 0, _("obsolete takes no arguments"))
1307 getargs(x, 0, 0, _("obsolete takes no arguments"))
1296 obsoletes = obsmod.getrevs(repo, 'obsolete')
1308 obsoletes = obsmod.getrevs(repo, 'obsolete')
1297 return subset & obsoletes
1309 return subset & obsoletes
1298
1310
1299 @predicate('only(set, [set])', safe=True)
1311 @predicate('only(set, [set])', safe=True)
1300 def only(repo, subset, x):
1312 def only(repo, subset, x):
1301 """Changesets that are ancestors of the first set that are not ancestors
1313 """Changesets that are ancestors of the first set that are not ancestors
1302 of any other head in the repo. If a second set is specified, the result
1314 of any other head in the repo. If a second set is specified, the result
1303 is ancestors of the first set that are not ancestors of the second set
1315 is ancestors of the first set that are not ancestors of the second set
1304 (i.e. ::<set1> - ::<set2>).
1316 (i.e. ::<set1> - ::<set2>).
1305 """
1317 """
1306 cl = repo.changelog
1318 cl = repo.changelog
1307 # i18n: "only" is a keyword
1319 # i18n: "only" is a keyword
1308 args = getargs(x, 1, 2, _('only takes one or two arguments'))
1320 args = getargs(x, 1, 2, _('only takes one or two arguments'))
1309 include = getset(repo, fullreposet(repo), args[0])
1321 include = getset(repo, fullreposet(repo), args[0])
1310 if len(args) == 1:
1322 if len(args) == 1:
1311 if not include:
1323 if not include:
1312 return baseset()
1324 return baseset()
1313
1325
1314 descendants = set(dagop.revdescendants(repo, include, False))
1326 descendants = set(dagop.revdescendants(repo, include, False))
1315 exclude = [rev for rev in cl.headrevs()
1327 exclude = [rev for rev in cl.headrevs()
1316 if not rev in descendants and not rev in include]
1328 if not rev in descendants and not rev in include]
1317 else:
1329 else:
1318 exclude = getset(repo, fullreposet(repo), args[1])
1330 exclude = getset(repo, fullreposet(repo), args[1])
1319
1331
1320 results = set(cl.findmissingrevs(common=exclude, heads=include))
1332 results = set(cl.findmissingrevs(common=exclude, heads=include))
1321 # XXX we should turn this into a baseset instead of a set, smartset may do
1333 # XXX we should turn this into a baseset instead of a set, smartset may do
1322 # some optimizations from the fact this is a baseset.
1334 # some optimizations from the fact this is a baseset.
1323 return subset & results
1335 return subset & results
1324
1336
1325 @predicate('origin([set])', safe=True)
1337 @predicate('origin([set])', safe=True)
1326 def origin(repo, subset, x):
1338 def origin(repo, subset, x):
1327 """
1339 """
1328 Changesets that were specified as a source for the grafts, transplants or
1340 Changesets that were specified as a source for the grafts, transplants or
1329 rebases that created the given revisions. Omitting the optional set is the
1341 rebases that created the given revisions. Omitting the optional set is the
1330 same as passing all(). If a changeset created by these operations is itself
1342 same as passing all(). If a changeset created by these operations is itself
1331 specified as a source for one of these operations, only the source changeset
1343 specified as a source for one of these operations, only the source changeset
1332 for the first operation is selected.
1344 for the first operation is selected.
1333 """
1345 """
1334 if x is not None:
1346 if x is not None:
1335 dests = getset(repo, fullreposet(repo), x)
1347 dests = getset(repo, fullreposet(repo), x)
1336 else:
1348 else:
1337 dests = fullreposet(repo)
1349 dests = fullreposet(repo)
1338
1350
1339 def _firstsrc(rev):
1351 def _firstsrc(rev):
1340 src = _getrevsource(repo, rev)
1352 src = _getrevsource(repo, rev)
1341 if src is None:
1353 if src is None:
1342 return None
1354 return None
1343
1355
1344 while True:
1356 while True:
1345 prev = _getrevsource(repo, src)
1357 prev = _getrevsource(repo, src)
1346
1358
1347 if prev is None:
1359 if prev is None:
1348 return src
1360 return src
1349 src = prev
1361 src = prev
1350
1362
1351 o = {_firstsrc(r) for r in dests}
1363 o = {_firstsrc(r) for r in dests}
1352 o -= {None}
1364 o -= {None}
1353 # XXX we should turn this into a baseset instead of a set, smartset may do
1365 # XXX we should turn this into a baseset instead of a set, smartset may do
1354 # some optimizations from the fact this is a baseset.
1366 # some optimizations from the fact this is a baseset.
1355 return subset & o
1367 return subset & o
1356
1368
1357 @predicate('outgoing([path])', safe=False)
1369 @predicate('outgoing([path])', safe=False)
1358 def outgoing(repo, subset, x):
1370 def outgoing(repo, subset, x):
1359 """Changesets not found in the specified destination repository, or the
1371 """Changesets not found in the specified destination repository, or the
1360 default push location.
1372 default push location.
1361 """
1373 """
1362 # Avoid cycles.
1374 # Avoid cycles.
1363 from . import (
1375 from . import (
1364 discovery,
1376 discovery,
1365 hg,
1377 hg,
1366 )
1378 )
1367 # i18n: "outgoing" is a keyword
1379 # i18n: "outgoing" is a keyword
1368 l = getargs(x, 0, 1, _("outgoing takes one or no arguments"))
1380 l = getargs(x, 0, 1, _("outgoing takes one or no arguments"))
1369 # i18n: "outgoing" is a keyword
1381 # i18n: "outgoing" is a keyword
1370 dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
1382 dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
1371 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
1383 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
1372 dest, branches = hg.parseurl(dest)
1384 dest, branches = hg.parseurl(dest)
1373 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1385 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1374 if revs:
1386 if revs:
1375 revs = [repo.lookup(rev) for rev in revs]
1387 revs = [repo.lookup(rev) for rev in revs]
1376 other = hg.peer(repo, {}, dest)
1388 other = hg.peer(repo, {}, dest)
1377 repo.ui.pushbuffer()
1389 repo.ui.pushbuffer()
1378 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs)
1390 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs)
1379 repo.ui.popbuffer()
1391 repo.ui.popbuffer()
1380 cl = repo.changelog
1392 cl = repo.changelog
1381 o = {cl.rev(r) for r in outgoing.missing}
1393 o = {cl.rev(r) for r in outgoing.missing}
1382 return subset & o
1394 return subset & o
1383
1395
1384 @predicate('p1([set])', safe=True)
1396 @predicate('p1([set])', safe=True)
1385 def p1(repo, subset, x):
1397 def p1(repo, subset, x):
1386 """First parent of changesets in set, or the working directory.
1398 """First parent of changesets in set, or the working directory.
1387 """
1399 """
1388 if x is None:
1400 if x is None:
1389 p = repo[x].p1().rev()
1401 p = repo[x].p1().rev()
1390 if p >= 0:
1402 if p >= 0:
1391 return subset & baseset([p])
1403 return subset & baseset([p])
1392 return baseset()
1404 return baseset()
1393
1405
1394 ps = set()
1406 ps = set()
1395 cl = repo.changelog
1407 cl = repo.changelog
1396 for r in getset(repo, fullreposet(repo), x):
1408 for r in getset(repo, fullreposet(repo), x):
1397 try:
1409 try:
1398 ps.add(cl.parentrevs(r)[0])
1410 ps.add(cl.parentrevs(r)[0])
1399 except error.WdirUnsupported:
1411 except error.WdirUnsupported:
1400 ps.add(repo[r].parents()[0].rev())
1412 ps.add(repo[r].parents()[0].rev())
1401 ps -= {node.nullrev}
1413 ps -= {node.nullrev}
1402 # XXX we should turn this into a baseset instead of a set, smartset may do
1414 # XXX we should turn this into a baseset instead of a set, smartset may do
1403 # some optimizations from the fact this is a baseset.
1415 # some optimizations from the fact this is a baseset.
1404 return subset & ps
1416 return subset & ps
1405
1417
1406 @predicate('p2([set])', safe=True)
1418 @predicate('p2([set])', safe=True)
1407 def p2(repo, subset, x):
1419 def p2(repo, subset, x):
1408 """Second parent of changesets in set, or the working directory.
1420 """Second parent of changesets in set, or the working directory.
1409 """
1421 """
1410 if x is None:
1422 if x is None:
1411 ps = repo[x].parents()
1423 ps = repo[x].parents()
1412 try:
1424 try:
1413 p = ps[1].rev()
1425 p = ps[1].rev()
1414 if p >= 0:
1426 if p >= 0:
1415 return subset & baseset([p])
1427 return subset & baseset([p])
1416 return baseset()
1428 return baseset()
1417 except IndexError:
1429 except IndexError:
1418 return baseset()
1430 return baseset()
1419
1431
1420 ps = set()
1432 ps = set()
1421 cl = repo.changelog
1433 cl = repo.changelog
1422 for r in getset(repo, fullreposet(repo), x):
1434 for r in getset(repo, fullreposet(repo), x):
1423 try:
1435 try:
1424 ps.add(cl.parentrevs(r)[1])
1436 ps.add(cl.parentrevs(r)[1])
1425 except error.WdirUnsupported:
1437 except error.WdirUnsupported:
1426 parents = repo[r].parents()
1438 parents = repo[r].parents()
1427 if len(parents) == 2:
1439 if len(parents) == 2:
1428 ps.add(parents[1])
1440 ps.add(parents[1])
1429 ps -= {node.nullrev}
1441 ps -= {node.nullrev}
1430 # XXX we should turn this into a baseset instead of a set, smartset may do
1442 # XXX we should turn this into a baseset instead of a set, smartset may do
1431 # some optimizations from the fact this is a baseset.
1443 # some optimizations from the fact this is a baseset.
1432 return subset & ps
1444 return subset & ps
1433
1445
1434 def parentpost(repo, subset, x, order):
1446 def parentpost(repo, subset, x, order):
1435 return p1(repo, subset, x)
1447 return p1(repo, subset, x)
1436
1448
1437 @predicate('parents([set])', safe=True)
1449 @predicate('parents([set])', safe=True)
1438 def parents(repo, subset, x):
1450 def parents(repo, subset, x):
1439 """
1451 """
1440 The set of all parents for all changesets in set, or the working directory.
1452 The set of all parents for all changesets in set, or the working directory.
1441 """
1453 """
1442 if x is None:
1454 if x is None:
1443 ps = set(p.rev() for p in repo[x].parents())
1455 ps = set(p.rev() for p in repo[x].parents())
1444 else:
1456 else:
1445 ps = set()
1457 ps = set()
1446 cl = repo.changelog
1458 cl = repo.changelog
1447 up = ps.update
1459 up = ps.update
1448 parentrevs = cl.parentrevs
1460 parentrevs = cl.parentrevs
1449 for r in getset(repo, fullreposet(repo), x):
1461 for r in getset(repo, fullreposet(repo), x):
1450 try:
1462 try:
1451 up(parentrevs(r))
1463 up(parentrevs(r))
1452 except error.WdirUnsupported:
1464 except error.WdirUnsupported:
1453 up(p.rev() for p in repo[r].parents())
1465 up(p.rev() for p in repo[r].parents())
1454 ps -= {node.nullrev}
1466 ps -= {node.nullrev}
1455 return subset & ps
1467 return subset & ps
1456
1468
1457 def _phase(repo, subset, *targets):
1469 def _phase(repo, subset, *targets):
1458 """helper to select all rev in <targets> phases"""
1470 """helper to select all rev in <targets> phases"""
1459 s = repo._phasecache.getrevset(repo, targets)
1471 s = repo._phasecache.getrevset(repo, targets)
1460 return subset & s
1472 return subset & s
1461
1473
1462 @predicate('draft()', safe=True)
1474 @predicate('draft()', safe=True)
1463 def draft(repo, subset, x):
1475 def draft(repo, subset, x):
1464 """Changeset in draft phase."""
1476 """Changeset in draft phase."""
1465 # i18n: "draft" is a keyword
1477 # i18n: "draft" is a keyword
1466 getargs(x, 0, 0, _("draft takes no arguments"))
1478 getargs(x, 0, 0, _("draft takes no arguments"))
1467 target = phases.draft
1479 target = phases.draft
1468 return _phase(repo, subset, target)
1480 return _phase(repo, subset, target)
1469
1481
1470 @predicate('secret()', safe=True)
1482 @predicate('secret()', safe=True)
1471 def secret(repo, subset, x):
1483 def secret(repo, subset, x):
1472 """Changeset in secret phase."""
1484 """Changeset in secret phase."""
1473 # i18n: "secret" is a keyword
1485 # i18n: "secret" is a keyword
1474 getargs(x, 0, 0, _("secret takes no arguments"))
1486 getargs(x, 0, 0, _("secret takes no arguments"))
1475 target = phases.secret
1487 target = phases.secret
1476 return _phase(repo, subset, target)
1488 return _phase(repo, subset, target)
1477
1489
1478 def parentspec(repo, subset, x, n, order):
1490 def parentspec(repo, subset, x, n, order):
1479 """``set^0``
1491 """``set^0``
1480 The set.
1492 The set.
1481 ``set^1`` (or ``set^``), ``set^2``
1493 ``set^1`` (or ``set^``), ``set^2``
1482 First or second parent, respectively, of all changesets in set.
1494 First or second parent, respectively, of all changesets in set.
1483 """
1495 """
1484 try:
1496 try:
1485 n = int(n[1])
1497 n = int(n[1])
1486 if n not in (0, 1, 2):
1498 if n not in (0, 1, 2):
1487 raise ValueError
1499 raise ValueError
1488 except (TypeError, ValueError):
1500 except (TypeError, ValueError):
1489 raise error.ParseError(_("^ expects a number 0, 1, or 2"))
1501 raise error.ParseError(_("^ expects a number 0, 1, or 2"))
1490 ps = set()
1502 ps = set()
1491 cl = repo.changelog
1503 cl = repo.changelog
1492 for r in getset(repo, fullreposet(repo), x):
1504 for r in getset(repo, fullreposet(repo), x):
1493 if n == 0:
1505 if n == 0:
1494 ps.add(r)
1506 ps.add(r)
1495 elif n == 1:
1507 elif n == 1:
1496 try:
1508 try:
1497 ps.add(cl.parentrevs(r)[0])
1509 ps.add(cl.parentrevs(r)[0])
1498 except error.WdirUnsupported:
1510 except error.WdirUnsupported:
1499 ps.add(repo[r].parents()[0].rev())
1511 ps.add(repo[r].parents()[0].rev())
1500 else:
1512 else:
1501 try:
1513 try:
1502 parents = cl.parentrevs(r)
1514 parents = cl.parentrevs(r)
1503 if parents[1] != node.nullrev:
1515 if parents[1] != node.nullrev:
1504 ps.add(parents[1])
1516 ps.add(parents[1])
1505 except error.WdirUnsupported:
1517 except error.WdirUnsupported:
1506 parents = repo[r].parents()
1518 parents = repo[r].parents()
1507 if len(parents) == 2:
1519 if len(parents) == 2:
1508 ps.add(parents[1].rev())
1520 ps.add(parents[1].rev())
1509 return subset & ps
1521 return subset & ps
1510
1522
1511 @predicate('present(set)', safe=True)
1523 @predicate('present(set)', safe=True, takeorder=True)
1512 def present(repo, subset, x):
1524 def present(repo, subset, x, order):
1513 """An empty set, if any revision in set isn't found; otherwise,
1525 """An empty set, if any revision in set isn't found; otherwise,
1514 all revisions in set.
1526 all revisions in set.
1515
1527
1516 If any of specified revisions is not present in the local repository,
1528 If any of specified revisions is not present in the local repository,
1517 the query is normally aborted. But this predicate allows the query
1529 the query is normally aborted. But this predicate allows the query
1518 to continue even in such cases.
1530 to continue even in such cases.
1519 """
1531 """
1520 try:
1532 try:
1521 return getset(repo, subset, x)
1533 return getset(repo, subset, x, order)
1522 except error.RepoLookupError:
1534 except error.RepoLookupError:
1523 return baseset()
1535 return baseset()
1524
1536
1525 # for internal use
1537 # for internal use
1526 @predicate('_notpublic', safe=True)
1538 @predicate('_notpublic', safe=True)
1527 def _notpublic(repo, subset, x):
1539 def _notpublic(repo, subset, x):
1528 getargs(x, 0, 0, "_notpublic takes no arguments")
1540 getargs(x, 0, 0, "_notpublic takes no arguments")
1529 return _phase(repo, subset, phases.draft, phases.secret)
1541 return _phase(repo, subset, phases.draft, phases.secret)
1530
1542
1531 @predicate('public()', safe=True)
1543 @predicate('public()', safe=True)
1532 def public(repo, subset, x):
1544 def public(repo, subset, x):
1533 """Changeset in public phase."""
1545 """Changeset in public phase."""
1534 # i18n: "public" is a keyword
1546 # i18n: "public" is a keyword
1535 getargs(x, 0, 0, _("public takes no arguments"))
1547 getargs(x, 0, 0, _("public takes no arguments"))
1536 phase = repo._phasecache.phase
1548 phase = repo._phasecache.phase
1537 target = phases.public
1549 target = phases.public
1538 condition = lambda r: phase(repo, r) == target
1550 condition = lambda r: phase(repo, r) == target
1539 return subset.filter(condition, condrepr=('<phase %r>', target),
1551 return subset.filter(condition, condrepr=('<phase %r>', target),
1540 cache=False)
1552 cache=False)
1541
1553
1542 @predicate('remote([id [,path]])', safe=False)
1554 @predicate('remote([id [,path]])', safe=False)
1543 def remote(repo, subset, x):
1555 def remote(repo, subset, x):
1544 """Local revision that corresponds to the given identifier in a
1556 """Local revision that corresponds to the given identifier in a
1545 remote repository, if present. Here, the '.' identifier is a
1557 remote repository, if present. Here, the '.' identifier is a
1546 synonym for the current local branch.
1558 synonym for the current local branch.
1547 """
1559 """
1548
1560
1549 from . import hg # avoid start-up nasties
1561 from . import hg # avoid start-up nasties
1550 # i18n: "remote" is a keyword
1562 # i18n: "remote" is a keyword
1551 l = getargs(x, 0, 2, _("remote takes zero, one, or two arguments"))
1563 l = getargs(x, 0, 2, _("remote takes zero, one, or two arguments"))
1552
1564
1553 q = '.'
1565 q = '.'
1554 if len(l) > 0:
1566 if len(l) > 0:
1555 # i18n: "remote" is a keyword
1567 # i18n: "remote" is a keyword
1556 q = getstring(l[0], _("remote requires a string id"))
1568 q = getstring(l[0], _("remote requires a string id"))
1557 if q == '.':
1569 if q == '.':
1558 q = repo['.'].branch()
1570 q = repo['.'].branch()
1559
1571
1560 dest = ''
1572 dest = ''
1561 if len(l) > 1:
1573 if len(l) > 1:
1562 # i18n: "remote" is a keyword
1574 # i18n: "remote" is a keyword
1563 dest = getstring(l[1], _("remote requires a repository path"))
1575 dest = getstring(l[1], _("remote requires a repository path"))
1564 dest = repo.ui.expandpath(dest or 'default')
1576 dest = repo.ui.expandpath(dest or 'default')
1565 dest, branches = hg.parseurl(dest)
1577 dest, branches = hg.parseurl(dest)
1566 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1578 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1567 if revs:
1579 if revs:
1568 revs = [repo.lookup(rev) for rev in revs]
1580 revs = [repo.lookup(rev) for rev in revs]
1569 other = hg.peer(repo, {}, dest)
1581 other = hg.peer(repo, {}, dest)
1570 n = other.lookup(q)
1582 n = other.lookup(q)
1571 if n in repo:
1583 if n in repo:
1572 r = repo[n].rev()
1584 r = repo[n].rev()
1573 if r in subset:
1585 if r in subset:
1574 return baseset([r])
1586 return baseset([r])
1575 return baseset()
1587 return baseset()
1576
1588
1577 @predicate('removes(pattern)', safe=True)
1589 @predicate('removes(pattern)', safe=True)
1578 def removes(repo, subset, x):
1590 def removes(repo, subset, x):
1579 """Changesets which remove files matching pattern.
1591 """Changesets which remove files matching pattern.
1580
1592
1581 The pattern without explicit kind like ``glob:`` is expected to be
1593 The pattern without explicit kind like ``glob:`` is expected to be
1582 relative to the current directory and match against a file or a
1594 relative to the current directory and match against a file or a
1583 directory.
1595 directory.
1584 """
1596 """
1585 # i18n: "removes" is a keyword
1597 # i18n: "removes" is a keyword
1586 pat = getstring(x, _("removes requires a pattern"))
1598 pat = getstring(x, _("removes requires a pattern"))
1587 return checkstatus(repo, subset, pat, 2)
1599 return checkstatus(repo, subset, pat, 2)
1588
1600
1589 @predicate('rev(number)', safe=True)
1601 @predicate('rev(number)', safe=True)
1590 def rev(repo, subset, x):
1602 def rev(repo, subset, x):
1591 """Revision with the given numeric identifier.
1603 """Revision with the given numeric identifier.
1592 """
1604 """
1593 # i18n: "rev" is a keyword
1605 # i18n: "rev" is a keyword
1594 l = getargs(x, 1, 1, _("rev requires one argument"))
1606 l = getargs(x, 1, 1, _("rev requires one argument"))
1595 try:
1607 try:
1596 # i18n: "rev" is a keyword
1608 # i18n: "rev" is a keyword
1597 l = int(getstring(l[0], _("rev requires a number")))
1609 l = int(getstring(l[0], _("rev requires a number")))
1598 except (TypeError, ValueError):
1610 except (TypeError, ValueError):
1599 # i18n: "rev" is a keyword
1611 # i18n: "rev" is a keyword
1600 raise error.ParseError(_("rev expects a number"))
1612 raise error.ParseError(_("rev expects a number"))
1601 if l not in repo.changelog and l not in (node.nullrev, node.wdirrev):
1613 if l not in repo.changelog and l not in (node.nullrev, node.wdirrev):
1602 return baseset()
1614 return baseset()
1603 return subset & baseset([l])
1615 return subset & baseset([l])
1604
1616
1605 @predicate('matching(revision [, field])', safe=True)
1617 @predicate('matching(revision [, field])', safe=True)
1606 def matching(repo, subset, x):
1618 def matching(repo, subset, x):
1607 """Changesets in which a given set of fields match the set of fields in the
1619 """Changesets in which a given set of fields match the set of fields in the
1608 selected revision or set.
1620 selected revision or set.
1609
1621
1610 To match more than one field pass the list of fields to match separated
1622 To match more than one field pass the list of fields to match separated
1611 by spaces (e.g. ``author description``).
1623 by spaces (e.g. ``author description``).
1612
1624
1613 Valid fields are most regular revision fields and some special fields.
1625 Valid fields are most regular revision fields and some special fields.
1614
1626
1615 Regular revision fields are ``description``, ``author``, ``branch``,
1627 Regular revision fields are ``description``, ``author``, ``branch``,
1616 ``date``, ``files``, ``phase``, ``parents``, ``substate``, ``user``
1628 ``date``, ``files``, ``phase``, ``parents``, ``substate``, ``user``
1617 and ``diff``.
1629 and ``diff``.
1618 Note that ``author`` and ``user`` are synonyms. ``diff`` refers to the
1630 Note that ``author`` and ``user`` are synonyms. ``diff`` refers to the
1619 contents of the revision. Two revisions matching their ``diff`` will
1631 contents of the revision. Two revisions matching their ``diff`` will
1620 also match their ``files``.
1632 also match their ``files``.
1621
1633
1622 Special fields are ``summary`` and ``metadata``:
1634 Special fields are ``summary`` and ``metadata``:
1623 ``summary`` matches the first line of the description.
1635 ``summary`` matches the first line of the description.
1624 ``metadata`` is equivalent to matching ``description user date``
1636 ``metadata`` is equivalent to matching ``description user date``
1625 (i.e. it matches the main metadata fields).
1637 (i.e. it matches the main metadata fields).
1626
1638
1627 ``metadata`` is the default field which is used when no fields are
1639 ``metadata`` is the default field which is used when no fields are
1628 specified. You can match more than one field at a time.
1640 specified. You can match more than one field at a time.
1629 """
1641 """
1630 # i18n: "matching" is a keyword
1642 # i18n: "matching" is a keyword
1631 l = getargs(x, 1, 2, _("matching takes 1 or 2 arguments"))
1643 l = getargs(x, 1, 2, _("matching takes 1 or 2 arguments"))
1632
1644
1633 revs = getset(repo, fullreposet(repo), l[0])
1645 revs = getset(repo, fullreposet(repo), l[0])
1634
1646
1635 fieldlist = ['metadata']
1647 fieldlist = ['metadata']
1636 if len(l) > 1:
1648 if len(l) > 1:
1637 fieldlist = getstring(l[1],
1649 fieldlist = getstring(l[1],
1638 # i18n: "matching" is a keyword
1650 # i18n: "matching" is a keyword
1639 _("matching requires a string "
1651 _("matching requires a string "
1640 "as its second argument")).split()
1652 "as its second argument")).split()
1641
1653
1642 # Make sure that there are no repeated fields,
1654 # Make sure that there are no repeated fields,
1643 # expand the 'special' 'metadata' field type
1655 # expand the 'special' 'metadata' field type
1644 # and check the 'files' whenever we check the 'diff'
1656 # and check the 'files' whenever we check the 'diff'
1645 fields = []
1657 fields = []
1646 for field in fieldlist:
1658 for field in fieldlist:
1647 if field == 'metadata':
1659 if field == 'metadata':
1648 fields += ['user', 'description', 'date']
1660 fields += ['user', 'description', 'date']
1649 elif field == 'diff':
1661 elif field == 'diff':
1650 # a revision matching the diff must also match the files
1662 # a revision matching the diff must also match the files
1651 # since matching the diff is very costly, make sure to
1663 # since matching the diff is very costly, make sure to
1652 # also match the files first
1664 # also match the files first
1653 fields += ['files', 'diff']
1665 fields += ['files', 'diff']
1654 else:
1666 else:
1655 if field == 'author':
1667 if field == 'author':
1656 field = 'user'
1668 field = 'user'
1657 fields.append(field)
1669 fields.append(field)
1658 fields = set(fields)
1670 fields = set(fields)
1659 if 'summary' in fields and 'description' in fields:
1671 if 'summary' in fields and 'description' in fields:
1660 # If a revision matches its description it also matches its summary
1672 # If a revision matches its description it also matches its summary
1661 fields.discard('summary')
1673 fields.discard('summary')
1662
1674
1663 # We may want to match more than one field
1675 # We may want to match more than one field
1664 # Not all fields take the same amount of time to be matched
1676 # Not all fields take the same amount of time to be matched
1665 # Sort the selected fields in order of increasing matching cost
1677 # Sort the selected fields in order of increasing matching cost
1666 fieldorder = ['phase', 'parents', 'user', 'date', 'branch', 'summary',
1678 fieldorder = ['phase', 'parents', 'user', 'date', 'branch', 'summary',
1667 'files', 'description', 'substate', 'diff']
1679 'files', 'description', 'substate', 'diff']
1668 def fieldkeyfunc(f):
1680 def fieldkeyfunc(f):
1669 try:
1681 try:
1670 return fieldorder.index(f)
1682 return fieldorder.index(f)
1671 except ValueError:
1683 except ValueError:
1672 # assume an unknown field is very costly
1684 # assume an unknown field is very costly
1673 return len(fieldorder)
1685 return len(fieldorder)
1674 fields = list(fields)
1686 fields = list(fields)
1675 fields.sort(key=fieldkeyfunc)
1687 fields.sort(key=fieldkeyfunc)
1676
1688
1677 # Each field will be matched with its own "getfield" function
1689 # Each field will be matched with its own "getfield" function
1678 # which will be added to the getfieldfuncs array of functions
1690 # which will be added to the getfieldfuncs array of functions
1679 getfieldfuncs = []
1691 getfieldfuncs = []
1680 _funcs = {
1692 _funcs = {
1681 'user': lambda r: repo[r].user(),
1693 'user': lambda r: repo[r].user(),
1682 'branch': lambda r: repo[r].branch(),
1694 'branch': lambda r: repo[r].branch(),
1683 'date': lambda r: repo[r].date(),
1695 'date': lambda r: repo[r].date(),
1684 'description': lambda r: repo[r].description(),
1696 'description': lambda r: repo[r].description(),
1685 'files': lambda r: repo[r].files(),
1697 'files': lambda r: repo[r].files(),
1686 'parents': lambda r: repo[r].parents(),
1698 'parents': lambda r: repo[r].parents(),
1687 'phase': lambda r: repo[r].phase(),
1699 'phase': lambda r: repo[r].phase(),
1688 'substate': lambda r: repo[r].substate,
1700 'substate': lambda r: repo[r].substate,
1689 'summary': lambda r: repo[r].description().splitlines()[0],
1701 'summary': lambda r: repo[r].description().splitlines()[0],
1690 'diff': lambda r: list(repo[r].diff(git=True),)
1702 'diff': lambda r: list(repo[r].diff(git=True),)
1691 }
1703 }
1692 for info in fields:
1704 for info in fields:
1693 getfield = _funcs.get(info, None)
1705 getfield = _funcs.get(info, None)
1694 if getfield is None:
1706 if getfield is None:
1695 raise error.ParseError(
1707 raise error.ParseError(
1696 # i18n: "matching" is a keyword
1708 # i18n: "matching" is a keyword
1697 _("unexpected field name passed to matching: %s") % info)
1709 _("unexpected field name passed to matching: %s") % info)
1698 getfieldfuncs.append(getfield)
1710 getfieldfuncs.append(getfield)
1699 # convert the getfield array of functions into a "getinfo" function
1711 # convert the getfield array of functions into a "getinfo" function
1700 # which returns an array of field values (or a single value if there
1712 # which returns an array of field values (or a single value if there
1701 # is only one field to match)
1713 # is only one field to match)
1702 getinfo = lambda r: [f(r) for f in getfieldfuncs]
1714 getinfo = lambda r: [f(r) for f in getfieldfuncs]
1703
1715
1704 def matches(x):
1716 def matches(x):
1705 for rev in revs:
1717 for rev in revs:
1706 target = getinfo(rev)
1718 target = getinfo(rev)
1707 match = True
1719 match = True
1708 for n, f in enumerate(getfieldfuncs):
1720 for n, f in enumerate(getfieldfuncs):
1709 if target[n] != f(x):
1721 if target[n] != f(x):
1710 match = False
1722 match = False
1711 if match:
1723 if match:
1712 return True
1724 return True
1713 return False
1725 return False
1714
1726
1715 return subset.filter(matches, condrepr=('<matching%r %r>', fields, revs))
1727 return subset.filter(matches, condrepr=('<matching%r %r>', fields, revs))
1716
1728
1717 @predicate('reverse(set)', safe=True, takeorder=True)
1729 @predicate('reverse(set)', safe=True, takeorder=True)
1718 def reverse(repo, subset, x, order):
1730 def reverse(repo, subset, x, order):
1719 """Reverse order of set.
1731 """Reverse order of set.
1720 """
1732 """
1721 l = getset(repo, subset, x)
1733 l = getset(repo, subset, x, order)
1722 if order == defineorder:
1734 if order == defineorder:
1723 l.reverse()
1735 l.reverse()
1724 return l
1736 return l
1725
1737
1726 @predicate('roots(set)', safe=True)
1738 @predicate('roots(set)', safe=True)
1727 def roots(repo, subset, x):
1739 def roots(repo, subset, x):
1728 """Changesets in set with no parent changeset in set.
1740 """Changesets in set with no parent changeset in set.
1729 """
1741 """
1730 s = getset(repo, fullreposet(repo), x)
1742 s = getset(repo, fullreposet(repo), x)
1731 parents = repo.changelog.parentrevs
1743 parents = repo.changelog.parentrevs
1732 def filter(r):
1744 def filter(r):
1733 for p in parents(r):
1745 for p in parents(r):
1734 if 0 <= p and p in s:
1746 if 0 <= p and p in s:
1735 return False
1747 return False
1736 return True
1748 return True
1737 return subset & s.filter(filter, condrepr='<roots>')
1749 return subset & s.filter(filter, condrepr='<roots>')
1738
1750
1739 _sortkeyfuncs = {
1751 _sortkeyfuncs = {
1740 'rev': lambda c: c.rev(),
1752 'rev': lambda c: c.rev(),
1741 'branch': lambda c: c.branch(),
1753 'branch': lambda c: c.branch(),
1742 'desc': lambda c: c.description(),
1754 'desc': lambda c: c.description(),
1743 'user': lambda c: c.user(),
1755 'user': lambda c: c.user(),
1744 'author': lambda c: c.user(),
1756 'author': lambda c: c.user(),
1745 'date': lambda c: c.date()[0],
1757 'date': lambda c: c.date()[0],
1746 }
1758 }
1747
1759
1748 def _getsortargs(x):
1760 def _getsortargs(x):
1749 """Parse sort options into (set, [(key, reverse)], opts)"""
1761 """Parse sort options into (set, [(key, reverse)], opts)"""
1750 args = getargsdict(x, 'sort', 'set keys topo.firstbranch')
1762 args = getargsdict(x, 'sort', 'set keys topo.firstbranch')
1751 if 'set' not in args:
1763 if 'set' not in args:
1752 # i18n: "sort" is a keyword
1764 # i18n: "sort" is a keyword
1753 raise error.ParseError(_('sort requires one or two arguments'))
1765 raise error.ParseError(_('sort requires one or two arguments'))
1754 keys = "rev"
1766 keys = "rev"
1755 if 'keys' in args:
1767 if 'keys' in args:
1756 # i18n: "sort" is a keyword
1768 # i18n: "sort" is a keyword
1757 keys = getstring(args['keys'], _("sort spec must be a string"))
1769 keys = getstring(args['keys'], _("sort spec must be a string"))
1758
1770
1759 keyflags = []
1771 keyflags = []
1760 for k in keys.split():
1772 for k in keys.split():
1761 fk = k
1773 fk = k
1762 reverse = (k[0] == '-')
1774 reverse = (k[0] == '-')
1763 if reverse:
1775 if reverse:
1764 k = k[1:]
1776 k = k[1:]
1765 if k not in _sortkeyfuncs and k != 'topo':
1777 if k not in _sortkeyfuncs and k != 'topo':
1766 raise error.ParseError(_("unknown sort key %r") % fk)
1778 raise error.ParseError(_("unknown sort key %r") % fk)
1767 keyflags.append((k, reverse))
1779 keyflags.append((k, reverse))
1768
1780
1769 if len(keyflags) > 1 and any(k == 'topo' for k, reverse in keyflags):
1781 if len(keyflags) > 1 and any(k == 'topo' for k, reverse in keyflags):
1770 # i18n: "topo" is a keyword
1782 # i18n: "topo" is a keyword
1771 raise error.ParseError(_('topo sort order cannot be combined '
1783 raise error.ParseError(_('topo sort order cannot be combined '
1772 'with other sort keys'))
1784 'with other sort keys'))
1773
1785
1774 opts = {}
1786 opts = {}
1775 if 'topo.firstbranch' in args:
1787 if 'topo.firstbranch' in args:
1776 if any(k == 'topo' for k, reverse in keyflags):
1788 if any(k == 'topo' for k, reverse in keyflags):
1777 opts['topo.firstbranch'] = args['topo.firstbranch']
1789 opts['topo.firstbranch'] = args['topo.firstbranch']
1778 else:
1790 else:
1779 # i18n: "topo" and "topo.firstbranch" are keywords
1791 # i18n: "topo" and "topo.firstbranch" are keywords
1780 raise error.ParseError(_('topo.firstbranch can only be used '
1792 raise error.ParseError(_('topo.firstbranch can only be used '
1781 'when using the topo sort key'))
1793 'when using the topo sort key'))
1782
1794
1783 return args['set'], keyflags, opts
1795 return args['set'], keyflags, opts
1784
1796
1785 @predicate('sort(set[, [-]key... [, ...]])', safe=True, takeorder=True)
1797 @predicate('sort(set[, [-]key... [, ...]])', safe=True, takeorder=True)
1786 def sort(repo, subset, x, order):
1798 def sort(repo, subset, x, order):
1787 """Sort set by keys. The default sort order is ascending, specify a key
1799 """Sort set by keys. The default sort order is ascending, specify a key
1788 as ``-key`` to sort in descending order.
1800 as ``-key`` to sort in descending order.
1789
1801
1790 The keys can be:
1802 The keys can be:
1791
1803
1792 - ``rev`` for the revision number,
1804 - ``rev`` for the revision number,
1793 - ``branch`` for the branch name,
1805 - ``branch`` for the branch name,
1794 - ``desc`` for the commit message (description),
1806 - ``desc`` for the commit message (description),
1795 - ``user`` for user name (``author`` can be used as an alias),
1807 - ``user`` for user name (``author`` can be used as an alias),
1796 - ``date`` for the commit date
1808 - ``date`` for the commit date
1797 - ``topo`` for a reverse topographical sort
1809 - ``topo`` for a reverse topographical sort
1798
1810
1799 The ``topo`` sort order cannot be combined with other sort keys. This sort
1811 The ``topo`` sort order cannot be combined with other sort keys. This sort
1800 takes one optional argument, ``topo.firstbranch``, which takes a revset that
1812 takes one optional argument, ``topo.firstbranch``, which takes a revset that
1801 specifies what topographical branches to prioritize in the sort.
1813 specifies what topographical branches to prioritize in the sort.
1802
1814
1803 """
1815 """
1804 s, keyflags, opts = _getsortargs(x)
1816 s, keyflags, opts = _getsortargs(x)
1805 revs = getset(repo, subset, s)
1817 revs = getset(repo, subset, s, order)
1806
1818
1807 if not keyflags or order != defineorder:
1819 if not keyflags or order != defineorder:
1808 return revs
1820 return revs
1809 if len(keyflags) == 1 and keyflags[0][0] == "rev":
1821 if len(keyflags) == 1 and keyflags[0][0] == "rev":
1810 revs.sort(reverse=keyflags[0][1])
1822 revs.sort(reverse=keyflags[0][1])
1811 return revs
1823 return revs
1812 elif keyflags[0][0] == "topo":
1824 elif keyflags[0][0] == "topo":
1813 firstbranch = ()
1825 firstbranch = ()
1814 if 'topo.firstbranch' in opts:
1826 if 'topo.firstbranch' in opts:
1815 firstbranch = getset(repo, subset, opts['topo.firstbranch'])
1827 firstbranch = getset(repo, subset, opts['topo.firstbranch'])
1816 revs = baseset(dagop.toposort(revs, repo.changelog.parentrevs,
1828 revs = baseset(dagop.toposort(revs, repo.changelog.parentrevs,
1817 firstbranch),
1829 firstbranch),
1818 istopo=True)
1830 istopo=True)
1819 if keyflags[0][1]:
1831 if keyflags[0][1]:
1820 revs.reverse()
1832 revs.reverse()
1821 return revs
1833 return revs
1822
1834
1823 # sort() is guaranteed to be stable
1835 # sort() is guaranteed to be stable
1824 ctxs = [repo[r] for r in revs]
1836 ctxs = [repo[r] for r in revs]
1825 for k, reverse in reversed(keyflags):
1837 for k, reverse in reversed(keyflags):
1826 ctxs.sort(key=_sortkeyfuncs[k], reverse=reverse)
1838 ctxs.sort(key=_sortkeyfuncs[k], reverse=reverse)
1827 return baseset([c.rev() for c in ctxs])
1839 return baseset([c.rev() for c in ctxs])
1828
1840
1829 @predicate('subrepo([pattern])')
1841 @predicate('subrepo([pattern])')
1830 def subrepo(repo, subset, x):
1842 def subrepo(repo, subset, x):
1831 """Changesets that add, modify or remove the given subrepo. If no subrepo
1843 """Changesets that add, modify or remove the given subrepo. If no subrepo
1832 pattern is named, any subrepo changes are returned.
1844 pattern is named, any subrepo changes are returned.
1833 """
1845 """
1834 # i18n: "subrepo" is a keyword
1846 # i18n: "subrepo" is a keyword
1835 args = getargs(x, 0, 1, _('subrepo takes at most one argument'))
1847 args = getargs(x, 0, 1, _('subrepo takes at most one argument'))
1836 pat = None
1848 pat = None
1837 if len(args) != 0:
1849 if len(args) != 0:
1838 pat = getstring(args[0], _("subrepo requires a pattern"))
1850 pat = getstring(args[0], _("subrepo requires a pattern"))
1839
1851
1840 m = matchmod.exact(repo.root, repo.root, ['.hgsubstate'])
1852 m = matchmod.exact(repo.root, repo.root, ['.hgsubstate'])
1841
1853
1842 def submatches(names):
1854 def submatches(names):
1843 k, p, m = util.stringmatcher(pat)
1855 k, p, m = util.stringmatcher(pat)
1844 for name in names:
1856 for name in names:
1845 if m(name):
1857 if m(name):
1846 yield name
1858 yield name
1847
1859
1848 def matches(x):
1860 def matches(x):
1849 c = repo[x]
1861 c = repo[x]
1850 s = repo.status(c.p1().node(), c.node(), match=m)
1862 s = repo.status(c.p1().node(), c.node(), match=m)
1851
1863
1852 if pat is None:
1864 if pat is None:
1853 return s.added or s.modified or s.removed
1865 return s.added or s.modified or s.removed
1854
1866
1855 if s.added:
1867 if s.added:
1856 return any(submatches(c.substate.keys()))
1868 return any(submatches(c.substate.keys()))
1857
1869
1858 if s.modified:
1870 if s.modified:
1859 subs = set(c.p1().substate.keys())
1871 subs = set(c.p1().substate.keys())
1860 subs.update(c.substate.keys())
1872 subs.update(c.substate.keys())
1861
1873
1862 for path in submatches(subs):
1874 for path in submatches(subs):
1863 if c.p1().substate.get(path) != c.substate.get(path):
1875 if c.p1().substate.get(path) != c.substate.get(path):
1864 return True
1876 return True
1865
1877
1866 if s.removed:
1878 if s.removed:
1867 return any(submatches(c.p1().substate.keys()))
1879 return any(submatches(c.p1().substate.keys()))
1868
1880
1869 return False
1881 return False
1870
1882
1871 return subset.filter(matches, condrepr=('<subrepo %r>', pat))
1883 return subset.filter(matches, condrepr=('<subrepo %r>', pat))
1872
1884
1873 def _mapbynodefunc(repo, s, f):
1885 def _mapbynodefunc(repo, s, f):
1874 """(repo, smartset, [node] -> [node]) -> smartset
1886 """(repo, smartset, [node] -> [node]) -> smartset
1875
1887
1876 Helper method to map a smartset to another smartset given a function only
1888 Helper method to map a smartset to another smartset given a function only
1877 talking about nodes. Handles converting between rev numbers and nodes, and
1889 talking about nodes. Handles converting between rev numbers and nodes, and
1878 filtering.
1890 filtering.
1879 """
1891 """
1880 cl = repo.unfiltered().changelog
1892 cl = repo.unfiltered().changelog
1881 torev = cl.rev
1893 torev = cl.rev
1882 tonode = cl.node
1894 tonode = cl.node
1883 nodemap = cl.nodemap
1895 nodemap = cl.nodemap
1884 result = set(torev(n) for n in f(tonode(r) for r in s) if n in nodemap)
1896 result = set(torev(n) for n in f(tonode(r) for r in s) if n in nodemap)
1885 return smartset.baseset(result - repo.changelog.filteredrevs)
1897 return smartset.baseset(result - repo.changelog.filteredrevs)
1886
1898
1887 @predicate('successors(set)', safe=True)
1899 @predicate('successors(set)', safe=True)
1888 def successors(repo, subset, x):
1900 def successors(repo, subset, x):
1889 """All successors for set, including the given set themselves"""
1901 """All successors for set, including the given set themselves"""
1890 s = getset(repo, fullreposet(repo), x)
1902 s = getset(repo, fullreposet(repo), x)
1891 f = lambda nodes: obsutil.allsuccessors(repo.obsstore, nodes)
1903 f = lambda nodes: obsutil.allsuccessors(repo.obsstore, nodes)
1892 d = _mapbynodefunc(repo, s, f)
1904 d = _mapbynodefunc(repo, s, f)
1893 return subset & d
1905 return subset & d
1894
1906
1895 def _substringmatcher(pattern, casesensitive=True):
1907 def _substringmatcher(pattern, casesensitive=True):
1896 kind, pattern, matcher = util.stringmatcher(pattern,
1908 kind, pattern, matcher = util.stringmatcher(pattern,
1897 casesensitive=casesensitive)
1909 casesensitive=casesensitive)
1898 if kind == 'literal':
1910 if kind == 'literal':
1899 if not casesensitive:
1911 if not casesensitive:
1900 pattern = encoding.lower(pattern)
1912 pattern = encoding.lower(pattern)
1901 matcher = lambda s: pattern in encoding.lower(s)
1913 matcher = lambda s: pattern in encoding.lower(s)
1902 else:
1914 else:
1903 matcher = lambda s: pattern in s
1915 matcher = lambda s: pattern in s
1904 return kind, pattern, matcher
1916 return kind, pattern, matcher
1905
1917
1906 @predicate('tag([name])', safe=True)
1918 @predicate('tag([name])', safe=True)
1907 def tag(repo, subset, x):
1919 def tag(repo, subset, x):
1908 """The specified tag by name, or all tagged revisions if no name is given.
1920 """The specified tag by name, or all tagged revisions if no name is given.
1909
1921
1910 Pattern matching is supported for `name`. See
1922 Pattern matching is supported for `name`. See
1911 :hg:`help revisions.patterns`.
1923 :hg:`help revisions.patterns`.
1912 """
1924 """
1913 # i18n: "tag" is a keyword
1925 # i18n: "tag" is a keyword
1914 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
1926 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
1915 cl = repo.changelog
1927 cl = repo.changelog
1916 if args:
1928 if args:
1917 pattern = getstring(args[0],
1929 pattern = getstring(args[0],
1918 # i18n: "tag" is a keyword
1930 # i18n: "tag" is a keyword
1919 _('the argument to tag must be a string'))
1931 _('the argument to tag must be a string'))
1920 kind, pattern, matcher = util.stringmatcher(pattern)
1932 kind, pattern, matcher = util.stringmatcher(pattern)
1921 if kind == 'literal':
1933 if kind == 'literal':
1922 # avoid resolving all tags
1934 # avoid resolving all tags
1923 tn = repo._tagscache.tags.get(pattern, None)
1935 tn = repo._tagscache.tags.get(pattern, None)
1924 if tn is None:
1936 if tn is None:
1925 raise error.RepoLookupError(_("tag '%s' does not exist")
1937 raise error.RepoLookupError(_("tag '%s' does not exist")
1926 % pattern)
1938 % pattern)
1927 s = {repo[tn].rev()}
1939 s = {repo[tn].rev()}
1928 else:
1940 else:
1929 s = {cl.rev(n) for t, n in repo.tagslist() if matcher(t)}
1941 s = {cl.rev(n) for t, n in repo.tagslist() if matcher(t)}
1930 else:
1942 else:
1931 s = {cl.rev(n) for t, n in repo.tagslist() if t != 'tip'}
1943 s = {cl.rev(n) for t, n in repo.tagslist() if t != 'tip'}
1932 return subset & s
1944 return subset & s
1933
1945
1934 @predicate('tagged', safe=True)
1946 @predicate('tagged', safe=True)
1935 def tagged(repo, subset, x):
1947 def tagged(repo, subset, x):
1936 return tag(repo, subset, x)
1948 return tag(repo, subset, x)
1937
1949
1938 @predicate('unstable()', safe=True)
1950 @predicate('unstable()', safe=True)
1939 def unstable(repo, subset, x):
1951 def unstable(repo, subset, x):
1940 msg = ("'unstable()' is deprecated, "
1952 msg = ("'unstable()' is deprecated, "
1941 "use 'orphan()'")
1953 "use 'orphan()'")
1942 repo.ui.deprecwarn(msg, '4.4')
1954 repo.ui.deprecwarn(msg, '4.4')
1943
1955
1944 return orphan(repo, subset, x)
1956 return orphan(repo, subset, x)
1945
1957
1946 @predicate('orphan()', safe=True)
1958 @predicate('orphan()', safe=True)
1947 def orphan(repo, subset, x):
1959 def orphan(repo, subset, x):
1948 """Non-obsolete changesets with obsolete ancestors. (EXPERIMENTAL)
1960 """Non-obsolete changesets with obsolete ancestors. (EXPERIMENTAL)
1949 """
1961 """
1950 # i18n: "orphan" is a keyword
1962 # i18n: "orphan" is a keyword
1951 getargs(x, 0, 0, _("orphan takes no arguments"))
1963 getargs(x, 0, 0, _("orphan takes no arguments"))
1952 orphan = obsmod.getrevs(repo, 'orphan')
1964 orphan = obsmod.getrevs(repo, 'orphan')
1953 return subset & orphan
1965 return subset & orphan
1954
1966
1955
1967
1956 @predicate('user(string)', safe=True)
1968 @predicate('user(string)', safe=True)
1957 def user(repo, subset, x):
1969 def user(repo, subset, x):
1958 """User name contains string. The match is case-insensitive.
1970 """User name contains string. The match is case-insensitive.
1959
1971
1960 Pattern matching is supported for `string`. See
1972 Pattern matching is supported for `string`. See
1961 :hg:`help revisions.patterns`.
1973 :hg:`help revisions.patterns`.
1962 """
1974 """
1963 return author(repo, subset, x)
1975 return author(repo, subset, x)
1964
1976
1965 @predicate('wdir()', safe=True)
1977 @predicate('wdir()', safe=True)
1966 def wdir(repo, subset, x):
1978 def wdir(repo, subset, x):
1967 """Working directory. (EXPERIMENTAL)"""
1979 """Working directory. (EXPERIMENTAL)"""
1968 # i18n: "wdir" is a keyword
1980 # i18n: "wdir" is a keyword
1969 getargs(x, 0, 0, _("wdir takes no arguments"))
1981 getargs(x, 0, 0, _("wdir takes no arguments"))
1970 if node.wdirrev in subset or isinstance(subset, fullreposet):
1982 if node.wdirrev in subset or isinstance(subset, fullreposet):
1971 return baseset([node.wdirrev])
1983 return baseset([node.wdirrev])
1972 return baseset()
1984 return baseset()
1973
1985
1974 def _orderedlist(repo, subset, x):
1986 def _orderedlist(repo, subset, x):
1975 s = getstring(x, "internal error")
1987 s = getstring(x, "internal error")
1976 if not s:
1988 if not s:
1977 return baseset()
1989 return baseset()
1978 # remove duplicates here. it's difficult for caller to deduplicate sets
1990 # remove duplicates here. it's difficult for caller to deduplicate sets
1979 # because different symbols can point to the same rev.
1991 # because different symbols can point to the same rev.
1980 cl = repo.changelog
1992 cl = repo.changelog
1981 ls = []
1993 ls = []
1982 seen = set()
1994 seen = set()
1983 for t in s.split('\0'):
1995 for t in s.split('\0'):
1984 try:
1996 try:
1985 # fast path for integer revision
1997 # fast path for integer revision
1986 r = int(t)
1998 r = int(t)
1987 if str(r) != t or r not in cl:
1999 if str(r) != t or r not in cl:
1988 raise ValueError
2000 raise ValueError
1989 revs = [r]
2001 revs = [r]
1990 except ValueError:
2002 except ValueError:
1991 revs = stringset(repo, subset, t)
2003 revs = stringset(repo, subset, t, defineorder)
1992
2004
1993 for r in revs:
2005 for r in revs:
1994 if r in seen:
2006 if r in seen:
1995 continue
2007 continue
1996 if (r in subset
2008 if (r in subset
1997 or r == node.nullrev and isinstance(subset, fullreposet)):
2009 or r == node.nullrev and isinstance(subset, fullreposet)):
1998 ls.append(r)
2010 ls.append(r)
1999 seen.add(r)
2011 seen.add(r)
2000 return baseset(ls)
2012 return baseset(ls)
2001
2013
2002 # for internal use
2014 # for internal use
2003 @predicate('_list', safe=True, takeorder=True)
2015 @predicate('_list', safe=True, takeorder=True)
2004 def _list(repo, subset, x, order):
2016 def _list(repo, subset, x, order):
2005 if order == followorder:
2017 if order == followorder:
2006 # slow path to take the subset order
2018 # slow path to take the subset order
2007 return subset & _orderedlist(repo, fullreposet(repo), x)
2019 return subset & _orderedlist(repo, fullreposet(repo), x)
2008 else:
2020 else:
2009 return _orderedlist(repo, subset, x)
2021 return _orderedlist(repo, subset, x)
2010
2022
2011 def _orderedintlist(repo, subset, x):
2023 def _orderedintlist(repo, subset, x):
2012 s = getstring(x, "internal error")
2024 s = getstring(x, "internal error")
2013 if not s:
2025 if not s:
2014 return baseset()
2026 return baseset()
2015 ls = [int(r) for r in s.split('\0')]
2027 ls = [int(r) for r in s.split('\0')]
2016 s = subset
2028 s = subset
2017 return baseset([r for r in ls if r in s])
2029 return baseset([r for r in ls if r in s])
2018
2030
2019 # for internal use
2031 # for internal use
2020 @predicate('_intlist', safe=True, takeorder=True)
2032 @predicate('_intlist', safe=True, takeorder=True)
2021 def _intlist(repo, subset, x, order):
2033 def _intlist(repo, subset, x, order):
2022 if order == followorder:
2034 if order == followorder:
2023 # slow path to take the subset order
2035 # slow path to take the subset order
2024 return subset & _orderedintlist(repo, fullreposet(repo), x)
2036 return subset & _orderedintlist(repo, fullreposet(repo), x)
2025 else:
2037 else:
2026 return _orderedintlist(repo, subset, x)
2038 return _orderedintlist(repo, subset, x)
2027
2039
2028 def _orderedhexlist(repo, subset, x):
2040 def _orderedhexlist(repo, subset, x):
2029 s = getstring(x, "internal error")
2041 s = getstring(x, "internal error")
2030 if not s:
2042 if not s:
2031 return baseset()
2043 return baseset()
2032 cl = repo.changelog
2044 cl = repo.changelog
2033 ls = [cl.rev(node.bin(r)) for r in s.split('\0')]
2045 ls = [cl.rev(node.bin(r)) for r in s.split('\0')]
2034 s = subset
2046 s = subset
2035 return baseset([r for r in ls if r in s])
2047 return baseset([r for r in ls if r in s])
2036
2048
2037 # for internal use
2049 # for internal use
2038 @predicate('_hexlist', safe=True, takeorder=True)
2050 @predicate('_hexlist', safe=True, takeorder=True)
2039 def _hexlist(repo, subset, x, order):
2051 def _hexlist(repo, subset, x, order):
2040 if order == followorder:
2052 if order == followorder:
2041 # slow path to take the subset order
2053 # slow path to take the subset order
2042 return subset & _orderedhexlist(repo, fullreposet(repo), x)
2054 return subset & _orderedhexlist(repo, fullreposet(repo), x)
2043 else:
2055 else:
2044 return _orderedhexlist(repo, subset, x)
2056 return _orderedhexlist(repo, subset, x)
2045
2057
2046 methods = {
2058 methods = {
2047 "range": rangeset,
2059 "range": rangeset,
2048 "rangeall": rangeall,
2060 "rangeall": rangeall,
2049 "rangepre": rangepre,
2061 "rangepre": rangepre,
2050 "rangepost": rangepost,
2062 "rangepost": rangepost,
2051 "dagrange": dagrange,
2063 "dagrange": dagrange,
2052 "string": stringset,
2064 "string": stringset,
2053 "symbol": stringset,
2065 "symbol": stringset,
2054 "and": andset,
2066 "and": andset,
2067 "flipand": flipandset,
2055 "or": orset,
2068 "or": orset,
2056 "not": notset,
2069 "not": notset,
2057 "difference": differenceset,
2070 "difference": differenceset,
2058 "relation": relationset,
2071 "relation": relationset,
2059 "relsubscript": relsubscriptset,
2072 "relsubscript": relsubscriptset,
2060 "subscript": subscriptset,
2073 "subscript": subscriptset,
2061 "list": listset,
2074 "list": listset,
2062 "keyvalue": keyvaluepair,
2075 "keyvalue": keyvaluepair,
2063 "func": func,
2076 "func": func,
2064 "ancestor": ancestorspec,
2077 "ancestor": ancestorspec,
2065 "parent": parentspec,
2078 "parent": parentspec,
2066 "parentpost": parentpost,
2079 "parentpost": parentpost,
2067 }
2080 }
2068
2081
2069 def posttreebuilthook(tree, repo):
2082 def posttreebuilthook(tree, repo):
2070 # hook for extensions to execute code on the optimized tree
2083 # hook for extensions to execute code on the optimized tree
2071 pass
2084 pass
2072
2085
2073 def match(ui, spec, repo=None, order=defineorder):
2086 def match(ui, spec, repo=None, order=defineorder):
2074 """Create a matcher for a single revision spec
2087 """Create a matcher for a single revision spec
2075
2088
2076 If order=followorder, a matcher takes the ordering specified by the input
2089 If order=followorder, a matcher takes the ordering specified by the input
2077 set.
2090 set.
2078 """
2091 """
2079 return matchany(ui, [spec], repo=repo, order=order)
2092 return matchany(ui, [spec], repo=repo, order=order)
2080
2093
2081 def matchany(ui, specs, repo=None, order=defineorder, localalias=None):
2094 def matchany(ui, specs, repo=None, order=defineorder, localalias=None):
2082 """Create a matcher that will include any revisions matching one of the
2095 """Create a matcher that will include any revisions matching one of the
2083 given specs
2096 given specs
2084
2097
2085 If order=followorder, a matcher takes the ordering specified by the input
2098 If order=followorder, a matcher takes the ordering specified by the input
2086 set.
2099 set.
2087
2100
2088 If localalias is not None, it is a dict {name: definitionstring}. It takes
2101 If localalias is not None, it is a dict {name: definitionstring}. It takes
2089 precedence over [revsetalias] config section.
2102 precedence over [revsetalias] config section.
2090 """
2103 """
2091 if not specs:
2104 if not specs:
2092 def mfunc(repo, subset=None):
2105 def mfunc(repo, subset=None):
2093 return baseset()
2106 return baseset()
2094 return mfunc
2107 return mfunc
2095 if not all(specs):
2108 if not all(specs):
2096 raise error.ParseError(_("empty query"))
2109 raise error.ParseError(_("empty query"))
2097 lookup = None
2110 lookup = None
2098 if repo:
2111 if repo:
2099 lookup = repo.__contains__
2112 lookup = repo.__contains__
2100 if len(specs) == 1:
2113 if len(specs) == 1:
2101 tree = revsetlang.parse(specs[0], lookup)
2114 tree = revsetlang.parse(specs[0], lookup)
2102 else:
2115 else:
2103 tree = ('or',
2116 tree = ('or',
2104 ('list',) + tuple(revsetlang.parse(s, lookup) for s in specs))
2117 ('list',) + tuple(revsetlang.parse(s, lookup) for s in specs))
2105
2118
2106 aliases = []
2119 aliases = []
2107 warn = None
2120 warn = None
2108 if ui:
2121 if ui:
2109 aliases.extend(ui.configitems('revsetalias'))
2122 aliases.extend(ui.configitems('revsetalias'))
2110 warn = ui.warn
2123 warn = ui.warn
2111 if localalias:
2124 if localalias:
2112 aliases.extend(localalias.items())
2125 aliases.extend(localalias.items())
2113 if aliases:
2126 if aliases:
2114 tree = revsetlang.expandaliases(tree, aliases, warn=warn)
2127 tree = revsetlang.expandaliases(tree, aliases, warn=warn)
2115 tree = revsetlang.foldconcat(tree)
2128 tree = revsetlang.foldconcat(tree)
2116 tree = revsetlang.analyze(tree, order)
2129 tree = revsetlang.analyze(tree)
2117 tree = revsetlang.optimize(tree)
2130 tree = revsetlang.optimize(tree)
2118 posttreebuilthook(tree, repo)
2131 posttreebuilthook(tree, repo)
2119 return makematcher(tree)
2132 return makematcher(tree, order)
2120
2133
2121 def makematcher(tree):
2134 def makematcher(tree, order=defineorder):
2122 """Create a matcher from an evaluatable tree"""
2135 """Create a matcher from an evaluatable tree"""
2123 def mfunc(repo, subset=None):
2136 def mfunc(repo, subset=None):
2124 if subset is None:
2137 if subset is None:
2125 subset = fullreposet(repo)
2138 subset = fullreposet(repo)
2126 return getset(repo, subset, tree)
2139 return getset(repo, subset, tree, order)
2127 return mfunc
2140 return mfunc
2128
2141
2129 def loadpredicate(ui, extname, registrarobj):
2142 def loadpredicate(ui, extname, registrarobj):
2130 """Load revset predicates from specified registrarobj
2143 """Load revset predicates from specified registrarobj
2131 """
2144 """
2132 for name, func in registrarobj._table.iteritems():
2145 for name, func in registrarobj._table.iteritems():
2133 symbols[name] = func
2146 symbols[name] = func
2134 if func._safe:
2147 if func._safe:
2135 safesymbols.add(name)
2148 safesymbols.add(name)
2136
2149
2137 # load built-in predicates explicitly to setup safesymbols
2150 # load built-in predicates explicitly to setup safesymbols
2138 loadpredicate(None, None, predicate)
2151 loadpredicate(None, None, predicate)
2139
2152
2140 # tell hggettext to extract docstrings from these functions:
2153 # tell hggettext to extract docstrings from these functions:
2141 i18nfunctions = symbols.values()
2154 i18nfunctions = symbols.values()
@@ -1,742 +1,699
1 # revsetlang.py - parser, tokenizer and utility for revision set language
1 # revsetlang.py - parser, tokenizer and utility for revision set language
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 string
10 import string
11
11
12 from .i18n import _
12 from .i18n import _
13 from . import (
13 from . import (
14 error,
14 error,
15 node,
15 node,
16 parser,
16 parser,
17 pycompat,
17 pycompat,
18 util,
18 util,
19 )
19 )
20
20
21 elements = {
21 elements = {
22 # token-type: binding-strength, primary, prefix, infix, suffix
22 # token-type: binding-strength, primary, prefix, infix, suffix
23 "(": (21, None, ("group", 1, ")"), ("func", 1, ")"), None),
23 "(": (21, None, ("group", 1, ")"), ("func", 1, ")"), None),
24 "[": (21, None, None, ("subscript", 1, "]"), None),
24 "[": (21, None, None, ("subscript", 1, "]"), None),
25 "#": (21, None, None, ("relation", 21), None),
25 "#": (21, None, None, ("relation", 21), None),
26 "##": (20, None, None, ("_concat", 20), None),
26 "##": (20, None, None, ("_concat", 20), None),
27 "~": (18, None, None, ("ancestor", 18), None),
27 "~": (18, None, None, ("ancestor", 18), None),
28 "^": (18, None, None, ("parent", 18), "parentpost"),
28 "^": (18, None, None, ("parent", 18), "parentpost"),
29 "-": (5, None, ("negate", 19), ("minus", 5), None),
29 "-": (5, None, ("negate", 19), ("minus", 5), None),
30 "::": (17, None, ("dagrangepre", 17), ("dagrange", 17), "dagrangepost"),
30 "::": (17, None, ("dagrangepre", 17), ("dagrange", 17), "dagrangepost"),
31 "..": (17, None, ("dagrangepre", 17), ("dagrange", 17), "dagrangepost"),
31 "..": (17, None, ("dagrangepre", 17), ("dagrange", 17), "dagrangepost"),
32 ":": (15, "rangeall", ("rangepre", 15), ("range", 15), "rangepost"),
32 ":": (15, "rangeall", ("rangepre", 15), ("range", 15), "rangepost"),
33 "not": (10, None, ("not", 10), None, None),
33 "not": (10, None, ("not", 10), None, None),
34 "!": (10, None, ("not", 10), None, None),
34 "!": (10, None, ("not", 10), None, None),
35 "and": (5, None, None, ("and", 5), None),
35 "and": (5, None, None, ("and", 5), None),
36 "&": (5, None, None, ("and", 5), None),
36 "&": (5, None, None, ("and", 5), None),
37 "%": (5, None, None, ("only", 5), "onlypost"),
37 "%": (5, None, None, ("only", 5), "onlypost"),
38 "or": (4, None, None, ("or", 4), None),
38 "or": (4, None, None, ("or", 4), None),
39 "|": (4, None, None, ("or", 4), None),
39 "|": (4, None, None, ("or", 4), None),
40 "+": (4, None, None, ("or", 4), None),
40 "+": (4, None, None, ("or", 4), None),
41 "=": (3, None, None, ("keyvalue", 3), None),
41 "=": (3, None, None, ("keyvalue", 3), None),
42 ",": (2, None, None, ("list", 2), None),
42 ",": (2, None, None, ("list", 2), None),
43 ")": (0, None, None, None, None),
43 ")": (0, None, None, None, None),
44 "]": (0, None, None, None, None),
44 "]": (0, None, None, None, None),
45 "symbol": (0, "symbol", None, None, None),
45 "symbol": (0, "symbol", None, None, None),
46 "string": (0, "string", None, None, None),
46 "string": (0, "string", None, None, None),
47 "end": (0, None, None, None, None),
47 "end": (0, None, None, None, None),
48 }
48 }
49
49
50 keywords = {'and', 'or', 'not'}
50 keywords = {'and', 'or', 'not'}
51
51
52 _quoteletters = {'"', "'"}
52 _quoteletters = {'"', "'"}
53 _simpleopletters = set(pycompat.iterbytestr("()[]#:=,-|&+!~^%"))
53 _simpleopletters = set(pycompat.iterbytestr("()[]#:=,-|&+!~^%"))
54
54
55 # default set of valid characters for the initial letter of symbols
55 # default set of valid characters for the initial letter of symbols
56 _syminitletters = set(pycompat.iterbytestr(
56 _syminitletters = set(pycompat.iterbytestr(
57 string.ascii_letters.encode('ascii') +
57 string.ascii_letters.encode('ascii') +
58 string.digits.encode('ascii') +
58 string.digits.encode('ascii') +
59 '._@')) | set(map(pycompat.bytechr, xrange(128, 256)))
59 '._@')) | set(map(pycompat.bytechr, xrange(128, 256)))
60
60
61 # default set of valid characters for non-initial letters of symbols
61 # default set of valid characters for non-initial letters of symbols
62 _symletters = _syminitletters | set(pycompat.iterbytestr('-/'))
62 _symletters = _syminitletters | set(pycompat.iterbytestr('-/'))
63
63
64 def tokenize(program, lookup=None, syminitletters=None, symletters=None):
64 def tokenize(program, lookup=None, syminitletters=None, symletters=None):
65 '''
65 '''
66 Parse a revset statement into a stream of tokens
66 Parse a revset statement into a stream of tokens
67
67
68 ``syminitletters`` is the set of valid characters for the initial
68 ``syminitletters`` is the set of valid characters for the initial
69 letter of symbols.
69 letter of symbols.
70
70
71 By default, character ``c`` is recognized as valid for initial
71 By default, character ``c`` is recognized as valid for initial
72 letter of symbols, if ``c.isalnum() or c in '._@' or ord(c) > 127``.
72 letter of symbols, if ``c.isalnum() or c in '._@' or ord(c) > 127``.
73
73
74 ``symletters`` is the set of valid characters for non-initial
74 ``symletters`` is the set of valid characters for non-initial
75 letters of symbols.
75 letters of symbols.
76
76
77 By default, character ``c`` is recognized as valid for non-initial
77 By default, character ``c`` is recognized as valid for non-initial
78 letters of symbols, if ``c.isalnum() or c in '-._/@' or ord(c) > 127``.
78 letters of symbols, if ``c.isalnum() or c in '-._/@' or ord(c) > 127``.
79
79
80 Check that @ is a valid unquoted token character (issue3686):
80 Check that @ is a valid unquoted token character (issue3686):
81 >>> list(tokenize("@::"))
81 >>> list(tokenize("@::"))
82 [('symbol', '@', 0), ('::', None, 1), ('end', None, 3)]
82 [('symbol', '@', 0), ('::', None, 1), ('end', None, 3)]
83
83
84 '''
84 '''
85 program = pycompat.bytestr(program)
85 program = pycompat.bytestr(program)
86 if syminitletters is None:
86 if syminitletters is None:
87 syminitletters = _syminitletters
87 syminitletters = _syminitletters
88 if symletters is None:
88 if symletters is None:
89 symletters = _symletters
89 symletters = _symletters
90
90
91 if program and lookup:
91 if program and lookup:
92 # attempt to parse old-style ranges first to deal with
92 # attempt to parse old-style ranges first to deal with
93 # things like old-tag which contain query metacharacters
93 # things like old-tag which contain query metacharacters
94 parts = program.split(':', 1)
94 parts = program.split(':', 1)
95 if all(lookup(sym) for sym in parts if sym):
95 if all(lookup(sym) for sym in parts if sym):
96 if parts[0]:
96 if parts[0]:
97 yield ('symbol', parts[0], 0)
97 yield ('symbol', parts[0], 0)
98 if len(parts) > 1:
98 if len(parts) > 1:
99 s = len(parts[0])
99 s = len(parts[0])
100 yield (':', None, s)
100 yield (':', None, s)
101 if parts[1]:
101 if parts[1]:
102 yield ('symbol', parts[1], s + 1)
102 yield ('symbol', parts[1], s + 1)
103 yield ('end', None, len(program))
103 yield ('end', None, len(program))
104 return
104 return
105
105
106 pos, l = 0, len(program)
106 pos, l = 0, len(program)
107 while pos < l:
107 while pos < l:
108 c = program[pos]
108 c = program[pos]
109 if c.isspace(): # skip inter-token whitespace
109 if c.isspace(): # skip inter-token whitespace
110 pass
110 pass
111 elif c == ':' and program[pos:pos + 2] == '::': # look ahead carefully
111 elif c == ':' and program[pos:pos + 2] == '::': # look ahead carefully
112 yield ('::', None, pos)
112 yield ('::', None, pos)
113 pos += 1 # skip ahead
113 pos += 1 # skip ahead
114 elif c == '.' and program[pos:pos + 2] == '..': # look ahead carefully
114 elif c == '.' and program[pos:pos + 2] == '..': # look ahead carefully
115 yield ('..', None, pos)
115 yield ('..', None, pos)
116 pos += 1 # skip ahead
116 pos += 1 # skip ahead
117 elif c == '#' and program[pos:pos + 2] == '##': # look ahead carefully
117 elif c == '#' and program[pos:pos + 2] == '##': # look ahead carefully
118 yield ('##', None, pos)
118 yield ('##', None, pos)
119 pos += 1 # skip ahead
119 pos += 1 # skip ahead
120 elif c in _simpleopletters: # handle simple operators
120 elif c in _simpleopletters: # handle simple operators
121 yield (c, None, pos)
121 yield (c, None, pos)
122 elif (c in _quoteletters or c == 'r' and
122 elif (c in _quoteletters or c == 'r' and
123 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
123 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
124 if c == 'r':
124 if c == 'r':
125 pos += 1
125 pos += 1
126 c = program[pos]
126 c = program[pos]
127 decode = lambda x: x
127 decode = lambda x: x
128 else:
128 else:
129 decode = parser.unescapestr
129 decode = parser.unescapestr
130 pos += 1
130 pos += 1
131 s = pos
131 s = pos
132 while pos < l: # find closing quote
132 while pos < l: # find closing quote
133 d = program[pos]
133 d = program[pos]
134 if d == '\\': # skip over escaped characters
134 if d == '\\': # skip over escaped characters
135 pos += 2
135 pos += 2
136 continue
136 continue
137 if d == c:
137 if d == c:
138 yield ('string', decode(program[s:pos]), s)
138 yield ('string', decode(program[s:pos]), s)
139 break
139 break
140 pos += 1
140 pos += 1
141 else:
141 else:
142 raise error.ParseError(_("unterminated string"), s)
142 raise error.ParseError(_("unterminated string"), s)
143 # gather up a symbol/keyword
143 # gather up a symbol/keyword
144 elif c in syminitletters:
144 elif c in syminitletters:
145 s = pos
145 s = pos
146 pos += 1
146 pos += 1
147 while pos < l: # find end of symbol
147 while pos < l: # find end of symbol
148 d = program[pos]
148 d = program[pos]
149 if d not in symletters:
149 if d not in symletters:
150 break
150 break
151 if d == '.' and program[pos - 1] == '.': # special case for ..
151 if d == '.' and program[pos - 1] == '.': # special case for ..
152 pos -= 1
152 pos -= 1
153 break
153 break
154 pos += 1
154 pos += 1
155 sym = program[s:pos]
155 sym = program[s:pos]
156 if sym in keywords: # operator keywords
156 if sym in keywords: # operator keywords
157 yield (sym, None, s)
157 yield (sym, None, s)
158 elif '-' in sym:
158 elif '-' in sym:
159 # some jerk gave us foo-bar-baz, try to check if it's a symbol
159 # some jerk gave us foo-bar-baz, try to check if it's a symbol
160 if lookup and lookup(sym):
160 if lookup and lookup(sym):
161 # looks like a real symbol
161 # looks like a real symbol
162 yield ('symbol', sym, s)
162 yield ('symbol', sym, s)
163 else:
163 else:
164 # looks like an expression
164 # looks like an expression
165 parts = sym.split('-')
165 parts = sym.split('-')
166 for p in parts[:-1]:
166 for p in parts[:-1]:
167 if p: # possible consecutive -
167 if p: # possible consecutive -
168 yield ('symbol', p, s)
168 yield ('symbol', p, s)
169 s += len(p)
169 s += len(p)
170 yield ('-', None, pos)
170 yield ('-', None, pos)
171 s += 1
171 s += 1
172 if parts[-1]: # possible trailing -
172 if parts[-1]: # possible trailing -
173 yield ('symbol', parts[-1], s)
173 yield ('symbol', parts[-1], s)
174 else:
174 else:
175 yield ('symbol', sym, s)
175 yield ('symbol', sym, s)
176 pos -= 1
176 pos -= 1
177 else:
177 else:
178 raise error.ParseError(_("syntax error in revset '%s'") %
178 raise error.ParseError(_("syntax error in revset '%s'") %
179 program, pos)
179 program, pos)
180 pos += 1
180 pos += 1
181 yield ('end', None, pos)
181 yield ('end', None, pos)
182
182
183 # helpers
183 # helpers
184
184
185 _notset = object()
185 _notset = object()
186
186
187 def getsymbol(x):
187 def getsymbol(x):
188 if x and x[0] == 'symbol':
188 if x and x[0] == 'symbol':
189 return x[1]
189 return x[1]
190 raise error.ParseError(_('not a symbol'))
190 raise error.ParseError(_('not a symbol'))
191
191
192 def getstring(x, err):
192 def getstring(x, err):
193 if x and (x[0] == 'string' or x[0] == 'symbol'):
193 if x and (x[0] == 'string' or x[0] == 'symbol'):
194 return x[1]
194 return x[1]
195 raise error.ParseError(err)
195 raise error.ParseError(err)
196
196
197 def getinteger(x, err, default=_notset):
197 def getinteger(x, err, default=_notset):
198 if not x and default is not _notset:
198 if not x and default is not _notset:
199 return default
199 return default
200 try:
200 try:
201 return int(getstring(x, err))
201 return int(getstring(x, err))
202 except ValueError:
202 except ValueError:
203 raise error.ParseError(err)
203 raise error.ParseError(err)
204
204
205 def getboolean(x, err):
205 def getboolean(x, err):
206 value = util.parsebool(getsymbol(x))
206 value = util.parsebool(getsymbol(x))
207 if value is not None:
207 if value is not None:
208 return value
208 return value
209 raise error.ParseError(err)
209 raise error.ParseError(err)
210
210
211 def getlist(x):
211 def getlist(x):
212 if not x:
212 if not x:
213 return []
213 return []
214 if x[0] == 'list':
214 if x[0] == 'list':
215 return list(x[1:])
215 return list(x[1:])
216 return [x]
216 return [x]
217
217
218 def getrange(x, err):
218 def getrange(x, err):
219 if not x:
219 if not x:
220 raise error.ParseError(err)
220 raise error.ParseError(err)
221 op = x[0]
221 op = x[0]
222 if op == 'range':
222 if op == 'range':
223 return x[1], x[2]
223 return x[1], x[2]
224 elif op == 'rangepre':
224 elif op == 'rangepre':
225 return None, x[1]
225 return None, x[1]
226 elif op == 'rangepost':
226 elif op == 'rangepost':
227 return x[1], None
227 return x[1], None
228 elif op == 'rangeall':
228 elif op == 'rangeall':
229 return None, None
229 return None, None
230 raise error.ParseError(err)
230 raise error.ParseError(err)
231
231
232 def getargs(x, min, max, err):
232 def getargs(x, min, max, err):
233 l = getlist(x)
233 l = getlist(x)
234 if len(l) < min or (max >= 0 and len(l) > max):
234 if len(l) < min or (max >= 0 and len(l) > max):
235 raise error.ParseError(err)
235 raise error.ParseError(err)
236 return l
236 return l
237
237
238 def getargsdict(x, funcname, keys):
238 def getargsdict(x, funcname, keys):
239 return parser.buildargsdict(getlist(x), funcname, parser.splitargspec(keys),
239 return parser.buildargsdict(getlist(x), funcname, parser.splitargspec(keys),
240 keyvaluenode='keyvalue', keynode='symbol')
240 keyvaluenode='keyvalue', keynode='symbol')
241
241
242 def _isnamedfunc(x, funcname):
242 def _isnamedfunc(x, funcname):
243 """Check if given tree matches named function"""
243 """Check if given tree matches named function"""
244 return x and x[0] == 'func' and getsymbol(x[1]) == funcname
244 return x and x[0] == 'func' and getsymbol(x[1]) == funcname
245
245
246 def _isposargs(x, n):
246 def _isposargs(x, n):
247 """Check if given tree is n-length list of positional arguments"""
247 """Check if given tree is n-length list of positional arguments"""
248 l = getlist(x)
248 l = getlist(x)
249 return len(l) == n and all(y and y[0] != 'keyvalue' for y in l)
249 return len(l) == n and all(y and y[0] != 'keyvalue' for y in l)
250
250
251 def _matchnamedfunc(x, funcname):
251 def _matchnamedfunc(x, funcname):
252 """Return args tree if given tree matches named function; otherwise None
252 """Return args tree if given tree matches named function; otherwise None
253
253
254 This can't be used for testing a nullary function since its args tree
254 This can't be used for testing a nullary function since its args tree
255 is also None. Use _isnamedfunc() instead.
255 is also None. Use _isnamedfunc() instead.
256 """
256 """
257 if not _isnamedfunc(x, funcname):
257 if not _isnamedfunc(x, funcname):
258 return
258 return
259 return x[2]
259 return x[2]
260
260
261 # Constants for ordering requirement, used in _analyze():
261 # Constants for ordering requirement, used in getset():
262 #
262 #
263 # If 'define', any nested functions and operations can change the ordering of
263 # If 'define', any nested functions and operations can change the ordering of
264 # the entries in the set. If 'follow', any nested functions and operations
264 # the entries in the set. If 'follow', any nested functions and operations
265 # should take the ordering specified by the first operand to the '&' operator.
265 # should take the ordering specified by the first operand to the '&' operator.
266 #
266 #
267 # For instance,
267 # For instance,
268 #
268 #
269 # X & (Y | Z)
269 # X & (Y | Z)
270 # ^ ^^^^^^^
270 # ^ ^^^^^^^
271 # | follow
271 # | follow
272 # define
272 # define
273 #
273 #
274 # will be evaluated as 'or(y(x()), z(x()))', where 'x()' can change the order
274 # will be evaluated as 'or(y(x()), z(x()))', where 'x()' can change the order
275 # of the entries in the set, but 'y()', 'z()' and 'or()' shouldn't.
275 # of the entries in the set, but 'y()', 'z()' and 'or()' shouldn't.
276 #
276 #
277 # 'any' means the order doesn't matter. For instance,
277 # 'any' means the order doesn't matter. For instance,
278 #
278 #
279 # X & !Y
279 # X & !Y
280 # ^
280 # ^
281 # any
281 # any
282 #
282 #
283 # 'y()' can either enforce its ordering requirement or take the ordering
283 # 'y()' can either enforce its ordering requirement or take the ordering
284 # specified by 'x()' because 'not()' doesn't care the order.
284 # specified by 'x()' because 'not()' doesn't care the order.
285 #
286 # Transition of ordering requirement:
287 #
288 # 1. starts with 'define'
289 # 2. shifts to 'follow' by 'x & y'
290 # 3. changes back to 'define' on function call 'f(x)' or function-like
291 # operation 'x (f) y' because 'f' may have its own ordering requirement
292 # for 'x' and 'y' (e.g. 'first(x)')
293 #
294 anyorder = 'any' # don't care the order
285 anyorder = 'any' # don't care the order
295 defineorder = 'define' # should define the order
286 defineorder = 'define' # should define the order
296 followorder = 'follow' # must follow the current order
287 followorder = 'follow' # must follow the current order
297
288
298 # transition table for 'x & y', from the current expression 'x' to 'y'
299 _tofolloworder = {
300 anyorder: anyorder,
301 defineorder: followorder,
302 followorder: followorder,
303 }
304
305 def _matchonly(revs, bases):
289 def _matchonly(revs, bases):
306 """
290 """
307 >>> f = lambda *args: _matchonly(*map(parse, args))
291 >>> f = lambda *args: _matchonly(*map(parse, args))
308 >>> f('ancestors(A)', 'not ancestors(B)')
292 >>> f('ancestors(A)', 'not ancestors(B)')
309 ('list', ('symbol', 'A'), ('symbol', 'B'))
293 ('list', ('symbol', 'A'), ('symbol', 'B'))
310 """
294 """
311 ta = _matchnamedfunc(revs, 'ancestors')
295 ta = _matchnamedfunc(revs, 'ancestors')
312 tb = bases and bases[0] == 'not' and _matchnamedfunc(bases[1], 'ancestors')
296 tb = bases and bases[0] == 'not' and _matchnamedfunc(bases[1], 'ancestors')
313 if _isposargs(ta, 1) and _isposargs(tb, 1):
297 if _isposargs(ta, 1) and _isposargs(tb, 1):
314 return ('list', ta, tb)
298 return ('list', ta, tb)
315
299
316 def _fixops(x):
300 def _fixops(x):
317 """Rewrite raw parsed tree to resolve ambiguous syntax which cannot be
301 """Rewrite raw parsed tree to resolve ambiguous syntax which cannot be
318 handled well by our simple top-down parser"""
302 handled well by our simple top-down parser"""
319 if not isinstance(x, tuple):
303 if not isinstance(x, tuple):
320 return x
304 return x
321
305
322 op = x[0]
306 op = x[0]
323 if op == 'parent':
307 if op == 'parent':
324 # x^:y means (x^) : y, not x ^ (:y)
308 # x^:y means (x^) : y, not x ^ (:y)
325 # x^: means (x^) :, not x ^ (:)
309 # x^: means (x^) :, not x ^ (:)
326 post = ('parentpost', x[1])
310 post = ('parentpost', x[1])
327 if x[2][0] == 'dagrangepre':
311 if x[2][0] == 'dagrangepre':
328 return _fixops(('dagrange', post, x[2][1]))
312 return _fixops(('dagrange', post, x[2][1]))
329 elif x[2][0] == 'rangepre':
313 elif x[2][0] == 'rangepre':
330 return _fixops(('range', post, x[2][1]))
314 return _fixops(('range', post, x[2][1]))
331 elif x[2][0] == 'rangeall':
315 elif x[2][0] == 'rangeall':
332 return _fixops(('rangepost', post))
316 return _fixops(('rangepost', post))
333 elif op == 'or':
317 elif op == 'or':
334 # make number of arguments deterministic:
318 # make number of arguments deterministic:
335 # x + y + z -> (or x y z) -> (or (list x y z))
319 # x + y + z -> (or x y z) -> (or (list x y z))
336 return (op, _fixops(('list',) + x[1:]))
320 return (op, _fixops(('list',) + x[1:]))
337 elif op == 'subscript' and x[1][0] == 'relation':
321 elif op == 'subscript' and x[1][0] == 'relation':
338 # x#y[z] ternary
322 # x#y[z] ternary
339 return _fixops(('relsubscript', x[1][1], x[1][2], x[2]))
323 return _fixops(('relsubscript', x[1][1], x[1][2], x[2]))
340
324
341 return (op,) + tuple(_fixops(y) for y in x[1:])
325 return (op,) + tuple(_fixops(y) for y in x[1:])
342
326
343 def _analyze(x, order):
327 def _analyze(x):
344 if x is None:
328 if x is None:
345 return x
329 return x
346
330
347 op = x[0]
331 op = x[0]
348 if op == 'minus':
332 if op == 'minus':
349 return _analyze(('and', x[1], ('not', x[2])), order)
333 return _analyze(('and', x[1], ('not', x[2])))
350 elif op == 'only':
334 elif op == 'only':
351 t = ('func', ('symbol', 'only'), ('list', x[1], x[2]))
335 t = ('func', ('symbol', 'only'), ('list', x[1], x[2]))
352 return _analyze(t, order)
336 return _analyze(t)
353 elif op == 'onlypost':
337 elif op == 'onlypost':
354 return _analyze(('func', ('symbol', 'only'), x[1]), order)
338 return _analyze(('func', ('symbol', 'only'), x[1]))
355 elif op == 'dagrangepre':
339 elif op == 'dagrangepre':
356 return _analyze(('func', ('symbol', 'ancestors'), x[1]), order)
340 return _analyze(('func', ('symbol', 'ancestors'), x[1]))
357 elif op == 'dagrangepost':
341 elif op == 'dagrangepost':
358 return _analyze(('func', ('symbol', 'descendants'), x[1]), order)
342 return _analyze(('func', ('symbol', 'descendants'), x[1]))
359 elif op == 'negate':
343 elif op == 'negate':
360 s = getstring(x[1], _("can't negate that"))
344 s = getstring(x[1], _("can't negate that"))
361 return _analyze(('string', '-' + s), order)
345 return _analyze(('string', '-' + s))
362 elif op in ('string', 'symbol'):
346 elif op in ('string', 'symbol'):
363 return x
347 return x
364 elif op == 'and':
365 ta = _analyze(x[1], order)
366 tb = _analyze(x[2], _tofolloworder[order])
367 return (op, ta, tb, order)
368 elif op == 'or':
369 return (op, _analyze(x[1], order), order)
370 elif op == 'not':
371 return (op, _analyze(x[1], anyorder), order)
372 elif op == 'rangeall':
348 elif op == 'rangeall':
373 return (op, None, order)
349 return (op, None)
374 elif op in ('rangepre', 'rangepost', 'parentpost'):
350 elif op in {'or', 'not', 'rangepre', 'rangepost', 'parentpost'}:
375 return (op, _analyze(x[1], defineorder), order)
351 return (op, _analyze(x[1]))
376 elif op == 'group':
352 elif op == 'group':
377 return _analyze(x[1], order)
353 return _analyze(x[1])
378 elif op in ('dagrange', 'range', 'parent', 'ancestor', 'relation',
354 elif op in {'and', 'dagrange', 'range', 'parent', 'ancestor', 'relation',
379 'subscript'):
355 'subscript'}:
380 ta = _analyze(x[1], defineorder)
356 ta = _analyze(x[1])
381 tb = _analyze(x[2], defineorder)
357 tb = _analyze(x[2])
382 return (op, ta, tb, order)
358 return (op, ta, tb)
383 elif op == 'relsubscript':
359 elif op == 'relsubscript':
384 ta = _analyze(x[1], defineorder)
360 ta = _analyze(x[1])
385 tb = _analyze(x[2], defineorder)
361 tb = _analyze(x[2])
386 tc = _analyze(x[3], defineorder)
362 tc = _analyze(x[3])
387 return (op, ta, tb, tc, order)
363 return (op, ta, tb, tc)
388 elif op == 'list':
364 elif op == 'list':
389 return (op,) + tuple(_analyze(y, order) for y in x[1:])
365 return (op,) + tuple(_analyze(y) for y in x[1:])
390 elif op == 'keyvalue':
366 elif op == 'keyvalue':
391 return (op, x[1], _analyze(x[2], order))
367 return (op, x[1], _analyze(x[2]))
392 elif op == 'func':
368 elif op == 'func':
393 f = getsymbol(x[1])
369 return (op, x[1], _analyze(x[2]))
394 d = defineorder
395 if f == 'present':
396 # 'present(set)' is known to return the argument set with no
397 # modification, so forward the current order to its argument
398 d = order
399 return (op, x[1], _analyze(x[2], d), order)
400 raise ValueError('invalid operator %r' % op)
370 raise ValueError('invalid operator %r' % op)
401
371
402 def analyze(x, order=defineorder):
372 def analyze(x):
403 """Transform raw parsed tree to evaluatable tree which can be fed to
373 """Transform raw parsed tree to evaluatable tree which can be fed to
404 optimize() or getset()
374 optimize() or getset()
405
375
406 All pseudo operations should be mapped to real operations or functions
376 All pseudo operations should be mapped to real operations or functions
407 defined in methods or symbols table respectively.
377 defined in methods or symbols table respectively.
408
409 'order' specifies how the current expression 'x' is ordered (see the
410 constants defined above.)
411 """
378 """
412 return _analyze(x, order)
379 return _analyze(x)
413
380
414 def _optimize(x, small):
381 def _optimize(x, small):
415 if x is None:
382 if x is None:
416 return 0, x
383 return 0, x
417
384
418 smallbonus = 1
385 smallbonus = 1
419 if small:
386 if small:
420 smallbonus = .5
387 smallbonus = .5
421
388
422 op = x[0]
389 op = x[0]
423 if op in ('string', 'symbol'):
390 if op in ('string', 'symbol'):
424 return smallbonus, x # single revisions are small
391 return smallbonus, x # single revisions are small
425 elif op == 'and':
392 elif op == 'and':
426 wa, ta = _optimize(x[1], True)
393 wa, ta = _optimize(x[1], True)
427 wb, tb = _optimize(x[2], True)
394 wb, tb = _optimize(x[2], True)
428 order = x[3]
429 w = min(wa, wb)
395 w = min(wa, wb)
430
396
431 # (::x and not ::y)/(not ::y and ::x) have a fast path
397 # (::x and not ::y)/(not ::y and ::x) have a fast path
432 tm = _matchonly(ta, tb) or _matchonly(tb, ta)
398 tm = _matchonly(ta, tb) or _matchonly(tb, ta)
433 if tm:
399 if tm:
434 return w, ('func', ('symbol', 'only'), tm, order)
400 return w, ('func', ('symbol', 'only'), tm)
435
401
436 if tb is not None and tb[0] == 'not':
402 if tb is not None and tb[0] == 'not':
437 return wa, ('difference', ta, tb[1], order)
403 return wa, ('difference', ta, tb[1])
438
439 if wa > wb:
404 if wa > wb:
440 return w, (op, tb, ta, order)
405 return w, ('flipand', tb, ta)
441 return w, (op, ta, tb, order)
406 return w, (op, ta, tb)
442 elif op == 'or':
407 elif op == 'or':
443 # fast path for machine-generated expression, that is likely to have
408 # fast path for machine-generated expression, that is likely to have
444 # lots of trivial revisions: 'a + b + c()' to '_list(a b) + c()'
409 # lots of trivial revisions: 'a + b + c()' to '_list(a b) + c()'
445 order = x[2]
446 ws, ts, ss = [], [], []
410 ws, ts, ss = [], [], []
447 def flushss():
411 def flushss():
448 if not ss:
412 if not ss:
449 return
413 return
450 if len(ss) == 1:
414 if len(ss) == 1:
451 w, t = ss[0]
415 w, t = ss[0]
452 else:
416 else:
453 s = '\0'.join(t[1] for w, t in ss)
417 s = '\0'.join(t[1] for w, t in ss)
454 y = ('func', ('symbol', '_list'), ('string', s), order)
418 y = ('func', ('symbol', '_list'), ('string', s))
455 w, t = _optimize(y, False)
419 w, t = _optimize(y, False)
456 ws.append(w)
420 ws.append(w)
457 ts.append(t)
421 ts.append(t)
458 del ss[:]
422 del ss[:]
459 for y in getlist(x[1]):
423 for y in getlist(x[1]):
460 w, t = _optimize(y, False)
424 w, t = _optimize(y, False)
461 if t is not None and (t[0] == 'string' or t[0] == 'symbol'):
425 if t is not None and (t[0] == 'string' or t[0] == 'symbol'):
462 ss.append((w, t))
426 ss.append((w, t))
463 continue
427 continue
464 flushss()
428 flushss()
465 ws.append(w)
429 ws.append(w)
466 ts.append(t)
430 ts.append(t)
467 flushss()
431 flushss()
468 if len(ts) == 1:
432 if len(ts) == 1:
469 return ws[0], ts[0] # 'or' operation is fully optimized out
433 return ws[0], ts[0] # 'or' operation is fully optimized out
470 return max(ws), (op, ('list',) + tuple(ts), order)
434 return max(ws), (op, ('list',) + tuple(ts))
471 elif op == 'not':
435 elif op == 'not':
472 # Optimize not public() to _notpublic() because we have a fast version
436 # Optimize not public() to _notpublic() because we have a fast version
473 if x[1][:3] == ('func', ('symbol', 'public'), None):
437 if x[1][:3] == ('func', ('symbol', 'public'), None):
474 order = x[1][3]
438 newsym = ('func', ('symbol', '_notpublic'), None)
475 newsym = ('func', ('symbol', '_notpublic'), None, order)
476 o = _optimize(newsym, not small)
439 o = _optimize(newsym, not small)
477 return o[0], o[1]
440 return o[0], o[1]
478 else:
441 else:
479 o = _optimize(x[1], not small)
442 o = _optimize(x[1], not small)
480 order = x[2]
443 return o[0], (op, o[1])
481 return o[0], (op, o[1], order)
482 elif op == 'rangeall':
444 elif op == 'rangeall':
483 return smallbonus, x
445 return smallbonus, x
484 elif op in ('rangepre', 'rangepost', 'parentpost'):
446 elif op in ('rangepre', 'rangepost', 'parentpost'):
485 o = _optimize(x[1], small)
447 o = _optimize(x[1], small)
486 order = x[2]
448 return o[0], (op, o[1])
487 return o[0], (op, o[1], order)
488 elif op in ('dagrange', 'range'):
449 elif op in ('dagrange', 'range'):
489 wa, ta = _optimize(x[1], small)
450 wa, ta = _optimize(x[1], small)
490 wb, tb = _optimize(x[2], small)
451 wb, tb = _optimize(x[2], small)
491 order = x[3]
452 return wa + wb, (op, ta, tb)
492 return wa + wb, (op, ta, tb, order)
493 elif op in ('parent', 'ancestor', 'relation', 'subscript'):
453 elif op in ('parent', 'ancestor', 'relation', 'subscript'):
494 w, t = _optimize(x[1], small)
454 w, t = _optimize(x[1], small)
495 order = x[3]
455 return w, (op, t, x[2])
496 return w, (op, t, x[2], order)
497 elif op == 'relsubscript':
456 elif op == 'relsubscript':
498 w, t = _optimize(x[1], small)
457 w, t = _optimize(x[1], small)
499 order = x[4]
458 return w, (op, t, x[2], x[3])
500 return w, (op, t, x[2], x[3], order)
501 elif op == 'list':
459 elif op == 'list':
502 ws, ts = zip(*(_optimize(y, small) for y in x[1:]))
460 ws, ts = zip(*(_optimize(y, small) for y in x[1:]))
503 return sum(ws), (op,) + ts
461 return sum(ws), (op,) + ts
504 elif op == 'keyvalue':
462 elif op == 'keyvalue':
505 w, t = _optimize(x[2], small)
463 w, t = _optimize(x[2], small)
506 return w, (op, x[1], t)
464 return w, (op, x[1], t)
507 elif op == 'func':
465 elif op == 'func':
508 f = getsymbol(x[1])
466 f = getsymbol(x[1])
509 wa, ta = _optimize(x[2], small)
467 wa, ta = _optimize(x[2], small)
510 if f in ('author', 'branch', 'closed', 'date', 'desc', 'file', 'grep',
468 if f in ('author', 'branch', 'closed', 'date', 'desc', 'file', 'grep',
511 'keyword', 'outgoing', 'user', 'destination'):
469 'keyword', 'outgoing', 'user', 'destination'):
512 w = 10 # slow
470 w = 10 # slow
513 elif f in ('modifies', 'adds', 'removes'):
471 elif f in ('modifies', 'adds', 'removes'):
514 w = 30 # slower
472 w = 30 # slower
515 elif f == "contains":
473 elif f == "contains":
516 w = 100 # very slow
474 w = 100 # very slow
517 elif f == "ancestor":
475 elif f == "ancestor":
518 w = 1 * smallbonus
476 w = 1 * smallbonus
519 elif f in ('reverse', 'limit', 'first', 'wdir', '_intlist'):
477 elif f in ('reverse', 'limit', 'first', 'wdir', '_intlist'):
520 w = 0
478 w = 0
521 elif f == "sort":
479 elif f == "sort":
522 w = 10 # assume most sorts look at changelog
480 w = 10 # assume most sorts look at changelog
523 else:
481 else:
524 w = 1
482 w = 1
525 order = x[3]
483 return w + wa, (op, x[1], ta)
526 return w + wa, (op, x[1], ta, order)
527 raise ValueError('invalid operator %r' % op)
484 raise ValueError('invalid operator %r' % op)
528
485
529 def optimize(tree):
486 def optimize(tree):
530 """Optimize evaluatable tree
487 """Optimize evaluatable tree
531
488
532 All pseudo operations should be transformed beforehand.
489 All pseudo operations should be transformed beforehand.
533 """
490 """
534 _weight, newtree = _optimize(tree, small=True)
491 _weight, newtree = _optimize(tree, small=True)
535 return newtree
492 return newtree
536
493
537 # the set of valid characters for the initial letter of symbols in
494 # the set of valid characters for the initial letter of symbols in
538 # alias declarations and definitions
495 # alias declarations and definitions
539 _aliassyminitletters = _syminitletters | set(pycompat.sysstr('$'))
496 _aliassyminitletters = _syminitletters | set(pycompat.sysstr('$'))
540
497
541 def _parsewith(spec, lookup=None, syminitletters=None):
498 def _parsewith(spec, lookup=None, syminitletters=None):
542 """Generate a parse tree of given spec with given tokenizing options
499 """Generate a parse tree of given spec with given tokenizing options
543
500
544 >>> _parsewith('foo($1)', syminitletters=_aliassyminitletters)
501 >>> _parsewith('foo($1)', syminitletters=_aliassyminitletters)
545 ('func', ('symbol', 'foo'), ('symbol', '$1'))
502 ('func', ('symbol', 'foo'), ('symbol', '$1'))
546 >>> _parsewith('$1')
503 >>> _parsewith('$1')
547 Traceback (most recent call last):
504 Traceback (most recent call last):
548 ...
505 ...
549 ParseError: ("syntax error in revset '$1'", 0)
506 ParseError: ("syntax error in revset '$1'", 0)
550 >>> _parsewith('foo bar')
507 >>> _parsewith('foo bar')
551 Traceback (most recent call last):
508 Traceback (most recent call last):
552 ...
509 ...
553 ParseError: ('invalid token', 4)
510 ParseError: ('invalid token', 4)
554 """
511 """
555 p = parser.parser(elements)
512 p = parser.parser(elements)
556 tree, pos = p.parse(tokenize(spec, lookup=lookup,
513 tree, pos = p.parse(tokenize(spec, lookup=lookup,
557 syminitletters=syminitletters))
514 syminitletters=syminitletters))
558 if pos != len(spec):
515 if pos != len(spec):
559 raise error.ParseError(_('invalid token'), pos)
516 raise error.ParseError(_('invalid token'), pos)
560 return _fixops(parser.simplifyinfixops(tree, ('list', 'or')))
517 return _fixops(parser.simplifyinfixops(tree, ('list', 'or')))
561
518
562 class _aliasrules(parser.basealiasrules):
519 class _aliasrules(parser.basealiasrules):
563 """Parsing and expansion rule set of revset aliases"""
520 """Parsing and expansion rule set of revset aliases"""
564 _section = _('revset alias')
521 _section = _('revset alias')
565
522
566 @staticmethod
523 @staticmethod
567 def _parse(spec):
524 def _parse(spec):
568 """Parse alias declaration/definition ``spec``
525 """Parse alias declaration/definition ``spec``
569
526
570 This allows symbol names to use also ``$`` as an initial letter
527 This allows symbol names to use also ``$`` as an initial letter
571 (for backward compatibility), and callers of this function should
528 (for backward compatibility), and callers of this function should
572 examine whether ``$`` is used also for unexpected symbols or not.
529 examine whether ``$`` is used also for unexpected symbols or not.
573 """
530 """
574 return _parsewith(spec, syminitletters=_aliassyminitletters)
531 return _parsewith(spec, syminitletters=_aliassyminitletters)
575
532
576 @staticmethod
533 @staticmethod
577 def _trygetfunc(tree):
534 def _trygetfunc(tree):
578 if tree[0] == 'func' and tree[1][0] == 'symbol':
535 if tree[0] == 'func' and tree[1][0] == 'symbol':
579 return tree[1][1], getlist(tree[2])
536 return tree[1][1], getlist(tree[2])
580
537
581 def expandaliases(tree, aliases, warn=None):
538 def expandaliases(tree, aliases, warn=None):
582 """Expand aliases in a tree, aliases is a list of (name, value) tuples"""
539 """Expand aliases in a tree, aliases is a list of (name, value) tuples"""
583 aliases = _aliasrules.buildmap(aliases)
540 aliases = _aliasrules.buildmap(aliases)
584 tree = _aliasrules.expand(aliases, tree)
541 tree = _aliasrules.expand(aliases, tree)
585 # warn about problematic (but not referred) aliases
542 # warn about problematic (but not referred) aliases
586 if warn is not None:
543 if warn is not None:
587 for name, alias in sorted(aliases.iteritems()):
544 for name, alias in sorted(aliases.iteritems()):
588 if alias.error and not alias.warned:
545 if alias.error and not alias.warned:
589 warn(_('warning: %s\n') % (alias.error))
546 warn(_('warning: %s\n') % (alias.error))
590 alias.warned = True
547 alias.warned = True
591 return tree
548 return tree
592
549
593 def foldconcat(tree):
550 def foldconcat(tree):
594 """Fold elements to be concatenated by `##`
551 """Fold elements to be concatenated by `##`
595 """
552 """
596 if not isinstance(tree, tuple) or tree[0] in ('string', 'symbol'):
553 if not isinstance(tree, tuple) or tree[0] in ('string', 'symbol'):
597 return tree
554 return tree
598 if tree[0] == '_concat':
555 if tree[0] == '_concat':
599 pending = [tree]
556 pending = [tree]
600 l = []
557 l = []
601 while pending:
558 while pending:
602 e = pending.pop()
559 e = pending.pop()
603 if e[0] == '_concat':
560 if e[0] == '_concat':
604 pending.extend(reversed(e[1:]))
561 pending.extend(reversed(e[1:]))
605 elif e[0] in ('string', 'symbol'):
562 elif e[0] in ('string', 'symbol'):
606 l.append(e[1])
563 l.append(e[1])
607 else:
564 else:
608 msg = _("\"##\" can't concatenate \"%s\" element") % (e[0])
565 msg = _("\"##\" can't concatenate \"%s\" element") % (e[0])
609 raise error.ParseError(msg)
566 raise error.ParseError(msg)
610 return ('string', ''.join(l))
567 return ('string', ''.join(l))
611 else:
568 else:
612 return tuple(foldconcat(t) for t in tree)
569 return tuple(foldconcat(t) for t in tree)
613
570
614 def parse(spec, lookup=None):
571 def parse(spec, lookup=None):
615 return _parsewith(spec, lookup=lookup)
572 return _parsewith(spec, lookup=lookup)
616
573
617 def _quote(s):
574 def _quote(s):
618 r"""Quote a value in order to make it safe for the revset engine.
575 r"""Quote a value in order to make it safe for the revset engine.
619
576
620 >>> _quote('asdf')
577 >>> _quote('asdf')
621 "'asdf'"
578 "'asdf'"
622 >>> _quote("asdf'\"")
579 >>> _quote("asdf'\"")
623 '\'asdf\\\'"\''
580 '\'asdf\\\'"\''
624 >>> _quote('asdf\'')
581 >>> _quote('asdf\'')
625 "'asdf\\''"
582 "'asdf\\''"
626 >>> _quote(1)
583 >>> _quote(1)
627 "'1'"
584 "'1'"
628 """
585 """
629 return "'%s'" % util.escapestr(pycompat.bytestr(s))
586 return "'%s'" % util.escapestr(pycompat.bytestr(s))
630
587
631 def formatspec(expr, *args):
588 def formatspec(expr, *args):
632 '''
589 '''
633 This is a convenience function for using revsets internally, and
590 This is a convenience function for using revsets internally, and
634 escapes arguments appropriately. Aliases are intentionally ignored
591 escapes arguments appropriately. Aliases are intentionally ignored
635 so that intended expression behavior isn't accidentally subverted.
592 so that intended expression behavior isn't accidentally subverted.
636
593
637 Supported arguments:
594 Supported arguments:
638
595
639 %r = revset expression, parenthesized
596 %r = revset expression, parenthesized
640 %d = int(arg), no quoting
597 %d = int(arg), no quoting
641 %s = string(arg), escaped and single-quoted
598 %s = string(arg), escaped and single-quoted
642 %b = arg.branch(), escaped and single-quoted
599 %b = arg.branch(), escaped and single-quoted
643 %n = hex(arg), single-quoted
600 %n = hex(arg), single-quoted
644 %% = a literal '%'
601 %% = a literal '%'
645
602
646 Prefixing the type with 'l' specifies a parenthesized list of that type.
603 Prefixing the type with 'l' specifies a parenthesized list of that type.
647
604
648 >>> formatspec('%r:: and %lr', '10 or 11', ("this()", "that()"))
605 >>> formatspec('%r:: and %lr', '10 or 11', ("this()", "that()"))
649 '(10 or 11):: and ((this()) or (that()))'
606 '(10 or 11):: and ((this()) or (that()))'
650 >>> formatspec('%d:: and not %d::', 10, 20)
607 >>> formatspec('%d:: and not %d::', 10, 20)
651 '10:: and not 20::'
608 '10:: and not 20::'
652 >>> formatspec('%ld or %ld', [], [1])
609 >>> formatspec('%ld or %ld', [], [1])
653 "_list('') or 1"
610 "_list('') or 1"
654 >>> formatspec('keyword(%s)', 'foo\\xe9')
611 >>> formatspec('keyword(%s)', 'foo\\xe9')
655 "keyword('foo\\\\xe9')"
612 "keyword('foo\\\\xe9')"
656 >>> b = lambda: 'default'
613 >>> b = lambda: 'default'
657 >>> b.branch = b
614 >>> b.branch = b
658 >>> formatspec('branch(%b)', b)
615 >>> formatspec('branch(%b)', b)
659 "branch('default')"
616 "branch('default')"
660 >>> formatspec('root(%ls)', ['a', 'b', 'c', 'd'])
617 >>> formatspec('root(%ls)', ['a', 'b', 'c', 'd'])
661 "root(_list('a\\x00b\\x00c\\x00d'))"
618 "root(_list('a\\x00b\\x00c\\x00d'))"
662 '''
619 '''
663
620
664 def argtype(c, arg):
621 def argtype(c, arg):
665 if c == 'd':
622 if c == 'd':
666 return '%d' % int(arg)
623 return '%d' % int(arg)
667 elif c == 's':
624 elif c == 's':
668 return _quote(arg)
625 return _quote(arg)
669 elif c == 'r':
626 elif c == 'r':
670 parse(arg) # make sure syntax errors are confined
627 parse(arg) # make sure syntax errors are confined
671 return '(%s)' % arg
628 return '(%s)' % arg
672 elif c == 'n':
629 elif c == 'n':
673 return _quote(node.hex(arg))
630 return _quote(node.hex(arg))
674 elif c == 'b':
631 elif c == 'b':
675 return _quote(arg.branch())
632 return _quote(arg.branch())
676
633
677 def listexp(s, t):
634 def listexp(s, t):
678 l = len(s)
635 l = len(s)
679 if l == 0:
636 if l == 0:
680 return "_list('')"
637 return "_list('')"
681 elif l == 1:
638 elif l == 1:
682 return argtype(t, s[0])
639 return argtype(t, s[0])
683 elif t == 'd':
640 elif t == 'd':
684 return "_intlist('%s')" % "\0".join('%d' % int(a) for a in s)
641 return "_intlist('%s')" % "\0".join('%d' % int(a) for a in s)
685 elif t == 's':
642 elif t == 's':
686 return "_list('%s')" % "\0".join(s)
643 return "_list('%s')" % "\0".join(s)
687 elif t == 'n':
644 elif t == 'n':
688 return "_hexlist('%s')" % "\0".join(node.hex(a) for a in s)
645 return "_hexlist('%s')" % "\0".join(node.hex(a) for a in s)
689 elif t == 'b':
646 elif t == 'b':
690 return "_list('%s')" % "\0".join(a.branch() for a in s)
647 return "_list('%s')" % "\0".join(a.branch() for a in s)
691
648
692 m = l // 2
649 m = l // 2
693 return '(%s or %s)' % (listexp(s[:m], t), listexp(s[m:], t))
650 return '(%s or %s)' % (listexp(s[:m], t), listexp(s[m:], t))
694
651
695 expr = pycompat.bytestr(expr)
652 expr = pycompat.bytestr(expr)
696 ret = ''
653 ret = ''
697 pos = 0
654 pos = 0
698 arg = 0
655 arg = 0
699 while pos < len(expr):
656 while pos < len(expr):
700 c = expr[pos]
657 c = expr[pos]
701 if c == '%':
658 if c == '%':
702 pos += 1
659 pos += 1
703 d = expr[pos]
660 d = expr[pos]
704 if d == '%':
661 if d == '%':
705 ret += d
662 ret += d
706 elif d in 'dsnbr':
663 elif d in 'dsnbr':
707 ret += argtype(d, args[arg])
664 ret += argtype(d, args[arg])
708 arg += 1
665 arg += 1
709 elif d == 'l':
666 elif d == 'l':
710 # a list of some type
667 # a list of some type
711 pos += 1
668 pos += 1
712 d = expr[pos]
669 d = expr[pos]
713 ret += listexp(list(args[arg]), d)
670 ret += listexp(list(args[arg]), d)
714 arg += 1
671 arg += 1
715 else:
672 else:
716 raise error.Abort(_('unexpected revspec format character %s')
673 raise error.Abort(_('unexpected revspec format character %s')
717 % d)
674 % d)
718 else:
675 else:
719 ret += c
676 ret += c
720 pos += 1
677 pos += 1
721
678
722 return ret
679 return ret
723
680
724 def prettyformat(tree):
681 def prettyformat(tree):
725 return parser.prettyformat(tree, ('string', 'symbol'))
682 return parser.prettyformat(tree, ('string', 'symbol'))
726
683
727 def depth(tree):
684 def depth(tree):
728 if isinstance(tree, tuple):
685 if isinstance(tree, tuple):
729 return max(map(depth, tree)) + 1
686 return max(map(depth, tree)) + 1
730 else:
687 else:
731 return 0
688 return 0
732
689
733 def funcsused(tree):
690 def funcsused(tree):
734 if not isinstance(tree, tuple) or tree[0] in ('string', 'symbol'):
691 if not isinstance(tree, tuple) or tree[0] in ('string', 'symbol'):
735 return set()
692 return set()
736 else:
693 else:
737 funcs = set()
694 funcs = set()
738 for s in tree[1:]:
695 for s in tree[1:]:
739 funcs |= funcsused(s)
696 funcs |= funcsused(s)
740 if tree[0] == 'func':
697 if tree[0] == 'func':
741 funcs.add(tree[1][1])
698 funcs.add(tree[1][1])
742 return funcs
699 return funcs
@@ -1,4453 +1,4323
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['r3232'] = r3232
19 > mercurial.revset.symbols['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 > smartset,
45 > smartset,
46 > )
46 > )
47 > cmdtable = {}
47 > cmdtable = {}
48 > command = registrar.command(cmdtable)
48 > command = registrar.command(cmdtable)
49 > @command(b'debugrevlistspec',
49 > @command(b'debugrevlistspec',
50 > [('', 'optimize', None, 'print parsed tree after optimizing'),
50 > [('', 'optimize', None, 'print parsed tree after optimizing'),
51 > ('', 'bin', None, 'unhexlify arguments')])
51 > ('', 'bin', None, '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=repo.__contains__)
57 > tree = revsetlang.parse(expr, lookup=repo.__contains__)
58 > ui.note(revsetlang.prettyformat(tree), "\n")
58 > ui.note(revsetlang.prettyformat(tree), "\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("* optimized:\n", revsetlang.prettyformat(opttree),
61 > ui.note("* optimized:\n", revsetlang.prettyformat(opttree),
62 > "\n")
62 > "\n")
63 > func = revset.match(ui, expr, repo)
63 > func = revset.match(ui, expr, repo)
64 > revs = func(repo)
64 > revs = func(repo)
65 > if ui.verbose:
65 > if ui.verbose:
66 > ui.note("* set:\n", smartset.prettyformat(revs), "\n")
66 > ui.note("* set:\n", smartset.prettyformat(revs), "\n")
67 > for c in revs:
67 > for c in revs:
68 > ui.write("%s\n" % c)
68 > ui.write("%s\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 define)
171 * set:
170 * set:
172 <spanset+ 0:10>
171 <spanset+ 0:10>
173 0
172 0
174 1
173 1
175 2
174 2
176 3
175 3
177 4
176 4
178 5
177 5
179 6
178 6
180 7
179 7
181 8
180 8
182 9
181 9
183 $ try 3::6
182 $ try 3::6
184 (dagrange
183 (dagrange
185 ('symbol', '3')
184 ('symbol', '3')
186 ('symbol', '6'))
185 ('symbol', '6'))
187 * set:
186 * set:
188 <baseset+ [3, 5, 6]>
187 <baseset+ [3, 5, 6]>
189 3
188 3
190 5
189 5
191 6
190 6
192 $ try '0|1|2'
191 $ try '0|1|2'
193 (or
192 (or
194 (list
193 (list
195 ('symbol', '0')
194 ('symbol', '0')
196 ('symbol', '1')
195 ('symbol', '1')
197 ('symbol', '2')))
196 ('symbol', '2')))
198 * set:
197 * set:
199 <baseset [0, 1, 2]>
198 <baseset [0, 1, 2]>
200 0
199 0
201 1
200 1
202 2
201 2
203
202
204 names that should work without quoting
203 names that should work without quoting
205
204
206 $ try a
205 $ try a
207 ('symbol', 'a')
206 ('symbol', 'a')
208 * set:
207 * set:
209 <baseset [0]>
208 <baseset [0]>
210 0
209 0
211 $ try b-a
210 $ try b-a
212 (minus
211 (minus
213 ('symbol', 'b')
212 ('symbol', 'b')
214 ('symbol', 'a'))
213 ('symbol', 'a'))
215 * set:
214 * set:
216 <filteredset
215 <filteredset
217 <baseset [1]>,
216 <baseset [1]>,
218 <not
217 <not
219 <baseset [0]>>>
218 <baseset [0]>>>
220 1
219 1
221 $ try _a_b_c_
220 $ try _a_b_c_
222 ('symbol', '_a_b_c_')
221 ('symbol', '_a_b_c_')
223 * set:
222 * set:
224 <baseset [6]>
223 <baseset [6]>
225 6
224 6
226 $ try _a_b_c_-a
225 $ try _a_b_c_-a
227 (minus
226 (minus
228 ('symbol', '_a_b_c_')
227 ('symbol', '_a_b_c_')
229 ('symbol', 'a'))
228 ('symbol', 'a'))
230 * set:
229 * set:
231 <filteredset
230 <filteredset
232 <baseset [6]>,
231 <baseset [6]>,
233 <not
232 <not
234 <baseset [0]>>>
233 <baseset [0]>>>
235 6
234 6
236 $ try .a.b.c.
235 $ try .a.b.c.
237 ('symbol', '.a.b.c.')
236 ('symbol', '.a.b.c.')
238 * set:
237 * set:
239 <baseset [7]>
238 <baseset [7]>
240 7
239 7
241 $ try .a.b.c.-a
240 $ try .a.b.c.-a
242 (minus
241 (minus
243 ('symbol', '.a.b.c.')
242 ('symbol', '.a.b.c.')
244 ('symbol', 'a'))
243 ('symbol', 'a'))
245 * set:
244 * set:
246 <filteredset
245 <filteredset
247 <baseset [7]>,
246 <baseset [7]>,
248 <not
247 <not
249 <baseset [0]>>>
248 <baseset [0]>>>
250 7
249 7
251
250
252 names that should be caught by fallback mechanism
251 names that should be caught by fallback mechanism
253
252
254 $ try -- '-a-b-c-'
253 $ try -- '-a-b-c-'
255 ('symbol', '-a-b-c-')
254 ('symbol', '-a-b-c-')
256 * set:
255 * set:
257 <baseset [4]>
256 <baseset [4]>
258 4
257 4
259 $ log -a-b-c-
258 $ log -a-b-c-
260 4
259 4
261 $ try '+a+b+c+'
260 $ try '+a+b+c+'
262 ('symbol', '+a+b+c+')
261 ('symbol', '+a+b+c+')
263 * set:
262 * set:
264 <baseset [3]>
263 <baseset [3]>
265 3
264 3
266 $ try '+a+b+c+:'
265 $ try '+a+b+c+:'
267 (rangepost
266 (rangepost
268 ('symbol', '+a+b+c+'))
267 ('symbol', '+a+b+c+'))
269 * set:
268 * set:
270 <spanset+ 3:10>
269 <spanset+ 3:10>
271 3
270 3
272 4
271 4
273 5
272 5
274 6
273 6
275 7
274 7
276 8
275 8
277 9
276 9
278 $ try ':+a+b+c+'
277 $ try ':+a+b+c+'
279 (rangepre
278 (rangepre
280 ('symbol', '+a+b+c+'))
279 ('symbol', '+a+b+c+'))
281 * set:
280 * set:
282 <spanset+ 0:4>
281 <spanset+ 0:4>
283 0
282 0
284 1
283 1
285 2
284 2
286 3
285 3
287 $ try -- '-a-b-c-:+a+b+c+'
286 $ try -- '-a-b-c-:+a+b+c+'
288 (range
287 (range
289 ('symbol', '-a-b-c-')
288 ('symbol', '-a-b-c-')
290 ('symbol', '+a+b+c+'))
289 ('symbol', '+a+b+c+'))
291 * set:
290 * set:
292 <spanset- 3:5>
291 <spanset- 3:5>
293 4
292 4
294 3
293 3
295 $ log '-a-b-c-:+a+b+c+'
294 $ log '-a-b-c-:+a+b+c+'
296 4
295 4
297 3
296 3
298
297
299 $ try -- -a-b-c--a # complains
298 $ try -- -a-b-c--a # complains
300 (minus
299 (minus
301 (minus
300 (minus
302 (minus
301 (minus
303 (negate
302 (negate
304 ('symbol', 'a'))
303 ('symbol', 'a'))
305 ('symbol', 'b'))
304 ('symbol', 'b'))
306 ('symbol', 'c'))
305 ('symbol', 'c'))
307 (negate
306 (negate
308 ('symbol', 'a')))
307 ('symbol', 'a')))
309 abort: unknown revision '-a'!
308 abort: unknown revision '-a'!
310 [255]
309 [255]
311 $ try Γ©
310 $ try Γ©
312 ('symbol', '\xc3\xa9')
311 ('symbol', '\xc3\xa9')
313 * set:
312 * set:
314 <baseset [9]>
313 <baseset [9]>
315 9
314 9
316
315
317 no quoting needed
316 no quoting needed
318
317
319 $ log ::a-b-c-
318 $ log ::a-b-c-
320 0
319 0
321 1
320 1
322 2
321 2
323
322
324 quoting needed
323 quoting needed
325
324
326 $ try '"-a-b-c-"-a'
325 $ try '"-a-b-c-"-a'
327 (minus
326 (minus
328 ('string', '-a-b-c-')
327 ('string', '-a-b-c-')
329 ('symbol', 'a'))
328 ('symbol', 'a'))
330 * set:
329 * set:
331 <filteredset
330 <filteredset
332 <baseset [4]>,
331 <baseset [4]>,
333 <not
332 <not
334 <baseset [0]>>>
333 <baseset [0]>>>
335 4
334 4
336
335
337 $ log '1 or 2'
336 $ log '1 or 2'
338 1
337 1
339 2
338 2
340 $ log '1|2'
339 $ log '1|2'
341 1
340 1
342 2
341 2
343 $ log '1 and 2'
342 $ log '1 and 2'
344 $ log '1&2'
343 $ log '1&2'
345 $ try '1&2|3' # precedence - and is higher
344 $ try '1&2|3' # precedence - and is higher
346 (or
345 (or
347 (list
346 (list
348 (and
347 (and
349 ('symbol', '1')
348 ('symbol', '1')
350 ('symbol', '2'))
349 ('symbol', '2'))
351 ('symbol', '3')))
350 ('symbol', '3')))
352 * set:
351 * set:
353 <addset
352 <addset
354 <baseset []>,
353 <baseset []>,
355 <baseset [3]>>
354 <baseset [3]>>
356 3
355 3
357 $ try '1|2&3'
356 $ try '1|2&3'
358 (or
357 (or
359 (list
358 (list
360 ('symbol', '1')
359 ('symbol', '1')
361 (and
360 (and
362 ('symbol', '2')
361 ('symbol', '2')
363 ('symbol', '3'))))
362 ('symbol', '3'))))
364 * set:
363 * set:
365 <addset
364 <addset
366 <baseset [1]>,
365 <baseset [1]>,
367 <baseset []>>
366 <baseset []>>
368 1
367 1
369 $ try '1&2&3' # associativity
368 $ try '1&2&3' # associativity
370 (and
369 (and
371 (and
370 (and
372 ('symbol', '1')
371 ('symbol', '1')
373 ('symbol', '2'))
372 ('symbol', '2'))
374 ('symbol', '3'))
373 ('symbol', '3'))
375 * set:
374 * set:
376 <baseset []>
375 <baseset []>
377 $ try '1|(2|3)'
376 $ try '1|(2|3)'
378 (or
377 (or
379 (list
378 (list
380 ('symbol', '1')
379 ('symbol', '1')
381 (group
380 (group
382 (or
381 (or
383 (list
382 (list
384 ('symbol', '2')
383 ('symbol', '2')
385 ('symbol', '3'))))))
384 ('symbol', '3'))))))
386 * set:
385 * set:
387 <addset
386 <addset
388 <baseset [1]>,
387 <baseset [1]>,
389 <baseset [2, 3]>>
388 <baseset [2, 3]>>
390 1
389 1
391 2
390 2
392 3
391 3
393 $ log '1.0' # tag
392 $ log '1.0' # tag
394 6
393 6
395 $ log 'a' # branch
394 $ log 'a' # branch
396 0
395 0
397 $ log '2785f51ee'
396 $ log '2785f51ee'
398 0
397 0
399 $ log 'date(2005)'
398 $ log 'date(2005)'
400 4
399 4
401 $ log 'date(this is a test)'
400 $ log 'date(this is a test)'
402 hg: parse error at 10: unexpected token: symbol
401 hg: parse error at 10: unexpected token: symbol
403 [255]
402 [255]
404 $ log 'date()'
403 $ log 'date()'
405 hg: parse error: date requires a string
404 hg: parse error: date requires a string
406 [255]
405 [255]
407 $ log 'date'
406 $ log 'date'
408 abort: unknown revision 'date'!
407 abort: unknown revision 'date'!
409 [255]
408 [255]
410 $ log 'date('
409 $ log 'date('
411 hg: parse error at 5: not a prefix: end
410 hg: parse error at 5: not a prefix: end
412 [255]
411 [255]
413 $ log 'date("\xy")'
412 $ log 'date("\xy")'
414 hg: parse error: invalid \x escape
413 hg: parse error: invalid \x escape
415 [255]
414 [255]
416 $ log 'date(tip)'
415 $ log 'date(tip)'
417 hg: parse error: invalid date: 'tip'
416 hg: parse error: invalid date: 'tip'
418 [255]
417 [255]
419 $ log '0:date'
418 $ log '0:date'
420 abort: unknown revision 'date'!
419 abort: unknown revision 'date'!
421 [255]
420 [255]
422 $ log '::"date"'
421 $ log '::"date"'
423 abort: unknown revision 'date'!
422 abort: unknown revision 'date'!
424 [255]
423 [255]
425 $ hg book date -r 4
424 $ hg book date -r 4
426 $ log '0:date'
425 $ log '0:date'
427 0
426 0
428 1
427 1
429 2
428 2
430 3
429 3
431 4
430 4
432 $ log '::date'
431 $ log '::date'
433 0
432 0
434 1
433 1
435 2
434 2
436 4
435 4
437 $ log '::"date"'
436 $ log '::"date"'
438 0
437 0
439 1
438 1
440 2
439 2
441 4
440 4
442 $ log 'date(2005) and 1::'
441 $ log 'date(2005) and 1::'
443 4
442 4
444 $ hg book -d date
443 $ hg book -d date
445
444
446 function name should be a symbol
445 function name should be a symbol
447
446
448 $ log '"date"(2005)'
447 $ log '"date"(2005)'
449 hg: parse error: not a symbol
448 hg: parse error: not a symbol
450 [255]
449 [255]
451
450
452 keyword arguments
451 keyword arguments
453
452
454 $ log 'extra(branch, value=a)'
453 $ log 'extra(branch, value=a)'
455 0
454 0
456
455
457 $ log 'extra(branch, a, b)'
456 $ log 'extra(branch, a, b)'
458 hg: parse error: extra takes at most 2 positional arguments
457 hg: parse error: extra takes at most 2 positional arguments
459 [255]
458 [255]
460 $ log 'extra(a, label=b)'
459 $ log 'extra(a, label=b)'
461 hg: parse error: extra got multiple values for keyword argument 'label'
460 hg: parse error: extra got multiple values for keyword argument 'label'
462 [255]
461 [255]
463 $ log 'extra(label=branch, default)'
462 $ log 'extra(label=branch, default)'
464 hg: parse error: extra got an invalid argument
463 hg: parse error: extra got an invalid argument
465 [255]
464 [255]
466 $ log 'extra(branch, foo+bar=baz)'
465 $ log 'extra(branch, foo+bar=baz)'
467 hg: parse error: extra got an invalid argument
466 hg: parse error: extra got an invalid argument
468 [255]
467 [255]
469 $ log 'extra(unknown=branch)'
468 $ log 'extra(unknown=branch)'
470 hg: parse error: extra got an unexpected keyword argument 'unknown'
469 hg: parse error: extra got an unexpected keyword argument 'unknown'
471 [255]
470 [255]
472
471
473 $ try 'foo=bar|baz'
472 $ try 'foo=bar|baz'
474 (keyvalue
473 (keyvalue
475 ('symbol', 'foo')
474 ('symbol', 'foo')
476 (or
475 (or
477 (list
476 (list
478 ('symbol', 'bar')
477 ('symbol', 'bar')
479 ('symbol', 'baz'))))
478 ('symbol', 'baz'))))
480 hg: parse error: can't use a key-value pair in this context
479 hg: parse error: can't use a key-value pair in this context
481 [255]
480 [255]
482
481
483 right-hand side should be optimized recursively
482 right-hand side should be optimized recursively
484
483
485 $ try --optimize 'foo=(not public())'
484 $ try --optimize 'foo=(not public())'
486 (keyvalue
485 (keyvalue
487 ('symbol', 'foo')
486 ('symbol', 'foo')
488 (group
487 (group
489 (not
488 (not
490 (func
489 (func
491 ('symbol', 'public')
490 ('symbol', 'public')
492 None))))
491 None))))
493 * optimized:
492 * optimized:
494 (keyvalue
493 (keyvalue
495 ('symbol', 'foo')
494 ('symbol', 'foo')
496 (func
495 (func
497 ('symbol', '_notpublic')
496 ('symbol', '_notpublic')
498 None
497 None))
499 any))
500 hg: parse error: can't use a key-value pair in this context
498 hg: parse error: can't use a key-value pair in this context
501 [255]
499 [255]
502
500
503 relation-subscript operator has the highest binding strength (as function call):
501 relation-subscript operator has the highest binding strength (as function call):
504
502
505 $ hg debugrevspec -p parsed 'tip:tip^#generations[-1]'
503 $ hg debugrevspec -p parsed 'tip:tip^#generations[-1]'
506 * parsed:
504 * parsed:
507 (range
505 (range
508 ('symbol', 'tip')
506 ('symbol', 'tip')
509 (relsubscript
507 (relsubscript
510 (parentpost
508 (parentpost
511 ('symbol', 'tip'))
509 ('symbol', 'tip'))
512 ('symbol', 'generations')
510 ('symbol', 'generations')
513 (negate
511 (negate
514 ('symbol', '1'))))
512 ('symbol', '1'))))
515 9
513 9
516 8
514 8
517 7
515 7
518 6
516 6
519 5
517 5
520 4
518 4
521
519
522 $ hg debugrevspec -p parsed --no-show-revs 'not public()#generations[0]'
520 $ hg debugrevspec -p parsed --no-show-revs 'not public()#generations[0]'
523 * parsed:
521 * parsed:
524 (not
522 (not
525 (relsubscript
523 (relsubscript
526 (func
524 (func
527 ('symbol', 'public')
525 ('symbol', 'public')
528 None)
526 None)
529 ('symbol', 'generations')
527 ('symbol', 'generations')
530 ('symbol', '0')))
528 ('symbol', '0')))
531
529
532 left-hand side of relation-subscript operator should be optimized recursively:
530 left-hand side of relation-subscript operator should be optimized recursively:
533
531
534 $ hg debugrevspec -p analyzed -p optimized --no-show-revs \
532 $ hg debugrevspec -p analyzed -p optimized --no-show-revs \
535 > '(not public())#generations[0]'
533 > '(not public())#generations[0]'
536 * analyzed:
534 * analyzed:
537 (relsubscript
535 (relsubscript
538 (not
536 (not
539 (func
537 (func
540 ('symbol', 'public')
538 ('symbol', 'public')
541 None
539 None))
542 any)
543 define)
544 ('symbol', 'generations')
540 ('symbol', 'generations')
545 ('symbol', '0')
541 ('symbol', '0'))
546 define)
547 * optimized:
542 * optimized:
548 (relsubscript
543 (relsubscript
549 (func
544 (func
550 ('symbol', '_notpublic')
545 ('symbol', '_notpublic')
551 None
546 None)
552 any)
553 ('symbol', 'generations')
547 ('symbol', 'generations')
554 ('symbol', '0')
548 ('symbol', '0'))
555 define)
556
549
557 resolution of subscript and relation-subscript ternary operators:
550 resolution of subscript and relation-subscript ternary operators:
558
551
559 $ hg debugrevspec -p analyzed 'tip[0]'
552 $ hg debugrevspec -p analyzed 'tip[0]'
560 * analyzed:
553 * analyzed:
561 (subscript
554 (subscript
562 ('symbol', 'tip')
555 ('symbol', 'tip')
563 ('symbol', '0')
556 ('symbol', '0'))
564 define)
565 hg: parse error: can't use a subscript in this context
557 hg: parse error: can't use a subscript in this context
566 [255]
558 [255]
567
559
568 $ hg debugrevspec -p analyzed 'tip#rel[0]'
560 $ hg debugrevspec -p analyzed 'tip#rel[0]'
569 * analyzed:
561 * analyzed:
570 (relsubscript
562 (relsubscript
571 ('symbol', 'tip')
563 ('symbol', 'tip')
572 ('symbol', 'rel')
564 ('symbol', 'rel')
573 ('symbol', '0')
565 ('symbol', '0'))
574 define)
575 hg: parse error: unknown identifier: rel
566 hg: parse error: unknown identifier: rel
576 [255]
567 [255]
577
568
578 $ hg debugrevspec -p analyzed '(tip#rel)[0]'
569 $ hg debugrevspec -p analyzed '(tip#rel)[0]'
579 * analyzed:
570 * analyzed:
580 (subscript
571 (subscript
581 (relation
572 (relation
582 ('symbol', 'tip')
573 ('symbol', 'tip')
583 ('symbol', 'rel')
574 ('symbol', 'rel'))
584 define)
575 ('symbol', '0'))
585 ('symbol', '0')
586 define)
587 hg: parse error: can't use a subscript in this context
576 hg: parse error: can't use a subscript in this context
588 [255]
577 [255]
589
578
590 $ hg debugrevspec -p analyzed 'tip#rel[0][1]'
579 $ hg debugrevspec -p analyzed 'tip#rel[0][1]'
591 * analyzed:
580 * analyzed:
592 (subscript
581 (subscript
593 (relsubscript
582 (relsubscript
594 ('symbol', 'tip')
583 ('symbol', 'tip')
595 ('symbol', 'rel')
584 ('symbol', 'rel')
596 ('symbol', '0')
585 ('symbol', '0'))
597 define)
586 ('symbol', '1'))
598 ('symbol', '1')
599 define)
600 hg: parse error: can't use a subscript in this context
587 hg: parse error: can't use a subscript in this context
601 [255]
588 [255]
602
589
603 $ hg debugrevspec -p analyzed 'tip#rel0#rel1[1]'
590 $ hg debugrevspec -p analyzed 'tip#rel0#rel1[1]'
604 * analyzed:
591 * analyzed:
605 (relsubscript
592 (relsubscript
606 (relation
593 (relation
607 ('symbol', 'tip')
594 ('symbol', 'tip')
608 ('symbol', 'rel0')
595 ('symbol', 'rel0'))
609 define)
610 ('symbol', 'rel1')
596 ('symbol', 'rel1')
611 ('symbol', '1')
597 ('symbol', '1'))
612 define)
613 hg: parse error: unknown identifier: rel1
598 hg: parse error: unknown identifier: rel1
614 [255]
599 [255]
615
600
616 $ hg debugrevspec -p analyzed 'tip#rel0[0]#rel1[1]'
601 $ hg debugrevspec -p analyzed 'tip#rel0[0]#rel1[1]'
617 * analyzed:
602 * analyzed:
618 (relsubscript
603 (relsubscript
619 (relsubscript
604 (relsubscript
620 ('symbol', 'tip')
605 ('symbol', 'tip')
621 ('symbol', 'rel0')
606 ('symbol', 'rel0')
622 ('symbol', '0')
607 ('symbol', '0'))
623 define)
624 ('symbol', 'rel1')
608 ('symbol', 'rel1')
625 ('symbol', '1')
609 ('symbol', '1'))
626 define)
627 hg: parse error: unknown identifier: rel1
610 hg: parse error: unknown identifier: rel1
628 [255]
611 [255]
629
612
630 parse errors of relation, subscript and relation-subscript operators:
613 parse errors of relation, subscript and relation-subscript operators:
631
614
632 $ hg debugrevspec '[0]'
615 $ hg debugrevspec '[0]'
633 hg: parse error at 0: not a prefix: [
616 hg: parse error at 0: not a prefix: [
634 [255]
617 [255]
635 $ hg debugrevspec '.#'
618 $ hg debugrevspec '.#'
636 hg: parse error at 2: not a prefix: end
619 hg: parse error at 2: not a prefix: end
637 [255]
620 [255]
638 $ hg debugrevspec '#rel'
621 $ hg debugrevspec '#rel'
639 hg: parse error at 0: not a prefix: #
622 hg: parse error at 0: not a prefix: #
640 [255]
623 [255]
641 $ hg debugrevspec '.#rel[0'
624 $ hg debugrevspec '.#rel[0'
642 hg: parse error at 7: unexpected token: end
625 hg: parse error at 7: unexpected token: end
643 [255]
626 [255]
644 $ hg debugrevspec '.]'
627 $ hg debugrevspec '.]'
645 hg: parse error at 1: invalid token
628 hg: parse error at 1: invalid token
646 [255]
629 [255]
647
630
648 $ hg debugrevspec '.#generations[a]'
631 $ hg debugrevspec '.#generations[a]'
649 hg: parse error: relation subscript must be an integer
632 hg: parse error: relation subscript must be an integer
650 [255]
633 [255]
651 $ hg debugrevspec '.#generations[1-2]'
634 $ hg debugrevspec '.#generations[1-2]'
652 hg: parse error: relation subscript must be an integer
635 hg: parse error: relation subscript must be an integer
653 [255]
636 [255]
654
637
655 parsed tree at stages:
638 parsed tree at stages:
656
639
657 $ hg debugrevspec -p all '()'
640 $ hg debugrevspec -p all '()'
658 * parsed:
641 * parsed:
659 (group
642 (group
660 None)
643 None)
661 * expanded:
644 * expanded:
662 (group
645 (group
663 None)
646 None)
664 * concatenated:
647 * concatenated:
665 (group
648 (group
666 None)
649 None)
667 * analyzed:
650 * analyzed:
668 None
651 None
669 * optimized:
652 * optimized:
670 None
653 None
671 hg: parse error: missing argument
654 hg: parse error: missing argument
672 [255]
655 [255]
673
656
674 $ hg debugrevspec --no-optimized -p all '()'
657 $ hg debugrevspec --no-optimized -p all '()'
675 * parsed:
658 * parsed:
676 (group
659 (group
677 None)
660 None)
678 * expanded:
661 * expanded:
679 (group
662 (group
680 None)
663 None)
681 * concatenated:
664 * concatenated:
682 (group
665 (group
683 None)
666 None)
684 * analyzed:
667 * analyzed:
685 None
668 None
686 hg: parse error: missing argument
669 hg: parse error: missing argument
687 [255]
670 [255]
688
671
689 $ hg debugrevspec -p parsed -p analyzed -p optimized '(0|1)-1'
672 $ hg debugrevspec -p parsed -p analyzed -p optimized '(0|1)-1'
690 * parsed:
673 * parsed:
691 (minus
674 (minus
692 (group
675 (group
693 (or
676 (or
694 (list
677 (list
695 ('symbol', '0')
678 ('symbol', '0')
696 ('symbol', '1'))))
679 ('symbol', '1'))))
697 ('symbol', '1'))
680 ('symbol', '1'))
698 * analyzed:
681 * analyzed:
699 (and
682 (and
700 (or
683 (or
701 (list
684 (list
702 ('symbol', '0')
685 ('symbol', '0')
703 ('symbol', '1'))
686 ('symbol', '1')))
704 define)
705 (not
687 (not
706 ('symbol', '1')
688 ('symbol', '1')))
707 follow)
708 define)
709 * optimized:
689 * optimized:
710 (difference
690 (difference
711 (func
691 (func
712 ('symbol', '_list')
692 ('symbol', '_list')
713 ('string', '0\x001')
693 ('string', '0\x001'))
714 define)
694 ('symbol', '1'))
715 ('symbol', '1')
716 define)
717 0
695 0
718
696
719 $ hg debugrevspec -p unknown '0'
697 $ hg debugrevspec -p unknown '0'
720 abort: invalid stage name: unknown
698 abort: invalid stage name: unknown
721 [255]
699 [255]
722
700
723 $ hg debugrevspec -p all --optimize '0'
701 $ hg debugrevspec -p all --optimize '0'
724 abort: cannot use --optimize with --show-stage
702 abort: cannot use --optimize with --show-stage
725 [255]
703 [255]
726
704
727 verify optimized tree:
705 verify optimized tree:
728
706
729 $ hg debugrevspec --verify '0|1'
707 $ hg debugrevspec --verify '0|1'
730
708
731 $ hg debugrevspec --verify -v -p analyzed -p optimized 'r3232() & 2'
709 $ hg debugrevspec --verify -v -p analyzed -p optimized 'r3232() & 2'
732 * analyzed:
710 * analyzed:
733 (and
711 (and
734 (func
712 (func
735 ('symbol', 'r3232')
713 ('symbol', 'r3232')
736 None
714 None)
737 define)
715 ('symbol', '2'))
738 ('symbol', '2')
739 define)
740 * optimized:
716 * optimized:
741 (and
717 (flipand
742 ('symbol', '2')
718 ('symbol', '2')
743 (func
719 (func
744 ('symbol', 'r3232')
720 ('symbol', 'r3232')
745 None
721 None))
746 define)
747 define)
748 * analyzed set:
722 * analyzed set:
749 <baseset [2]>
723 <baseset [2]>
750 * optimized set:
724 * optimized set:
751 <baseset [2, 2]>
725 <baseset [2, 2]>
752 --- analyzed
726 --- analyzed
753 +++ optimized
727 +++ optimized
754 2
728 2
755 +2
729 +2
756 [1]
730 [1]
757
731
758 $ hg debugrevspec --no-optimized --verify-optimized '0'
732 $ hg debugrevspec --no-optimized --verify-optimized '0'
759 abort: cannot use --verify-optimized with --no-optimized
733 abort: cannot use --verify-optimized with --no-optimized
760 [255]
734 [255]
761
735
762 Test that symbols only get parsed as functions if there's an opening
736 Test that symbols only get parsed as functions if there's an opening
763 parenthesis.
737 parenthesis.
764
738
765 $ hg book only -r 9
739 $ hg book only -r 9
766 $ log 'only(only)' # Outer "only" is a function, inner "only" is the bookmark
740 $ log 'only(only)' # Outer "only" is a function, inner "only" is the bookmark
767 8
741 8
768 9
742 9
769
743
770 ':y' behaves like '0:y', but can't be rewritten as such since the revision '0'
744 ':y' behaves like '0:y', but can't be rewritten as such since the revision '0'
771 may be hidden (issue5385)
745 may be hidden (issue5385)
772
746
773 $ try -p parsed -p analyzed ':'
747 $ try -p parsed -p analyzed ':'
774 * parsed:
748 * parsed:
775 (rangeall
749 (rangeall
776 None)
750 None)
777 * analyzed:
751 * analyzed:
778 (rangeall
752 (rangeall
779 None
753 None)
780 define)
781 * set:
754 * set:
782 <spanset+ 0:10>
755 <spanset+ 0:10>
783 0
756 0
784 1
757 1
785 2
758 2
786 3
759 3
787 4
760 4
788 5
761 5
789 6
762 6
790 7
763 7
791 8
764 8
792 9
765 9
793 $ try -p analyzed ':1'
766 $ try -p analyzed ':1'
794 * analyzed:
767 * analyzed:
795 (rangepre
768 (rangepre
796 ('symbol', '1')
769 ('symbol', '1'))
797 define)
798 * set:
770 * set:
799 <spanset+ 0:2>
771 <spanset+ 0:2>
800 0
772 0
801 1
773 1
802 $ try -p analyzed ':(1|2)'
774 $ try -p analyzed ':(1|2)'
803 * analyzed:
775 * analyzed:
804 (rangepre
776 (rangepre
805 (or
777 (or
806 (list
778 (list
807 ('symbol', '1')
779 ('symbol', '1')
808 ('symbol', '2'))
780 ('symbol', '2'))))
809 define)
810 define)
811 * set:
781 * set:
812 <spanset+ 0:3>
782 <spanset+ 0:3>
813 0
783 0
814 1
784 1
815 2
785 2
816 $ try -p analyzed ':(1&2)'
786 $ try -p analyzed ':(1&2)'
817 * analyzed:
787 * analyzed:
818 (rangepre
788 (rangepre
819 (and
789 (and
820 ('symbol', '1')
790 ('symbol', '1')
821 ('symbol', '2')
791 ('symbol', '2')))
822 define)
823 define)
824 * set:
792 * set:
825 <baseset []>
793 <baseset []>
826
794
827 infix/suffix resolution of ^ operator (issue2884):
795 infix/suffix resolution of ^ operator (issue2884):
828
796
829 x^:y means (x^):y
797 x^:y means (x^):y
830
798
831 $ try '1^:2'
799 $ try '1^:2'
832 (range
800 (range
833 (parentpost
801 (parentpost
834 ('symbol', '1'))
802 ('symbol', '1'))
835 ('symbol', '2'))
803 ('symbol', '2'))
836 * set:
804 * set:
837 <spanset+ 0:3>
805 <spanset+ 0:3>
838 0
806 0
839 1
807 1
840 2
808 2
841
809
842 $ try '1^::2'
810 $ try '1^::2'
843 (dagrange
811 (dagrange
844 (parentpost
812 (parentpost
845 ('symbol', '1'))
813 ('symbol', '1'))
846 ('symbol', '2'))
814 ('symbol', '2'))
847 * set:
815 * set:
848 <baseset+ [0, 1, 2]>
816 <baseset+ [0, 1, 2]>
849 0
817 0
850 1
818 1
851 2
819 2
852
820
853 $ try '9^:'
821 $ try '9^:'
854 (rangepost
822 (rangepost
855 (parentpost
823 (parentpost
856 ('symbol', '9')))
824 ('symbol', '9')))
857 * set:
825 * set:
858 <spanset+ 8:10>
826 <spanset+ 8:10>
859 8
827 8
860 9
828 9
861
829
862 x^:y should be resolved before omitting group operators
830 x^:y should be resolved before omitting group operators
863
831
864 $ try '1^(:2)'
832 $ try '1^(:2)'
865 (parent
833 (parent
866 ('symbol', '1')
834 ('symbol', '1')
867 (group
835 (group
868 (rangepre
836 (rangepre
869 ('symbol', '2'))))
837 ('symbol', '2'))))
870 hg: parse error: ^ expects a number 0, 1, or 2
838 hg: parse error: ^ expects a number 0, 1, or 2
871 [255]
839 [255]
872
840
873 x^:y should be resolved recursively
841 x^:y should be resolved recursively
874
842
875 $ try 'sort(1^:2)'
843 $ try 'sort(1^:2)'
876 (func
844 (func
877 ('symbol', 'sort')
845 ('symbol', 'sort')
878 (range
846 (range
879 (parentpost
847 (parentpost
880 ('symbol', '1'))
848 ('symbol', '1'))
881 ('symbol', '2')))
849 ('symbol', '2')))
882 * set:
850 * set:
883 <spanset+ 0:3>
851 <spanset+ 0:3>
884 0
852 0
885 1
853 1
886 2
854 2
887
855
888 $ try '(3^:4)^:2'
856 $ try '(3^:4)^:2'
889 (range
857 (range
890 (parentpost
858 (parentpost
891 (group
859 (group
892 (range
860 (range
893 (parentpost
861 (parentpost
894 ('symbol', '3'))
862 ('symbol', '3'))
895 ('symbol', '4'))))
863 ('symbol', '4'))))
896 ('symbol', '2'))
864 ('symbol', '2'))
897 * set:
865 * set:
898 <spanset+ 0:3>
866 <spanset+ 0:3>
899 0
867 0
900 1
868 1
901 2
869 2
902
870
903 $ try '(3^::4)^::2'
871 $ try '(3^::4)^::2'
904 (dagrange
872 (dagrange
905 (parentpost
873 (parentpost
906 (group
874 (group
907 (dagrange
875 (dagrange
908 (parentpost
876 (parentpost
909 ('symbol', '3'))
877 ('symbol', '3'))
910 ('symbol', '4'))))
878 ('symbol', '4'))))
911 ('symbol', '2'))
879 ('symbol', '2'))
912 * set:
880 * set:
913 <baseset+ [0, 1, 2]>
881 <baseset+ [0, 1, 2]>
914 0
882 0
915 1
883 1
916 2
884 2
917
885
918 $ try '(9^:)^:'
886 $ try '(9^:)^:'
919 (rangepost
887 (rangepost
920 (parentpost
888 (parentpost
921 (group
889 (group
922 (rangepost
890 (rangepost
923 (parentpost
891 (parentpost
924 ('symbol', '9'))))))
892 ('symbol', '9'))))))
925 * set:
893 * set:
926 <spanset+ 4:10>
894 <spanset+ 4:10>
927 4
895 4
928 5
896 5
929 6
897 6
930 7
898 7
931 8
899 8
932 9
900 9
933
901
934 x^ in alias should also be resolved
902 x^ in alias should also be resolved
935
903
936 $ try 'A' --config 'revsetalias.A=1^:2'
904 $ try 'A' --config 'revsetalias.A=1^:2'
937 ('symbol', 'A')
905 ('symbol', 'A')
938 * expanded:
906 * expanded:
939 (range
907 (range
940 (parentpost
908 (parentpost
941 ('symbol', '1'))
909 ('symbol', '1'))
942 ('symbol', '2'))
910 ('symbol', '2'))
943 * set:
911 * set:
944 <spanset+ 0:3>
912 <spanset+ 0:3>
945 0
913 0
946 1
914 1
947 2
915 2
948
916
949 $ try 'A:2' --config 'revsetalias.A=1^'
917 $ try 'A:2' --config 'revsetalias.A=1^'
950 (range
918 (range
951 ('symbol', 'A')
919 ('symbol', 'A')
952 ('symbol', '2'))
920 ('symbol', '2'))
953 * expanded:
921 * expanded:
954 (range
922 (range
955 (parentpost
923 (parentpost
956 ('symbol', '1'))
924 ('symbol', '1'))
957 ('symbol', '2'))
925 ('symbol', '2'))
958 * set:
926 * set:
959 <spanset+ 0:3>
927 <spanset+ 0:3>
960 0
928 0
961 1
929 1
962 2
930 2
963
931
964 but not beyond the boundary of alias expansion, because the resolution should
932 but not beyond the boundary of alias expansion, because the resolution should
965 be made at the parsing stage
933 be made at the parsing stage
966
934
967 $ try '1^A' --config 'revsetalias.A=:2'
935 $ try '1^A' --config 'revsetalias.A=:2'
968 (parent
936 (parent
969 ('symbol', '1')
937 ('symbol', '1')
970 ('symbol', 'A'))
938 ('symbol', 'A'))
971 * expanded:
939 * expanded:
972 (parent
940 (parent
973 ('symbol', '1')
941 ('symbol', '1')
974 (rangepre
942 (rangepre
975 ('symbol', '2')))
943 ('symbol', '2')))
976 hg: parse error: ^ expects a number 0, 1, or 2
944 hg: parse error: ^ expects a number 0, 1, or 2
977 [255]
945 [255]
978
946
979 ancestor can accept 0 or more arguments
947 ancestor can accept 0 or more arguments
980
948
981 $ log 'ancestor()'
949 $ log 'ancestor()'
982 $ log 'ancestor(1)'
950 $ log 'ancestor(1)'
983 1
951 1
984 $ log 'ancestor(4,5)'
952 $ log 'ancestor(4,5)'
985 1
953 1
986 $ log 'ancestor(4,5) and 4'
954 $ log 'ancestor(4,5) and 4'
987 $ log 'ancestor(0,0,1,3)'
955 $ log 'ancestor(0,0,1,3)'
988 0
956 0
989 $ log 'ancestor(3,1,5,3,5,1)'
957 $ log 'ancestor(3,1,5,3,5,1)'
990 1
958 1
991 $ log 'ancestor(0,1,3,5)'
959 $ log 'ancestor(0,1,3,5)'
992 0
960 0
993 $ log 'ancestor(1,2,3,4,5)'
961 $ log 'ancestor(1,2,3,4,5)'
994 1
962 1
995
963
996 test ancestors
964 test ancestors
997
965
998 $ hg log -G -T '{rev}\n' --config experimental.graphshorten=True
966 $ hg log -G -T '{rev}\n' --config experimental.graphshorten=True
999 @ 9
967 @ 9
1000 o 8
968 o 8
1001 | o 7
969 | o 7
1002 | o 6
970 | o 6
1003 |/|
971 |/|
1004 | o 5
972 | o 5
1005 o | 4
973 o | 4
1006 | o 3
974 | o 3
1007 o | 2
975 o | 2
1008 |/
976 |/
1009 o 1
977 o 1
1010 o 0
978 o 0
1011
979
1012 $ log 'ancestors(5)'
980 $ log 'ancestors(5)'
1013 0
981 0
1014 1
982 1
1015 3
983 3
1016 5
984 5
1017 $ log 'ancestor(ancestors(5))'
985 $ log 'ancestor(ancestors(5))'
1018 0
986 0
1019 $ log '::r3232()'
987 $ log '::r3232()'
1020 0
988 0
1021 1
989 1
1022 2
990 2
1023 3
991 3
1024
992
1025 test ancestors with depth limit
993 test ancestors with depth limit
1026
994
1027 (depth=0 selects the node itself)
995 (depth=0 selects the node itself)
1028
996
1029 $ log 'reverse(ancestors(9, depth=0))'
997 $ log 'reverse(ancestors(9, depth=0))'
1030 9
998 9
1031
999
1032 (interleaved: '4' would be missing if heap queue were higher depth first)
1000 (interleaved: '4' would be missing if heap queue were higher depth first)
1033
1001
1034 $ log 'reverse(ancestors(8:9, depth=1))'
1002 $ log 'reverse(ancestors(8:9, depth=1))'
1035 9
1003 9
1036 8
1004 8
1037 4
1005 4
1038
1006
1039 (interleaved: '2' would be missing if heap queue were higher depth first)
1007 (interleaved: '2' would be missing if heap queue were higher depth first)
1040
1008
1041 $ log 'reverse(ancestors(7+8, depth=2))'
1009 $ log 'reverse(ancestors(7+8, depth=2))'
1042 8
1010 8
1043 7
1011 7
1044 6
1012 6
1045 5
1013 5
1046 4
1014 4
1047 2
1015 2
1048
1016
1049 (walk example above by separate queries)
1017 (walk example above by separate queries)
1050
1018
1051 $ log 'reverse(ancestors(8, depth=2)) + reverse(ancestors(7, depth=2))'
1019 $ log 'reverse(ancestors(8, depth=2)) + reverse(ancestors(7, depth=2))'
1052 8
1020 8
1053 4
1021 4
1054 2
1022 2
1055 7
1023 7
1056 6
1024 6
1057 5
1025 5
1058
1026
1059 (walk 2nd and 3rd ancestors)
1027 (walk 2nd and 3rd ancestors)
1060
1028
1061 $ log 'reverse(ancestors(7, depth=3, startdepth=2))'
1029 $ log 'reverse(ancestors(7, depth=3, startdepth=2))'
1062 5
1030 5
1063 4
1031 4
1064 3
1032 3
1065 2
1033 2
1066
1034
1067 (interleaved: '4' would be missing if higher-depth ancestors weren't scanned)
1035 (interleaved: '4' would be missing if higher-depth ancestors weren't scanned)
1068
1036
1069 $ log 'reverse(ancestors(7+8, depth=2, startdepth=2))'
1037 $ log 'reverse(ancestors(7+8, depth=2, startdepth=2))'
1070 5
1038 5
1071 4
1039 4
1072 2
1040 2
1073
1041
1074 (note that 'ancestors(x, depth=y, startdepth=z)' does not identical to
1042 (note that 'ancestors(x, depth=y, startdepth=z)' does not identical to
1075 'ancestors(x, depth=y) - ancestors(x, depth=z-1)' because a node may have
1043 'ancestors(x, depth=y) - ancestors(x, depth=z-1)' because a node may have
1076 multiple depths)
1044 multiple depths)
1077
1045
1078 $ log 'reverse(ancestors(7+8, depth=2) - ancestors(7+8, depth=1))'
1046 $ log 'reverse(ancestors(7+8, depth=2) - ancestors(7+8, depth=1))'
1079 5
1047 5
1080 2
1048 2
1081
1049
1082 test bad arguments passed to ancestors()
1050 test bad arguments passed to ancestors()
1083
1051
1084 $ log 'ancestors(., depth=-1)'
1052 $ log 'ancestors(., depth=-1)'
1085 hg: parse error: negative depth
1053 hg: parse error: negative depth
1086 [255]
1054 [255]
1087 $ log 'ancestors(., depth=foo)'
1055 $ log 'ancestors(., depth=foo)'
1088 hg: parse error: ancestors expects an integer depth
1056 hg: parse error: ancestors expects an integer depth
1089 [255]
1057 [255]
1090
1058
1091 test descendants
1059 test descendants
1092
1060
1093 $ hg log -G -T '{rev}\n' --config experimental.graphshorten=True
1061 $ hg log -G -T '{rev}\n' --config experimental.graphshorten=True
1094 @ 9
1062 @ 9
1095 o 8
1063 o 8
1096 | o 7
1064 | o 7
1097 | o 6
1065 | o 6
1098 |/|
1066 |/|
1099 | o 5
1067 | o 5
1100 o | 4
1068 o | 4
1101 | o 3
1069 | o 3
1102 o | 2
1070 o | 2
1103 |/
1071 |/
1104 o 1
1072 o 1
1105 o 0
1073 o 0
1106
1074
1107 (null is ultimate root and has optimized path)
1075 (null is ultimate root and has optimized path)
1108
1076
1109 $ log 'null:4 & descendants(null)'
1077 $ log 'null:4 & descendants(null)'
1110 -1
1078 -1
1111 0
1079 0
1112 1
1080 1
1113 2
1081 2
1114 3
1082 3
1115 4
1083 4
1116
1084
1117 (including merge)
1085 (including merge)
1118
1086
1119 $ log ':8 & descendants(2)'
1087 $ log ':8 & descendants(2)'
1120 2
1088 2
1121 4
1089 4
1122 6
1090 6
1123 7
1091 7
1124 8
1092 8
1125
1093
1126 (multiple roots)
1094 (multiple roots)
1127
1095
1128 $ log ':8 & descendants(2+5)'
1096 $ log ':8 & descendants(2+5)'
1129 2
1097 2
1130 4
1098 4
1131 5
1099 5
1132 6
1100 6
1133 7
1101 7
1134 8
1102 8
1135
1103
1136 test descendants with depth limit
1104 test descendants with depth limit
1137
1105
1138 (depth=0 selects the node itself)
1106 (depth=0 selects the node itself)
1139
1107
1140 $ log 'descendants(0, depth=0)'
1108 $ log 'descendants(0, depth=0)'
1141 0
1109 0
1142 $ log 'null: & descendants(null, depth=0)'
1110 $ log 'null: & descendants(null, depth=0)'
1143 -1
1111 -1
1144
1112
1145 (p2 = null should be ignored)
1113 (p2 = null should be ignored)
1146
1114
1147 $ log 'null: & descendants(null, depth=2)'
1115 $ log 'null: & descendants(null, depth=2)'
1148 -1
1116 -1
1149 0
1117 0
1150 1
1118 1
1151
1119
1152 (multiple paths: depth(6) = (2, 3))
1120 (multiple paths: depth(6) = (2, 3))
1153
1121
1154 $ log 'descendants(1+3, depth=2)'
1122 $ log 'descendants(1+3, depth=2)'
1155 1
1123 1
1156 2
1124 2
1157 3
1125 3
1158 4
1126 4
1159 5
1127 5
1160 6
1128 6
1161
1129
1162 (multiple paths: depth(5) = (1, 2), depth(6) = (2, 3))
1130 (multiple paths: depth(5) = (1, 2), depth(6) = (2, 3))
1163
1131
1164 $ log 'descendants(3+1, depth=2, startdepth=2)'
1132 $ log 'descendants(3+1, depth=2, startdepth=2)'
1165 4
1133 4
1166 5
1134 5
1167 6
1135 6
1168
1136
1169 (multiple depths: depth(6) = (0, 2, 4), search for depth=2)
1137 (multiple depths: depth(6) = (0, 2, 4), search for depth=2)
1170
1138
1171 $ log 'descendants(0+3+6, depth=3, startdepth=1)'
1139 $ log 'descendants(0+3+6, depth=3, startdepth=1)'
1172 1
1140 1
1173 2
1141 2
1174 3
1142 3
1175 4
1143 4
1176 5
1144 5
1177 6
1145 6
1178 7
1146 7
1179
1147
1180 (multiple depths: depth(6) = (0, 4), no match)
1148 (multiple depths: depth(6) = (0, 4), no match)
1181
1149
1182 $ log 'descendants(0+6, depth=3, startdepth=1)'
1150 $ log 'descendants(0+6, depth=3, startdepth=1)'
1183 1
1151 1
1184 2
1152 2
1185 3
1153 3
1186 4
1154 4
1187 5
1155 5
1188 7
1156 7
1189
1157
1190 test ancestors/descendants relation subscript:
1158 test ancestors/descendants relation subscript:
1191
1159
1192 $ log 'tip#generations[0]'
1160 $ log 'tip#generations[0]'
1193 9
1161 9
1194 $ log '.#generations[-1]'
1162 $ log '.#generations[-1]'
1195 8
1163 8
1196 $ log '.#g[(-1)]'
1164 $ log '.#g[(-1)]'
1197 8
1165 8
1198
1166
1199 $ hg debugrevspec -p parsed 'roots(:)#g[2]'
1167 $ hg debugrevspec -p parsed 'roots(:)#g[2]'
1200 * parsed:
1168 * parsed:
1201 (relsubscript
1169 (relsubscript
1202 (func
1170 (func
1203 ('symbol', 'roots')
1171 ('symbol', 'roots')
1204 (rangeall
1172 (rangeall
1205 None))
1173 None))
1206 ('symbol', 'g')
1174 ('symbol', 'g')
1207 ('symbol', '2'))
1175 ('symbol', '2'))
1208 2
1176 2
1209 3
1177 3
1210
1178
1211 test author
1179 test author
1212
1180
1213 $ log 'author(bob)'
1181 $ log 'author(bob)'
1214 2
1182 2
1215 $ log 'author("re:bob|test")'
1183 $ log 'author("re:bob|test")'
1216 0
1184 0
1217 1
1185 1
1218 2
1186 2
1219 3
1187 3
1220 4
1188 4
1221 5
1189 5
1222 6
1190 6
1223 7
1191 7
1224 8
1192 8
1225 9
1193 9
1226 $ log 'author(r"re:\S")'
1194 $ log 'author(r"re:\S")'
1227 0
1195 0
1228 1
1196 1
1229 2
1197 2
1230 3
1198 3
1231 4
1199 4
1232 5
1200 5
1233 6
1201 6
1234 7
1202 7
1235 8
1203 8
1236 9
1204 9
1237 $ log 'branch(Γ©)'
1205 $ log 'branch(Γ©)'
1238 8
1206 8
1239 9
1207 9
1240 $ log 'branch(a)'
1208 $ log 'branch(a)'
1241 0
1209 0
1242 $ hg log -r 'branch("re:a")' --template '{rev} {branch}\n'
1210 $ hg log -r 'branch("re:a")' --template '{rev} {branch}\n'
1243 0 a
1211 0 a
1244 2 a-b-c-
1212 2 a-b-c-
1245 3 +a+b+c+
1213 3 +a+b+c+
1246 4 -a-b-c-
1214 4 -a-b-c-
1247 5 !a/b/c/
1215 5 !a/b/c/
1248 6 _a_b_c_
1216 6 _a_b_c_
1249 7 .a.b.c.
1217 7 .a.b.c.
1250 $ log 'children(ancestor(4,5))'
1218 $ log 'children(ancestor(4,5))'
1251 2
1219 2
1252 3
1220 3
1253
1221
1254 $ log 'children(4)'
1222 $ log 'children(4)'
1255 6
1223 6
1256 8
1224 8
1257 $ log 'children(null)'
1225 $ log 'children(null)'
1258 0
1226 0
1259
1227
1260 $ log 'closed()'
1228 $ log 'closed()'
1261 $ log 'contains(a)'
1229 $ log 'contains(a)'
1262 0
1230 0
1263 1
1231 1
1264 3
1232 3
1265 5
1233 5
1266 $ log 'contains("../repo/a")'
1234 $ log 'contains("../repo/a")'
1267 0
1235 0
1268 1
1236 1
1269 3
1237 3
1270 5
1238 5
1271 $ log 'desc(B)'
1239 $ log 'desc(B)'
1272 5
1240 5
1273 $ hg log -r 'desc(r"re:S?u")' --template "{rev} {desc|firstline}\n"
1241 $ hg log -r 'desc(r"re:S?u")' --template "{rev} {desc|firstline}\n"
1274 5 5 bug
1242 5 5 bug
1275 6 6 issue619
1243 6 6 issue619
1276 $ log 'descendants(2 or 3)'
1244 $ log 'descendants(2 or 3)'
1277 2
1245 2
1278 3
1246 3
1279 4
1247 4
1280 5
1248 5
1281 6
1249 6
1282 7
1250 7
1283 8
1251 8
1284 9
1252 9
1285 $ log 'file("b*")'
1253 $ log 'file("b*")'
1286 1
1254 1
1287 4
1255 4
1288 $ log 'filelog("b")'
1256 $ log 'filelog("b")'
1289 1
1257 1
1290 4
1258 4
1291 $ log 'filelog("../repo/b")'
1259 $ log 'filelog("../repo/b")'
1292 1
1260 1
1293 4
1261 4
1294 $ log 'follow()'
1262 $ log 'follow()'
1295 0
1263 0
1296 1
1264 1
1297 2
1265 2
1298 4
1266 4
1299 8
1267 8
1300 9
1268 9
1301 $ log 'grep("issue\d+")'
1269 $ log 'grep("issue\d+")'
1302 6
1270 6
1303 $ try 'grep("(")' # invalid regular expression
1271 $ try 'grep("(")' # invalid regular expression
1304 (func
1272 (func
1305 ('symbol', 'grep')
1273 ('symbol', 'grep')
1306 ('string', '('))
1274 ('string', '('))
1307 hg: parse error: invalid match pattern: unbalanced parenthesis
1275 hg: parse error: invalid match pattern: unbalanced parenthesis
1308 [255]
1276 [255]
1309 $ try 'grep("\bissue\d+")'
1277 $ try 'grep("\bissue\d+")'
1310 (func
1278 (func
1311 ('symbol', 'grep')
1279 ('symbol', 'grep')
1312 ('string', '\x08issue\\d+'))
1280 ('string', '\x08issue\\d+'))
1313 * set:
1281 * set:
1314 <filteredset
1282 <filteredset
1315 <fullreposet+ 0:10>,
1283 <fullreposet+ 0:10>,
1316 <grep '\x08issue\\d+'>>
1284 <grep '\x08issue\\d+'>>
1317 $ try 'grep(r"\bissue\d+")'
1285 $ try 'grep(r"\bissue\d+")'
1318 (func
1286 (func
1319 ('symbol', 'grep')
1287 ('symbol', 'grep')
1320 ('string', '\\bissue\\d+'))
1288 ('string', '\\bissue\\d+'))
1321 * set:
1289 * set:
1322 <filteredset
1290 <filteredset
1323 <fullreposet+ 0:10>,
1291 <fullreposet+ 0:10>,
1324 <grep '\\bissue\\d+'>>
1292 <grep '\\bissue\\d+'>>
1325 6
1293 6
1326 $ try 'grep(r"\")'
1294 $ try 'grep(r"\")'
1327 hg: parse error at 7: unterminated string
1295 hg: parse error at 7: unterminated string
1328 [255]
1296 [255]
1329 $ log 'head()'
1297 $ log 'head()'
1330 0
1298 0
1331 1
1299 1
1332 2
1300 2
1333 3
1301 3
1334 4
1302 4
1335 5
1303 5
1336 6
1304 6
1337 7
1305 7
1338 9
1306 9
1339 $ log 'heads(6::)'
1307 $ log 'heads(6::)'
1340 7
1308 7
1341 $ log 'keyword(issue)'
1309 $ log 'keyword(issue)'
1342 6
1310 6
1343 $ log 'keyword("test a")'
1311 $ log 'keyword("test a")'
1344
1312
1345 Test first (=limit) and last
1313 Test first (=limit) and last
1346
1314
1347 $ log 'limit(head(), 1)'
1315 $ log 'limit(head(), 1)'
1348 0
1316 0
1349 $ log 'limit(author("re:bob|test"), 3, 5)'
1317 $ log 'limit(author("re:bob|test"), 3, 5)'
1350 5
1318 5
1351 6
1319 6
1352 7
1320 7
1353 $ log 'limit(author("re:bob|test"), offset=6)'
1321 $ log 'limit(author("re:bob|test"), offset=6)'
1354 6
1322 6
1355 $ log 'limit(author("re:bob|test"), offset=10)'
1323 $ log 'limit(author("re:bob|test"), offset=10)'
1356 $ log 'limit(all(), 1, -1)'
1324 $ log 'limit(all(), 1, -1)'
1357 hg: parse error: negative offset
1325 hg: parse error: negative offset
1358 [255]
1326 [255]
1359 $ log 'limit(all(), -1)'
1327 $ log 'limit(all(), -1)'
1360 hg: parse error: negative number to select
1328 hg: parse error: negative number to select
1361 [255]
1329 [255]
1362 $ log 'limit(all(), 0)'
1330 $ log 'limit(all(), 0)'
1363
1331
1364 $ log 'last(all(), -1)'
1332 $ log 'last(all(), -1)'
1365 hg: parse error: negative number to select
1333 hg: parse error: negative number to select
1366 [255]
1334 [255]
1367 $ log 'last(all(), 0)'
1335 $ log 'last(all(), 0)'
1368 $ log 'last(all(), 1)'
1336 $ log 'last(all(), 1)'
1369 9
1337 9
1370 $ log 'last(all(), 2)'
1338 $ log 'last(all(), 2)'
1371 8
1339 8
1372 9
1340 9
1373
1341
1374 Test smartset.slice() by first/last()
1342 Test smartset.slice() by first/last()
1375
1343
1376 (using unoptimized set, filteredset as example)
1344 (using unoptimized set, filteredset as example)
1377
1345
1378 $ hg debugrevspec --no-show-revs -s '0:7 & branch("re:")'
1346 $ hg debugrevspec --no-show-revs -s '0:7 & branch("re:")'
1379 * set:
1347 * set:
1380 <filteredset
1348 <filteredset
1381 <spanset+ 0:8>,
1349 <spanset+ 0:8>,
1382 <branch 're:'>>
1350 <branch 're:'>>
1383 $ log 'limit(0:7 & branch("re:"), 3, 4)'
1351 $ log 'limit(0:7 & branch("re:"), 3, 4)'
1384 4
1352 4
1385 5
1353 5
1386 6
1354 6
1387 $ log 'limit(7:0 & branch("re:"), 3, 4)'
1355 $ log 'limit(7:0 & branch("re:"), 3, 4)'
1388 3
1356 3
1389 2
1357 2
1390 1
1358 1
1391 $ log 'last(0:7 & branch("re:"), 2)'
1359 $ log 'last(0:7 & branch("re:"), 2)'
1392 6
1360 6
1393 7
1361 7
1394
1362
1395 (using baseset)
1363 (using baseset)
1396
1364
1397 $ hg debugrevspec --no-show-revs -s 0+1+2+3+4+5+6+7
1365 $ hg debugrevspec --no-show-revs -s 0+1+2+3+4+5+6+7
1398 * set:
1366 * set:
1399 <baseset [0, 1, 2, 3, 4, 5, 6, 7]>
1367 <baseset [0, 1, 2, 3, 4, 5, 6, 7]>
1400 $ hg debugrevspec --no-show-revs -s 0::7
1368 $ hg debugrevspec --no-show-revs -s 0::7
1401 * set:
1369 * set:
1402 <baseset+ [0, 1, 2, 3, 4, 5, 6, 7]>
1370 <baseset+ [0, 1, 2, 3, 4, 5, 6, 7]>
1403 $ log 'limit(0+1+2+3+4+5+6+7, 3, 4)'
1371 $ log 'limit(0+1+2+3+4+5+6+7, 3, 4)'
1404 4
1372 4
1405 5
1373 5
1406 6
1374 6
1407 $ log 'limit(sort(0::7, rev), 3, 4)'
1375 $ log 'limit(sort(0::7, rev), 3, 4)'
1408 4
1376 4
1409 5
1377 5
1410 6
1378 6
1411 $ log 'limit(sort(0::7, -rev), 3, 4)'
1379 $ log 'limit(sort(0::7, -rev), 3, 4)'
1412 3
1380 3
1413 2
1381 2
1414 1
1382 1
1415 $ log 'last(sort(0::7, rev), 2)'
1383 $ log 'last(sort(0::7, rev), 2)'
1416 6
1384 6
1417 7
1385 7
1418 $ hg debugrevspec -s 'limit(sort(0::7, rev), 3, 6)'
1386 $ hg debugrevspec -s 'limit(sort(0::7, rev), 3, 6)'
1419 * set:
1387 * set:
1420 <baseset+ [6, 7]>
1388 <baseset+ [6, 7]>
1421 6
1389 6
1422 7
1390 7
1423 $ hg debugrevspec -s 'limit(sort(0::7, rev), 3, 9)'
1391 $ hg debugrevspec -s 'limit(sort(0::7, rev), 3, 9)'
1424 * set:
1392 * set:
1425 <baseset+ []>
1393 <baseset+ []>
1426 $ hg debugrevspec -s 'limit(sort(0::7, -rev), 3, 6)'
1394 $ hg debugrevspec -s 'limit(sort(0::7, -rev), 3, 6)'
1427 * set:
1395 * set:
1428 <baseset- [0, 1]>
1396 <baseset- [0, 1]>
1429 1
1397 1
1430 0
1398 0
1431 $ hg debugrevspec -s 'limit(sort(0::7, -rev), 3, 9)'
1399 $ hg debugrevspec -s 'limit(sort(0::7, -rev), 3, 9)'
1432 * set:
1400 * set:
1433 <baseset- []>
1401 <baseset- []>
1434 $ hg debugrevspec -s 'limit(0::7, 0)'
1402 $ hg debugrevspec -s 'limit(0::7, 0)'
1435 * set:
1403 * set:
1436 <baseset+ []>
1404 <baseset+ []>
1437
1405
1438 (using spanset)
1406 (using spanset)
1439
1407
1440 $ hg debugrevspec --no-show-revs -s 0:7
1408 $ hg debugrevspec --no-show-revs -s 0:7
1441 * set:
1409 * set:
1442 <spanset+ 0:8>
1410 <spanset+ 0:8>
1443 $ log 'limit(0:7, 3, 4)'
1411 $ log 'limit(0:7, 3, 4)'
1444 4
1412 4
1445 5
1413 5
1446 6
1414 6
1447 $ log 'limit(7:0, 3, 4)'
1415 $ log 'limit(7:0, 3, 4)'
1448 3
1416 3
1449 2
1417 2
1450 1
1418 1
1451 $ log 'limit(0:7, 3, 6)'
1419 $ log 'limit(0:7, 3, 6)'
1452 6
1420 6
1453 7
1421 7
1454 $ log 'limit(7:0, 3, 6)'
1422 $ log 'limit(7:0, 3, 6)'
1455 1
1423 1
1456 0
1424 0
1457 $ log 'last(0:7, 2)'
1425 $ log 'last(0:7, 2)'
1458 6
1426 6
1459 7
1427 7
1460 $ hg debugrevspec -s 'limit(0:7, 3, 6)'
1428 $ hg debugrevspec -s 'limit(0:7, 3, 6)'
1461 * set:
1429 * set:
1462 <spanset+ 6:8>
1430 <spanset+ 6:8>
1463 6
1431 6
1464 7
1432 7
1465 $ hg debugrevspec -s 'limit(0:7, 3, 9)'
1433 $ hg debugrevspec -s 'limit(0:7, 3, 9)'
1466 * set:
1434 * set:
1467 <spanset+ 8:8>
1435 <spanset+ 8:8>
1468 $ hg debugrevspec -s 'limit(7:0, 3, 6)'
1436 $ hg debugrevspec -s 'limit(7:0, 3, 6)'
1469 * set:
1437 * set:
1470 <spanset- 0:2>
1438 <spanset- 0:2>
1471 1
1439 1
1472 0
1440 0
1473 $ hg debugrevspec -s 'limit(7:0, 3, 9)'
1441 $ hg debugrevspec -s 'limit(7:0, 3, 9)'
1474 * set:
1442 * set:
1475 <spanset- 0:0>
1443 <spanset- 0:0>
1476 $ hg debugrevspec -s 'limit(0:7, 0)'
1444 $ hg debugrevspec -s 'limit(0:7, 0)'
1477 * set:
1445 * set:
1478 <spanset+ 0:0>
1446 <spanset+ 0:0>
1479
1447
1480 Test order of first/last revisions
1448 Test order of first/last revisions
1481
1449
1482 $ hg debugrevspec -s 'first(4:0, 3) & 3:'
1450 $ hg debugrevspec -s 'first(4:0, 3) & 3:'
1483 * set:
1451 * set:
1484 <filteredset
1452 <filteredset
1485 <spanset- 2:5>,
1453 <spanset- 2:5>,
1486 <spanset+ 3:10>>
1454 <spanset+ 3:10>>
1487 4
1455 4
1488 3
1456 3
1489
1457
1490 $ hg debugrevspec -s '3: & first(4:0, 3)'
1458 $ hg debugrevspec -s '3: & first(4:0, 3)'
1491 * set:
1459 * set:
1492 <filteredset
1460 <filteredset
1493 <spanset+ 3:10>,
1461 <spanset+ 3:10>,
1494 <spanset- 2:5>>
1462 <spanset- 2:5>>
1495 3
1463 3
1496 4
1464 4
1497
1465
1498 $ hg debugrevspec -s 'last(4:0, 3) & :1'
1466 $ hg debugrevspec -s 'last(4:0, 3) & :1'
1499 * set:
1467 * set:
1500 <filteredset
1468 <filteredset
1501 <spanset- 0:3>,
1469 <spanset- 0:3>,
1502 <spanset+ 0:2>>
1470 <spanset+ 0:2>>
1503 1
1471 1
1504 0
1472 0
1505
1473
1506 $ hg debugrevspec -s ':1 & last(4:0, 3)'
1474 $ hg debugrevspec -s ':1 & last(4:0, 3)'
1507 * set:
1475 * set:
1508 <filteredset
1476 <filteredset
1509 <spanset+ 0:2>,
1477 <spanset+ 0:2>,
1510 <spanset+ 0:3>>
1478 <spanset+ 0:3>>
1511 0
1479 0
1512 1
1480 1
1513
1481
1514 Test scmutil.revsingle() should return the last revision
1482 Test scmutil.revsingle() should return the last revision
1515
1483
1516 $ hg debugrevspec -s 'last(0::)'
1484 $ hg debugrevspec -s 'last(0::)'
1517 * set:
1485 * set:
1518 <baseset slice=0:1
1486 <baseset slice=0:1
1519 <generatorset->>
1487 <generatorset->>
1520 9
1488 9
1521 $ hg identify -r '0::' --num
1489 $ hg identify -r '0::' --num
1522 9
1490 9
1523
1491
1524 Test matching
1492 Test matching
1525
1493
1526 $ log 'matching(6)'
1494 $ log 'matching(6)'
1527 6
1495 6
1528 $ log 'matching(6:7, "phase parents user date branch summary files description substate")'
1496 $ log 'matching(6:7, "phase parents user date branch summary files description substate")'
1529 6
1497 6
1530 7
1498 7
1531
1499
1532 Testing min and max
1500 Testing min and max
1533
1501
1534 max: simple
1502 max: simple
1535
1503
1536 $ log 'max(contains(a))'
1504 $ log 'max(contains(a))'
1537 5
1505 5
1538
1506
1539 max: simple on unordered set)
1507 max: simple on unordered set)
1540
1508
1541 $ log 'max((4+0+2+5+7) and contains(a))'
1509 $ log 'max((4+0+2+5+7) and contains(a))'
1542 5
1510 5
1543
1511
1544 max: no result
1512 max: no result
1545
1513
1546 $ log 'max(contains(stringthatdoesnotappearanywhere))'
1514 $ log 'max(contains(stringthatdoesnotappearanywhere))'
1547
1515
1548 max: no result on unordered set
1516 max: no result on unordered set
1549
1517
1550 $ log 'max((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
1518 $ log 'max((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
1551
1519
1552 min: simple
1520 min: simple
1553
1521
1554 $ log 'min(contains(a))'
1522 $ log 'min(contains(a))'
1555 0
1523 0
1556
1524
1557 min: simple on unordered set
1525 min: simple on unordered set
1558
1526
1559 $ log 'min((4+0+2+5+7) and contains(a))'
1527 $ log 'min((4+0+2+5+7) and contains(a))'
1560 0
1528 0
1561
1529
1562 min: empty
1530 min: empty
1563
1531
1564 $ log 'min(contains(stringthatdoesnotappearanywhere))'
1532 $ log 'min(contains(stringthatdoesnotappearanywhere))'
1565
1533
1566 min: empty on unordered set
1534 min: empty on unordered set
1567
1535
1568 $ log 'min((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
1536 $ log 'min((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
1569
1537
1570
1538
1571 $ log 'merge()'
1539 $ log 'merge()'
1572 6
1540 6
1573 $ log 'branchpoint()'
1541 $ log 'branchpoint()'
1574 1
1542 1
1575 4
1543 4
1576 $ log 'modifies(b)'
1544 $ log 'modifies(b)'
1577 4
1545 4
1578 $ log 'modifies("path:b")'
1546 $ log 'modifies("path:b")'
1579 4
1547 4
1580 $ log 'modifies("*")'
1548 $ log 'modifies("*")'
1581 4
1549 4
1582 6
1550 6
1583 $ log 'modifies("set:modified()")'
1551 $ log 'modifies("set:modified()")'
1584 4
1552 4
1585 $ log 'id(5)'
1553 $ log 'id(5)'
1586 2
1554 2
1587 $ log 'only(9)'
1555 $ log 'only(9)'
1588 8
1556 8
1589 9
1557 9
1590 $ log 'only(8)'
1558 $ log 'only(8)'
1591 8
1559 8
1592 $ log 'only(9, 5)'
1560 $ log 'only(9, 5)'
1593 2
1561 2
1594 4
1562 4
1595 8
1563 8
1596 9
1564 9
1597 $ log 'only(7 + 9, 5 + 2)'
1565 $ log 'only(7 + 9, 5 + 2)'
1598 4
1566 4
1599 6
1567 6
1600 7
1568 7
1601 8
1569 8
1602 9
1570 9
1603
1571
1604 Test empty set input
1572 Test empty set input
1605 $ log 'only(p2())'
1573 $ log 'only(p2())'
1606 $ log 'only(p1(), p2())'
1574 $ log 'only(p1(), p2())'
1607 0
1575 0
1608 1
1576 1
1609 2
1577 2
1610 4
1578 4
1611 8
1579 8
1612 9
1580 9
1613
1581
1614 Test '%' operator
1582 Test '%' operator
1615
1583
1616 $ log '9%'
1584 $ log '9%'
1617 8
1585 8
1618 9
1586 9
1619 $ log '9%5'
1587 $ log '9%5'
1620 2
1588 2
1621 4
1589 4
1622 8
1590 8
1623 9
1591 9
1624 $ log '(7 + 9)%(5 + 2)'
1592 $ log '(7 + 9)%(5 + 2)'
1625 4
1593 4
1626 6
1594 6
1627 7
1595 7
1628 8
1596 8
1629 9
1597 9
1630
1598
1631 Test operand of '%' is optimized recursively (issue4670)
1599 Test operand of '%' is optimized recursively (issue4670)
1632
1600
1633 $ try --optimize '8:9-8%'
1601 $ try --optimize '8:9-8%'
1634 (onlypost
1602 (onlypost
1635 (minus
1603 (minus
1636 (range
1604 (range
1637 ('symbol', '8')
1605 ('symbol', '8')
1638 ('symbol', '9'))
1606 ('symbol', '9'))
1639 ('symbol', '8')))
1607 ('symbol', '8')))
1640 * optimized:
1608 * optimized:
1641 (func
1609 (func
1642 ('symbol', 'only')
1610 ('symbol', 'only')
1643 (difference
1611 (difference
1644 (range
1612 (range
1645 ('symbol', '8')
1613 ('symbol', '8')
1646 ('symbol', '9')
1614 ('symbol', '9'))
1647 define)
1615 ('symbol', '8')))
1648 ('symbol', '8')
1649 define)
1650 define)
1651 * set:
1616 * set:
1652 <baseset+ [8, 9]>
1617 <baseset+ [8, 9]>
1653 8
1618 8
1654 9
1619 9
1655 $ try --optimize '(9)%(5)'
1620 $ try --optimize '(9)%(5)'
1656 (only
1621 (only
1657 (group
1622 (group
1658 ('symbol', '9'))
1623 ('symbol', '9'))
1659 (group
1624 (group
1660 ('symbol', '5')))
1625 ('symbol', '5')))
1661 * optimized:
1626 * optimized:
1662 (func
1627 (func
1663 ('symbol', 'only')
1628 ('symbol', 'only')
1664 (list
1629 (list
1665 ('symbol', '9')
1630 ('symbol', '9')
1666 ('symbol', '5'))
1631 ('symbol', '5')))
1667 define)
1668 * set:
1632 * set:
1669 <baseset+ [2, 4, 8, 9]>
1633 <baseset+ [2, 4, 8, 9]>
1670 2
1634 2
1671 4
1635 4
1672 8
1636 8
1673 9
1637 9
1674
1638
1675 Test the order of operations
1639 Test the order of operations
1676
1640
1677 $ log '7 + 9%5 + 2'
1641 $ log '7 + 9%5 + 2'
1678 7
1642 7
1679 2
1643 2
1680 4
1644 4
1681 8
1645 8
1682 9
1646 9
1683
1647
1684 Test explicit numeric revision
1648 Test explicit numeric revision
1685 $ log 'rev(-2)'
1649 $ log 'rev(-2)'
1686 $ log 'rev(-1)'
1650 $ log 'rev(-1)'
1687 -1
1651 -1
1688 $ log 'rev(0)'
1652 $ log 'rev(0)'
1689 0
1653 0
1690 $ log 'rev(9)'
1654 $ log 'rev(9)'
1691 9
1655 9
1692 $ log 'rev(10)'
1656 $ log 'rev(10)'
1693 $ log 'rev(tip)'
1657 $ log 'rev(tip)'
1694 hg: parse error: rev expects a number
1658 hg: parse error: rev expects a number
1695 [255]
1659 [255]
1696
1660
1697 Test hexadecimal revision
1661 Test hexadecimal revision
1698 $ log 'id(2)'
1662 $ log 'id(2)'
1699 abort: 00changelog.i@2: ambiguous identifier!
1663 abort: 00changelog.i@2: ambiguous identifier!
1700 [255]
1664 [255]
1701 $ log 'id(23268)'
1665 $ log 'id(23268)'
1702 4
1666 4
1703 $ log 'id(2785f51eece)'
1667 $ log 'id(2785f51eece)'
1704 0
1668 0
1705 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532c)'
1669 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532c)'
1706 8
1670 8
1707 $ log 'id(d5d0dcbdc4a)'
1671 $ log 'id(d5d0dcbdc4a)'
1708 $ log 'id(d5d0dcbdc4w)'
1672 $ log 'id(d5d0dcbdc4w)'
1709 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532d)'
1673 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532d)'
1710 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532q)'
1674 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532q)'
1711 $ log 'id(1.0)'
1675 $ log 'id(1.0)'
1712 $ log 'id(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)'
1676 $ log 'id(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)'
1713
1677
1714 Test null revision
1678 Test null revision
1715 $ log '(null)'
1679 $ log '(null)'
1716 -1
1680 -1
1717 $ log '(null:0)'
1681 $ log '(null:0)'
1718 -1
1682 -1
1719 0
1683 0
1720 $ log '(0:null)'
1684 $ log '(0:null)'
1721 0
1685 0
1722 -1
1686 -1
1723 $ log 'null::0'
1687 $ log 'null::0'
1724 -1
1688 -1
1725 0
1689 0
1726 $ log 'null:tip - 0:'
1690 $ log 'null:tip - 0:'
1727 -1
1691 -1
1728 $ log 'null: and null::' | head -1
1692 $ log 'null: and null::' | head -1
1729 -1
1693 -1
1730 $ log 'null: or 0:' | head -2
1694 $ log 'null: or 0:' | head -2
1731 -1
1695 -1
1732 0
1696 0
1733 $ log 'ancestors(null)'
1697 $ log 'ancestors(null)'
1734 -1
1698 -1
1735 $ log 'reverse(null:)' | tail -2
1699 $ log 'reverse(null:)' | tail -2
1736 0
1700 0
1737 -1
1701 -1
1738 $ log 'first(null:)'
1702 $ log 'first(null:)'
1739 -1
1703 -1
1740 $ log 'min(null:)'
1704 $ log 'min(null:)'
1741 BROKEN: should be '-1'
1705 BROKEN: should be '-1'
1742 $ log 'tip:null and all()' | tail -2
1706 $ log 'tip:null and all()' | tail -2
1743 1
1707 1
1744 0
1708 0
1745
1709
1746 Test working-directory revision
1710 Test working-directory revision
1747 $ hg debugrevspec 'wdir()'
1711 $ hg debugrevspec 'wdir()'
1748 2147483647
1712 2147483647
1749 $ hg debugrevspec 'wdir()^'
1713 $ hg debugrevspec 'wdir()^'
1750 9
1714 9
1751 $ hg up 7
1715 $ hg up 7
1752 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1716 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1753 $ hg debugrevspec 'wdir()^'
1717 $ hg debugrevspec 'wdir()^'
1754 7
1718 7
1755 $ hg debugrevspec 'wdir()^0'
1719 $ hg debugrevspec 'wdir()^0'
1756 2147483647
1720 2147483647
1757 $ hg debugrevspec 'wdir()~3'
1721 $ hg debugrevspec 'wdir()~3'
1758 5
1722 5
1759 $ hg debugrevspec 'ancestors(wdir())'
1723 $ hg debugrevspec 'ancestors(wdir())'
1760 0
1724 0
1761 1
1725 1
1762 2
1726 2
1763 3
1727 3
1764 4
1728 4
1765 5
1729 5
1766 6
1730 6
1767 7
1731 7
1768 2147483647
1732 2147483647
1769 $ hg debugrevspec 'wdir()~0'
1733 $ hg debugrevspec 'wdir()~0'
1770 2147483647
1734 2147483647
1771 $ hg debugrevspec 'p1(wdir())'
1735 $ hg debugrevspec 'p1(wdir())'
1772 7
1736 7
1773 $ hg debugrevspec 'p2(wdir())'
1737 $ hg debugrevspec 'p2(wdir())'
1774 $ hg debugrevspec 'parents(wdir())'
1738 $ hg debugrevspec 'parents(wdir())'
1775 7
1739 7
1776 $ hg debugrevspec 'wdir()^1'
1740 $ hg debugrevspec 'wdir()^1'
1777 7
1741 7
1778 $ hg debugrevspec 'wdir()^2'
1742 $ hg debugrevspec 'wdir()^2'
1779 $ hg debugrevspec 'wdir()^3'
1743 $ hg debugrevspec 'wdir()^3'
1780 hg: parse error: ^ expects a number 0, 1, or 2
1744 hg: parse error: ^ expects a number 0, 1, or 2
1781 [255]
1745 [255]
1782 For tests consistency
1746 For tests consistency
1783 $ hg up 9
1747 $ hg up 9
1784 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1748 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1785 $ hg debugrevspec 'tip or wdir()'
1749 $ hg debugrevspec 'tip or wdir()'
1786 9
1750 9
1787 2147483647
1751 2147483647
1788 $ hg debugrevspec '0:tip and wdir()'
1752 $ hg debugrevspec '0:tip and wdir()'
1789 $ log '0:wdir()' | tail -3
1753 $ log '0:wdir()' | tail -3
1790 8
1754 8
1791 9
1755 9
1792 2147483647
1756 2147483647
1793 $ log 'wdir():0' | head -3
1757 $ log 'wdir():0' | head -3
1794 2147483647
1758 2147483647
1795 9
1759 9
1796 8
1760 8
1797 $ log 'wdir():wdir()'
1761 $ log 'wdir():wdir()'
1798 2147483647
1762 2147483647
1799 $ log '(all() + wdir()) & min(. + wdir())'
1763 $ log '(all() + wdir()) & min(. + wdir())'
1800 9
1764 9
1801 $ log '(all() + wdir()) & max(. + wdir())'
1765 $ log '(all() + wdir()) & max(. + wdir())'
1802 2147483647
1766 2147483647
1803 $ log 'first(wdir() + .)'
1767 $ log 'first(wdir() + .)'
1804 2147483647
1768 2147483647
1805 $ log 'last(. + wdir())'
1769 $ log 'last(. + wdir())'
1806 2147483647
1770 2147483647
1807
1771
1808 Test working-directory integer revision and node id
1772 Test working-directory integer revision and node id
1809 (BUG: '0:wdir()' is still needed to populate wdir revision)
1773 (BUG: '0:wdir()' is still needed to populate wdir revision)
1810
1774
1811 $ hg debugrevspec '0:wdir() & 2147483647'
1775 $ hg debugrevspec '0:wdir() & 2147483647'
1812 2147483647
1776 2147483647
1813 $ hg debugrevspec '0:wdir() & rev(2147483647)'
1777 $ hg debugrevspec '0:wdir() & rev(2147483647)'
1814 2147483647
1778 2147483647
1815 $ hg debugrevspec '0:wdir() & ffffffffffffffffffffffffffffffffffffffff'
1779 $ hg debugrevspec '0:wdir() & ffffffffffffffffffffffffffffffffffffffff'
1816 2147483647
1780 2147483647
1817 $ hg debugrevspec '0:wdir() & ffffffffffff'
1781 $ hg debugrevspec '0:wdir() & ffffffffffff'
1818 2147483647
1782 2147483647
1819 $ hg debugrevspec '0:wdir() & id(ffffffffffffffffffffffffffffffffffffffff)'
1783 $ hg debugrevspec '0:wdir() & id(ffffffffffffffffffffffffffffffffffffffff)'
1820 2147483647
1784 2147483647
1821 $ hg debugrevspec '0:wdir() & id(ffffffffffff)'
1785 $ hg debugrevspec '0:wdir() & id(ffffffffffff)'
1822 2147483647
1786 2147483647
1823
1787
1824 $ cd ..
1788 $ cd ..
1825
1789
1826 Test short 'ff...' hash collision
1790 Test short 'ff...' hash collision
1827 (BUG: '0:wdir()' is still needed to populate wdir revision)
1791 (BUG: '0:wdir()' is still needed to populate wdir revision)
1828
1792
1829 $ hg init wdir-hashcollision
1793 $ hg init wdir-hashcollision
1830 $ cd wdir-hashcollision
1794 $ cd wdir-hashcollision
1831 $ cat <<EOF >> .hg/hgrc
1795 $ cat <<EOF >> .hg/hgrc
1832 > [experimental]
1796 > [experimental]
1833 > stabilization = createmarkers
1797 > stabilization = createmarkers
1834 > EOF
1798 > EOF
1835 $ echo 0 > a
1799 $ echo 0 > a
1836 $ hg ci -qAm 0
1800 $ hg ci -qAm 0
1837 $ for i in 2463 2961 6726 78127; do
1801 $ for i in 2463 2961 6726 78127; do
1838 > hg up -q 0
1802 > hg up -q 0
1839 > echo $i > a
1803 > echo $i > a
1840 > hg ci -qm $i
1804 > hg ci -qm $i
1841 > done
1805 > done
1842 $ hg up -q null
1806 $ hg up -q null
1843 $ hg log -r '0:wdir()' -T '{rev}:{node} {shortest(node, 3)}\n'
1807 $ hg log -r '0:wdir()' -T '{rev}:{node} {shortest(node, 3)}\n'
1844 0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a b4e
1808 0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a b4e
1845 1:fffbae3886c8fbb2114296380d276fd37715d571 fffba
1809 1:fffbae3886c8fbb2114296380d276fd37715d571 fffba
1846 2:fffb6093b00943f91034b9bdad069402c834e572 fffb6
1810 2:fffb6093b00943f91034b9bdad069402c834e572 fffb6
1847 3:fff48a9b9de34a4d64120c29548214c67980ade3 fff4
1811 3:fff48a9b9de34a4d64120c29548214c67980ade3 fff4
1848 4:ffff85cff0ff78504fcdc3c0bc10de0c65379249 ffff8
1812 4:ffff85cff0ff78504fcdc3c0bc10de0c65379249 ffff8
1849 2147483647:ffffffffffffffffffffffffffffffffffffffff fffff
1813 2147483647:ffffffffffffffffffffffffffffffffffffffff fffff
1850 $ hg debugobsolete fffbae3886c8fbb2114296380d276fd37715d571
1814 $ hg debugobsolete fffbae3886c8fbb2114296380d276fd37715d571
1851 obsoleted 1 changesets
1815 obsoleted 1 changesets
1852
1816
1853 $ hg debugrevspec '0:wdir() & fff'
1817 $ hg debugrevspec '0:wdir() & fff'
1854 abort: 00changelog.i@fff: ambiguous identifier!
1818 abort: 00changelog.i@fff: ambiguous identifier!
1855 [255]
1819 [255]
1856 $ hg debugrevspec '0:wdir() & ffff'
1820 $ hg debugrevspec '0:wdir() & ffff'
1857 abort: 00changelog.i@ffff: ambiguous identifier!
1821 abort: 00changelog.i@ffff: ambiguous identifier!
1858 [255]
1822 [255]
1859 $ hg debugrevspec '0:wdir() & fffb'
1823 $ hg debugrevspec '0:wdir() & fffb'
1860 abort: 00changelog.i@fffb: ambiguous identifier!
1824 abort: 00changelog.i@fffb: ambiguous identifier!
1861 [255]
1825 [255]
1862 BROKEN should be '2' (node lookup uses unfiltered repo since dc25ed84bee8)
1826 BROKEN should be '2' (node lookup uses unfiltered repo since dc25ed84bee8)
1863 $ hg debugrevspec '0:wdir() & id(fffb)'
1827 $ hg debugrevspec '0:wdir() & id(fffb)'
1864 2
1828 2
1865 $ hg debugrevspec '0:wdir() & ffff8'
1829 $ hg debugrevspec '0:wdir() & ffff8'
1866 4
1830 4
1867 $ hg debugrevspec '0:wdir() & fffff'
1831 $ hg debugrevspec '0:wdir() & fffff'
1868 2147483647
1832 2147483647
1869
1833
1870 $ cd ..
1834 $ cd ..
1871
1835
1872 Test branch() with wdir()
1836 Test branch() with wdir()
1873
1837
1874 $ cd repo
1838 $ cd repo
1875
1839
1876 $ log '0:wdir() & branch("literal:Γ©")'
1840 $ log '0:wdir() & branch("literal:Γ©")'
1877 8
1841 8
1878 9
1842 9
1879 2147483647
1843 2147483647
1880 $ log '0:wdir() & branch("re:Γ©")'
1844 $ log '0:wdir() & branch("re:Γ©")'
1881 8
1845 8
1882 9
1846 9
1883 2147483647
1847 2147483647
1884 $ log '0:wdir() & branch("re:^a")'
1848 $ log '0:wdir() & branch("re:^a")'
1885 0
1849 0
1886 2
1850 2
1887 $ log '0:wdir() & branch(8)'
1851 $ log '0:wdir() & branch(8)'
1888 8
1852 8
1889 9
1853 9
1890 2147483647
1854 2147483647
1891
1855
1892 branch(wdir()) returns all revisions belonging to the working branch. The wdir
1856 branch(wdir()) returns all revisions belonging to the working branch. The wdir
1893 itself isn't returned unless it is explicitly populated.
1857 itself isn't returned unless it is explicitly populated.
1894
1858
1895 $ log 'branch(wdir())'
1859 $ log 'branch(wdir())'
1896 8
1860 8
1897 9
1861 9
1898 $ log '0:wdir() & branch(wdir())'
1862 $ log '0:wdir() & branch(wdir())'
1899 8
1863 8
1900 9
1864 9
1901 2147483647
1865 2147483647
1902
1866
1903 $ log 'outgoing()'
1867 $ log 'outgoing()'
1904 8
1868 8
1905 9
1869 9
1906 $ log 'outgoing("../remote1")'
1870 $ log 'outgoing("../remote1")'
1907 8
1871 8
1908 9
1872 9
1909 $ log 'outgoing("../remote2")'
1873 $ log 'outgoing("../remote2")'
1910 3
1874 3
1911 5
1875 5
1912 6
1876 6
1913 7
1877 7
1914 9
1878 9
1915 $ log 'p1(merge())'
1879 $ log 'p1(merge())'
1916 5
1880 5
1917 $ log 'p2(merge())'
1881 $ log 'p2(merge())'
1918 4
1882 4
1919 $ log 'parents(merge())'
1883 $ log 'parents(merge())'
1920 4
1884 4
1921 5
1885 5
1922 $ log 'p1(branchpoint())'
1886 $ log 'p1(branchpoint())'
1923 0
1887 0
1924 2
1888 2
1925 $ log 'p2(branchpoint())'
1889 $ log 'p2(branchpoint())'
1926 $ log 'parents(branchpoint())'
1890 $ log 'parents(branchpoint())'
1927 0
1891 0
1928 2
1892 2
1929 $ log 'removes(a)'
1893 $ log 'removes(a)'
1930 2
1894 2
1931 6
1895 6
1932 $ log 'roots(all())'
1896 $ log 'roots(all())'
1933 0
1897 0
1934 $ log 'reverse(2 or 3 or 4 or 5)'
1898 $ log 'reverse(2 or 3 or 4 or 5)'
1935 5
1899 5
1936 4
1900 4
1937 3
1901 3
1938 2
1902 2
1939 $ log 'reverse(all())'
1903 $ log 'reverse(all())'
1940 9
1904 9
1941 8
1905 8
1942 7
1906 7
1943 6
1907 6
1944 5
1908 5
1945 4
1909 4
1946 3
1910 3
1947 2
1911 2
1948 1
1912 1
1949 0
1913 0
1950 $ log 'reverse(all()) & filelog(b)'
1914 $ log 'reverse(all()) & filelog(b)'
1951 4
1915 4
1952 1
1916 1
1953 $ log 'rev(5)'
1917 $ log 'rev(5)'
1954 5
1918 5
1955 $ log 'sort(limit(reverse(all()), 3))'
1919 $ log 'sort(limit(reverse(all()), 3))'
1956 7
1920 7
1957 8
1921 8
1958 9
1922 9
1959 $ log 'sort(2 or 3 or 4 or 5, date)'
1923 $ log 'sort(2 or 3 or 4 or 5, date)'
1960 2
1924 2
1961 3
1925 3
1962 5
1926 5
1963 4
1927 4
1964 $ log 'tagged()'
1928 $ log 'tagged()'
1965 6
1929 6
1966 $ log 'tag()'
1930 $ log 'tag()'
1967 6
1931 6
1968 $ log 'tag(1.0)'
1932 $ log 'tag(1.0)'
1969 6
1933 6
1970 $ log 'tag(tip)'
1934 $ log 'tag(tip)'
1971 9
1935 9
1972
1936
1973 Test order of revisions in compound expression
1937 Test order of revisions in compound expression
1974 ----------------------------------------------
1938 ----------------------------------------------
1975
1939
1976 The general rule is that only the outermost (= leftmost) predicate can
1940 The general rule is that only the outermost (= leftmost) predicate can
1977 enforce its ordering requirement. The other predicates should take the
1941 enforce its ordering requirement. The other predicates should take the
1978 ordering defined by it.
1942 ordering defined by it.
1979
1943
1980 'A & B' should follow the order of 'A':
1944 'A & B' should follow the order of 'A':
1981
1945
1982 $ log '2:0 & 0::2'
1946 $ log '2:0 & 0::2'
1983 2
1947 2
1984 1
1948 1
1985 0
1949 0
1986
1950
1987 'head()' combines sets in right order:
1951 'head()' combines sets in right order:
1988
1952
1989 $ log '2:0 & head()'
1953 $ log '2:0 & head()'
1990 2
1954 2
1991 1
1955 1
1992 0
1956 0
1993
1957
1994 'x:y' takes ordering parameter into account:
1958 'x:y' takes ordering parameter into account:
1995
1959
1996 $ try -p optimized '3:0 & 0:3 & not 2:1'
1960 $ try -p optimized '3:0 & 0:3 & not 2:1'
1997 * optimized:
1961 * optimized:
1998 (difference
1962 (difference
1999 (and
1963 (and
2000 (range
1964 (range
2001 ('symbol', '3')
1965 ('symbol', '3')
2002 ('symbol', '0')
1966 ('symbol', '0'))
2003 define)
2004 (range
1967 (range
2005 ('symbol', '0')
1968 ('symbol', '0')
2006 ('symbol', '3')
1969 ('symbol', '3')))
2007 follow)
2008 define)
2009 (range
1970 (range
2010 ('symbol', '2')
1971 ('symbol', '2')
2011 ('symbol', '1')
1972 ('symbol', '1')))
2012 any)
2013 define)
2014 * set:
1973 * set:
2015 <filteredset
1974 <filteredset
2016 <filteredset
1975 <filteredset
2017 <spanset- 0:4>,
1976 <spanset- 0:4>,
2018 <spanset+ 0:4>>,
1977 <spanset+ 0:4>>,
2019 <not
1978 <not
2020 <spanset+ 1:3>>>
1979 <spanset+ 1:3>>>
2021 3
1980 3
2022 0
1981 0
2023
1982
2024 'a + b', which is optimized to '_list(a b)', should take the ordering of
1983 'a + b', which is optimized to '_list(a b)', should take the ordering of
2025 the left expression:
1984 the left expression:
2026
1985
2027 $ try --optimize '2:0 & (0 + 1 + 2)'
1986 $ try --optimize '2:0 & (0 + 1 + 2)'
2028 (and
1987 (and
2029 (range
1988 (range
2030 ('symbol', '2')
1989 ('symbol', '2')
2031 ('symbol', '0'))
1990 ('symbol', '0'))
2032 (group
1991 (group
2033 (or
1992 (or
2034 (list
1993 (list
2035 ('symbol', '0')
1994 ('symbol', '0')
2036 ('symbol', '1')
1995 ('symbol', '1')
2037 ('symbol', '2')))))
1996 ('symbol', '2')))))
2038 * optimized:
1997 * optimized:
2039 (and
1998 (and
2040 (range
1999 (range
2041 ('symbol', '2')
2000 ('symbol', '2')
2042 ('symbol', '0')
2001 ('symbol', '0'))
2043 define)
2044 (func
2002 (func
2045 ('symbol', '_list')
2003 ('symbol', '_list')
2046 ('string', '0\x001\x002')
2004 ('string', '0\x001\x002')))
2047 follow)
2048 define)
2049 * set:
2005 * set:
2050 <filteredset
2006 <filteredset
2051 <spanset- 0:3>,
2007 <spanset- 0:3>,
2052 <baseset [0, 1, 2]>>
2008 <baseset [0, 1, 2]>>
2053 2
2009 2
2054 1
2010 1
2055 0
2011 0
2056
2012
2057 'A + B' should take the ordering of the left expression:
2013 'A + B' should take the ordering of the left expression:
2058
2014
2059 $ try --optimize '2:0 & (0:1 + 2)'
2015 $ try --optimize '2:0 & (0:1 + 2)'
2060 (and
2016 (and
2061 (range
2017 (range
2062 ('symbol', '2')
2018 ('symbol', '2')
2063 ('symbol', '0'))
2019 ('symbol', '0'))
2064 (group
2020 (group
2065 (or
2021 (or
2066 (list
2022 (list
2067 (range
2023 (range
2068 ('symbol', '0')
2024 ('symbol', '0')
2069 ('symbol', '1'))
2025 ('symbol', '1'))
2070 ('symbol', '2')))))
2026 ('symbol', '2')))))
2071 * optimized:
2027 * optimized:
2072 (and
2028 (and
2073 (range
2029 (range
2074 ('symbol', '2')
2030 ('symbol', '2')
2075 ('symbol', '0')
2031 ('symbol', '0'))
2076 define)
2077 (or
2032 (or
2078 (list
2033 (list
2079 (range
2034 (range
2080 ('symbol', '0')
2035 ('symbol', '0')
2081 ('symbol', '1')
2036 ('symbol', '1'))
2082 follow)
2037 ('symbol', '2'))))
2083 ('symbol', '2'))
2084 follow)
2085 define)
2086 * set:
2038 * set:
2087 <filteredset
2039 <filteredset
2088 <spanset- 0:3>,
2040 <spanset- 0:3>,
2089 <addset
2041 <addset
2090 <spanset+ 0:2>,
2042 <spanset+ 0:2>,
2091 <baseset [2]>>>
2043 <baseset [2]>>>
2092 2
2044 2
2093 1
2045 1
2094 0
2046 0
2095
2047
2096 '_intlist(a b)' should behave like 'a + b':
2048 '_intlist(a b)' should behave like 'a + b':
2097
2049
2098 $ trylist --optimize '2:0 & %ld' 0 1 2
2050 $ trylist --optimize '2:0 & %ld' 0 1 2
2099 (and
2051 (and
2100 (range
2052 (range
2101 ('symbol', '2')
2053 ('symbol', '2')
2102 ('symbol', '0'))
2054 ('symbol', '0'))
2103 (func
2055 (func
2104 ('symbol', '_intlist')
2056 ('symbol', '_intlist')
2105 ('string', '0\x001\x002')))
2057 ('string', '0\x001\x002')))
2106 * optimized:
2058 * optimized:
2107 (and
2059 (flipand
2108 (func
2060 (func
2109 ('symbol', '_intlist')
2061 ('symbol', '_intlist')
2110 ('string', '0\x001\x002')
2062 ('string', '0\x001\x002'))
2111 follow)
2112 (range
2063 (range
2113 ('symbol', '2')
2064 ('symbol', '2')
2114 ('symbol', '0')
2065 ('symbol', '0')))
2115 define)
2116 define)
2117 * set:
2066 * set:
2118 <filteredset
2067 <filteredset
2119 <spanset- 0:3>,
2068 <spanset- 0:3>,
2120 <baseset+ [0, 1, 2]>>
2069 <baseset+ [0, 1, 2]>>
2121 2
2070 2
2122 1
2071 1
2123 0
2072 0
2124
2073
2125 $ trylist --optimize '%ld & 2:0' 0 2 1
2074 $ trylist --optimize '%ld & 2:0' 0 2 1
2126 (and
2075 (and
2127 (func
2076 (func
2128 ('symbol', '_intlist')
2077 ('symbol', '_intlist')
2129 ('string', '0\x002\x001'))
2078 ('string', '0\x002\x001'))
2130 (range
2079 (range
2131 ('symbol', '2')
2080 ('symbol', '2')
2132 ('symbol', '0')))
2081 ('symbol', '0')))
2133 * optimized:
2082 * optimized:
2134 (and
2083 (and
2135 (func
2084 (func
2136 ('symbol', '_intlist')
2085 ('symbol', '_intlist')
2137 ('string', '0\x002\x001')
2086 ('string', '0\x002\x001'))
2138 define)
2139 (range
2087 (range
2140 ('symbol', '2')
2088 ('symbol', '2')
2141 ('symbol', '0')
2089 ('symbol', '0')))
2142 follow)
2143 define)
2144 * set:
2090 * set:
2145 <filteredset
2091 <filteredset
2146 <baseset [0, 2, 1]>,
2092 <baseset [0, 2, 1]>,
2147 <spanset- 0:3>>
2093 <spanset- 0:3>>
2148 0
2094 0
2149 2
2095 2
2150 1
2096 1
2151
2097
2152 '_hexlist(a b)' should behave like 'a + b':
2098 '_hexlist(a b)' should behave like 'a + b':
2153
2099
2154 $ trylist --optimize --bin '2:0 & %ln' `hg log -T '{node} ' -r0:2`
2100 $ trylist --optimize --bin '2:0 & %ln' `hg log -T '{node} ' -r0:2`
2155 (and
2101 (and
2156 (range
2102 (range
2157 ('symbol', '2')
2103 ('symbol', '2')
2158 ('symbol', '0'))
2104 ('symbol', '0'))
2159 (func
2105 (func
2160 ('symbol', '_hexlist')
2106 ('symbol', '_hexlist')
2161 ('string', '*'))) (glob)
2107 ('string', '*'))) (glob)
2162 * optimized:
2108 * optimized:
2163 (and
2109 (and
2164 (range
2110 (range
2165 ('symbol', '2')
2111 ('symbol', '2')
2166 ('symbol', '0')
2112 ('symbol', '0'))
2167 define)
2168 (func
2113 (func
2169 ('symbol', '_hexlist')
2114 ('symbol', '_hexlist')
2170 ('string', '*') (glob)
2115 ('string', '*'))) (glob)
2171 follow)
2172 define)
2173 * set:
2116 * set:
2174 <filteredset
2117 <filteredset
2175 <spanset- 0:3>,
2118 <spanset- 0:3>,
2176 <baseset [0, 1, 2]>>
2119 <baseset [0, 1, 2]>>
2177 2
2120 2
2178 1
2121 1
2179 0
2122 0
2180
2123
2181 $ trylist --optimize --bin '%ln & 2:0' `hg log -T '{node} ' -r0+2+1`
2124 $ trylist --optimize --bin '%ln & 2:0' `hg log -T '{node} ' -r0+2+1`
2182 (and
2125 (and
2183 (func
2126 (func
2184 ('symbol', '_hexlist')
2127 ('symbol', '_hexlist')
2185 ('string', '*')) (glob)
2128 ('string', '*')) (glob)
2186 (range
2129 (range
2187 ('symbol', '2')
2130 ('symbol', '2')
2188 ('symbol', '0')))
2131 ('symbol', '0')))
2189 * optimized:
2132 * optimized:
2190 (and
2133 (flipand
2191 (range
2134 (range
2192 ('symbol', '2')
2135 ('symbol', '2')
2193 ('symbol', '0')
2136 ('symbol', '0'))
2194 follow)
2195 (func
2137 (func
2196 ('symbol', '_hexlist')
2138 ('symbol', '_hexlist')
2197 ('string', '*') (glob)
2139 ('string', '*'))) (glob)
2198 define)
2199 define)
2200 * set:
2140 * set:
2201 <baseset [0, 2, 1]>
2141 <baseset [0, 2, 1]>
2202 0
2142 0
2203 2
2143 2
2204 1
2144 1
2205
2145
2206 '_list' should not go through the slow follow-order path if order doesn't
2146 '_list' should not go through the slow follow-order path if order doesn't
2207 matter:
2147 matter:
2208
2148
2209 $ try -p optimized '2:0 & not (0 + 1)'
2149 $ try -p optimized '2:0 & not (0 + 1)'
2210 * optimized:
2150 * optimized:
2211 (difference
2151 (difference
2212 (range
2152 (range
2213 ('symbol', '2')
2153 ('symbol', '2')
2214 ('symbol', '0')
2154 ('symbol', '0'))
2215 define)
2216 (func
2155 (func
2217 ('symbol', '_list')
2156 ('symbol', '_list')
2218 ('string', '0\x001')
2157 ('string', '0\x001')))
2219 any)
2220 define)
2221 * set:
2158 * set:
2222 <filteredset
2159 <filteredset
2223 <spanset- 0:3>,
2160 <spanset- 0:3>,
2224 <not
2161 <not
2225 <baseset [0, 1]>>>
2162 <baseset [0, 1]>>>
2226 2
2163 2
2227
2164
2228 $ try -p optimized '2:0 & not (0:2 & (0 + 1))'
2165 $ try -p optimized '2:0 & not (0:2 & (0 + 1))'
2229 * optimized:
2166 * optimized:
2230 (difference
2167 (difference
2231 (range
2168 (range
2232 ('symbol', '2')
2169 ('symbol', '2')
2233 ('symbol', '0')
2170 ('symbol', '0'))
2234 define)
2235 (and
2171 (and
2236 (range
2172 (range
2237 ('symbol', '0')
2173 ('symbol', '0')
2238 ('symbol', '2')
2174 ('symbol', '2'))
2239 any)
2240 (func
2175 (func
2241 ('symbol', '_list')
2176 ('symbol', '_list')
2242 ('string', '0\x001')
2177 ('string', '0\x001'))))
2243 any)
2244 any)
2245 define)
2246 * set:
2178 * set:
2247 <filteredset
2179 <filteredset
2248 <spanset- 0:3>,
2180 <spanset- 0:3>,
2249 <not
2181 <not
2250 <baseset [0, 1]>>>
2182 <baseset [0, 1]>>>
2251 2
2183 2
2252
2184
2253 because 'present()' does nothing other than suppressing an error, the
2185 because 'present()' does nothing other than suppressing an error, the
2254 ordering requirement should be forwarded to the nested expression
2186 ordering requirement should be forwarded to the nested expression
2255
2187
2256 $ try -p optimized 'present(2 + 0 + 1)'
2188 $ try -p optimized 'present(2 + 0 + 1)'
2257 * optimized:
2189 * optimized:
2258 (func
2190 (func
2259 ('symbol', 'present')
2191 ('symbol', 'present')
2260 (func
2192 (func
2261 ('symbol', '_list')
2193 ('symbol', '_list')
2262 ('string', '2\x000\x001')
2194 ('string', '2\x000\x001')))
2263 define)
2264 define)
2265 * set:
2195 * set:
2266 <baseset [2, 0, 1]>
2196 <baseset [2, 0, 1]>
2267 2
2197 2
2268 0
2198 0
2269 1
2199 1
2270
2200
2271 $ try --optimize '2:0 & present(0 + 1 + 2)'
2201 $ try --optimize '2:0 & present(0 + 1 + 2)'
2272 (and
2202 (and
2273 (range
2203 (range
2274 ('symbol', '2')
2204 ('symbol', '2')
2275 ('symbol', '0'))
2205 ('symbol', '0'))
2276 (func
2206 (func
2277 ('symbol', 'present')
2207 ('symbol', 'present')
2278 (or
2208 (or
2279 (list
2209 (list
2280 ('symbol', '0')
2210 ('symbol', '0')
2281 ('symbol', '1')
2211 ('symbol', '1')
2282 ('symbol', '2')))))
2212 ('symbol', '2')))))
2283 * optimized:
2213 * optimized:
2284 (and
2214 (and
2285 (range
2215 (range
2286 ('symbol', '2')
2216 ('symbol', '2')
2287 ('symbol', '0')
2217 ('symbol', '0'))
2288 define)
2289 (func
2218 (func
2290 ('symbol', 'present')
2219 ('symbol', 'present')
2291 (func
2220 (func
2292 ('symbol', '_list')
2221 ('symbol', '_list')
2293 ('string', '0\x001\x002')
2222 ('string', '0\x001\x002'))))
2294 follow)
2295 follow)
2296 define)
2297 * set:
2223 * set:
2298 <filteredset
2224 <filteredset
2299 <spanset- 0:3>,
2225 <spanset- 0:3>,
2300 <baseset [0, 1, 2]>>
2226 <baseset [0, 1, 2]>>
2301 2
2227 2
2302 1
2228 1
2303 0
2229 0
2304
2230
2305 'reverse()' should take effect only if it is the outermost expression:
2231 'reverse()' should take effect only if it is the outermost expression:
2306
2232
2307 $ try --optimize '0:2 & reverse(all())'
2233 $ try --optimize '0:2 & reverse(all())'
2308 (and
2234 (and
2309 (range
2235 (range
2310 ('symbol', '0')
2236 ('symbol', '0')
2311 ('symbol', '2'))
2237 ('symbol', '2'))
2312 (func
2238 (func
2313 ('symbol', 'reverse')
2239 ('symbol', 'reverse')
2314 (func
2240 (func
2315 ('symbol', 'all')
2241 ('symbol', 'all')
2316 None)))
2242 None)))
2317 * optimized:
2243 * optimized:
2318 (and
2244 (and
2319 (range
2245 (range
2320 ('symbol', '0')
2246 ('symbol', '0')
2321 ('symbol', '2')
2247 ('symbol', '2'))
2322 define)
2323 (func
2248 (func
2324 ('symbol', 'reverse')
2249 ('symbol', 'reverse')
2325 (func
2250 (func
2326 ('symbol', 'all')
2251 ('symbol', 'all')
2327 None
2252 None)))
2328 define)
2329 follow)
2330 define)
2331 * set:
2253 * set:
2332 <filteredset
2254 <filteredset
2333 <spanset+ 0:3>,
2255 <spanset+ 0:3>,
2334 <spanset+ 0:10>>
2256 <spanset+ 0:10>>
2335 0
2257 0
2336 1
2258 1
2337 2
2259 2
2338
2260
2339 'sort()' should take effect only if it is the outermost expression:
2261 'sort()' should take effect only if it is the outermost expression:
2340
2262
2341 $ try --optimize '0:2 & sort(all(), -rev)'
2263 $ try --optimize '0:2 & sort(all(), -rev)'
2342 (and
2264 (and
2343 (range
2265 (range
2344 ('symbol', '0')
2266 ('symbol', '0')
2345 ('symbol', '2'))
2267 ('symbol', '2'))
2346 (func
2268 (func
2347 ('symbol', 'sort')
2269 ('symbol', 'sort')
2348 (list
2270 (list
2349 (func
2271 (func
2350 ('symbol', 'all')
2272 ('symbol', 'all')
2351 None)
2273 None)
2352 (negate
2274 (negate
2353 ('symbol', 'rev')))))
2275 ('symbol', 'rev')))))
2354 * optimized:
2276 * optimized:
2355 (and
2277 (and
2356 (range
2278 (range
2357 ('symbol', '0')
2279 ('symbol', '0')
2358 ('symbol', '2')
2280 ('symbol', '2'))
2359 define)
2360 (func
2281 (func
2361 ('symbol', 'sort')
2282 ('symbol', 'sort')
2362 (list
2283 (list
2363 (func
2284 (func
2364 ('symbol', 'all')
2285 ('symbol', 'all')
2365 None
2286 None)
2366 define)
2287 ('string', '-rev'))))
2367 ('string', '-rev'))
2368 follow)
2369 define)
2370 * set:
2288 * set:
2371 <filteredset
2289 <filteredset
2372 <spanset+ 0:3>,
2290 <spanset+ 0:3>,
2373 <spanset+ 0:10>>
2291 <spanset+ 0:10>>
2374 0
2292 0
2375 1
2293 1
2376 2
2294 2
2377
2295
2378 invalid argument passed to noop sort():
2296 invalid argument passed to noop sort():
2379
2297
2380 $ log '0:2 & sort()'
2298 $ log '0:2 & sort()'
2381 hg: parse error: sort requires one or two arguments
2299 hg: parse error: sort requires one or two arguments
2382 [255]
2300 [255]
2383 $ log '0:2 & sort(all(), -invalid)'
2301 $ log '0:2 & sort(all(), -invalid)'
2384 hg: parse error: unknown sort key '-invalid'
2302 hg: parse error: unknown sort key '-invalid'
2385 [255]
2303 [255]
2386
2304
2387 for 'A & f(B)', 'B' should not be affected by the order of 'A':
2305 for 'A & f(B)', 'B' should not be affected by the order of 'A':
2388
2306
2389 $ try --optimize '2:0 & first(1 + 0 + 2)'
2307 $ try --optimize '2:0 & first(1 + 0 + 2)'
2390 (and
2308 (and
2391 (range
2309 (range
2392 ('symbol', '2')
2310 ('symbol', '2')
2393 ('symbol', '0'))
2311 ('symbol', '0'))
2394 (func
2312 (func
2395 ('symbol', 'first')
2313 ('symbol', 'first')
2396 (or
2314 (or
2397 (list
2315 (list
2398 ('symbol', '1')
2316 ('symbol', '1')
2399 ('symbol', '0')
2317 ('symbol', '0')
2400 ('symbol', '2')))))
2318 ('symbol', '2')))))
2401 * optimized:
2319 * optimized:
2402 (and
2320 (and
2403 (range
2321 (range
2404 ('symbol', '2')
2322 ('symbol', '2')
2405 ('symbol', '0')
2323 ('symbol', '0'))
2406 define)
2407 (func
2324 (func
2408 ('symbol', 'first')
2325 ('symbol', 'first')
2409 (func
2326 (func
2410 ('symbol', '_list')
2327 ('symbol', '_list')
2411 ('string', '1\x000\x002')
2328 ('string', '1\x000\x002'))))
2412 define)
2413 follow)
2414 define)
2415 * set:
2329 * set:
2416 <filteredset
2330 <filteredset
2417 <baseset [1]>,
2331 <baseset [1]>,
2418 <spanset- 0:3>>
2332 <spanset- 0:3>>
2419 1
2333 1
2420
2334
2421 $ try --optimize '2:0 & not last(0 + 2 + 1)'
2335 $ try --optimize '2:0 & not last(0 + 2 + 1)'
2422 (and
2336 (and
2423 (range
2337 (range
2424 ('symbol', '2')
2338 ('symbol', '2')
2425 ('symbol', '0'))
2339 ('symbol', '0'))
2426 (not
2340 (not
2427 (func
2341 (func
2428 ('symbol', 'last')
2342 ('symbol', 'last')
2429 (or
2343 (or
2430 (list
2344 (list
2431 ('symbol', '0')
2345 ('symbol', '0')
2432 ('symbol', '2')
2346 ('symbol', '2')
2433 ('symbol', '1'))))))
2347 ('symbol', '1'))))))
2434 * optimized:
2348 * optimized:
2435 (difference
2349 (difference
2436 (range
2350 (range
2437 ('symbol', '2')
2351 ('symbol', '2')
2438 ('symbol', '0')
2352 ('symbol', '0'))
2439 define)
2440 (func
2353 (func
2441 ('symbol', 'last')
2354 ('symbol', 'last')
2442 (func
2355 (func
2443 ('symbol', '_list')
2356 ('symbol', '_list')
2444 ('string', '0\x002\x001')
2357 ('string', '0\x002\x001'))))
2445 define)
2446 any)
2447 define)
2448 * set:
2358 * set:
2449 <filteredset
2359 <filteredset
2450 <spanset- 0:3>,
2360 <spanset- 0:3>,
2451 <not
2361 <not
2452 <baseset [1]>>>
2362 <baseset [1]>>>
2453 2
2363 2
2454 0
2364 0
2455
2365
2456 for 'A & (op)(B)', 'B' should not be affected by the order of 'A':
2366 for 'A & (op)(B)', 'B' should not be affected by the order of 'A':
2457
2367
2458 $ try --optimize '2:0 & (1 + 0 + 2):(0 + 2 + 1)'
2368 $ try --optimize '2:0 & (1 + 0 + 2):(0 + 2 + 1)'
2459 (and
2369 (and
2460 (range
2370 (range
2461 ('symbol', '2')
2371 ('symbol', '2')
2462 ('symbol', '0'))
2372 ('symbol', '0'))
2463 (range
2373 (range
2464 (group
2374 (group
2465 (or
2375 (or
2466 (list
2376 (list
2467 ('symbol', '1')
2377 ('symbol', '1')
2468 ('symbol', '0')
2378 ('symbol', '0')
2469 ('symbol', '2'))))
2379 ('symbol', '2'))))
2470 (group
2380 (group
2471 (or
2381 (or
2472 (list
2382 (list
2473 ('symbol', '0')
2383 ('symbol', '0')
2474 ('symbol', '2')
2384 ('symbol', '2')
2475 ('symbol', '1'))))))
2385 ('symbol', '1'))))))
2476 * optimized:
2386 * optimized:
2477 (and
2387 (and
2478 (range
2388 (range
2479 ('symbol', '2')
2389 ('symbol', '2')
2480 ('symbol', '0')
2390 ('symbol', '0'))
2481 define)
2482 (range
2391 (range
2483 (func
2392 (func
2484 ('symbol', '_list')
2393 ('symbol', '_list')
2485 ('string', '1\x000\x002')
2394 ('string', '1\x000\x002'))
2486 define)
2487 (func
2395 (func
2488 ('symbol', '_list')
2396 ('symbol', '_list')
2489 ('string', '0\x002\x001')
2397 ('string', '0\x002\x001'))))
2490 define)
2491 follow)
2492 define)
2493 * set:
2398 * set:
2494 <filteredset
2399 <filteredset
2495 <spanset- 0:3>,
2400 <spanset- 0:3>,
2496 <baseset [1]>>
2401 <baseset [1]>>
2497 1
2402 1
2498
2403
2499 'A & B' can be rewritten as 'B & A' by weight, but that's fine as long as
2404 'A & B' can be rewritten as 'flipand(B, A)' by weight.
2500 the ordering rule is determined before the rewrite; in this example,
2501 'B' follows the order of the initial set, which is the same order as 'A'
2502 since 'A' also follows the order:
2503
2405
2504 $ try --optimize 'contains("glob:*") & (2 + 0 + 1)'
2406 $ try --optimize 'contains("glob:*") & (2 + 0 + 1)'
2505 (and
2407 (and
2506 (func
2408 (func
2507 ('symbol', 'contains')
2409 ('symbol', 'contains')
2508 ('string', 'glob:*'))
2410 ('string', 'glob:*'))
2509 (group
2411 (group
2510 (or
2412 (or
2511 (list
2413 (list
2512 ('symbol', '2')
2414 ('symbol', '2')
2513 ('symbol', '0')
2415 ('symbol', '0')
2514 ('symbol', '1')))))
2416 ('symbol', '1')))))
2515 * optimized:
2417 * optimized:
2516 (and
2418 (flipand
2517 (func
2419 (func
2518 ('symbol', '_list')
2420 ('symbol', '_list')
2519 ('string', '2\x000\x001')
2421 ('string', '2\x000\x001'))
2520 follow)
2521 (func
2422 (func
2522 ('symbol', 'contains')
2423 ('symbol', 'contains')
2523 ('string', 'glob:*')
2424 ('string', 'glob:*')))
2524 define)
2525 define)
2526 * set:
2425 * set:
2527 <filteredset
2426 <filteredset
2528 <baseset+ [0, 1, 2]>,
2427 <baseset+ [0, 1, 2]>,
2529 <contains 'glob:*'>>
2428 <contains 'glob:*'>>
2530 0
2429 0
2531 1
2430 1
2532 2
2431 2
2533
2432
2534 and in this example, 'A & B' is rewritten as 'B & A', but 'A' overrides
2433 and in this example, 'A & B' is rewritten as 'B & A', but 'A' overrides
2535 the order appropriately:
2434 the order appropriately:
2536
2435
2537 $ try --optimize 'reverse(contains("glob:*")) & (0 + 2 + 1)'
2436 $ try --optimize 'reverse(contains("glob:*")) & (0 + 2 + 1)'
2538 (and
2437 (and
2539 (func
2438 (func
2540 ('symbol', 'reverse')
2439 ('symbol', 'reverse')
2541 (func
2440 (func
2542 ('symbol', 'contains')
2441 ('symbol', 'contains')
2543 ('string', 'glob:*')))
2442 ('string', 'glob:*')))
2544 (group
2443 (group
2545 (or
2444 (or
2546 (list
2445 (list
2547 ('symbol', '0')
2446 ('symbol', '0')
2548 ('symbol', '2')
2447 ('symbol', '2')
2549 ('symbol', '1')))))
2448 ('symbol', '1')))))
2550 * optimized:
2449 * optimized:
2551 (and
2450 (flipand
2552 (func
2451 (func
2553 ('symbol', '_list')
2452 ('symbol', '_list')
2554 ('string', '0\x002\x001')
2453 ('string', '0\x002\x001'))
2555 follow)
2556 (func
2454 (func
2557 ('symbol', 'reverse')
2455 ('symbol', 'reverse')
2558 (func
2456 (func
2559 ('symbol', 'contains')
2457 ('symbol', 'contains')
2560 ('string', 'glob:*')
2458 ('string', 'glob:*'))))
2561 define)
2562 define)
2563 define)
2564 * set:
2459 * set:
2565 <filteredset
2460 <filteredset
2566 <baseset- [0, 1, 2]>,
2461 <baseset- [0, 1, 2]>,
2567 <contains 'glob:*'>>
2462 <contains 'glob:*'>>
2568 2
2463 2
2569 1
2464 1
2570 0
2465 0
2571
2466
2572 test sort revset
2467 test sort revset
2573 --------------------------------------------
2468 --------------------------------------------
2574
2469
2575 test when adding two unordered revsets
2470 test when adding two unordered revsets
2576
2471
2577 $ log 'sort(keyword(issue) or modifies(b))'
2472 $ log 'sort(keyword(issue) or modifies(b))'
2578 4
2473 4
2579 6
2474 6
2580
2475
2581 test when sorting a reversed collection in the same way it is
2476 test when sorting a reversed collection in the same way it is
2582
2477
2583 $ log 'sort(reverse(all()), -rev)'
2478 $ log 'sort(reverse(all()), -rev)'
2584 9
2479 9
2585 8
2480 8
2586 7
2481 7
2587 6
2482 6
2588 5
2483 5
2589 4
2484 4
2590 3
2485 3
2591 2
2486 2
2592 1
2487 1
2593 0
2488 0
2594
2489
2595 test when sorting a reversed collection
2490 test when sorting a reversed collection
2596
2491
2597 $ log 'sort(reverse(all()), rev)'
2492 $ log 'sort(reverse(all()), rev)'
2598 0
2493 0
2599 1
2494 1
2600 2
2495 2
2601 3
2496 3
2602 4
2497 4
2603 5
2498 5
2604 6
2499 6
2605 7
2500 7
2606 8
2501 8
2607 9
2502 9
2608
2503
2609
2504
2610 test sorting two sorted collections in different orders
2505 test sorting two sorted collections in different orders
2611
2506
2612 $ log 'sort(outgoing() or reverse(removes(a)), rev)'
2507 $ log 'sort(outgoing() or reverse(removes(a)), rev)'
2613 2
2508 2
2614 6
2509 6
2615 8
2510 8
2616 9
2511 9
2617
2512
2618 test sorting two sorted collections in different orders backwards
2513 test sorting two sorted collections in different orders backwards
2619
2514
2620 $ log 'sort(outgoing() or reverse(removes(a)), -rev)'
2515 $ log 'sort(outgoing() or reverse(removes(a)), -rev)'
2621 9
2516 9
2622 8
2517 8
2623 6
2518 6
2624 2
2519 2
2625
2520
2626 test empty sort key which is noop
2521 test empty sort key which is noop
2627
2522
2628 $ log 'sort(0 + 2 + 1, "")'
2523 $ log 'sort(0 + 2 + 1, "")'
2629 0
2524 0
2630 2
2525 2
2631 1
2526 1
2632
2527
2633 test invalid sort keys
2528 test invalid sort keys
2634
2529
2635 $ log 'sort(all(), -invalid)'
2530 $ log 'sort(all(), -invalid)'
2636 hg: parse error: unknown sort key '-invalid'
2531 hg: parse error: unknown sort key '-invalid'
2637 [255]
2532 [255]
2638
2533
2639 $ cd ..
2534 $ cd ..
2640
2535
2641 test sorting by multiple keys including variable-length strings
2536 test sorting by multiple keys including variable-length strings
2642
2537
2643 $ hg init sorting
2538 $ hg init sorting
2644 $ cd sorting
2539 $ cd sorting
2645 $ cat <<EOF >> .hg/hgrc
2540 $ cat <<EOF >> .hg/hgrc
2646 > [ui]
2541 > [ui]
2647 > logtemplate = '{rev} {branch|p5}{desc|p5}{author|p5}{date|hgdate}\n'
2542 > logtemplate = '{rev} {branch|p5}{desc|p5}{author|p5}{date|hgdate}\n'
2648 > [templatealias]
2543 > [templatealias]
2649 > p5(s) = pad(s, 5)
2544 > p5(s) = pad(s, 5)
2650 > EOF
2545 > EOF
2651 $ hg branch -qf b12
2546 $ hg branch -qf b12
2652 $ hg ci -m m111 -u u112 -d '111 10800'
2547 $ hg ci -m m111 -u u112 -d '111 10800'
2653 $ hg branch -qf b11
2548 $ hg branch -qf b11
2654 $ hg ci -m m12 -u u111 -d '112 7200'
2549 $ hg ci -m m12 -u u111 -d '112 7200'
2655 $ hg branch -qf b111
2550 $ hg branch -qf b111
2656 $ hg ci -m m11 -u u12 -d '111 3600'
2551 $ hg ci -m m11 -u u12 -d '111 3600'
2657 $ hg branch -qf b112
2552 $ hg branch -qf b112
2658 $ hg ci -m m111 -u u11 -d '120 0'
2553 $ hg ci -m m111 -u u11 -d '120 0'
2659 $ hg branch -qf b111
2554 $ hg branch -qf b111
2660 $ hg ci -m m112 -u u111 -d '110 14400'
2555 $ hg ci -m m112 -u u111 -d '110 14400'
2661 created new head
2556 created new head
2662
2557
2663 compare revisions (has fast path):
2558 compare revisions (has fast path):
2664
2559
2665 $ hg log -r 'sort(all(), rev)'
2560 $ hg log -r 'sort(all(), rev)'
2666 0 b12 m111 u112 111 10800
2561 0 b12 m111 u112 111 10800
2667 1 b11 m12 u111 112 7200
2562 1 b11 m12 u111 112 7200
2668 2 b111 m11 u12 111 3600
2563 2 b111 m11 u12 111 3600
2669 3 b112 m111 u11 120 0
2564 3 b112 m111 u11 120 0
2670 4 b111 m112 u111 110 14400
2565 4 b111 m112 u111 110 14400
2671
2566
2672 $ hg log -r 'sort(all(), -rev)'
2567 $ hg log -r 'sort(all(), -rev)'
2673 4 b111 m112 u111 110 14400
2568 4 b111 m112 u111 110 14400
2674 3 b112 m111 u11 120 0
2569 3 b112 m111 u11 120 0
2675 2 b111 m11 u12 111 3600
2570 2 b111 m11 u12 111 3600
2676 1 b11 m12 u111 112 7200
2571 1 b11 m12 u111 112 7200
2677 0 b12 m111 u112 111 10800
2572 0 b12 m111 u112 111 10800
2678
2573
2679 compare variable-length strings (issue5218):
2574 compare variable-length strings (issue5218):
2680
2575
2681 $ hg log -r 'sort(all(), branch)'
2576 $ hg log -r 'sort(all(), branch)'
2682 1 b11 m12 u111 112 7200
2577 1 b11 m12 u111 112 7200
2683 2 b111 m11 u12 111 3600
2578 2 b111 m11 u12 111 3600
2684 4 b111 m112 u111 110 14400
2579 4 b111 m112 u111 110 14400
2685 3 b112 m111 u11 120 0
2580 3 b112 m111 u11 120 0
2686 0 b12 m111 u112 111 10800
2581 0 b12 m111 u112 111 10800
2687
2582
2688 $ hg log -r 'sort(all(), -branch)'
2583 $ hg log -r 'sort(all(), -branch)'
2689 0 b12 m111 u112 111 10800
2584 0 b12 m111 u112 111 10800
2690 3 b112 m111 u11 120 0
2585 3 b112 m111 u11 120 0
2691 2 b111 m11 u12 111 3600
2586 2 b111 m11 u12 111 3600
2692 4 b111 m112 u111 110 14400
2587 4 b111 m112 u111 110 14400
2693 1 b11 m12 u111 112 7200
2588 1 b11 m12 u111 112 7200
2694
2589
2695 $ hg log -r 'sort(all(), desc)'
2590 $ hg log -r 'sort(all(), desc)'
2696 2 b111 m11 u12 111 3600
2591 2 b111 m11 u12 111 3600
2697 0 b12 m111 u112 111 10800
2592 0 b12 m111 u112 111 10800
2698 3 b112 m111 u11 120 0
2593 3 b112 m111 u11 120 0
2699 4 b111 m112 u111 110 14400
2594 4 b111 m112 u111 110 14400
2700 1 b11 m12 u111 112 7200
2595 1 b11 m12 u111 112 7200
2701
2596
2702 $ hg log -r 'sort(all(), -desc)'
2597 $ hg log -r 'sort(all(), -desc)'
2703 1 b11 m12 u111 112 7200
2598 1 b11 m12 u111 112 7200
2704 4 b111 m112 u111 110 14400
2599 4 b111 m112 u111 110 14400
2705 0 b12 m111 u112 111 10800
2600 0 b12 m111 u112 111 10800
2706 3 b112 m111 u11 120 0
2601 3 b112 m111 u11 120 0
2707 2 b111 m11 u12 111 3600
2602 2 b111 m11 u12 111 3600
2708
2603
2709 $ hg log -r 'sort(all(), user)'
2604 $ hg log -r 'sort(all(), user)'
2710 3 b112 m111 u11 120 0
2605 3 b112 m111 u11 120 0
2711 1 b11 m12 u111 112 7200
2606 1 b11 m12 u111 112 7200
2712 4 b111 m112 u111 110 14400
2607 4 b111 m112 u111 110 14400
2713 0 b12 m111 u112 111 10800
2608 0 b12 m111 u112 111 10800
2714 2 b111 m11 u12 111 3600
2609 2 b111 m11 u12 111 3600
2715
2610
2716 $ hg log -r 'sort(all(), -user)'
2611 $ hg log -r 'sort(all(), -user)'
2717 2 b111 m11 u12 111 3600
2612 2 b111 m11 u12 111 3600
2718 0 b12 m111 u112 111 10800
2613 0 b12 m111 u112 111 10800
2719 1 b11 m12 u111 112 7200
2614 1 b11 m12 u111 112 7200
2720 4 b111 m112 u111 110 14400
2615 4 b111 m112 u111 110 14400
2721 3 b112 m111 u11 120 0
2616 3 b112 m111 u11 120 0
2722
2617
2723 compare dates (tz offset should have no effect):
2618 compare dates (tz offset should have no effect):
2724
2619
2725 $ hg log -r 'sort(all(), date)'
2620 $ hg log -r 'sort(all(), date)'
2726 4 b111 m112 u111 110 14400
2621 4 b111 m112 u111 110 14400
2727 0 b12 m111 u112 111 10800
2622 0 b12 m111 u112 111 10800
2728 2 b111 m11 u12 111 3600
2623 2 b111 m11 u12 111 3600
2729 1 b11 m12 u111 112 7200
2624 1 b11 m12 u111 112 7200
2730 3 b112 m111 u11 120 0
2625 3 b112 m111 u11 120 0
2731
2626
2732 $ hg log -r 'sort(all(), -date)'
2627 $ hg log -r 'sort(all(), -date)'
2733 3 b112 m111 u11 120 0
2628 3 b112 m111 u11 120 0
2734 1 b11 m12 u111 112 7200
2629 1 b11 m12 u111 112 7200
2735 0 b12 m111 u112 111 10800
2630 0 b12 m111 u112 111 10800
2736 2 b111 m11 u12 111 3600
2631 2 b111 m11 u12 111 3600
2737 4 b111 m112 u111 110 14400
2632 4 b111 m112 u111 110 14400
2738
2633
2739 be aware that 'sort(x, -k)' is not exactly the same as 'reverse(sort(x, k))'
2634 be aware that 'sort(x, -k)' is not exactly the same as 'reverse(sort(x, k))'
2740 because '-k' reverses the comparison, not the list itself:
2635 because '-k' reverses the comparison, not the list itself:
2741
2636
2742 $ hg log -r 'sort(0 + 2, date)'
2637 $ hg log -r 'sort(0 + 2, date)'
2743 0 b12 m111 u112 111 10800
2638 0 b12 m111 u112 111 10800
2744 2 b111 m11 u12 111 3600
2639 2 b111 m11 u12 111 3600
2745
2640
2746 $ hg log -r 'sort(0 + 2, -date)'
2641 $ hg log -r 'sort(0 + 2, -date)'
2747 0 b12 m111 u112 111 10800
2642 0 b12 m111 u112 111 10800
2748 2 b111 m11 u12 111 3600
2643 2 b111 m11 u12 111 3600
2749
2644
2750 $ hg log -r 'reverse(sort(0 + 2, date))'
2645 $ hg log -r 'reverse(sort(0 + 2, date))'
2751 2 b111 m11 u12 111 3600
2646 2 b111 m11 u12 111 3600
2752 0 b12 m111 u112 111 10800
2647 0 b12 m111 u112 111 10800
2753
2648
2754 sort by multiple keys:
2649 sort by multiple keys:
2755
2650
2756 $ hg log -r 'sort(all(), "branch -rev")'
2651 $ hg log -r 'sort(all(), "branch -rev")'
2757 1 b11 m12 u111 112 7200
2652 1 b11 m12 u111 112 7200
2758 4 b111 m112 u111 110 14400
2653 4 b111 m112 u111 110 14400
2759 2 b111 m11 u12 111 3600
2654 2 b111 m11 u12 111 3600
2760 3 b112 m111 u11 120 0
2655 3 b112 m111 u11 120 0
2761 0 b12 m111 u112 111 10800
2656 0 b12 m111 u112 111 10800
2762
2657
2763 $ hg log -r 'sort(all(), "-desc -date")'
2658 $ hg log -r 'sort(all(), "-desc -date")'
2764 1 b11 m12 u111 112 7200
2659 1 b11 m12 u111 112 7200
2765 4 b111 m112 u111 110 14400
2660 4 b111 m112 u111 110 14400
2766 3 b112 m111 u11 120 0
2661 3 b112 m111 u11 120 0
2767 0 b12 m111 u112 111 10800
2662 0 b12 m111 u112 111 10800
2768 2 b111 m11 u12 111 3600
2663 2 b111 m11 u12 111 3600
2769
2664
2770 $ hg log -r 'sort(all(), "user -branch date rev")'
2665 $ hg log -r 'sort(all(), "user -branch date rev")'
2771 3 b112 m111 u11 120 0
2666 3 b112 m111 u11 120 0
2772 4 b111 m112 u111 110 14400
2667 4 b111 m112 u111 110 14400
2773 1 b11 m12 u111 112 7200
2668 1 b11 m12 u111 112 7200
2774 0 b12 m111 u112 111 10800
2669 0 b12 m111 u112 111 10800
2775 2 b111 m11 u12 111 3600
2670 2 b111 m11 u12 111 3600
2776
2671
2777 toposort prioritises graph branches
2672 toposort prioritises graph branches
2778
2673
2779 $ hg up 2
2674 $ hg up 2
2780 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
2675 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
2781 $ touch a
2676 $ touch a
2782 $ hg addremove
2677 $ hg addremove
2783 adding a
2678 adding a
2784 $ hg ci -m 't1' -u 'tu' -d '130 0'
2679 $ hg ci -m 't1' -u 'tu' -d '130 0'
2785 created new head
2680 created new head
2786 $ echo 'a' >> a
2681 $ echo 'a' >> a
2787 $ hg ci -m 't2' -u 'tu' -d '130 0'
2682 $ hg ci -m 't2' -u 'tu' -d '130 0'
2788 $ hg book book1
2683 $ hg book book1
2789 $ hg up 4
2684 $ hg up 4
2790 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
2685 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
2791 (leaving bookmark book1)
2686 (leaving bookmark book1)
2792 $ touch a
2687 $ touch a
2793 $ hg addremove
2688 $ hg addremove
2794 adding a
2689 adding a
2795 $ hg ci -m 't3' -u 'tu' -d '130 0'
2690 $ hg ci -m 't3' -u 'tu' -d '130 0'
2796
2691
2797 $ hg log -r 'sort(all(), topo)'
2692 $ hg log -r 'sort(all(), topo)'
2798 7 b111 t3 tu 130 0
2693 7 b111 t3 tu 130 0
2799 4 b111 m112 u111 110 14400
2694 4 b111 m112 u111 110 14400
2800 3 b112 m111 u11 120 0
2695 3 b112 m111 u11 120 0
2801 6 b111 t2 tu 130 0
2696 6 b111 t2 tu 130 0
2802 5 b111 t1 tu 130 0
2697 5 b111 t1 tu 130 0
2803 2 b111 m11 u12 111 3600
2698 2 b111 m11 u12 111 3600
2804 1 b11 m12 u111 112 7200
2699 1 b11 m12 u111 112 7200
2805 0 b12 m111 u112 111 10800
2700 0 b12 m111 u112 111 10800
2806
2701
2807 $ hg log -r 'sort(all(), -topo)'
2702 $ hg log -r 'sort(all(), -topo)'
2808 0 b12 m111 u112 111 10800
2703 0 b12 m111 u112 111 10800
2809 1 b11 m12 u111 112 7200
2704 1 b11 m12 u111 112 7200
2810 2 b111 m11 u12 111 3600
2705 2 b111 m11 u12 111 3600
2811 5 b111 t1 tu 130 0
2706 5 b111 t1 tu 130 0
2812 6 b111 t2 tu 130 0
2707 6 b111 t2 tu 130 0
2813 3 b112 m111 u11 120 0
2708 3 b112 m111 u11 120 0
2814 4 b111 m112 u111 110 14400
2709 4 b111 m112 u111 110 14400
2815 7 b111 t3 tu 130 0
2710 7 b111 t3 tu 130 0
2816
2711
2817 $ hg log -r 'sort(all(), topo, topo.firstbranch=book1)'
2712 $ hg log -r 'sort(all(), topo, topo.firstbranch=book1)'
2818 6 b111 t2 tu 130 0
2713 6 b111 t2 tu 130 0
2819 5 b111 t1 tu 130 0
2714 5 b111 t1 tu 130 0
2820 7 b111 t3 tu 130 0
2715 7 b111 t3 tu 130 0
2821 4 b111 m112 u111 110 14400
2716 4 b111 m112 u111 110 14400
2822 3 b112 m111 u11 120 0
2717 3 b112 m111 u11 120 0
2823 2 b111 m11 u12 111 3600
2718 2 b111 m11 u12 111 3600
2824 1 b11 m12 u111 112 7200
2719 1 b11 m12 u111 112 7200
2825 0 b12 m111 u112 111 10800
2720 0 b12 m111 u112 111 10800
2826
2721
2827 topographical sorting can't be combined with other sort keys, and you can't
2722 topographical sorting can't be combined with other sort keys, and you can't
2828 use the topo.firstbranch option when topo sort is not active:
2723 use the topo.firstbranch option when topo sort is not active:
2829
2724
2830 $ hg log -r 'sort(all(), "topo user")'
2725 $ hg log -r 'sort(all(), "topo user")'
2831 hg: parse error: topo sort order cannot be combined with other sort keys
2726 hg: parse error: topo sort order cannot be combined with other sort keys
2832 [255]
2727 [255]
2833
2728
2834 $ hg log -r 'sort(all(), user, topo.firstbranch=book1)'
2729 $ hg log -r 'sort(all(), user, topo.firstbranch=book1)'
2835 hg: parse error: topo.firstbranch can only be used when using the topo sort key
2730 hg: parse error: topo.firstbranch can only be used when using the topo sort key
2836 [255]
2731 [255]
2837
2732
2838 topo.firstbranch should accept any kind of expressions:
2733 topo.firstbranch should accept any kind of expressions:
2839
2734
2840 $ hg log -r 'sort(0, topo, topo.firstbranch=(book1))'
2735 $ hg log -r 'sort(0, topo, topo.firstbranch=(book1))'
2841 0 b12 m111 u112 111 10800
2736 0 b12 m111 u112 111 10800
2842
2737
2843 $ cd ..
2738 $ cd ..
2844 $ cd repo
2739 $ cd repo
2845
2740
2846 test subtracting something from an addset
2741 test subtracting something from an addset
2847
2742
2848 $ log '(outgoing() or removes(a)) - removes(a)'
2743 $ log '(outgoing() or removes(a)) - removes(a)'
2849 8
2744 8
2850 9
2745 9
2851
2746
2852 test intersecting something with an addset
2747 test intersecting something with an addset
2853
2748
2854 $ log 'parents(outgoing() or removes(a))'
2749 $ log 'parents(outgoing() or removes(a))'
2855 1
2750 1
2856 4
2751 4
2857 5
2752 5
2858 8
2753 8
2859
2754
2860 test that `or` operation combines elements in the right order:
2755 test that `or` operation combines elements in the right order:
2861
2756
2862 $ log '3:4 or 2:5'
2757 $ log '3:4 or 2:5'
2863 3
2758 3
2864 4
2759 4
2865 2
2760 2
2866 5
2761 5
2867 $ log '3:4 or 5:2'
2762 $ log '3:4 or 5:2'
2868 3
2763 3
2869 4
2764 4
2870 5
2765 5
2871 2
2766 2
2872 $ log 'sort(3:4 or 2:5)'
2767 $ log 'sort(3:4 or 2:5)'
2873 2
2768 2
2874 3
2769 3
2875 4
2770 4
2876 5
2771 5
2877 $ log 'sort(3:4 or 5:2)'
2772 $ log 'sort(3:4 or 5:2)'
2878 2
2773 2
2879 3
2774 3
2880 4
2775 4
2881 5
2776 5
2882
2777
2883 test that more than one `-r`s are combined in the right order and deduplicated:
2778 test that more than one `-r`s are combined in the right order and deduplicated:
2884
2779
2885 $ hg log -T '{rev}\n' -r 3 -r 3 -r 4 -r 5:2 -r 'ancestors(4)'
2780 $ hg log -T '{rev}\n' -r 3 -r 3 -r 4 -r 5:2 -r 'ancestors(4)'
2886 3
2781 3
2887 4
2782 4
2888 5
2783 5
2889 2
2784 2
2890 0
2785 0
2891 1
2786 1
2892
2787
2893 test that `or` operation skips duplicated revisions from right-hand side
2788 test that `or` operation skips duplicated revisions from right-hand side
2894
2789
2895 $ try 'reverse(1::5) or ancestors(4)'
2790 $ try 'reverse(1::5) or ancestors(4)'
2896 (or
2791 (or
2897 (list
2792 (list
2898 (func
2793 (func
2899 ('symbol', 'reverse')
2794 ('symbol', 'reverse')
2900 (dagrange
2795 (dagrange
2901 ('symbol', '1')
2796 ('symbol', '1')
2902 ('symbol', '5')))
2797 ('symbol', '5')))
2903 (func
2798 (func
2904 ('symbol', 'ancestors')
2799 ('symbol', 'ancestors')
2905 ('symbol', '4'))))
2800 ('symbol', '4'))))
2906 * set:
2801 * set:
2907 <addset
2802 <addset
2908 <baseset- [1, 3, 5]>,
2803 <baseset- [1, 3, 5]>,
2909 <generatorset+>>
2804 <generatorset+>>
2910 5
2805 5
2911 3
2806 3
2912 1
2807 1
2913 0
2808 0
2914 2
2809 2
2915 4
2810 4
2916 $ try 'sort(ancestors(4) or reverse(1::5))'
2811 $ try 'sort(ancestors(4) or reverse(1::5))'
2917 (func
2812 (func
2918 ('symbol', 'sort')
2813 ('symbol', 'sort')
2919 (or
2814 (or
2920 (list
2815 (list
2921 (func
2816 (func
2922 ('symbol', 'ancestors')
2817 ('symbol', 'ancestors')
2923 ('symbol', '4'))
2818 ('symbol', '4'))
2924 (func
2819 (func
2925 ('symbol', 'reverse')
2820 ('symbol', 'reverse')
2926 (dagrange
2821 (dagrange
2927 ('symbol', '1')
2822 ('symbol', '1')
2928 ('symbol', '5'))))))
2823 ('symbol', '5'))))))
2929 * set:
2824 * set:
2930 <addset+
2825 <addset+
2931 <generatorset+>,
2826 <generatorset+>,
2932 <baseset- [1, 3, 5]>>
2827 <baseset- [1, 3, 5]>>
2933 0
2828 0
2934 1
2829 1
2935 2
2830 2
2936 3
2831 3
2937 4
2832 4
2938 5
2833 5
2939
2834
2940 test optimization of trivial `or` operation
2835 test optimization of trivial `or` operation
2941
2836
2942 $ try --optimize '0|(1)|"2"|-2|tip|null'
2837 $ try --optimize '0|(1)|"2"|-2|tip|null'
2943 (or
2838 (or
2944 (list
2839 (list
2945 ('symbol', '0')
2840 ('symbol', '0')
2946 (group
2841 (group
2947 ('symbol', '1'))
2842 ('symbol', '1'))
2948 ('string', '2')
2843 ('string', '2')
2949 (negate
2844 (negate
2950 ('symbol', '2'))
2845 ('symbol', '2'))
2951 ('symbol', 'tip')
2846 ('symbol', 'tip')
2952 ('symbol', 'null')))
2847 ('symbol', 'null')))
2953 * optimized:
2848 * optimized:
2954 (func
2849 (func
2955 ('symbol', '_list')
2850 ('symbol', '_list')
2956 ('string', '0\x001\x002\x00-2\x00tip\x00null')
2851 ('string', '0\x001\x002\x00-2\x00tip\x00null'))
2957 define)
2958 * set:
2852 * set:
2959 <baseset [0, 1, 2, 8, 9, -1]>
2853 <baseset [0, 1, 2, 8, 9, -1]>
2960 0
2854 0
2961 1
2855 1
2962 2
2856 2
2963 8
2857 8
2964 9
2858 9
2965 -1
2859 -1
2966
2860
2967 $ try --optimize '0|1|2:3'
2861 $ try --optimize '0|1|2:3'
2968 (or
2862 (or
2969 (list
2863 (list
2970 ('symbol', '0')
2864 ('symbol', '0')
2971 ('symbol', '1')
2865 ('symbol', '1')
2972 (range
2866 (range
2973 ('symbol', '2')
2867 ('symbol', '2')
2974 ('symbol', '3'))))
2868 ('symbol', '3'))))
2975 * optimized:
2869 * optimized:
2976 (or
2870 (or
2977 (list
2871 (list
2978 (func
2872 (func
2979 ('symbol', '_list')
2873 ('symbol', '_list')
2980 ('string', '0\x001')
2874 ('string', '0\x001'))
2981 define)
2982 (range
2875 (range
2983 ('symbol', '2')
2876 ('symbol', '2')
2984 ('symbol', '3')
2877 ('symbol', '3'))))
2985 define))
2986 define)
2987 * set:
2878 * set:
2988 <addset
2879 <addset
2989 <baseset [0, 1]>,
2880 <baseset [0, 1]>,
2990 <spanset+ 2:4>>
2881 <spanset+ 2:4>>
2991 0
2882 0
2992 1
2883 1
2993 2
2884 2
2994 3
2885 3
2995
2886
2996 $ try --optimize '0:1|2|3:4|5|6'
2887 $ try --optimize '0:1|2|3:4|5|6'
2997 (or
2888 (or
2998 (list
2889 (list
2999 (range
2890 (range
3000 ('symbol', '0')
2891 ('symbol', '0')
3001 ('symbol', '1'))
2892 ('symbol', '1'))
3002 ('symbol', '2')
2893 ('symbol', '2')
3003 (range
2894 (range
3004 ('symbol', '3')
2895 ('symbol', '3')
3005 ('symbol', '4'))
2896 ('symbol', '4'))
3006 ('symbol', '5')
2897 ('symbol', '5')
3007 ('symbol', '6')))
2898 ('symbol', '6')))
3008 * optimized:
2899 * optimized:
3009 (or
2900 (or
3010 (list
2901 (list
3011 (range
2902 (range
3012 ('symbol', '0')
2903 ('symbol', '0')
3013 ('symbol', '1')
2904 ('symbol', '1'))
3014 define)
3015 ('symbol', '2')
2905 ('symbol', '2')
3016 (range
2906 (range
3017 ('symbol', '3')
2907 ('symbol', '3')
3018 ('symbol', '4')
2908 ('symbol', '4'))
3019 define)
3020 (func
2909 (func
3021 ('symbol', '_list')
2910 ('symbol', '_list')
3022 ('string', '5\x006')
2911 ('string', '5\x006'))))
3023 define))
3024 define)
3025 * set:
2912 * set:
3026 <addset
2913 <addset
3027 <addset
2914 <addset
3028 <spanset+ 0:2>,
2915 <spanset+ 0:2>,
3029 <baseset [2]>>,
2916 <baseset [2]>>,
3030 <addset
2917 <addset
3031 <spanset+ 3:5>,
2918 <spanset+ 3:5>,
3032 <baseset [5, 6]>>>
2919 <baseset [5, 6]>>>
3033 0
2920 0
3034 1
2921 1
3035 2
2922 2
3036 3
2923 3
3037 4
2924 4
3038 5
2925 5
3039 6
2926 6
3040
2927
3041 unoptimized `or` looks like this
2928 unoptimized `or` looks like this
3042
2929
3043 $ try --no-optimized -p analyzed '0|1|2|3|4'
2930 $ try --no-optimized -p analyzed '0|1|2|3|4'
3044 * analyzed:
2931 * analyzed:
3045 (or
2932 (or
3046 (list
2933 (list
3047 ('symbol', '0')
2934 ('symbol', '0')
3048 ('symbol', '1')
2935 ('symbol', '1')
3049 ('symbol', '2')
2936 ('symbol', '2')
3050 ('symbol', '3')
2937 ('symbol', '3')
3051 ('symbol', '4'))
2938 ('symbol', '4')))
3052 define)
3053 * set:
2939 * set:
3054 <addset
2940 <addset
3055 <addset
2941 <addset
3056 <baseset [0]>,
2942 <baseset [0]>,
3057 <baseset [1]>>,
2943 <baseset [1]>>,
3058 <addset
2944 <addset
3059 <baseset [2]>,
2945 <baseset [2]>,
3060 <addset
2946 <addset
3061 <baseset [3]>,
2947 <baseset [3]>,
3062 <baseset [4]>>>>
2948 <baseset [4]>>>>
3063 0
2949 0
3064 1
2950 1
3065 2
2951 2
3066 3
2952 3
3067 4
2953 4
3068
2954
3069 test that `_list` should be narrowed by provided `subset`
2955 test that `_list` should be narrowed by provided `subset`
3070
2956
3071 $ log '0:2 and (null|1|2|3)'
2957 $ log '0:2 and (null|1|2|3)'
3072 1
2958 1
3073 2
2959 2
3074
2960
3075 test that `_list` should remove duplicates
2961 test that `_list` should remove duplicates
3076
2962
3077 $ log '0|1|2|1|2|-1|tip'
2963 $ log '0|1|2|1|2|-1|tip'
3078 0
2964 0
3079 1
2965 1
3080 2
2966 2
3081 9
2967 9
3082
2968
3083 test unknown revision in `_list`
2969 test unknown revision in `_list`
3084
2970
3085 $ log '0|unknown'
2971 $ log '0|unknown'
3086 abort: unknown revision 'unknown'!
2972 abort: unknown revision 'unknown'!
3087 [255]
2973 [255]
3088
2974
3089 test integer range in `_list`
2975 test integer range in `_list`
3090
2976
3091 $ log '-1|-10'
2977 $ log '-1|-10'
3092 9
2978 9
3093 0
2979 0
3094
2980
3095 $ log '-10|-11'
2981 $ log '-10|-11'
3096 abort: unknown revision '-11'!
2982 abort: unknown revision '-11'!
3097 [255]
2983 [255]
3098
2984
3099 $ log '9|10'
2985 $ log '9|10'
3100 abort: unknown revision '10'!
2986 abort: unknown revision '10'!
3101 [255]
2987 [255]
3102
2988
3103 test '0000' != '0' in `_list`
2989 test '0000' != '0' in `_list`
3104
2990
3105 $ log '0|0000'
2991 $ log '0|0000'
3106 0
2992 0
3107 -1
2993 -1
3108
2994
3109 test ',' in `_list`
2995 test ',' in `_list`
3110 $ log '0,1'
2996 $ log '0,1'
3111 hg: parse error: can't use a list in this context
2997 hg: parse error: can't use a list in this context
3112 (see hg help "revsets.x or y")
2998 (see hg help "revsets.x or y")
3113 [255]
2999 [255]
3114 $ try '0,1,2'
3000 $ try '0,1,2'
3115 (list
3001 (list
3116 ('symbol', '0')
3002 ('symbol', '0')
3117 ('symbol', '1')
3003 ('symbol', '1')
3118 ('symbol', '2'))
3004 ('symbol', '2'))
3119 hg: parse error: can't use a list in this context
3005 hg: parse error: can't use a list in this context
3120 (see hg help "revsets.x or y")
3006 (see hg help "revsets.x or y")
3121 [255]
3007 [255]
3122
3008
3123 test that chained `or` operations make balanced addsets
3009 test that chained `or` operations make balanced addsets
3124
3010
3125 $ try '0:1|1:2|2:3|3:4|4:5'
3011 $ try '0:1|1:2|2:3|3:4|4:5'
3126 (or
3012 (or
3127 (list
3013 (list
3128 (range
3014 (range
3129 ('symbol', '0')
3015 ('symbol', '0')
3130 ('symbol', '1'))
3016 ('symbol', '1'))
3131 (range
3017 (range
3132 ('symbol', '1')
3018 ('symbol', '1')
3133 ('symbol', '2'))
3019 ('symbol', '2'))
3134 (range
3020 (range
3135 ('symbol', '2')
3021 ('symbol', '2')
3136 ('symbol', '3'))
3022 ('symbol', '3'))
3137 (range
3023 (range
3138 ('symbol', '3')
3024 ('symbol', '3')
3139 ('symbol', '4'))
3025 ('symbol', '4'))
3140 (range
3026 (range
3141 ('symbol', '4')
3027 ('symbol', '4')
3142 ('symbol', '5'))))
3028 ('symbol', '5'))))
3143 * set:
3029 * set:
3144 <addset
3030 <addset
3145 <addset
3031 <addset
3146 <spanset+ 0:2>,
3032 <spanset+ 0:2>,
3147 <spanset+ 1:3>>,
3033 <spanset+ 1:3>>,
3148 <addset
3034 <addset
3149 <spanset+ 2:4>,
3035 <spanset+ 2:4>,
3150 <addset
3036 <addset
3151 <spanset+ 3:5>,
3037 <spanset+ 3:5>,
3152 <spanset+ 4:6>>>>
3038 <spanset+ 4:6>>>>
3153 0
3039 0
3154 1
3040 1
3155 2
3041 2
3156 3
3042 3
3157 4
3043 4
3158 5
3044 5
3159
3045
3160 no crash by empty group "()" while optimizing `or` operations
3046 no crash by empty group "()" while optimizing `or` operations
3161
3047
3162 $ try --optimize '0|()'
3048 $ try --optimize '0|()'
3163 (or
3049 (or
3164 (list
3050 (list
3165 ('symbol', '0')
3051 ('symbol', '0')
3166 (group
3052 (group
3167 None)))
3053 None)))
3168 * optimized:
3054 * optimized:
3169 (or
3055 (or
3170 (list
3056 (list
3171 ('symbol', '0')
3057 ('symbol', '0')
3172 None)
3058 None))
3173 define)
3174 hg: parse error: missing argument
3059 hg: parse error: missing argument
3175 [255]
3060 [255]
3176
3061
3177 test that chained `or` operations never eat up stack (issue4624)
3062 test that chained `or` operations never eat up stack (issue4624)
3178 (uses `0:1` instead of `0` to avoid future optimization of trivial revisions)
3063 (uses `0:1` instead of `0` to avoid future optimization of trivial revisions)
3179
3064
3180 $ hg log -T '{rev}\n' -r `$PYTHON -c "print '+'.join(['0:1'] * 500)"`
3065 $ hg log -T '{rev}\n' -r `$PYTHON -c "print '+'.join(['0:1'] * 500)"`
3181 0
3066 0
3182 1
3067 1
3183
3068
3184 test that repeated `-r` options never eat up stack (issue4565)
3069 test that repeated `-r` options never eat up stack (issue4565)
3185 (uses `-r 0::1` to avoid possible optimization at old-style parser)
3070 (uses `-r 0::1` to avoid possible optimization at old-style parser)
3186
3071
3187 $ hg log -T '{rev}\n' `$PYTHON -c "for i in xrange(500): print '-r 0::1 ',"`
3072 $ hg log -T '{rev}\n' `$PYTHON -c "for i in xrange(500): print '-r 0::1 ',"`
3188 0
3073 0
3189 1
3074 1
3190
3075
3191 check that conversion to only works
3076 check that conversion to only works
3192 $ try --optimize '::3 - ::1'
3077 $ try --optimize '::3 - ::1'
3193 (minus
3078 (minus
3194 (dagrangepre
3079 (dagrangepre
3195 ('symbol', '3'))
3080 ('symbol', '3'))
3196 (dagrangepre
3081 (dagrangepre
3197 ('symbol', '1')))
3082 ('symbol', '1')))
3198 * optimized:
3083 * optimized:
3199 (func
3084 (func
3200 ('symbol', 'only')
3085 ('symbol', 'only')
3201 (list
3086 (list
3202 ('symbol', '3')
3087 ('symbol', '3')
3203 ('symbol', '1'))
3088 ('symbol', '1')))
3204 define)
3205 * set:
3089 * set:
3206 <baseset+ [3]>
3090 <baseset+ [3]>
3207 3
3091 3
3208 $ try --optimize 'ancestors(1) - ancestors(3)'
3092 $ try --optimize 'ancestors(1) - ancestors(3)'
3209 (minus
3093 (minus
3210 (func
3094 (func
3211 ('symbol', 'ancestors')
3095 ('symbol', 'ancestors')
3212 ('symbol', '1'))
3096 ('symbol', '1'))
3213 (func
3097 (func
3214 ('symbol', 'ancestors')
3098 ('symbol', 'ancestors')
3215 ('symbol', '3')))
3099 ('symbol', '3')))
3216 * optimized:
3100 * optimized:
3217 (func
3101 (func
3218 ('symbol', 'only')
3102 ('symbol', 'only')
3219 (list
3103 (list
3220 ('symbol', '1')
3104 ('symbol', '1')
3221 ('symbol', '3'))
3105 ('symbol', '3')))
3222 define)
3223 * set:
3106 * set:
3224 <baseset+ []>
3107 <baseset+ []>
3225 $ try --optimize 'not ::2 and ::6'
3108 $ try --optimize 'not ::2 and ::6'
3226 (and
3109 (and
3227 (not
3110 (not
3228 (dagrangepre
3111 (dagrangepre
3229 ('symbol', '2')))
3112 ('symbol', '2')))
3230 (dagrangepre
3113 (dagrangepre
3231 ('symbol', '6')))
3114 ('symbol', '6')))
3232 * optimized:
3115 * optimized:
3233 (func
3116 (func
3234 ('symbol', 'only')
3117 ('symbol', 'only')
3235 (list
3118 (list
3236 ('symbol', '6')
3119 ('symbol', '6')
3237 ('symbol', '2'))
3120 ('symbol', '2')))
3238 define)
3239 * set:
3121 * set:
3240 <baseset+ [3, 4, 5, 6]>
3122 <baseset+ [3, 4, 5, 6]>
3241 3
3123 3
3242 4
3124 4
3243 5
3125 5
3244 6
3126 6
3245 $ try --optimize 'ancestors(6) and not ancestors(4)'
3127 $ try --optimize 'ancestors(6) and not ancestors(4)'
3246 (and
3128 (and
3247 (func
3129 (func
3248 ('symbol', 'ancestors')
3130 ('symbol', 'ancestors')
3249 ('symbol', '6'))
3131 ('symbol', '6'))
3250 (not
3132 (not
3251 (func
3133 (func
3252 ('symbol', 'ancestors')
3134 ('symbol', 'ancestors')
3253 ('symbol', '4'))))
3135 ('symbol', '4'))))
3254 * optimized:
3136 * optimized:
3255 (func
3137 (func
3256 ('symbol', 'only')
3138 ('symbol', 'only')
3257 (list
3139 (list
3258 ('symbol', '6')
3140 ('symbol', '6')
3259 ('symbol', '4'))
3141 ('symbol', '4')))
3260 define)
3261 * set:
3142 * set:
3262 <baseset+ [3, 5, 6]>
3143 <baseset+ [3, 5, 6]>
3263 3
3144 3
3264 5
3145 5
3265 6
3146 6
3266
3147
3267 no crash by empty group "()" while optimizing to "only()"
3148 no crash by empty group "()" while optimizing to "only()"
3268
3149
3269 $ try --optimize '::1 and ()'
3150 $ try --optimize '::1 and ()'
3270 (and
3151 (and
3271 (dagrangepre
3152 (dagrangepre
3272 ('symbol', '1'))
3153 ('symbol', '1'))
3273 (group
3154 (group
3274 None))
3155 None))
3275 * optimized:
3156 * optimized:
3276 (and
3157 (flipand
3277 None
3158 None
3278 (func
3159 (func
3279 ('symbol', 'ancestors')
3160 ('symbol', 'ancestors')
3280 ('symbol', '1')
3161 ('symbol', '1')))
3281 define)
3282 define)
3283 hg: parse error: missing argument
3162 hg: parse error: missing argument
3284 [255]
3163 [255]
3285
3164
3286 optimization to only() works only if ancestors() takes only one argument
3165 optimization to only() works only if ancestors() takes only one argument
3287
3166
3288 $ hg debugrevspec -p optimized 'ancestors(6) - ancestors(4, 1)'
3167 $ hg debugrevspec -p optimized 'ancestors(6) - ancestors(4, 1)'
3289 * optimized:
3168 * optimized:
3290 (difference
3169 (difference
3291 (func
3170 (func
3292 ('symbol', 'ancestors')
3171 ('symbol', 'ancestors')
3293 ('symbol', '6')
3172 ('symbol', '6'))
3294 define)
3295 (func
3173 (func
3296 ('symbol', 'ancestors')
3174 ('symbol', 'ancestors')
3297 (list
3175 (list
3298 ('symbol', '4')
3176 ('symbol', '4')
3299 ('symbol', '1'))
3177 ('symbol', '1'))))
3300 any)
3301 define)
3302 0
3178 0
3303 1
3179 1
3304 3
3180 3
3305 5
3181 5
3306 6
3182 6
3307 $ hg debugrevspec -p optimized 'ancestors(6, 1) - ancestors(4)'
3183 $ hg debugrevspec -p optimized 'ancestors(6, 1) - ancestors(4)'
3308 * optimized:
3184 * optimized:
3309 (difference
3185 (difference
3310 (func
3186 (func
3311 ('symbol', 'ancestors')
3187 ('symbol', 'ancestors')
3312 (list
3188 (list
3313 ('symbol', '6')
3189 ('symbol', '6')
3314 ('symbol', '1'))
3190 ('symbol', '1')))
3315 define)
3316 (func
3191 (func
3317 ('symbol', 'ancestors')
3192 ('symbol', 'ancestors')
3318 ('symbol', '4')
3193 ('symbol', '4')))
3319 any)
3320 define)
3321 5
3194 5
3322 6
3195 6
3323
3196
3324 optimization disabled if keyword arguments passed (because we're too lazy
3197 optimization disabled if keyword arguments passed (because we're too lazy
3325 to support it)
3198 to support it)
3326
3199
3327 $ hg debugrevspec -p optimized 'ancestors(set=6) - ancestors(set=4)'
3200 $ hg debugrevspec -p optimized 'ancestors(set=6) - ancestors(set=4)'
3328 * optimized:
3201 * optimized:
3329 (difference
3202 (difference
3330 (func
3203 (func
3331 ('symbol', 'ancestors')
3204 ('symbol', 'ancestors')
3332 (keyvalue
3205 (keyvalue
3333 ('symbol', 'set')
3206 ('symbol', 'set')
3334 ('symbol', '6'))
3207 ('symbol', '6')))
3335 define)
3336 (func
3208 (func
3337 ('symbol', 'ancestors')
3209 ('symbol', 'ancestors')
3338 (keyvalue
3210 (keyvalue
3339 ('symbol', 'set')
3211 ('symbol', 'set')
3340 ('symbol', '4'))
3212 ('symbol', '4'))))
3341 any)
3342 define)
3343 3
3213 3
3344 5
3214 5
3345 6
3215 6
3346
3216
3347 invalid function call should not be optimized to only()
3217 invalid function call should not be optimized to only()
3348
3218
3349 $ log '"ancestors"(6) and not ancestors(4)'
3219 $ log '"ancestors"(6) and not ancestors(4)'
3350 hg: parse error: not a symbol
3220 hg: parse error: not a symbol
3351 [255]
3221 [255]
3352
3222
3353 $ log 'ancestors(6) and not "ancestors"(4)'
3223 $ log 'ancestors(6) and not "ancestors"(4)'
3354 hg: parse error: not a symbol
3224 hg: parse error: not a symbol
3355 [255]
3225 [255]
3356
3226
3357 we can use patterns when searching for tags
3227 we can use patterns when searching for tags
3358
3228
3359 $ log 'tag("1..*")'
3229 $ log 'tag("1..*")'
3360 abort: tag '1..*' does not exist!
3230 abort: tag '1..*' does not exist!
3361 [255]
3231 [255]
3362 $ log 'tag("re:1..*")'
3232 $ log 'tag("re:1..*")'
3363 6
3233 6
3364 $ log 'tag("re:[0-9].[0-9]")'
3234 $ log 'tag("re:[0-9].[0-9]")'
3365 6
3235 6
3366 $ log 'tag("literal:1.0")'
3236 $ log 'tag("literal:1.0")'
3367 6
3237 6
3368 $ log 'tag("re:0..*")'
3238 $ log 'tag("re:0..*")'
3369
3239
3370 $ log 'tag(unknown)'
3240 $ log 'tag(unknown)'
3371 abort: tag 'unknown' does not exist!
3241 abort: tag 'unknown' does not exist!
3372 [255]
3242 [255]
3373 $ log 'tag("re:unknown")'
3243 $ log 'tag("re:unknown")'
3374 $ log 'present(tag("unknown"))'
3244 $ log 'present(tag("unknown"))'
3375 $ log 'present(tag("re:unknown"))'
3245 $ log 'present(tag("re:unknown"))'
3376 $ log 'branch(unknown)'
3246 $ log 'branch(unknown)'
3377 abort: unknown revision 'unknown'!
3247 abort: unknown revision 'unknown'!
3378 [255]
3248 [255]
3379 $ log 'branch("literal:unknown")'
3249 $ log 'branch("literal:unknown")'
3380 abort: branch 'unknown' does not exist!
3250 abort: branch 'unknown' does not exist!
3381 [255]
3251 [255]
3382 $ log 'branch("re:unknown")'
3252 $ log 'branch("re:unknown")'
3383 $ log 'present(branch("unknown"))'
3253 $ log 'present(branch("unknown"))'
3384 $ log 'present(branch("re:unknown"))'
3254 $ log 'present(branch("re:unknown"))'
3385 $ log 'user(bob)'
3255 $ log 'user(bob)'
3386 2
3256 2
3387
3257
3388 $ log '4::8'
3258 $ log '4::8'
3389 4
3259 4
3390 8
3260 8
3391 $ log '4:8'
3261 $ log '4:8'
3392 4
3262 4
3393 5
3263 5
3394 6
3264 6
3395 7
3265 7
3396 8
3266 8
3397
3267
3398 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
3268 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
3399 4
3269 4
3400 2
3270 2
3401 5
3271 5
3402
3272
3403 $ log 'not 0 and 0:2'
3273 $ log 'not 0 and 0:2'
3404 1
3274 1
3405 2
3275 2
3406 $ log 'not 1 and 0:2'
3276 $ log 'not 1 and 0:2'
3407 0
3277 0
3408 2
3278 2
3409 $ log 'not 2 and 0:2'
3279 $ log 'not 2 and 0:2'
3410 0
3280 0
3411 1
3281 1
3412 $ log '(1 and 2)::'
3282 $ log '(1 and 2)::'
3413 $ log '(1 and 2):'
3283 $ log '(1 and 2):'
3414 $ log '(1 and 2):3'
3284 $ log '(1 and 2):3'
3415 $ log 'sort(head(), -rev)'
3285 $ log 'sort(head(), -rev)'
3416 9
3286 9
3417 7
3287 7
3418 6
3288 6
3419 5
3289 5
3420 4
3290 4
3421 3
3291 3
3422 2
3292 2
3423 1
3293 1
3424 0
3294 0
3425 $ log '4::8 - 8'
3295 $ log '4::8 - 8'
3426 4
3296 4
3427
3297
3428 matching() should preserve the order of the input set:
3298 matching() should preserve the order of the input set:
3429
3299
3430 $ log '(2 or 3 or 1) and matching(1 or 2 or 3)'
3300 $ log '(2 or 3 or 1) and matching(1 or 2 or 3)'
3431 2
3301 2
3432 3
3302 3
3433 1
3303 1
3434
3304
3435 $ log 'named("unknown")'
3305 $ log 'named("unknown")'
3436 abort: namespace 'unknown' does not exist!
3306 abort: namespace 'unknown' does not exist!
3437 [255]
3307 [255]
3438 $ log 'named("re:unknown")'
3308 $ log 'named("re:unknown")'
3439 abort: no namespace exists that match 'unknown'!
3309 abort: no namespace exists that match 'unknown'!
3440 [255]
3310 [255]
3441 $ log 'present(named("unknown"))'
3311 $ log 'present(named("unknown"))'
3442 $ log 'present(named("re:unknown"))'
3312 $ log 'present(named("re:unknown"))'
3443
3313
3444 $ log 'tag()'
3314 $ log 'tag()'
3445 6
3315 6
3446 $ log 'named("tags")'
3316 $ log 'named("tags")'
3447 6
3317 6
3448
3318
3449 issue2437
3319 issue2437
3450
3320
3451 $ log '3 and p1(5)'
3321 $ log '3 and p1(5)'
3452 3
3322 3
3453 $ log '4 and p2(6)'
3323 $ log '4 and p2(6)'
3454 4
3324 4
3455 $ log '1 and parents(:2)'
3325 $ log '1 and parents(:2)'
3456 1
3326 1
3457 $ log '2 and children(1:)'
3327 $ log '2 and children(1:)'
3458 2
3328 2
3459 $ log 'roots(all()) or roots(all())'
3329 $ log 'roots(all()) or roots(all())'
3460 0
3330 0
3461 $ hg debugrevspec 'roots(all()) or roots(all())'
3331 $ hg debugrevspec 'roots(all()) or roots(all())'
3462 0
3332 0
3463 $ log 'heads(branch(Γ©)) or heads(branch(Γ©))'
3333 $ log 'heads(branch(Γ©)) or heads(branch(Γ©))'
3464 9
3334 9
3465 $ log 'ancestors(8) and (heads(branch("-a-b-c-")) or heads(branch(Γ©)))'
3335 $ log 'ancestors(8) and (heads(branch("-a-b-c-")) or heads(branch(Γ©)))'
3466 4
3336 4
3467
3337
3468 issue2654: report a parse error if the revset was not completely parsed
3338 issue2654: report a parse error if the revset was not completely parsed
3469
3339
3470 $ log '1 OR 2'
3340 $ log '1 OR 2'
3471 hg: parse error at 2: invalid token
3341 hg: parse error at 2: invalid token
3472 [255]
3342 [255]
3473
3343
3474 or operator should preserve ordering:
3344 or operator should preserve ordering:
3475 $ log 'reverse(2::4) or tip'
3345 $ log 'reverse(2::4) or tip'
3476 4
3346 4
3477 2
3347 2
3478 9
3348 9
3479
3349
3480 parentrevspec
3350 parentrevspec
3481
3351
3482 $ log 'merge()^0'
3352 $ log 'merge()^0'
3483 6
3353 6
3484 $ log 'merge()^'
3354 $ log 'merge()^'
3485 5
3355 5
3486 $ log 'merge()^1'
3356 $ log 'merge()^1'
3487 5
3357 5
3488 $ log 'merge()^2'
3358 $ log 'merge()^2'
3489 4
3359 4
3490 $ log '(not merge())^2'
3360 $ log '(not merge())^2'
3491 $ log 'merge()^^'
3361 $ log 'merge()^^'
3492 3
3362 3
3493 $ log 'merge()^1^'
3363 $ log 'merge()^1^'
3494 3
3364 3
3495 $ log 'merge()^^^'
3365 $ log 'merge()^^^'
3496 1
3366 1
3497
3367
3498 $ hg debugrevspec -s '(merge() | 0)~-1'
3368 $ hg debugrevspec -s '(merge() | 0)~-1'
3499 * set:
3369 * set:
3500 <baseset+ [1, 7]>
3370 <baseset+ [1, 7]>
3501 1
3371 1
3502 7
3372 7
3503 $ log 'merge()~-1'
3373 $ log 'merge()~-1'
3504 7
3374 7
3505 $ log 'tip~-1'
3375 $ log 'tip~-1'
3506 $ log '(tip | merge())~-1'
3376 $ log '(tip | merge())~-1'
3507 7
3377 7
3508 $ log 'merge()~0'
3378 $ log 'merge()~0'
3509 6
3379 6
3510 $ log 'merge()~1'
3380 $ log 'merge()~1'
3511 5
3381 5
3512 $ log 'merge()~2'
3382 $ log 'merge()~2'
3513 3
3383 3
3514 $ log 'merge()~2^1'
3384 $ log 'merge()~2^1'
3515 1
3385 1
3516 $ log 'merge()~3'
3386 $ log 'merge()~3'
3517 1
3387 1
3518
3388
3519 $ log '(-3:tip)^'
3389 $ log '(-3:tip)^'
3520 4
3390 4
3521 6
3391 6
3522 8
3392 8
3523
3393
3524 $ log 'tip^foo'
3394 $ log 'tip^foo'
3525 hg: parse error: ^ expects a number 0, 1, or 2
3395 hg: parse error: ^ expects a number 0, 1, or 2
3526 [255]
3396 [255]
3527
3397
3528 $ log 'branchpoint()~-1'
3398 $ log 'branchpoint()~-1'
3529 abort: revision in set has more than one child!
3399 abort: revision in set has more than one child!
3530 [255]
3400 [255]
3531
3401
3532 Bogus function gets suggestions
3402 Bogus function gets suggestions
3533 $ log 'add()'
3403 $ log 'add()'
3534 hg: parse error: unknown identifier: add
3404 hg: parse error: unknown identifier: add
3535 (did you mean adds?)
3405 (did you mean adds?)
3536 [255]
3406 [255]
3537 $ log 'added()'
3407 $ log 'added()'
3538 hg: parse error: unknown identifier: added
3408 hg: parse error: unknown identifier: added
3539 (did you mean adds?)
3409 (did you mean adds?)
3540 [255]
3410 [255]
3541 $ log 'remo()'
3411 $ log 'remo()'
3542 hg: parse error: unknown identifier: remo
3412 hg: parse error: unknown identifier: remo
3543 (did you mean one of remote, removes?)
3413 (did you mean one of remote, removes?)
3544 [255]
3414 [255]
3545 $ log 'babar()'
3415 $ log 'babar()'
3546 hg: parse error: unknown identifier: babar
3416 hg: parse error: unknown identifier: babar
3547 [255]
3417 [255]
3548
3418
3549 Bogus function with a similar internal name doesn't suggest the internal name
3419 Bogus function with a similar internal name doesn't suggest the internal name
3550 $ log 'matches()'
3420 $ log 'matches()'
3551 hg: parse error: unknown identifier: matches
3421 hg: parse error: unknown identifier: matches
3552 (did you mean matching?)
3422 (did you mean matching?)
3553 [255]
3423 [255]
3554
3424
3555 Undocumented functions aren't suggested as similar either
3425 Undocumented functions aren't suggested as similar either
3556 $ log 'tagged2()'
3426 $ log 'tagged2()'
3557 hg: parse error: unknown identifier: tagged2
3427 hg: parse error: unknown identifier: tagged2
3558 [255]
3428 [255]
3559
3429
3560 multiple revspecs
3430 multiple revspecs
3561
3431
3562 $ hg log -r 'tip~1:tip' -r 'tip~2:tip~1' --template '{rev}\n'
3432 $ hg log -r 'tip~1:tip' -r 'tip~2:tip~1' --template '{rev}\n'
3563 8
3433 8
3564 9
3434 9
3565 4
3435 4
3566 5
3436 5
3567 6
3437 6
3568 7
3438 7
3569
3439
3570 test usage in revpair (with "+")
3440 test usage in revpair (with "+")
3571
3441
3572 (real pair)
3442 (real pair)
3573
3443
3574 $ hg diff -r 'tip^^' -r 'tip'
3444 $ hg diff -r 'tip^^' -r 'tip'
3575 diff -r 2326846efdab -r 24286f4ae135 .hgtags
3445 diff -r 2326846efdab -r 24286f4ae135 .hgtags
3576 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3446 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3577 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
3447 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
3578 @@ -0,0 +1,1 @@
3448 @@ -0,0 +1,1 @@
3579 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3449 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3580 $ hg diff -r 'tip^^::tip'
3450 $ hg diff -r 'tip^^::tip'
3581 diff -r 2326846efdab -r 24286f4ae135 .hgtags
3451 diff -r 2326846efdab -r 24286f4ae135 .hgtags
3582 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3452 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3583 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
3453 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
3584 @@ -0,0 +1,1 @@
3454 @@ -0,0 +1,1 @@
3585 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3455 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3586
3456
3587 (single rev)
3457 (single rev)
3588
3458
3589 $ hg diff -r 'tip^' -r 'tip^'
3459 $ hg diff -r 'tip^' -r 'tip^'
3590 $ hg diff -r 'tip^:tip^'
3460 $ hg diff -r 'tip^:tip^'
3591
3461
3592 (single rev that does not looks like a range)
3462 (single rev that does not looks like a range)
3593
3463
3594 $ hg diff -r 'tip^::tip^ or tip^'
3464 $ hg diff -r 'tip^::tip^ or tip^'
3595 diff -r d5d0dcbdc4d9 .hgtags
3465 diff -r d5d0dcbdc4d9 .hgtags
3596 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3466 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3597 +++ b/.hgtags * (glob)
3467 +++ b/.hgtags * (glob)
3598 @@ -0,0 +1,1 @@
3468 @@ -0,0 +1,1 @@
3599 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3469 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3600 $ hg diff -r 'tip^ or tip^'
3470 $ hg diff -r 'tip^ or tip^'
3601 diff -r d5d0dcbdc4d9 .hgtags
3471 diff -r d5d0dcbdc4d9 .hgtags
3602 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3472 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3603 +++ b/.hgtags * (glob)
3473 +++ b/.hgtags * (glob)
3604 @@ -0,0 +1,1 @@
3474 @@ -0,0 +1,1 @@
3605 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3475 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3606
3476
3607 (no rev)
3477 (no rev)
3608
3478
3609 $ hg diff -r 'author("babar") or author("celeste")'
3479 $ hg diff -r 'author("babar") or author("celeste")'
3610 abort: empty revision range
3480 abort: empty revision range
3611 [255]
3481 [255]
3612
3482
3613 aliases:
3483 aliases:
3614
3484
3615 $ echo '[revsetalias]' >> .hg/hgrc
3485 $ echo '[revsetalias]' >> .hg/hgrc
3616 $ echo 'm = merge()' >> .hg/hgrc
3486 $ echo 'm = merge()' >> .hg/hgrc
3617 (revset aliases can override builtin revsets)
3487 (revset aliases can override builtin revsets)
3618 $ echo 'p2($1) = p1($1)' >> .hg/hgrc
3488 $ echo 'p2($1) = p1($1)' >> .hg/hgrc
3619 $ echo 'sincem = descendants(m)' >> .hg/hgrc
3489 $ echo 'sincem = descendants(m)' >> .hg/hgrc
3620 $ echo 'd($1) = reverse(sort($1, date))' >> .hg/hgrc
3490 $ echo 'd($1) = reverse(sort($1, date))' >> .hg/hgrc
3621 $ echo 'rs(ARG1, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
3491 $ echo 'rs(ARG1, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
3622 $ echo 'rs4(ARG1, ARGA, ARGB, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
3492 $ echo 'rs4(ARG1, ARGA, ARGB, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
3623
3493
3624 $ try m
3494 $ try m
3625 ('symbol', 'm')
3495 ('symbol', 'm')
3626 * expanded:
3496 * expanded:
3627 (func
3497 (func
3628 ('symbol', 'merge')
3498 ('symbol', 'merge')
3629 None)
3499 None)
3630 * set:
3500 * set:
3631 <filteredset
3501 <filteredset
3632 <fullreposet+ 0:10>,
3502 <fullreposet+ 0:10>,
3633 <merge>>
3503 <merge>>
3634 6
3504 6
3635
3505
3636 $ HGPLAIN=1
3506 $ HGPLAIN=1
3637 $ export HGPLAIN
3507 $ export HGPLAIN
3638 $ try m
3508 $ try m
3639 ('symbol', 'm')
3509 ('symbol', 'm')
3640 abort: unknown revision 'm'!
3510 abort: unknown revision 'm'!
3641 [255]
3511 [255]
3642
3512
3643 $ HGPLAINEXCEPT=revsetalias
3513 $ HGPLAINEXCEPT=revsetalias
3644 $ export HGPLAINEXCEPT
3514 $ export HGPLAINEXCEPT
3645 $ try m
3515 $ try m
3646 ('symbol', 'm')
3516 ('symbol', 'm')
3647 * expanded:
3517 * expanded:
3648 (func
3518 (func
3649 ('symbol', 'merge')
3519 ('symbol', 'merge')
3650 None)
3520 None)
3651 * set:
3521 * set:
3652 <filteredset
3522 <filteredset
3653 <fullreposet+ 0:10>,
3523 <fullreposet+ 0:10>,
3654 <merge>>
3524 <merge>>
3655 6
3525 6
3656
3526
3657 $ unset HGPLAIN
3527 $ unset HGPLAIN
3658 $ unset HGPLAINEXCEPT
3528 $ unset HGPLAINEXCEPT
3659
3529
3660 $ try 'p2(.)'
3530 $ try 'p2(.)'
3661 (func
3531 (func
3662 ('symbol', 'p2')
3532 ('symbol', 'p2')
3663 ('symbol', '.'))
3533 ('symbol', '.'))
3664 * expanded:
3534 * expanded:
3665 (func
3535 (func
3666 ('symbol', 'p1')
3536 ('symbol', 'p1')
3667 ('symbol', '.'))
3537 ('symbol', '.'))
3668 * set:
3538 * set:
3669 <baseset+ [8]>
3539 <baseset+ [8]>
3670 8
3540 8
3671
3541
3672 $ HGPLAIN=1
3542 $ HGPLAIN=1
3673 $ export HGPLAIN
3543 $ export HGPLAIN
3674 $ try 'p2(.)'
3544 $ try 'p2(.)'
3675 (func
3545 (func
3676 ('symbol', 'p2')
3546 ('symbol', 'p2')
3677 ('symbol', '.'))
3547 ('symbol', '.'))
3678 * set:
3548 * set:
3679 <baseset+ []>
3549 <baseset+ []>
3680
3550
3681 $ HGPLAINEXCEPT=revsetalias
3551 $ HGPLAINEXCEPT=revsetalias
3682 $ export HGPLAINEXCEPT
3552 $ export HGPLAINEXCEPT
3683 $ try 'p2(.)'
3553 $ try 'p2(.)'
3684 (func
3554 (func
3685 ('symbol', 'p2')
3555 ('symbol', 'p2')
3686 ('symbol', '.'))
3556 ('symbol', '.'))
3687 * expanded:
3557 * expanded:
3688 (func
3558 (func
3689 ('symbol', 'p1')
3559 ('symbol', 'p1')
3690 ('symbol', '.'))
3560 ('symbol', '.'))
3691 * set:
3561 * set:
3692 <baseset+ [8]>
3562 <baseset+ [8]>
3693 8
3563 8
3694
3564
3695 $ unset HGPLAIN
3565 $ unset HGPLAIN
3696 $ unset HGPLAINEXCEPT
3566 $ unset HGPLAINEXCEPT
3697
3567
3698 test alias recursion
3568 test alias recursion
3699
3569
3700 $ try sincem
3570 $ try sincem
3701 ('symbol', 'sincem')
3571 ('symbol', 'sincem')
3702 * expanded:
3572 * expanded:
3703 (func
3573 (func
3704 ('symbol', 'descendants')
3574 ('symbol', 'descendants')
3705 (func
3575 (func
3706 ('symbol', 'merge')
3576 ('symbol', 'merge')
3707 None))
3577 None))
3708 * set:
3578 * set:
3709 <generatorset+>
3579 <generatorset+>
3710 6
3580 6
3711 7
3581 7
3712
3582
3713 test infinite recursion
3583 test infinite recursion
3714
3584
3715 $ echo 'recurse1 = recurse2' >> .hg/hgrc
3585 $ echo 'recurse1 = recurse2' >> .hg/hgrc
3716 $ echo 'recurse2 = recurse1' >> .hg/hgrc
3586 $ echo 'recurse2 = recurse1' >> .hg/hgrc
3717 $ try recurse1
3587 $ try recurse1
3718 ('symbol', 'recurse1')
3588 ('symbol', 'recurse1')
3719 hg: parse error: infinite expansion of revset alias "recurse1" detected
3589 hg: parse error: infinite expansion of revset alias "recurse1" detected
3720 [255]
3590 [255]
3721
3591
3722 $ echo 'level1($1, $2) = $1 or $2' >> .hg/hgrc
3592 $ echo 'level1($1, $2) = $1 or $2' >> .hg/hgrc
3723 $ echo 'level2($1, $2) = level1($2, $1)' >> .hg/hgrc
3593 $ echo 'level2($1, $2) = level1($2, $1)' >> .hg/hgrc
3724 $ try "level2(level1(1, 2), 3)"
3594 $ try "level2(level1(1, 2), 3)"
3725 (func
3595 (func
3726 ('symbol', 'level2')
3596 ('symbol', 'level2')
3727 (list
3597 (list
3728 (func
3598 (func
3729 ('symbol', 'level1')
3599 ('symbol', 'level1')
3730 (list
3600 (list
3731 ('symbol', '1')
3601 ('symbol', '1')
3732 ('symbol', '2')))
3602 ('symbol', '2')))
3733 ('symbol', '3')))
3603 ('symbol', '3')))
3734 * expanded:
3604 * expanded:
3735 (or
3605 (or
3736 (list
3606 (list
3737 ('symbol', '3')
3607 ('symbol', '3')
3738 (or
3608 (or
3739 (list
3609 (list
3740 ('symbol', '1')
3610 ('symbol', '1')
3741 ('symbol', '2')))))
3611 ('symbol', '2')))))
3742 * set:
3612 * set:
3743 <addset
3613 <addset
3744 <baseset [3]>,
3614 <baseset [3]>,
3745 <baseset [1, 2]>>
3615 <baseset [1, 2]>>
3746 3
3616 3
3747 1
3617 1
3748 2
3618 2
3749
3619
3750 test nesting and variable passing
3620 test nesting and variable passing
3751
3621
3752 $ echo 'nested($1) = nested2($1)' >> .hg/hgrc
3622 $ echo 'nested($1) = nested2($1)' >> .hg/hgrc
3753 $ echo 'nested2($1) = nested3($1)' >> .hg/hgrc
3623 $ echo 'nested2($1) = nested3($1)' >> .hg/hgrc
3754 $ echo 'nested3($1) = max($1)' >> .hg/hgrc
3624 $ echo 'nested3($1) = max($1)' >> .hg/hgrc
3755 $ try 'nested(2:5)'
3625 $ try 'nested(2:5)'
3756 (func
3626 (func
3757 ('symbol', 'nested')
3627 ('symbol', 'nested')
3758 (range
3628 (range
3759 ('symbol', '2')
3629 ('symbol', '2')
3760 ('symbol', '5')))
3630 ('symbol', '5')))
3761 * expanded:
3631 * expanded:
3762 (func
3632 (func
3763 ('symbol', 'max')
3633 ('symbol', 'max')
3764 (range
3634 (range
3765 ('symbol', '2')
3635 ('symbol', '2')
3766 ('symbol', '5')))
3636 ('symbol', '5')))
3767 * set:
3637 * set:
3768 <baseset
3638 <baseset
3769 <max
3639 <max
3770 <fullreposet+ 0:10>,
3640 <fullreposet+ 0:10>,
3771 <spanset+ 2:6>>>
3641 <spanset+ 2:6>>>
3772 5
3642 5
3773
3643
3774 test chained `or` operations are flattened at parsing phase
3644 test chained `or` operations are flattened at parsing phase
3775
3645
3776 $ echo 'chainedorops($1, $2, $3) = $1|$2|$3' >> .hg/hgrc
3646 $ echo 'chainedorops($1, $2, $3) = $1|$2|$3' >> .hg/hgrc
3777 $ try 'chainedorops(0:1, 1:2, 2:3)'
3647 $ try 'chainedorops(0:1, 1:2, 2:3)'
3778 (func
3648 (func
3779 ('symbol', 'chainedorops')
3649 ('symbol', 'chainedorops')
3780 (list
3650 (list
3781 (range
3651 (range
3782 ('symbol', '0')
3652 ('symbol', '0')
3783 ('symbol', '1'))
3653 ('symbol', '1'))
3784 (range
3654 (range
3785 ('symbol', '1')
3655 ('symbol', '1')
3786 ('symbol', '2'))
3656 ('symbol', '2'))
3787 (range
3657 (range
3788 ('symbol', '2')
3658 ('symbol', '2')
3789 ('symbol', '3'))))
3659 ('symbol', '3'))))
3790 * expanded:
3660 * expanded:
3791 (or
3661 (or
3792 (list
3662 (list
3793 (range
3663 (range
3794 ('symbol', '0')
3664 ('symbol', '0')
3795 ('symbol', '1'))
3665 ('symbol', '1'))
3796 (range
3666 (range
3797 ('symbol', '1')
3667 ('symbol', '1')
3798 ('symbol', '2'))
3668 ('symbol', '2'))
3799 (range
3669 (range
3800 ('symbol', '2')
3670 ('symbol', '2')
3801 ('symbol', '3'))))
3671 ('symbol', '3'))))
3802 * set:
3672 * set:
3803 <addset
3673 <addset
3804 <spanset+ 0:2>,
3674 <spanset+ 0:2>,
3805 <addset
3675 <addset
3806 <spanset+ 1:3>,
3676 <spanset+ 1:3>,
3807 <spanset+ 2:4>>>
3677 <spanset+ 2:4>>>
3808 0
3678 0
3809 1
3679 1
3810 2
3680 2
3811 3
3681 3
3812
3682
3813 test variable isolation, variable placeholders are rewritten as string
3683 test variable isolation, variable placeholders are rewritten as string
3814 then parsed and matched again as string. Check they do not leak too
3684 then parsed and matched again as string. Check they do not leak too
3815 far away.
3685 far away.
3816
3686
3817 $ echo 'injectparamasstring = max("$1")' >> .hg/hgrc
3687 $ echo 'injectparamasstring = max("$1")' >> .hg/hgrc
3818 $ echo 'callinjection($1) = descendants(injectparamasstring)' >> .hg/hgrc
3688 $ echo 'callinjection($1) = descendants(injectparamasstring)' >> .hg/hgrc
3819 $ try 'callinjection(2:5)'
3689 $ try 'callinjection(2:5)'
3820 (func
3690 (func
3821 ('symbol', 'callinjection')
3691 ('symbol', 'callinjection')
3822 (range
3692 (range
3823 ('symbol', '2')
3693 ('symbol', '2')
3824 ('symbol', '5')))
3694 ('symbol', '5')))
3825 * expanded:
3695 * expanded:
3826 (func
3696 (func
3827 ('symbol', 'descendants')
3697 ('symbol', 'descendants')
3828 (func
3698 (func
3829 ('symbol', 'max')
3699 ('symbol', 'max')
3830 ('string', '$1')))
3700 ('string', '$1')))
3831 abort: unknown revision '$1'!
3701 abort: unknown revision '$1'!
3832 [255]
3702 [255]
3833
3703
3834 test scope of alias expansion: 'universe' is expanded prior to 'shadowall(0)',
3704 test scope of alias expansion: 'universe' is expanded prior to 'shadowall(0)',
3835 but 'all()' should never be substituted to '0()'.
3705 but 'all()' should never be substituted to '0()'.
3836
3706
3837 $ echo 'universe = all()' >> .hg/hgrc
3707 $ echo 'universe = all()' >> .hg/hgrc
3838 $ echo 'shadowall(all) = all and universe' >> .hg/hgrc
3708 $ echo 'shadowall(all) = all and universe' >> .hg/hgrc
3839 $ try 'shadowall(0)'
3709 $ try 'shadowall(0)'
3840 (func
3710 (func
3841 ('symbol', 'shadowall')
3711 ('symbol', 'shadowall')
3842 ('symbol', '0'))
3712 ('symbol', '0'))
3843 * expanded:
3713 * expanded:
3844 (and
3714 (and
3845 ('symbol', '0')
3715 ('symbol', '0')
3846 (func
3716 (func
3847 ('symbol', 'all')
3717 ('symbol', 'all')
3848 None))
3718 None))
3849 * set:
3719 * set:
3850 <filteredset
3720 <filteredset
3851 <baseset [0]>,
3721 <baseset [0]>,
3852 <spanset+ 0:10>>
3722 <spanset+ 0:10>>
3853 0
3723 0
3854
3724
3855 test unknown reference:
3725 test unknown reference:
3856
3726
3857 $ try "unknownref(0)" --config 'revsetalias.unknownref($1)=$1:$2'
3727 $ try "unknownref(0)" --config 'revsetalias.unknownref($1)=$1:$2'
3858 (func
3728 (func
3859 ('symbol', 'unknownref')
3729 ('symbol', 'unknownref')
3860 ('symbol', '0'))
3730 ('symbol', '0'))
3861 abort: bad definition of revset alias "unknownref": invalid symbol '$2'
3731 abort: bad definition of revset alias "unknownref": invalid symbol '$2'
3862 [255]
3732 [255]
3863
3733
3864 $ hg debugrevspec --debug --config revsetalias.anotherbadone='branch(' "tip"
3734 $ hg debugrevspec --debug --config revsetalias.anotherbadone='branch(' "tip"
3865 ('symbol', 'tip')
3735 ('symbol', 'tip')
3866 warning: bad definition of revset alias "anotherbadone": at 7: not a prefix: end
3736 warning: bad definition of revset alias "anotherbadone": at 7: not a prefix: end
3867 * set:
3737 * set:
3868 <baseset [9]>
3738 <baseset [9]>
3869 9
3739 9
3870
3740
3871 $ try 'tip'
3741 $ try 'tip'
3872 ('symbol', 'tip')
3742 ('symbol', 'tip')
3873 * set:
3743 * set:
3874 <baseset [9]>
3744 <baseset [9]>
3875 9
3745 9
3876
3746
3877 $ hg debugrevspec --debug --config revsetalias.'bad name'='tip' "tip"
3747 $ hg debugrevspec --debug --config revsetalias.'bad name'='tip' "tip"
3878 ('symbol', 'tip')
3748 ('symbol', 'tip')
3879 warning: bad declaration of revset alias "bad name": at 4: invalid token
3749 warning: bad declaration of revset alias "bad name": at 4: invalid token
3880 * set:
3750 * set:
3881 <baseset [9]>
3751 <baseset [9]>
3882 9
3752 9
3883 $ echo 'strictreplacing($1, $10) = $10 or desc("$1")' >> .hg/hgrc
3753 $ echo 'strictreplacing($1, $10) = $10 or desc("$1")' >> .hg/hgrc
3884 $ try 'strictreplacing("foo", tip)'
3754 $ try 'strictreplacing("foo", tip)'
3885 (func
3755 (func
3886 ('symbol', 'strictreplacing')
3756 ('symbol', 'strictreplacing')
3887 (list
3757 (list
3888 ('string', 'foo')
3758 ('string', 'foo')
3889 ('symbol', 'tip')))
3759 ('symbol', 'tip')))
3890 * expanded:
3760 * expanded:
3891 (or
3761 (or
3892 (list
3762 (list
3893 ('symbol', 'tip')
3763 ('symbol', 'tip')
3894 (func
3764 (func
3895 ('symbol', 'desc')
3765 ('symbol', 'desc')
3896 ('string', '$1'))))
3766 ('string', '$1'))))
3897 * set:
3767 * set:
3898 <addset
3768 <addset
3899 <baseset [9]>,
3769 <baseset [9]>,
3900 <filteredset
3770 <filteredset
3901 <fullreposet+ 0:10>,
3771 <fullreposet+ 0:10>,
3902 <desc '$1'>>>
3772 <desc '$1'>>>
3903 9
3773 9
3904
3774
3905 $ try 'd(2:5)'
3775 $ try 'd(2:5)'
3906 (func
3776 (func
3907 ('symbol', 'd')
3777 ('symbol', 'd')
3908 (range
3778 (range
3909 ('symbol', '2')
3779 ('symbol', '2')
3910 ('symbol', '5')))
3780 ('symbol', '5')))
3911 * expanded:
3781 * expanded:
3912 (func
3782 (func
3913 ('symbol', 'reverse')
3783 ('symbol', 'reverse')
3914 (func
3784 (func
3915 ('symbol', 'sort')
3785 ('symbol', 'sort')
3916 (list
3786 (list
3917 (range
3787 (range
3918 ('symbol', '2')
3788 ('symbol', '2')
3919 ('symbol', '5'))
3789 ('symbol', '5'))
3920 ('symbol', 'date'))))
3790 ('symbol', 'date'))))
3921 * set:
3791 * set:
3922 <baseset [4, 5, 3, 2]>
3792 <baseset [4, 5, 3, 2]>
3923 4
3793 4
3924 5
3794 5
3925 3
3795 3
3926 2
3796 2
3927 $ try 'rs(2 or 3, date)'
3797 $ try 'rs(2 or 3, date)'
3928 (func
3798 (func
3929 ('symbol', 'rs')
3799 ('symbol', 'rs')
3930 (list
3800 (list
3931 (or
3801 (or
3932 (list
3802 (list
3933 ('symbol', '2')
3803 ('symbol', '2')
3934 ('symbol', '3')))
3804 ('symbol', '3')))
3935 ('symbol', 'date')))
3805 ('symbol', 'date')))
3936 * expanded:
3806 * expanded:
3937 (func
3807 (func
3938 ('symbol', 'reverse')
3808 ('symbol', 'reverse')
3939 (func
3809 (func
3940 ('symbol', 'sort')
3810 ('symbol', 'sort')
3941 (list
3811 (list
3942 (or
3812 (or
3943 (list
3813 (list
3944 ('symbol', '2')
3814 ('symbol', '2')
3945 ('symbol', '3')))
3815 ('symbol', '3')))
3946 ('symbol', 'date'))))
3816 ('symbol', 'date'))))
3947 * set:
3817 * set:
3948 <baseset [3, 2]>
3818 <baseset [3, 2]>
3949 3
3819 3
3950 2
3820 2
3951 $ try 'rs()'
3821 $ try 'rs()'
3952 (func
3822 (func
3953 ('symbol', 'rs')
3823 ('symbol', 'rs')
3954 None)
3824 None)
3955 hg: parse error: invalid number of arguments: 0
3825 hg: parse error: invalid number of arguments: 0
3956 [255]
3826 [255]
3957 $ try 'rs(2)'
3827 $ try 'rs(2)'
3958 (func
3828 (func
3959 ('symbol', 'rs')
3829 ('symbol', 'rs')
3960 ('symbol', '2'))
3830 ('symbol', '2'))
3961 hg: parse error: invalid number of arguments: 1
3831 hg: parse error: invalid number of arguments: 1
3962 [255]
3832 [255]
3963 $ try 'rs(2, data, 7)'
3833 $ try 'rs(2, data, 7)'
3964 (func
3834 (func
3965 ('symbol', 'rs')
3835 ('symbol', 'rs')
3966 (list
3836 (list
3967 ('symbol', '2')
3837 ('symbol', '2')
3968 ('symbol', 'data')
3838 ('symbol', 'data')
3969 ('symbol', '7')))
3839 ('symbol', '7')))
3970 hg: parse error: invalid number of arguments: 3
3840 hg: parse error: invalid number of arguments: 3
3971 [255]
3841 [255]
3972 $ try 'rs4(2 or 3, x, x, date)'
3842 $ try 'rs4(2 or 3, x, x, date)'
3973 (func
3843 (func
3974 ('symbol', 'rs4')
3844 ('symbol', 'rs4')
3975 (list
3845 (list
3976 (or
3846 (or
3977 (list
3847 (list
3978 ('symbol', '2')
3848 ('symbol', '2')
3979 ('symbol', '3')))
3849 ('symbol', '3')))
3980 ('symbol', 'x')
3850 ('symbol', 'x')
3981 ('symbol', 'x')
3851 ('symbol', 'x')
3982 ('symbol', 'date')))
3852 ('symbol', 'date')))
3983 * expanded:
3853 * expanded:
3984 (func
3854 (func
3985 ('symbol', 'reverse')
3855 ('symbol', 'reverse')
3986 (func
3856 (func
3987 ('symbol', 'sort')
3857 ('symbol', 'sort')
3988 (list
3858 (list
3989 (or
3859 (or
3990 (list
3860 (list
3991 ('symbol', '2')
3861 ('symbol', '2')
3992 ('symbol', '3')))
3862 ('symbol', '3')))
3993 ('symbol', 'date'))))
3863 ('symbol', 'date'))))
3994 * set:
3864 * set:
3995 <baseset [3, 2]>
3865 <baseset [3, 2]>
3996 3
3866 3
3997 2
3867 2
3998
3868
3999 issue4553: check that revset aliases override existing hash prefix
3869 issue4553: check that revset aliases override existing hash prefix
4000
3870
4001 $ hg log -qr e
3871 $ hg log -qr e
4002 6:e0cc66ef77e8
3872 6:e0cc66ef77e8
4003
3873
4004 $ hg log -qr e --config revsetalias.e="all()"
3874 $ hg log -qr e --config revsetalias.e="all()"
4005 0:2785f51eece5
3875 0:2785f51eece5
4006 1:d75937da8da0
3876 1:d75937da8da0
4007 2:5ed5505e9f1c
3877 2:5ed5505e9f1c
4008 3:8528aa5637f2
3878 3:8528aa5637f2
4009 4:2326846efdab
3879 4:2326846efdab
4010 5:904fa392b941
3880 5:904fa392b941
4011 6:e0cc66ef77e8
3881 6:e0cc66ef77e8
4012 7:013af1973af4
3882 7:013af1973af4
4013 8:d5d0dcbdc4d9
3883 8:d5d0dcbdc4d9
4014 9:24286f4ae135
3884 9:24286f4ae135
4015
3885
4016 $ hg log -qr e: --config revsetalias.e="0"
3886 $ hg log -qr e: --config revsetalias.e="0"
4017 0:2785f51eece5
3887 0:2785f51eece5
4018 1:d75937da8da0
3888 1:d75937da8da0
4019 2:5ed5505e9f1c
3889 2:5ed5505e9f1c
4020 3:8528aa5637f2
3890 3:8528aa5637f2
4021 4:2326846efdab
3891 4:2326846efdab
4022 5:904fa392b941
3892 5:904fa392b941
4023 6:e0cc66ef77e8
3893 6:e0cc66ef77e8
4024 7:013af1973af4
3894 7:013af1973af4
4025 8:d5d0dcbdc4d9
3895 8:d5d0dcbdc4d9
4026 9:24286f4ae135
3896 9:24286f4ae135
4027
3897
4028 $ hg log -qr :e --config revsetalias.e="9"
3898 $ hg log -qr :e --config revsetalias.e="9"
4029 0:2785f51eece5
3899 0:2785f51eece5
4030 1:d75937da8da0
3900 1:d75937da8da0
4031 2:5ed5505e9f1c
3901 2:5ed5505e9f1c
4032 3:8528aa5637f2
3902 3:8528aa5637f2
4033 4:2326846efdab
3903 4:2326846efdab
4034 5:904fa392b941
3904 5:904fa392b941
4035 6:e0cc66ef77e8
3905 6:e0cc66ef77e8
4036 7:013af1973af4
3906 7:013af1973af4
4037 8:d5d0dcbdc4d9
3907 8:d5d0dcbdc4d9
4038 9:24286f4ae135
3908 9:24286f4ae135
4039
3909
4040 $ hg log -qr e:
3910 $ hg log -qr e:
4041 6:e0cc66ef77e8
3911 6:e0cc66ef77e8
4042 7:013af1973af4
3912 7:013af1973af4
4043 8:d5d0dcbdc4d9
3913 8:d5d0dcbdc4d9
4044 9:24286f4ae135
3914 9:24286f4ae135
4045
3915
4046 $ hg log -qr :e
3916 $ hg log -qr :e
4047 0:2785f51eece5
3917 0:2785f51eece5
4048 1:d75937da8da0
3918 1:d75937da8da0
4049 2:5ed5505e9f1c
3919 2:5ed5505e9f1c
4050 3:8528aa5637f2
3920 3:8528aa5637f2
4051 4:2326846efdab
3921 4:2326846efdab
4052 5:904fa392b941
3922 5:904fa392b941
4053 6:e0cc66ef77e8
3923 6:e0cc66ef77e8
4054
3924
4055 issue2549 - correct optimizations
3925 issue2549 - correct optimizations
4056
3926
4057 $ try 'limit(1 or 2 or 3, 2) and not 2'
3927 $ try 'limit(1 or 2 or 3, 2) and not 2'
4058 (and
3928 (and
4059 (func
3929 (func
4060 ('symbol', 'limit')
3930 ('symbol', 'limit')
4061 (list
3931 (list
4062 (or
3932 (or
4063 (list
3933 (list
4064 ('symbol', '1')
3934 ('symbol', '1')
4065 ('symbol', '2')
3935 ('symbol', '2')
4066 ('symbol', '3')))
3936 ('symbol', '3')))
4067 ('symbol', '2')))
3937 ('symbol', '2')))
4068 (not
3938 (not
4069 ('symbol', '2')))
3939 ('symbol', '2')))
4070 * set:
3940 * set:
4071 <filteredset
3941 <filteredset
4072 <baseset [1, 2]>,
3942 <baseset [1, 2]>,
4073 <not
3943 <not
4074 <baseset [2]>>>
3944 <baseset [2]>>>
4075 1
3945 1
4076 $ try 'max(1 or 2) and not 2'
3946 $ try 'max(1 or 2) and not 2'
4077 (and
3947 (and
4078 (func
3948 (func
4079 ('symbol', 'max')
3949 ('symbol', 'max')
4080 (or
3950 (or
4081 (list
3951 (list
4082 ('symbol', '1')
3952 ('symbol', '1')
4083 ('symbol', '2'))))
3953 ('symbol', '2'))))
4084 (not
3954 (not
4085 ('symbol', '2')))
3955 ('symbol', '2')))
4086 * set:
3956 * set:
4087 <filteredset
3957 <filteredset
4088 <baseset
3958 <baseset
4089 <max
3959 <max
4090 <fullreposet+ 0:10>,
3960 <fullreposet+ 0:10>,
4091 <baseset [1, 2]>>>,
3961 <baseset [1, 2]>>>,
4092 <not
3962 <not
4093 <baseset [2]>>>
3963 <baseset [2]>>>
4094 $ try 'min(1 or 2) and not 1'
3964 $ try 'min(1 or 2) and not 1'
4095 (and
3965 (and
4096 (func
3966 (func
4097 ('symbol', 'min')
3967 ('symbol', 'min')
4098 (or
3968 (or
4099 (list
3969 (list
4100 ('symbol', '1')
3970 ('symbol', '1')
4101 ('symbol', '2'))))
3971 ('symbol', '2'))))
4102 (not
3972 (not
4103 ('symbol', '1')))
3973 ('symbol', '1')))
4104 * set:
3974 * set:
4105 <filteredset
3975 <filteredset
4106 <baseset
3976 <baseset
4107 <min
3977 <min
4108 <fullreposet+ 0:10>,
3978 <fullreposet+ 0:10>,
4109 <baseset [1, 2]>>>,
3979 <baseset [1, 2]>>>,
4110 <not
3980 <not
4111 <baseset [1]>>>
3981 <baseset [1]>>>
4112 $ try 'last(1 or 2, 1) and not 2'
3982 $ try 'last(1 or 2, 1) and not 2'
4113 (and
3983 (and
4114 (func
3984 (func
4115 ('symbol', 'last')
3985 ('symbol', 'last')
4116 (list
3986 (list
4117 (or
3987 (or
4118 (list
3988 (list
4119 ('symbol', '1')
3989 ('symbol', '1')
4120 ('symbol', '2')))
3990 ('symbol', '2')))
4121 ('symbol', '1')))
3991 ('symbol', '1')))
4122 (not
3992 (not
4123 ('symbol', '2')))
3993 ('symbol', '2')))
4124 * set:
3994 * set:
4125 <filteredset
3995 <filteredset
4126 <baseset [2]>,
3996 <baseset [2]>,
4127 <not
3997 <not
4128 <baseset [2]>>>
3998 <baseset [2]>>>
4129
3999
4130 issue4289 - ordering of built-ins
4000 issue4289 - ordering of built-ins
4131 $ hg log -M -q -r 3:2
4001 $ hg log -M -q -r 3:2
4132 3:8528aa5637f2
4002 3:8528aa5637f2
4133 2:5ed5505e9f1c
4003 2:5ed5505e9f1c
4134
4004
4135 test revsets started with 40-chars hash (issue3669)
4005 test revsets started with 40-chars hash (issue3669)
4136
4006
4137 $ ISSUE3669_TIP=`hg tip --template '{node}'`
4007 $ ISSUE3669_TIP=`hg tip --template '{node}'`
4138 $ hg log -r "${ISSUE3669_TIP}" --template '{rev}\n'
4008 $ hg log -r "${ISSUE3669_TIP}" --template '{rev}\n'
4139 9
4009 9
4140 $ hg log -r "${ISSUE3669_TIP}^" --template '{rev}\n'
4010 $ hg log -r "${ISSUE3669_TIP}^" --template '{rev}\n'
4141 8
4011 8
4142
4012
4143 test or-ed indirect predicates (issue3775)
4013 test or-ed indirect predicates (issue3775)
4144
4014
4145 $ log '6 or 6^1' | sort
4015 $ log '6 or 6^1' | sort
4146 5
4016 5
4147 6
4017 6
4148 $ log '6^1 or 6' | sort
4018 $ log '6^1 or 6' | sort
4149 5
4019 5
4150 6
4020 6
4151 $ log '4 or 4~1' | sort
4021 $ log '4 or 4~1' | sort
4152 2
4022 2
4153 4
4023 4
4154 $ log '4~1 or 4' | sort
4024 $ log '4~1 or 4' | sort
4155 2
4025 2
4156 4
4026 4
4157 $ log '(0 or 2):(4 or 6) or 0 or 6' | sort
4027 $ log '(0 or 2):(4 or 6) or 0 or 6' | sort
4158 0
4028 0
4159 1
4029 1
4160 2
4030 2
4161 3
4031 3
4162 4
4032 4
4163 5
4033 5
4164 6
4034 6
4165 $ log '0 or 6 or (0 or 2):(4 or 6)' | sort
4035 $ log '0 or 6 or (0 or 2):(4 or 6)' | sort
4166 0
4036 0
4167 1
4037 1
4168 2
4038 2
4169 3
4039 3
4170 4
4040 4
4171 5
4041 5
4172 6
4042 6
4173
4043
4174 tests for 'remote()' predicate:
4044 tests for 'remote()' predicate:
4175 #. (csets in remote) (id) (remote)
4045 #. (csets in remote) (id) (remote)
4176 1. less than local current branch "default"
4046 1. less than local current branch "default"
4177 2. same with local specified "default"
4047 2. same with local specified "default"
4178 3. more than local specified specified
4048 3. more than local specified specified
4179
4049
4180 $ hg clone --quiet -U . ../remote3
4050 $ hg clone --quiet -U . ../remote3
4181 $ cd ../remote3
4051 $ cd ../remote3
4182 $ hg update -q 7
4052 $ hg update -q 7
4183 $ echo r > r
4053 $ echo r > r
4184 $ hg ci -Aqm 10
4054 $ hg ci -Aqm 10
4185 $ log 'remote()'
4055 $ log 'remote()'
4186 7
4056 7
4187 $ log 'remote("a-b-c-")'
4057 $ log 'remote("a-b-c-")'
4188 2
4058 2
4189 $ cd ../repo
4059 $ cd ../repo
4190 $ log 'remote(".a.b.c.", "../remote3")'
4060 $ log 'remote(".a.b.c.", "../remote3")'
4191
4061
4192 tests for concatenation of strings/symbols by "##"
4062 tests for concatenation of strings/symbols by "##"
4193
4063
4194 $ try "278 ## '5f5' ## 1ee ## 'ce5'"
4064 $ try "278 ## '5f5' ## 1ee ## 'ce5'"
4195 (_concat
4065 (_concat
4196 (_concat
4066 (_concat
4197 (_concat
4067 (_concat
4198 ('symbol', '278')
4068 ('symbol', '278')
4199 ('string', '5f5'))
4069 ('string', '5f5'))
4200 ('symbol', '1ee'))
4070 ('symbol', '1ee'))
4201 ('string', 'ce5'))
4071 ('string', 'ce5'))
4202 * concatenated:
4072 * concatenated:
4203 ('string', '2785f51eece5')
4073 ('string', '2785f51eece5')
4204 * set:
4074 * set:
4205 <baseset [0]>
4075 <baseset [0]>
4206 0
4076 0
4207
4077
4208 $ echo 'cat4($1, $2, $3, $4) = $1 ## $2 ## $3 ## $4' >> .hg/hgrc
4078 $ echo 'cat4($1, $2, $3, $4) = $1 ## $2 ## $3 ## $4' >> .hg/hgrc
4209 $ try "cat4(278, '5f5', 1ee, 'ce5')"
4079 $ try "cat4(278, '5f5', 1ee, 'ce5')"
4210 (func
4080 (func
4211 ('symbol', 'cat4')
4081 ('symbol', 'cat4')
4212 (list
4082 (list
4213 ('symbol', '278')
4083 ('symbol', '278')
4214 ('string', '5f5')
4084 ('string', '5f5')
4215 ('symbol', '1ee')
4085 ('symbol', '1ee')
4216 ('string', 'ce5')))
4086 ('string', 'ce5')))
4217 * expanded:
4087 * expanded:
4218 (_concat
4088 (_concat
4219 (_concat
4089 (_concat
4220 (_concat
4090 (_concat
4221 ('symbol', '278')
4091 ('symbol', '278')
4222 ('string', '5f5'))
4092 ('string', '5f5'))
4223 ('symbol', '1ee'))
4093 ('symbol', '1ee'))
4224 ('string', 'ce5'))
4094 ('string', 'ce5'))
4225 * concatenated:
4095 * concatenated:
4226 ('string', '2785f51eece5')
4096 ('string', '2785f51eece5')
4227 * set:
4097 * set:
4228 <baseset [0]>
4098 <baseset [0]>
4229 0
4099 0
4230
4100
4231 (check concatenation in alias nesting)
4101 (check concatenation in alias nesting)
4232
4102
4233 $ echo 'cat2($1, $2) = $1 ## $2' >> .hg/hgrc
4103 $ echo 'cat2($1, $2) = $1 ## $2' >> .hg/hgrc
4234 $ echo 'cat2x2($1, $2, $3, $4) = cat2($1 ## $2, $3 ## $4)' >> .hg/hgrc
4104 $ echo 'cat2x2($1, $2, $3, $4) = cat2($1 ## $2, $3 ## $4)' >> .hg/hgrc
4235 $ log "cat2x2(278, '5f5', 1ee, 'ce5')"
4105 $ log "cat2x2(278, '5f5', 1ee, 'ce5')"
4236 0
4106 0
4237
4107
4238 (check operator priority)
4108 (check operator priority)
4239
4109
4240 $ echo 'cat2n2($1, $2, $3, $4) = $1 ## $2 or $3 ## $4~2' >> .hg/hgrc
4110 $ echo 'cat2n2($1, $2, $3, $4) = $1 ## $2 or $3 ## $4~2' >> .hg/hgrc
4241 $ log "cat2n2(2785f5, 1eece5, 24286f, 4ae135)"
4111 $ log "cat2n2(2785f5, 1eece5, 24286f, 4ae135)"
4242 0
4112 0
4243 4
4113 4
4244
4114
4245 $ cd ..
4115 $ cd ..
4246
4116
4247 prepare repository that has "default" branches of multiple roots
4117 prepare repository that has "default" branches of multiple roots
4248
4118
4249 $ hg init namedbranch
4119 $ hg init namedbranch
4250 $ cd namedbranch
4120 $ cd namedbranch
4251
4121
4252 $ echo default0 >> a
4122 $ echo default0 >> a
4253 $ hg ci -Aqm0
4123 $ hg ci -Aqm0
4254 $ echo default1 >> a
4124 $ echo default1 >> a
4255 $ hg ci -m1
4125 $ hg ci -m1
4256
4126
4257 $ hg branch -q stable
4127 $ hg branch -q stable
4258 $ echo stable2 >> a
4128 $ echo stable2 >> a
4259 $ hg ci -m2
4129 $ hg ci -m2
4260 $ echo stable3 >> a
4130 $ echo stable3 >> a
4261 $ hg ci -m3
4131 $ hg ci -m3
4262
4132
4263 $ hg update -q null
4133 $ hg update -q null
4264 $ echo default4 >> a
4134 $ echo default4 >> a
4265 $ hg ci -Aqm4
4135 $ hg ci -Aqm4
4266 $ echo default5 >> a
4136 $ echo default5 >> a
4267 $ hg ci -m5
4137 $ hg ci -m5
4268
4138
4269 "null" revision belongs to "default" branch (issue4683)
4139 "null" revision belongs to "default" branch (issue4683)
4270
4140
4271 $ log 'branch(null)'
4141 $ log 'branch(null)'
4272 0
4142 0
4273 1
4143 1
4274 4
4144 4
4275 5
4145 5
4276
4146
4277 "null" revision belongs to "default" branch, but it shouldn't appear in set
4147 "null" revision belongs to "default" branch, but it shouldn't appear in set
4278 unless explicitly specified (issue4682)
4148 unless explicitly specified (issue4682)
4279
4149
4280 $ log 'children(branch(default))'
4150 $ log 'children(branch(default))'
4281 1
4151 1
4282 2
4152 2
4283 5
4153 5
4284
4154
4285 $ cd ..
4155 $ cd ..
4286
4156
4287 test author/desc/keyword in problematic encoding
4157 test author/desc/keyword in problematic encoding
4288 # unicode: cp932:
4158 # unicode: cp932:
4289 # u30A2 0x83 0x41(= 'A')
4159 # u30A2 0x83 0x41(= 'A')
4290 # u30C2 0x83 0x61(= 'a')
4160 # u30C2 0x83 0x61(= 'a')
4291
4161
4292 $ hg init problematicencoding
4162 $ hg init problematicencoding
4293 $ cd problematicencoding
4163 $ cd problematicencoding
4294
4164
4295 $ $PYTHON > setup.sh <<EOF
4165 $ $PYTHON > setup.sh <<EOF
4296 > print u'''
4166 > print u'''
4297 > echo a > text
4167 > echo a > text
4298 > hg add text
4168 > hg add text
4299 > hg --encoding utf-8 commit -u '\u30A2' -m none
4169 > hg --encoding utf-8 commit -u '\u30A2' -m none
4300 > echo b > text
4170 > echo b > text
4301 > hg --encoding utf-8 commit -u '\u30C2' -m none
4171 > hg --encoding utf-8 commit -u '\u30C2' -m none
4302 > echo c > text
4172 > echo c > text
4303 > hg --encoding utf-8 commit -u none -m '\u30A2'
4173 > hg --encoding utf-8 commit -u none -m '\u30A2'
4304 > echo d > text
4174 > echo d > text
4305 > hg --encoding utf-8 commit -u none -m '\u30C2'
4175 > hg --encoding utf-8 commit -u none -m '\u30C2'
4306 > '''.encode('utf-8')
4176 > '''.encode('utf-8')
4307 > EOF
4177 > EOF
4308 $ sh < setup.sh
4178 $ sh < setup.sh
4309
4179
4310 test in problematic encoding
4180 test in problematic encoding
4311 $ $PYTHON > test.sh <<EOF
4181 $ $PYTHON > test.sh <<EOF
4312 > print u'''
4182 > print u'''
4313 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30A2)'
4183 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30A2)'
4314 > echo ====
4184 > echo ====
4315 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30C2)'
4185 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30C2)'
4316 > echo ====
4186 > echo ====
4317 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30A2)'
4187 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30A2)'
4318 > echo ====
4188 > echo ====
4319 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30C2)'
4189 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30C2)'
4320 > echo ====
4190 > echo ====
4321 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30A2)'
4191 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30A2)'
4322 > echo ====
4192 > echo ====
4323 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30C2)'
4193 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30C2)'
4324 > '''.encode('cp932')
4194 > '''.encode('cp932')
4325 > EOF
4195 > EOF
4326 $ sh < test.sh
4196 $ sh < test.sh
4327 0
4197 0
4328 ====
4198 ====
4329 1
4199 1
4330 ====
4200 ====
4331 2
4201 2
4332 ====
4202 ====
4333 3
4203 3
4334 ====
4204 ====
4335 0
4205 0
4336 2
4206 2
4337 ====
4207 ====
4338 1
4208 1
4339 3
4209 3
4340
4210
4341 test error message of bad revset
4211 test error message of bad revset
4342 $ hg log -r 'foo\\'
4212 $ hg log -r 'foo\\'
4343 hg: parse error at 3: syntax error in revset 'foo\\'
4213 hg: parse error at 3: syntax error in revset 'foo\\'
4344 [255]
4214 [255]
4345
4215
4346 $ cd ..
4216 $ cd ..
4347
4217
4348 Test that revset predicate of extension isn't loaded at failure of
4218 Test that revset predicate of extension isn't loaded at failure of
4349 loading it
4219 loading it
4350
4220
4351 $ cd repo
4221 $ cd repo
4352
4222
4353 $ cat <<EOF > $TESTTMP/custompredicate.py
4223 $ cat <<EOF > $TESTTMP/custompredicate.py
4354 > from mercurial import error, registrar, revset
4224 > from mercurial import error, registrar, revset
4355 >
4225 >
4356 > revsetpredicate = registrar.revsetpredicate()
4226 > revsetpredicate = registrar.revsetpredicate()
4357 >
4227 >
4358 > @revsetpredicate('custom1()')
4228 > @revsetpredicate('custom1()')
4359 > def custom1(repo, subset, x):
4229 > def custom1(repo, subset, x):
4360 > return revset.baseset([1])
4230 > return revset.baseset([1])
4361 >
4231 >
4362 > raise error.Abort('intentional failure of loading extension')
4232 > raise error.Abort('intentional failure of loading extension')
4363 > EOF
4233 > EOF
4364 $ cat <<EOF > .hg/hgrc
4234 $ cat <<EOF > .hg/hgrc
4365 > [extensions]
4235 > [extensions]
4366 > custompredicate = $TESTTMP/custompredicate.py
4236 > custompredicate = $TESTTMP/custompredicate.py
4367 > EOF
4237 > EOF
4368
4238
4369 $ hg debugrevspec "custom1()"
4239 $ hg debugrevspec "custom1()"
4370 *** failed to import extension custompredicate from $TESTTMP/custompredicate.py: intentional failure of loading extension
4240 *** failed to import extension custompredicate from $TESTTMP/custompredicate.py: intentional failure of loading extension
4371 hg: parse error: unknown identifier: custom1
4241 hg: parse error: unknown identifier: custom1
4372 [255]
4242 [255]
4373
4243
4374 Test repo.anyrevs with customized revset overrides
4244 Test repo.anyrevs with customized revset overrides
4375
4245
4376 $ cat > $TESTTMP/printprevset.py <<EOF
4246 $ cat > $TESTTMP/printprevset.py <<EOF
4377 > from mercurial import encoding, registrar
4247 > from mercurial import encoding, registrar
4378 > cmdtable = {}
4248 > cmdtable = {}
4379 > command = registrar.command(cmdtable)
4249 > command = registrar.command(cmdtable)
4380 > @command('printprevset')
4250 > @command('printprevset')
4381 > def printprevset(ui, repo):
4251 > def printprevset(ui, repo):
4382 > alias = {}
4252 > alias = {}
4383 > p = encoding.environ.get('P')
4253 > p = encoding.environ.get('P')
4384 > if p:
4254 > if p:
4385 > alias['P'] = p
4255 > alias['P'] = p
4386 > revs = repo.anyrevs(['P'], user=True, localalias=alias)
4256 > revs = repo.anyrevs(['P'], user=True, localalias=alias)
4387 > ui.write('P=%r\n' % list(revs))
4257 > ui.write('P=%r\n' % list(revs))
4388 > EOF
4258 > EOF
4389
4259
4390 $ cat >> .hg/hgrc <<EOF
4260 $ cat >> .hg/hgrc <<EOF
4391 > custompredicate = !
4261 > custompredicate = !
4392 > printprevset = $TESTTMP/printprevset.py
4262 > printprevset = $TESTTMP/printprevset.py
4393 > EOF
4263 > EOF
4394
4264
4395 $ hg --config revsetalias.P=1 printprevset
4265 $ hg --config revsetalias.P=1 printprevset
4396 P=[1]
4266 P=[1]
4397 $ P=3 hg --config revsetalias.P=2 printprevset
4267 $ P=3 hg --config revsetalias.P=2 printprevset
4398 P=[3]
4268 P=[3]
4399
4269
4400 $ cd ..
4270 $ cd ..
4401
4271
4402 Test obsstore related revsets
4272 Test obsstore related revsets
4403
4273
4404 $ hg init repo1
4274 $ hg init repo1
4405 $ cd repo1
4275 $ cd repo1
4406 $ cat <<EOF >> .hg/hgrc
4276 $ cat <<EOF >> .hg/hgrc
4407 > [experimental]
4277 > [experimental]
4408 > stabilization = createmarkers
4278 > stabilization = createmarkers
4409 > EOF
4279 > EOF
4410
4280
4411 $ hg debugdrawdag <<'EOS'
4281 $ hg debugdrawdag <<'EOS'
4412 > F G
4282 > F G
4413 > |/ # split: B -> E, F
4283 > |/ # split: B -> E, F
4414 > B C D E # amend: B -> C -> D
4284 > B C D E # amend: B -> C -> D
4415 > \|/ | # amend: F -> G
4285 > \|/ | # amend: F -> G
4416 > A A Z # amend: A -> Z
4286 > A A Z # amend: A -> Z
4417 > EOS
4287 > EOS
4418
4288
4419 $ hg log -r 'successors(Z)' -T '{desc}\n'
4289 $ hg log -r 'successors(Z)' -T '{desc}\n'
4420 Z
4290 Z
4421
4291
4422 $ hg log -r 'successors(F)' -T '{desc}\n'
4292 $ hg log -r 'successors(F)' -T '{desc}\n'
4423 F
4293 F
4424 G
4294 G
4425
4295
4426 $ hg tag --remove --local C D E F G
4296 $ hg tag --remove --local C D E F G
4427
4297
4428 $ hg log -r 'successors(B)' -T '{desc}\n'
4298 $ hg log -r 'successors(B)' -T '{desc}\n'
4429 B
4299 B
4430 D
4300 D
4431 E
4301 E
4432 G
4302 G
4433
4303
4434 $ hg log -r 'successors(B)' -T '{desc}\n' --hidden
4304 $ hg log -r 'successors(B)' -T '{desc}\n' --hidden
4435 B
4305 B
4436 C
4306 C
4437 D
4307 D
4438 E
4308 E
4439 F
4309 F
4440 G
4310 G
4441
4311
4442 $ hg log -r 'successors(B)-obsolete()' -T '{desc}\n' --hidden
4312 $ hg log -r 'successors(B)-obsolete()' -T '{desc}\n' --hidden
4443 D
4313 D
4444 E
4314 E
4445 G
4315 G
4446
4316
4447 $ hg log -r 'successors(B+A)-contentdivergent()' -T '{desc}\n'
4317 $ hg log -r 'successors(B+A)-contentdivergent()' -T '{desc}\n'
4448 A
4318 A
4449 Z
4319 Z
4450 B
4320 B
4451
4321
4452 $ hg log -r 'successors(B+A)-contentdivergent()-obsolete()' -T '{desc}\n'
4322 $ hg log -r 'successors(B+A)-contentdivergent()-obsolete()' -T '{desc}\n'
4453 Z
4323 Z
General Comments 0
You need to be logged in to leave comments. Login now