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