##// END OF EJS Templates
revset: add support of keyword arguments to ancestors() and descendants()...
Yuya Nishihara -
r32914:577759ef default
parent child Browse files
Show More
@@ -1,2020 +1,2028
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 pathutil,
22 pathutil,
23 phases,
23 phases,
24 registrar,
24 registrar,
25 repoview,
25 repoview,
26 revsetlang,
26 revsetlang,
27 scmutil,
27 scmutil,
28 smartset,
28 smartset,
29 util,
29 util,
30 )
30 )
31
31
32 # helpers for processing parsed tree
32 # helpers for processing parsed tree
33 getsymbol = revsetlang.getsymbol
33 getsymbol = revsetlang.getsymbol
34 getstring = revsetlang.getstring
34 getstring = revsetlang.getstring
35 getinteger = revsetlang.getinteger
35 getinteger = revsetlang.getinteger
36 getboolean = revsetlang.getboolean
36 getboolean = revsetlang.getboolean
37 getlist = revsetlang.getlist
37 getlist = revsetlang.getlist
38 getrange = revsetlang.getrange
38 getrange = revsetlang.getrange
39 getargs = revsetlang.getargs
39 getargs = revsetlang.getargs
40 getargsdict = revsetlang.getargsdict
40 getargsdict = revsetlang.getargsdict
41
41
42 # constants used as an argument of match() and matchany()
42 # constants used as an argument of match() and matchany()
43 anyorder = revsetlang.anyorder
43 anyorder = revsetlang.anyorder
44 defineorder = revsetlang.defineorder
44 defineorder = revsetlang.defineorder
45 followorder = revsetlang.followorder
45 followorder = revsetlang.followorder
46
46
47 baseset = smartset.baseset
47 baseset = smartset.baseset
48 generatorset = smartset.generatorset
48 generatorset = smartset.generatorset
49 spanset = smartset.spanset
49 spanset = smartset.spanset
50 fullreposet = smartset.fullreposet
50 fullreposet = smartset.fullreposet
51
51
52 # helpers
52 # helpers
53
53
54 def getset(repo, subset, x):
54 def getset(repo, subset, x):
55 if not x:
55 if not x:
56 raise error.ParseError(_("missing argument"))
56 raise error.ParseError(_("missing argument"))
57 return methods[x[0]](repo, subset, *x[1:])
57 return methods[x[0]](repo, subset, *x[1:])
58
58
59 def _getrevsource(repo, r):
59 def _getrevsource(repo, r):
60 extra = repo[r].extra()
60 extra = repo[r].extra()
61 for label in ('source', 'transplant_source', 'rebase_source'):
61 for label in ('source', 'transplant_source', 'rebase_source'):
62 if label in extra:
62 if label in extra:
63 try:
63 try:
64 return repo[extra[label]].rev()
64 return repo[extra[label]].rev()
65 except error.RepoLookupError:
65 except error.RepoLookupError:
66 pass
66 pass
67 return None
67 return None
68
68
69 # operator methods
69 # operator methods
70
70
71 def stringset(repo, subset, x):
71 def stringset(repo, subset, x):
72 x = scmutil.intrev(repo[x])
72 x = scmutil.intrev(repo[x])
73 if (x in subset
73 if (x in subset
74 or x == node.nullrev and isinstance(subset, fullreposet)):
74 or x == node.nullrev and isinstance(subset, fullreposet)):
75 return baseset([x])
75 return baseset([x])
76 return baseset()
76 return baseset()
77
77
78 def rangeset(repo, subset, x, y, order):
78 def rangeset(repo, subset, x, y, order):
79 m = getset(repo, fullreposet(repo), x)
79 m = getset(repo, fullreposet(repo), x)
80 n = getset(repo, fullreposet(repo), y)
80 n = getset(repo, fullreposet(repo), y)
81
81
82 if not m or not n:
82 if not m or not n:
83 return baseset()
83 return baseset()
84 return _makerangeset(repo, subset, m.first(), n.last(), order)
84 return _makerangeset(repo, subset, m.first(), n.last(), order)
85
85
86 def rangeall(repo, subset, x, order):
86 def rangeall(repo, subset, x, order):
87 assert x is None
87 assert x is None
88 return _makerangeset(repo, subset, 0, len(repo) - 1, order)
88 return _makerangeset(repo, subset, 0, len(repo) - 1, order)
89
89
90 def rangepre(repo, subset, y, order):
90 def rangepre(repo, subset, y, order):
91 # ':y' can't be rewritten to '0:y' since '0' may be hidden
91 # ':y' can't be rewritten to '0:y' since '0' may be hidden
92 n = getset(repo, fullreposet(repo), y)
92 n = getset(repo, fullreposet(repo), y)
93 if not n:
93 if not n:
94 return baseset()
94 return baseset()
95 return _makerangeset(repo, subset, 0, n.last(), order)
95 return _makerangeset(repo, subset, 0, n.last(), order)
96
96
97 def rangepost(repo, subset, x, order):
97 def rangepost(repo, subset, x, order):
98 m = getset(repo, fullreposet(repo), x)
98 m = getset(repo, fullreposet(repo), x)
99 if not m:
99 if not m:
100 return baseset()
100 return baseset()
101 return _makerangeset(repo, subset, m.first(), len(repo) - 1, order)
101 return _makerangeset(repo, subset, m.first(), len(repo) - 1, order)
102
102
103 def _makerangeset(repo, subset, m, n, order):
103 def _makerangeset(repo, subset, m, n, order):
104 if m == n:
104 if m == n:
105 r = baseset([m])
105 r = baseset([m])
106 elif n == node.wdirrev:
106 elif n == node.wdirrev:
107 r = spanset(repo, m, len(repo)) + baseset([n])
107 r = spanset(repo, m, len(repo)) + baseset([n])
108 elif m == node.wdirrev:
108 elif m == node.wdirrev:
109 r = baseset([m]) + spanset(repo, len(repo) - 1, n - 1)
109 r = baseset([m]) + spanset(repo, len(repo) - 1, n - 1)
110 elif m < n:
110 elif m < n:
111 r = spanset(repo, m, n + 1)
111 r = spanset(repo, m, n + 1)
112 else:
112 else:
113 r = spanset(repo, m, n - 1)
113 r = spanset(repo, m, n - 1)
114
114
115 if order == defineorder:
115 if order == defineorder:
116 return r & subset
116 return r & subset
117 else:
117 else:
118 # carrying the sorting over when possible would be more efficient
118 # carrying the sorting over when possible would be more efficient
119 return subset & r
119 return subset & r
120
120
121 def dagrange(repo, subset, x, y, order):
121 def dagrange(repo, subset, x, y, order):
122 r = fullreposet(repo)
122 r = fullreposet(repo)
123 xs = dagop.reachableroots(repo, getset(repo, r, x), getset(repo, r, y),
123 xs = dagop.reachableroots(repo, getset(repo, r, x), getset(repo, r, y),
124 includepath=True)
124 includepath=True)
125 return subset & xs
125 return subset & xs
126
126
127 def andset(repo, subset, x, y, order):
127 def andset(repo, subset, x, y, order):
128 return getset(repo, getset(repo, subset, x), y)
128 return getset(repo, getset(repo, subset, x), y)
129
129
130 def differenceset(repo, subset, x, y, order):
130 def differenceset(repo, subset, x, y, order):
131 return getset(repo, subset, x) - getset(repo, subset, y)
131 return getset(repo, subset, x) - getset(repo, subset, y)
132
132
133 def _orsetlist(repo, subset, xs):
133 def _orsetlist(repo, subset, xs):
134 assert xs
134 assert xs
135 if len(xs) == 1:
135 if len(xs) == 1:
136 return getset(repo, subset, xs[0])
136 return getset(repo, subset, xs[0])
137 p = len(xs) // 2
137 p = len(xs) // 2
138 a = _orsetlist(repo, subset, xs[:p])
138 a = _orsetlist(repo, subset, xs[:p])
139 b = _orsetlist(repo, subset, xs[p:])
139 b = _orsetlist(repo, subset, xs[p:])
140 return a + b
140 return a + b
141
141
142 def orset(repo, subset, x, order):
142 def orset(repo, subset, x, order):
143 xs = getlist(x)
143 xs = getlist(x)
144 if order == followorder:
144 if order == followorder:
145 # slow path to take the subset order
145 # slow path to take the subset order
146 return subset & _orsetlist(repo, fullreposet(repo), xs)
146 return subset & _orsetlist(repo, fullreposet(repo), xs)
147 else:
147 else:
148 return _orsetlist(repo, subset, xs)
148 return _orsetlist(repo, subset, xs)
149
149
150 def notset(repo, subset, x, order):
150 def notset(repo, subset, x, order):
151 return subset - getset(repo, subset, x)
151 return subset - getset(repo, subset, x)
152
152
153 def listset(repo, subset, *xs):
153 def listset(repo, subset, *xs):
154 raise error.ParseError(_("can't use a list in this context"),
154 raise error.ParseError(_("can't use a list in this context"),
155 hint=_('see hg help "revsets.x or y"'))
155 hint=_('see hg help "revsets.x or y"'))
156
156
157 def keyvaluepair(repo, subset, k, v):
157 def keyvaluepair(repo, subset, k, v):
158 raise error.ParseError(_("can't use a key-value pair in this context"))
158 raise error.ParseError(_("can't use a key-value pair in this context"))
159
159
160 def func(repo, subset, a, b, order):
160 def func(repo, subset, a, b, order):
161 f = getsymbol(a)
161 f = getsymbol(a)
162 if f in symbols:
162 if f in symbols:
163 func = symbols[f]
163 func = symbols[f]
164 if getattr(func, '_takeorder', False):
164 if getattr(func, '_takeorder', False):
165 return func(repo, subset, b, order)
165 return func(repo, subset, b, order)
166 return func(repo, subset, b)
166 return func(repo, subset, b)
167
167
168 keep = lambda fn: getattr(fn, '__doc__', None) is not None
168 keep = lambda fn: getattr(fn, '__doc__', None) is not None
169
169
170 syms = [s for (s, fn) in symbols.items() if keep(fn)]
170 syms = [s for (s, fn) in symbols.items() if keep(fn)]
171 raise error.UnknownIdentifier(f, syms)
171 raise error.UnknownIdentifier(f, syms)
172
172
173 # functions
173 # functions
174
174
175 # symbols are callables like:
175 # symbols are callables like:
176 # fn(repo, subset, x)
176 # fn(repo, subset, x)
177 # with:
177 # with:
178 # repo - current repository instance
178 # repo - current repository instance
179 # subset - of revisions to be examined
179 # subset - of revisions to be examined
180 # x - argument in tree form
180 # x - argument in tree form
181 symbols = {}
181 symbols = {}
182
182
183 # symbols which can't be used for a DoS attack for any given input
183 # symbols which can't be used for a DoS attack for any given input
184 # (e.g. those which accept regexes as plain strings shouldn't be included)
184 # (e.g. those which accept regexes as plain strings shouldn't be included)
185 # functions that just return a lot of changesets (like all) don't count here
185 # functions that just return a lot of changesets (like all) don't count here
186 safesymbols = set()
186 safesymbols = set()
187
187
188 predicate = registrar.revsetpredicate()
188 predicate = registrar.revsetpredicate()
189
189
190 @predicate('_destupdate')
190 @predicate('_destupdate')
191 def _destupdate(repo, subset, x):
191 def _destupdate(repo, subset, x):
192 # experimental revset for update destination
192 # experimental revset for update destination
193 args = getargsdict(x, 'limit', 'clean')
193 args = getargsdict(x, 'limit', 'clean')
194 return subset & baseset([destutil.destupdate(repo, **args)[0]])
194 return subset & baseset([destutil.destupdate(repo, **args)[0]])
195
195
196 @predicate('_destmerge')
196 @predicate('_destmerge')
197 def _destmerge(repo, subset, x):
197 def _destmerge(repo, subset, x):
198 # experimental revset for merge destination
198 # experimental revset for merge destination
199 sourceset = None
199 sourceset = None
200 if x is not None:
200 if x is not None:
201 sourceset = getset(repo, fullreposet(repo), x)
201 sourceset = getset(repo, fullreposet(repo), x)
202 return subset & baseset([destutil.destmerge(repo, sourceset=sourceset)])
202 return subset & baseset([destutil.destmerge(repo, sourceset=sourceset)])
203
203
204 @predicate('adds(pattern)', safe=True)
204 @predicate('adds(pattern)', safe=True)
205 def adds(repo, subset, x):
205 def adds(repo, subset, x):
206 """Changesets that add a file matching pattern.
206 """Changesets that add a file matching pattern.
207
207
208 The pattern without explicit kind like ``glob:`` is expected to be
208 The pattern without explicit kind like ``glob:`` is expected to be
209 relative to the current directory and match against a file or a
209 relative to the current directory and match against a file or a
210 directory.
210 directory.
211 """
211 """
212 # i18n: "adds" is a keyword
212 # i18n: "adds" is a keyword
213 pat = getstring(x, _("adds requires a pattern"))
213 pat = getstring(x, _("adds requires a pattern"))
214 return checkstatus(repo, subset, pat, 1)
214 return checkstatus(repo, subset, pat, 1)
215
215
216 @predicate('ancestor(*changeset)', safe=True)
216 @predicate('ancestor(*changeset)', safe=True)
217 def ancestor(repo, subset, x):
217 def ancestor(repo, subset, x):
218 """A greatest common ancestor of the changesets.
218 """A greatest common ancestor of the changesets.
219
219
220 Accepts 0 or more changesets.
220 Accepts 0 or more changesets.
221 Will return empty list when passed no args.
221 Will return empty list when passed no args.
222 Greatest common ancestor of a single changeset is that changeset.
222 Greatest common ancestor of a single changeset is that changeset.
223 """
223 """
224 # i18n: "ancestor" is a keyword
224 # i18n: "ancestor" is a keyword
225 l = getlist(x)
225 l = getlist(x)
226 rl = fullreposet(repo)
226 rl = fullreposet(repo)
227 anc = None
227 anc = None
228
228
229 # (getset(repo, rl, i) for i in l) generates a list of lists
229 # (getset(repo, rl, i) for i in l) generates a list of lists
230 for revs in (getset(repo, rl, i) for i in l):
230 for revs in (getset(repo, rl, i) for i in l):
231 for r in revs:
231 for r in revs:
232 if anc is None:
232 if anc is None:
233 anc = repo[r]
233 anc = repo[r]
234 else:
234 else:
235 anc = anc.ancestor(repo[r])
235 anc = anc.ancestor(repo[r])
236
236
237 if anc is not None and anc.rev() in subset:
237 if anc is not None and anc.rev() in subset:
238 return baseset([anc.rev()])
238 return baseset([anc.rev()])
239 return baseset()
239 return baseset()
240
240
241 def _ancestors(repo, subset, x, followfirst=False):
241 def _ancestors(repo, subset, x, followfirst=False):
242 heads = getset(repo, fullreposet(repo), x)
242 heads = getset(repo, fullreposet(repo), x)
243 if not heads:
243 if not heads:
244 return baseset()
244 return baseset()
245 s = dagop.revancestors(repo, heads, followfirst)
245 s = dagop.revancestors(repo, heads, followfirst)
246 return subset & s
246 return subset & s
247
247
248 @predicate('ancestors(set)', safe=True)
248 @predicate('ancestors(set)', safe=True)
249 def ancestors(repo, subset, x):
249 def ancestors(repo, subset, x):
250 """Changesets that are ancestors of changesets in set, including the
250 """Changesets that are ancestors of changesets in set, including the
251 given changesets themselves.
251 given changesets themselves.
252 """
252 """
253 return _ancestors(repo, subset, x)
253 args = getargsdict(x, 'ancestors', 'set')
254 if 'set' not in args:
255 # i18n: "ancestors" is a keyword
256 raise error.ParseError(_('ancestors takes at least 1 argument'))
257 return _ancestors(repo, subset, args['set'])
254
258
255 @predicate('_firstancestors', safe=True)
259 @predicate('_firstancestors', safe=True)
256 def _firstancestors(repo, subset, x):
260 def _firstancestors(repo, subset, x):
257 # ``_firstancestors(set)``
261 # ``_firstancestors(set)``
258 # Like ``ancestors(set)`` but follows only the first parents.
262 # Like ``ancestors(set)`` but follows only the first parents.
259 return _ancestors(repo, subset, x, followfirst=True)
263 return _ancestors(repo, subset, x, followfirst=True)
260
264
261 def _childrenspec(repo, subset, x, n, order):
265 def _childrenspec(repo, subset, x, n, order):
262 """Changesets that are the Nth child of a changeset
266 """Changesets that are the Nth child of a changeset
263 in set.
267 in set.
264 """
268 """
265 cs = set()
269 cs = set()
266 for r in getset(repo, fullreposet(repo), x):
270 for r in getset(repo, fullreposet(repo), x):
267 for i in range(n):
271 for i in range(n):
268 c = repo[r].children()
272 c = repo[r].children()
269 if len(c) == 0:
273 if len(c) == 0:
270 break
274 break
271 if len(c) > 1:
275 if len(c) > 1:
272 raise error.RepoLookupError(
276 raise error.RepoLookupError(
273 _("revision in set has more than one child"))
277 _("revision in set has more than one child"))
274 r = c[0].rev()
278 r = c[0].rev()
275 else:
279 else:
276 cs.add(r)
280 cs.add(r)
277 return subset & cs
281 return subset & cs
278
282
279 def ancestorspec(repo, subset, x, n, order):
283 def ancestorspec(repo, subset, x, n, order):
280 """``set~n``
284 """``set~n``
281 Changesets that are the Nth ancestor (first parents only) of a changeset
285 Changesets that are the Nth ancestor (first parents only) of a changeset
282 in set.
286 in set.
283 """
287 """
284 n = getinteger(n, _("~ expects a number"))
288 n = getinteger(n, _("~ expects a number"))
285 if n < 0:
289 if n < 0:
286 # children lookup
290 # children lookup
287 return _childrenspec(repo, subset, x, -n, order)
291 return _childrenspec(repo, subset, x, -n, order)
288 ps = set()
292 ps = set()
289 cl = repo.changelog
293 cl = repo.changelog
290 for r in getset(repo, fullreposet(repo), x):
294 for r in getset(repo, fullreposet(repo), x):
291 for i in range(n):
295 for i in range(n):
292 try:
296 try:
293 r = cl.parentrevs(r)[0]
297 r = cl.parentrevs(r)[0]
294 except error.WdirUnsupported:
298 except error.WdirUnsupported:
295 r = repo[r].parents()[0].rev()
299 r = repo[r].parents()[0].rev()
296 ps.add(r)
300 ps.add(r)
297 return subset & ps
301 return subset & ps
298
302
299 @predicate('author(string)', safe=True)
303 @predicate('author(string)', safe=True)
300 def author(repo, subset, x):
304 def author(repo, subset, x):
301 """Alias for ``user(string)``.
305 """Alias for ``user(string)``.
302 """
306 """
303 # i18n: "author" is a keyword
307 # i18n: "author" is a keyword
304 n = getstring(x, _("author requires a string"))
308 n = getstring(x, _("author requires a string"))
305 kind, pattern, matcher = _substringmatcher(n, casesensitive=False)
309 kind, pattern, matcher = _substringmatcher(n, casesensitive=False)
306 return subset.filter(lambda x: matcher(repo[x].user()),
310 return subset.filter(lambda x: matcher(repo[x].user()),
307 condrepr=('<user %r>', n))
311 condrepr=('<user %r>', n))
308
312
309 @predicate('bisect(string)', safe=True)
313 @predicate('bisect(string)', safe=True)
310 def bisect(repo, subset, x):
314 def bisect(repo, subset, x):
311 """Changesets marked in the specified bisect status:
315 """Changesets marked in the specified bisect status:
312
316
313 - ``good``, ``bad``, ``skip``: csets explicitly marked as good/bad/skip
317 - ``good``, ``bad``, ``skip``: csets explicitly marked as good/bad/skip
314 - ``goods``, ``bads`` : csets topologically good/bad
318 - ``goods``, ``bads`` : csets topologically good/bad
315 - ``range`` : csets taking part in the bisection
319 - ``range`` : csets taking part in the bisection
316 - ``pruned`` : csets that are goods, bads or skipped
320 - ``pruned`` : csets that are goods, bads or skipped
317 - ``untested`` : csets whose fate is yet unknown
321 - ``untested`` : csets whose fate is yet unknown
318 - ``ignored`` : csets ignored due to DAG topology
322 - ``ignored`` : csets ignored due to DAG topology
319 - ``current`` : the cset currently being bisected
323 - ``current`` : the cset currently being bisected
320 """
324 """
321 # i18n: "bisect" is a keyword
325 # i18n: "bisect" is a keyword
322 status = getstring(x, _("bisect requires a string")).lower()
326 status = getstring(x, _("bisect requires a string")).lower()
323 state = set(hbisect.get(repo, status))
327 state = set(hbisect.get(repo, status))
324 return subset & state
328 return subset & state
325
329
326 # Backward-compatibility
330 # Backward-compatibility
327 # - no help entry so that we do not advertise it any more
331 # - no help entry so that we do not advertise it any more
328 @predicate('bisected', safe=True)
332 @predicate('bisected', safe=True)
329 def bisected(repo, subset, x):
333 def bisected(repo, subset, x):
330 return bisect(repo, subset, x)
334 return bisect(repo, subset, x)
331
335
332 @predicate('bookmark([name])', safe=True)
336 @predicate('bookmark([name])', safe=True)
333 def bookmark(repo, subset, x):
337 def bookmark(repo, subset, x):
334 """The named bookmark or all bookmarks.
338 """The named bookmark or all bookmarks.
335
339
336 Pattern matching is supported for `name`. See :hg:`help revisions.patterns`.
340 Pattern matching is supported for `name`. See :hg:`help revisions.patterns`.
337 """
341 """
338 # i18n: "bookmark" is a keyword
342 # i18n: "bookmark" is a keyword
339 args = getargs(x, 0, 1, _('bookmark takes one or no arguments'))
343 args = getargs(x, 0, 1, _('bookmark takes one or no arguments'))
340 if args:
344 if args:
341 bm = getstring(args[0],
345 bm = getstring(args[0],
342 # i18n: "bookmark" is a keyword
346 # i18n: "bookmark" is a keyword
343 _('the argument to bookmark must be a string'))
347 _('the argument to bookmark must be a string'))
344 kind, pattern, matcher = util.stringmatcher(bm)
348 kind, pattern, matcher = util.stringmatcher(bm)
345 bms = set()
349 bms = set()
346 if kind == 'literal':
350 if kind == 'literal':
347 bmrev = repo._bookmarks.get(pattern, None)
351 bmrev = repo._bookmarks.get(pattern, None)
348 if not bmrev:
352 if not bmrev:
349 raise error.RepoLookupError(_("bookmark '%s' does not exist")
353 raise error.RepoLookupError(_("bookmark '%s' does not exist")
350 % pattern)
354 % pattern)
351 bms.add(repo[bmrev].rev())
355 bms.add(repo[bmrev].rev())
352 else:
356 else:
353 matchrevs = set()
357 matchrevs = set()
354 for name, bmrev in repo._bookmarks.iteritems():
358 for name, bmrev in repo._bookmarks.iteritems():
355 if matcher(name):
359 if matcher(name):
356 matchrevs.add(bmrev)
360 matchrevs.add(bmrev)
357 if not matchrevs:
361 if not matchrevs:
358 raise error.RepoLookupError(_("no bookmarks exist"
362 raise error.RepoLookupError(_("no bookmarks exist"
359 " that match '%s'") % pattern)
363 " that match '%s'") % pattern)
360 for bmrev in matchrevs:
364 for bmrev in matchrevs:
361 bms.add(repo[bmrev].rev())
365 bms.add(repo[bmrev].rev())
362 else:
366 else:
363 bms = {repo[r].rev() for r in repo._bookmarks.values()}
367 bms = {repo[r].rev() for r in repo._bookmarks.values()}
364 bms -= {node.nullrev}
368 bms -= {node.nullrev}
365 return subset & bms
369 return subset & bms
366
370
367 @predicate('branch(string or set)', safe=True)
371 @predicate('branch(string or set)', safe=True)
368 def branch(repo, subset, x):
372 def branch(repo, subset, x):
369 """
373 """
370 All changesets belonging to the given branch or the branches of the given
374 All changesets belonging to the given branch or the branches of the given
371 changesets.
375 changesets.
372
376
373 Pattern matching is supported for `string`. See
377 Pattern matching is supported for `string`. See
374 :hg:`help revisions.patterns`.
378 :hg:`help revisions.patterns`.
375 """
379 """
376 getbi = repo.revbranchcache().branchinfo
380 getbi = repo.revbranchcache().branchinfo
377 def getbranch(r):
381 def getbranch(r):
378 try:
382 try:
379 return getbi(r)[0]
383 return getbi(r)[0]
380 except error.WdirUnsupported:
384 except error.WdirUnsupported:
381 return repo[r].branch()
385 return repo[r].branch()
382
386
383 try:
387 try:
384 b = getstring(x, '')
388 b = getstring(x, '')
385 except error.ParseError:
389 except error.ParseError:
386 # not a string, but another revspec, e.g. tip()
390 # not a string, but another revspec, e.g. tip()
387 pass
391 pass
388 else:
392 else:
389 kind, pattern, matcher = util.stringmatcher(b)
393 kind, pattern, matcher = util.stringmatcher(b)
390 if kind == 'literal':
394 if kind == 'literal':
391 # note: falls through to the revspec case if no branch with
395 # note: falls through to the revspec case if no branch with
392 # this name exists and pattern kind is not specified explicitly
396 # this name exists and pattern kind is not specified explicitly
393 if pattern in repo.branchmap():
397 if pattern in repo.branchmap():
394 return subset.filter(lambda r: matcher(getbranch(r)),
398 return subset.filter(lambda r: matcher(getbranch(r)),
395 condrepr=('<branch %r>', b))
399 condrepr=('<branch %r>', b))
396 if b.startswith('literal:'):
400 if b.startswith('literal:'):
397 raise error.RepoLookupError(_("branch '%s' does not exist")
401 raise error.RepoLookupError(_("branch '%s' does not exist")
398 % pattern)
402 % pattern)
399 else:
403 else:
400 return subset.filter(lambda r: matcher(getbranch(r)),
404 return subset.filter(lambda r: matcher(getbranch(r)),
401 condrepr=('<branch %r>', b))
405 condrepr=('<branch %r>', b))
402
406
403 s = getset(repo, fullreposet(repo), x)
407 s = getset(repo, fullreposet(repo), x)
404 b = set()
408 b = set()
405 for r in s:
409 for r in s:
406 b.add(getbranch(r))
410 b.add(getbranch(r))
407 c = s.__contains__
411 c = s.__contains__
408 return subset.filter(lambda r: c(r) or getbranch(r) in b,
412 return subset.filter(lambda r: c(r) or getbranch(r) in b,
409 condrepr=lambda: '<branch %r>' % sorted(b))
413 condrepr=lambda: '<branch %r>' % sorted(b))
410
414
411 @predicate('bumped()', safe=True)
415 @predicate('bumped()', safe=True)
412 def bumped(repo, subset, x):
416 def bumped(repo, subset, x):
413 """Mutable changesets marked as successors of public changesets.
417 """Mutable changesets marked as successors of public changesets.
414
418
415 Only non-public and non-obsolete changesets can be `bumped`.
419 Only non-public and non-obsolete changesets can be `bumped`.
416 """
420 """
417 # i18n: "bumped" is a keyword
421 # i18n: "bumped" is a keyword
418 getargs(x, 0, 0, _("bumped takes no arguments"))
422 getargs(x, 0, 0, _("bumped takes no arguments"))
419 bumped = obsmod.getrevs(repo, 'bumped')
423 bumped = obsmod.getrevs(repo, 'bumped')
420 return subset & bumped
424 return subset & bumped
421
425
422 @predicate('bundle()', safe=True)
426 @predicate('bundle()', safe=True)
423 def bundle(repo, subset, x):
427 def bundle(repo, subset, x):
424 """Changesets in the bundle.
428 """Changesets in the bundle.
425
429
426 Bundle must be specified by the -R option."""
430 Bundle must be specified by the -R option."""
427
431
428 try:
432 try:
429 bundlerevs = repo.changelog.bundlerevs
433 bundlerevs = repo.changelog.bundlerevs
430 except AttributeError:
434 except AttributeError:
431 raise error.Abort(_("no bundle provided - specify with -R"))
435 raise error.Abort(_("no bundle provided - specify with -R"))
432 return subset & bundlerevs
436 return subset & bundlerevs
433
437
434 def checkstatus(repo, subset, pat, field):
438 def checkstatus(repo, subset, pat, field):
435 hasset = matchmod.patkind(pat) == 'set'
439 hasset = matchmod.patkind(pat) == 'set'
436
440
437 mcache = [None]
441 mcache = [None]
438 def matches(x):
442 def matches(x):
439 c = repo[x]
443 c = repo[x]
440 if not mcache[0] or hasset:
444 if not mcache[0] or hasset:
441 mcache[0] = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
445 mcache[0] = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
442 m = mcache[0]
446 m = mcache[0]
443 fname = None
447 fname = None
444 if not m.anypats() and len(m.files()) == 1:
448 if not m.anypats() and len(m.files()) == 1:
445 fname = m.files()[0]
449 fname = m.files()[0]
446 if fname is not None:
450 if fname is not None:
447 if fname not in c.files():
451 if fname not in c.files():
448 return False
452 return False
449 else:
453 else:
450 for f in c.files():
454 for f in c.files():
451 if m(f):
455 if m(f):
452 break
456 break
453 else:
457 else:
454 return False
458 return False
455 files = repo.status(c.p1().node(), c.node())[field]
459 files = repo.status(c.p1().node(), c.node())[field]
456 if fname is not None:
460 if fname is not None:
457 if fname in files:
461 if fname in files:
458 return True
462 return True
459 else:
463 else:
460 for f in files:
464 for f in files:
461 if m(f):
465 if m(f):
462 return True
466 return True
463
467
464 return subset.filter(matches, condrepr=('<status[%r] %r>', field, pat))
468 return subset.filter(matches, condrepr=('<status[%r] %r>', field, pat))
465
469
466 def _children(repo, subset, parentset):
470 def _children(repo, subset, parentset):
467 if not parentset:
471 if not parentset:
468 return baseset()
472 return baseset()
469 cs = set()
473 cs = set()
470 pr = repo.changelog.parentrevs
474 pr = repo.changelog.parentrevs
471 minrev = parentset.min()
475 minrev = parentset.min()
472 nullrev = node.nullrev
476 nullrev = node.nullrev
473 for r in subset:
477 for r in subset:
474 if r <= minrev:
478 if r <= minrev:
475 continue
479 continue
476 p1, p2 = pr(r)
480 p1, p2 = pr(r)
477 if p1 in parentset:
481 if p1 in parentset:
478 cs.add(r)
482 cs.add(r)
479 if p2 != nullrev and p2 in parentset:
483 if p2 != nullrev and p2 in parentset:
480 cs.add(r)
484 cs.add(r)
481 return baseset(cs)
485 return baseset(cs)
482
486
483 @predicate('children(set)', safe=True)
487 @predicate('children(set)', safe=True)
484 def children(repo, subset, x):
488 def children(repo, subset, x):
485 """Child changesets of changesets in set.
489 """Child changesets of changesets in set.
486 """
490 """
487 s = getset(repo, fullreposet(repo), x)
491 s = getset(repo, fullreposet(repo), x)
488 cs = _children(repo, subset, s)
492 cs = _children(repo, subset, s)
489 return subset & cs
493 return subset & cs
490
494
491 @predicate('closed()', safe=True)
495 @predicate('closed()', safe=True)
492 def closed(repo, subset, x):
496 def closed(repo, subset, x):
493 """Changeset is closed.
497 """Changeset is closed.
494 """
498 """
495 # i18n: "closed" is a keyword
499 # i18n: "closed" is a keyword
496 getargs(x, 0, 0, _("closed takes no arguments"))
500 getargs(x, 0, 0, _("closed takes no arguments"))
497 return subset.filter(lambda r: repo[r].closesbranch(),
501 return subset.filter(lambda r: repo[r].closesbranch(),
498 condrepr='<branch closed>')
502 condrepr='<branch closed>')
499
503
500 @predicate('contains(pattern)')
504 @predicate('contains(pattern)')
501 def contains(repo, subset, x):
505 def contains(repo, subset, x):
502 """The revision's manifest contains a file matching pattern (but might not
506 """The revision's manifest contains a file matching pattern (but might not
503 modify it). See :hg:`help patterns` for information about file patterns.
507 modify it). See :hg:`help patterns` for information about file patterns.
504
508
505 The pattern without explicit kind like ``glob:`` is expected to be
509 The pattern without explicit kind like ``glob:`` is expected to be
506 relative to the current directory and match against a file exactly
510 relative to the current directory and match against a file exactly
507 for efficiency.
511 for efficiency.
508 """
512 """
509 # i18n: "contains" is a keyword
513 # i18n: "contains" is a keyword
510 pat = getstring(x, _("contains requires a pattern"))
514 pat = getstring(x, _("contains requires a pattern"))
511
515
512 def matches(x):
516 def matches(x):
513 if not matchmod.patkind(pat):
517 if not matchmod.patkind(pat):
514 pats = pathutil.canonpath(repo.root, repo.getcwd(), pat)
518 pats = pathutil.canonpath(repo.root, repo.getcwd(), pat)
515 if pats in repo[x]:
519 if pats in repo[x]:
516 return True
520 return True
517 else:
521 else:
518 c = repo[x]
522 c = repo[x]
519 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
523 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
520 for f in c.manifest():
524 for f in c.manifest():
521 if m(f):
525 if m(f):
522 return True
526 return True
523 return False
527 return False
524
528
525 return subset.filter(matches, condrepr=('<contains %r>', pat))
529 return subset.filter(matches, condrepr=('<contains %r>', pat))
526
530
527 @predicate('converted([id])', safe=True)
531 @predicate('converted([id])', safe=True)
528 def converted(repo, subset, x):
532 def converted(repo, subset, x):
529 """Changesets converted from the given identifier in the old repository if
533 """Changesets converted from the given identifier in the old repository if
530 present, or all converted changesets if no identifier is specified.
534 present, or all converted changesets if no identifier is specified.
531 """
535 """
532
536
533 # There is exactly no chance of resolving the revision, so do a simple
537 # There is exactly no chance of resolving the revision, so do a simple
534 # string compare and hope for the best
538 # string compare and hope for the best
535
539
536 rev = None
540 rev = None
537 # i18n: "converted" is a keyword
541 # i18n: "converted" is a keyword
538 l = getargs(x, 0, 1, _('converted takes one or no arguments'))
542 l = getargs(x, 0, 1, _('converted takes one or no arguments'))
539 if l:
543 if l:
540 # i18n: "converted" is a keyword
544 # i18n: "converted" is a keyword
541 rev = getstring(l[0], _('converted requires a revision'))
545 rev = getstring(l[0], _('converted requires a revision'))
542
546
543 def _matchvalue(r):
547 def _matchvalue(r):
544 source = repo[r].extra().get('convert_revision', None)
548 source = repo[r].extra().get('convert_revision', None)
545 return source is not None and (rev is None or source.startswith(rev))
549 return source is not None and (rev is None or source.startswith(rev))
546
550
547 return subset.filter(lambda r: _matchvalue(r),
551 return subset.filter(lambda r: _matchvalue(r),
548 condrepr=('<converted %r>', rev))
552 condrepr=('<converted %r>', rev))
549
553
550 @predicate('date(interval)', safe=True)
554 @predicate('date(interval)', safe=True)
551 def date(repo, subset, x):
555 def date(repo, subset, x):
552 """Changesets within the interval, see :hg:`help dates`.
556 """Changesets within the interval, see :hg:`help dates`.
553 """
557 """
554 # i18n: "date" is a keyword
558 # i18n: "date" is a keyword
555 ds = getstring(x, _("date requires a string"))
559 ds = getstring(x, _("date requires a string"))
556 dm = util.matchdate(ds)
560 dm = util.matchdate(ds)
557 return subset.filter(lambda x: dm(repo[x].date()[0]),
561 return subset.filter(lambda x: dm(repo[x].date()[0]),
558 condrepr=('<date %r>', ds))
562 condrepr=('<date %r>', ds))
559
563
560 @predicate('desc(string)', safe=True)
564 @predicate('desc(string)', safe=True)
561 def desc(repo, subset, x):
565 def desc(repo, subset, x):
562 """Search commit message for string. The match is case-insensitive.
566 """Search commit message for string. The match is case-insensitive.
563
567
564 Pattern matching is supported for `string`. See
568 Pattern matching is supported for `string`. See
565 :hg:`help revisions.patterns`.
569 :hg:`help revisions.patterns`.
566 """
570 """
567 # i18n: "desc" is a keyword
571 # i18n: "desc" is a keyword
568 ds = getstring(x, _("desc requires a string"))
572 ds = getstring(x, _("desc requires a string"))
569
573
570 kind, pattern, matcher = _substringmatcher(ds, casesensitive=False)
574 kind, pattern, matcher = _substringmatcher(ds, casesensitive=False)
571
575
572 return subset.filter(lambda r: matcher(repo[r].description()),
576 return subset.filter(lambda r: matcher(repo[r].description()),
573 condrepr=('<desc %r>', ds))
577 condrepr=('<desc %r>', ds))
574
578
575 def _descendants(repo, subset, x, followfirst=False):
579 def _descendants(repo, subset, x, followfirst=False):
576 roots = getset(repo, fullreposet(repo), x)
580 roots = getset(repo, fullreposet(repo), x)
577 if not roots:
581 if not roots:
578 return baseset()
582 return baseset()
579 s = dagop.revdescendants(repo, roots, followfirst)
583 s = dagop.revdescendants(repo, roots, followfirst)
580
584
581 # Both sets need to be ascending in order to lazily return the union
585 # Both sets need to be ascending in order to lazily return the union
582 # in the correct order.
586 # in the correct order.
583 base = subset & roots
587 base = subset & roots
584 desc = subset & s
588 desc = subset & s
585 result = base + desc
589 result = base + desc
586 if subset.isascending():
590 if subset.isascending():
587 result.sort()
591 result.sort()
588 elif subset.isdescending():
592 elif subset.isdescending():
589 result.sort(reverse=True)
593 result.sort(reverse=True)
590 else:
594 else:
591 result = subset & result
595 result = subset & result
592 return result
596 return result
593
597
594 @predicate('descendants(set)', safe=True)
598 @predicate('descendants(set)', safe=True)
595 def descendants(repo, subset, x):
599 def descendants(repo, subset, x):
596 """Changesets which are descendants of changesets in set, including the
600 """Changesets which are descendants of changesets in set, including the
597 given changesets themselves.
601 given changesets themselves.
598 """
602 """
599 return _descendants(repo, subset, x)
603 args = getargsdict(x, 'descendants', 'set')
604 if 'set' not in args:
605 # i18n: "descendants" is a keyword
606 raise error.ParseError(_('descendants takes at least 1 argument'))
607 return _descendants(repo, subset, args['set'])
600
608
601 @predicate('_firstdescendants', safe=True)
609 @predicate('_firstdescendants', safe=True)
602 def _firstdescendants(repo, subset, x):
610 def _firstdescendants(repo, subset, x):
603 # ``_firstdescendants(set)``
611 # ``_firstdescendants(set)``
604 # Like ``descendants(set)`` but follows only the first parents.
612 # Like ``descendants(set)`` but follows only the first parents.
605 return _descendants(repo, subset, x, followfirst=True)
613 return _descendants(repo, subset, x, followfirst=True)
606
614
607 @predicate('destination([set])', safe=True)
615 @predicate('destination([set])', safe=True)
608 def destination(repo, subset, x):
616 def destination(repo, subset, x):
609 """Changesets that were created by a graft, transplant or rebase operation,
617 """Changesets that were created by a graft, transplant or rebase operation,
610 with the given revisions specified as the source. Omitting the optional set
618 with the given revisions specified as the source. Omitting the optional set
611 is the same as passing all().
619 is the same as passing all().
612 """
620 """
613 if x is not None:
621 if x is not None:
614 sources = getset(repo, fullreposet(repo), x)
622 sources = getset(repo, fullreposet(repo), x)
615 else:
623 else:
616 sources = fullreposet(repo)
624 sources = fullreposet(repo)
617
625
618 dests = set()
626 dests = set()
619
627
620 # subset contains all of the possible destinations that can be returned, so
628 # subset contains all of the possible destinations that can be returned, so
621 # iterate over them and see if their source(s) were provided in the arg set.
629 # iterate over them and see if their source(s) were provided in the arg set.
622 # Even if the immediate src of r is not in the arg set, src's source (or
630 # Even if the immediate src of r is not in the arg set, src's source (or
623 # further back) may be. Scanning back further than the immediate src allows
631 # further back) may be. Scanning back further than the immediate src allows
624 # transitive transplants and rebases to yield the same results as transitive
632 # transitive transplants and rebases to yield the same results as transitive
625 # grafts.
633 # grafts.
626 for r in subset:
634 for r in subset:
627 src = _getrevsource(repo, r)
635 src = _getrevsource(repo, r)
628 lineage = None
636 lineage = None
629
637
630 while src is not None:
638 while src is not None:
631 if lineage is None:
639 if lineage is None:
632 lineage = list()
640 lineage = list()
633
641
634 lineage.append(r)
642 lineage.append(r)
635
643
636 # The visited lineage is a match if the current source is in the arg
644 # The visited lineage is a match if the current source is in the arg
637 # set. Since every candidate dest is visited by way of iterating
645 # set. Since every candidate dest is visited by way of iterating
638 # subset, any dests further back in the lineage will be tested by a
646 # subset, any dests further back in the lineage will be tested by a
639 # different iteration over subset. Likewise, if the src was already
647 # different iteration over subset. Likewise, if the src was already
640 # selected, the current lineage can be selected without going back
648 # selected, the current lineage can be selected without going back
641 # further.
649 # further.
642 if src in sources or src in dests:
650 if src in sources or src in dests:
643 dests.update(lineage)
651 dests.update(lineage)
644 break
652 break
645
653
646 r = src
654 r = src
647 src = _getrevsource(repo, r)
655 src = _getrevsource(repo, r)
648
656
649 return subset.filter(dests.__contains__,
657 return subset.filter(dests.__contains__,
650 condrepr=lambda: '<destination %r>' % sorted(dests))
658 condrepr=lambda: '<destination %r>' % sorted(dests))
651
659
652 @predicate('divergent()', safe=True)
660 @predicate('divergent()', safe=True)
653 def divergent(repo, subset, x):
661 def divergent(repo, subset, x):
654 """
662 """
655 Final successors of changesets with an alternative set of final successors.
663 Final successors of changesets with an alternative set of final successors.
656 """
664 """
657 # i18n: "divergent" is a keyword
665 # i18n: "divergent" is a keyword
658 getargs(x, 0, 0, _("divergent takes no arguments"))
666 getargs(x, 0, 0, _("divergent takes no arguments"))
659 divergent = obsmod.getrevs(repo, 'divergent')
667 divergent = obsmod.getrevs(repo, 'divergent')
660 return subset & divergent
668 return subset & divergent
661
669
662 @predicate('extinct()', safe=True)
670 @predicate('extinct()', safe=True)
663 def extinct(repo, subset, x):
671 def extinct(repo, subset, x):
664 """Obsolete changesets with obsolete descendants only.
672 """Obsolete changesets with obsolete descendants only.
665 """
673 """
666 # i18n: "extinct" is a keyword
674 # i18n: "extinct" is a keyword
667 getargs(x, 0, 0, _("extinct takes no arguments"))
675 getargs(x, 0, 0, _("extinct takes no arguments"))
668 extincts = obsmod.getrevs(repo, 'extinct')
676 extincts = obsmod.getrevs(repo, 'extinct')
669 return subset & extincts
677 return subset & extincts
670
678
671 @predicate('extra(label, [value])', safe=True)
679 @predicate('extra(label, [value])', safe=True)
672 def extra(repo, subset, x):
680 def extra(repo, subset, x):
673 """Changesets with the given label in the extra metadata, with the given
681 """Changesets with the given label in the extra metadata, with the given
674 optional value.
682 optional value.
675
683
676 Pattern matching is supported for `value`. See
684 Pattern matching is supported for `value`. See
677 :hg:`help revisions.patterns`.
685 :hg:`help revisions.patterns`.
678 """
686 """
679 args = getargsdict(x, 'extra', 'label value')
687 args = getargsdict(x, 'extra', 'label value')
680 if 'label' not in args:
688 if 'label' not in args:
681 # i18n: "extra" is a keyword
689 # i18n: "extra" is a keyword
682 raise error.ParseError(_('extra takes at least 1 argument'))
690 raise error.ParseError(_('extra takes at least 1 argument'))
683 # i18n: "extra" is a keyword
691 # i18n: "extra" is a keyword
684 label = getstring(args['label'], _('first argument to extra must be '
692 label = getstring(args['label'], _('first argument to extra must be '
685 'a string'))
693 'a string'))
686 value = None
694 value = None
687
695
688 if 'value' in args:
696 if 'value' in args:
689 # i18n: "extra" is a keyword
697 # i18n: "extra" is a keyword
690 value = getstring(args['value'], _('second argument to extra must be '
698 value = getstring(args['value'], _('second argument to extra must be '
691 'a string'))
699 'a string'))
692 kind, value, matcher = util.stringmatcher(value)
700 kind, value, matcher = util.stringmatcher(value)
693
701
694 def _matchvalue(r):
702 def _matchvalue(r):
695 extra = repo[r].extra()
703 extra = repo[r].extra()
696 return label in extra and (value is None or matcher(extra[label]))
704 return label in extra and (value is None or matcher(extra[label]))
697
705
698 return subset.filter(lambda r: _matchvalue(r),
706 return subset.filter(lambda r: _matchvalue(r),
699 condrepr=('<extra[%r] %r>', label, value))
707 condrepr=('<extra[%r] %r>', label, value))
700
708
701 @predicate('filelog(pattern)', safe=True)
709 @predicate('filelog(pattern)', safe=True)
702 def filelog(repo, subset, x):
710 def filelog(repo, subset, x):
703 """Changesets connected to the specified filelog.
711 """Changesets connected to the specified filelog.
704
712
705 For performance reasons, visits only revisions mentioned in the file-level
713 For performance reasons, visits only revisions mentioned in the file-level
706 filelog, rather than filtering through all changesets (much faster, but
714 filelog, rather than filtering through all changesets (much faster, but
707 doesn't include deletes or duplicate changes). For a slower, more accurate
715 doesn't include deletes or duplicate changes). For a slower, more accurate
708 result, use ``file()``.
716 result, use ``file()``.
709
717
710 The pattern without explicit kind like ``glob:`` is expected to be
718 The pattern without explicit kind like ``glob:`` is expected to be
711 relative to the current directory and match against a file exactly
719 relative to the current directory and match against a file exactly
712 for efficiency.
720 for efficiency.
713
721
714 If some linkrev points to revisions filtered by the current repoview, we'll
722 If some linkrev points to revisions filtered by the current repoview, we'll
715 work around it to return a non-filtered value.
723 work around it to return a non-filtered value.
716 """
724 """
717
725
718 # i18n: "filelog" is a keyword
726 # i18n: "filelog" is a keyword
719 pat = getstring(x, _("filelog requires a pattern"))
727 pat = getstring(x, _("filelog requires a pattern"))
720 s = set()
728 s = set()
721 cl = repo.changelog
729 cl = repo.changelog
722
730
723 if not matchmod.patkind(pat):
731 if not matchmod.patkind(pat):
724 f = pathutil.canonpath(repo.root, repo.getcwd(), pat)
732 f = pathutil.canonpath(repo.root, repo.getcwd(), pat)
725 files = [f]
733 files = [f]
726 else:
734 else:
727 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=repo[None])
735 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=repo[None])
728 files = (f for f in repo[None] if m(f))
736 files = (f for f in repo[None] if m(f))
729
737
730 for f in files:
738 for f in files:
731 fl = repo.file(f)
739 fl = repo.file(f)
732 known = {}
740 known = {}
733 scanpos = 0
741 scanpos = 0
734 for fr in list(fl):
742 for fr in list(fl):
735 fn = fl.node(fr)
743 fn = fl.node(fr)
736 if fn in known:
744 if fn in known:
737 s.add(known[fn])
745 s.add(known[fn])
738 continue
746 continue
739
747
740 lr = fl.linkrev(fr)
748 lr = fl.linkrev(fr)
741 if lr in cl:
749 if lr in cl:
742 s.add(lr)
750 s.add(lr)
743 elif scanpos is not None:
751 elif scanpos is not None:
744 # lowest matching changeset is filtered, scan further
752 # lowest matching changeset is filtered, scan further
745 # ahead in changelog
753 # ahead in changelog
746 start = max(lr, scanpos) + 1
754 start = max(lr, scanpos) + 1
747 scanpos = None
755 scanpos = None
748 for r in cl.revs(start):
756 for r in cl.revs(start):
749 # minimize parsing of non-matching entries
757 # minimize parsing of non-matching entries
750 if f in cl.revision(r) and f in cl.readfiles(r):
758 if f in cl.revision(r) and f in cl.readfiles(r):
751 try:
759 try:
752 # try to use manifest delta fastpath
760 # try to use manifest delta fastpath
753 n = repo[r].filenode(f)
761 n = repo[r].filenode(f)
754 if n not in known:
762 if n not in known:
755 if n == fn:
763 if n == fn:
756 s.add(r)
764 s.add(r)
757 scanpos = r
765 scanpos = r
758 break
766 break
759 else:
767 else:
760 known[n] = r
768 known[n] = r
761 except error.ManifestLookupError:
769 except error.ManifestLookupError:
762 # deletion in changelog
770 # deletion in changelog
763 continue
771 continue
764
772
765 return subset & s
773 return subset & s
766
774
767 @predicate('first(set, [n])', safe=True, takeorder=True)
775 @predicate('first(set, [n])', safe=True, takeorder=True)
768 def first(repo, subset, x, order):
776 def first(repo, subset, x, order):
769 """An alias for limit().
777 """An alias for limit().
770 """
778 """
771 return limit(repo, subset, x, order)
779 return limit(repo, subset, x, order)
772
780
773 def _follow(repo, subset, x, name, followfirst=False):
781 def _follow(repo, subset, x, name, followfirst=False):
774 l = getargs(x, 0, 2, _("%s takes no arguments or a pattern "
782 l = getargs(x, 0, 2, _("%s takes no arguments or a pattern "
775 "and an optional revset") % name)
783 "and an optional revset") % name)
776 c = repo['.']
784 c = repo['.']
777 if l:
785 if l:
778 x = getstring(l[0], _("%s expected a pattern") % name)
786 x = getstring(l[0], _("%s expected a pattern") % name)
779 rev = None
787 rev = None
780 if len(l) >= 2:
788 if len(l) >= 2:
781 revs = getset(repo, fullreposet(repo), l[1])
789 revs = getset(repo, fullreposet(repo), l[1])
782 if len(revs) != 1:
790 if len(revs) != 1:
783 raise error.RepoLookupError(
791 raise error.RepoLookupError(
784 _("%s expected one starting revision") % name)
792 _("%s expected one starting revision") % name)
785 rev = revs.last()
793 rev = revs.last()
786 c = repo[rev]
794 c = repo[rev]
787 matcher = matchmod.match(repo.root, repo.getcwd(), [x],
795 matcher = matchmod.match(repo.root, repo.getcwd(), [x],
788 ctx=repo[rev], default='path')
796 ctx=repo[rev], default='path')
789
797
790 files = c.manifest().walk(matcher)
798 files = c.manifest().walk(matcher)
791
799
792 s = set()
800 s = set()
793 for fname in files:
801 for fname in files:
794 fctx = c[fname]
802 fctx = c[fname]
795 s = s.union(set(c.rev() for c in fctx.ancestors(followfirst)))
803 s = s.union(set(c.rev() for c in fctx.ancestors(followfirst)))
796 # include the revision responsible for the most recent version
804 # include the revision responsible for the most recent version
797 s.add(fctx.introrev())
805 s.add(fctx.introrev())
798 else:
806 else:
799 s = dagop.revancestors(repo, baseset([c.rev()]), followfirst)
807 s = dagop.revancestors(repo, baseset([c.rev()]), followfirst)
800
808
801 return subset & s
809 return subset & s
802
810
803 @predicate('follow([pattern[, startrev]])', safe=True)
811 @predicate('follow([pattern[, startrev]])', safe=True)
804 def follow(repo, subset, x):
812 def follow(repo, subset, x):
805 """
813 """
806 An alias for ``::.`` (ancestors of the working directory's first parent).
814 An alias for ``::.`` (ancestors of the working directory's first parent).
807 If pattern is specified, the histories of files matching given
815 If pattern is specified, the histories of files matching given
808 pattern in the revision given by startrev are followed, including copies.
816 pattern in the revision given by startrev are followed, including copies.
809 """
817 """
810 return _follow(repo, subset, x, 'follow')
818 return _follow(repo, subset, x, 'follow')
811
819
812 @predicate('_followfirst', safe=True)
820 @predicate('_followfirst', safe=True)
813 def _followfirst(repo, subset, x):
821 def _followfirst(repo, subset, x):
814 # ``followfirst([pattern[, startrev]])``
822 # ``followfirst([pattern[, startrev]])``
815 # Like ``follow([pattern[, startrev]])`` but follows only the first parent
823 # Like ``follow([pattern[, startrev]])`` but follows only the first parent
816 # of every revisions or files revisions.
824 # of every revisions or files revisions.
817 return _follow(repo, subset, x, '_followfirst', followfirst=True)
825 return _follow(repo, subset, x, '_followfirst', followfirst=True)
818
826
819 @predicate('followlines(file, fromline:toline[, startrev=., descend=False])',
827 @predicate('followlines(file, fromline:toline[, startrev=., descend=False])',
820 safe=True)
828 safe=True)
821 def followlines(repo, subset, x):
829 def followlines(repo, subset, x):
822 """Changesets modifying `file` in line range ('fromline', 'toline').
830 """Changesets modifying `file` in line range ('fromline', 'toline').
823
831
824 Line range corresponds to 'file' content at 'startrev' and should hence be
832 Line range corresponds to 'file' content at 'startrev' and should hence be
825 consistent with file size. If startrev is not specified, working directory's
833 consistent with file size. If startrev is not specified, working directory's
826 parent is used.
834 parent is used.
827
835
828 By default, ancestors of 'startrev' are returned. If 'descend' is True,
836 By default, ancestors of 'startrev' are returned. If 'descend' is True,
829 descendants of 'startrev' are returned though renames are (currently) not
837 descendants of 'startrev' are returned though renames are (currently) not
830 followed in this direction.
838 followed in this direction.
831 """
839 """
832 args = getargsdict(x, 'followlines', 'file *lines startrev descend')
840 args = getargsdict(x, 'followlines', 'file *lines startrev descend')
833 if len(args['lines']) != 1:
841 if len(args['lines']) != 1:
834 raise error.ParseError(_("followlines requires a line range"))
842 raise error.ParseError(_("followlines requires a line range"))
835
843
836 rev = '.'
844 rev = '.'
837 if 'startrev' in args:
845 if 'startrev' in args:
838 revs = getset(repo, fullreposet(repo), args['startrev'])
846 revs = getset(repo, fullreposet(repo), args['startrev'])
839 if len(revs) != 1:
847 if len(revs) != 1:
840 raise error.ParseError(
848 raise error.ParseError(
841 # i18n: "followlines" is a keyword
849 # i18n: "followlines" is a keyword
842 _("followlines expects exactly one revision"))
850 _("followlines expects exactly one revision"))
843 rev = revs.last()
851 rev = revs.last()
844
852
845 pat = getstring(args['file'], _("followlines requires a pattern"))
853 pat = getstring(args['file'], _("followlines requires a pattern"))
846 if not matchmod.patkind(pat):
854 if not matchmod.patkind(pat):
847 fname = pathutil.canonpath(repo.root, repo.getcwd(), pat)
855 fname = pathutil.canonpath(repo.root, repo.getcwd(), pat)
848 else:
856 else:
849 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=repo[rev])
857 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=repo[rev])
850 files = [f for f in repo[rev] if m(f)]
858 files = [f for f in repo[rev] if m(f)]
851 if len(files) != 1:
859 if len(files) != 1:
852 # i18n: "followlines" is a keyword
860 # i18n: "followlines" is a keyword
853 raise error.ParseError(_("followlines expects exactly one file"))
861 raise error.ParseError(_("followlines expects exactly one file"))
854 fname = files[0]
862 fname = files[0]
855
863
856 # i18n: "followlines" is a keyword
864 # i18n: "followlines" is a keyword
857 lr = getrange(args['lines'][0], _("followlines expects a line range"))
865 lr = getrange(args['lines'][0], _("followlines expects a line range"))
858 fromline, toline = [getinteger(a, _("line range bounds must be integers"))
866 fromline, toline = [getinteger(a, _("line range bounds must be integers"))
859 for a in lr]
867 for a in lr]
860 fromline, toline = util.processlinerange(fromline, toline)
868 fromline, toline = util.processlinerange(fromline, toline)
861
869
862 fctx = repo[rev].filectx(fname)
870 fctx = repo[rev].filectx(fname)
863 descend = False
871 descend = False
864 if 'descend' in args:
872 if 'descend' in args:
865 descend = getboolean(args['descend'],
873 descend = getboolean(args['descend'],
866 # i18n: "descend" is a keyword
874 # i18n: "descend" is a keyword
867 _("descend argument must be a boolean"))
875 _("descend argument must be a boolean"))
868 if descend:
876 if descend:
869 rs = generatorset(
877 rs = generatorset(
870 (c.rev() for c, _linerange
878 (c.rev() for c, _linerange
871 in dagop.blockdescendants(fctx, fromline, toline)),
879 in dagop.blockdescendants(fctx, fromline, toline)),
872 iterasc=True)
880 iterasc=True)
873 else:
881 else:
874 rs = generatorset(
882 rs = generatorset(
875 (c.rev() for c, _linerange
883 (c.rev() for c, _linerange
876 in dagop.blockancestors(fctx, fromline, toline)),
884 in dagop.blockancestors(fctx, fromline, toline)),
877 iterasc=False)
885 iterasc=False)
878 return subset & rs
886 return subset & rs
879
887
880 @predicate('all()', safe=True)
888 @predicate('all()', safe=True)
881 def getall(repo, subset, x):
889 def getall(repo, subset, x):
882 """All changesets, the same as ``0:tip``.
890 """All changesets, the same as ``0:tip``.
883 """
891 """
884 # i18n: "all" is a keyword
892 # i18n: "all" is a keyword
885 getargs(x, 0, 0, _("all takes no arguments"))
893 getargs(x, 0, 0, _("all takes no arguments"))
886 return subset & spanset(repo) # drop "null" if any
894 return subset & spanset(repo) # drop "null" if any
887
895
888 @predicate('grep(regex)')
896 @predicate('grep(regex)')
889 def grep(repo, subset, x):
897 def grep(repo, subset, x):
890 """Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
898 """Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
891 to ensure special escape characters are handled correctly. Unlike
899 to ensure special escape characters are handled correctly. Unlike
892 ``keyword(string)``, the match is case-sensitive.
900 ``keyword(string)``, the match is case-sensitive.
893 """
901 """
894 try:
902 try:
895 # i18n: "grep" is a keyword
903 # i18n: "grep" is a keyword
896 gr = re.compile(getstring(x, _("grep requires a string")))
904 gr = re.compile(getstring(x, _("grep requires a string")))
897 except re.error as e:
905 except re.error as e:
898 raise error.ParseError(_('invalid match pattern: %s') % e)
906 raise error.ParseError(_('invalid match pattern: %s') % e)
899
907
900 def matches(x):
908 def matches(x):
901 c = repo[x]
909 c = repo[x]
902 for e in c.files() + [c.user(), c.description()]:
910 for e in c.files() + [c.user(), c.description()]:
903 if gr.search(e):
911 if gr.search(e):
904 return True
912 return True
905 return False
913 return False
906
914
907 return subset.filter(matches, condrepr=('<grep %r>', gr.pattern))
915 return subset.filter(matches, condrepr=('<grep %r>', gr.pattern))
908
916
909 @predicate('_matchfiles', safe=True)
917 @predicate('_matchfiles', safe=True)
910 def _matchfiles(repo, subset, x):
918 def _matchfiles(repo, subset, x):
911 # _matchfiles takes a revset list of prefixed arguments:
919 # _matchfiles takes a revset list of prefixed arguments:
912 #
920 #
913 # [p:foo, i:bar, x:baz]
921 # [p:foo, i:bar, x:baz]
914 #
922 #
915 # builds a match object from them and filters subset. Allowed
923 # builds a match object from them and filters subset. Allowed
916 # prefixes are 'p:' for regular patterns, 'i:' for include
924 # prefixes are 'p:' for regular patterns, 'i:' for include
917 # patterns and 'x:' for exclude patterns. Use 'r:' prefix to pass
925 # patterns and 'x:' for exclude patterns. Use 'r:' prefix to pass
918 # a revision identifier, or the empty string to reference the
926 # a revision identifier, or the empty string to reference the
919 # working directory, from which the match object is
927 # working directory, from which the match object is
920 # initialized. Use 'd:' to set the default matching mode, default
928 # initialized. Use 'd:' to set the default matching mode, default
921 # to 'glob'. At most one 'r:' and 'd:' argument can be passed.
929 # to 'glob'. At most one 'r:' and 'd:' argument can be passed.
922
930
923 l = getargs(x, 1, -1, "_matchfiles requires at least one argument")
931 l = getargs(x, 1, -1, "_matchfiles requires at least one argument")
924 pats, inc, exc = [], [], []
932 pats, inc, exc = [], [], []
925 rev, default = None, None
933 rev, default = None, None
926 for arg in l:
934 for arg in l:
927 s = getstring(arg, "_matchfiles requires string arguments")
935 s = getstring(arg, "_matchfiles requires string arguments")
928 prefix, value = s[:2], s[2:]
936 prefix, value = s[:2], s[2:]
929 if prefix == 'p:':
937 if prefix == 'p:':
930 pats.append(value)
938 pats.append(value)
931 elif prefix == 'i:':
939 elif prefix == 'i:':
932 inc.append(value)
940 inc.append(value)
933 elif prefix == 'x:':
941 elif prefix == 'x:':
934 exc.append(value)
942 exc.append(value)
935 elif prefix == 'r:':
943 elif prefix == 'r:':
936 if rev is not None:
944 if rev is not None:
937 raise error.ParseError('_matchfiles expected at most one '
945 raise error.ParseError('_matchfiles expected at most one '
938 'revision')
946 'revision')
939 if value != '': # empty means working directory; leave rev as None
947 if value != '': # empty means working directory; leave rev as None
940 rev = value
948 rev = value
941 elif prefix == 'd:':
949 elif prefix == 'd:':
942 if default is not None:
950 if default is not None:
943 raise error.ParseError('_matchfiles expected at most one '
951 raise error.ParseError('_matchfiles expected at most one '
944 'default mode')
952 'default mode')
945 default = value
953 default = value
946 else:
954 else:
947 raise error.ParseError('invalid _matchfiles prefix: %s' % prefix)
955 raise error.ParseError('invalid _matchfiles prefix: %s' % prefix)
948 if not default:
956 if not default:
949 default = 'glob'
957 default = 'glob'
950
958
951 m = matchmod.match(repo.root, repo.getcwd(), pats, include=inc,
959 m = matchmod.match(repo.root, repo.getcwd(), pats, include=inc,
952 exclude=exc, ctx=repo[rev], default=default)
960 exclude=exc, ctx=repo[rev], default=default)
953
961
954 # This directly read the changelog data as creating changectx for all
962 # This directly read the changelog data as creating changectx for all
955 # revisions is quite expensive.
963 # revisions is quite expensive.
956 getfiles = repo.changelog.readfiles
964 getfiles = repo.changelog.readfiles
957 wdirrev = node.wdirrev
965 wdirrev = node.wdirrev
958 def matches(x):
966 def matches(x):
959 if x == wdirrev:
967 if x == wdirrev:
960 files = repo[x].files()
968 files = repo[x].files()
961 else:
969 else:
962 files = getfiles(x)
970 files = getfiles(x)
963 for f in files:
971 for f in files:
964 if m(f):
972 if m(f):
965 return True
973 return True
966 return False
974 return False
967
975
968 return subset.filter(matches,
976 return subset.filter(matches,
969 condrepr=('<matchfiles patterns=%r, include=%r '
977 condrepr=('<matchfiles patterns=%r, include=%r '
970 'exclude=%r, default=%r, rev=%r>',
978 'exclude=%r, default=%r, rev=%r>',
971 pats, inc, exc, default, rev))
979 pats, inc, exc, default, rev))
972
980
973 @predicate('file(pattern)', safe=True)
981 @predicate('file(pattern)', safe=True)
974 def hasfile(repo, subset, x):
982 def hasfile(repo, subset, x):
975 """Changesets affecting files matched by pattern.
983 """Changesets affecting files matched by pattern.
976
984
977 For a faster but less accurate result, consider using ``filelog()``
985 For a faster but less accurate result, consider using ``filelog()``
978 instead.
986 instead.
979
987
980 This predicate uses ``glob:`` as the default kind of pattern.
988 This predicate uses ``glob:`` as the default kind of pattern.
981 """
989 """
982 # i18n: "file" is a keyword
990 # i18n: "file" is a keyword
983 pat = getstring(x, _("file requires a pattern"))
991 pat = getstring(x, _("file requires a pattern"))
984 return _matchfiles(repo, subset, ('string', 'p:' + pat))
992 return _matchfiles(repo, subset, ('string', 'p:' + pat))
985
993
986 @predicate('head()', safe=True)
994 @predicate('head()', safe=True)
987 def head(repo, subset, x):
995 def head(repo, subset, x):
988 """Changeset is a named branch head.
996 """Changeset is a named branch head.
989 """
997 """
990 # i18n: "head" is a keyword
998 # i18n: "head" is a keyword
991 getargs(x, 0, 0, _("head takes no arguments"))
999 getargs(x, 0, 0, _("head takes no arguments"))
992 hs = set()
1000 hs = set()
993 cl = repo.changelog
1001 cl = repo.changelog
994 for ls in repo.branchmap().itervalues():
1002 for ls in repo.branchmap().itervalues():
995 hs.update(cl.rev(h) for h in ls)
1003 hs.update(cl.rev(h) for h in ls)
996 return subset & baseset(hs)
1004 return subset & baseset(hs)
997
1005
998 @predicate('heads(set)', safe=True)
1006 @predicate('heads(set)', safe=True)
999 def heads(repo, subset, x):
1007 def heads(repo, subset, x):
1000 """Members of set with no children in set.
1008 """Members of set with no children in set.
1001 """
1009 """
1002 s = getset(repo, subset, x)
1010 s = getset(repo, subset, x)
1003 ps = parents(repo, subset, x)
1011 ps = parents(repo, subset, x)
1004 return s - ps
1012 return s - ps
1005
1013
1006 @predicate('hidden()', safe=True)
1014 @predicate('hidden()', safe=True)
1007 def hidden(repo, subset, x):
1015 def hidden(repo, subset, x):
1008 """Hidden changesets.
1016 """Hidden changesets.
1009 """
1017 """
1010 # i18n: "hidden" is a keyword
1018 # i18n: "hidden" is a keyword
1011 getargs(x, 0, 0, _("hidden takes no arguments"))
1019 getargs(x, 0, 0, _("hidden takes no arguments"))
1012 hiddenrevs = repoview.filterrevs(repo, 'visible')
1020 hiddenrevs = repoview.filterrevs(repo, 'visible')
1013 return subset & hiddenrevs
1021 return subset & hiddenrevs
1014
1022
1015 @predicate('keyword(string)', safe=True)
1023 @predicate('keyword(string)', safe=True)
1016 def keyword(repo, subset, x):
1024 def keyword(repo, subset, x):
1017 """Search commit message, user name, and names of changed files for
1025 """Search commit message, user name, and names of changed files for
1018 string. The match is case-insensitive.
1026 string. The match is case-insensitive.
1019
1027
1020 For a regular expression or case sensitive search of these fields, use
1028 For a regular expression or case sensitive search of these fields, use
1021 ``grep(regex)``.
1029 ``grep(regex)``.
1022 """
1030 """
1023 # i18n: "keyword" is a keyword
1031 # i18n: "keyword" is a keyword
1024 kw = encoding.lower(getstring(x, _("keyword requires a string")))
1032 kw = encoding.lower(getstring(x, _("keyword requires a string")))
1025
1033
1026 def matches(r):
1034 def matches(r):
1027 c = repo[r]
1035 c = repo[r]
1028 return any(kw in encoding.lower(t)
1036 return any(kw in encoding.lower(t)
1029 for t in c.files() + [c.user(), c.description()])
1037 for t in c.files() + [c.user(), c.description()])
1030
1038
1031 return subset.filter(matches, condrepr=('<keyword %r>', kw))
1039 return subset.filter(matches, condrepr=('<keyword %r>', kw))
1032
1040
1033 @predicate('limit(set[, n[, offset]])', safe=True, takeorder=True)
1041 @predicate('limit(set[, n[, offset]])', safe=True, takeorder=True)
1034 def limit(repo, subset, x, order):
1042 def limit(repo, subset, x, order):
1035 """First n members of set, defaulting to 1, starting from offset.
1043 """First n members of set, defaulting to 1, starting from offset.
1036 """
1044 """
1037 args = getargsdict(x, 'limit', 'set n offset')
1045 args = getargsdict(x, 'limit', 'set n offset')
1038 if 'set' not in args:
1046 if 'set' not in args:
1039 # i18n: "limit" is a keyword
1047 # i18n: "limit" is a keyword
1040 raise error.ParseError(_("limit requires one to three arguments"))
1048 raise error.ParseError(_("limit requires one to three arguments"))
1041 # i18n: "limit" is a keyword
1049 # i18n: "limit" is a keyword
1042 lim = getinteger(args.get('n'), _("limit expects a number"), default=1)
1050 lim = getinteger(args.get('n'), _("limit expects a number"), default=1)
1043 if lim < 0:
1051 if lim < 0:
1044 raise error.ParseError(_("negative number to select"))
1052 raise error.ParseError(_("negative number to select"))
1045 # i18n: "limit" is a keyword
1053 # i18n: "limit" is a keyword
1046 ofs = getinteger(args.get('offset'), _("limit expects a number"), default=0)
1054 ofs = getinteger(args.get('offset'), _("limit expects a number"), default=0)
1047 if ofs < 0:
1055 if ofs < 0:
1048 raise error.ParseError(_("negative offset"))
1056 raise error.ParseError(_("negative offset"))
1049 os = getset(repo, fullreposet(repo), args['set'])
1057 os = getset(repo, fullreposet(repo), args['set'])
1050 ls = os.slice(ofs, ofs + lim)
1058 ls = os.slice(ofs, ofs + lim)
1051 if order == followorder and lim > 1:
1059 if order == followorder and lim > 1:
1052 return subset & ls
1060 return subset & ls
1053 return ls & subset
1061 return ls & subset
1054
1062
1055 @predicate('last(set, [n])', safe=True, takeorder=True)
1063 @predicate('last(set, [n])', safe=True, takeorder=True)
1056 def last(repo, subset, x, order):
1064 def last(repo, subset, x, order):
1057 """Last n members of set, defaulting to 1.
1065 """Last n members of set, defaulting to 1.
1058 """
1066 """
1059 # i18n: "last" is a keyword
1067 # i18n: "last" is a keyword
1060 l = getargs(x, 1, 2, _("last requires one or two arguments"))
1068 l = getargs(x, 1, 2, _("last requires one or two arguments"))
1061 lim = 1
1069 lim = 1
1062 if len(l) == 2:
1070 if len(l) == 2:
1063 # i18n: "last" is a keyword
1071 # i18n: "last" is a keyword
1064 lim = getinteger(l[1], _("last expects a number"))
1072 lim = getinteger(l[1], _("last expects a number"))
1065 if lim < 0:
1073 if lim < 0:
1066 raise error.ParseError(_("negative number to select"))
1074 raise error.ParseError(_("negative number to select"))
1067 os = getset(repo, fullreposet(repo), l[0])
1075 os = getset(repo, fullreposet(repo), l[0])
1068 os.reverse()
1076 os.reverse()
1069 ls = os.slice(0, lim)
1077 ls = os.slice(0, lim)
1070 if order == followorder and lim > 1:
1078 if order == followorder and lim > 1:
1071 return subset & ls
1079 return subset & ls
1072 ls.reverse()
1080 ls.reverse()
1073 return ls & subset
1081 return ls & subset
1074
1082
1075 @predicate('max(set)', safe=True)
1083 @predicate('max(set)', safe=True)
1076 def maxrev(repo, subset, x):
1084 def maxrev(repo, subset, x):
1077 """Changeset with highest revision number in set.
1085 """Changeset with highest revision number in set.
1078 """
1086 """
1079 os = getset(repo, fullreposet(repo), x)
1087 os = getset(repo, fullreposet(repo), x)
1080 try:
1088 try:
1081 m = os.max()
1089 m = os.max()
1082 if m in subset:
1090 if m in subset:
1083 return baseset([m], datarepr=('<max %r, %r>', subset, os))
1091 return baseset([m], datarepr=('<max %r, %r>', subset, os))
1084 except ValueError:
1092 except ValueError:
1085 # os.max() throws a ValueError when the collection is empty.
1093 # os.max() throws a ValueError when the collection is empty.
1086 # Same as python's max().
1094 # Same as python's max().
1087 pass
1095 pass
1088 return baseset(datarepr=('<max %r, %r>', subset, os))
1096 return baseset(datarepr=('<max %r, %r>', subset, os))
1089
1097
1090 @predicate('merge()', safe=True)
1098 @predicate('merge()', safe=True)
1091 def merge(repo, subset, x):
1099 def merge(repo, subset, x):
1092 """Changeset is a merge changeset.
1100 """Changeset is a merge changeset.
1093 """
1101 """
1094 # i18n: "merge" is a keyword
1102 # i18n: "merge" is a keyword
1095 getargs(x, 0, 0, _("merge takes no arguments"))
1103 getargs(x, 0, 0, _("merge takes no arguments"))
1096 cl = repo.changelog
1104 cl = repo.changelog
1097 return subset.filter(lambda r: cl.parentrevs(r)[1] != -1,
1105 return subset.filter(lambda r: cl.parentrevs(r)[1] != -1,
1098 condrepr='<merge>')
1106 condrepr='<merge>')
1099
1107
1100 @predicate('branchpoint()', safe=True)
1108 @predicate('branchpoint()', safe=True)
1101 def branchpoint(repo, subset, x):
1109 def branchpoint(repo, subset, x):
1102 """Changesets with more than one child.
1110 """Changesets with more than one child.
1103 """
1111 """
1104 # i18n: "branchpoint" is a keyword
1112 # i18n: "branchpoint" is a keyword
1105 getargs(x, 0, 0, _("branchpoint takes no arguments"))
1113 getargs(x, 0, 0, _("branchpoint takes no arguments"))
1106 cl = repo.changelog
1114 cl = repo.changelog
1107 if not subset:
1115 if not subset:
1108 return baseset()
1116 return baseset()
1109 # XXX this should be 'parentset.min()' assuming 'parentset' is a smartset
1117 # XXX this should be 'parentset.min()' assuming 'parentset' is a smartset
1110 # (and if it is not, it should.)
1118 # (and if it is not, it should.)
1111 baserev = min(subset)
1119 baserev = min(subset)
1112 parentscount = [0]*(len(repo) - baserev)
1120 parentscount = [0]*(len(repo) - baserev)
1113 for r in cl.revs(start=baserev + 1):
1121 for r in cl.revs(start=baserev + 1):
1114 for p in cl.parentrevs(r):
1122 for p in cl.parentrevs(r):
1115 if p >= baserev:
1123 if p >= baserev:
1116 parentscount[p - baserev] += 1
1124 parentscount[p - baserev] += 1
1117 return subset.filter(lambda r: parentscount[r - baserev] > 1,
1125 return subset.filter(lambda r: parentscount[r - baserev] > 1,
1118 condrepr='<branchpoint>')
1126 condrepr='<branchpoint>')
1119
1127
1120 @predicate('min(set)', safe=True)
1128 @predicate('min(set)', safe=True)
1121 def minrev(repo, subset, x):
1129 def minrev(repo, subset, x):
1122 """Changeset with lowest revision number in set.
1130 """Changeset with lowest revision number in set.
1123 """
1131 """
1124 os = getset(repo, fullreposet(repo), x)
1132 os = getset(repo, fullreposet(repo), x)
1125 try:
1133 try:
1126 m = os.min()
1134 m = os.min()
1127 if m in subset:
1135 if m in subset:
1128 return baseset([m], datarepr=('<min %r, %r>', subset, os))
1136 return baseset([m], datarepr=('<min %r, %r>', subset, os))
1129 except ValueError:
1137 except ValueError:
1130 # os.min() throws a ValueError when the collection is empty.
1138 # os.min() throws a ValueError when the collection is empty.
1131 # Same as python's min().
1139 # Same as python's min().
1132 pass
1140 pass
1133 return baseset(datarepr=('<min %r, %r>', subset, os))
1141 return baseset(datarepr=('<min %r, %r>', subset, os))
1134
1142
1135 @predicate('modifies(pattern)', safe=True)
1143 @predicate('modifies(pattern)', safe=True)
1136 def modifies(repo, subset, x):
1144 def modifies(repo, subset, x):
1137 """Changesets modifying files matched by pattern.
1145 """Changesets modifying files matched by pattern.
1138
1146
1139 The pattern without explicit kind like ``glob:`` is expected to be
1147 The pattern without explicit kind like ``glob:`` is expected to be
1140 relative to the current directory and match against a file or a
1148 relative to the current directory and match against a file or a
1141 directory.
1149 directory.
1142 """
1150 """
1143 # i18n: "modifies" is a keyword
1151 # i18n: "modifies" is a keyword
1144 pat = getstring(x, _("modifies requires a pattern"))
1152 pat = getstring(x, _("modifies requires a pattern"))
1145 return checkstatus(repo, subset, pat, 0)
1153 return checkstatus(repo, subset, pat, 0)
1146
1154
1147 @predicate('named(namespace)')
1155 @predicate('named(namespace)')
1148 def named(repo, subset, x):
1156 def named(repo, subset, x):
1149 """The changesets in a given namespace.
1157 """The changesets in a given namespace.
1150
1158
1151 Pattern matching is supported for `namespace`. See
1159 Pattern matching is supported for `namespace`. See
1152 :hg:`help revisions.patterns`.
1160 :hg:`help revisions.patterns`.
1153 """
1161 """
1154 # i18n: "named" is a keyword
1162 # i18n: "named" is a keyword
1155 args = getargs(x, 1, 1, _('named requires a namespace argument'))
1163 args = getargs(x, 1, 1, _('named requires a namespace argument'))
1156
1164
1157 ns = getstring(args[0],
1165 ns = getstring(args[0],
1158 # i18n: "named" is a keyword
1166 # i18n: "named" is a keyword
1159 _('the argument to named must be a string'))
1167 _('the argument to named must be a string'))
1160 kind, pattern, matcher = util.stringmatcher(ns)
1168 kind, pattern, matcher = util.stringmatcher(ns)
1161 namespaces = set()
1169 namespaces = set()
1162 if kind == 'literal':
1170 if kind == 'literal':
1163 if pattern not in repo.names:
1171 if pattern not in repo.names:
1164 raise error.RepoLookupError(_("namespace '%s' does not exist")
1172 raise error.RepoLookupError(_("namespace '%s' does not exist")
1165 % ns)
1173 % ns)
1166 namespaces.add(repo.names[pattern])
1174 namespaces.add(repo.names[pattern])
1167 else:
1175 else:
1168 for name, ns in repo.names.iteritems():
1176 for name, ns in repo.names.iteritems():
1169 if matcher(name):
1177 if matcher(name):
1170 namespaces.add(ns)
1178 namespaces.add(ns)
1171 if not namespaces:
1179 if not namespaces:
1172 raise error.RepoLookupError(_("no namespace exists"
1180 raise error.RepoLookupError(_("no namespace exists"
1173 " that match '%s'") % pattern)
1181 " that match '%s'") % pattern)
1174
1182
1175 names = set()
1183 names = set()
1176 for ns in namespaces:
1184 for ns in namespaces:
1177 for name in ns.listnames(repo):
1185 for name in ns.listnames(repo):
1178 if name not in ns.deprecated:
1186 if name not in ns.deprecated:
1179 names.update(repo[n].rev() for n in ns.nodes(repo, name))
1187 names.update(repo[n].rev() for n in ns.nodes(repo, name))
1180
1188
1181 names -= {node.nullrev}
1189 names -= {node.nullrev}
1182 return subset & names
1190 return subset & names
1183
1191
1184 @predicate('id(string)', safe=True)
1192 @predicate('id(string)', safe=True)
1185 def node_(repo, subset, x):
1193 def node_(repo, subset, x):
1186 """Revision non-ambiguously specified by the given hex string prefix.
1194 """Revision non-ambiguously specified by the given hex string prefix.
1187 """
1195 """
1188 # i18n: "id" is a keyword
1196 # i18n: "id" is a keyword
1189 l = getargs(x, 1, 1, _("id requires one argument"))
1197 l = getargs(x, 1, 1, _("id requires one argument"))
1190 # i18n: "id" is a keyword
1198 # i18n: "id" is a keyword
1191 n = getstring(l[0], _("id requires a string"))
1199 n = getstring(l[0], _("id requires a string"))
1192 if len(n) == 40:
1200 if len(n) == 40:
1193 try:
1201 try:
1194 rn = repo.changelog.rev(node.bin(n))
1202 rn = repo.changelog.rev(node.bin(n))
1195 except error.WdirUnsupported:
1203 except error.WdirUnsupported:
1196 rn = node.wdirrev
1204 rn = node.wdirrev
1197 except (LookupError, TypeError):
1205 except (LookupError, TypeError):
1198 rn = None
1206 rn = None
1199 else:
1207 else:
1200 rn = None
1208 rn = None
1201 try:
1209 try:
1202 pm = repo.changelog._partialmatch(n)
1210 pm = repo.changelog._partialmatch(n)
1203 if pm is not None:
1211 if pm is not None:
1204 rn = repo.changelog.rev(pm)
1212 rn = repo.changelog.rev(pm)
1205 except error.WdirUnsupported:
1213 except error.WdirUnsupported:
1206 rn = node.wdirrev
1214 rn = node.wdirrev
1207
1215
1208 if rn is None:
1216 if rn is None:
1209 return baseset()
1217 return baseset()
1210 result = baseset([rn])
1218 result = baseset([rn])
1211 return result & subset
1219 return result & subset
1212
1220
1213 @predicate('obsolete()', safe=True)
1221 @predicate('obsolete()', safe=True)
1214 def obsolete(repo, subset, x):
1222 def obsolete(repo, subset, x):
1215 """Mutable changeset with a newer version."""
1223 """Mutable changeset with a newer version."""
1216 # i18n: "obsolete" is a keyword
1224 # i18n: "obsolete" is a keyword
1217 getargs(x, 0, 0, _("obsolete takes no arguments"))
1225 getargs(x, 0, 0, _("obsolete takes no arguments"))
1218 obsoletes = obsmod.getrevs(repo, 'obsolete')
1226 obsoletes = obsmod.getrevs(repo, 'obsolete')
1219 return subset & obsoletes
1227 return subset & obsoletes
1220
1228
1221 @predicate('only(set, [set])', safe=True)
1229 @predicate('only(set, [set])', safe=True)
1222 def only(repo, subset, x):
1230 def only(repo, subset, x):
1223 """Changesets that are ancestors of the first set that are not ancestors
1231 """Changesets that are ancestors of the first set that are not ancestors
1224 of any other head in the repo. If a second set is specified, the result
1232 of any other head in the repo. If a second set is specified, the result
1225 is ancestors of the first set that are not ancestors of the second set
1233 is ancestors of the first set that are not ancestors of the second set
1226 (i.e. ::<set1> - ::<set2>).
1234 (i.e. ::<set1> - ::<set2>).
1227 """
1235 """
1228 cl = repo.changelog
1236 cl = repo.changelog
1229 # i18n: "only" is a keyword
1237 # i18n: "only" is a keyword
1230 args = getargs(x, 1, 2, _('only takes one or two arguments'))
1238 args = getargs(x, 1, 2, _('only takes one or two arguments'))
1231 include = getset(repo, fullreposet(repo), args[0])
1239 include = getset(repo, fullreposet(repo), args[0])
1232 if len(args) == 1:
1240 if len(args) == 1:
1233 if not include:
1241 if not include:
1234 return baseset()
1242 return baseset()
1235
1243
1236 descendants = set(dagop.revdescendants(repo, include, False))
1244 descendants = set(dagop.revdescendants(repo, include, False))
1237 exclude = [rev for rev in cl.headrevs()
1245 exclude = [rev for rev in cl.headrevs()
1238 if not rev in descendants and not rev in include]
1246 if not rev in descendants and not rev in include]
1239 else:
1247 else:
1240 exclude = getset(repo, fullreposet(repo), args[1])
1248 exclude = getset(repo, fullreposet(repo), args[1])
1241
1249
1242 results = set(cl.findmissingrevs(common=exclude, heads=include))
1250 results = set(cl.findmissingrevs(common=exclude, heads=include))
1243 # XXX we should turn this into a baseset instead of a set, smartset may do
1251 # XXX we should turn this into a baseset instead of a set, smartset may do
1244 # some optimizations from the fact this is a baseset.
1252 # some optimizations from the fact this is a baseset.
1245 return subset & results
1253 return subset & results
1246
1254
1247 @predicate('origin([set])', safe=True)
1255 @predicate('origin([set])', safe=True)
1248 def origin(repo, subset, x):
1256 def origin(repo, subset, x):
1249 """
1257 """
1250 Changesets that were specified as a source for the grafts, transplants or
1258 Changesets that were specified as a source for the grafts, transplants or
1251 rebases that created the given revisions. Omitting the optional set is the
1259 rebases that created the given revisions. Omitting the optional set is the
1252 same as passing all(). If a changeset created by these operations is itself
1260 same as passing all(). If a changeset created by these operations is itself
1253 specified as a source for one of these operations, only the source changeset
1261 specified as a source for one of these operations, only the source changeset
1254 for the first operation is selected.
1262 for the first operation is selected.
1255 """
1263 """
1256 if x is not None:
1264 if x is not None:
1257 dests = getset(repo, fullreposet(repo), x)
1265 dests = getset(repo, fullreposet(repo), x)
1258 else:
1266 else:
1259 dests = fullreposet(repo)
1267 dests = fullreposet(repo)
1260
1268
1261 def _firstsrc(rev):
1269 def _firstsrc(rev):
1262 src = _getrevsource(repo, rev)
1270 src = _getrevsource(repo, rev)
1263 if src is None:
1271 if src is None:
1264 return None
1272 return None
1265
1273
1266 while True:
1274 while True:
1267 prev = _getrevsource(repo, src)
1275 prev = _getrevsource(repo, src)
1268
1276
1269 if prev is None:
1277 if prev is None:
1270 return src
1278 return src
1271 src = prev
1279 src = prev
1272
1280
1273 o = {_firstsrc(r) for r in dests}
1281 o = {_firstsrc(r) for r in dests}
1274 o -= {None}
1282 o -= {None}
1275 # XXX we should turn this into a baseset instead of a set, smartset may do
1283 # XXX we should turn this into a baseset instead of a set, smartset may do
1276 # some optimizations from the fact this is a baseset.
1284 # some optimizations from the fact this is a baseset.
1277 return subset & o
1285 return subset & o
1278
1286
1279 @predicate('outgoing([path])', safe=False)
1287 @predicate('outgoing([path])', safe=False)
1280 def outgoing(repo, subset, x):
1288 def outgoing(repo, subset, x):
1281 """Changesets not found in the specified destination repository, or the
1289 """Changesets not found in the specified destination repository, or the
1282 default push location.
1290 default push location.
1283 """
1291 """
1284 # Avoid cycles.
1292 # Avoid cycles.
1285 from . import (
1293 from . import (
1286 discovery,
1294 discovery,
1287 hg,
1295 hg,
1288 )
1296 )
1289 # i18n: "outgoing" is a keyword
1297 # i18n: "outgoing" is a keyword
1290 l = getargs(x, 0, 1, _("outgoing takes one or no arguments"))
1298 l = getargs(x, 0, 1, _("outgoing takes one or no arguments"))
1291 # i18n: "outgoing" is a keyword
1299 # i18n: "outgoing" is a keyword
1292 dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
1300 dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
1293 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
1301 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
1294 dest, branches = hg.parseurl(dest)
1302 dest, branches = hg.parseurl(dest)
1295 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1303 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1296 if revs:
1304 if revs:
1297 revs = [repo.lookup(rev) for rev in revs]
1305 revs = [repo.lookup(rev) for rev in revs]
1298 other = hg.peer(repo, {}, dest)
1306 other = hg.peer(repo, {}, dest)
1299 repo.ui.pushbuffer()
1307 repo.ui.pushbuffer()
1300 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs)
1308 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs)
1301 repo.ui.popbuffer()
1309 repo.ui.popbuffer()
1302 cl = repo.changelog
1310 cl = repo.changelog
1303 o = {cl.rev(r) for r in outgoing.missing}
1311 o = {cl.rev(r) for r in outgoing.missing}
1304 return subset & o
1312 return subset & o
1305
1313
1306 @predicate('p1([set])', safe=True)
1314 @predicate('p1([set])', safe=True)
1307 def p1(repo, subset, x):
1315 def p1(repo, subset, x):
1308 """First parent of changesets in set, or the working directory.
1316 """First parent of changesets in set, or the working directory.
1309 """
1317 """
1310 if x is None:
1318 if x is None:
1311 p = repo[x].p1().rev()
1319 p = repo[x].p1().rev()
1312 if p >= 0:
1320 if p >= 0:
1313 return subset & baseset([p])
1321 return subset & baseset([p])
1314 return baseset()
1322 return baseset()
1315
1323
1316 ps = set()
1324 ps = set()
1317 cl = repo.changelog
1325 cl = repo.changelog
1318 for r in getset(repo, fullreposet(repo), x):
1326 for r in getset(repo, fullreposet(repo), x):
1319 try:
1327 try:
1320 ps.add(cl.parentrevs(r)[0])
1328 ps.add(cl.parentrevs(r)[0])
1321 except error.WdirUnsupported:
1329 except error.WdirUnsupported:
1322 ps.add(repo[r].parents()[0].rev())
1330 ps.add(repo[r].parents()[0].rev())
1323 ps -= {node.nullrev}
1331 ps -= {node.nullrev}
1324 # XXX we should turn this into a baseset instead of a set, smartset may do
1332 # XXX we should turn this into a baseset instead of a set, smartset may do
1325 # some optimizations from the fact this is a baseset.
1333 # some optimizations from the fact this is a baseset.
1326 return subset & ps
1334 return subset & ps
1327
1335
1328 @predicate('p2([set])', safe=True)
1336 @predicate('p2([set])', safe=True)
1329 def p2(repo, subset, x):
1337 def p2(repo, subset, x):
1330 """Second parent of changesets in set, or the working directory.
1338 """Second parent of changesets in set, or the working directory.
1331 """
1339 """
1332 if x is None:
1340 if x is None:
1333 ps = repo[x].parents()
1341 ps = repo[x].parents()
1334 try:
1342 try:
1335 p = ps[1].rev()
1343 p = ps[1].rev()
1336 if p >= 0:
1344 if p >= 0:
1337 return subset & baseset([p])
1345 return subset & baseset([p])
1338 return baseset()
1346 return baseset()
1339 except IndexError:
1347 except IndexError:
1340 return baseset()
1348 return baseset()
1341
1349
1342 ps = set()
1350 ps = set()
1343 cl = repo.changelog
1351 cl = repo.changelog
1344 for r in getset(repo, fullreposet(repo), x):
1352 for r in getset(repo, fullreposet(repo), x):
1345 try:
1353 try:
1346 ps.add(cl.parentrevs(r)[1])
1354 ps.add(cl.parentrevs(r)[1])
1347 except error.WdirUnsupported:
1355 except error.WdirUnsupported:
1348 parents = repo[r].parents()
1356 parents = repo[r].parents()
1349 if len(parents) == 2:
1357 if len(parents) == 2:
1350 ps.add(parents[1])
1358 ps.add(parents[1])
1351 ps -= {node.nullrev}
1359 ps -= {node.nullrev}
1352 # XXX we should turn this into a baseset instead of a set, smartset may do
1360 # XXX we should turn this into a baseset instead of a set, smartset may do
1353 # some optimizations from the fact this is a baseset.
1361 # some optimizations from the fact this is a baseset.
1354 return subset & ps
1362 return subset & ps
1355
1363
1356 def parentpost(repo, subset, x, order):
1364 def parentpost(repo, subset, x, order):
1357 return p1(repo, subset, x)
1365 return p1(repo, subset, x)
1358
1366
1359 @predicate('parents([set])', safe=True)
1367 @predicate('parents([set])', safe=True)
1360 def parents(repo, subset, x):
1368 def parents(repo, subset, x):
1361 """
1369 """
1362 The set of all parents for all changesets in set, or the working directory.
1370 The set of all parents for all changesets in set, or the working directory.
1363 """
1371 """
1364 if x is None:
1372 if x is None:
1365 ps = set(p.rev() for p in repo[x].parents())
1373 ps = set(p.rev() for p in repo[x].parents())
1366 else:
1374 else:
1367 ps = set()
1375 ps = set()
1368 cl = repo.changelog
1376 cl = repo.changelog
1369 up = ps.update
1377 up = ps.update
1370 parentrevs = cl.parentrevs
1378 parentrevs = cl.parentrevs
1371 for r in getset(repo, fullreposet(repo), x):
1379 for r in getset(repo, fullreposet(repo), x):
1372 try:
1380 try:
1373 up(parentrevs(r))
1381 up(parentrevs(r))
1374 except error.WdirUnsupported:
1382 except error.WdirUnsupported:
1375 up(p.rev() for p in repo[r].parents())
1383 up(p.rev() for p in repo[r].parents())
1376 ps -= {node.nullrev}
1384 ps -= {node.nullrev}
1377 return subset & ps
1385 return subset & ps
1378
1386
1379 def _phase(repo, subset, *targets):
1387 def _phase(repo, subset, *targets):
1380 """helper to select all rev in <targets> phases"""
1388 """helper to select all rev in <targets> phases"""
1381 s = repo._phasecache.getrevset(repo, targets)
1389 s = repo._phasecache.getrevset(repo, targets)
1382 return subset & s
1390 return subset & s
1383
1391
1384 @predicate('draft()', safe=True)
1392 @predicate('draft()', safe=True)
1385 def draft(repo, subset, x):
1393 def draft(repo, subset, x):
1386 """Changeset in draft phase."""
1394 """Changeset in draft phase."""
1387 # i18n: "draft" is a keyword
1395 # i18n: "draft" is a keyword
1388 getargs(x, 0, 0, _("draft takes no arguments"))
1396 getargs(x, 0, 0, _("draft takes no arguments"))
1389 target = phases.draft
1397 target = phases.draft
1390 return _phase(repo, subset, target)
1398 return _phase(repo, subset, target)
1391
1399
1392 @predicate('secret()', safe=True)
1400 @predicate('secret()', safe=True)
1393 def secret(repo, subset, x):
1401 def secret(repo, subset, x):
1394 """Changeset in secret phase."""
1402 """Changeset in secret phase."""
1395 # i18n: "secret" is a keyword
1403 # i18n: "secret" is a keyword
1396 getargs(x, 0, 0, _("secret takes no arguments"))
1404 getargs(x, 0, 0, _("secret takes no arguments"))
1397 target = phases.secret
1405 target = phases.secret
1398 return _phase(repo, subset, target)
1406 return _phase(repo, subset, target)
1399
1407
1400 def parentspec(repo, subset, x, n, order):
1408 def parentspec(repo, subset, x, n, order):
1401 """``set^0``
1409 """``set^0``
1402 The set.
1410 The set.
1403 ``set^1`` (or ``set^``), ``set^2``
1411 ``set^1`` (or ``set^``), ``set^2``
1404 First or second parent, respectively, of all changesets in set.
1412 First or second parent, respectively, of all changesets in set.
1405 """
1413 """
1406 try:
1414 try:
1407 n = int(n[1])
1415 n = int(n[1])
1408 if n not in (0, 1, 2):
1416 if n not in (0, 1, 2):
1409 raise ValueError
1417 raise ValueError
1410 except (TypeError, ValueError):
1418 except (TypeError, ValueError):
1411 raise error.ParseError(_("^ expects a number 0, 1, or 2"))
1419 raise error.ParseError(_("^ expects a number 0, 1, or 2"))
1412 ps = set()
1420 ps = set()
1413 cl = repo.changelog
1421 cl = repo.changelog
1414 for r in getset(repo, fullreposet(repo), x):
1422 for r in getset(repo, fullreposet(repo), x):
1415 if n == 0:
1423 if n == 0:
1416 ps.add(r)
1424 ps.add(r)
1417 elif n == 1:
1425 elif n == 1:
1418 try:
1426 try:
1419 ps.add(cl.parentrevs(r)[0])
1427 ps.add(cl.parentrevs(r)[0])
1420 except error.WdirUnsupported:
1428 except error.WdirUnsupported:
1421 ps.add(repo[r].parents()[0].rev())
1429 ps.add(repo[r].parents()[0].rev())
1422 else:
1430 else:
1423 try:
1431 try:
1424 parents = cl.parentrevs(r)
1432 parents = cl.parentrevs(r)
1425 if parents[1] != node.nullrev:
1433 if parents[1] != node.nullrev:
1426 ps.add(parents[1])
1434 ps.add(parents[1])
1427 except error.WdirUnsupported:
1435 except error.WdirUnsupported:
1428 parents = repo[r].parents()
1436 parents = repo[r].parents()
1429 if len(parents) == 2:
1437 if len(parents) == 2:
1430 ps.add(parents[1].rev())
1438 ps.add(parents[1].rev())
1431 return subset & ps
1439 return subset & ps
1432
1440
1433 @predicate('present(set)', safe=True)
1441 @predicate('present(set)', safe=True)
1434 def present(repo, subset, x):
1442 def present(repo, subset, x):
1435 """An empty set, if any revision in set isn't found; otherwise,
1443 """An empty set, if any revision in set isn't found; otherwise,
1436 all revisions in set.
1444 all revisions in set.
1437
1445
1438 If any of specified revisions is not present in the local repository,
1446 If any of specified revisions is not present in the local repository,
1439 the query is normally aborted. But this predicate allows the query
1447 the query is normally aborted. But this predicate allows the query
1440 to continue even in such cases.
1448 to continue even in such cases.
1441 """
1449 """
1442 try:
1450 try:
1443 return getset(repo, subset, x)
1451 return getset(repo, subset, x)
1444 except error.RepoLookupError:
1452 except error.RepoLookupError:
1445 return baseset()
1453 return baseset()
1446
1454
1447 # for internal use
1455 # for internal use
1448 @predicate('_notpublic', safe=True)
1456 @predicate('_notpublic', safe=True)
1449 def _notpublic(repo, subset, x):
1457 def _notpublic(repo, subset, x):
1450 getargs(x, 0, 0, "_notpublic takes no arguments")
1458 getargs(x, 0, 0, "_notpublic takes no arguments")
1451 return _phase(repo, subset, phases.draft, phases.secret)
1459 return _phase(repo, subset, phases.draft, phases.secret)
1452
1460
1453 @predicate('public()', safe=True)
1461 @predicate('public()', safe=True)
1454 def public(repo, subset, x):
1462 def public(repo, subset, x):
1455 """Changeset in public phase."""
1463 """Changeset in public phase."""
1456 # i18n: "public" is a keyword
1464 # i18n: "public" is a keyword
1457 getargs(x, 0, 0, _("public takes no arguments"))
1465 getargs(x, 0, 0, _("public takes no arguments"))
1458 phase = repo._phasecache.phase
1466 phase = repo._phasecache.phase
1459 target = phases.public
1467 target = phases.public
1460 condition = lambda r: phase(repo, r) == target
1468 condition = lambda r: phase(repo, r) == target
1461 return subset.filter(condition, condrepr=('<phase %r>', target),
1469 return subset.filter(condition, condrepr=('<phase %r>', target),
1462 cache=False)
1470 cache=False)
1463
1471
1464 @predicate('remote([id [,path]])', safe=False)
1472 @predicate('remote([id [,path]])', safe=False)
1465 def remote(repo, subset, x):
1473 def remote(repo, subset, x):
1466 """Local revision that corresponds to the given identifier in a
1474 """Local revision that corresponds to the given identifier in a
1467 remote repository, if present. Here, the '.' identifier is a
1475 remote repository, if present. Here, the '.' identifier is a
1468 synonym for the current local branch.
1476 synonym for the current local branch.
1469 """
1477 """
1470
1478
1471 from . import hg # avoid start-up nasties
1479 from . import hg # avoid start-up nasties
1472 # i18n: "remote" is a keyword
1480 # i18n: "remote" is a keyword
1473 l = getargs(x, 0, 2, _("remote takes zero, one, or two arguments"))
1481 l = getargs(x, 0, 2, _("remote takes zero, one, or two arguments"))
1474
1482
1475 q = '.'
1483 q = '.'
1476 if len(l) > 0:
1484 if len(l) > 0:
1477 # i18n: "remote" is a keyword
1485 # i18n: "remote" is a keyword
1478 q = getstring(l[0], _("remote requires a string id"))
1486 q = getstring(l[0], _("remote requires a string id"))
1479 if q == '.':
1487 if q == '.':
1480 q = repo['.'].branch()
1488 q = repo['.'].branch()
1481
1489
1482 dest = ''
1490 dest = ''
1483 if len(l) > 1:
1491 if len(l) > 1:
1484 # i18n: "remote" is a keyword
1492 # i18n: "remote" is a keyword
1485 dest = getstring(l[1], _("remote requires a repository path"))
1493 dest = getstring(l[1], _("remote requires a repository path"))
1486 dest = repo.ui.expandpath(dest or 'default')
1494 dest = repo.ui.expandpath(dest or 'default')
1487 dest, branches = hg.parseurl(dest)
1495 dest, branches = hg.parseurl(dest)
1488 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1496 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1489 if revs:
1497 if revs:
1490 revs = [repo.lookup(rev) for rev in revs]
1498 revs = [repo.lookup(rev) for rev in revs]
1491 other = hg.peer(repo, {}, dest)
1499 other = hg.peer(repo, {}, dest)
1492 n = other.lookup(q)
1500 n = other.lookup(q)
1493 if n in repo:
1501 if n in repo:
1494 r = repo[n].rev()
1502 r = repo[n].rev()
1495 if r in subset:
1503 if r in subset:
1496 return baseset([r])
1504 return baseset([r])
1497 return baseset()
1505 return baseset()
1498
1506
1499 @predicate('removes(pattern)', safe=True)
1507 @predicate('removes(pattern)', safe=True)
1500 def removes(repo, subset, x):
1508 def removes(repo, subset, x):
1501 """Changesets which remove files matching pattern.
1509 """Changesets which remove files matching pattern.
1502
1510
1503 The pattern without explicit kind like ``glob:`` is expected to be
1511 The pattern without explicit kind like ``glob:`` is expected to be
1504 relative to the current directory and match against a file or a
1512 relative to the current directory and match against a file or a
1505 directory.
1513 directory.
1506 """
1514 """
1507 # i18n: "removes" is a keyword
1515 # i18n: "removes" is a keyword
1508 pat = getstring(x, _("removes requires a pattern"))
1516 pat = getstring(x, _("removes requires a pattern"))
1509 return checkstatus(repo, subset, pat, 2)
1517 return checkstatus(repo, subset, pat, 2)
1510
1518
1511 @predicate('rev(number)', safe=True)
1519 @predicate('rev(number)', safe=True)
1512 def rev(repo, subset, x):
1520 def rev(repo, subset, x):
1513 """Revision with the given numeric identifier.
1521 """Revision with the given numeric identifier.
1514 """
1522 """
1515 # i18n: "rev" is a keyword
1523 # i18n: "rev" is a keyword
1516 l = getargs(x, 1, 1, _("rev requires one argument"))
1524 l = getargs(x, 1, 1, _("rev requires one argument"))
1517 try:
1525 try:
1518 # i18n: "rev" is a keyword
1526 # i18n: "rev" is a keyword
1519 l = int(getstring(l[0], _("rev requires a number")))
1527 l = int(getstring(l[0], _("rev requires a number")))
1520 except (TypeError, ValueError):
1528 except (TypeError, ValueError):
1521 # i18n: "rev" is a keyword
1529 # i18n: "rev" is a keyword
1522 raise error.ParseError(_("rev expects a number"))
1530 raise error.ParseError(_("rev expects a number"))
1523 if l not in repo.changelog and l not in (node.nullrev, node.wdirrev):
1531 if l not in repo.changelog and l not in (node.nullrev, node.wdirrev):
1524 return baseset()
1532 return baseset()
1525 return subset & baseset([l])
1533 return subset & baseset([l])
1526
1534
1527 @predicate('matching(revision [, field])', safe=True)
1535 @predicate('matching(revision [, field])', safe=True)
1528 def matching(repo, subset, x):
1536 def matching(repo, subset, x):
1529 """Changesets in which a given set of fields match the set of fields in the
1537 """Changesets in which a given set of fields match the set of fields in the
1530 selected revision or set.
1538 selected revision or set.
1531
1539
1532 To match more than one field pass the list of fields to match separated
1540 To match more than one field pass the list of fields to match separated
1533 by spaces (e.g. ``author description``).
1541 by spaces (e.g. ``author description``).
1534
1542
1535 Valid fields are most regular revision fields and some special fields.
1543 Valid fields are most regular revision fields and some special fields.
1536
1544
1537 Regular revision fields are ``description``, ``author``, ``branch``,
1545 Regular revision fields are ``description``, ``author``, ``branch``,
1538 ``date``, ``files``, ``phase``, ``parents``, ``substate``, ``user``
1546 ``date``, ``files``, ``phase``, ``parents``, ``substate``, ``user``
1539 and ``diff``.
1547 and ``diff``.
1540 Note that ``author`` and ``user`` are synonyms. ``diff`` refers to the
1548 Note that ``author`` and ``user`` are synonyms. ``diff`` refers to the
1541 contents of the revision. Two revisions matching their ``diff`` will
1549 contents of the revision. Two revisions matching their ``diff`` will
1542 also match their ``files``.
1550 also match their ``files``.
1543
1551
1544 Special fields are ``summary`` and ``metadata``:
1552 Special fields are ``summary`` and ``metadata``:
1545 ``summary`` matches the first line of the description.
1553 ``summary`` matches the first line of the description.
1546 ``metadata`` is equivalent to matching ``description user date``
1554 ``metadata`` is equivalent to matching ``description user date``
1547 (i.e. it matches the main metadata fields).
1555 (i.e. it matches the main metadata fields).
1548
1556
1549 ``metadata`` is the default field which is used when no fields are
1557 ``metadata`` is the default field which is used when no fields are
1550 specified. You can match more than one field at a time.
1558 specified. You can match more than one field at a time.
1551 """
1559 """
1552 # i18n: "matching" is a keyword
1560 # i18n: "matching" is a keyword
1553 l = getargs(x, 1, 2, _("matching takes 1 or 2 arguments"))
1561 l = getargs(x, 1, 2, _("matching takes 1 or 2 arguments"))
1554
1562
1555 revs = getset(repo, fullreposet(repo), l[0])
1563 revs = getset(repo, fullreposet(repo), l[0])
1556
1564
1557 fieldlist = ['metadata']
1565 fieldlist = ['metadata']
1558 if len(l) > 1:
1566 if len(l) > 1:
1559 fieldlist = getstring(l[1],
1567 fieldlist = getstring(l[1],
1560 # i18n: "matching" is a keyword
1568 # i18n: "matching" is a keyword
1561 _("matching requires a string "
1569 _("matching requires a string "
1562 "as its second argument")).split()
1570 "as its second argument")).split()
1563
1571
1564 # Make sure that there are no repeated fields,
1572 # Make sure that there are no repeated fields,
1565 # expand the 'special' 'metadata' field type
1573 # expand the 'special' 'metadata' field type
1566 # and check the 'files' whenever we check the 'diff'
1574 # and check the 'files' whenever we check the 'diff'
1567 fields = []
1575 fields = []
1568 for field in fieldlist:
1576 for field in fieldlist:
1569 if field == 'metadata':
1577 if field == 'metadata':
1570 fields += ['user', 'description', 'date']
1578 fields += ['user', 'description', 'date']
1571 elif field == 'diff':
1579 elif field == 'diff':
1572 # a revision matching the diff must also match the files
1580 # a revision matching the diff must also match the files
1573 # since matching the diff is very costly, make sure to
1581 # since matching the diff is very costly, make sure to
1574 # also match the files first
1582 # also match the files first
1575 fields += ['files', 'diff']
1583 fields += ['files', 'diff']
1576 else:
1584 else:
1577 if field == 'author':
1585 if field == 'author':
1578 field = 'user'
1586 field = 'user'
1579 fields.append(field)
1587 fields.append(field)
1580 fields = set(fields)
1588 fields = set(fields)
1581 if 'summary' in fields and 'description' in fields:
1589 if 'summary' in fields and 'description' in fields:
1582 # If a revision matches its description it also matches its summary
1590 # If a revision matches its description it also matches its summary
1583 fields.discard('summary')
1591 fields.discard('summary')
1584
1592
1585 # We may want to match more than one field
1593 # We may want to match more than one field
1586 # Not all fields take the same amount of time to be matched
1594 # Not all fields take the same amount of time to be matched
1587 # Sort the selected fields in order of increasing matching cost
1595 # Sort the selected fields in order of increasing matching cost
1588 fieldorder = ['phase', 'parents', 'user', 'date', 'branch', 'summary',
1596 fieldorder = ['phase', 'parents', 'user', 'date', 'branch', 'summary',
1589 'files', 'description', 'substate', 'diff']
1597 'files', 'description', 'substate', 'diff']
1590 def fieldkeyfunc(f):
1598 def fieldkeyfunc(f):
1591 try:
1599 try:
1592 return fieldorder.index(f)
1600 return fieldorder.index(f)
1593 except ValueError:
1601 except ValueError:
1594 # assume an unknown field is very costly
1602 # assume an unknown field is very costly
1595 return len(fieldorder)
1603 return len(fieldorder)
1596 fields = list(fields)
1604 fields = list(fields)
1597 fields.sort(key=fieldkeyfunc)
1605 fields.sort(key=fieldkeyfunc)
1598
1606
1599 # Each field will be matched with its own "getfield" function
1607 # Each field will be matched with its own "getfield" function
1600 # which will be added to the getfieldfuncs array of functions
1608 # which will be added to the getfieldfuncs array of functions
1601 getfieldfuncs = []
1609 getfieldfuncs = []
1602 _funcs = {
1610 _funcs = {
1603 'user': lambda r: repo[r].user(),
1611 'user': lambda r: repo[r].user(),
1604 'branch': lambda r: repo[r].branch(),
1612 'branch': lambda r: repo[r].branch(),
1605 'date': lambda r: repo[r].date(),
1613 'date': lambda r: repo[r].date(),
1606 'description': lambda r: repo[r].description(),
1614 'description': lambda r: repo[r].description(),
1607 'files': lambda r: repo[r].files(),
1615 'files': lambda r: repo[r].files(),
1608 'parents': lambda r: repo[r].parents(),
1616 'parents': lambda r: repo[r].parents(),
1609 'phase': lambda r: repo[r].phase(),
1617 'phase': lambda r: repo[r].phase(),
1610 'substate': lambda r: repo[r].substate,
1618 'substate': lambda r: repo[r].substate,
1611 'summary': lambda r: repo[r].description().splitlines()[0],
1619 'summary': lambda r: repo[r].description().splitlines()[0],
1612 'diff': lambda r: list(repo[r].diff(git=True),)
1620 'diff': lambda r: list(repo[r].diff(git=True),)
1613 }
1621 }
1614 for info in fields:
1622 for info in fields:
1615 getfield = _funcs.get(info, None)
1623 getfield = _funcs.get(info, None)
1616 if getfield is None:
1624 if getfield is None:
1617 raise error.ParseError(
1625 raise error.ParseError(
1618 # i18n: "matching" is a keyword
1626 # i18n: "matching" is a keyword
1619 _("unexpected field name passed to matching: %s") % info)
1627 _("unexpected field name passed to matching: %s") % info)
1620 getfieldfuncs.append(getfield)
1628 getfieldfuncs.append(getfield)
1621 # convert the getfield array of functions into a "getinfo" function
1629 # convert the getfield array of functions into a "getinfo" function
1622 # which returns an array of field values (or a single value if there
1630 # which returns an array of field values (or a single value if there
1623 # is only one field to match)
1631 # is only one field to match)
1624 getinfo = lambda r: [f(r) for f in getfieldfuncs]
1632 getinfo = lambda r: [f(r) for f in getfieldfuncs]
1625
1633
1626 def matches(x):
1634 def matches(x):
1627 for rev in revs:
1635 for rev in revs:
1628 target = getinfo(rev)
1636 target = getinfo(rev)
1629 match = True
1637 match = True
1630 for n, f in enumerate(getfieldfuncs):
1638 for n, f in enumerate(getfieldfuncs):
1631 if target[n] != f(x):
1639 if target[n] != f(x):
1632 match = False
1640 match = False
1633 if match:
1641 if match:
1634 return True
1642 return True
1635 return False
1643 return False
1636
1644
1637 return subset.filter(matches, condrepr=('<matching%r %r>', fields, revs))
1645 return subset.filter(matches, condrepr=('<matching%r %r>', fields, revs))
1638
1646
1639 @predicate('reverse(set)', safe=True, takeorder=True)
1647 @predicate('reverse(set)', safe=True, takeorder=True)
1640 def reverse(repo, subset, x, order):
1648 def reverse(repo, subset, x, order):
1641 """Reverse order of set.
1649 """Reverse order of set.
1642 """
1650 """
1643 l = getset(repo, subset, x)
1651 l = getset(repo, subset, x)
1644 if order == defineorder:
1652 if order == defineorder:
1645 l.reverse()
1653 l.reverse()
1646 return l
1654 return l
1647
1655
1648 @predicate('roots(set)', safe=True)
1656 @predicate('roots(set)', safe=True)
1649 def roots(repo, subset, x):
1657 def roots(repo, subset, x):
1650 """Changesets in set with no parent changeset in set.
1658 """Changesets in set with no parent changeset in set.
1651 """
1659 """
1652 s = getset(repo, fullreposet(repo), x)
1660 s = getset(repo, fullreposet(repo), x)
1653 parents = repo.changelog.parentrevs
1661 parents = repo.changelog.parentrevs
1654 def filter(r):
1662 def filter(r):
1655 for p in parents(r):
1663 for p in parents(r):
1656 if 0 <= p and p in s:
1664 if 0 <= p and p in s:
1657 return False
1665 return False
1658 return True
1666 return True
1659 return subset & s.filter(filter, condrepr='<roots>')
1667 return subset & s.filter(filter, condrepr='<roots>')
1660
1668
1661 _sortkeyfuncs = {
1669 _sortkeyfuncs = {
1662 'rev': lambda c: c.rev(),
1670 'rev': lambda c: c.rev(),
1663 'branch': lambda c: c.branch(),
1671 'branch': lambda c: c.branch(),
1664 'desc': lambda c: c.description(),
1672 'desc': lambda c: c.description(),
1665 'user': lambda c: c.user(),
1673 'user': lambda c: c.user(),
1666 'author': lambda c: c.user(),
1674 'author': lambda c: c.user(),
1667 'date': lambda c: c.date()[0],
1675 'date': lambda c: c.date()[0],
1668 }
1676 }
1669
1677
1670 def _getsortargs(x):
1678 def _getsortargs(x):
1671 """Parse sort options into (set, [(key, reverse)], opts)"""
1679 """Parse sort options into (set, [(key, reverse)], opts)"""
1672 args = getargsdict(x, 'sort', 'set keys topo.firstbranch')
1680 args = getargsdict(x, 'sort', 'set keys topo.firstbranch')
1673 if 'set' not in args:
1681 if 'set' not in args:
1674 # i18n: "sort" is a keyword
1682 # i18n: "sort" is a keyword
1675 raise error.ParseError(_('sort requires one or two arguments'))
1683 raise error.ParseError(_('sort requires one or two arguments'))
1676 keys = "rev"
1684 keys = "rev"
1677 if 'keys' in args:
1685 if 'keys' in args:
1678 # i18n: "sort" is a keyword
1686 # i18n: "sort" is a keyword
1679 keys = getstring(args['keys'], _("sort spec must be a string"))
1687 keys = getstring(args['keys'], _("sort spec must be a string"))
1680
1688
1681 keyflags = []
1689 keyflags = []
1682 for k in keys.split():
1690 for k in keys.split():
1683 fk = k
1691 fk = k
1684 reverse = (k[0] == '-')
1692 reverse = (k[0] == '-')
1685 if reverse:
1693 if reverse:
1686 k = k[1:]
1694 k = k[1:]
1687 if k not in _sortkeyfuncs and k != 'topo':
1695 if k not in _sortkeyfuncs and k != 'topo':
1688 raise error.ParseError(_("unknown sort key %r") % fk)
1696 raise error.ParseError(_("unknown sort key %r") % fk)
1689 keyflags.append((k, reverse))
1697 keyflags.append((k, reverse))
1690
1698
1691 if len(keyflags) > 1 and any(k == 'topo' for k, reverse in keyflags):
1699 if len(keyflags) > 1 and any(k == 'topo' for k, reverse in keyflags):
1692 # i18n: "topo" is a keyword
1700 # i18n: "topo" is a keyword
1693 raise error.ParseError(_('topo sort order cannot be combined '
1701 raise error.ParseError(_('topo sort order cannot be combined '
1694 'with other sort keys'))
1702 'with other sort keys'))
1695
1703
1696 opts = {}
1704 opts = {}
1697 if 'topo.firstbranch' in args:
1705 if 'topo.firstbranch' in args:
1698 if any(k == 'topo' for k, reverse in keyflags):
1706 if any(k == 'topo' for k, reverse in keyflags):
1699 opts['topo.firstbranch'] = args['topo.firstbranch']
1707 opts['topo.firstbranch'] = args['topo.firstbranch']
1700 else:
1708 else:
1701 # i18n: "topo" and "topo.firstbranch" are keywords
1709 # i18n: "topo" and "topo.firstbranch" are keywords
1702 raise error.ParseError(_('topo.firstbranch can only be used '
1710 raise error.ParseError(_('topo.firstbranch can only be used '
1703 'when using the topo sort key'))
1711 'when using the topo sort key'))
1704
1712
1705 return args['set'], keyflags, opts
1713 return args['set'], keyflags, opts
1706
1714
1707 @predicate('sort(set[, [-]key... [, ...]])', safe=True, takeorder=True)
1715 @predicate('sort(set[, [-]key... [, ...]])', safe=True, takeorder=True)
1708 def sort(repo, subset, x, order):
1716 def sort(repo, subset, x, order):
1709 """Sort set by keys. The default sort order is ascending, specify a key
1717 """Sort set by keys. The default sort order is ascending, specify a key
1710 as ``-key`` to sort in descending order.
1718 as ``-key`` to sort in descending order.
1711
1719
1712 The keys can be:
1720 The keys can be:
1713
1721
1714 - ``rev`` for the revision number,
1722 - ``rev`` for the revision number,
1715 - ``branch`` for the branch name,
1723 - ``branch`` for the branch name,
1716 - ``desc`` for the commit message (description),
1724 - ``desc`` for the commit message (description),
1717 - ``user`` for user name (``author`` can be used as an alias),
1725 - ``user`` for user name (``author`` can be used as an alias),
1718 - ``date`` for the commit date
1726 - ``date`` for the commit date
1719 - ``topo`` for a reverse topographical sort
1727 - ``topo`` for a reverse topographical sort
1720
1728
1721 The ``topo`` sort order cannot be combined with other sort keys. This sort
1729 The ``topo`` sort order cannot be combined with other sort keys. This sort
1722 takes one optional argument, ``topo.firstbranch``, which takes a revset that
1730 takes one optional argument, ``topo.firstbranch``, which takes a revset that
1723 specifies what topographical branches to prioritize in the sort.
1731 specifies what topographical branches to prioritize in the sort.
1724
1732
1725 """
1733 """
1726 s, keyflags, opts = _getsortargs(x)
1734 s, keyflags, opts = _getsortargs(x)
1727 revs = getset(repo, subset, s)
1735 revs = getset(repo, subset, s)
1728
1736
1729 if not keyflags or order != defineorder:
1737 if not keyflags or order != defineorder:
1730 return revs
1738 return revs
1731 if len(keyflags) == 1 and keyflags[0][0] == "rev":
1739 if len(keyflags) == 1 and keyflags[0][0] == "rev":
1732 revs.sort(reverse=keyflags[0][1])
1740 revs.sort(reverse=keyflags[0][1])
1733 return revs
1741 return revs
1734 elif keyflags[0][0] == "topo":
1742 elif keyflags[0][0] == "topo":
1735 firstbranch = ()
1743 firstbranch = ()
1736 if 'topo.firstbranch' in opts:
1744 if 'topo.firstbranch' in opts:
1737 firstbranch = getset(repo, subset, opts['topo.firstbranch'])
1745 firstbranch = getset(repo, subset, opts['topo.firstbranch'])
1738 revs = baseset(dagop.toposort(revs, repo.changelog.parentrevs,
1746 revs = baseset(dagop.toposort(revs, repo.changelog.parentrevs,
1739 firstbranch),
1747 firstbranch),
1740 istopo=True)
1748 istopo=True)
1741 if keyflags[0][1]:
1749 if keyflags[0][1]:
1742 revs.reverse()
1750 revs.reverse()
1743 return revs
1751 return revs
1744
1752
1745 # sort() is guaranteed to be stable
1753 # sort() is guaranteed to be stable
1746 ctxs = [repo[r] for r in revs]
1754 ctxs = [repo[r] for r in revs]
1747 for k, reverse in reversed(keyflags):
1755 for k, reverse in reversed(keyflags):
1748 ctxs.sort(key=_sortkeyfuncs[k], reverse=reverse)
1756 ctxs.sort(key=_sortkeyfuncs[k], reverse=reverse)
1749 return baseset([c.rev() for c in ctxs])
1757 return baseset([c.rev() for c in ctxs])
1750
1758
1751 @predicate('subrepo([pattern])')
1759 @predicate('subrepo([pattern])')
1752 def subrepo(repo, subset, x):
1760 def subrepo(repo, subset, x):
1753 """Changesets that add, modify or remove the given subrepo. If no subrepo
1761 """Changesets that add, modify or remove the given subrepo. If no subrepo
1754 pattern is named, any subrepo changes are returned.
1762 pattern is named, any subrepo changes are returned.
1755 """
1763 """
1756 # i18n: "subrepo" is a keyword
1764 # i18n: "subrepo" is a keyword
1757 args = getargs(x, 0, 1, _('subrepo takes at most one argument'))
1765 args = getargs(x, 0, 1, _('subrepo takes at most one argument'))
1758 pat = None
1766 pat = None
1759 if len(args) != 0:
1767 if len(args) != 0:
1760 pat = getstring(args[0], _("subrepo requires a pattern"))
1768 pat = getstring(args[0], _("subrepo requires a pattern"))
1761
1769
1762 m = matchmod.exact(repo.root, repo.root, ['.hgsubstate'])
1770 m = matchmod.exact(repo.root, repo.root, ['.hgsubstate'])
1763
1771
1764 def submatches(names):
1772 def submatches(names):
1765 k, p, m = util.stringmatcher(pat)
1773 k, p, m = util.stringmatcher(pat)
1766 for name in names:
1774 for name in names:
1767 if m(name):
1775 if m(name):
1768 yield name
1776 yield name
1769
1777
1770 def matches(x):
1778 def matches(x):
1771 c = repo[x]
1779 c = repo[x]
1772 s = repo.status(c.p1().node(), c.node(), match=m)
1780 s = repo.status(c.p1().node(), c.node(), match=m)
1773
1781
1774 if pat is None:
1782 if pat is None:
1775 return s.added or s.modified or s.removed
1783 return s.added or s.modified or s.removed
1776
1784
1777 if s.added:
1785 if s.added:
1778 return any(submatches(c.substate.keys()))
1786 return any(submatches(c.substate.keys()))
1779
1787
1780 if s.modified:
1788 if s.modified:
1781 subs = set(c.p1().substate.keys())
1789 subs = set(c.p1().substate.keys())
1782 subs.update(c.substate.keys())
1790 subs.update(c.substate.keys())
1783
1791
1784 for path in submatches(subs):
1792 for path in submatches(subs):
1785 if c.p1().substate.get(path) != c.substate.get(path):
1793 if c.p1().substate.get(path) != c.substate.get(path):
1786 return True
1794 return True
1787
1795
1788 if s.removed:
1796 if s.removed:
1789 return any(submatches(c.p1().substate.keys()))
1797 return any(submatches(c.p1().substate.keys()))
1790
1798
1791 return False
1799 return False
1792
1800
1793 return subset.filter(matches, condrepr=('<subrepo %r>', pat))
1801 return subset.filter(matches, condrepr=('<subrepo %r>', pat))
1794
1802
1795 def _substringmatcher(pattern, casesensitive=True):
1803 def _substringmatcher(pattern, casesensitive=True):
1796 kind, pattern, matcher = util.stringmatcher(pattern,
1804 kind, pattern, matcher = util.stringmatcher(pattern,
1797 casesensitive=casesensitive)
1805 casesensitive=casesensitive)
1798 if kind == 'literal':
1806 if kind == 'literal':
1799 if not casesensitive:
1807 if not casesensitive:
1800 pattern = encoding.lower(pattern)
1808 pattern = encoding.lower(pattern)
1801 matcher = lambda s: pattern in encoding.lower(s)
1809 matcher = lambda s: pattern in encoding.lower(s)
1802 else:
1810 else:
1803 matcher = lambda s: pattern in s
1811 matcher = lambda s: pattern in s
1804 return kind, pattern, matcher
1812 return kind, pattern, matcher
1805
1813
1806 @predicate('tag([name])', safe=True)
1814 @predicate('tag([name])', safe=True)
1807 def tag(repo, subset, x):
1815 def tag(repo, subset, x):
1808 """The specified tag by name, or all tagged revisions if no name is given.
1816 """The specified tag by name, or all tagged revisions if no name is given.
1809
1817
1810 Pattern matching is supported for `name`. See
1818 Pattern matching is supported for `name`. See
1811 :hg:`help revisions.patterns`.
1819 :hg:`help revisions.patterns`.
1812 """
1820 """
1813 # i18n: "tag" is a keyword
1821 # i18n: "tag" is a keyword
1814 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
1822 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
1815 cl = repo.changelog
1823 cl = repo.changelog
1816 if args:
1824 if args:
1817 pattern = getstring(args[0],
1825 pattern = getstring(args[0],
1818 # i18n: "tag" is a keyword
1826 # i18n: "tag" is a keyword
1819 _('the argument to tag must be a string'))
1827 _('the argument to tag must be a string'))
1820 kind, pattern, matcher = util.stringmatcher(pattern)
1828 kind, pattern, matcher = util.stringmatcher(pattern)
1821 if kind == 'literal':
1829 if kind == 'literal':
1822 # avoid resolving all tags
1830 # avoid resolving all tags
1823 tn = repo._tagscache.tags.get(pattern, None)
1831 tn = repo._tagscache.tags.get(pattern, None)
1824 if tn is None:
1832 if tn is None:
1825 raise error.RepoLookupError(_("tag '%s' does not exist")
1833 raise error.RepoLookupError(_("tag '%s' does not exist")
1826 % pattern)
1834 % pattern)
1827 s = {repo[tn].rev()}
1835 s = {repo[tn].rev()}
1828 else:
1836 else:
1829 s = {cl.rev(n) for t, n in repo.tagslist() if matcher(t)}
1837 s = {cl.rev(n) for t, n in repo.tagslist() if matcher(t)}
1830 else:
1838 else:
1831 s = {cl.rev(n) for t, n in repo.tagslist() if t != 'tip'}
1839 s = {cl.rev(n) for t, n in repo.tagslist() if t != 'tip'}
1832 return subset & s
1840 return subset & s
1833
1841
1834 @predicate('tagged', safe=True)
1842 @predicate('tagged', safe=True)
1835 def tagged(repo, subset, x):
1843 def tagged(repo, subset, x):
1836 return tag(repo, subset, x)
1844 return tag(repo, subset, x)
1837
1845
1838 @predicate('unstable()', safe=True)
1846 @predicate('unstable()', safe=True)
1839 def unstable(repo, subset, x):
1847 def unstable(repo, subset, x):
1840 """Non-obsolete changesets with obsolete ancestors.
1848 """Non-obsolete changesets with obsolete ancestors.
1841 """
1849 """
1842 # i18n: "unstable" is a keyword
1850 # i18n: "unstable" is a keyword
1843 getargs(x, 0, 0, _("unstable takes no arguments"))
1851 getargs(x, 0, 0, _("unstable takes no arguments"))
1844 unstables = obsmod.getrevs(repo, 'unstable')
1852 unstables = obsmod.getrevs(repo, 'unstable')
1845 return subset & unstables
1853 return subset & unstables
1846
1854
1847
1855
1848 @predicate('user(string)', safe=True)
1856 @predicate('user(string)', safe=True)
1849 def user(repo, subset, x):
1857 def user(repo, subset, x):
1850 """User name contains string. The match is case-insensitive.
1858 """User name contains string. The match is case-insensitive.
1851
1859
1852 Pattern matching is supported for `string`. See
1860 Pattern matching is supported for `string`. See
1853 :hg:`help revisions.patterns`.
1861 :hg:`help revisions.patterns`.
1854 """
1862 """
1855 return author(repo, subset, x)
1863 return author(repo, subset, x)
1856
1864
1857 @predicate('wdir()', safe=True)
1865 @predicate('wdir()', safe=True)
1858 def wdir(repo, subset, x):
1866 def wdir(repo, subset, x):
1859 """Working directory. (EXPERIMENTAL)"""
1867 """Working directory. (EXPERIMENTAL)"""
1860 # i18n: "wdir" is a keyword
1868 # i18n: "wdir" is a keyword
1861 getargs(x, 0, 0, _("wdir takes no arguments"))
1869 getargs(x, 0, 0, _("wdir takes no arguments"))
1862 if node.wdirrev in subset or isinstance(subset, fullreposet):
1870 if node.wdirrev in subset or isinstance(subset, fullreposet):
1863 return baseset([node.wdirrev])
1871 return baseset([node.wdirrev])
1864 return baseset()
1872 return baseset()
1865
1873
1866 def _orderedlist(repo, subset, x):
1874 def _orderedlist(repo, subset, x):
1867 s = getstring(x, "internal error")
1875 s = getstring(x, "internal error")
1868 if not s:
1876 if not s:
1869 return baseset()
1877 return baseset()
1870 # remove duplicates here. it's difficult for caller to deduplicate sets
1878 # remove duplicates here. it's difficult for caller to deduplicate sets
1871 # because different symbols can point to the same rev.
1879 # because different symbols can point to the same rev.
1872 cl = repo.changelog
1880 cl = repo.changelog
1873 ls = []
1881 ls = []
1874 seen = set()
1882 seen = set()
1875 for t in s.split('\0'):
1883 for t in s.split('\0'):
1876 try:
1884 try:
1877 # fast path for integer revision
1885 # fast path for integer revision
1878 r = int(t)
1886 r = int(t)
1879 if str(r) != t or r not in cl:
1887 if str(r) != t or r not in cl:
1880 raise ValueError
1888 raise ValueError
1881 revs = [r]
1889 revs = [r]
1882 except ValueError:
1890 except ValueError:
1883 revs = stringset(repo, subset, t)
1891 revs = stringset(repo, subset, t)
1884
1892
1885 for r in revs:
1893 for r in revs:
1886 if r in seen:
1894 if r in seen:
1887 continue
1895 continue
1888 if (r in subset
1896 if (r in subset
1889 or r == node.nullrev and isinstance(subset, fullreposet)):
1897 or r == node.nullrev and isinstance(subset, fullreposet)):
1890 ls.append(r)
1898 ls.append(r)
1891 seen.add(r)
1899 seen.add(r)
1892 return baseset(ls)
1900 return baseset(ls)
1893
1901
1894 # for internal use
1902 # for internal use
1895 @predicate('_list', safe=True, takeorder=True)
1903 @predicate('_list', safe=True, takeorder=True)
1896 def _list(repo, subset, x, order):
1904 def _list(repo, subset, x, order):
1897 if order == followorder:
1905 if order == followorder:
1898 # slow path to take the subset order
1906 # slow path to take the subset order
1899 return subset & _orderedlist(repo, fullreposet(repo), x)
1907 return subset & _orderedlist(repo, fullreposet(repo), x)
1900 else:
1908 else:
1901 return _orderedlist(repo, subset, x)
1909 return _orderedlist(repo, subset, x)
1902
1910
1903 def _orderedintlist(repo, subset, x):
1911 def _orderedintlist(repo, subset, x):
1904 s = getstring(x, "internal error")
1912 s = getstring(x, "internal error")
1905 if not s:
1913 if not s:
1906 return baseset()
1914 return baseset()
1907 ls = [int(r) for r in s.split('\0')]
1915 ls = [int(r) for r in s.split('\0')]
1908 s = subset
1916 s = subset
1909 return baseset([r for r in ls if r in s])
1917 return baseset([r for r in ls if r in s])
1910
1918
1911 # for internal use
1919 # for internal use
1912 @predicate('_intlist', safe=True, takeorder=True)
1920 @predicate('_intlist', safe=True, takeorder=True)
1913 def _intlist(repo, subset, x, order):
1921 def _intlist(repo, subset, x, order):
1914 if order == followorder:
1922 if order == followorder:
1915 # slow path to take the subset order
1923 # slow path to take the subset order
1916 return subset & _orderedintlist(repo, fullreposet(repo), x)
1924 return subset & _orderedintlist(repo, fullreposet(repo), x)
1917 else:
1925 else:
1918 return _orderedintlist(repo, subset, x)
1926 return _orderedintlist(repo, subset, x)
1919
1927
1920 def _orderedhexlist(repo, subset, x):
1928 def _orderedhexlist(repo, subset, x):
1921 s = getstring(x, "internal error")
1929 s = getstring(x, "internal error")
1922 if not s:
1930 if not s:
1923 return baseset()
1931 return baseset()
1924 cl = repo.changelog
1932 cl = repo.changelog
1925 ls = [cl.rev(node.bin(r)) for r in s.split('\0')]
1933 ls = [cl.rev(node.bin(r)) for r in s.split('\0')]
1926 s = subset
1934 s = subset
1927 return baseset([r for r in ls if r in s])
1935 return baseset([r for r in ls if r in s])
1928
1936
1929 # for internal use
1937 # for internal use
1930 @predicate('_hexlist', safe=True, takeorder=True)
1938 @predicate('_hexlist', safe=True, takeorder=True)
1931 def _hexlist(repo, subset, x, order):
1939 def _hexlist(repo, subset, x, order):
1932 if order == followorder:
1940 if order == followorder:
1933 # slow path to take the subset order
1941 # slow path to take the subset order
1934 return subset & _orderedhexlist(repo, fullreposet(repo), x)
1942 return subset & _orderedhexlist(repo, fullreposet(repo), x)
1935 else:
1943 else:
1936 return _orderedhexlist(repo, subset, x)
1944 return _orderedhexlist(repo, subset, x)
1937
1945
1938 methods = {
1946 methods = {
1939 "range": rangeset,
1947 "range": rangeset,
1940 "rangeall": rangeall,
1948 "rangeall": rangeall,
1941 "rangepre": rangepre,
1949 "rangepre": rangepre,
1942 "rangepost": rangepost,
1950 "rangepost": rangepost,
1943 "dagrange": dagrange,
1951 "dagrange": dagrange,
1944 "string": stringset,
1952 "string": stringset,
1945 "symbol": stringset,
1953 "symbol": stringset,
1946 "and": andset,
1954 "and": andset,
1947 "or": orset,
1955 "or": orset,
1948 "not": notset,
1956 "not": notset,
1949 "difference": differenceset,
1957 "difference": differenceset,
1950 "list": listset,
1958 "list": listset,
1951 "keyvalue": keyvaluepair,
1959 "keyvalue": keyvaluepair,
1952 "func": func,
1960 "func": func,
1953 "ancestor": ancestorspec,
1961 "ancestor": ancestorspec,
1954 "parent": parentspec,
1962 "parent": parentspec,
1955 "parentpost": parentpost,
1963 "parentpost": parentpost,
1956 }
1964 }
1957
1965
1958 def posttreebuilthook(tree, repo):
1966 def posttreebuilthook(tree, repo):
1959 # hook for extensions to execute code on the optimized tree
1967 # hook for extensions to execute code on the optimized tree
1960 pass
1968 pass
1961
1969
1962 def match(ui, spec, repo=None, order=defineorder):
1970 def match(ui, spec, repo=None, order=defineorder):
1963 """Create a matcher for a single revision spec
1971 """Create a matcher for a single revision spec
1964
1972
1965 If order=followorder, a matcher takes the ordering specified by the input
1973 If order=followorder, a matcher takes the ordering specified by the input
1966 set.
1974 set.
1967 """
1975 """
1968 return matchany(ui, [spec], repo=repo, order=order)
1976 return matchany(ui, [spec], repo=repo, order=order)
1969
1977
1970 def matchany(ui, specs, repo=None, order=defineorder):
1978 def matchany(ui, specs, repo=None, order=defineorder):
1971 """Create a matcher that will include any revisions matching one of the
1979 """Create a matcher that will include any revisions matching one of the
1972 given specs
1980 given specs
1973
1981
1974 If order=followorder, a matcher takes the ordering specified by the input
1982 If order=followorder, a matcher takes the ordering specified by the input
1975 set.
1983 set.
1976 """
1984 """
1977 if not specs:
1985 if not specs:
1978 def mfunc(repo, subset=None):
1986 def mfunc(repo, subset=None):
1979 return baseset()
1987 return baseset()
1980 return mfunc
1988 return mfunc
1981 if not all(specs):
1989 if not all(specs):
1982 raise error.ParseError(_("empty query"))
1990 raise error.ParseError(_("empty query"))
1983 lookup = None
1991 lookup = None
1984 if repo:
1992 if repo:
1985 lookup = repo.__contains__
1993 lookup = repo.__contains__
1986 if len(specs) == 1:
1994 if len(specs) == 1:
1987 tree = revsetlang.parse(specs[0], lookup)
1995 tree = revsetlang.parse(specs[0], lookup)
1988 else:
1996 else:
1989 tree = ('or',
1997 tree = ('or',
1990 ('list',) + tuple(revsetlang.parse(s, lookup) for s in specs))
1998 ('list',) + tuple(revsetlang.parse(s, lookup) for s in specs))
1991
1999
1992 if ui:
2000 if ui:
1993 tree = revsetlang.expandaliases(ui, tree)
2001 tree = revsetlang.expandaliases(ui, tree)
1994 tree = revsetlang.foldconcat(tree)
2002 tree = revsetlang.foldconcat(tree)
1995 tree = revsetlang.analyze(tree, order)
2003 tree = revsetlang.analyze(tree, order)
1996 tree = revsetlang.optimize(tree)
2004 tree = revsetlang.optimize(tree)
1997 posttreebuilthook(tree, repo)
2005 posttreebuilthook(tree, repo)
1998 return makematcher(tree)
2006 return makematcher(tree)
1999
2007
2000 def makematcher(tree):
2008 def makematcher(tree):
2001 """Create a matcher from an evaluatable tree"""
2009 """Create a matcher from an evaluatable tree"""
2002 def mfunc(repo, subset=None):
2010 def mfunc(repo, subset=None):
2003 if subset is None:
2011 if subset is None:
2004 subset = fullreposet(repo)
2012 subset = fullreposet(repo)
2005 return getset(repo, subset, tree)
2013 return getset(repo, subset, tree)
2006 return mfunc
2014 return mfunc
2007
2015
2008 def loadpredicate(ui, extname, registrarobj):
2016 def loadpredicate(ui, extname, registrarobj):
2009 """Load revset predicates from specified registrarobj
2017 """Load revset predicates from specified registrarobj
2010 """
2018 """
2011 for name, func in registrarobj._table.iteritems():
2019 for name, func in registrarobj._table.iteritems():
2012 symbols[name] = func
2020 symbols[name] = func
2013 if func._safe:
2021 if func._safe:
2014 safesymbols.add(name)
2022 safesymbols.add(name)
2015
2023
2016 # load built-in predicates explicitly to setup safesymbols
2024 # load built-in predicates explicitly to setup safesymbols
2017 loadpredicate(None, None, predicate)
2025 loadpredicate(None, None, predicate)
2018
2026
2019 # tell hggettext to extract docstrings from these functions:
2027 # tell hggettext to extract docstrings from these functions:
2020 i18nfunctions = symbols.values()
2028 i18nfunctions = symbols.values()
@@ -1,4073 +1,4072
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 > testrevset=$TESTTMP/testrevset.py
23 > testrevset=$TESTTMP/testrevset.py
24 > EOF
24 > EOF
25
25
26 $ try() {
26 $ try() {
27 > hg debugrevspec --debug "$@"
27 > hg debugrevspec --debug "$@"
28 > }
28 > }
29
29
30 $ log() {
30 $ log() {
31 > hg log --template '{rev}\n' -r "$1"
31 > hg log --template '{rev}\n' -r "$1"
32 > }
32 > }
33
33
34 extension to build '_intlist()' and '_hexlist()', which is necessary because
34 extension to build '_intlist()' and '_hexlist()', which is necessary because
35 these predicates use '\0' as a separator:
35 these predicates use '\0' as a separator:
36
36
37 $ cat <<EOF > debugrevlistspec.py
37 $ cat <<EOF > debugrevlistspec.py
38 > from __future__ import absolute_import
38 > from __future__ import absolute_import
39 > from mercurial import (
39 > from mercurial import (
40 > node as nodemod,
40 > node as nodemod,
41 > registrar,
41 > registrar,
42 > revset,
42 > revset,
43 > revsetlang,
43 > revsetlang,
44 > smartset,
44 > smartset,
45 > )
45 > )
46 > cmdtable = {}
46 > cmdtable = {}
47 > command = registrar.command(cmdtable)
47 > command = registrar.command(cmdtable)
48 > @command('debugrevlistspec',
48 > @command('debugrevlistspec',
49 > [('', 'optimize', None, 'print parsed tree after optimizing'),
49 > [('', 'optimize', None, 'print parsed tree after optimizing'),
50 > ('', 'bin', None, 'unhexlify arguments')])
50 > ('', 'bin', None, 'unhexlify arguments')])
51 > def debugrevlistspec(ui, repo, fmt, *args, **opts):
51 > def debugrevlistspec(ui, repo, fmt, *args, **opts):
52 > if opts['bin']:
52 > if opts['bin']:
53 > args = map(nodemod.bin, args)
53 > args = map(nodemod.bin, args)
54 > expr = revsetlang.formatspec(fmt, list(args))
54 > expr = revsetlang.formatspec(fmt, list(args))
55 > if ui.verbose:
55 > if ui.verbose:
56 > tree = revsetlang.parse(expr, lookup=repo.__contains__)
56 > tree = revsetlang.parse(expr, lookup=repo.__contains__)
57 > ui.note(revsetlang.prettyformat(tree), "\n")
57 > ui.note(revsetlang.prettyformat(tree), "\n")
58 > if opts["optimize"]:
58 > if opts["optimize"]:
59 > opttree = revsetlang.optimize(revsetlang.analyze(tree))
59 > opttree = revsetlang.optimize(revsetlang.analyze(tree))
60 > ui.note("* optimized:\n", revsetlang.prettyformat(opttree),
60 > ui.note("* optimized:\n", revsetlang.prettyformat(opttree),
61 > "\n")
61 > "\n")
62 > func = revset.match(ui, expr, repo)
62 > func = revset.match(ui, expr, repo)
63 > revs = func(repo)
63 > revs = func(repo)
64 > if ui.verbose:
64 > if ui.verbose:
65 > ui.note("* set:\n", smartset.prettyformat(revs), "\n")
65 > ui.note("* set:\n", smartset.prettyformat(revs), "\n")
66 > for c in revs:
66 > for c in revs:
67 > ui.write("%s\n" % c)
67 > ui.write("%s\n" % c)
68 > EOF
68 > EOF
69 $ cat <<EOF >> $HGRCPATH
69 $ cat <<EOF >> $HGRCPATH
70 > [extensions]
70 > [extensions]
71 > debugrevlistspec = $TESTTMP/debugrevlistspec.py
71 > debugrevlistspec = $TESTTMP/debugrevlistspec.py
72 > EOF
72 > EOF
73 $ trylist() {
73 $ trylist() {
74 > hg debugrevlistspec --debug "$@"
74 > hg debugrevlistspec --debug "$@"
75 > }
75 > }
76
76
77 $ hg init repo
77 $ hg init repo
78 $ cd repo
78 $ cd repo
79
79
80 $ echo a > a
80 $ echo a > a
81 $ hg branch a
81 $ hg branch a
82 marked working directory as branch a
82 marked working directory as branch a
83 (branches are permanent and global, did you want a bookmark?)
83 (branches are permanent and global, did you want a bookmark?)
84 $ hg ci -Aqm0
84 $ hg ci -Aqm0
85
85
86 $ echo b > b
86 $ echo b > b
87 $ hg branch b
87 $ hg branch b
88 marked working directory as branch b
88 marked working directory as branch b
89 $ hg ci -Aqm1
89 $ hg ci -Aqm1
90
90
91 $ rm a
91 $ rm a
92 $ hg branch a-b-c-
92 $ hg branch a-b-c-
93 marked working directory as branch a-b-c-
93 marked working directory as branch a-b-c-
94 $ hg ci -Aqm2 -u Bob
94 $ hg ci -Aqm2 -u Bob
95
95
96 $ hg log -r "extra('branch', 'a-b-c-')" --template '{rev}\n'
96 $ hg log -r "extra('branch', 'a-b-c-')" --template '{rev}\n'
97 2
97 2
98 $ hg log -r "extra('branch')" --template '{rev}\n'
98 $ hg log -r "extra('branch')" --template '{rev}\n'
99 0
99 0
100 1
100 1
101 2
101 2
102 $ hg log -r "extra('branch', 're:a')" --template '{rev} {branch}\n'
102 $ hg log -r "extra('branch', 're:a')" --template '{rev} {branch}\n'
103 0 a
103 0 a
104 2 a-b-c-
104 2 a-b-c-
105
105
106 $ hg co 1
106 $ hg co 1
107 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
107 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
108 $ hg branch +a+b+c+
108 $ hg branch +a+b+c+
109 marked working directory as branch +a+b+c+
109 marked working directory as branch +a+b+c+
110 $ hg ci -Aqm3
110 $ hg ci -Aqm3
111
111
112 $ hg co 2 # interleave
112 $ hg co 2 # interleave
113 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
113 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
114 $ echo bb > b
114 $ echo bb > b
115 $ hg branch -- -a-b-c-
115 $ hg branch -- -a-b-c-
116 marked working directory as branch -a-b-c-
116 marked working directory as branch -a-b-c-
117 $ hg ci -Aqm4 -d "May 12 2005"
117 $ hg ci -Aqm4 -d "May 12 2005"
118
118
119 $ hg co 3
119 $ hg co 3
120 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
120 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
121 $ hg branch !a/b/c/
121 $ hg branch !a/b/c/
122 marked working directory as branch !a/b/c/
122 marked working directory as branch !a/b/c/
123 $ hg ci -Aqm"5 bug"
123 $ hg ci -Aqm"5 bug"
124
124
125 $ hg merge 4
125 $ hg merge 4
126 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
126 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
127 (branch merge, don't forget to commit)
127 (branch merge, don't forget to commit)
128 $ hg branch _a_b_c_
128 $ hg branch _a_b_c_
129 marked working directory as branch _a_b_c_
129 marked working directory as branch _a_b_c_
130 $ hg ci -Aqm"6 issue619"
130 $ hg ci -Aqm"6 issue619"
131
131
132 $ hg branch .a.b.c.
132 $ hg branch .a.b.c.
133 marked working directory as branch .a.b.c.
133 marked working directory as branch .a.b.c.
134 $ hg ci -Aqm7
134 $ hg ci -Aqm7
135
135
136 $ hg branch all
136 $ hg branch all
137 marked working directory as branch all
137 marked working directory as branch all
138
138
139 $ hg co 4
139 $ hg co 4
140 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
140 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
141 $ hg branch Γ©
141 $ hg branch Γ©
142 marked working directory as branch \xc3\xa9 (esc)
142 marked working directory as branch \xc3\xa9 (esc)
143 $ hg ci -Aqm9
143 $ hg ci -Aqm9
144
144
145 $ hg tag -r6 1.0
145 $ hg tag -r6 1.0
146 $ hg bookmark -r6 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
146 $ hg bookmark -r6 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
147
147
148 $ hg clone --quiet -U -r 7 . ../remote1
148 $ hg clone --quiet -U -r 7 . ../remote1
149 $ hg clone --quiet -U -r 8 . ../remote2
149 $ hg clone --quiet -U -r 8 . ../remote2
150 $ echo "[paths]" >> .hg/hgrc
150 $ echo "[paths]" >> .hg/hgrc
151 $ echo "default = ../remote1" >> .hg/hgrc
151 $ echo "default = ../remote1" >> .hg/hgrc
152
152
153 trivial
153 trivial
154
154
155 $ try 0:1
155 $ try 0:1
156 (range
156 (range
157 ('symbol', '0')
157 ('symbol', '0')
158 ('symbol', '1'))
158 ('symbol', '1'))
159 * set:
159 * set:
160 <spanset+ 0:2>
160 <spanset+ 0:2>
161 0
161 0
162 1
162 1
163 $ try --optimize :
163 $ try --optimize :
164 (rangeall
164 (rangeall
165 None)
165 None)
166 * optimized:
166 * optimized:
167 (rangeall
167 (rangeall
168 None
168 None
169 define)
169 define)
170 * set:
170 * set:
171 <spanset+ 0:10>
171 <spanset+ 0:10>
172 0
172 0
173 1
173 1
174 2
174 2
175 3
175 3
176 4
176 4
177 5
177 5
178 6
178 6
179 7
179 7
180 8
180 8
181 9
181 9
182 $ try 3::6
182 $ try 3::6
183 (dagrange
183 (dagrange
184 ('symbol', '3')
184 ('symbol', '3')
185 ('symbol', '6'))
185 ('symbol', '6'))
186 * set:
186 * set:
187 <baseset+ [3, 5, 6]>
187 <baseset+ [3, 5, 6]>
188 3
188 3
189 5
189 5
190 6
190 6
191 $ try '0|1|2'
191 $ try '0|1|2'
192 (or
192 (or
193 (list
193 (list
194 ('symbol', '0')
194 ('symbol', '0')
195 ('symbol', '1')
195 ('symbol', '1')
196 ('symbol', '2')))
196 ('symbol', '2')))
197 * set:
197 * set:
198 <baseset [0, 1, 2]>
198 <baseset [0, 1, 2]>
199 0
199 0
200 1
200 1
201 2
201 2
202
202
203 names that should work without quoting
203 names that should work without quoting
204
204
205 $ try a
205 $ try a
206 ('symbol', 'a')
206 ('symbol', 'a')
207 * set:
207 * set:
208 <baseset [0]>
208 <baseset [0]>
209 0
209 0
210 $ try b-a
210 $ try b-a
211 (minus
211 (minus
212 ('symbol', 'b')
212 ('symbol', 'b')
213 ('symbol', 'a'))
213 ('symbol', 'a'))
214 * set:
214 * set:
215 <filteredset
215 <filteredset
216 <baseset [1]>,
216 <baseset [1]>,
217 <not
217 <not
218 <baseset [0]>>>
218 <baseset [0]>>>
219 1
219 1
220 $ try _a_b_c_
220 $ try _a_b_c_
221 ('symbol', '_a_b_c_')
221 ('symbol', '_a_b_c_')
222 * set:
222 * set:
223 <baseset [6]>
223 <baseset [6]>
224 6
224 6
225 $ try _a_b_c_-a
225 $ try _a_b_c_-a
226 (minus
226 (minus
227 ('symbol', '_a_b_c_')
227 ('symbol', '_a_b_c_')
228 ('symbol', 'a'))
228 ('symbol', 'a'))
229 * set:
229 * set:
230 <filteredset
230 <filteredset
231 <baseset [6]>,
231 <baseset [6]>,
232 <not
232 <not
233 <baseset [0]>>>
233 <baseset [0]>>>
234 6
234 6
235 $ try .a.b.c.
235 $ try .a.b.c.
236 ('symbol', '.a.b.c.')
236 ('symbol', '.a.b.c.')
237 * set:
237 * set:
238 <baseset [7]>
238 <baseset [7]>
239 7
239 7
240 $ try .a.b.c.-a
240 $ try .a.b.c.-a
241 (minus
241 (minus
242 ('symbol', '.a.b.c.')
242 ('symbol', '.a.b.c.')
243 ('symbol', 'a'))
243 ('symbol', 'a'))
244 * set:
244 * set:
245 <filteredset
245 <filteredset
246 <baseset [7]>,
246 <baseset [7]>,
247 <not
247 <not
248 <baseset [0]>>>
248 <baseset [0]>>>
249 7
249 7
250
250
251 names that should be caught by fallback mechanism
251 names that should be caught by fallback mechanism
252
252
253 $ try -- '-a-b-c-'
253 $ try -- '-a-b-c-'
254 ('symbol', '-a-b-c-')
254 ('symbol', '-a-b-c-')
255 * set:
255 * set:
256 <baseset [4]>
256 <baseset [4]>
257 4
257 4
258 $ log -a-b-c-
258 $ log -a-b-c-
259 4
259 4
260 $ try '+a+b+c+'
260 $ try '+a+b+c+'
261 ('symbol', '+a+b+c+')
261 ('symbol', '+a+b+c+')
262 * set:
262 * set:
263 <baseset [3]>
263 <baseset [3]>
264 3
264 3
265 $ try '+a+b+c+:'
265 $ try '+a+b+c+:'
266 (rangepost
266 (rangepost
267 ('symbol', '+a+b+c+'))
267 ('symbol', '+a+b+c+'))
268 * set:
268 * set:
269 <spanset+ 3:10>
269 <spanset+ 3:10>
270 3
270 3
271 4
271 4
272 5
272 5
273 6
273 6
274 7
274 7
275 8
275 8
276 9
276 9
277 $ try ':+a+b+c+'
277 $ try ':+a+b+c+'
278 (rangepre
278 (rangepre
279 ('symbol', '+a+b+c+'))
279 ('symbol', '+a+b+c+'))
280 * set:
280 * set:
281 <spanset+ 0:4>
281 <spanset+ 0:4>
282 0
282 0
283 1
283 1
284 2
284 2
285 3
285 3
286 $ try -- '-a-b-c-:+a+b+c+'
286 $ try -- '-a-b-c-:+a+b+c+'
287 (range
287 (range
288 ('symbol', '-a-b-c-')
288 ('symbol', '-a-b-c-')
289 ('symbol', '+a+b+c+'))
289 ('symbol', '+a+b+c+'))
290 * set:
290 * set:
291 <spanset- 3:5>
291 <spanset- 3:5>
292 4
292 4
293 3
293 3
294 $ log '-a-b-c-:+a+b+c+'
294 $ log '-a-b-c-:+a+b+c+'
295 4
295 4
296 3
296 3
297
297
298 $ try -- -a-b-c--a # complains
298 $ try -- -a-b-c--a # complains
299 (minus
299 (minus
300 (minus
300 (minus
301 (minus
301 (minus
302 (negate
302 (negate
303 ('symbol', 'a'))
303 ('symbol', 'a'))
304 ('symbol', 'b'))
304 ('symbol', 'b'))
305 ('symbol', 'c'))
305 ('symbol', 'c'))
306 (negate
306 (negate
307 ('symbol', 'a')))
307 ('symbol', 'a')))
308 abort: unknown revision '-a'!
308 abort: unknown revision '-a'!
309 [255]
309 [255]
310 $ try Γ©
310 $ try Γ©
311 ('symbol', '\xc3\xa9')
311 ('symbol', '\xc3\xa9')
312 * set:
312 * set:
313 <baseset [9]>
313 <baseset [9]>
314 9
314 9
315
315
316 no quoting needed
316 no quoting needed
317
317
318 $ log ::a-b-c-
318 $ log ::a-b-c-
319 0
319 0
320 1
320 1
321 2
321 2
322
322
323 quoting needed
323 quoting needed
324
324
325 $ try '"-a-b-c-"-a'
325 $ try '"-a-b-c-"-a'
326 (minus
326 (minus
327 ('string', '-a-b-c-')
327 ('string', '-a-b-c-')
328 ('symbol', 'a'))
328 ('symbol', 'a'))
329 * set:
329 * set:
330 <filteredset
330 <filteredset
331 <baseset [4]>,
331 <baseset [4]>,
332 <not
332 <not
333 <baseset [0]>>>
333 <baseset [0]>>>
334 4
334 4
335
335
336 $ log '1 or 2'
336 $ log '1 or 2'
337 1
337 1
338 2
338 2
339 $ log '1|2'
339 $ log '1|2'
340 1
340 1
341 2
341 2
342 $ log '1 and 2'
342 $ log '1 and 2'
343 $ log '1&2'
343 $ log '1&2'
344 $ try '1&2|3' # precedence - and is higher
344 $ try '1&2|3' # precedence - and is higher
345 (or
345 (or
346 (list
346 (list
347 (and
347 (and
348 ('symbol', '1')
348 ('symbol', '1')
349 ('symbol', '2'))
349 ('symbol', '2'))
350 ('symbol', '3')))
350 ('symbol', '3')))
351 * set:
351 * set:
352 <addset
352 <addset
353 <baseset []>,
353 <baseset []>,
354 <baseset [3]>>
354 <baseset [3]>>
355 3
355 3
356 $ try '1|2&3'
356 $ try '1|2&3'
357 (or
357 (or
358 (list
358 (list
359 ('symbol', '1')
359 ('symbol', '1')
360 (and
360 (and
361 ('symbol', '2')
361 ('symbol', '2')
362 ('symbol', '3'))))
362 ('symbol', '3'))))
363 * set:
363 * set:
364 <addset
364 <addset
365 <baseset [1]>,
365 <baseset [1]>,
366 <baseset []>>
366 <baseset []>>
367 1
367 1
368 $ try '1&2&3' # associativity
368 $ try '1&2&3' # associativity
369 (and
369 (and
370 (and
370 (and
371 ('symbol', '1')
371 ('symbol', '1')
372 ('symbol', '2'))
372 ('symbol', '2'))
373 ('symbol', '3'))
373 ('symbol', '3'))
374 * set:
374 * set:
375 <baseset []>
375 <baseset []>
376 $ try '1|(2|3)'
376 $ try '1|(2|3)'
377 (or
377 (or
378 (list
378 (list
379 ('symbol', '1')
379 ('symbol', '1')
380 (group
380 (group
381 (or
381 (or
382 (list
382 (list
383 ('symbol', '2')
383 ('symbol', '2')
384 ('symbol', '3'))))))
384 ('symbol', '3'))))))
385 * set:
385 * set:
386 <addset
386 <addset
387 <baseset [1]>,
387 <baseset [1]>,
388 <baseset [2, 3]>>
388 <baseset [2, 3]>>
389 1
389 1
390 2
390 2
391 3
391 3
392 $ log '1.0' # tag
392 $ log '1.0' # tag
393 6
393 6
394 $ log 'a' # branch
394 $ log 'a' # branch
395 0
395 0
396 $ log '2785f51ee'
396 $ log '2785f51ee'
397 0
397 0
398 $ log 'date(2005)'
398 $ log 'date(2005)'
399 4
399 4
400 $ log 'date(this is a test)'
400 $ log 'date(this is a test)'
401 hg: parse error at 10: unexpected token: symbol
401 hg: parse error at 10: unexpected token: symbol
402 [255]
402 [255]
403 $ log 'date()'
403 $ log 'date()'
404 hg: parse error: date requires a string
404 hg: parse error: date requires a string
405 [255]
405 [255]
406 $ log 'date'
406 $ log 'date'
407 abort: unknown revision 'date'!
407 abort: unknown revision 'date'!
408 [255]
408 [255]
409 $ log 'date('
409 $ log 'date('
410 hg: parse error at 5: not a prefix: end
410 hg: parse error at 5: not a prefix: end
411 [255]
411 [255]
412 $ log 'date("\xy")'
412 $ log 'date("\xy")'
413 hg: parse error: invalid \x escape
413 hg: parse error: invalid \x escape
414 [255]
414 [255]
415 $ log 'date(tip)'
415 $ log 'date(tip)'
416 hg: parse error: invalid date: 'tip'
416 hg: parse error: invalid date: 'tip'
417 [255]
417 [255]
418 $ log '0:date'
418 $ log '0:date'
419 abort: unknown revision 'date'!
419 abort: unknown revision 'date'!
420 [255]
420 [255]
421 $ log '::"date"'
421 $ log '::"date"'
422 abort: unknown revision 'date'!
422 abort: unknown revision 'date'!
423 [255]
423 [255]
424 $ hg book date -r 4
424 $ hg book date -r 4
425 $ log '0:date'
425 $ log '0:date'
426 0
426 0
427 1
427 1
428 2
428 2
429 3
429 3
430 4
430 4
431 $ log '::date'
431 $ log '::date'
432 0
432 0
433 1
433 1
434 2
434 2
435 4
435 4
436 $ log '::"date"'
436 $ log '::"date"'
437 0
437 0
438 1
438 1
439 2
439 2
440 4
440 4
441 $ log 'date(2005) and 1::'
441 $ log 'date(2005) and 1::'
442 4
442 4
443 $ hg book -d date
443 $ hg book -d date
444
444
445 function name should be a symbol
445 function name should be a symbol
446
446
447 $ log '"date"(2005)'
447 $ log '"date"(2005)'
448 hg: parse error: not a symbol
448 hg: parse error: not a symbol
449 [255]
449 [255]
450
450
451 keyword arguments
451 keyword arguments
452
452
453 $ log 'extra(branch, value=a)'
453 $ log 'extra(branch, value=a)'
454 0
454 0
455
455
456 $ log 'extra(branch, a, b)'
456 $ log 'extra(branch, a, b)'
457 hg: parse error: extra takes at most 2 positional arguments
457 hg: parse error: extra takes at most 2 positional arguments
458 [255]
458 [255]
459 $ log 'extra(a, label=b)'
459 $ log 'extra(a, label=b)'
460 hg: parse error: extra got multiple values for keyword argument 'label'
460 hg: parse error: extra got multiple values for keyword argument 'label'
461 [255]
461 [255]
462 $ log 'extra(label=branch, default)'
462 $ log 'extra(label=branch, default)'
463 hg: parse error: extra got an invalid argument
463 hg: parse error: extra got an invalid argument
464 [255]
464 [255]
465 $ log 'extra(branch, foo+bar=baz)'
465 $ log 'extra(branch, foo+bar=baz)'
466 hg: parse error: extra got an invalid argument
466 hg: parse error: extra got an invalid argument
467 [255]
467 [255]
468 $ log 'extra(unknown=branch)'
468 $ log 'extra(unknown=branch)'
469 hg: parse error: extra got an unexpected keyword argument 'unknown'
469 hg: parse error: extra got an unexpected keyword argument 'unknown'
470 [255]
470 [255]
471
471
472 $ try 'foo=bar|baz'
472 $ try 'foo=bar|baz'
473 (keyvalue
473 (keyvalue
474 ('symbol', 'foo')
474 ('symbol', 'foo')
475 (or
475 (or
476 (list
476 (list
477 ('symbol', 'bar')
477 ('symbol', 'bar')
478 ('symbol', 'baz'))))
478 ('symbol', 'baz'))))
479 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
480 [255]
480 [255]
481
481
482 right-hand side should be optimized recursively
482 right-hand side should be optimized recursively
483
483
484 $ try --optimize 'foo=(not public())'
484 $ try --optimize 'foo=(not public())'
485 (keyvalue
485 (keyvalue
486 ('symbol', 'foo')
486 ('symbol', 'foo')
487 (group
487 (group
488 (not
488 (not
489 (func
489 (func
490 ('symbol', 'public')
490 ('symbol', 'public')
491 None))))
491 None))))
492 * optimized:
492 * optimized:
493 (keyvalue
493 (keyvalue
494 ('symbol', 'foo')
494 ('symbol', 'foo')
495 (func
495 (func
496 ('symbol', '_notpublic')
496 ('symbol', '_notpublic')
497 None
497 None
498 any))
498 any))
499 hg: parse error: can't use a key-value pair in this context
499 hg: parse error: can't use a key-value pair in this context
500 [255]
500 [255]
501
501
502 parsed tree at stages:
502 parsed tree at stages:
503
503
504 $ hg debugrevspec -p all '()'
504 $ hg debugrevspec -p all '()'
505 * parsed:
505 * parsed:
506 (group
506 (group
507 None)
507 None)
508 * expanded:
508 * expanded:
509 (group
509 (group
510 None)
510 None)
511 * concatenated:
511 * concatenated:
512 (group
512 (group
513 None)
513 None)
514 * analyzed:
514 * analyzed:
515 None
515 None
516 * optimized:
516 * optimized:
517 None
517 None
518 hg: parse error: missing argument
518 hg: parse error: missing argument
519 [255]
519 [255]
520
520
521 $ hg debugrevspec --no-optimized -p all '()'
521 $ hg debugrevspec --no-optimized -p all '()'
522 * parsed:
522 * parsed:
523 (group
523 (group
524 None)
524 None)
525 * expanded:
525 * expanded:
526 (group
526 (group
527 None)
527 None)
528 * concatenated:
528 * concatenated:
529 (group
529 (group
530 None)
530 None)
531 * analyzed:
531 * analyzed:
532 None
532 None
533 hg: parse error: missing argument
533 hg: parse error: missing argument
534 [255]
534 [255]
535
535
536 $ hg debugrevspec -p parsed -p analyzed -p optimized '(0|1)-1'
536 $ hg debugrevspec -p parsed -p analyzed -p optimized '(0|1)-1'
537 * parsed:
537 * parsed:
538 (minus
538 (minus
539 (group
539 (group
540 (or
540 (or
541 (list
541 (list
542 ('symbol', '0')
542 ('symbol', '0')
543 ('symbol', '1'))))
543 ('symbol', '1'))))
544 ('symbol', '1'))
544 ('symbol', '1'))
545 * analyzed:
545 * analyzed:
546 (and
546 (and
547 (or
547 (or
548 (list
548 (list
549 ('symbol', '0')
549 ('symbol', '0')
550 ('symbol', '1'))
550 ('symbol', '1'))
551 define)
551 define)
552 (not
552 (not
553 ('symbol', '1')
553 ('symbol', '1')
554 follow)
554 follow)
555 define)
555 define)
556 * optimized:
556 * optimized:
557 (difference
557 (difference
558 (func
558 (func
559 ('symbol', '_list')
559 ('symbol', '_list')
560 ('string', '0\x001')
560 ('string', '0\x001')
561 define)
561 define)
562 ('symbol', '1')
562 ('symbol', '1')
563 define)
563 define)
564 0
564 0
565
565
566 $ hg debugrevspec -p unknown '0'
566 $ hg debugrevspec -p unknown '0'
567 abort: invalid stage name: unknown
567 abort: invalid stage name: unknown
568 [255]
568 [255]
569
569
570 $ hg debugrevspec -p all --optimize '0'
570 $ hg debugrevspec -p all --optimize '0'
571 abort: cannot use --optimize with --show-stage
571 abort: cannot use --optimize with --show-stage
572 [255]
572 [255]
573
573
574 verify optimized tree:
574 verify optimized tree:
575
575
576 $ hg debugrevspec --verify '0|1'
576 $ hg debugrevspec --verify '0|1'
577
577
578 $ hg debugrevspec --verify -v -p analyzed -p optimized 'r3232() & 2'
578 $ hg debugrevspec --verify -v -p analyzed -p optimized 'r3232() & 2'
579 * analyzed:
579 * analyzed:
580 (and
580 (and
581 (func
581 (func
582 ('symbol', 'r3232')
582 ('symbol', 'r3232')
583 None
583 None
584 define)
584 define)
585 ('symbol', '2')
585 ('symbol', '2')
586 define)
586 define)
587 * optimized:
587 * optimized:
588 (and
588 (and
589 ('symbol', '2')
589 ('symbol', '2')
590 (func
590 (func
591 ('symbol', 'r3232')
591 ('symbol', 'r3232')
592 None
592 None
593 define)
593 define)
594 define)
594 define)
595 * analyzed set:
595 * analyzed set:
596 <baseset [2]>
596 <baseset [2]>
597 * optimized set:
597 * optimized set:
598 <baseset [2, 2]>
598 <baseset [2, 2]>
599 --- analyzed
599 --- analyzed
600 +++ optimized
600 +++ optimized
601 2
601 2
602 +2
602 +2
603 [1]
603 [1]
604
604
605 $ hg debugrevspec --no-optimized --verify-optimized '0'
605 $ hg debugrevspec --no-optimized --verify-optimized '0'
606 abort: cannot use --verify-optimized with --no-optimized
606 abort: cannot use --verify-optimized with --no-optimized
607 [255]
607 [255]
608
608
609 Test that symbols only get parsed as functions if there's an opening
609 Test that symbols only get parsed as functions if there's an opening
610 parenthesis.
610 parenthesis.
611
611
612 $ hg book only -r 9
612 $ hg book only -r 9
613 $ log 'only(only)' # Outer "only" is a function, inner "only" is the bookmark
613 $ log 'only(only)' # Outer "only" is a function, inner "only" is the bookmark
614 8
614 8
615 9
615 9
616
616
617 ':y' behaves like '0:y', but can't be rewritten as such since the revision '0'
617 ':y' behaves like '0:y', but can't be rewritten as such since the revision '0'
618 may be hidden (issue5385)
618 may be hidden (issue5385)
619
619
620 $ try -p parsed -p analyzed ':'
620 $ try -p parsed -p analyzed ':'
621 * parsed:
621 * parsed:
622 (rangeall
622 (rangeall
623 None)
623 None)
624 * analyzed:
624 * analyzed:
625 (rangeall
625 (rangeall
626 None
626 None
627 define)
627 define)
628 * set:
628 * set:
629 <spanset+ 0:10>
629 <spanset+ 0:10>
630 0
630 0
631 1
631 1
632 2
632 2
633 3
633 3
634 4
634 4
635 5
635 5
636 6
636 6
637 7
637 7
638 8
638 8
639 9
639 9
640 $ try -p analyzed ':1'
640 $ try -p analyzed ':1'
641 * analyzed:
641 * analyzed:
642 (rangepre
642 (rangepre
643 ('symbol', '1')
643 ('symbol', '1')
644 define)
644 define)
645 * set:
645 * set:
646 <spanset+ 0:2>
646 <spanset+ 0:2>
647 0
647 0
648 1
648 1
649 $ try -p analyzed ':(1|2)'
649 $ try -p analyzed ':(1|2)'
650 * analyzed:
650 * analyzed:
651 (rangepre
651 (rangepre
652 (or
652 (or
653 (list
653 (list
654 ('symbol', '1')
654 ('symbol', '1')
655 ('symbol', '2'))
655 ('symbol', '2'))
656 define)
656 define)
657 define)
657 define)
658 * set:
658 * set:
659 <spanset+ 0:3>
659 <spanset+ 0:3>
660 0
660 0
661 1
661 1
662 2
662 2
663 $ try -p analyzed ':(1&2)'
663 $ try -p analyzed ':(1&2)'
664 * analyzed:
664 * analyzed:
665 (rangepre
665 (rangepre
666 (and
666 (and
667 ('symbol', '1')
667 ('symbol', '1')
668 ('symbol', '2')
668 ('symbol', '2')
669 define)
669 define)
670 define)
670 define)
671 * set:
671 * set:
672 <baseset []>
672 <baseset []>
673
673
674 infix/suffix resolution of ^ operator (issue2884):
674 infix/suffix resolution of ^ operator (issue2884):
675
675
676 x^:y means (x^):y
676 x^:y means (x^):y
677
677
678 $ try '1^:2'
678 $ try '1^:2'
679 (range
679 (range
680 (parentpost
680 (parentpost
681 ('symbol', '1'))
681 ('symbol', '1'))
682 ('symbol', '2'))
682 ('symbol', '2'))
683 * set:
683 * set:
684 <spanset+ 0:3>
684 <spanset+ 0:3>
685 0
685 0
686 1
686 1
687 2
687 2
688
688
689 $ try '1^::2'
689 $ try '1^::2'
690 (dagrange
690 (dagrange
691 (parentpost
691 (parentpost
692 ('symbol', '1'))
692 ('symbol', '1'))
693 ('symbol', '2'))
693 ('symbol', '2'))
694 * set:
694 * set:
695 <baseset+ [0, 1, 2]>
695 <baseset+ [0, 1, 2]>
696 0
696 0
697 1
697 1
698 2
698 2
699
699
700 $ try '9^:'
700 $ try '9^:'
701 (rangepost
701 (rangepost
702 (parentpost
702 (parentpost
703 ('symbol', '9')))
703 ('symbol', '9')))
704 * set:
704 * set:
705 <spanset+ 8:10>
705 <spanset+ 8:10>
706 8
706 8
707 9
707 9
708
708
709 x^:y should be resolved before omitting group operators
709 x^:y should be resolved before omitting group operators
710
710
711 $ try '1^(:2)'
711 $ try '1^(:2)'
712 (parent
712 (parent
713 ('symbol', '1')
713 ('symbol', '1')
714 (group
714 (group
715 (rangepre
715 (rangepre
716 ('symbol', '2'))))
716 ('symbol', '2'))))
717 hg: parse error: ^ expects a number 0, 1, or 2
717 hg: parse error: ^ expects a number 0, 1, or 2
718 [255]
718 [255]
719
719
720 x^:y should be resolved recursively
720 x^:y should be resolved recursively
721
721
722 $ try 'sort(1^:2)'
722 $ try 'sort(1^:2)'
723 (func
723 (func
724 ('symbol', 'sort')
724 ('symbol', 'sort')
725 (range
725 (range
726 (parentpost
726 (parentpost
727 ('symbol', '1'))
727 ('symbol', '1'))
728 ('symbol', '2')))
728 ('symbol', '2')))
729 * set:
729 * set:
730 <spanset+ 0:3>
730 <spanset+ 0:3>
731 0
731 0
732 1
732 1
733 2
733 2
734
734
735 $ try '(3^:4)^:2'
735 $ try '(3^:4)^:2'
736 (range
736 (range
737 (parentpost
737 (parentpost
738 (group
738 (group
739 (range
739 (range
740 (parentpost
740 (parentpost
741 ('symbol', '3'))
741 ('symbol', '3'))
742 ('symbol', '4'))))
742 ('symbol', '4'))))
743 ('symbol', '2'))
743 ('symbol', '2'))
744 * set:
744 * set:
745 <spanset+ 0:3>
745 <spanset+ 0:3>
746 0
746 0
747 1
747 1
748 2
748 2
749
749
750 $ try '(3^::4)^::2'
750 $ try '(3^::4)^::2'
751 (dagrange
751 (dagrange
752 (parentpost
752 (parentpost
753 (group
753 (group
754 (dagrange
754 (dagrange
755 (parentpost
755 (parentpost
756 ('symbol', '3'))
756 ('symbol', '3'))
757 ('symbol', '4'))))
757 ('symbol', '4'))))
758 ('symbol', '2'))
758 ('symbol', '2'))
759 * set:
759 * set:
760 <baseset+ [0, 1, 2]>
760 <baseset+ [0, 1, 2]>
761 0
761 0
762 1
762 1
763 2
763 2
764
764
765 $ try '(9^:)^:'
765 $ try '(9^:)^:'
766 (rangepost
766 (rangepost
767 (parentpost
767 (parentpost
768 (group
768 (group
769 (rangepost
769 (rangepost
770 (parentpost
770 (parentpost
771 ('symbol', '9'))))))
771 ('symbol', '9'))))))
772 * set:
772 * set:
773 <spanset+ 4:10>
773 <spanset+ 4:10>
774 4
774 4
775 5
775 5
776 6
776 6
777 7
777 7
778 8
778 8
779 9
779 9
780
780
781 x^ in alias should also be resolved
781 x^ in alias should also be resolved
782
782
783 $ try 'A' --config 'revsetalias.A=1^:2'
783 $ try 'A' --config 'revsetalias.A=1^:2'
784 ('symbol', 'A')
784 ('symbol', 'A')
785 * expanded:
785 * expanded:
786 (range
786 (range
787 (parentpost
787 (parentpost
788 ('symbol', '1'))
788 ('symbol', '1'))
789 ('symbol', '2'))
789 ('symbol', '2'))
790 * set:
790 * set:
791 <spanset+ 0:3>
791 <spanset+ 0:3>
792 0
792 0
793 1
793 1
794 2
794 2
795
795
796 $ try 'A:2' --config 'revsetalias.A=1^'
796 $ try 'A:2' --config 'revsetalias.A=1^'
797 (range
797 (range
798 ('symbol', 'A')
798 ('symbol', 'A')
799 ('symbol', '2'))
799 ('symbol', '2'))
800 * expanded:
800 * expanded:
801 (range
801 (range
802 (parentpost
802 (parentpost
803 ('symbol', '1'))
803 ('symbol', '1'))
804 ('symbol', '2'))
804 ('symbol', '2'))
805 * set:
805 * set:
806 <spanset+ 0:3>
806 <spanset+ 0:3>
807 0
807 0
808 1
808 1
809 2
809 2
810
810
811 but not beyond the boundary of alias expansion, because the resolution should
811 but not beyond the boundary of alias expansion, because the resolution should
812 be made at the parsing stage
812 be made at the parsing stage
813
813
814 $ try '1^A' --config 'revsetalias.A=:2'
814 $ try '1^A' --config 'revsetalias.A=:2'
815 (parent
815 (parent
816 ('symbol', '1')
816 ('symbol', '1')
817 ('symbol', 'A'))
817 ('symbol', 'A'))
818 * expanded:
818 * expanded:
819 (parent
819 (parent
820 ('symbol', '1')
820 ('symbol', '1')
821 (rangepre
821 (rangepre
822 ('symbol', '2')))
822 ('symbol', '2')))
823 hg: parse error: ^ expects a number 0, 1, or 2
823 hg: parse error: ^ expects a number 0, 1, or 2
824 [255]
824 [255]
825
825
826 ancestor can accept 0 or more arguments
826 ancestor can accept 0 or more arguments
827
827
828 $ log 'ancestor()'
828 $ log 'ancestor()'
829 $ log 'ancestor(1)'
829 $ log 'ancestor(1)'
830 1
830 1
831 $ log 'ancestor(4,5)'
831 $ log 'ancestor(4,5)'
832 1
832 1
833 $ log 'ancestor(4,5) and 4'
833 $ log 'ancestor(4,5) and 4'
834 $ log 'ancestor(0,0,1,3)'
834 $ log 'ancestor(0,0,1,3)'
835 0
835 0
836 $ log 'ancestor(3,1,5,3,5,1)'
836 $ log 'ancestor(3,1,5,3,5,1)'
837 1
837 1
838 $ log 'ancestor(0,1,3,5)'
838 $ log 'ancestor(0,1,3,5)'
839 0
839 0
840 $ log 'ancestor(1,2,3,4,5)'
840 $ log 'ancestor(1,2,3,4,5)'
841 1
841 1
842
842
843 test ancestors
843 test ancestors
844
844
845 $ log 'ancestors(5)'
845 $ log 'ancestors(5)'
846 0
846 0
847 1
847 1
848 3
848 3
849 5
849 5
850 $ log 'ancestor(ancestors(5))'
850 $ log 'ancestor(ancestors(5))'
851 0
851 0
852 $ log '::r3232()'
852 $ log '::r3232()'
853 0
853 0
854 1
854 1
855 2
855 2
856 3
856 3
857
857
858 $ log 'author(bob)'
858 $ log 'author(bob)'
859 2
859 2
860 $ log 'author("re:bob|test")'
860 $ log 'author("re:bob|test")'
861 0
861 0
862 1
862 1
863 2
863 2
864 3
864 3
865 4
865 4
866 5
866 5
867 6
867 6
868 7
868 7
869 8
869 8
870 9
870 9
871 $ log 'author(r"re:\S")'
871 $ log 'author(r"re:\S")'
872 0
872 0
873 1
873 1
874 2
874 2
875 3
875 3
876 4
876 4
877 5
877 5
878 6
878 6
879 7
879 7
880 8
880 8
881 9
881 9
882 $ log 'branch(Γ©)'
882 $ log 'branch(Γ©)'
883 8
883 8
884 9
884 9
885 $ log 'branch(a)'
885 $ log 'branch(a)'
886 0
886 0
887 $ hg log -r 'branch("re:a")' --template '{rev} {branch}\n'
887 $ hg log -r 'branch("re:a")' --template '{rev} {branch}\n'
888 0 a
888 0 a
889 2 a-b-c-
889 2 a-b-c-
890 3 +a+b+c+
890 3 +a+b+c+
891 4 -a-b-c-
891 4 -a-b-c-
892 5 !a/b/c/
892 5 !a/b/c/
893 6 _a_b_c_
893 6 _a_b_c_
894 7 .a.b.c.
894 7 .a.b.c.
895 $ log 'children(ancestor(4,5))'
895 $ log 'children(ancestor(4,5))'
896 2
896 2
897 3
897 3
898
898
899 $ log 'children(4)'
899 $ log 'children(4)'
900 6
900 6
901 8
901 8
902 $ log 'children(null)'
902 $ log 'children(null)'
903 0
903 0
904
904
905 $ log 'closed()'
905 $ log 'closed()'
906 $ log 'contains(a)'
906 $ log 'contains(a)'
907 0
907 0
908 1
908 1
909 3
909 3
910 5
910 5
911 $ log 'contains("../repo/a")'
911 $ log 'contains("../repo/a")'
912 0
912 0
913 1
913 1
914 3
914 3
915 5
915 5
916 $ log 'desc(B)'
916 $ log 'desc(B)'
917 5
917 5
918 $ hg log -r 'desc(r"re:S?u")' --template "{rev} {desc|firstline}\n"
918 $ hg log -r 'desc(r"re:S?u")' --template "{rev} {desc|firstline}\n"
919 5 5 bug
919 5 5 bug
920 6 6 issue619
920 6 6 issue619
921 $ log 'descendants(2 or 3)'
921 $ log 'descendants(2 or 3)'
922 2
922 2
923 3
923 3
924 4
924 4
925 5
925 5
926 6
926 6
927 7
927 7
928 8
928 8
929 9
929 9
930 $ log 'file("b*")'
930 $ log 'file("b*")'
931 1
931 1
932 4
932 4
933 $ log 'filelog("b")'
933 $ log 'filelog("b")'
934 1
934 1
935 4
935 4
936 $ log 'filelog("../repo/b")'
936 $ log 'filelog("../repo/b")'
937 1
937 1
938 4
938 4
939 $ log 'follow()'
939 $ log 'follow()'
940 0
940 0
941 1
941 1
942 2
942 2
943 4
943 4
944 8
944 8
945 9
945 9
946 $ log 'grep("issue\d+")'
946 $ log 'grep("issue\d+")'
947 6
947 6
948 $ try 'grep("(")' # invalid regular expression
948 $ try 'grep("(")' # invalid regular expression
949 (func
949 (func
950 ('symbol', 'grep')
950 ('symbol', 'grep')
951 ('string', '('))
951 ('string', '('))
952 hg: parse error: invalid match pattern: unbalanced parenthesis
952 hg: parse error: invalid match pattern: unbalanced parenthesis
953 [255]
953 [255]
954 $ try 'grep("\bissue\d+")'
954 $ try 'grep("\bissue\d+")'
955 (func
955 (func
956 ('symbol', 'grep')
956 ('symbol', 'grep')
957 ('string', '\x08issue\\d+'))
957 ('string', '\x08issue\\d+'))
958 * set:
958 * set:
959 <filteredset
959 <filteredset
960 <fullreposet+ 0:10>,
960 <fullreposet+ 0:10>,
961 <grep '\x08issue\\d+'>>
961 <grep '\x08issue\\d+'>>
962 $ try 'grep(r"\bissue\d+")'
962 $ try 'grep(r"\bissue\d+")'
963 (func
963 (func
964 ('symbol', 'grep')
964 ('symbol', 'grep')
965 ('string', '\\bissue\\d+'))
965 ('string', '\\bissue\\d+'))
966 * set:
966 * set:
967 <filteredset
967 <filteredset
968 <fullreposet+ 0:10>,
968 <fullreposet+ 0:10>,
969 <grep '\\bissue\\d+'>>
969 <grep '\\bissue\\d+'>>
970 6
970 6
971 $ try 'grep(r"\")'
971 $ try 'grep(r"\")'
972 hg: parse error at 7: unterminated string
972 hg: parse error at 7: unterminated string
973 [255]
973 [255]
974 $ log 'head()'
974 $ log 'head()'
975 0
975 0
976 1
976 1
977 2
977 2
978 3
978 3
979 4
979 4
980 5
980 5
981 6
981 6
982 7
982 7
983 9
983 9
984 $ log 'heads(6::)'
984 $ log 'heads(6::)'
985 7
985 7
986 $ log 'keyword(issue)'
986 $ log 'keyword(issue)'
987 6
987 6
988 $ log 'keyword("test a")'
988 $ log 'keyword("test a")'
989
989
990 Test first (=limit) and last
990 Test first (=limit) and last
991
991
992 $ log 'limit(head(), 1)'
992 $ log 'limit(head(), 1)'
993 0
993 0
994 $ log 'limit(author("re:bob|test"), 3, 5)'
994 $ log 'limit(author("re:bob|test"), 3, 5)'
995 5
995 5
996 6
996 6
997 7
997 7
998 $ log 'limit(author("re:bob|test"), offset=6)'
998 $ log 'limit(author("re:bob|test"), offset=6)'
999 6
999 6
1000 $ log 'limit(author("re:bob|test"), offset=10)'
1000 $ log 'limit(author("re:bob|test"), offset=10)'
1001 $ log 'limit(all(), 1, -1)'
1001 $ log 'limit(all(), 1, -1)'
1002 hg: parse error: negative offset
1002 hg: parse error: negative offset
1003 [255]
1003 [255]
1004 $ log 'limit(all(), -1)'
1004 $ log 'limit(all(), -1)'
1005 hg: parse error: negative number to select
1005 hg: parse error: negative number to select
1006 [255]
1006 [255]
1007 $ log 'limit(all(), 0)'
1007 $ log 'limit(all(), 0)'
1008
1008
1009 $ log 'last(all(), -1)'
1009 $ log 'last(all(), -1)'
1010 hg: parse error: negative number to select
1010 hg: parse error: negative number to select
1011 [255]
1011 [255]
1012 $ log 'last(all(), 0)'
1012 $ log 'last(all(), 0)'
1013 $ log 'last(all(), 1)'
1013 $ log 'last(all(), 1)'
1014 9
1014 9
1015 $ log 'last(all(), 2)'
1015 $ log 'last(all(), 2)'
1016 8
1016 8
1017 9
1017 9
1018
1018
1019 Test smartset.slice() by first/last()
1019 Test smartset.slice() by first/last()
1020
1020
1021 (using unoptimized set, filteredset as example)
1021 (using unoptimized set, filteredset as example)
1022
1022
1023 $ hg debugrevspec --no-show-revs -s '0:7 & branch("re:")'
1023 $ hg debugrevspec --no-show-revs -s '0:7 & branch("re:")'
1024 * set:
1024 * set:
1025 <filteredset
1025 <filteredset
1026 <spanset+ 0:8>,
1026 <spanset+ 0:8>,
1027 <branch 're:'>>
1027 <branch 're:'>>
1028 $ log 'limit(0:7 & branch("re:"), 3, 4)'
1028 $ log 'limit(0:7 & branch("re:"), 3, 4)'
1029 4
1029 4
1030 5
1030 5
1031 6
1031 6
1032 $ log 'limit(7:0 & branch("re:"), 3, 4)'
1032 $ log 'limit(7:0 & branch("re:"), 3, 4)'
1033 3
1033 3
1034 2
1034 2
1035 1
1035 1
1036 $ log 'last(0:7 & branch("re:"), 2)'
1036 $ log 'last(0:7 & branch("re:"), 2)'
1037 6
1037 6
1038 7
1038 7
1039
1039
1040 (using baseset)
1040 (using baseset)
1041
1041
1042 $ hg debugrevspec --no-show-revs -s 0+1+2+3+4+5+6+7
1042 $ hg debugrevspec --no-show-revs -s 0+1+2+3+4+5+6+7
1043 * set:
1043 * set:
1044 <baseset [0, 1, 2, 3, 4, 5, 6, 7]>
1044 <baseset [0, 1, 2, 3, 4, 5, 6, 7]>
1045 $ hg debugrevspec --no-show-revs -s 0::7
1045 $ hg debugrevspec --no-show-revs -s 0::7
1046 * set:
1046 * set:
1047 <baseset+ [0, 1, 2, 3, 4, 5, 6, 7]>
1047 <baseset+ [0, 1, 2, 3, 4, 5, 6, 7]>
1048 $ log 'limit(0+1+2+3+4+5+6+7, 3, 4)'
1048 $ log 'limit(0+1+2+3+4+5+6+7, 3, 4)'
1049 4
1049 4
1050 5
1050 5
1051 6
1051 6
1052 $ log 'limit(sort(0::7, rev), 3, 4)'
1052 $ log 'limit(sort(0::7, rev), 3, 4)'
1053 4
1053 4
1054 5
1054 5
1055 6
1055 6
1056 $ log 'limit(sort(0::7, -rev), 3, 4)'
1056 $ log 'limit(sort(0::7, -rev), 3, 4)'
1057 3
1057 3
1058 2
1058 2
1059 1
1059 1
1060 $ log 'last(sort(0::7, rev), 2)'
1060 $ log 'last(sort(0::7, rev), 2)'
1061 6
1061 6
1062 7
1062 7
1063 $ hg debugrevspec -s 'limit(sort(0::7, rev), 3, 6)'
1063 $ hg debugrevspec -s 'limit(sort(0::7, rev), 3, 6)'
1064 * set:
1064 * set:
1065 <baseset+ [6, 7]>
1065 <baseset+ [6, 7]>
1066 6
1066 6
1067 7
1067 7
1068 $ hg debugrevspec -s 'limit(sort(0::7, rev), 3, 9)'
1068 $ hg debugrevspec -s 'limit(sort(0::7, rev), 3, 9)'
1069 * set:
1069 * set:
1070 <baseset+ []>
1070 <baseset+ []>
1071 $ hg debugrevspec -s 'limit(sort(0::7, -rev), 3, 6)'
1071 $ hg debugrevspec -s 'limit(sort(0::7, -rev), 3, 6)'
1072 * set:
1072 * set:
1073 <baseset- [0, 1]>
1073 <baseset- [0, 1]>
1074 1
1074 1
1075 0
1075 0
1076 $ hg debugrevspec -s 'limit(sort(0::7, -rev), 3, 9)'
1076 $ hg debugrevspec -s 'limit(sort(0::7, -rev), 3, 9)'
1077 * set:
1077 * set:
1078 <baseset- []>
1078 <baseset- []>
1079 $ hg debugrevspec -s 'limit(0::7, 0)'
1079 $ hg debugrevspec -s 'limit(0::7, 0)'
1080 * set:
1080 * set:
1081 <baseset+ []>
1081 <baseset+ []>
1082
1082
1083 (using spanset)
1083 (using spanset)
1084
1084
1085 $ hg debugrevspec --no-show-revs -s 0:7
1085 $ hg debugrevspec --no-show-revs -s 0:7
1086 * set:
1086 * set:
1087 <spanset+ 0:8>
1087 <spanset+ 0:8>
1088 $ log 'limit(0:7, 3, 4)'
1088 $ log 'limit(0:7, 3, 4)'
1089 4
1089 4
1090 5
1090 5
1091 6
1091 6
1092 $ log 'limit(7:0, 3, 4)'
1092 $ log 'limit(7:0, 3, 4)'
1093 3
1093 3
1094 2
1094 2
1095 1
1095 1
1096 $ log 'limit(0:7, 3, 6)'
1096 $ log 'limit(0:7, 3, 6)'
1097 6
1097 6
1098 7
1098 7
1099 $ log 'limit(7:0, 3, 6)'
1099 $ log 'limit(7:0, 3, 6)'
1100 1
1100 1
1101 0
1101 0
1102 $ log 'last(0:7, 2)'
1102 $ log 'last(0:7, 2)'
1103 6
1103 6
1104 7
1104 7
1105 $ hg debugrevspec -s 'limit(0:7, 3, 6)'
1105 $ hg debugrevspec -s 'limit(0:7, 3, 6)'
1106 * set:
1106 * set:
1107 <spanset+ 6:8>
1107 <spanset+ 6:8>
1108 6
1108 6
1109 7
1109 7
1110 $ hg debugrevspec -s 'limit(0:7, 3, 9)'
1110 $ hg debugrevspec -s 'limit(0:7, 3, 9)'
1111 * set:
1111 * set:
1112 <spanset+ 8:8>
1112 <spanset+ 8:8>
1113 $ hg debugrevspec -s 'limit(7:0, 3, 6)'
1113 $ hg debugrevspec -s 'limit(7:0, 3, 6)'
1114 * set:
1114 * set:
1115 <spanset- 0:2>
1115 <spanset- 0:2>
1116 1
1116 1
1117 0
1117 0
1118 $ hg debugrevspec -s 'limit(7:0, 3, 9)'
1118 $ hg debugrevspec -s 'limit(7:0, 3, 9)'
1119 * set:
1119 * set:
1120 <spanset- 0:0>
1120 <spanset- 0:0>
1121 $ hg debugrevspec -s 'limit(0:7, 0)'
1121 $ hg debugrevspec -s 'limit(0:7, 0)'
1122 * set:
1122 * set:
1123 <spanset+ 0:0>
1123 <spanset+ 0:0>
1124
1124
1125 Test order of first/last revisions
1125 Test order of first/last revisions
1126
1126
1127 $ hg debugrevspec -s 'first(4:0, 3) & 3:'
1127 $ hg debugrevspec -s 'first(4:0, 3) & 3:'
1128 * set:
1128 * set:
1129 <filteredset
1129 <filteredset
1130 <spanset- 2:5>,
1130 <spanset- 2:5>,
1131 <spanset+ 3:10>>
1131 <spanset+ 3:10>>
1132 4
1132 4
1133 3
1133 3
1134
1134
1135 $ hg debugrevspec -s '3: & first(4:0, 3)'
1135 $ hg debugrevspec -s '3: & first(4:0, 3)'
1136 * set:
1136 * set:
1137 <filteredset
1137 <filteredset
1138 <spanset+ 3:10>,
1138 <spanset+ 3:10>,
1139 <spanset- 2:5>>
1139 <spanset- 2:5>>
1140 3
1140 3
1141 4
1141 4
1142
1142
1143 $ hg debugrevspec -s 'last(4:0, 3) & :1'
1143 $ hg debugrevspec -s 'last(4:0, 3) & :1'
1144 * set:
1144 * set:
1145 <filteredset
1145 <filteredset
1146 <spanset- 0:3>,
1146 <spanset- 0:3>,
1147 <spanset+ 0:2>>
1147 <spanset+ 0:2>>
1148 1
1148 1
1149 0
1149 0
1150
1150
1151 $ hg debugrevspec -s ':1 & last(4:0, 3)'
1151 $ hg debugrevspec -s ':1 & last(4:0, 3)'
1152 * set:
1152 * set:
1153 <filteredset
1153 <filteredset
1154 <spanset+ 0:2>,
1154 <spanset+ 0:2>,
1155 <spanset+ 0:3>>
1155 <spanset+ 0:3>>
1156 0
1156 0
1157 1
1157 1
1158
1158
1159 Test matching
1159 Test matching
1160
1160
1161 $ log 'matching(6)'
1161 $ log 'matching(6)'
1162 6
1162 6
1163 $ log 'matching(6:7, "phase parents user date branch summary files description substate")'
1163 $ log 'matching(6:7, "phase parents user date branch summary files description substate")'
1164 6
1164 6
1165 7
1165 7
1166
1166
1167 Testing min and max
1167 Testing min and max
1168
1168
1169 max: simple
1169 max: simple
1170
1170
1171 $ log 'max(contains(a))'
1171 $ log 'max(contains(a))'
1172 5
1172 5
1173
1173
1174 max: simple on unordered set)
1174 max: simple on unordered set)
1175
1175
1176 $ log 'max((4+0+2+5+7) and contains(a))'
1176 $ log 'max((4+0+2+5+7) and contains(a))'
1177 5
1177 5
1178
1178
1179 max: no result
1179 max: no result
1180
1180
1181 $ log 'max(contains(stringthatdoesnotappearanywhere))'
1181 $ log 'max(contains(stringthatdoesnotappearanywhere))'
1182
1182
1183 max: no result on unordered set
1183 max: no result on unordered set
1184
1184
1185 $ log 'max((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
1185 $ log 'max((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
1186
1186
1187 min: simple
1187 min: simple
1188
1188
1189 $ log 'min(contains(a))'
1189 $ log 'min(contains(a))'
1190 0
1190 0
1191
1191
1192 min: simple on unordered set
1192 min: simple on unordered set
1193
1193
1194 $ log 'min((4+0+2+5+7) and contains(a))'
1194 $ log 'min((4+0+2+5+7) and contains(a))'
1195 0
1195 0
1196
1196
1197 min: empty
1197 min: empty
1198
1198
1199 $ log 'min(contains(stringthatdoesnotappearanywhere))'
1199 $ log 'min(contains(stringthatdoesnotappearanywhere))'
1200
1200
1201 min: empty on unordered set
1201 min: empty on unordered set
1202
1202
1203 $ log 'min((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
1203 $ log 'min((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
1204
1204
1205
1205
1206 $ log 'merge()'
1206 $ log 'merge()'
1207 6
1207 6
1208 $ log 'branchpoint()'
1208 $ log 'branchpoint()'
1209 1
1209 1
1210 4
1210 4
1211 $ log 'modifies(b)'
1211 $ log 'modifies(b)'
1212 4
1212 4
1213 $ log 'modifies("path:b")'
1213 $ log 'modifies("path:b")'
1214 4
1214 4
1215 $ log 'modifies("*")'
1215 $ log 'modifies("*")'
1216 4
1216 4
1217 6
1217 6
1218 $ log 'modifies("set:modified()")'
1218 $ log 'modifies("set:modified()")'
1219 4
1219 4
1220 $ log 'id(5)'
1220 $ log 'id(5)'
1221 2
1221 2
1222 $ log 'only(9)'
1222 $ log 'only(9)'
1223 8
1223 8
1224 9
1224 9
1225 $ log 'only(8)'
1225 $ log 'only(8)'
1226 8
1226 8
1227 $ log 'only(9, 5)'
1227 $ log 'only(9, 5)'
1228 2
1228 2
1229 4
1229 4
1230 8
1230 8
1231 9
1231 9
1232 $ log 'only(7 + 9, 5 + 2)'
1232 $ log 'only(7 + 9, 5 + 2)'
1233 4
1233 4
1234 6
1234 6
1235 7
1235 7
1236 8
1236 8
1237 9
1237 9
1238
1238
1239 Test empty set input
1239 Test empty set input
1240 $ log 'only(p2())'
1240 $ log 'only(p2())'
1241 $ log 'only(p1(), p2())'
1241 $ log 'only(p1(), p2())'
1242 0
1242 0
1243 1
1243 1
1244 2
1244 2
1245 4
1245 4
1246 8
1246 8
1247 9
1247 9
1248
1248
1249 Test '%' operator
1249 Test '%' operator
1250
1250
1251 $ log '9%'
1251 $ log '9%'
1252 8
1252 8
1253 9
1253 9
1254 $ log '9%5'
1254 $ log '9%5'
1255 2
1255 2
1256 4
1256 4
1257 8
1257 8
1258 9
1258 9
1259 $ log '(7 + 9)%(5 + 2)'
1259 $ log '(7 + 9)%(5 + 2)'
1260 4
1260 4
1261 6
1261 6
1262 7
1262 7
1263 8
1263 8
1264 9
1264 9
1265
1265
1266 Test operand of '%' is optimized recursively (issue4670)
1266 Test operand of '%' is optimized recursively (issue4670)
1267
1267
1268 $ try --optimize '8:9-8%'
1268 $ try --optimize '8:9-8%'
1269 (onlypost
1269 (onlypost
1270 (minus
1270 (minus
1271 (range
1271 (range
1272 ('symbol', '8')
1272 ('symbol', '8')
1273 ('symbol', '9'))
1273 ('symbol', '9'))
1274 ('symbol', '8')))
1274 ('symbol', '8')))
1275 * optimized:
1275 * optimized:
1276 (func
1276 (func
1277 ('symbol', 'only')
1277 ('symbol', 'only')
1278 (difference
1278 (difference
1279 (range
1279 (range
1280 ('symbol', '8')
1280 ('symbol', '8')
1281 ('symbol', '9')
1281 ('symbol', '9')
1282 define)
1282 define)
1283 ('symbol', '8')
1283 ('symbol', '8')
1284 define)
1284 define)
1285 define)
1285 define)
1286 * set:
1286 * set:
1287 <baseset+ [8, 9]>
1287 <baseset+ [8, 9]>
1288 8
1288 8
1289 9
1289 9
1290 $ try --optimize '(9)%(5)'
1290 $ try --optimize '(9)%(5)'
1291 (only
1291 (only
1292 (group
1292 (group
1293 ('symbol', '9'))
1293 ('symbol', '9'))
1294 (group
1294 (group
1295 ('symbol', '5')))
1295 ('symbol', '5')))
1296 * optimized:
1296 * optimized:
1297 (func
1297 (func
1298 ('symbol', 'only')
1298 ('symbol', 'only')
1299 (list
1299 (list
1300 ('symbol', '9')
1300 ('symbol', '9')
1301 ('symbol', '5'))
1301 ('symbol', '5'))
1302 define)
1302 define)
1303 * set:
1303 * set:
1304 <baseset+ [2, 4, 8, 9]>
1304 <baseset+ [2, 4, 8, 9]>
1305 2
1305 2
1306 4
1306 4
1307 8
1307 8
1308 9
1308 9
1309
1309
1310 Test the order of operations
1310 Test the order of operations
1311
1311
1312 $ log '7 + 9%5 + 2'
1312 $ log '7 + 9%5 + 2'
1313 7
1313 7
1314 2
1314 2
1315 4
1315 4
1316 8
1316 8
1317 9
1317 9
1318
1318
1319 Test explicit numeric revision
1319 Test explicit numeric revision
1320 $ log 'rev(-2)'
1320 $ log 'rev(-2)'
1321 $ log 'rev(-1)'
1321 $ log 'rev(-1)'
1322 -1
1322 -1
1323 $ log 'rev(0)'
1323 $ log 'rev(0)'
1324 0
1324 0
1325 $ log 'rev(9)'
1325 $ log 'rev(9)'
1326 9
1326 9
1327 $ log 'rev(10)'
1327 $ log 'rev(10)'
1328 $ log 'rev(tip)'
1328 $ log 'rev(tip)'
1329 hg: parse error: rev expects a number
1329 hg: parse error: rev expects a number
1330 [255]
1330 [255]
1331
1331
1332 Test hexadecimal revision
1332 Test hexadecimal revision
1333 $ log 'id(2)'
1333 $ log 'id(2)'
1334 abort: 00changelog.i@2: ambiguous identifier!
1334 abort: 00changelog.i@2: ambiguous identifier!
1335 [255]
1335 [255]
1336 $ log 'id(23268)'
1336 $ log 'id(23268)'
1337 4
1337 4
1338 $ log 'id(2785f51eece)'
1338 $ log 'id(2785f51eece)'
1339 0
1339 0
1340 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532c)'
1340 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532c)'
1341 8
1341 8
1342 $ log 'id(d5d0dcbdc4a)'
1342 $ log 'id(d5d0dcbdc4a)'
1343 $ log 'id(d5d0dcbdc4w)'
1343 $ log 'id(d5d0dcbdc4w)'
1344 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532d)'
1344 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532d)'
1345 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532q)'
1345 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532q)'
1346 $ log 'id(1.0)'
1346 $ log 'id(1.0)'
1347 $ log 'id(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)'
1347 $ log 'id(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)'
1348
1348
1349 Test null revision
1349 Test null revision
1350 $ log '(null)'
1350 $ log '(null)'
1351 -1
1351 -1
1352 $ log '(null:0)'
1352 $ log '(null:0)'
1353 -1
1353 -1
1354 0
1354 0
1355 $ log '(0:null)'
1355 $ log '(0:null)'
1356 0
1356 0
1357 -1
1357 -1
1358 $ log 'null::0'
1358 $ log 'null::0'
1359 -1
1359 -1
1360 0
1360 0
1361 $ log 'null:tip - 0:'
1361 $ log 'null:tip - 0:'
1362 -1
1362 -1
1363 $ log 'null: and null::' | head -1
1363 $ log 'null: and null::' | head -1
1364 -1
1364 -1
1365 $ log 'null: or 0:' | head -2
1365 $ log 'null: or 0:' | head -2
1366 -1
1366 -1
1367 0
1367 0
1368 $ log 'ancestors(null)'
1368 $ log 'ancestors(null)'
1369 -1
1369 -1
1370 $ log 'reverse(null:)' | tail -2
1370 $ log 'reverse(null:)' | tail -2
1371 0
1371 0
1372 -1
1372 -1
1373 $ log 'first(null:)'
1373 $ log 'first(null:)'
1374 -1
1374 -1
1375 $ log 'min(null:)'
1375 $ log 'min(null:)'
1376 BROKEN: should be '-1'
1376 BROKEN: should be '-1'
1377 $ log 'tip:null and all()' | tail -2
1377 $ log 'tip:null and all()' | tail -2
1378 1
1378 1
1379 0
1379 0
1380
1380
1381 Test working-directory revision
1381 Test working-directory revision
1382 $ hg debugrevspec 'wdir()'
1382 $ hg debugrevspec 'wdir()'
1383 2147483647
1383 2147483647
1384 $ hg debugrevspec 'wdir()^'
1384 $ hg debugrevspec 'wdir()^'
1385 9
1385 9
1386 $ hg up 7
1386 $ hg up 7
1387 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1387 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1388 $ hg debugrevspec 'wdir()^'
1388 $ hg debugrevspec 'wdir()^'
1389 7
1389 7
1390 $ hg debugrevspec 'wdir()^0'
1390 $ hg debugrevspec 'wdir()^0'
1391 2147483647
1391 2147483647
1392 $ hg debugrevspec 'wdir()~3'
1392 $ hg debugrevspec 'wdir()~3'
1393 5
1393 5
1394 $ hg debugrevspec 'ancestors(wdir())'
1394 $ hg debugrevspec 'ancestors(wdir())'
1395 0
1395 0
1396 1
1396 1
1397 2
1397 2
1398 3
1398 3
1399 4
1399 4
1400 5
1400 5
1401 6
1401 6
1402 7
1402 7
1403 2147483647
1403 2147483647
1404 $ hg debugrevspec 'wdir()~0'
1404 $ hg debugrevspec 'wdir()~0'
1405 2147483647
1405 2147483647
1406 $ hg debugrevspec 'p1(wdir())'
1406 $ hg debugrevspec 'p1(wdir())'
1407 7
1407 7
1408 $ hg debugrevspec 'p2(wdir())'
1408 $ hg debugrevspec 'p2(wdir())'
1409 $ hg debugrevspec 'parents(wdir())'
1409 $ hg debugrevspec 'parents(wdir())'
1410 7
1410 7
1411 $ hg debugrevspec 'wdir()^1'
1411 $ hg debugrevspec 'wdir()^1'
1412 7
1412 7
1413 $ hg debugrevspec 'wdir()^2'
1413 $ hg debugrevspec 'wdir()^2'
1414 $ hg debugrevspec 'wdir()^3'
1414 $ hg debugrevspec 'wdir()^3'
1415 hg: parse error: ^ expects a number 0, 1, or 2
1415 hg: parse error: ^ expects a number 0, 1, or 2
1416 [255]
1416 [255]
1417 For tests consistency
1417 For tests consistency
1418 $ hg up 9
1418 $ hg up 9
1419 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1419 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1420 $ hg debugrevspec 'tip or wdir()'
1420 $ hg debugrevspec 'tip or wdir()'
1421 9
1421 9
1422 2147483647
1422 2147483647
1423 $ hg debugrevspec '0:tip and wdir()'
1423 $ hg debugrevspec '0:tip and wdir()'
1424 $ log '0:wdir()' | tail -3
1424 $ log '0:wdir()' | tail -3
1425 8
1425 8
1426 9
1426 9
1427 2147483647
1427 2147483647
1428 $ log 'wdir():0' | head -3
1428 $ log 'wdir():0' | head -3
1429 2147483647
1429 2147483647
1430 9
1430 9
1431 8
1431 8
1432 $ log 'wdir():wdir()'
1432 $ log 'wdir():wdir()'
1433 2147483647
1433 2147483647
1434 $ log '(all() + wdir()) & min(. + wdir())'
1434 $ log '(all() + wdir()) & min(. + wdir())'
1435 9
1435 9
1436 $ log '(all() + wdir()) & max(. + wdir())'
1436 $ log '(all() + wdir()) & max(. + wdir())'
1437 2147483647
1437 2147483647
1438 $ log 'first(wdir() + .)'
1438 $ log 'first(wdir() + .)'
1439 2147483647
1439 2147483647
1440 $ log 'last(. + wdir())'
1440 $ log 'last(. + wdir())'
1441 2147483647
1441 2147483647
1442
1442
1443 Test working-directory integer revision and node id
1443 Test working-directory integer revision and node id
1444 (BUG: '0:wdir()' is still needed to populate wdir revision)
1444 (BUG: '0:wdir()' is still needed to populate wdir revision)
1445
1445
1446 $ hg debugrevspec '0:wdir() & 2147483647'
1446 $ hg debugrevspec '0:wdir() & 2147483647'
1447 2147483647
1447 2147483647
1448 $ hg debugrevspec '0:wdir() & rev(2147483647)'
1448 $ hg debugrevspec '0:wdir() & rev(2147483647)'
1449 2147483647
1449 2147483647
1450 $ hg debugrevspec '0:wdir() & ffffffffffffffffffffffffffffffffffffffff'
1450 $ hg debugrevspec '0:wdir() & ffffffffffffffffffffffffffffffffffffffff'
1451 2147483647
1451 2147483647
1452 $ hg debugrevspec '0:wdir() & ffffffffffff'
1452 $ hg debugrevspec '0:wdir() & ffffffffffff'
1453 2147483647
1453 2147483647
1454 $ hg debugrevspec '0:wdir() & id(ffffffffffffffffffffffffffffffffffffffff)'
1454 $ hg debugrevspec '0:wdir() & id(ffffffffffffffffffffffffffffffffffffffff)'
1455 2147483647
1455 2147483647
1456 $ hg debugrevspec '0:wdir() & id(ffffffffffff)'
1456 $ hg debugrevspec '0:wdir() & id(ffffffffffff)'
1457 2147483647
1457 2147483647
1458
1458
1459 $ cd ..
1459 $ cd ..
1460
1460
1461 Test short 'ff...' hash collision
1461 Test short 'ff...' hash collision
1462 (BUG: '0:wdir()' is still needed to populate wdir revision)
1462 (BUG: '0:wdir()' is still needed to populate wdir revision)
1463
1463
1464 $ hg init wdir-hashcollision
1464 $ hg init wdir-hashcollision
1465 $ cd wdir-hashcollision
1465 $ cd wdir-hashcollision
1466 $ cat <<EOF >> .hg/hgrc
1466 $ cat <<EOF >> .hg/hgrc
1467 > [experimental]
1467 > [experimental]
1468 > evolution = createmarkers
1468 > evolution = createmarkers
1469 > EOF
1469 > EOF
1470 $ echo 0 > a
1470 $ echo 0 > a
1471 $ hg ci -qAm 0
1471 $ hg ci -qAm 0
1472 $ for i in 2463 2961 6726 78127; do
1472 $ for i in 2463 2961 6726 78127; do
1473 > hg up -q 0
1473 > hg up -q 0
1474 > echo $i > a
1474 > echo $i > a
1475 > hg ci -qm $i
1475 > hg ci -qm $i
1476 > done
1476 > done
1477 $ hg up -q null
1477 $ hg up -q null
1478 $ hg log -r '0:wdir()' -T '{rev}:{node} {shortest(node, 3)}\n'
1478 $ hg log -r '0:wdir()' -T '{rev}:{node} {shortest(node, 3)}\n'
1479 0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a b4e
1479 0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a b4e
1480 1:fffbae3886c8fbb2114296380d276fd37715d571 fffba
1480 1:fffbae3886c8fbb2114296380d276fd37715d571 fffba
1481 2:fffb6093b00943f91034b9bdad069402c834e572 fffb6
1481 2:fffb6093b00943f91034b9bdad069402c834e572 fffb6
1482 3:fff48a9b9de34a4d64120c29548214c67980ade3 fff4
1482 3:fff48a9b9de34a4d64120c29548214c67980ade3 fff4
1483 4:ffff85cff0ff78504fcdc3c0bc10de0c65379249 ffff8
1483 4:ffff85cff0ff78504fcdc3c0bc10de0c65379249 ffff8
1484 2147483647:ffffffffffffffffffffffffffffffffffffffff fffff
1484 2147483647:ffffffffffffffffffffffffffffffffffffffff fffff
1485 $ hg debugobsolete fffbae3886c8fbb2114296380d276fd37715d571
1485 $ hg debugobsolete fffbae3886c8fbb2114296380d276fd37715d571
1486
1486
1487 $ hg debugrevspec '0:wdir() & fff'
1487 $ hg debugrevspec '0:wdir() & fff'
1488 abort: 00changelog.i@fff: ambiguous identifier!
1488 abort: 00changelog.i@fff: ambiguous identifier!
1489 [255]
1489 [255]
1490 $ hg debugrevspec '0:wdir() & ffff'
1490 $ hg debugrevspec '0:wdir() & ffff'
1491 abort: 00changelog.i@ffff: ambiguous identifier!
1491 abort: 00changelog.i@ffff: ambiguous identifier!
1492 [255]
1492 [255]
1493 $ hg debugrevspec '0:wdir() & fffb'
1493 $ hg debugrevspec '0:wdir() & fffb'
1494 abort: 00changelog.i@fffb: ambiguous identifier!
1494 abort: 00changelog.i@fffb: ambiguous identifier!
1495 [255]
1495 [255]
1496 BROKEN should be '2' (node lookup uses unfiltered repo since dc25ed84bee8)
1496 BROKEN should be '2' (node lookup uses unfiltered repo since dc25ed84bee8)
1497 $ hg debugrevspec '0:wdir() & id(fffb)'
1497 $ hg debugrevspec '0:wdir() & id(fffb)'
1498 2
1498 2
1499 $ hg debugrevspec '0:wdir() & ffff8'
1499 $ hg debugrevspec '0:wdir() & ffff8'
1500 4
1500 4
1501 $ hg debugrevspec '0:wdir() & fffff'
1501 $ hg debugrevspec '0:wdir() & fffff'
1502 2147483647
1502 2147483647
1503
1503
1504 $ cd ..
1504 $ cd ..
1505
1505
1506 Test branch() with wdir()
1506 Test branch() with wdir()
1507
1507
1508 $ cd repo
1508 $ cd repo
1509
1509
1510 $ log '0:wdir() & branch("literal:Γ©")'
1510 $ log '0:wdir() & branch("literal:Γ©")'
1511 8
1511 8
1512 9
1512 9
1513 2147483647
1513 2147483647
1514 $ log '0:wdir() & branch("re:Γ©")'
1514 $ log '0:wdir() & branch("re:Γ©")'
1515 8
1515 8
1516 9
1516 9
1517 2147483647
1517 2147483647
1518 $ log '0:wdir() & branch("re:^a")'
1518 $ log '0:wdir() & branch("re:^a")'
1519 0
1519 0
1520 2
1520 2
1521 $ log '0:wdir() & branch(8)'
1521 $ log '0:wdir() & branch(8)'
1522 8
1522 8
1523 9
1523 9
1524 2147483647
1524 2147483647
1525
1525
1526 branch(wdir()) returns all revisions belonging to the working branch. The wdir
1526 branch(wdir()) returns all revisions belonging to the working branch. The wdir
1527 itself isn't returned unless it is explicitly populated.
1527 itself isn't returned unless it is explicitly populated.
1528
1528
1529 $ log 'branch(wdir())'
1529 $ log 'branch(wdir())'
1530 8
1530 8
1531 9
1531 9
1532 $ log '0:wdir() & branch(wdir())'
1532 $ log '0:wdir() & branch(wdir())'
1533 8
1533 8
1534 9
1534 9
1535 2147483647
1535 2147483647
1536
1536
1537 $ log 'outgoing()'
1537 $ log 'outgoing()'
1538 8
1538 8
1539 9
1539 9
1540 $ log 'outgoing("../remote1")'
1540 $ log 'outgoing("../remote1")'
1541 8
1541 8
1542 9
1542 9
1543 $ log 'outgoing("../remote2")'
1543 $ log 'outgoing("../remote2")'
1544 3
1544 3
1545 5
1545 5
1546 6
1546 6
1547 7
1547 7
1548 9
1548 9
1549 $ log 'p1(merge())'
1549 $ log 'p1(merge())'
1550 5
1550 5
1551 $ log 'p2(merge())'
1551 $ log 'p2(merge())'
1552 4
1552 4
1553 $ log 'parents(merge())'
1553 $ log 'parents(merge())'
1554 4
1554 4
1555 5
1555 5
1556 $ log 'p1(branchpoint())'
1556 $ log 'p1(branchpoint())'
1557 0
1557 0
1558 2
1558 2
1559 $ log 'p2(branchpoint())'
1559 $ log 'p2(branchpoint())'
1560 $ log 'parents(branchpoint())'
1560 $ log 'parents(branchpoint())'
1561 0
1561 0
1562 2
1562 2
1563 $ log 'removes(a)'
1563 $ log 'removes(a)'
1564 2
1564 2
1565 6
1565 6
1566 $ log 'roots(all())'
1566 $ log 'roots(all())'
1567 0
1567 0
1568 $ log 'reverse(2 or 3 or 4 or 5)'
1568 $ log 'reverse(2 or 3 or 4 or 5)'
1569 5
1569 5
1570 4
1570 4
1571 3
1571 3
1572 2
1572 2
1573 $ log 'reverse(all())'
1573 $ log 'reverse(all())'
1574 9
1574 9
1575 8
1575 8
1576 7
1576 7
1577 6
1577 6
1578 5
1578 5
1579 4
1579 4
1580 3
1580 3
1581 2
1581 2
1582 1
1582 1
1583 0
1583 0
1584 $ log 'reverse(all()) & filelog(b)'
1584 $ log 'reverse(all()) & filelog(b)'
1585 4
1585 4
1586 1
1586 1
1587 $ log 'rev(5)'
1587 $ log 'rev(5)'
1588 5
1588 5
1589 $ log 'sort(limit(reverse(all()), 3))'
1589 $ log 'sort(limit(reverse(all()), 3))'
1590 7
1590 7
1591 8
1591 8
1592 9
1592 9
1593 $ log 'sort(2 or 3 or 4 or 5, date)'
1593 $ log 'sort(2 or 3 or 4 or 5, date)'
1594 2
1594 2
1595 3
1595 3
1596 5
1596 5
1597 4
1597 4
1598 $ log 'tagged()'
1598 $ log 'tagged()'
1599 6
1599 6
1600 $ log 'tag()'
1600 $ log 'tag()'
1601 6
1601 6
1602 $ log 'tag(1.0)'
1602 $ log 'tag(1.0)'
1603 6
1603 6
1604 $ log 'tag(tip)'
1604 $ log 'tag(tip)'
1605 9
1605 9
1606
1606
1607 Test order of revisions in compound expression
1607 Test order of revisions in compound expression
1608 ----------------------------------------------
1608 ----------------------------------------------
1609
1609
1610 The general rule is that only the outermost (= leftmost) predicate can
1610 The general rule is that only the outermost (= leftmost) predicate can
1611 enforce its ordering requirement. The other predicates should take the
1611 enforce its ordering requirement. The other predicates should take the
1612 ordering defined by it.
1612 ordering defined by it.
1613
1613
1614 'A & B' should follow the order of 'A':
1614 'A & B' should follow the order of 'A':
1615
1615
1616 $ log '2:0 & 0::2'
1616 $ log '2:0 & 0::2'
1617 2
1617 2
1618 1
1618 1
1619 0
1619 0
1620
1620
1621 'head()' combines sets in right order:
1621 'head()' combines sets in right order:
1622
1622
1623 $ log '2:0 & head()'
1623 $ log '2:0 & head()'
1624 2
1624 2
1625 1
1625 1
1626 0
1626 0
1627
1627
1628 'x:y' takes ordering parameter into account:
1628 'x:y' takes ordering parameter into account:
1629
1629
1630 $ try -p optimized '3:0 & 0:3 & not 2:1'
1630 $ try -p optimized '3:0 & 0:3 & not 2:1'
1631 * optimized:
1631 * optimized:
1632 (difference
1632 (difference
1633 (and
1633 (and
1634 (range
1634 (range
1635 ('symbol', '3')
1635 ('symbol', '3')
1636 ('symbol', '0')
1636 ('symbol', '0')
1637 define)
1637 define)
1638 (range
1638 (range
1639 ('symbol', '0')
1639 ('symbol', '0')
1640 ('symbol', '3')
1640 ('symbol', '3')
1641 follow)
1641 follow)
1642 define)
1642 define)
1643 (range
1643 (range
1644 ('symbol', '2')
1644 ('symbol', '2')
1645 ('symbol', '1')
1645 ('symbol', '1')
1646 any)
1646 any)
1647 define)
1647 define)
1648 * set:
1648 * set:
1649 <filteredset
1649 <filteredset
1650 <filteredset
1650 <filteredset
1651 <spanset- 0:4>,
1651 <spanset- 0:4>,
1652 <spanset+ 0:4>>,
1652 <spanset+ 0:4>>,
1653 <not
1653 <not
1654 <spanset+ 1:3>>>
1654 <spanset+ 1:3>>>
1655 3
1655 3
1656 0
1656 0
1657
1657
1658 'a + b', which is optimized to '_list(a b)', should take the ordering of
1658 'a + b', which is optimized to '_list(a b)', should take the ordering of
1659 the left expression:
1659 the left expression:
1660
1660
1661 $ try --optimize '2:0 & (0 + 1 + 2)'
1661 $ try --optimize '2:0 & (0 + 1 + 2)'
1662 (and
1662 (and
1663 (range
1663 (range
1664 ('symbol', '2')
1664 ('symbol', '2')
1665 ('symbol', '0'))
1665 ('symbol', '0'))
1666 (group
1666 (group
1667 (or
1667 (or
1668 (list
1668 (list
1669 ('symbol', '0')
1669 ('symbol', '0')
1670 ('symbol', '1')
1670 ('symbol', '1')
1671 ('symbol', '2')))))
1671 ('symbol', '2')))))
1672 * optimized:
1672 * optimized:
1673 (and
1673 (and
1674 (range
1674 (range
1675 ('symbol', '2')
1675 ('symbol', '2')
1676 ('symbol', '0')
1676 ('symbol', '0')
1677 define)
1677 define)
1678 (func
1678 (func
1679 ('symbol', '_list')
1679 ('symbol', '_list')
1680 ('string', '0\x001\x002')
1680 ('string', '0\x001\x002')
1681 follow)
1681 follow)
1682 define)
1682 define)
1683 * set:
1683 * set:
1684 <filteredset
1684 <filteredset
1685 <spanset- 0:3>,
1685 <spanset- 0:3>,
1686 <baseset [0, 1, 2]>>
1686 <baseset [0, 1, 2]>>
1687 2
1687 2
1688 1
1688 1
1689 0
1689 0
1690
1690
1691 'A + B' should take the ordering of the left expression:
1691 'A + B' should take the ordering of the left expression:
1692
1692
1693 $ try --optimize '2:0 & (0:1 + 2)'
1693 $ try --optimize '2:0 & (0:1 + 2)'
1694 (and
1694 (and
1695 (range
1695 (range
1696 ('symbol', '2')
1696 ('symbol', '2')
1697 ('symbol', '0'))
1697 ('symbol', '0'))
1698 (group
1698 (group
1699 (or
1699 (or
1700 (list
1700 (list
1701 (range
1701 (range
1702 ('symbol', '0')
1702 ('symbol', '0')
1703 ('symbol', '1'))
1703 ('symbol', '1'))
1704 ('symbol', '2')))))
1704 ('symbol', '2')))))
1705 * optimized:
1705 * optimized:
1706 (and
1706 (and
1707 (range
1707 (range
1708 ('symbol', '2')
1708 ('symbol', '2')
1709 ('symbol', '0')
1709 ('symbol', '0')
1710 define)
1710 define)
1711 (or
1711 (or
1712 (list
1712 (list
1713 ('symbol', '2')
1713 ('symbol', '2')
1714 (range
1714 (range
1715 ('symbol', '0')
1715 ('symbol', '0')
1716 ('symbol', '1')
1716 ('symbol', '1')
1717 follow))
1717 follow))
1718 follow)
1718 follow)
1719 define)
1719 define)
1720 * set:
1720 * set:
1721 <filteredset
1721 <filteredset
1722 <spanset- 0:3>,
1722 <spanset- 0:3>,
1723 <addset
1723 <addset
1724 <baseset [2]>,
1724 <baseset [2]>,
1725 <spanset+ 0:2>>>
1725 <spanset+ 0:2>>>
1726 2
1726 2
1727 1
1727 1
1728 0
1728 0
1729
1729
1730 '_intlist(a b)' should behave like 'a + b':
1730 '_intlist(a b)' should behave like 'a + b':
1731
1731
1732 $ trylist --optimize '2:0 & %ld' 0 1 2
1732 $ trylist --optimize '2:0 & %ld' 0 1 2
1733 (and
1733 (and
1734 (range
1734 (range
1735 ('symbol', '2')
1735 ('symbol', '2')
1736 ('symbol', '0'))
1736 ('symbol', '0'))
1737 (func
1737 (func
1738 ('symbol', '_intlist')
1738 ('symbol', '_intlist')
1739 ('string', '0\x001\x002')))
1739 ('string', '0\x001\x002')))
1740 * optimized:
1740 * optimized:
1741 (and
1741 (and
1742 (func
1742 (func
1743 ('symbol', '_intlist')
1743 ('symbol', '_intlist')
1744 ('string', '0\x001\x002')
1744 ('string', '0\x001\x002')
1745 follow)
1745 follow)
1746 (range
1746 (range
1747 ('symbol', '2')
1747 ('symbol', '2')
1748 ('symbol', '0')
1748 ('symbol', '0')
1749 define)
1749 define)
1750 define)
1750 define)
1751 * set:
1751 * set:
1752 <filteredset
1752 <filteredset
1753 <spanset- 0:3>,
1753 <spanset- 0:3>,
1754 <baseset+ [0, 1, 2]>>
1754 <baseset+ [0, 1, 2]>>
1755 2
1755 2
1756 1
1756 1
1757 0
1757 0
1758
1758
1759 $ trylist --optimize '%ld & 2:0' 0 2 1
1759 $ trylist --optimize '%ld & 2:0' 0 2 1
1760 (and
1760 (and
1761 (func
1761 (func
1762 ('symbol', '_intlist')
1762 ('symbol', '_intlist')
1763 ('string', '0\x002\x001'))
1763 ('string', '0\x002\x001'))
1764 (range
1764 (range
1765 ('symbol', '2')
1765 ('symbol', '2')
1766 ('symbol', '0')))
1766 ('symbol', '0')))
1767 * optimized:
1767 * optimized:
1768 (and
1768 (and
1769 (func
1769 (func
1770 ('symbol', '_intlist')
1770 ('symbol', '_intlist')
1771 ('string', '0\x002\x001')
1771 ('string', '0\x002\x001')
1772 define)
1772 define)
1773 (range
1773 (range
1774 ('symbol', '2')
1774 ('symbol', '2')
1775 ('symbol', '0')
1775 ('symbol', '0')
1776 follow)
1776 follow)
1777 define)
1777 define)
1778 * set:
1778 * set:
1779 <filteredset
1779 <filteredset
1780 <baseset [0, 2, 1]>,
1780 <baseset [0, 2, 1]>,
1781 <spanset- 0:3>>
1781 <spanset- 0:3>>
1782 0
1782 0
1783 2
1783 2
1784 1
1784 1
1785
1785
1786 '_hexlist(a b)' should behave like 'a + b':
1786 '_hexlist(a b)' should behave like 'a + b':
1787
1787
1788 $ trylist --optimize --bin '2:0 & %ln' `hg log -T '{node} ' -r0:2`
1788 $ trylist --optimize --bin '2:0 & %ln' `hg log -T '{node} ' -r0:2`
1789 (and
1789 (and
1790 (range
1790 (range
1791 ('symbol', '2')
1791 ('symbol', '2')
1792 ('symbol', '0'))
1792 ('symbol', '0'))
1793 (func
1793 (func
1794 ('symbol', '_hexlist')
1794 ('symbol', '_hexlist')
1795 ('string', '*'))) (glob)
1795 ('string', '*'))) (glob)
1796 * optimized:
1796 * optimized:
1797 (and
1797 (and
1798 (range
1798 (range
1799 ('symbol', '2')
1799 ('symbol', '2')
1800 ('symbol', '0')
1800 ('symbol', '0')
1801 define)
1801 define)
1802 (func
1802 (func
1803 ('symbol', '_hexlist')
1803 ('symbol', '_hexlist')
1804 ('string', '*') (glob)
1804 ('string', '*') (glob)
1805 follow)
1805 follow)
1806 define)
1806 define)
1807 * set:
1807 * set:
1808 <filteredset
1808 <filteredset
1809 <spanset- 0:3>,
1809 <spanset- 0:3>,
1810 <baseset [0, 1, 2]>>
1810 <baseset [0, 1, 2]>>
1811 2
1811 2
1812 1
1812 1
1813 0
1813 0
1814
1814
1815 $ trylist --optimize --bin '%ln & 2:0' `hg log -T '{node} ' -r0+2+1`
1815 $ trylist --optimize --bin '%ln & 2:0' `hg log -T '{node} ' -r0+2+1`
1816 (and
1816 (and
1817 (func
1817 (func
1818 ('symbol', '_hexlist')
1818 ('symbol', '_hexlist')
1819 ('string', '*')) (glob)
1819 ('string', '*')) (glob)
1820 (range
1820 (range
1821 ('symbol', '2')
1821 ('symbol', '2')
1822 ('symbol', '0')))
1822 ('symbol', '0')))
1823 * optimized:
1823 * optimized:
1824 (and
1824 (and
1825 (range
1825 (range
1826 ('symbol', '2')
1826 ('symbol', '2')
1827 ('symbol', '0')
1827 ('symbol', '0')
1828 follow)
1828 follow)
1829 (func
1829 (func
1830 ('symbol', '_hexlist')
1830 ('symbol', '_hexlist')
1831 ('string', '*') (glob)
1831 ('string', '*') (glob)
1832 define)
1832 define)
1833 define)
1833 define)
1834 * set:
1834 * set:
1835 <baseset [0, 2, 1]>
1835 <baseset [0, 2, 1]>
1836 0
1836 0
1837 2
1837 2
1838 1
1838 1
1839
1839
1840 '_list' should not go through the slow follow-order path if order doesn't
1840 '_list' should not go through the slow follow-order path if order doesn't
1841 matter:
1841 matter:
1842
1842
1843 $ try -p optimized '2:0 & not (0 + 1)'
1843 $ try -p optimized '2:0 & not (0 + 1)'
1844 * optimized:
1844 * optimized:
1845 (difference
1845 (difference
1846 (range
1846 (range
1847 ('symbol', '2')
1847 ('symbol', '2')
1848 ('symbol', '0')
1848 ('symbol', '0')
1849 define)
1849 define)
1850 (func
1850 (func
1851 ('symbol', '_list')
1851 ('symbol', '_list')
1852 ('string', '0\x001')
1852 ('string', '0\x001')
1853 any)
1853 any)
1854 define)
1854 define)
1855 * set:
1855 * set:
1856 <filteredset
1856 <filteredset
1857 <spanset- 0:3>,
1857 <spanset- 0:3>,
1858 <not
1858 <not
1859 <baseset [0, 1]>>>
1859 <baseset [0, 1]>>>
1860 2
1860 2
1861
1861
1862 $ try -p optimized '2:0 & not (0:2 & (0 + 1))'
1862 $ try -p optimized '2:0 & not (0:2 & (0 + 1))'
1863 * optimized:
1863 * optimized:
1864 (difference
1864 (difference
1865 (range
1865 (range
1866 ('symbol', '2')
1866 ('symbol', '2')
1867 ('symbol', '0')
1867 ('symbol', '0')
1868 define)
1868 define)
1869 (and
1869 (and
1870 (range
1870 (range
1871 ('symbol', '0')
1871 ('symbol', '0')
1872 ('symbol', '2')
1872 ('symbol', '2')
1873 any)
1873 any)
1874 (func
1874 (func
1875 ('symbol', '_list')
1875 ('symbol', '_list')
1876 ('string', '0\x001')
1876 ('string', '0\x001')
1877 any)
1877 any)
1878 any)
1878 any)
1879 define)
1879 define)
1880 * set:
1880 * set:
1881 <filteredset
1881 <filteredset
1882 <spanset- 0:3>,
1882 <spanset- 0:3>,
1883 <not
1883 <not
1884 <baseset [0, 1]>>>
1884 <baseset [0, 1]>>>
1885 2
1885 2
1886
1886
1887 because 'present()' does nothing other than suppressing an error, the
1887 because 'present()' does nothing other than suppressing an error, the
1888 ordering requirement should be forwarded to the nested expression
1888 ordering requirement should be forwarded to the nested expression
1889
1889
1890 $ try -p optimized 'present(2 + 0 + 1)'
1890 $ try -p optimized 'present(2 + 0 + 1)'
1891 * optimized:
1891 * optimized:
1892 (func
1892 (func
1893 ('symbol', 'present')
1893 ('symbol', 'present')
1894 (func
1894 (func
1895 ('symbol', '_list')
1895 ('symbol', '_list')
1896 ('string', '2\x000\x001')
1896 ('string', '2\x000\x001')
1897 define)
1897 define)
1898 define)
1898 define)
1899 * set:
1899 * set:
1900 <baseset [2, 0, 1]>
1900 <baseset [2, 0, 1]>
1901 2
1901 2
1902 0
1902 0
1903 1
1903 1
1904
1904
1905 $ try --optimize '2:0 & present(0 + 1 + 2)'
1905 $ try --optimize '2:0 & present(0 + 1 + 2)'
1906 (and
1906 (and
1907 (range
1907 (range
1908 ('symbol', '2')
1908 ('symbol', '2')
1909 ('symbol', '0'))
1909 ('symbol', '0'))
1910 (func
1910 (func
1911 ('symbol', 'present')
1911 ('symbol', 'present')
1912 (or
1912 (or
1913 (list
1913 (list
1914 ('symbol', '0')
1914 ('symbol', '0')
1915 ('symbol', '1')
1915 ('symbol', '1')
1916 ('symbol', '2')))))
1916 ('symbol', '2')))))
1917 * optimized:
1917 * optimized:
1918 (and
1918 (and
1919 (range
1919 (range
1920 ('symbol', '2')
1920 ('symbol', '2')
1921 ('symbol', '0')
1921 ('symbol', '0')
1922 define)
1922 define)
1923 (func
1923 (func
1924 ('symbol', 'present')
1924 ('symbol', 'present')
1925 (func
1925 (func
1926 ('symbol', '_list')
1926 ('symbol', '_list')
1927 ('string', '0\x001\x002')
1927 ('string', '0\x001\x002')
1928 follow)
1928 follow)
1929 follow)
1929 follow)
1930 define)
1930 define)
1931 * set:
1931 * set:
1932 <filteredset
1932 <filteredset
1933 <spanset- 0:3>,
1933 <spanset- 0:3>,
1934 <baseset [0, 1, 2]>>
1934 <baseset [0, 1, 2]>>
1935 2
1935 2
1936 1
1936 1
1937 0
1937 0
1938
1938
1939 'reverse()' should take effect only if it is the outermost expression:
1939 'reverse()' should take effect only if it is the outermost expression:
1940
1940
1941 $ try --optimize '0:2 & reverse(all())'
1941 $ try --optimize '0:2 & reverse(all())'
1942 (and
1942 (and
1943 (range
1943 (range
1944 ('symbol', '0')
1944 ('symbol', '0')
1945 ('symbol', '2'))
1945 ('symbol', '2'))
1946 (func
1946 (func
1947 ('symbol', 'reverse')
1947 ('symbol', 'reverse')
1948 (func
1948 (func
1949 ('symbol', 'all')
1949 ('symbol', 'all')
1950 None)))
1950 None)))
1951 * optimized:
1951 * optimized:
1952 (and
1952 (and
1953 (range
1953 (range
1954 ('symbol', '0')
1954 ('symbol', '0')
1955 ('symbol', '2')
1955 ('symbol', '2')
1956 define)
1956 define)
1957 (func
1957 (func
1958 ('symbol', 'reverse')
1958 ('symbol', 'reverse')
1959 (func
1959 (func
1960 ('symbol', 'all')
1960 ('symbol', 'all')
1961 None
1961 None
1962 define)
1962 define)
1963 follow)
1963 follow)
1964 define)
1964 define)
1965 * set:
1965 * set:
1966 <filteredset
1966 <filteredset
1967 <spanset+ 0:3>,
1967 <spanset+ 0:3>,
1968 <spanset+ 0:10>>
1968 <spanset+ 0:10>>
1969 0
1969 0
1970 1
1970 1
1971 2
1971 2
1972
1972
1973 'sort()' should take effect only if it is the outermost expression:
1973 'sort()' should take effect only if it is the outermost expression:
1974
1974
1975 $ try --optimize '0:2 & sort(all(), -rev)'
1975 $ try --optimize '0:2 & sort(all(), -rev)'
1976 (and
1976 (and
1977 (range
1977 (range
1978 ('symbol', '0')
1978 ('symbol', '0')
1979 ('symbol', '2'))
1979 ('symbol', '2'))
1980 (func
1980 (func
1981 ('symbol', 'sort')
1981 ('symbol', 'sort')
1982 (list
1982 (list
1983 (func
1983 (func
1984 ('symbol', 'all')
1984 ('symbol', 'all')
1985 None)
1985 None)
1986 (negate
1986 (negate
1987 ('symbol', 'rev')))))
1987 ('symbol', 'rev')))))
1988 * optimized:
1988 * optimized:
1989 (and
1989 (and
1990 (range
1990 (range
1991 ('symbol', '0')
1991 ('symbol', '0')
1992 ('symbol', '2')
1992 ('symbol', '2')
1993 define)
1993 define)
1994 (func
1994 (func
1995 ('symbol', 'sort')
1995 ('symbol', 'sort')
1996 (list
1996 (list
1997 (func
1997 (func
1998 ('symbol', 'all')
1998 ('symbol', 'all')
1999 None
1999 None
2000 define)
2000 define)
2001 ('string', '-rev'))
2001 ('string', '-rev'))
2002 follow)
2002 follow)
2003 define)
2003 define)
2004 * set:
2004 * set:
2005 <filteredset
2005 <filteredset
2006 <spanset+ 0:3>,
2006 <spanset+ 0:3>,
2007 <spanset+ 0:10>>
2007 <spanset+ 0:10>>
2008 0
2008 0
2009 1
2009 1
2010 2
2010 2
2011
2011
2012 invalid argument passed to noop sort():
2012 invalid argument passed to noop sort():
2013
2013
2014 $ log '0:2 & sort()'
2014 $ log '0:2 & sort()'
2015 hg: parse error: sort requires one or two arguments
2015 hg: parse error: sort requires one or two arguments
2016 [255]
2016 [255]
2017 $ log '0:2 & sort(all(), -invalid)'
2017 $ log '0:2 & sort(all(), -invalid)'
2018 hg: parse error: unknown sort key '-invalid'
2018 hg: parse error: unknown sort key '-invalid'
2019 [255]
2019 [255]
2020
2020
2021 for 'A & f(B)', 'B' should not be affected by the order of 'A':
2021 for 'A & f(B)', 'B' should not be affected by the order of 'A':
2022
2022
2023 $ try --optimize '2:0 & first(1 + 0 + 2)'
2023 $ try --optimize '2:0 & first(1 + 0 + 2)'
2024 (and
2024 (and
2025 (range
2025 (range
2026 ('symbol', '2')
2026 ('symbol', '2')
2027 ('symbol', '0'))
2027 ('symbol', '0'))
2028 (func
2028 (func
2029 ('symbol', 'first')
2029 ('symbol', 'first')
2030 (or
2030 (or
2031 (list
2031 (list
2032 ('symbol', '1')
2032 ('symbol', '1')
2033 ('symbol', '0')
2033 ('symbol', '0')
2034 ('symbol', '2')))))
2034 ('symbol', '2')))))
2035 * optimized:
2035 * optimized:
2036 (and
2036 (and
2037 (range
2037 (range
2038 ('symbol', '2')
2038 ('symbol', '2')
2039 ('symbol', '0')
2039 ('symbol', '0')
2040 define)
2040 define)
2041 (func
2041 (func
2042 ('symbol', 'first')
2042 ('symbol', 'first')
2043 (func
2043 (func
2044 ('symbol', '_list')
2044 ('symbol', '_list')
2045 ('string', '1\x000\x002')
2045 ('string', '1\x000\x002')
2046 define)
2046 define)
2047 follow)
2047 follow)
2048 define)
2048 define)
2049 * set:
2049 * set:
2050 <filteredset
2050 <filteredset
2051 <baseset [1]>,
2051 <baseset [1]>,
2052 <spanset- 0:3>>
2052 <spanset- 0:3>>
2053 1
2053 1
2054
2054
2055 $ try --optimize '2:0 & not last(0 + 2 + 1)'
2055 $ try --optimize '2:0 & not last(0 + 2 + 1)'
2056 (and
2056 (and
2057 (range
2057 (range
2058 ('symbol', '2')
2058 ('symbol', '2')
2059 ('symbol', '0'))
2059 ('symbol', '0'))
2060 (not
2060 (not
2061 (func
2061 (func
2062 ('symbol', 'last')
2062 ('symbol', 'last')
2063 (or
2063 (or
2064 (list
2064 (list
2065 ('symbol', '0')
2065 ('symbol', '0')
2066 ('symbol', '2')
2066 ('symbol', '2')
2067 ('symbol', '1'))))))
2067 ('symbol', '1'))))))
2068 * optimized:
2068 * optimized:
2069 (difference
2069 (difference
2070 (range
2070 (range
2071 ('symbol', '2')
2071 ('symbol', '2')
2072 ('symbol', '0')
2072 ('symbol', '0')
2073 define)
2073 define)
2074 (func
2074 (func
2075 ('symbol', 'last')
2075 ('symbol', 'last')
2076 (func
2076 (func
2077 ('symbol', '_list')
2077 ('symbol', '_list')
2078 ('string', '0\x002\x001')
2078 ('string', '0\x002\x001')
2079 define)
2079 define)
2080 any)
2080 any)
2081 define)
2081 define)
2082 * set:
2082 * set:
2083 <filteredset
2083 <filteredset
2084 <spanset- 0:3>,
2084 <spanset- 0:3>,
2085 <not
2085 <not
2086 <baseset [1]>>>
2086 <baseset [1]>>>
2087 2
2087 2
2088 0
2088 0
2089
2089
2090 for 'A & (op)(B)', 'B' should not be affected by the order of 'A':
2090 for 'A & (op)(B)', 'B' should not be affected by the order of 'A':
2091
2091
2092 $ try --optimize '2:0 & (1 + 0 + 2):(0 + 2 + 1)'
2092 $ try --optimize '2:0 & (1 + 0 + 2):(0 + 2 + 1)'
2093 (and
2093 (and
2094 (range
2094 (range
2095 ('symbol', '2')
2095 ('symbol', '2')
2096 ('symbol', '0'))
2096 ('symbol', '0'))
2097 (range
2097 (range
2098 (group
2098 (group
2099 (or
2099 (or
2100 (list
2100 (list
2101 ('symbol', '1')
2101 ('symbol', '1')
2102 ('symbol', '0')
2102 ('symbol', '0')
2103 ('symbol', '2'))))
2103 ('symbol', '2'))))
2104 (group
2104 (group
2105 (or
2105 (or
2106 (list
2106 (list
2107 ('symbol', '0')
2107 ('symbol', '0')
2108 ('symbol', '2')
2108 ('symbol', '2')
2109 ('symbol', '1'))))))
2109 ('symbol', '1'))))))
2110 * optimized:
2110 * optimized:
2111 (and
2111 (and
2112 (range
2112 (range
2113 ('symbol', '2')
2113 ('symbol', '2')
2114 ('symbol', '0')
2114 ('symbol', '0')
2115 define)
2115 define)
2116 (range
2116 (range
2117 (func
2117 (func
2118 ('symbol', '_list')
2118 ('symbol', '_list')
2119 ('string', '1\x000\x002')
2119 ('string', '1\x000\x002')
2120 define)
2120 define)
2121 (func
2121 (func
2122 ('symbol', '_list')
2122 ('symbol', '_list')
2123 ('string', '0\x002\x001')
2123 ('string', '0\x002\x001')
2124 define)
2124 define)
2125 follow)
2125 follow)
2126 define)
2126 define)
2127 * set:
2127 * set:
2128 <filteredset
2128 <filteredset
2129 <spanset- 0:3>,
2129 <spanset- 0:3>,
2130 <baseset [1]>>
2130 <baseset [1]>>
2131 1
2131 1
2132
2132
2133 'A & B' can be rewritten as 'B & A' by weight, but that's fine as long as
2133 'A & B' can be rewritten as 'B & A' by weight, but that's fine as long as
2134 the ordering rule is determined before the rewrite; in this example,
2134 the ordering rule is determined before the rewrite; in this example,
2135 'B' follows the order of the initial set, which is the same order as 'A'
2135 'B' follows the order of the initial set, which is the same order as 'A'
2136 since 'A' also follows the order:
2136 since 'A' also follows the order:
2137
2137
2138 $ try --optimize 'contains("glob:*") & (2 + 0 + 1)'
2138 $ try --optimize 'contains("glob:*") & (2 + 0 + 1)'
2139 (and
2139 (and
2140 (func
2140 (func
2141 ('symbol', 'contains')
2141 ('symbol', 'contains')
2142 ('string', 'glob:*'))
2142 ('string', 'glob:*'))
2143 (group
2143 (group
2144 (or
2144 (or
2145 (list
2145 (list
2146 ('symbol', '2')
2146 ('symbol', '2')
2147 ('symbol', '0')
2147 ('symbol', '0')
2148 ('symbol', '1')))))
2148 ('symbol', '1')))))
2149 * optimized:
2149 * optimized:
2150 (and
2150 (and
2151 (func
2151 (func
2152 ('symbol', '_list')
2152 ('symbol', '_list')
2153 ('string', '2\x000\x001')
2153 ('string', '2\x000\x001')
2154 follow)
2154 follow)
2155 (func
2155 (func
2156 ('symbol', 'contains')
2156 ('symbol', 'contains')
2157 ('string', 'glob:*')
2157 ('string', 'glob:*')
2158 define)
2158 define)
2159 define)
2159 define)
2160 * set:
2160 * set:
2161 <filteredset
2161 <filteredset
2162 <baseset+ [0, 1, 2]>,
2162 <baseset+ [0, 1, 2]>,
2163 <contains 'glob:*'>>
2163 <contains 'glob:*'>>
2164 0
2164 0
2165 1
2165 1
2166 2
2166 2
2167
2167
2168 and in this example, 'A & B' is rewritten as 'B & A', but 'A' overrides
2168 and in this example, 'A & B' is rewritten as 'B & A', but 'A' overrides
2169 the order appropriately:
2169 the order appropriately:
2170
2170
2171 $ try --optimize 'reverse(contains("glob:*")) & (0 + 2 + 1)'
2171 $ try --optimize 'reverse(contains("glob:*")) & (0 + 2 + 1)'
2172 (and
2172 (and
2173 (func
2173 (func
2174 ('symbol', 'reverse')
2174 ('symbol', 'reverse')
2175 (func
2175 (func
2176 ('symbol', 'contains')
2176 ('symbol', 'contains')
2177 ('string', 'glob:*')))
2177 ('string', 'glob:*')))
2178 (group
2178 (group
2179 (or
2179 (or
2180 (list
2180 (list
2181 ('symbol', '0')
2181 ('symbol', '0')
2182 ('symbol', '2')
2182 ('symbol', '2')
2183 ('symbol', '1')))))
2183 ('symbol', '1')))))
2184 * optimized:
2184 * optimized:
2185 (and
2185 (and
2186 (func
2186 (func
2187 ('symbol', '_list')
2187 ('symbol', '_list')
2188 ('string', '0\x002\x001')
2188 ('string', '0\x002\x001')
2189 follow)
2189 follow)
2190 (func
2190 (func
2191 ('symbol', 'reverse')
2191 ('symbol', 'reverse')
2192 (func
2192 (func
2193 ('symbol', 'contains')
2193 ('symbol', 'contains')
2194 ('string', 'glob:*')
2194 ('string', 'glob:*')
2195 define)
2195 define)
2196 define)
2196 define)
2197 define)
2197 define)
2198 * set:
2198 * set:
2199 <filteredset
2199 <filteredset
2200 <baseset- [0, 1, 2]>,
2200 <baseset- [0, 1, 2]>,
2201 <contains 'glob:*'>>
2201 <contains 'glob:*'>>
2202 2
2202 2
2203 1
2203 1
2204 0
2204 0
2205
2205
2206 'A + B' can be rewritten to 'B + A' by weight only when the order doesn't
2206 'A + B' can be rewritten to 'B + A' by weight only when the order doesn't
2207 matter (e.g. 'X & (A + B)' can be 'X & (B + A)', but '(A + B) & X' can't):
2207 matter (e.g. 'X & (A + B)' can be 'X & (B + A)', but '(A + B) & X' can't):
2208
2208
2209 $ try -p optimized '0:2 & (reverse(contains("a")) + 2)'
2209 $ try -p optimized '0:2 & (reverse(contains("a")) + 2)'
2210 * optimized:
2210 * optimized:
2211 (and
2211 (and
2212 (range
2212 (range
2213 ('symbol', '0')
2213 ('symbol', '0')
2214 ('symbol', '2')
2214 ('symbol', '2')
2215 define)
2215 define)
2216 (or
2216 (or
2217 (list
2217 (list
2218 ('symbol', '2')
2218 ('symbol', '2')
2219 (func
2219 (func
2220 ('symbol', 'reverse')
2220 ('symbol', 'reverse')
2221 (func
2221 (func
2222 ('symbol', 'contains')
2222 ('symbol', 'contains')
2223 ('string', 'a')
2223 ('string', 'a')
2224 define)
2224 define)
2225 follow))
2225 follow))
2226 follow)
2226 follow)
2227 define)
2227 define)
2228 * set:
2228 * set:
2229 <filteredset
2229 <filteredset
2230 <spanset+ 0:3>,
2230 <spanset+ 0:3>,
2231 <addset
2231 <addset
2232 <baseset [2]>,
2232 <baseset [2]>,
2233 <filteredset
2233 <filteredset
2234 <fullreposet+ 0:10>,
2234 <fullreposet+ 0:10>,
2235 <contains 'a'>>>>
2235 <contains 'a'>>>>
2236 0
2236 0
2237 1
2237 1
2238 2
2238 2
2239
2239
2240 $ try -p optimized '(reverse(contains("a")) + 2) & 0:2'
2240 $ try -p optimized '(reverse(contains("a")) + 2) & 0:2'
2241 * optimized:
2241 * optimized:
2242 (and
2242 (and
2243 (range
2243 (range
2244 ('symbol', '0')
2244 ('symbol', '0')
2245 ('symbol', '2')
2245 ('symbol', '2')
2246 follow)
2246 follow)
2247 (or
2247 (or
2248 (list
2248 (list
2249 (func
2249 (func
2250 ('symbol', 'reverse')
2250 ('symbol', 'reverse')
2251 (func
2251 (func
2252 ('symbol', 'contains')
2252 ('symbol', 'contains')
2253 ('string', 'a')
2253 ('string', 'a')
2254 define)
2254 define)
2255 define)
2255 define)
2256 ('symbol', '2'))
2256 ('symbol', '2'))
2257 define)
2257 define)
2258 define)
2258 define)
2259 * set:
2259 * set:
2260 <addset
2260 <addset
2261 <filteredset
2261 <filteredset
2262 <spanset- 0:3>,
2262 <spanset- 0:3>,
2263 <contains 'a'>>,
2263 <contains 'a'>>,
2264 <baseset [2]>>
2264 <baseset [2]>>
2265 1
2265 1
2266 0
2266 0
2267 2
2267 2
2268
2268
2269 test sort revset
2269 test sort revset
2270 --------------------------------------------
2270 --------------------------------------------
2271
2271
2272 test when adding two unordered revsets
2272 test when adding two unordered revsets
2273
2273
2274 $ log 'sort(keyword(issue) or modifies(b))'
2274 $ log 'sort(keyword(issue) or modifies(b))'
2275 4
2275 4
2276 6
2276 6
2277
2277
2278 test when sorting a reversed collection in the same way it is
2278 test when sorting a reversed collection in the same way it is
2279
2279
2280 $ log 'sort(reverse(all()), -rev)'
2280 $ log 'sort(reverse(all()), -rev)'
2281 9
2281 9
2282 8
2282 8
2283 7
2283 7
2284 6
2284 6
2285 5
2285 5
2286 4
2286 4
2287 3
2287 3
2288 2
2288 2
2289 1
2289 1
2290 0
2290 0
2291
2291
2292 test when sorting a reversed collection
2292 test when sorting a reversed collection
2293
2293
2294 $ log 'sort(reverse(all()), rev)'
2294 $ log 'sort(reverse(all()), rev)'
2295 0
2295 0
2296 1
2296 1
2297 2
2297 2
2298 3
2298 3
2299 4
2299 4
2300 5
2300 5
2301 6
2301 6
2302 7
2302 7
2303 8
2303 8
2304 9
2304 9
2305
2305
2306
2306
2307 test sorting two sorted collections in different orders
2307 test sorting two sorted collections in different orders
2308
2308
2309 $ log 'sort(outgoing() or reverse(removes(a)), rev)'
2309 $ log 'sort(outgoing() or reverse(removes(a)), rev)'
2310 2
2310 2
2311 6
2311 6
2312 8
2312 8
2313 9
2313 9
2314
2314
2315 test sorting two sorted collections in different orders backwards
2315 test sorting two sorted collections in different orders backwards
2316
2316
2317 $ log 'sort(outgoing() or reverse(removes(a)), -rev)'
2317 $ log 'sort(outgoing() or reverse(removes(a)), -rev)'
2318 9
2318 9
2319 8
2319 8
2320 6
2320 6
2321 2
2321 2
2322
2322
2323 test empty sort key which is noop
2323 test empty sort key which is noop
2324
2324
2325 $ log 'sort(0 + 2 + 1, "")'
2325 $ log 'sort(0 + 2 + 1, "")'
2326 0
2326 0
2327 2
2327 2
2328 1
2328 1
2329
2329
2330 test invalid sort keys
2330 test invalid sort keys
2331
2331
2332 $ log 'sort(all(), -invalid)'
2332 $ log 'sort(all(), -invalid)'
2333 hg: parse error: unknown sort key '-invalid'
2333 hg: parse error: unknown sort key '-invalid'
2334 [255]
2334 [255]
2335
2335
2336 $ cd ..
2336 $ cd ..
2337
2337
2338 test sorting by multiple keys including variable-length strings
2338 test sorting by multiple keys including variable-length strings
2339
2339
2340 $ hg init sorting
2340 $ hg init sorting
2341 $ cd sorting
2341 $ cd sorting
2342 $ cat <<EOF >> .hg/hgrc
2342 $ cat <<EOF >> .hg/hgrc
2343 > [ui]
2343 > [ui]
2344 > logtemplate = '{rev} {branch|p5}{desc|p5}{author|p5}{date|hgdate}\n'
2344 > logtemplate = '{rev} {branch|p5}{desc|p5}{author|p5}{date|hgdate}\n'
2345 > [templatealias]
2345 > [templatealias]
2346 > p5(s) = pad(s, 5)
2346 > p5(s) = pad(s, 5)
2347 > EOF
2347 > EOF
2348 $ hg branch -qf b12
2348 $ hg branch -qf b12
2349 $ hg ci -m m111 -u u112 -d '111 10800'
2349 $ hg ci -m m111 -u u112 -d '111 10800'
2350 $ hg branch -qf b11
2350 $ hg branch -qf b11
2351 $ hg ci -m m12 -u u111 -d '112 7200'
2351 $ hg ci -m m12 -u u111 -d '112 7200'
2352 $ hg branch -qf b111
2352 $ hg branch -qf b111
2353 $ hg ci -m m11 -u u12 -d '111 3600'
2353 $ hg ci -m m11 -u u12 -d '111 3600'
2354 $ hg branch -qf b112
2354 $ hg branch -qf b112
2355 $ hg ci -m m111 -u u11 -d '120 0'
2355 $ hg ci -m m111 -u u11 -d '120 0'
2356 $ hg branch -qf b111
2356 $ hg branch -qf b111
2357 $ hg ci -m m112 -u u111 -d '110 14400'
2357 $ hg ci -m m112 -u u111 -d '110 14400'
2358 created new head
2358 created new head
2359
2359
2360 compare revisions (has fast path):
2360 compare revisions (has fast path):
2361
2361
2362 $ hg log -r 'sort(all(), rev)'
2362 $ hg log -r 'sort(all(), rev)'
2363 0 b12 m111 u112 111 10800
2363 0 b12 m111 u112 111 10800
2364 1 b11 m12 u111 112 7200
2364 1 b11 m12 u111 112 7200
2365 2 b111 m11 u12 111 3600
2365 2 b111 m11 u12 111 3600
2366 3 b112 m111 u11 120 0
2366 3 b112 m111 u11 120 0
2367 4 b111 m112 u111 110 14400
2367 4 b111 m112 u111 110 14400
2368
2368
2369 $ hg log -r 'sort(all(), -rev)'
2369 $ hg log -r 'sort(all(), -rev)'
2370 4 b111 m112 u111 110 14400
2370 4 b111 m112 u111 110 14400
2371 3 b112 m111 u11 120 0
2371 3 b112 m111 u11 120 0
2372 2 b111 m11 u12 111 3600
2372 2 b111 m11 u12 111 3600
2373 1 b11 m12 u111 112 7200
2373 1 b11 m12 u111 112 7200
2374 0 b12 m111 u112 111 10800
2374 0 b12 m111 u112 111 10800
2375
2375
2376 compare variable-length strings (issue5218):
2376 compare variable-length strings (issue5218):
2377
2377
2378 $ hg log -r 'sort(all(), branch)'
2378 $ hg log -r 'sort(all(), branch)'
2379 1 b11 m12 u111 112 7200
2379 1 b11 m12 u111 112 7200
2380 2 b111 m11 u12 111 3600
2380 2 b111 m11 u12 111 3600
2381 4 b111 m112 u111 110 14400
2381 4 b111 m112 u111 110 14400
2382 3 b112 m111 u11 120 0
2382 3 b112 m111 u11 120 0
2383 0 b12 m111 u112 111 10800
2383 0 b12 m111 u112 111 10800
2384
2384
2385 $ hg log -r 'sort(all(), -branch)'
2385 $ hg log -r 'sort(all(), -branch)'
2386 0 b12 m111 u112 111 10800
2386 0 b12 m111 u112 111 10800
2387 3 b112 m111 u11 120 0
2387 3 b112 m111 u11 120 0
2388 2 b111 m11 u12 111 3600
2388 2 b111 m11 u12 111 3600
2389 4 b111 m112 u111 110 14400
2389 4 b111 m112 u111 110 14400
2390 1 b11 m12 u111 112 7200
2390 1 b11 m12 u111 112 7200
2391
2391
2392 $ hg log -r 'sort(all(), desc)'
2392 $ hg log -r 'sort(all(), desc)'
2393 2 b111 m11 u12 111 3600
2393 2 b111 m11 u12 111 3600
2394 0 b12 m111 u112 111 10800
2394 0 b12 m111 u112 111 10800
2395 3 b112 m111 u11 120 0
2395 3 b112 m111 u11 120 0
2396 4 b111 m112 u111 110 14400
2396 4 b111 m112 u111 110 14400
2397 1 b11 m12 u111 112 7200
2397 1 b11 m12 u111 112 7200
2398
2398
2399 $ hg log -r 'sort(all(), -desc)'
2399 $ hg log -r 'sort(all(), -desc)'
2400 1 b11 m12 u111 112 7200
2400 1 b11 m12 u111 112 7200
2401 4 b111 m112 u111 110 14400
2401 4 b111 m112 u111 110 14400
2402 0 b12 m111 u112 111 10800
2402 0 b12 m111 u112 111 10800
2403 3 b112 m111 u11 120 0
2403 3 b112 m111 u11 120 0
2404 2 b111 m11 u12 111 3600
2404 2 b111 m11 u12 111 3600
2405
2405
2406 $ hg log -r 'sort(all(), user)'
2406 $ hg log -r 'sort(all(), user)'
2407 3 b112 m111 u11 120 0
2407 3 b112 m111 u11 120 0
2408 1 b11 m12 u111 112 7200
2408 1 b11 m12 u111 112 7200
2409 4 b111 m112 u111 110 14400
2409 4 b111 m112 u111 110 14400
2410 0 b12 m111 u112 111 10800
2410 0 b12 m111 u112 111 10800
2411 2 b111 m11 u12 111 3600
2411 2 b111 m11 u12 111 3600
2412
2412
2413 $ hg log -r 'sort(all(), -user)'
2413 $ hg log -r 'sort(all(), -user)'
2414 2 b111 m11 u12 111 3600
2414 2 b111 m11 u12 111 3600
2415 0 b12 m111 u112 111 10800
2415 0 b12 m111 u112 111 10800
2416 1 b11 m12 u111 112 7200
2416 1 b11 m12 u111 112 7200
2417 4 b111 m112 u111 110 14400
2417 4 b111 m112 u111 110 14400
2418 3 b112 m111 u11 120 0
2418 3 b112 m111 u11 120 0
2419
2419
2420 compare dates (tz offset should have no effect):
2420 compare dates (tz offset should have no effect):
2421
2421
2422 $ hg log -r 'sort(all(), date)'
2422 $ hg log -r 'sort(all(), date)'
2423 4 b111 m112 u111 110 14400
2423 4 b111 m112 u111 110 14400
2424 0 b12 m111 u112 111 10800
2424 0 b12 m111 u112 111 10800
2425 2 b111 m11 u12 111 3600
2425 2 b111 m11 u12 111 3600
2426 1 b11 m12 u111 112 7200
2426 1 b11 m12 u111 112 7200
2427 3 b112 m111 u11 120 0
2427 3 b112 m111 u11 120 0
2428
2428
2429 $ hg log -r 'sort(all(), -date)'
2429 $ hg log -r 'sort(all(), -date)'
2430 3 b112 m111 u11 120 0
2430 3 b112 m111 u11 120 0
2431 1 b11 m12 u111 112 7200
2431 1 b11 m12 u111 112 7200
2432 0 b12 m111 u112 111 10800
2432 0 b12 m111 u112 111 10800
2433 2 b111 m11 u12 111 3600
2433 2 b111 m11 u12 111 3600
2434 4 b111 m112 u111 110 14400
2434 4 b111 m112 u111 110 14400
2435
2435
2436 be aware that 'sort(x, -k)' is not exactly the same as 'reverse(sort(x, k))'
2436 be aware that 'sort(x, -k)' is not exactly the same as 'reverse(sort(x, k))'
2437 because '-k' reverses the comparison, not the list itself:
2437 because '-k' reverses the comparison, not the list itself:
2438
2438
2439 $ hg log -r 'sort(0 + 2, date)'
2439 $ hg log -r 'sort(0 + 2, date)'
2440 0 b12 m111 u112 111 10800
2440 0 b12 m111 u112 111 10800
2441 2 b111 m11 u12 111 3600
2441 2 b111 m11 u12 111 3600
2442
2442
2443 $ hg log -r 'sort(0 + 2, -date)'
2443 $ hg log -r 'sort(0 + 2, -date)'
2444 0 b12 m111 u112 111 10800
2444 0 b12 m111 u112 111 10800
2445 2 b111 m11 u12 111 3600
2445 2 b111 m11 u12 111 3600
2446
2446
2447 $ hg log -r 'reverse(sort(0 + 2, date))'
2447 $ hg log -r 'reverse(sort(0 + 2, date))'
2448 2 b111 m11 u12 111 3600
2448 2 b111 m11 u12 111 3600
2449 0 b12 m111 u112 111 10800
2449 0 b12 m111 u112 111 10800
2450
2450
2451 sort by multiple keys:
2451 sort by multiple keys:
2452
2452
2453 $ hg log -r 'sort(all(), "branch -rev")'
2453 $ hg log -r 'sort(all(), "branch -rev")'
2454 1 b11 m12 u111 112 7200
2454 1 b11 m12 u111 112 7200
2455 4 b111 m112 u111 110 14400
2455 4 b111 m112 u111 110 14400
2456 2 b111 m11 u12 111 3600
2456 2 b111 m11 u12 111 3600
2457 3 b112 m111 u11 120 0
2457 3 b112 m111 u11 120 0
2458 0 b12 m111 u112 111 10800
2458 0 b12 m111 u112 111 10800
2459
2459
2460 $ hg log -r 'sort(all(), "-desc -date")'
2460 $ hg log -r 'sort(all(), "-desc -date")'
2461 1 b11 m12 u111 112 7200
2461 1 b11 m12 u111 112 7200
2462 4 b111 m112 u111 110 14400
2462 4 b111 m112 u111 110 14400
2463 3 b112 m111 u11 120 0
2463 3 b112 m111 u11 120 0
2464 0 b12 m111 u112 111 10800
2464 0 b12 m111 u112 111 10800
2465 2 b111 m11 u12 111 3600
2465 2 b111 m11 u12 111 3600
2466
2466
2467 $ hg log -r 'sort(all(), "user -branch date rev")'
2467 $ hg log -r 'sort(all(), "user -branch date rev")'
2468 3 b112 m111 u11 120 0
2468 3 b112 m111 u11 120 0
2469 4 b111 m112 u111 110 14400
2469 4 b111 m112 u111 110 14400
2470 1 b11 m12 u111 112 7200
2470 1 b11 m12 u111 112 7200
2471 0 b12 m111 u112 111 10800
2471 0 b12 m111 u112 111 10800
2472 2 b111 m11 u12 111 3600
2472 2 b111 m11 u12 111 3600
2473
2473
2474 toposort prioritises graph branches
2474 toposort prioritises graph branches
2475
2475
2476 $ hg up 2
2476 $ hg up 2
2477 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
2477 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
2478 $ touch a
2478 $ touch a
2479 $ hg addremove
2479 $ hg addremove
2480 adding a
2480 adding a
2481 $ hg ci -m 't1' -u 'tu' -d '130 0'
2481 $ hg ci -m 't1' -u 'tu' -d '130 0'
2482 created new head
2482 created new head
2483 $ echo 'a' >> a
2483 $ echo 'a' >> a
2484 $ hg ci -m 't2' -u 'tu' -d '130 0'
2484 $ hg ci -m 't2' -u 'tu' -d '130 0'
2485 $ hg book book1
2485 $ hg book book1
2486 $ hg up 4
2486 $ hg up 4
2487 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
2487 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
2488 (leaving bookmark book1)
2488 (leaving bookmark book1)
2489 $ touch a
2489 $ touch a
2490 $ hg addremove
2490 $ hg addremove
2491 adding a
2491 adding a
2492 $ hg ci -m 't3' -u 'tu' -d '130 0'
2492 $ hg ci -m 't3' -u 'tu' -d '130 0'
2493
2493
2494 $ hg log -r 'sort(all(), topo)'
2494 $ hg log -r 'sort(all(), topo)'
2495 7 b111 t3 tu 130 0
2495 7 b111 t3 tu 130 0
2496 4 b111 m112 u111 110 14400
2496 4 b111 m112 u111 110 14400
2497 3 b112 m111 u11 120 0
2497 3 b112 m111 u11 120 0
2498 6 b111 t2 tu 130 0
2498 6 b111 t2 tu 130 0
2499 5 b111 t1 tu 130 0
2499 5 b111 t1 tu 130 0
2500 2 b111 m11 u12 111 3600
2500 2 b111 m11 u12 111 3600
2501 1 b11 m12 u111 112 7200
2501 1 b11 m12 u111 112 7200
2502 0 b12 m111 u112 111 10800
2502 0 b12 m111 u112 111 10800
2503
2503
2504 $ hg log -r 'sort(all(), -topo)'
2504 $ hg log -r 'sort(all(), -topo)'
2505 0 b12 m111 u112 111 10800
2505 0 b12 m111 u112 111 10800
2506 1 b11 m12 u111 112 7200
2506 1 b11 m12 u111 112 7200
2507 2 b111 m11 u12 111 3600
2507 2 b111 m11 u12 111 3600
2508 5 b111 t1 tu 130 0
2508 5 b111 t1 tu 130 0
2509 6 b111 t2 tu 130 0
2509 6 b111 t2 tu 130 0
2510 3 b112 m111 u11 120 0
2510 3 b112 m111 u11 120 0
2511 4 b111 m112 u111 110 14400
2511 4 b111 m112 u111 110 14400
2512 7 b111 t3 tu 130 0
2512 7 b111 t3 tu 130 0
2513
2513
2514 $ hg log -r 'sort(all(), topo, topo.firstbranch=book1)'
2514 $ hg log -r 'sort(all(), topo, topo.firstbranch=book1)'
2515 6 b111 t2 tu 130 0
2515 6 b111 t2 tu 130 0
2516 5 b111 t1 tu 130 0
2516 5 b111 t1 tu 130 0
2517 7 b111 t3 tu 130 0
2517 7 b111 t3 tu 130 0
2518 4 b111 m112 u111 110 14400
2518 4 b111 m112 u111 110 14400
2519 3 b112 m111 u11 120 0
2519 3 b112 m111 u11 120 0
2520 2 b111 m11 u12 111 3600
2520 2 b111 m11 u12 111 3600
2521 1 b11 m12 u111 112 7200
2521 1 b11 m12 u111 112 7200
2522 0 b12 m111 u112 111 10800
2522 0 b12 m111 u112 111 10800
2523
2523
2524 topographical sorting can't be combined with other sort keys, and you can't
2524 topographical sorting can't be combined with other sort keys, and you can't
2525 use the topo.firstbranch option when topo sort is not active:
2525 use the topo.firstbranch option when topo sort is not active:
2526
2526
2527 $ hg log -r 'sort(all(), "topo user")'
2527 $ hg log -r 'sort(all(), "topo user")'
2528 hg: parse error: topo sort order cannot be combined with other sort keys
2528 hg: parse error: topo sort order cannot be combined with other sort keys
2529 [255]
2529 [255]
2530
2530
2531 $ hg log -r 'sort(all(), user, topo.firstbranch=book1)'
2531 $ hg log -r 'sort(all(), user, topo.firstbranch=book1)'
2532 hg: parse error: topo.firstbranch can only be used when using the topo sort key
2532 hg: parse error: topo.firstbranch can only be used when using the topo sort key
2533 [255]
2533 [255]
2534
2534
2535 topo.firstbranch should accept any kind of expressions:
2535 topo.firstbranch should accept any kind of expressions:
2536
2536
2537 $ hg log -r 'sort(0, topo, topo.firstbranch=(book1))'
2537 $ hg log -r 'sort(0, topo, topo.firstbranch=(book1))'
2538 0 b12 m111 u112 111 10800
2538 0 b12 m111 u112 111 10800
2539
2539
2540 $ cd ..
2540 $ cd ..
2541 $ cd repo
2541 $ cd repo
2542
2542
2543 test subtracting something from an addset
2543 test subtracting something from an addset
2544
2544
2545 $ log '(outgoing() or removes(a)) - removes(a)'
2545 $ log '(outgoing() or removes(a)) - removes(a)'
2546 8
2546 8
2547 9
2547 9
2548
2548
2549 test intersecting something with an addset
2549 test intersecting something with an addset
2550
2550
2551 $ log 'parents(outgoing() or removes(a))'
2551 $ log 'parents(outgoing() or removes(a))'
2552 1
2552 1
2553 4
2553 4
2554 5
2554 5
2555 8
2555 8
2556
2556
2557 test that `or` operation combines elements in the right order:
2557 test that `or` operation combines elements in the right order:
2558
2558
2559 $ log '3:4 or 2:5'
2559 $ log '3:4 or 2:5'
2560 3
2560 3
2561 4
2561 4
2562 2
2562 2
2563 5
2563 5
2564 $ log '3:4 or 5:2'
2564 $ log '3:4 or 5:2'
2565 3
2565 3
2566 4
2566 4
2567 5
2567 5
2568 2
2568 2
2569 $ log 'sort(3:4 or 2:5)'
2569 $ log 'sort(3:4 or 2:5)'
2570 2
2570 2
2571 3
2571 3
2572 4
2572 4
2573 5
2573 5
2574 $ log 'sort(3:4 or 5:2)'
2574 $ log 'sort(3:4 or 5:2)'
2575 2
2575 2
2576 3
2576 3
2577 4
2577 4
2578 5
2578 5
2579
2579
2580 test that more than one `-r`s are combined in the right order and deduplicated:
2580 test that more than one `-r`s are combined in the right order and deduplicated:
2581
2581
2582 $ hg log -T '{rev}\n' -r 3 -r 3 -r 4 -r 5:2 -r 'ancestors(4)'
2582 $ hg log -T '{rev}\n' -r 3 -r 3 -r 4 -r 5:2 -r 'ancestors(4)'
2583 3
2583 3
2584 4
2584 4
2585 5
2585 5
2586 2
2586 2
2587 0
2587 0
2588 1
2588 1
2589
2589
2590 test that `or` operation skips duplicated revisions from right-hand side
2590 test that `or` operation skips duplicated revisions from right-hand side
2591
2591
2592 $ try 'reverse(1::5) or ancestors(4)'
2592 $ try 'reverse(1::5) or ancestors(4)'
2593 (or
2593 (or
2594 (list
2594 (list
2595 (func
2595 (func
2596 ('symbol', 'reverse')
2596 ('symbol', 'reverse')
2597 (dagrange
2597 (dagrange
2598 ('symbol', '1')
2598 ('symbol', '1')
2599 ('symbol', '5')))
2599 ('symbol', '5')))
2600 (func
2600 (func
2601 ('symbol', 'ancestors')
2601 ('symbol', 'ancestors')
2602 ('symbol', '4'))))
2602 ('symbol', '4'))))
2603 * set:
2603 * set:
2604 <addset
2604 <addset
2605 <baseset- [1, 3, 5]>,
2605 <baseset- [1, 3, 5]>,
2606 <generatorset+>>
2606 <generatorset+>>
2607 5
2607 5
2608 3
2608 3
2609 1
2609 1
2610 0
2610 0
2611 2
2611 2
2612 4
2612 4
2613 $ try 'sort(ancestors(4) or reverse(1::5))'
2613 $ try 'sort(ancestors(4) or reverse(1::5))'
2614 (func
2614 (func
2615 ('symbol', 'sort')
2615 ('symbol', 'sort')
2616 (or
2616 (or
2617 (list
2617 (list
2618 (func
2618 (func
2619 ('symbol', 'ancestors')
2619 ('symbol', 'ancestors')
2620 ('symbol', '4'))
2620 ('symbol', '4'))
2621 (func
2621 (func
2622 ('symbol', 'reverse')
2622 ('symbol', 'reverse')
2623 (dagrange
2623 (dagrange
2624 ('symbol', '1')
2624 ('symbol', '1')
2625 ('symbol', '5'))))))
2625 ('symbol', '5'))))))
2626 * set:
2626 * set:
2627 <addset+
2627 <addset+
2628 <generatorset+>,
2628 <generatorset+>,
2629 <baseset- [1, 3, 5]>>
2629 <baseset- [1, 3, 5]>>
2630 0
2630 0
2631 1
2631 1
2632 2
2632 2
2633 3
2633 3
2634 4
2634 4
2635 5
2635 5
2636
2636
2637 test optimization of trivial `or` operation
2637 test optimization of trivial `or` operation
2638
2638
2639 $ try --optimize '0|(1)|"2"|-2|tip|null'
2639 $ try --optimize '0|(1)|"2"|-2|tip|null'
2640 (or
2640 (or
2641 (list
2641 (list
2642 ('symbol', '0')
2642 ('symbol', '0')
2643 (group
2643 (group
2644 ('symbol', '1'))
2644 ('symbol', '1'))
2645 ('string', '2')
2645 ('string', '2')
2646 (negate
2646 (negate
2647 ('symbol', '2'))
2647 ('symbol', '2'))
2648 ('symbol', 'tip')
2648 ('symbol', 'tip')
2649 ('symbol', 'null')))
2649 ('symbol', 'null')))
2650 * optimized:
2650 * optimized:
2651 (func
2651 (func
2652 ('symbol', '_list')
2652 ('symbol', '_list')
2653 ('string', '0\x001\x002\x00-2\x00tip\x00null')
2653 ('string', '0\x001\x002\x00-2\x00tip\x00null')
2654 define)
2654 define)
2655 * set:
2655 * set:
2656 <baseset [0, 1, 2, 8, 9, -1]>
2656 <baseset [0, 1, 2, 8, 9, -1]>
2657 0
2657 0
2658 1
2658 1
2659 2
2659 2
2660 8
2660 8
2661 9
2661 9
2662 -1
2662 -1
2663
2663
2664 $ try --optimize '0|1|2:3'
2664 $ try --optimize '0|1|2:3'
2665 (or
2665 (or
2666 (list
2666 (list
2667 ('symbol', '0')
2667 ('symbol', '0')
2668 ('symbol', '1')
2668 ('symbol', '1')
2669 (range
2669 (range
2670 ('symbol', '2')
2670 ('symbol', '2')
2671 ('symbol', '3'))))
2671 ('symbol', '3'))))
2672 * optimized:
2672 * optimized:
2673 (or
2673 (or
2674 (list
2674 (list
2675 (func
2675 (func
2676 ('symbol', '_list')
2676 ('symbol', '_list')
2677 ('string', '0\x001')
2677 ('string', '0\x001')
2678 define)
2678 define)
2679 (range
2679 (range
2680 ('symbol', '2')
2680 ('symbol', '2')
2681 ('symbol', '3')
2681 ('symbol', '3')
2682 define))
2682 define))
2683 define)
2683 define)
2684 * set:
2684 * set:
2685 <addset
2685 <addset
2686 <baseset [0, 1]>,
2686 <baseset [0, 1]>,
2687 <spanset+ 2:4>>
2687 <spanset+ 2:4>>
2688 0
2688 0
2689 1
2689 1
2690 2
2690 2
2691 3
2691 3
2692
2692
2693 $ try --optimize '0:1|2|3:4|5|6'
2693 $ try --optimize '0:1|2|3:4|5|6'
2694 (or
2694 (or
2695 (list
2695 (list
2696 (range
2696 (range
2697 ('symbol', '0')
2697 ('symbol', '0')
2698 ('symbol', '1'))
2698 ('symbol', '1'))
2699 ('symbol', '2')
2699 ('symbol', '2')
2700 (range
2700 (range
2701 ('symbol', '3')
2701 ('symbol', '3')
2702 ('symbol', '4'))
2702 ('symbol', '4'))
2703 ('symbol', '5')
2703 ('symbol', '5')
2704 ('symbol', '6')))
2704 ('symbol', '6')))
2705 * optimized:
2705 * optimized:
2706 (or
2706 (or
2707 (list
2707 (list
2708 (range
2708 (range
2709 ('symbol', '0')
2709 ('symbol', '0')
2710 ('symbol', '1')
2710 ('symbol', '1')
2711 define)
2711 define)
2712 ('symbol', '2')
2712 ('symbol', '2')
2713 (range
2713 (range
2714 ('symbol', '3')
2714 ('symbol', '3')
2715 ('symbol', '4')
2715 ('symbol', '4')
2716 define)
2716 define)
2717 (func
2717 (func
2718 ('symbol', '_list')
2718 ('symbol', '_list')
2719 ('string', '5\x006')
2719 ('string', '5\x006')
2720 define))
2720 define))
2721 define)
2721 define)
2722 * set:
2722 * set:
2723 <addset
2723 <addset
2724 <addset
2724 <addset
2725 <spanset+ 0:2>,
2725 <spanset+ 0:2>,
2726 <baseset [2]>>,
2726 <baseset [2]>>,
2727 <addset
2727 <addset
2728 <spanset+ 3:5>,
2728 <spanset+ 3:5>,
2729 <baseset [5, 6]>>>
2729 <baseset [5, 6]>>>
2730 0
2730 0
2731 1
2731 1
2732 2
2732 2
2733 3
2733 3
2734 4
2734 4
2735 5
2735 5
2736 6
2736 6
2737
2737
2738 unoptimized `or` looks like this
2738 unoptimized `or` looks like this
2739
2739
2740 $ try --no-optimized -p analyzed '0|1|2|3|4'
2740 $ try --no-optimized -p analyzed '0|1|2|3|4'
2741 * analyzed:
2741 * analyzed:
2742 (or
2742 (or
2743 (list
2743 (list
2744 ('symbol', '0')
2744 ('symbol', '0')
2745 ('symbol', '1')
2745 ('symbol', '1')
2746 ('symbol', '2')
2746 ('symbol', '2')
2747 ('symbol', '3')
2747 ('symbol', '3')
2748 ('symbol', '4'))
2748 ('symbol', '4'))
2749 define)
2749 define)
2750 * set:
2750 * set:
2751 <addset
2751 <addset
2752 <addset
2752 <addset
2753 <baseset [0]>,
2753 <baseset [0]>,
2754 <baseset [1]>>,
2754 <baseset [1]>>,
2755 <addset
2755 <addset
2756 <baseset [2]>,
2756 <baseset [2]>,
2757 <addset
2757 <addset
2758 <baseset [3]>,
2758 <baseset [3]>,
2759 <baseset [4]>>>>
2759 <baseset [4]>>>>
2760 0
2760 0
2761 1
2761 1
2762 2
2762 2
2763 3
2763 3
2764 4
2764 4
2765
2765
2766 test that `_list` should be narrowed by provided `subset`
2766 test that `_list` should be narrowed by provided `subset`
2767
2767
2768 $ log '0:2 and (null|1|2|3)'
2768 $ log '0:2 and (null|1|2|3)'
2769 1
2769 1
2770 2
2770 2
2771
2771
2772 test that `_list` should remove duplicates
2772 test that `_list` should remove duplicates
2773
2773
2774 $ log '0|1|2|1|2|-1|tip'
2774 $ log '0|1|2|1|2|-1|tip'
2775 0
2775 0
2776 1
2776 1
2777 2
2777 2
2778 9
2778 9
2779
2779
2780 test unknown revision in `_list`
2780 test unknown revision in `_list`
2781
2781
2782 $ log '0|unknown'
2782 $ log '0|unknown'
2783 abort: unknown revision 'unknown'!
2783 abort: unknown revision 'unknown'!
2784 [255]
2784 [255]
2785
2785
2786 test integer range in `_list`
2786 test integer range in `_list`
2787
2787
2788 $ log '-1|-10'
2788 $ log '-1|-10'
2789 9
2789 9
2790 0
2790 0
2791
2791
2792 $ log '-10|-11'
2792 $ log '-10|-11'
2793 abort: unknown revision '-11'!
2793 abort: unknown revision '-11'!
2794 [255]
2794 [255]
2795
2795
2796 $ log '9|10'
2796 $ log '9|10'
2797 abort: unknown revision '10'!
2797 abort: unknown revision '10'!
2798 [255]
2798 [255]
2799
2799
2800 test '0000' != '0' in `_list`
2800 test '0000' != '0' in `_list`
2801
2801
2802 $ log '0|0000'
2802 $ log '0|0000'
2803 0
2803 0
2804 -1
2804 -1
2805
2805
2806 test ',' in `_list`
2806 test ',' in `_list`
2807 $ log '0,1'
2807 $ log '0,1'
2808 hg: parse error: can't use a list in this context
2808 hg: parse error: can't use a list in this context
2809 (see hg help "revsets.x or y")
2809 (see hg help "revsets.x or y")
2810 [255]
2810 [255]
2811 $ try '0,1,2'
2811 $ try '0,1,2'
2812 (list
2812 (list
2813 ('symbol', '0')
2813 ('symbol', '0')
2814 ('symbol', '1')
2814 ('symbol', '1')
2815 ('symbol', '2'))
2815 ('symbol', '2'))
2816 hg: parse error: can't use a list in this context
2816 hg: parse error: can't use a list in this context
2817 (see hg help "revsets.x or y")
2817 (see hg help "revsets.x or y")
2818 [255]
2818 [255]
2819
2819
2820 test that chained `or` operations make balanced addsets
2820 test that chained `or` operations make balanced addsets
2821
2821
2822 $ try '0:1|1:2|2:3|3:4|4:5'
2822 $ try '0:1|1:2|2:3|3:4|4:5'
2823 (or
2823 (or
2824 (list
2824 (list
2825 (range
2825 (range
2826 ('symbol', '0')
2826 ('symbol', '0')
2827 ('symbol', '1'))
2827 ('symbol', '1'))
2828 (range
2828 (range
2829 ('symbol', '1')
2829 ('symbol', '1')
2830 ('symbol', '2'))
2830 ('symbol', '2'))
2831 (range
2831 (range
2832 ('symbol', '2')
2832 ('symbol', '2')
2833 ('symbol', '3'))
2833 ('symbol', '3'))
2834 (range
2834 (range
2835 ('symbol', '3')
2835 ('symbol', '3')
2836 ('symbol', '4'))
2836 ('symbol', '4'))
2837 (range
2837 (range
2838 ('symbol', '4')
2838 ('symbol', '4')
2839 ('symbol', '5'))))
2839 ('symbol', '5'))))
2840 * set:
2840 * set:
2841 <addset
2841 <addset
2842 <addset
2842 <addset
2843 <spanset+ 0:2>,
2843 <spanset+ 0:2>,
2844 <spanset+ 1:3>>,
2844 <spanset+ 1:3>>,
2845 <addset
2845 <addset
2846 <spanset+ 2:4>,
2846 <spanset+ 2:4>,
2847 <addset
2847 <addset
2848 <spanset+ 3:5>,
2848 <spanset+ 3:5>,
2849 <spanset+ 4:6>>>>
2849 <spanset+ 4:6>>>>
2850 0
2850 0
2851 1
2851 1
2852 2
2852 2
2853 3
2853 3
2854 4
2854 4
2855 5
2855 5
2856
2856
2857 no crash by empty group "()" while optimizing `or` operations
2857 no crash by empty group "()" while optimizing `or` operations
2858
2858
2859 $ try --optimize '0|()'
2859 $ try --optimize '0|()'
2860 (or
2860 (or
2861 (list
2861 (list
2862 ('symbol', '0')
2862 ('symbol', '0')
2863 (group
2863 (group
2864 None)))
2864 None)))
2865 * optimized:
2865 * optimized:
2866 (or
2866 (or
2867 (list
2867 (list
2868 ('symbol', '0')
2868 ('symbol', '0')
2869 None)
2869 None)
2870 define)
2870 define)
2871 hg: parse error: missing argument
2871 hg: parse error: missing argument
2872 [255]
2872 [255]
2873
2873
2874 test that chained `or` operations never eat up stack (issue4624)
2874 test that chained `or` operations never eat up stack (issue4624)
2875 (uses `0:1` instead of `0` to avoid future optimization of trivial revisions)
2875 (uses `0:1` instead of `0` to avoid future optimization of trivial revisions)
2876
2876
2877 $ hg log -T '{rev}\n' -r `python -c "print '+'.join(['0:1'] * 500)"`
2877 $ hg log -T '{rev}\n' -r `python -c "print '+'.join(['0:1'] * 500)"`
2878 0
2878 0
2879 1
2879 1
2880
2880
2881 test that repeated `-r` options never eat up stack (issue4565)
2881 test that repeated `-r` options never eat up stack (issue4565)
2882 (uses `-r 0::1` to avoid possible optimization at old-style parser)
2882 (uses `-r 0::1` to avoid possible optimization at old-style parser)
2883
2883
2884 $ hg log -T '{rev}\n' `python -c "for i in xrange(500): print '-r 0::1 ',"`
2884 $ hg log -T '{rev}\n' `python -c "for i in xrange(500): print '-r 0::1 ',"`
2885 0
2885 0
2886 1
2886 1
2887
2887
2888 check that conversion to only works
2888 check that conversion to only works
2889 $ try --optimize '::3 - ::1'
2889 $ try --optimize '::3 - ::1'
2890 (minus
2890 (minus
2891 (dagrangepre
2891 (dagrangepre
2892 ('symbol', '3'))
2892 ('symbol', '3'))
2893 (dagrangepre
2893 (dagrangepre
2894 ('symbol', '1')))
2894 ('symbol', '1')))
2895 * optimized:
2895 * optimized:
2896 (func
2896 (func
2897 ('symbol', 'only')
2897 ('symbol', 'only')
2898 (list
2898 (list
2899 ('symbol', '3')
2899 ('symbol', '3')
2900 ('symbol', '1'))
2900 ('symbol', '1'))
2901 define)
2901 define)
2902 * set:
2902 * set:
2903 <baseset+ [3]>
2903 <baseset+ [3]>
2904 3
2904 3
2905 $ try --optimize 'ancestors(1) - ancestors(3)'
2905 $ try --optimize 'ancestors(1) - ancestors(3)'
2906 (minus
2906 (minus
2907 (func
2907 (func
2908 ('symbol', 'ancestors')
2908 ('symbol', 'ancestors')
2909 ('symbol', '1'))
2909 ('symbol', '1'))
2910 (func
2910 (func
2911 ('symbol', 'ancestors')
2911 ('symbol', 'ancestors')
2912 ('symbol', '3')))
2912 ('symbol', '3')))
2913 * optimized:
2913 * optimized:
2914 (func
2914 (func
2915 ('symbol', 'only')
2915 ('symbol', 'only')
2916 (list
2916 (list
2917 ('symbol', '1')
2917 ('symbol', '1')
2918 ('symbol', '3'))
2918 ('symbol', '3'))
2919 define)
2919 define)
2920 * set:
2920 * set:
2921 <baseset+ []>
2921 <baseset+ []>
2922 $ try --optimize 'not ::2 and ::6'
2922 $ try --optimize 'not ::2 and ::6'
2923 (and
2923 (and
2924 (not
2924 (not
2925 (dagrangepre
2925 (dagrangepre
2926 ('symbol', '2')))
2926 ('symbol', '2')))
2927 (dagrangepre
2927 (dagrangepre
2928 ('symbol', '6')))
2928 ('symbol', '6')))
2929 * optimized:
2929 * optimized:
2930 (func
2930 (func
2931 ('symbol', 'only')
2931 ('symbol', 'only')
2932 (list
2932 (list
2933 ('symbol', '6')
2933 ('symbol', '6')
2934 ('symbol', '2'))
2934 ('symbol', '2'))
2935 define)
2935 define)
2936 * set:
2936 * set:
2937 <baseset+ [3, 4, 5, 6]>
2937 <baseset+ [3, 4, 5, 6]>
2938 3
2938 3
2939 4
2939 4
2940 5
2940 5
2941 6
2941 6
2942 $ try --optimize 'ancestors(6) and not ancestors(4)'
2942 $ try --optimize 'ancestors(6) and not ancestors(4)'
2943 (and
2943 (and
2944 (func
2944 (func
2945 ('symbol', 'ancestors')
2945 ('symbol', 'ancestors')
2946 ('symbol', '6'))
2946 ('symbol', '6'))
2947 (not
2947 (not
2948 (func
2948 (func
2949 ('symbol', 'ancestors')
2949 ('symbol', 'ancestors')
2950 ('symbol', '4'))))
2950 ('symbol', '4'))))
2951 * optimized:
2951 * optimized:
2952 (func
2952 (func
2953 ('symbol', 'only')
2953 ('symbol', 'only')
2954 (list
2954 (list
2955 ('symbol', '6')
2955 ('symbol', '6')
2956 ('symbol', '4'))
2956 ('symbol', '4'))
2957 define)
2957 define)
2958 * set:
2958 * set:
2959 <baseset+ [3, 5, 6]>
2959 <baseset+ [3, 5, 6]>
2960 3
2960 3
2961 5
2961 5
2962 6
2962 6
2963
2963
2964 no crash by empty group "()" while optimizing to "only()"
2964 no crash by empty group "()" while optimizing to "only()"
2965
2965
2966 $ try --optimize '::1 and ()'
2966 $ try --optimize '::1 and ()'
2967 (and
2967 (and
2968 (dagrangepre
2968 (dagrangepre
2969 ('symbol', '1'))
2969 ('symbol', '1'))
2970 (group
2970 (group
2971 None))
2971 None))
2972 * optimized:
2972 * optimized:
2973 (and
2973 (and
2974 None
2974 None
2975 (func
2975 (func
2976 ('symbol', 'ancestors')
2976 ('symbol', 'ancestors')
2977 ('symbol', '1')
2977 ('symbol', '1')
2978 define)
2978 define)
2979 define)
2979 define)
2980 hg: parse error: missing argument
2980 hg: parse error: missing argument
2981 [255]
2981 [255]
2982
2982
2983 optimization to only() works only if ancestors() takes only one argument
2983 optimization to only() works only if ancestors() takes only one argument
2984
2984
2985 $ hg debugrevspec -p optimized 'ancestors(6) - ancestors(4, 1)'
2985 $ hg debugrevspec -p optimized 'ancestors(6) - ancestors(4, 1)'
2986 * optimized:
2986 * optimized:
2987 (difference
2987 (difference
2988 (func
2988 (func
2989 ('symbol', 'ancestors')
2989 ('symbol', 'ancestors')
2990 ('symbol', '6')
2990 ('symbol', '6')
2991 define)
2991 define)
2992 (func
2992 (func
2993 ('symbol', 'ancestors')
2993 ('symbol', 'ancestors')
2994 (list
2994 (list
2995 ('symbol', '4')
2995 ('symbol', '4')
2996 ('symbol', '1'))
2996 ('symbol', '1'))
2997 any)
2997 any)
2998 define)
2998 define)
2999 hg: parse error: can't use a list in this context
2999 hg: parse error: ancestors takes at most 1 positional arguments
3000 (see hg help "revsets.x or y")
3001 [255]
3000 [255]
3002 $ hg debugrevspec -p optimized 'ancestors(6, 1) - ancestors(4)'
3001 $ hg debugrevspec -p optimized 'ancestors(6, 1) - ancestors(4)'
3003 * optimized:
3002 * optimized:
3004 (difference
3003 (difference
3005 (func
3004 (func
3006 ('symbol', 'ancestors')
3005 ('symbol', 'ancestors')
3007 (list
3006 (list
3008 ('symbol', '6')
3007 ('symbol', '6')
3009 ('symbol', '1'))
3008 ('symbol', '1'))
3010 define)
3009 define)
3011 (func
3010 (func
3012 ('symbol', 'ancestors')
3011 ('symbol', 'ancestors')
3013 ('symbol', '4')
3012 ('symbol', '4')
3014 any)
3013 any)
3015 define)
3014 define)
3016 hg: parse error: can't use a list in this context
3015 hg: parse error: ancestors takes at most 1 positional arguments
3017 (see hg help "revsets.x or y")
3018 [255]
3016 [255]
3019
3017
3020 optimization disabled if keyword arguments passed (because we're too lazy
3018 optimization disabled if keyword arguments passed (because we're too lazy
3021 to support it)
3019 to support it)
3022
3020
3023 $ hg debugrevspec -p optimized 'ancestors(set=6) - ancestors(set=4)'
3021 $ hg debugrevspec -p optimized 'ancestors(set=6) - ancestors(set=4)'
3024 * optimized:
3022 * optimized:
3025 (difference
3023 (difference
3026 (func
3024 (func
3027 ('symbol', 'ancestors')
3025 ('symbol', 'ancestors')
3028 (keyvalue
3026 (keyvalue
3029 ('symbol', 'set')
3027 ('symbol', 'set')
3030 ('symbol', '6'))
3028 ('symbol', '6'))
3031 define)
3029 define)
3032 (func
3030 (func
3033 ('symbol', 'ancestors')
3031 ('symbol', 'ancestors')
3034 (keyvalue
3032 (keyvalue
3035 ('symbol', 'set')
3033 ('symbol', 'set')
3036 ('symbol', '4'))
3034 ('symbol', '4'))
3037 any)
3035 any)
3038 define)
3036 define)
3039 hg: parse error: can't use a key-value pair in this context
3037 3
3040 [255]
3038 5
3039 6
3041
3040
3042 invalid function call should not be optimized to only()
3041 invalid function call should not be optimized to only()
3043
3042
3044 $ log '"ancestors"(6) and not ancestors(4)'
3043 $ log '"ancestors"(6) and not ancestors(4)'
3045 hg: parse error: not a symbol
3044 hg: parse error: not a symbol
3046 [255]
3045 [255]
3047
3046
3048 $ log 'ancestors(6) and not "ancestors"(4)'
3047 $ log 'ancestors(6) and not "ancestors"(4)'
3049 hg: parse error: not a symbol
3048 hg: parse error: not a symbol
3050 [255]
3049 [255]
3051
3050
3052 we can use patterns when searching for tags
3051 we can use patterns when searching for tags
3053
3052
3054 $ log 'tag("1..*")'
3053 $ log 'tag("1..*")'
3055 abort: tag '1..*' does not exist!
3054 abort: tag '1..*' does not exist!
3056 [255]
3055 [255]
3057 $ log 'tag("re:1..*")'
3056 $ log 'tag("re:1..*")'
3058 6
3057 6
3059 $ log 'tag("re:[0-9].[0-9]")'
3058 $ log 'tag("re:[0-9].[0-9]")'
3060 6
3059 6
3061 $ log 'tag("literal:1.0")'
3060 $ log 'tag("literal:1.0")'
3062 6
3061 6
3063 $ log 'tag("re:0..*")'
3062 $ log 'tag("re:0..*")'
3064
3063
3065 $ log 'tag(unknown)'
3064 $ log 'tag(unknown)'
3066 abort: tag 'unknown' does not exist!
3065 abort: tag 'unknown' does not exist!
3067 [255]
3066 [255]
3068 $ log 'tag("re:unknown")'
3067 $ log 'tag("re:unknown")'
3069 $ log 'present(tag("unknown"))'
3068 $ log 'present(tag("unknown"))'
3070 $ log 'present(tag("re:unknown"))'
3069 $ log 'present(tag("re:unknown"))'
3071 $ log 'branch(unknown)'
3070 $ log 'branch(unknown)'
3072 abort: unknown revision 'unknown'!
3071 abort: unknown revision 'unknown'!
3073 [255]
3072 [255]
3074 $ log 'branch("literal:unknown")'
3073 $ log 'branch("literal:unknown")'
3075 abort: branch 'unknown' does not exist!
3074 abort: branch 'unknown' does not exist!
3076 [255]
3075 [255]
3077 $ log 'branch("re:unknown")'
3076 $ log 'branch("re:unknown")'
3078 $ log 'present(branch("unknown"))'
3077 $ log 'present(branch("unknown"))'
3079 $ log 'present(branch("re:unknown"))'
3078 $ log 'present(branch("re:unknown"))'
3080 $ log 'user(bob)'
3079 $ log 'user(bob)'
3081 2
3080 2
3082
3081
3083 $ log '4::8'
3082 $ log '4::8'
3084 4
3083 4
3085 8
3084 8
3086 $ log '4:8'
3085 $ log '4:8'
3087 4
3086 4
3088 5
3087 5
3089 6
3088 6
3090 7
3089 7
3091 8
3090 8
3092
3091
3093 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
3092 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
3094 4
3093 4
3095 2
3094 2
3096 5
3095 5
3097
3096
3098 $ log 'not 0 and 0:2'
3097 $ log 'not 0 and 0:2'
3099 1
3098 1
3100 2
3099 2
3101 $ log 'not 1 and 0:2'
3100 $ log 'not 1 and 0:2'
3102 0
3101 0
3103 2
3102 2
3104 $ log 'not 2 and 0:2'
3103 $ log 'not 2 and 0:2'
3105 0
3104 0
3106 1
3105 1
3107 $ log '(1 and 2)::'
3106 $ log '(1 and 2)::'
3108 $ log '(1 and 2):'
3107 $ log '(1 and 2):'
3109 $ log '(1 and 2):3'
3108 $ log '(1 and 2):3'
3110 $ log 'sort(head(), -rev)'
3109 $ log 'sort(head(), -rev)'
3111 9
3110 9
3112 7
3111 7
3113 6
3112 6
3114 5
3113 5
3115 4
3114 4
3116 3
3115 3
3117 2
3116 2
3118 1
3117 1
3119 0
3118 0
3120 $ log '4::8 - 8'
3119 $ log '4::8 - 8'
3121 4
3120 4
3122
3121
3123 matching() should preserve the order of the input set:
3122 matching() should preserve the order of the input set:
3124
3123
3125 $ log '(2 or 3 or 1) and matching(1 or 2 or 3)'
3124 $ log '(2 or 3 or 1) and matching(1 or 2 or 3)'
3126 2
3125 2
3127 3
3126 3
3128 1
3127 1
3129
3128
3130 $ log 'named("unknown")'
3129 $ log 'named("unknown")'
3131 abort: namespace 'unknown' does not exist!
3130 abort: namespace 'unknown' does not exist!
3132 [255]
3131 [255]
3133 $ log 'named("re:unknown")'
3132 $ log 'named("re:unknown")'
3134 abort: no namespace exists that match 'unknown'!
3133 abort: no namespace exists that match 'unknown'!
3135 [255]
3134 [255]
3136 $ log 'present(named("unknown"))'
3135 $ log 'present(named("unknown"))'
3137 $ log 'present(named("re:unknown"))'
3136 $ log 'present(named("re:unknown"))'
3138
3137
3139 $ log 'tag()'
3138 $ log 'tag()'
3140 6
3139 6
3141 $ log 'named("tags")'
3140 $ log 'named("tags")'
3142 6
3141 6
3143
3142
3144 issue2437
3143 issue2437
3145
3144
3146 $ log '3 and p1(5)'
3145 $ log '3 and p1(5)'
3147 3
3146 3
3148 $ log '4 and p2(6)'
3147 $ log '4 and p2(6)'
3149 4
3148 4
3150 $ log '1 and parents(:2)'
3149 $ log '1 and parents(:2)'
3151 1
3150 1
3152 $ log '2 and children(1:)'
3151 $ log '2 and children(1:)'
3153 2
3152 2
3154 $ log 'roots(all()) or roots(all())'
3153 $ log 'roots(all()) or roots(all())'
3155 0
3154 0
3156 $ hg debugrevspec 'roots(all()) or roots(all())'
3155 $ hg debugrevspec 'roots(all()) or roots(all())'
3157 0
3156 0
3158 $ log 'heads(branch(Γ©)) or heads(branch(Γ©))'
3157 $ log 'heads(branch(Γ©)) or heads(branch(Γ©))'
3159 9
3158 9
3160 $ log 'ancestors(8) and (heads(branch("-a-b-c-")) or heads(branch(Γ©)))'
3159 $ log 'ancestors(8) and (heads(branch("-a-b-c-")) or heads(branch(Γ©)))'
3161 4
3160 4
3162
3161
3163 issue2654: report a parse error if the revset was not completely parsed
3162 issue2654: report a parse error if the revset was not completely parsed
3164
3163
3165 $ log '1 OR 2'
3164 $ log '1 OR 2'
3166 hg: parse error at 2: invalid token
3165 hg: parse error at 2: invalid token
3167 [255]
3166 [255]
3168
3167
3169 or operator should preserve ordering:
3168 or operator should preserve ordering:
3170 $ log 'reverse(2::4) or tip'
3169 $ log 'reverse(2::4) or tip'
3171 4
3170 4
3172 2
3171 2
3173 9
3172 9
3174
3173
3175 parentrevspec
3174 parentrevspec
3176
3175
3177 $ log 'merge()^0'
3176 $ log 'merge()^0'
3178 6
3177 6
3179 $ log 'merge()^'
3178 $ log 'merge()^'
3180 5
3179 5
3181 $ log 'merge()^1'
3180 $ log 'merge()^1'
3182 5
3181 5
3183 $ log 'merge()^2'
3182 $ log 'merge()^2'
3184 4
3183 4
3185 $ log '(not merge())^2'
3184 $ log '(not merge())^2'
3186 $ log 'merge()^^'
3185 $ log 'merge()^^'
3187 3
3186 3
3188 $ log 'merge()^1^'
3187 $ log 'merge()^1^'
3189 3
3188 3
3190 $ log 'merge()^^^'
3189 $ log 'merge()^^^'
3191 1
3190 1
3192
3191
3193 $ hg debugrevspec -s '(merge() | 0)~-1'
3192 $ hg debugrevspec -s '(merge() | 0)~-1'
3194 * set:
3193 * set:
3195 <baseset+ [1, 7]>
3194 <baseset+ [1, 7]>
3196 1
3195 1
3197 7
3196 7
3198 $ log 'merge()~-1'
3197 $ log 'merge()~-1'
3199 7
3198 7
3200 $ log 'tip~-1'
3199 $ log 'tip~-1'
3201 $ log '(tip | merge())~-1'
3200 $ log '(tip | merge())~-1'
3202 7
3201 7
3203 $ log 'merge()~0'
3202 $ log 'merge()~0'
3204 6
3203 6
3205 $ log 'merge()~1'
3204 $ log 'merge()~1'
3206 5
3205 5
3207 $ log 'merge()~2'
3206 $ log 'merge()~2'
3208 3
3207 3
3209 $ log 'merge()~2^1'
3208 $ log 'merge()~2^1'
3210 1
3209 1
3211 $ log 'merge()~3'
3210 $ log 'merge()~3'
3212 1
3211 1
3213
3212
3214 $ log '(-3:tip)^'
3213 $ log '(-3:tip)^'
3215 4
3214 4
3216 6
3215 6
3217 8
3216 8
3218
3217
3219 $ log 'tip^foo'
3218 $ log 'tip^foo'
3220 hg: parse error: ^ expects a number 0, 1, or 2
3219 hg: parse error: ^ expects a number 0, 1, or 2
3221 [255]
3220 [255]
3222
3221
3223 $ log 'branchpoint()~-1'
3222 $ log 'branchpoint()~-1'
3224 abort: revision in set has more than one child!
3223 abort: revision in set has more than one child!
3225 [255]
3224 [255]
3226
3225
3227 Bogus function gets suggestions
3226 Bogus function gets suggestions
3228 $ log 'add()'
3227 $ log 'add()'
3229 hg: parse error: unknown identifier: add
3228 hg: parse error: unknown identifier: add
3230 (did you mean adds?)
3229 (did you mean adds?)
3231 [255]
3230 [255]
3232 $ log 'added()'
3231 $ log 'added()'
3233 hg: parse error: unknown identifier: added
3232 hg: parse error: unknown identifier: added
3234 (did you mean adds?)
3233 (did you mean adds?)
3235 [255]
3234 [255]
3236 $ log 'remo()'
3235 $ log 'remo()'
3237 hg: parse error: unknown identifier: remo
3236 hg: parse error: unknown identifier: remo
3238 (did you mean one of remote, removes?)
3237 (did you mean one of remote, removes?)
3239 [255]
3238 [255]
3240 $ log 'babar()'
3239 $ log 'babar()'
3241 hg: parse error: unknown identifier: babar
3240 hg: parse error: unknown identifier: babar
3242 [255]
3241 [255]
3243
3242
3244 Bogus function with a similar internal name doesn't suggest the internal name
3243 Bogus function with a similar internal name doesn't suggest the internal name
3245 $ log 'matches()'
3244 $ log 'matches()'
3246 hg: parse error: unknown identifier: matches
3245 hg: parse error: unknown identifier: matches
3247 (did you mean matching?)
3246 (did you mean matching?)
3248 [255]
3247 [255]
3249
3248
3250 Undocumented functions aren't suggested as similar either
3249 Undocumented functions aren't suggested as similar either
3251 $ log 'tagged2()'
3250 $ log 'tagged2()'
3252 hg: parse error: unknown identifier: tagged2
3251 hg: parse error: unknown identifier: tagged2
3253 [255]
3252 [255]
3254
3253
3255 multiple revspecs
3254 multiple revspecs
3256
3255
3257 $ hg log -r 'tip~1:tip' -r 'tip~2:tip~1' --template '{rev}\n'
3256 $ hg log -r 'tip~1:tip' -r 'tip~2:tip~1' --template '{rev}\n'
3258 8
3257 8
3259 9
3258 9
3260 4
3259 4
3261 5
3260 5
3262 6
3261 6
3263 7
3262 7
3264
3263
3265 test usage in revpair (with "+")
3264 test usage in revpair (with "+")
3266
3265
3267 (real pair)
3266 (real pair)
3268
3267
3269 $ hg diff -r 'tip^^' -r 'tip'
3268 $ hg diff -r 'tip^^' -r 'tip'
3270 diff -r 2326846efdab -r 24286f4ae135 .hgtags
3269 diff -r 2326846efdab -r 24286f4ae135 .hgtags
3271 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3270 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3272 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
3271 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
3273 @@ -0,0 +1,1 @@
3272 @@ -0,0 +1,1 @@
3274 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3273 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3275 $ hg diff -r 'tip^^::tip'
3274 $ hg diff -r 'tip^^::tip'
3276 diff -r 2326846efdab -r 24286f4ae135 .hgtags
3275 diff -r 2326846efdab -r 24286f4ae135 .hgtags
3277 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3276 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3278 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
3277 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
3279 @@ -0,0 +1,1 @@
3278 @@ -0,0 +1,1 @@
3280 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3279 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3281
3280
3282 (single rev)
3281 (single rev)
3283
3282
3284 $ hg diff -r 'tip^' -r 'tip^'
3283 $ hg diff -r 'tip^' -r 'tip^'
3285 $ hg diff -r 'tip^:tip^'
3284 $ hg diff -r 'tip^:tip^'
3286
3285
3287 (single rev that does not looks like a range)
3286 (single rev that does not looks like a range)
3288
3287
3289 $ hg diff -r 'tip^::tip^ or tip^'
3288 $ hg diff -r 'tip^::tip^ or tip^'
3290 diff -r d5d0dcbdc4d9 .hgtags
3289 diff -r d5d0dcbdc4d9 .hgtags
3291 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3290 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3292 +++ b/.hgtags * (glob)
3291 +++ b/.hgtags * (glob)
3293 @@ -0,0 +1,1 @@
3292 @@ -0,0 +1,1 @@
3294 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3293 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3295 $ hg diff -r 'tip^ or tip^'
3294 $ hg diff -r 'tip^ or tip^'
3296 diff -r d5d0dcbdc4d9 .hgtags
3295 diff -r d5d0dcbdc4d9 .hgtags
3297 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3296 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3298 +++ b/.hgtags * (glob)
3297 +++ b/.hgtags * (glob)
3299 @@ -0,0 +1,1 @@
3298 @@ -0,0 +1,1 @@
3300 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3299 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3301
3300
3302 (no rev)
3301 (no rev)
3303
3302
3304 $ hg diff -r 'author("babar") or author("celeste")'
3303 $ hg diff -r 'author("babar") or author("celeste")'
3305 abort: empty revision range
3304 abort: empty revision range
3306 [255]
3305 [255]
3307
3306
3308 aliases:
3307 aliases:
3309
3308
3310 $ echo '[revsetalias]' >> .hg/hgrc
3309 $ echo '[revsetalias]' >> .hg/hgrc
3311 $ echo 'm = merge()' >> .hg/hgrc
3310 $ echo 'm = merge()' >> .hg/hgrc
3312 (revset aliases can override builtin revsets)
3311 (revset aliases can override builtin revsets)
3313 $ echo 'p2($1) = p1($1)' >> .hg/hgrc
3312 $ echo 'p2($1) = p1($1)' >> .hg/hgrc
3314 $ echo 'sincem = descendants(m)' >> .hg/hgrc
3313 $ echo 'sincem = descendants(m)' >> .hg/hgrc
3315 $ echo 'd($1) = reverse(sort($1, date))' >> .hg/hgrc
3314 $ echo 'd($1) = reverse(sort($1, date))' >> .hg/hgrc
3316 $ echo 'rs(ARG1, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
3315 $ echo 'rs(ARG1, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
3317 $ echo 'rs4(ARG1, ARGA, ARGB, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
3316 $ echo 'rs4(ARG1, ARGA, ARGB, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
3318
3317
3319 $ try m
3318 $ try m
3320 ('symbol', 'm')
3319 ('symbol', 'm')
3321 * expanded:
3320 * expanded:
3322 (func
3321 (func
3323 ('symbol', 'merge')
3322 ('symbol', 'merge')
3324 None)
3323 None)
3325 * set:
3324 * set:
3326 <filteredset
3325 <filteredset
3327 <fullreposet+ 0:10>,
3326 <fullreposet+ 0:10>,
3328 <merge>>
3327 <merge>>
3329 6
3328 6
3330
3329
3331 $ HGPLAIN=1
3330 $ HGPLAIN=1
3332 $ export HGPLAIN
3331 $ export HGPLAIN
3333 $ try m
3332 $ try m
3334 ('symbol', 'm')
3333 ('symbol', 'm')
3335 abort: unknown revision 'm'!
3334 abort: unknown revision 'm'!
3336 [255]
3335 [255]
3337
3336
3338 $ HGPLAINEXCEPT=revsetalias
3337 $ HGPLAINEXCEPT=revsetalias
3339 $ export HGPLAINEXCEPT
3338 $ export HGPLAINEXCEPT
3340 $ try m
3339 $ try m
3341 ('symbol', 'm')
3340 ('symbol', 'm')
3342 * expanded:
3341 * expanded:
3343 (func
3342 (func
3344 ('symbol', 'merge')
3343 ('symbol', 'merge')
3345 None)
3344 None)
3346 * set:
3345 * set:
3347 <filteredset
3346 <filteredset
3348 <fullreposet+ 0:10>,
3347 <fullreposet+ 0:10>,
3349 <merge>>
3348 <merge>>
3350 6
3349 6
3351
3350
3352 $ unset HGPLAIN
3351 $ unset HGPLAIN
3353 $ unset HGPLAINEXCEPT
3352 $ unset HGPLAINEXCEPT
3354
3353
3355 $ try 'p2(.)'
3354 $ try 'p2(.)'
3356 (func
3355 (func
3357 ('symbol', 'p2')
3356 ('symbol', 'p2')
3358 ('symbol', '.'))
3357 ('symbol', '.'))
3359 * expanded:
3358 * expanded:
3360 (func
3359 (func
3361 ('symbol', 'p1')
3360 ('symbol', 'p1')
3362 ('symbol', '.'))
3361 ('symbol', '.'))
3363 * set:
3362 * set:
3364 <baseset+ [8]>
3363 <baseset+ [8]>
3365 8
3364 8
3366
3365
3367 $ HGPLAIN=1
3366 $ HGPLAIN=1
3368 $ export HGPLAIN
3367 $ export HGPLAIN
3369 $ try 'p2(.)'
3368 $ try 'p2(.)'
3370 (func
3369 (func
3371 ('symbol', 'p2')
3370 ('symbol', 'p2')
3372 ('symbol', '.'))
3371 ('symbol', '.'))
3373 * set:
3372 * set:
3374 <baseset+ []>
3373 <baseset+ []>
3375
3374
3376 $ HGPLAINEXCEPT=revsetalias
3375 $ HGPLAINEXCEPT=revsetalias
3377 $ export HGPLAINEXCEPT
3376 $ export HGPLAINEXCEPT
3378 $ try 'p2(.)'
3377 $ try 'p2(.)'
3379 (func
3378 (func
3380 ('symbol', 'p2')
3379 ('symbol', 'p2')
3381 ('symbol', '.'))
3380 ('symbol', '.'))
3382 * expanded:
3381 * expanded:
3383 (func
3382 (func
3384 ('symbol', 'p1')
3383 ('symbol', 'p1')
3385 ('symbol', '.'))
3384 ('symbol', '.'))
3386 * set:
3385 * set:
3387 <baseset+ [8]>
3386 <baseset+ [8]>
3388 8
3387 8
3389
3388
3390 $ unset HGPLAIN
3389 $ unset HGPLAIN
3391 $ unset HGPLAINEXCEPT
3390 $ unset HGPLAINEXCEPT
3392
3391
3393 test alias recursion
3392 test alias recursion
3394
3393
3395 $ try sincem
3394 $ try sincem
3396 ('symbol', 'sincem')
3395 ('symbol', 'sincem')
3397 * expanded:
3396 * expanded:
3398 (func
3397 (func
3399 ('symbol', 'descendants')
3398 ('symbol', 'descendants')
3400 (func
3399 (func
3401 ('symbol', 'merge')
3400 ('symbol', 'merge')
3402 None))
3401 None))
3403 * set:
3402 * set:
3404 <addset+
3403 <addset+
3405 <filteredset
3404 <filteredset
3406 <fullreposet+ 0:10>,
3405 <fullreposet+ 0:10>,
3407 <merge>>,
3406 <merge>>,
3408 <generatorset+>>
3407 <generatorset+>>
3409 6
3408 6
3410 7
3409 7
3411
3410
3412 test infinite recursion
3411 test infinite recursion
3413
3412
3414 $ echo 'recurse1 = recurse2' >> .hg/hgrc
3413 $ echo 'recurse1 = recurse2' >> .hg/hgrc
3415 $ echo 'recurse2 = recurse1' >> .hg/hgrc
3414 $ echo 'recurse2 = recurse1' >> .hg/hgrc
3416 $ try recurse1
3415 $ try recurse1
3417 ('symbol', 'recurse1')
3416 ('symbol', 'recurse1')
3418 hg: parse error: infinite expansion of revset alias "recurse1" detected
3417 hg: parse error: infinite expansion of revset alias "recurse1" detected
3419 [255]
3418 [255]
3420
3419
3421 $ echo 'level1($1, $2) = $1 or $2' >> .hg/hgrc
3420 $ echo 'level1($1, $2) = $1 or $2' >> .hg/hgrc
3422 $ echo 'level2($1, $2) = level1($2, $1)' >> .hg/hgrc
3421 $ echo 'level2($1, $2) = level1($2, $1)' >> .hg/hgrc
3423 $ try "level2(level1(1, 2), 3)"
3422 $ try "level2(level1(1, 2), 3)"
3424 (func
3423 (func
3425 ('symbol', 'level2')
3424 ('symbol', 'level2')
3426 (list
3425 (list
3427 (func
3426 (func
3428 ('symbol', 'level1')
3427 ('symbol', 'level1')
3429 (list
3428 (list
3430 ('symbol', '1')
3429 ('symbol', '1')
3431 ('symbol', '2')))
3430 ('symbol', '2')))
3432 ('symbol', '3')))
3431 ('symbol', '3')))
3433 * expanded:
3432 * expanded:
3434 (or
3433 (or
3435 (list
3434 (list
3436 ('symbol', '3')
3435 ('symbol', '3')
3437 (or
3436 (or
3438 (list
3437 (list
3439 ('symbol', '1')
3438 ('symbol', '1')
3440 ('symbol', '2')))))
3439 ('symbol', '2')))))
3441 * set:
3440 * set:
3442 <addset
3441 <addset
3443 <baseset [3]>,
3442 <baseset [3]>,
3444 <baseset [1, 2]>>
3443 <baseset [1, 2]>>
3445 3
3444 3
3446 1
3445 1
3447 2
3446 2
3448
3447
3449 test nesting and variable passing
3448 test nesting and variable passing
3450
3449
3451 $ echo 'nested($1) = nested2($1)' >> .hg/hgrc
3450 $ echo 'nested($1) = nested2($1)' >> .hg/hgrc
3452 $ echo 'nested2($1) = nested3($1)' >> .hg/hgrc
3451 $ echo 'nested2($1) = nested3($1)' >> .hg/hgrc
3453 $ echo 'nested3($1) = max($1)' >> .hg/hgrc
3452 $ echo 'nested3($1) = max($1)' >> .hg/hgrc
3454 $ try 'nested(2:5)'
3453 $ try 'nested(2:5)'
3455 (func
3454 (func
3456 ('symbol', 'nested')
3455 ('symbol', 'nested')
3457 (range
3456 (range
3458 ('symbol', '2')
3457 ('symbol', '2')
3459 ('symbol', '5')))
3458 ('symbol', '5')))
3460 * expanded:
3459 * expanded:
3461 (func
3460 (func
3462 ('symbol', 'max')
3461 ('symbol', 'max')
3463 (range
3462 (range
3464 ('symbol', '2')
3463 ('symbol', '2')
3465 ('symbol', '5')))
3464 ('symbol', '5')))
3466 * set:
3465 * set:
3467 <baseset
3466 <baseset
3468 <max
3467 <max
3469 <fullreposet+ 0:10>,
3468 <fullreposet+ 0:10>,
3470 <spanset+ 2:6>>>
3469 <spanset+ 2:6>>>
3471 5
3470 5
3472
3471
3473 test chained `or` operations are flattened at parsing phase
3472 test chained `or` operations are flattened at parsing phase
3474
3473
3475 $ echo 'chainedorops($1, $2, $3) = $1|$2|$3' >> .hg/hgrc
3474 $ echo 'chainedorops($1, $2, $3) = $1|$2|$3' >> .hg/hgrc
3476 $ try 'chainedorops(0:1, 1:2, 2:3)'
3475 $ try 'chainedorops(0:1, 1:2, 2:3)'
3477 (func
3476 (func
3478 ('symbol', 'chainedorops')
3477 ('symbol', 'chainedorops')
3479 (list
3478 (list
3480 (range
3479 (range
3481 ('symbol', '0')
3480 ('symbol', '0')
3482 ('symbol', '1'))
3481 ('symbol', '1'))
3483 (range
3482 (range
3484 ('symbol', '1')
3483 ('symbol', '1')
3485 ('symbol', '2'))
3484 ('symbol', '2'))
3486 (range
3485 (range
3487 ('symbol', '2')
3486 ('symbol', '2')
3488 ('symbol', '3'))))
3487 ('symbol', '3'))))
3489 * expanded:
3488 * expanded:
3490 (or
3489 (or
3491 (list
3490 (list
3492 (range
3491 (range
3493 ('symbol', '0')
3492 ('symbol', '0')
3494 ('symbol', '1'))
3493 ('symbol', '1'))
3495 (range
3494 (range
3496 ('symbol', '1')
3495 ('symbol', '1')
3497 ('symbol', '2'))
3496 ('symbol', '2'))
3498 (range
3497 (range
3499 ('symbol', '2')
3498 ('symbol', '2')
3500 ('symbol', '3'))))
3499 ('symbol', '3'))))
3501 * set:
3500 * set:
3502 <addset
3501 <addset
3503 <spanset+ 0:2>,
3502 <spanset+ 0:2>,
3504 <addset
3503 <addset
3505 <spanset+ 1:3>,
3504 <spanset+ 1:3>,
3506 <spanset+ 2:4>>>
3505 <spanset+ 2:4>>>
3507 0
3506 0
3508 1
3507 1
3509 2
3508 2
3510 3
3509 3
3511
3510
3512 test variable isolation, variable placeholders are rewritten as string
3511 test variable isolation, variable placeholders are rewritten as string
3513 then parsed and matched again as string. Check they do not leak too
3512 then parsed and matched again as string. Check they do not leak too
3514 far away.
3513 far away.
3515
3514
3516 $ echo 'injectparamasstring = max("$1")' >> .hg/hgrc
3515 $ echo 'injectparamasstring = max("$1")' >> .hg/hgrc
3517 $ echo 'callinjection($1) = descendants(injectparamasstring)' >> .hg/hgrc
3516 $ echo 'callinjection($1) = descendants(injectparamasstring)' >> .hg/hgrc
3518 $ try 'callinjection(2:5)'
3517 $ try 'callinjection(2:5)'
3519 (func
3518 (func
3520 ('symbol', 'callinjection')
3519 ('symbol', 'callinjection')
3521 (range
3520 (range
3522 ('symbol', '2')
3521 ('symbol', '2')
3523 ('symbol', '5')))
3522 ('symbol', '5')))
3524 * expanded:
3523 * expanded:
3525 (func
3524 (func
3526 ('symbol', 'descendants')
3525 ('symbol', 'descendants')
3527 (func
3526 (func
3528 ('symbol', 'max')
3527 ('symbol', 'max')
3529 ('string', '$1')))
3528 ('string', '$1')))
3530 abort: unknown revision '$1'!
3529 abort: unknown revision '$1'!
3531 [255]
3530 [255]
3532
3531
3533 test scope of alias expansion: 'universe' is expanded prior to 'shadowall(0)',
3532 test scope of alias expansion: 'universe' is expanded prior to 'shadowall(0)',
3534 but 'all()' should never be substituted to '0()'.
3533 but 'all()' should never be substituted to '0()'.
3535
3534
3536 $ echo 'universe = all()' >> .hg/hgrc
3535 $ echo 'universe = all()' >> .hg/hgrc
3537 $ echo 'shadowall(all) = all and universe' >> .hg/hgrc
3536 $ echo 'shadowall(all) = all and universe' >> .hg/hgrc
3538 $ try 'shadowall(0)'
3537 $ try 'shadowall(0)'
3539 (func
3538 (func
3540 ('symbol', 'shadowall')
3539 ('symbol', 'shadowall')
3541 ('symbol', '0'))
3540 ('symbol', '0'))
3542 * expanded:
3541 * expanded:
3543 (and
3542 (and
3544 ('symbol', '0')
3543 ('symbol', '0')
3545 (func
3544 (func
3546 ('symbol', 'all')
3545 ('symbol', 'all')
3547 None))
3546 None))
3548 * set:
3547 * set:
3549 <filteredset
3548 <filteredset
3550 <baseset [0]>,
3549 <baseset [0]>,
3551 <spanset+ 0:10>>
3550 <spanset+ 0:10>>
3552 0
3551 0
3553
3552
3554 test unknown reference:
3553 test unknown reference:
3555
3554
3556 $ try "unknownref(0)" --config 'revsetalias.unknownref($1)=$1:$2'
3555 $ try "unknownref(0)" --config 'revsetalias.unknownref($1)=$1:$2'
3557 (func
3556 (func
3558 ('symbol', 'unknownref')
3557 ('symbol', 'unknownref')
3559 ('symbol', '0'))
3558 ('symbol', '0'))
3560 abort: bad definition of revset alias "unknownref": invalid symbol '$2'
3559 abort: bad definition of revset alias "unknownref": invalid symbol '$2'
3561 [255]
3560 [255]
3562
3561
3563 $ hg debugrevspec --debug --config revsetalias.anotherbadone='branch(' "tip"
3562 $ hg debugrevspec --debug --config revsetalias.anotherbadone='branch(' "tip"
3564 ('symbol', 'tip')
3563 ('symbol', 'tip')
3565 warning: bad definition of revset alias "anotherbadone": at 7: not a prefix: end
3564 warning: bad definition of revset alias "anotherbadone": at 7: not a prefix: end
3566 * set:
3565 * set:
3567 <baseset [9]>
3566 <baseset [9]>
3568 9
3567 9
3569
3568
3570 $ try 'tip'
3569 $ try 'tip'
3571 ('symbol', 'tip')
3570 ('symbol', 'tip')
3572 * set:
3571 * set:
3573 <baseset [9]>
3572 <baseset [9]>
3574 9
3573 9
3575
3574
3576 $ hg debugrevspec --debug --config revsetalias.'bad name'='tip' "tip"
3575 $ hg debugrevspec --debug --config revsetalias.'bad name'='tip' "tip"
3577 ('symbol', 'tip')
3576 ('symbol', 'tip')
3578 warning: bad declaration of revset alias "bad name": at 4: invalid token
3577 warning: bad declaration of revset alias "bad name": at 4: invalid token
3579 * set:
3578 * set:
3580 <baseset [9]>
3579 <baseset [9]>
3581 9
3580 9
3582 $ echo 'strictreplacing($1, $10) = $10 or desc("$1")' >> .hg/hgrc
3581 $ echo 'strictreplacing($1, $10) = $10 or desc("$1")' >> .hg/hgrc
3583 $ try 'strictreplacing("foo", tip)'
3582 $ try 'strictreplacing("foo", tip)'
3584 (func
3583 (func
3585 ('symbol', 'strictreplacing')
3584 ('symbol', 'strictreplacing')
3586 (list
3585 (list
3587 ('string', 'foo')
3586 ('string', 'foo')
3588 ('symbol', 'tip')))
3587 ('symbol', 'tip')))
3589 * expanded:
3588 * expanded:
3590 (or
3589 (or
3591 (list
3590 (list
3592 ('symbol', 'tip')
3591 ('symbol', 'tip')
3593 (func
3592 (func
3594 ('symbol', 'desc')
3593 ('symbol', 'desc')
3595 ('string', '$1'))))
3594 ('string', '$1'))))
3596 * set:
3595 * set:
3597 <addset
3596 <addset
3598 <baseset [9]>,
3597 <baseset [9]>,
3599 <filteredset
3598 <filteredset
3600 <fullreposet+ 0:10>,
3599 <fullreposet+ 0:10>,
3601 <desc '$1'>>>
3600 <desc '$1'>>>
3602 9
3601 9
3603
3602
3604 $ try 'd(2:5)'
3603 $ try 'd(2:5)'
3605 (func
3604 (func
3606 ('symbol', 'd')
3605 ('symbol', 'd')
3607 (range
3606 (range
3608 ('symbol', '2')
3607 ('symbol', '2')
3609 ('symbol', '5')))
3608 ('symbol', '5')))
3610 * expanded:
3609 * expanded:
3611 (func
3610 (func
3612 ('symbol', 'reverse')
3611 ('symbol', 'reverse')
3613 (func
3612 (func
3614 ('symbol', 'sort')
3613 ('symbol', 'sort')
3615 (list
3614 (list
3616 (range
3615 (range
3617 ('symbol', '2')
3616 ('symbol', '2')
3618 ('symbol', '5'))
3617 ('symbol', '5'))
3619 ('symbol', 'date'))))
3618 ('symbol', 'date'))))
3620 * set:
3619 * set:
3621 <baseset [4, 5, 3, 2]>
3620 <baseset [4, 5, 3, 2]>
3622 4
3621 4
3623 5
3622 5
3624 3
3623 3
3625 2
3624 2
3626 $ try 'rs(2 or 3, date)'
3625 $ try 'rs(2 or 3, date)'
3627 (func
3626 (func
3628 ('symbol', 'rs')
3627 ('symbol', 'rs')
3629 (list
3628 (list
3630 (or
3629 (or
3631 (list
3630 (list
3632 ('symbol', '2')
3631 ('symbol', '2')
3633 ('symbol', '3')))
3632 ('symbol', '3')))
3634 ('symbol', 'date')))
3633 ('symbol', 'date')))
3635 * expanded:
3634 * expanded:
3636 (func
3635 (func
3637 ('symbol', 'reverse')
3636 ('symbol', 'reverse')
3638 (func
3637 (func
3639 ('symbol', 'sort')
3638 ('symbol', 'sort')
3640 (list
3639 (list
3641 (or
3640 (or
3642 (list
3641 (list
3643 ('symbol', '2')
3642 ('symbol', '2')
3644 ('symbol', '3')))
3643 ('symbol', '3')))
3645 ('symbol', 'date'))))
3644 ('symbol', 'date'))))
3646 * set:
3645 * set:
3647 <baseset [3, 2]>
3646 <baseset [3, 2]>
3648 3
3647 3
3649 2
3648 2
3650 $ try 'rs()'
3649 $ try 'rs()'
3651 (func
3650 (func
3652 ('symbol', 'rs')
3651 ('symbol', 'rs')
3653 None)
3652 None)
3654 hg: parse error: invalid number of arguments: 0
3653 hg: parse error: invalid number of arguments: 0
3655 [255]
3654 [255]
3656 $ try 'rs(2)'
3655 $ try 'rs(2)'
3657 (func
3656 (func
3658 ('symbol', 'rs')
3657 ('symbol', 'rs')
3659 ('symbol', '2'))
3658 ('symbol', '2'))
3660 hg: parse error: invalid number of arguments: 1
3659 hg: parse error: invalid number of arguments: 1
3661 [255]
3660 [255]
3662 $ try 'rs(2, data, 7)'
3661 $ try 'rs(2, data, 7)'
3663 (func
3662 (func
3664 ('symbol', 'rs')
3663 ('symbol', 'rs')
3665 (list
3664 (list
3666 ('symbol', '2')
3665 ('symbol', '2')
3667 ('symbol', 'data')
3666 ('symbol', 'data')
3668 ('symbol', '7')))
3667 ('symbol', '7')))
3669 hg: parse error: invalid number of arguments: 3
3668 hg: parse error: invalid number of arguments: 3
3670 [255]
3669 [255]
3671 $ try 'rs4(2 or 3, x, x, date)'
3670 $ try 'rs4(2 or 3, x, x, date)'
3672 (func
3671 (func
3673 ('symbol', 'rs4')
3672 ('symbol', 'rs4')
3674 (list
3673 (list
3675 (or
3674 (or
3676 (list
3675 (list
3677 ('symbol', '2')
3676 ('symbol', '2')
3678 ('symbol', '3')))
3677 ('symbol', '3')))
3679 ('symbol', 'x')
3678 ('symbol', 'x')
3680 ('symbol', 'x')
3679 ('symbol', 'x')
3681 ('symbol', 'date')))
3680 ('symbol', 'date')))
3682 * expanded:
3681 * expanded:
3683 (func
3682 (func
3684 ('symbol', 'reverse')
3683 ('symbol', 'reverse')
3685 (func
3684 (func
3686 ('symbol', 'sort')
3685 ('symbol', 'sort')
3687 (list
3686 (list
3688 (or
3687 (or
3689 (list
3688 (list
3690 ('symbol', '2')
3689 ('symbol', '2')
3691 ('symbol', '3')))
3690 ('symbol', '3')))
3692 ('symbol', 'date'))))
3691 ('symbol', 'date'))))
3693 * set:
3692 * set:
3694 <baseset [3, 2]>
3693 <baseset [3, 2]>
3695 3
3694 3
3696 2
3695 2
3697
3696
3698 issue4553: check that revset aliases override existing hash prefix
3697 issue4553: check that revset aliases override existing hash prefix
3699
3698
3700 $ hg log -qr e
3699 $ hg log -qr e
3701 6:e0cc66ef77e8
3700 6:e0cc66ef77e8
3702
3701
3703 $ hg log -qr e --config revsetalias.e="all()"
3702 $ hg log -qr e --config revsetalias.e="all()"
3704 0:2785f51eece5
3703 0:2785f51eece5
3705 1:d75937da8da0
3704 1:d75937da8da0
3706 2:5ed5505e9f1c
3705 2:5ed5505e9f1c
3707 3:8528aa5637f2
3706 3:8528aa5637f2
3708 4:2326846efdab
3707 4:2326846efdab
3709 5:904fa392b941
3708 5:904fa392b941
3710 6:e0cc66ef77e8
3709 6:e0cc66ef77e8
3711 7:013af1973af4
3710 7:013af1973af4
3712 8:d5d0dcbdc4d9
3711 8:d5d0dcbdc4d9
3713 9:24286f4ae135
3712 9:24286f4ae135
3714
3713
3715 $ hg log -qr e: --config revsetalias.e="0"
3714 $ hg log -qr e: --config revsetalias.e="0"
3716 0:2785f51eece5
3715 0:2785f51eece5
3717 1:d75937da8da0
3716 1:d75937da8da0
3718 2:5ed5505e9f1c
3717 2:5ed5505e9f1c
3719 3:8528aa5637f2
3718 3:8528aa5637f2
3720 4:2326846efdab
3719 4:2326846efdab
3721 5:904fa392b941
3720 5:904fa392b941
3722 6:e0cc66ef77e8
3721 6:e0cc66ef77e8
3723 7:013af1973af4
3722 7:013af1973af4
3724 8:d5d0dcbdc4d9
3723 8:d5d0dcbdc4d9
3725 9:24286f4ae135
3724 9:24286f4ae135
3726
3725
3727 $ hg log -qr :e --config revsetalias.e="9"
3726 $ hg log -qr :e --config revsetalias.e="9"
3728 0:2785f51eece5
3727 0:2785f51eece5
3729 1:d75937da8da0
3728 1:d75937da8da0
3730 2:5ed5505e9f1c
3729 2:5ed5505e9f1c
3731 3:8528aa5637f2
3730 3:8528aa5637f2
3732 4:2326846efdab
3731 4:2326846efdab
3733 5:904fa392b941
3732 5:904fa392b941
3734 6:e0cc66ef77e8
3733 6:e0cc66ef77e8
3735 7:013af1973af4
3734 7:013af1973af4
3736 8:d5d0dcbdc4d9
3735 8:d5d0dcbdc4d9
3737 9:24286f4ae135
3736 9:24286f4ae135
3738
3737
3739 $ hg log -qr e:
3738 $ hg log -qr e:
3740 6:e0cc66ef77e8
3739 6:e0cc66ef77e8
3741 7:013af1973af4
3740 7:013af1973af4
3742 8:d5d0dcbdc4d9
3741 8:d5d0dcbdc4d9
3743 9:24286f4ae135
3742 9:24286f4ae135
3744
3743
3745 $ hg log -qr :e
3744 $ hg log -qr :e
3746 0:2785f51eece5
3745 0:2785f51eece5
3747 1:d75937da8da0
3746 1:d75937da8da0
3748 2:5ed5505e9f1c
3747 2:5ed5505e9f1c
3749 3:8528aa5637f2
3748 3:8528aa5637f2
3750 4:2326846efdab
3749 4:2326846efdab
3751 5:904fa392b941
3750 5:904fa392b941
3752 6:e0cc66ef77e8
3751 6:e0cc66ef77e8
3753
3752
3754 issue2549 - correct optimizations
3753 issue2549 - correct optimizations
3755
3754
3756 $ try 'limit(1 or 2 or 3, 2) and not 2'
3755 $ try 'limit(1 or 2 or 3, 2) and not 2'
3757 (and
3756 (and
3758 (func
3757 (func
3759 ('symbol', 'limit')
3758 ('symbol', 'limit')
3760 (list
3759 (list
3761 (or
3760 (or
3762 (list
3761 (list
3763 ('symbol', '1')
3762 ('symbol', '1')
3764 ('symbol', '2')
3763 ('symbol', '2')
3765 ('symbol', '3')))
3764 ('symbol', '3')))
3766 ('symbol', '2')))
3765 ('symbol', '2')))
3767 (not
3766 (not
3768 ('symbol', '2')))
3767 ('symbol', '2')))
3769 * set:
3768 * set:
3770 <filteredset
3769 <filteredset
3771 <baseset [1, 2]>,
3770 <baseset [1, 2]>,
3772 <not
3771 <not
3773 <baseset [2]>>>
3772 <baseset [2]>>>
3774 1
3773 1
3775 $ try 'max(1 or 2) and not 2'
3774 $ try 'max(1 or 2) and not 2'
3776 (and
3775 (and
3777 (func
3776 (func
3778 ('symbol', 'max')
3777 ('symbol', 'max')
3779 (or
3778 (or
3780 (list
3779 (list
3781 ('symbol', '1')
3780 ('symbol', '1')
3782 ('symbol', '2'))))
3781 ('symbol', '2'))))
3783 (not
3782 (not
3784 ('symbol', '2')))
3783 ('symbol', '2')))
3785 * set:
3784 * set:
3786 <filteredset
3785 <filteredset
3787 <baseset
3786 <baseset
3788 <max
3787 <max
3789 <fullreposet+ 0:10>,
3788 <fullreposet+ 0:10>,
3790 <baseset [1, 2]>>>,
3789 <baseset [1, 2]>>>,
3791 <not
3790 <not
3792 <baseset [2]>>>
3791 <baseset [2]>>>
3793 $ try 'min(1 or 2) and not 1'
3792 $ try 'min(1 or 2) and not 1'
3794 (and
3793 (and
3795 (func
3794 (func
3796 ('symbol', 'min')
3795 ('symbol', 'min')
3797 (or
3796 (or
3798 (list
3797 (list
3799 ('symbol', '1')
3798 ('symbol', '1')
3800 ('symbol', '2'))))
3799 ('symbol', '2'))))
3801 (not
3800 (not
3802 ('symbol', '1')))
3801 ('symbol', '1')))
3803 * set:
3802 * set:
3804 <filteredset
3803 <filteredset
3805 <baseset
3804 <baseset
3806 <min
3805 <min
3807 <fullreposet+ 0:10>,
3806 <fullreposet+ 0:10>,
3808 <baseset [1, 2]>>>,
3807 <baseset [1, 2]>>>,
3809 <not
3808 <not
3810 <baseset [1]>>>
3809 <baseset [1]>>>
3811 $ try 'last(1 or 2, 1) and not 2'
3810 $ try 'last(1 or 2, 1) and not 2'
3812 (and
3811 (and
3813 (func
3812 (func
3814 ('symbol', 'last')
3813 ('symbol', 'last')
3815 (list
3814 (list
3816 (or
3815 (or
3817 (list
3816 (list
3818 ('symbol', '1')
3817 ('symbol', '1')
3819 ('symbol', '2')))
3818 ('symbol', '2')))
3820 ('symbol', '1')))
3819 ('symbol', '1')))
3821 (not
3820 (not
3822 ('symbol', '2')))
3821 ('symbol', '2')))
3823 * set:
3822 * set:
3824 <filteredset
3823 <filteredset
3825 <baseset [2]>,
3824 <baseset [2]>,
3826 <not
3825 <not
3827 <baseset [2]>>>
3826 <baseset [2]>>>
3828
3827
3829 issue4289 - ordering of built-ins
3828 issue4289 - ordering of built-ins
3830 $ hg log -M -q -r 3:2
3829 $ hg log -M -q -r 3:2
3831 3:8528aa5637f2
3830 3:8528aa5637f2
3832 2:5ed5505e9f1c
3831 2:5ed5505e9f1c
3833
3832
3834 test revsets started with 40-chars hash (issue3669)
3833 test revsets started with 40-chars hash (issue3669)
3835
3834
3836 $ ISSUE3669_TIP=`hg tip --template '{node}'`
3835 $ ISSUE3669_TIP=`hg tip --template '{node}'`
3837 $ hg log -r "${ISSUE3669_TIP}" --template '{rev}\n'
3836 $ hg log -r "${ISSUE3669_TIP}" --template '{rev}\n'
3838 9
3837 9
3839 $ hg log -r "${ISSUE3669_TIP}^" --template '{rev}\n'
3838 $ hg log -r "${ISSUE3669_TIP}^" --template '{rev}\n'
3840 8
3839 8
3841
3840
3842 test or-ed indirect predicates (issue3775)
3841 test or-ed indirect predicates (issue3775)
3843
3842
3844 $ log '6 or 6^1' | sort
3843 $ log '6 or 6^1' | sort
3845 5
3844 5
3846 6
3845 6
3847 $ log '6^1 or 6' | sort
3846 $ log '6^1 or 6' | sort
3848 5
3847 5
3849 6
3848 6
3850 $ log '4 or 4~1' | sort
3849 $ log '4 or 4~1' | sort
3851 2
3850 2
3852 4
3851 4
3853 $ log '4~1 or 4' | sort
3852 $ log '4~1 or 4' | sort
3854 2
3853 2
3855 4
3854 4
3856 $ log '(0 or 2):(4 or 6) or 0 or 6' | sort
3855 $ log '(0 or 2):(4 or 6) or 0 or 6' | sort
3857 0
3856 0
3858 1
3857 1
3859 2
3858 2
3860 3
3859 3
3861 4
3860 4
3862 5
3861 5
3863 6
3862 6
3864 $ log '0 or 6 or (0 or 2):(4 or 6)' | sort
3863 $ log '0 or 6 or (0 or 2):(4 or 6)' | sort
3865 0
3864 0
3866 1
3865 1
3867 2
3866 2
3868 3
3867 3
3869 4
3868 4
3870 5
3869 5
3871 6
3870 6
3872
3871
3873 tests for 'remote()' predicate:
3872 tests for 'remote()' predicate:
3874 #. (csets in remote) (id) (remote)
3873 #. (csets in remote) (id) (remote)
3875 1. less than local current branch "default"
3874 1. less than local current branch "default"
3876 2. same with local specified "default"
3875 2. same with local specified "default"
3877 3. more than local specified specified
3876 3. more than local specified specified
3878
3877
3879 $ hg clone --quiet -U . ../remote3
3878 $ hg clone --quiet -U . ../remote3
3880 $ cd ../remote3
3879 $ cd ../remote3
3881 $ hg update -q 7
3880 $ hg update -q 7
3882 $ echo r > r
3881 $ echo r > r
3883 $ hg ci -Aqm 10
3882 $ hg ci -Aqm 10
3884 $ log 'remote()'
3883 $ log 'remote()'
3885 7
3884 7
3886 $ log 'remote("a-b-c-")'
3885 $ log 'remote("a-b-c-")'
3887 2
3886 2
3888 $ cd ../repo
3887 $ cd ../repo
3889 $ log 'remote(".a.b.c.", "../remote3")'
3888 $ log 'remote(".a.b.c.", "../remote3")'
3890
3889
3891 tests for concatenation of strings/symbols by "##"
3890 tests for concatenation of strings/symbols by "##"
3892
3891
3893 $ try "278 ## '5f5' ## 1ee ## 'ce5'"
3892 $ try "278 ## '5f5' ## 1ee ## 'ce5'"
3894 (_concat
3893 (_concat
3895 (_concat
3894 (_concat
3896 (_concat
3895 (_concat
3897 ('symbol', '278')
3896 ('symbol', '278')
3898 ('string', '5f5'))
3897 ('string', '5f5'))
3899 ('symbol', '1ee'))
3898 ('symbol', '1ee'))
3900 ('string', 'ce5'))
3899 ('string', 'ce5'))
3901 * concatenated:
3900 * concatenated:
3902 ('string', '2785f51eece5')
3901 ('string', '2785f51eece5')
3903 * set:
3902 * set:
3904 <baseset [0]>
3903 <baseset [0]>
3905 0
3904 0
3906
3905
3907 $ echo 'cat4($1, $2, $3, $4) = $1 ## $2 ## $3 ## $4' >> .hg/hgrc
3906 $ echo 'cat4($1, $2, $3, $4) = $1 ## $2 ## $3 ## $4' >> .hg/hgrc
3908 $ try "cat4(278, '5f5', 1ee, 'ce5')"
3907 $ try "cat4(278, '5f5', 1ee, 'ce5')"
3909 (func
3908 (func
3910 ('symbol', 'cat4')
3909 ('symbol', 'cat4')
3911 (list
3910 (list
3912 ('symbol', '278')
3911 ('symbol', '278')
3913 ('string', '5f5')
3912 ('string', '5f5')
3914 ('symbol', '1ee')
3913 ('symbol', '1ee')
3915 ('string', 'ce5')))
3914 ('string', 'ce5')))
3916 * expanded:
3915 * expanded:
3917 (_concat
3916 (_concat
3918 (_concat
3917 (_concat
3919 (_concat
3918 (_concat
3920 ('symbol', '278')
3919 ('symbol', '278')
3921 ('string', '5f5'))
3920 ('string', '5f5'))
3922 ('symbol', '1ee'))
3921 ('symbol', '1ee'))
3923 ('string', 'ce5'))
3922 ('string', 'ce5'))
3924 * concatenated:
3923 * concatenated:
3925 ('string', '2785f51eece5')
3924 ('string', '2785f51eece5')
3926 * set:
3925 * set:
3927 <baseset [0]>
3926 <baseset [0]>
3928 0
3927 0
3929
3928
3930 (check concatenation in alias nesting)
3929 (check concatenation in alias nesting)
3931
3930
3932 $ echo 'cat2($1, $2) = $1 ## $2' >> .hg/hgrc
3931 $ echo 'cat2($1, $2) = $1 ## $2' >> .hg/hgrc
3933 $ echo 'cat2x2($1, $2, $3, $4) = cat2($1 ## $2, $3 ## $4)' >> .hg/hgrc
3932 $ echo 'cat2x2($1, $2, $3, $4) = cat2($1 ## $2, $3 ## $4)' >> .hg/hgrc
3934 $ log "cat2x2(278, '5f5', 1ee, 'ce5')"
3933 $ log "cat2x2(278, '5f5', 1ee, 'ce5')"
3935 0
3934 0
3936
3935
3937 (check operator priority)
3936 (check operator priority)
3938
3937
3939 $ echo 'cat2n2($1, $2, $3, $4) = $1 ## $2 or $3 ## $4~2' >> .hg/hgrc
3938 $ echo 'cat2n2($1, $2, $3, $4) = $1 ## $2 or $3 ## $4~2' >> .hg/hgrc
3940 $ log "cat2n2(2785f5, 1eece5, 24286f, 4ae135)"
3939 $ log "cat2n2(2785f5, 1eece5, 24286f, 4ae135)"
3941 0
3940 0
3942 4
3941 4
3943
3942
3944 $ cd ..
3943 $ cd ..
3945
3944
3946 prepare repository that has "default" branches of multiple roots
3945 prepare repository that has "default" branches of multiple roots
3947
3946
3948 $ hg init namedbranch
3947 $ hg init namedbranch
3949 $ cd namedbranch
3948 $ cd namedbranch
3950
3949
3951 $ echo default0 >> a
3950 $ echo default0 >> a
3952 $ hg ci -Aqm0
3951 $ hg ci -Aqm0
3953 $ echo default1 >> a
3952 $ echo default1 >> a
3954 $ hg ci -m1
3953 $ hg ci -m1
3955
3954
3956 $ hg branch -q stable
3955 $ hg branch -q stable
3957 $ echo stable2 >> a
3956 $ echo stable2 >> a
3958 $ hg ci -m2
3957 $ hg ci -m2
3959 $ echo stable3 >> a
3958 $ echo stable3 >> a
3960 $ hg ci -m3
3959 $ hg ci -m3
3961
3960
3962 $ hg update -q null
3961 $ hg update -q null
3963 $ echo default4 >> a
3962 $ echo default4 >> a
3964 $ hg ci -Aqm4
3963 $ hg ci -Aqm4
3965 $ echo default5 >> a
3964 $ echo default5 >> a
3966 $ hg ci -m5
3965 $ hg ci -m5
3967
3966
3968 "null" revision belongs to "default" branch (issue4683)
3967 "null" revision belongs to "default" branch (issue4683)
3969
3968
3970 $ log 'branch(null)'
3969 $ log 'branch(null)'
3971 0
3970 0
3972 1
3971 1
3973 4
3972 4
3974 5
3973 5
3975
3974
3976 "null" revision belongs to "default" branch, but it shouldn't appear in set
3975 "null" revision belongs to "default" branch, but it shouldn't appear in set
3977 unless explicitly specified (issue4682)
3976 unless explicitly specified (issue4682)
3978
3977
3979 $ log 'children(branch(default))'
3978 $ log 'children(branch(default))'
3980 1
3979 1
3981 2
3980 2
3982 5
3981 5
3983
3982
3984 $ cd ..
3983 $ cd ..
3985
3984
3986 test author/desc/keyword in problematic encoding
3985 test author/desc/keyword in problematic encoding
3987 # unicode: cp932:
3986 # unicode: cp932:
3988 # u30A2 0x83 0x41(= 'A')
3987 # u30A2 0x83 0x41(= 'A')
3989 # u30C2 0x83 0x61(= 'a')
3988 # u30C2 0x83 0x61(= 'a')
3990
3989
3991 $ hg init problematicencoding
3990 $ hg init problematicencoding
3992 $ cd problematicencoding
3991 $ cd problematicencoding
3993
3992
3994 $ python > setup.sh <<EOF
3993 $ python > setup.sh <<EOF
3995 > print u'''
3994 > print u'''
3996 > echo a > text
3995 > echo a > text
3997 > hg add text
3996 > hg add text
3998 > hg --encoding utf-8 commit -u '\u30A2' -m none
3997 > hg --encoding utf-8 commit -u '\u30A2' -m none
3999 > echo b > text
3998 > echo b > text
4000 > hg --encoding utf-8 commit -u '\u30C2' -m none
3999 > hg --encoding utf-8 commit -u '\u30C2' -m none
4001 > echo c > text
4000 > echo c > text
4002 > hg --encoding utf-8 commit -u none -m '\u30A2'
4001 > hg --encoding utf-8 commit -u none -m '\u30A2'
4003 > echo d > text
4002 > echo d > text
4004 > hg --encoding utf-8 commit -u none -m '\u30C2'
4003 > hg --encoding utf-8 commit -u none -m '\u30C2'
4005 > '''.encode('utf-8')
4004 > '''.encode('utf-8')
4006 > EOF
4005 > EOF
4007 $ sh < setup.sh
4006 $ sh < setup.sh
4008
4007
4009 test in problematic encoding
4008 test in problematic encoding
4010 $ python > test.sh <<EOF
4009 $ python > test.sh <<EOF
4011 > print u'''
4010 > print u'''
4012 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30A2)'
4011 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30A2)'
4013 > echo ====
4012 > echo ====
4014 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30C2)'
4013 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30C2)'
4015 > echo ====
4014 > echo ====
4016 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30A2)'
4015 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30A2)'
4017 > echo ====
4016 > echo ====
4018 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30C2)'
4017 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30C2)'
4019 > echo ====
4018 > echo ====
4020 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30A2)'
4019 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30A2)'
4021 > echo ====
4020 > echo ====
4022 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30C2)'
4021 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30C2)'
4023 > '''.encode('cp932')
4022 > '''.encode('cp932')
4024 > EOF
4023 > EOF
4025 $ sh < test.sh
4024 $ sh < test.sh
4026 0
4025 0
4027 ====
4026 ====
4028 1
4027 1
4029 ====
4028 ====
4030 2
4029 2
4031 ====
4030 ====
4032 3
4031 3
4033 ====
4032 ====
4034 0
4033 0
4035 2
4034 2
4036 ====
4035 ====
4037 1
4036 1
4038 3
4037 3
4039
4038
4040 test error message of bad revset
4039 test error message of bad revset
4041 $ hg log -r 'foo\\'
4040 $ hg log -r 'foo\\'
4042 hg: parse error at 3: syntax error in revset 'foo\\'
4041 hg: parse error at 3: syntax error in revset 'foo\\'
4043 [255]
4042 [255]
4044
4043
4045 $ cd ..
4044 $ cd ..
4046
4045
4047 Test that revset predicate of extension isn't loaded at failure of
4046 Test that revset predicate of extension isn't loaded at failure of
4048 loading it
4047 loading it
4049
4048
4050 $ cd repo
4049 $ cd repo
4051
4050
4052 $ cat <<EOF > $TESTTMP/custompredicate.py
4051 $ cat <<EOF > $TESTTMP/custompredicate.py
4053 > from mercurial import error, registrar, revset
4052 > from mercurial import error, registrar, revset
4054 >
4053 >
4055 > revsetpredicate = registrar.revsetpredicate()
4054 > revsetpredicate = registrar.revsetpredicate()
4056 >
4055 >
4057 > @revsetpredicate('custom1()')
4056 > @revsetpredicate('custom1()')
4058 > def custom1(repo, subset, x):
4057 > def custom1(repo, subset, x):
4059 > return revset.baseset([1])
4058 > return revset.baseset([1])
4060 >
4059 >
4061 > raise error.Abort('intentional failure of loading extension')
4060 > raise error.Abort('intentional failure of loading extension')
4062 > EOF
4061 > EOF
4063 $ cat <<EOF > .hg/hgrc
4062 $ cat <<EOF > .hg/hgrc
4064 > [extensions]
4063 > [extensions]
4065 > custompredicate = $TESTTMP/custompredicate.py
4064 > custompredicate = $TESTTMP/custompredicate.py
4066 > EOF
4065 > EOF
4067
4066
4068 $ hg debugrevspec "custom1()"
4067 $ hg debugrevspec "custom1()"
4069 *** failed to import extension custompredicate from $TESTTMP/custompredicate.py: intentional failure of loading extension
4068 *** failed to import extension custompredicate from $TESTTMP/custompredicate.py: intentional failure of loading extension
4070 hg: parse error: unknown identifier: custom1
4069 hg: parse error: unknown identifier: custom1
4071 [255]
4070 [255]
4072
4071
4073 $ cd ..
4072 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now