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