##// END OF EJS Templates
reachableroots: use baseset lazy sorting...
Pierre-Yves David -
r26061:be8a4e08 default
parent child Browse files
Show More
@@ -1,408 +1,410
1 1 # changelog.py - changelog class for mercurial
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 from .i18n import _
11 11 from .node import (
12 12 bin,
13 13 hex,
14 14 nullid,
15 15 )
16 16
17 17 from . import (
18 18 encoding,
19 19 error,
20 20 revlog,
21 21 revset,
22 22 util,
23 23 )
24 24
25 25 _defaultextra = {'branch': 'default'}
26 26
27 27 def _string_escape(text):
28 28 """
29 29 >>> d = {'nl': chr(10), 'bs': chr(92), 'cr': chr(13), 'nul': chr(0)}
30 30 >>> s = "ab%(nl)scd%(bs)s%(bs)sn%(nul)sab%(cr)scd%(bs)s%(nl)s" % d
31 31 >>> s
32 32 'ab\\ncd\\\\\\\\n\\x00ab\\rcd\\\\\\n'
33 33 >>> res = _string_escape(s)
34 34 >>> s == res.decode('string_escape')
35 35 True
36 36 """
37 37 # subset of the string_escape codec
38 38 text = text.replace('\\', '\\\\').replace('\n', '\\n').replace('\r', '\\r')
39 39 return text.replace('\0', '\\0')
40 40
41 41 def decodeextra(text):
42 42 """
43 43 >>> sorted(decodeextra(encodeextra({'foo': 'bar', 'baz': chr(0) + '2'})
44 44 ... ).iteritems())
45 45 [('baz', '\\x002'), ('branch', 'default'), ('foo', 'bar')]
46 46 >>> sorted(decodeextra(encodeextra({'foo': 'bar',
47 47 ... 'baz': chr(92) + chr(0) + '2'})
48 48 ... ).iteritems())
49 49 [('baz', '\\\\\\x002'), ('branch', 'default'), ('foo', 'bar')]
50 50 """
51 51 extra = _defaultextra.copy()
52 52 for l in text.split('\0'):
53 53 if l:
54 54 if '\\0' in l:
55 55 # fix up \0 without getting into trouble with \\0
56 56 l = l.replace('\\\\', '\\\\\n')
57 57 l = l.replace('\\0', '\0')
58 58 l = l.replace('\n', '')
59 59 k, v = l.decode('string_escape').split(':', 1)
60 60 extra[k] = v
61 61 return extra
62 62
63 63 def encodeextra(d):
64 64 # keys must be sorted to produce a deterministic changelog entry
65 65 items = [_string_escape('%s:%s' % (k, d[k])) for k in sorted(d)]
66 66 return "\0".join(items)
67 67
68 68 def stripdesc(desc):
69 69 """strip trailing whitespace and leading and trailing empty lines"""
70 70 return '\n'.join([l.rstrip() for l in desc.splitlines()]).strip('\n')
71 71
72 72 class appender(object):
73 73 '''the changelog index must be updated last on disk, so we use this class
74 74 to delay writes to it'''
75 75 def __init__(self, vfs, name, mode, buf):
76 76 self.data = buf
77 77 fp = vfs(name, mode)
78 78 self.fp = fp
79 79 self.offset = fp.tell()
80 80 self.size = vfs.fstat(fp).st_size
81 81
82 82 def end(self):
83 83 return self.size + len("".join(self.data))
84 84 def tell(self):
85 85 return self.offset
86 86 def flush(self):
87 87 pass
88 88 def close(self):
89 89 self.fp.close()
90 90
91 91 def seek(self, offset, whence=0):
92 92 '''virtual file offset spans real file and data'''
93 93 if whence == 0:
94 94 self.offset = offset
95 95 elif whence == 1:
96 96 self.offset += offset
97 97 elif whence == 2:
98 98 self.offset = self.end() + offset
99 99 if self.offset < self.size:
100 100 self.fp.seek(self.offset)
101 101
102 102 def read(self, count=-1):
103 103 '''only trick here is reads that span real file and data'''
104 104 ret = ""
105 105 if self.offset < self.size:
106 106 s = self.fp.read(count)
107 107 ret = s
108 108 self.offset += len(s)
109 109 if count > 0:
110 110 count -= len(s)
111 111 if count != 0:
112 112 doff = self.offset - self.size
113 113 self.data.insert(0, "".join(self.data))
114 114 del self.data[1:]
115 115 s = self.data[0][doff:doff + count]
116 116 self.offset += len(s)
117 117 ret += s
118 118 return ret
119 119
120 120 def write(self, s):
121 121 self.data.append(str(s))
122 122 self.offset += len(s)
123 123
124 124 def _divertopener(opener, target):
125 125 """build an opener that writes in 'target.a' instead of 'target'"""
126 126 def _divert(name, mode='r'):
127 127 if name != target:
128 128 return opener(name, mode)
129 129 return opener(name + ".a", mode)
130 130 return _divert
131 131
132 132 def _delayopener(opener, target, buf):
133 133 """build an opener that stores chunks in 'buf' instead of 'target'"""
134 134 def _delay(name, mode='r'):
135 135 if name != target:
136 136 return opener(name, mode)
137 137 return appender(opener, name, mode, buf)
138 138 return _delay
139 139
140 140 class changelog(revlog.revlog):
141 141 def __init__(self, opener):
142 142 revlog.revlog.__init__(self, opener, "00changelog.i")
143 143 if self._initempty:
144 144 # changelogs don't benefit from generaldelta
145 145 self.version &= ~revlog.REVLOGGENERALDELTA
146 146 self._generaldelta = False
147 147 self._realopener = opener
148 148 self._delayed = False
149 149 self._delaybuf = None
150 150 self._divert = False
151 151 self.filteredrevs = frozenset()
152 152
153 153 def tip(self):
154 154 """filtered version of revlog.tip"""
155 155 for i in xrange(len(self) -1, -2, -1):
156 156 if i not in self.filteredrevs:
157 157 return self.node(i)
158 158
159 159 def __contains__(self, rev):
160 160 """filtered version of revlog.__contains__"""
161 161 return (0 <= rev < len(self)
162 162 and rev not in self.filteredrevs)
163 163
164 164 def __iter__(self):
165 165 """filtered version of revlog.__iter__"""
166 166 if len(self.filteredrevs) == 0:
167 167 return revlog.revlog.__iter__(self)
168 168
169 169 def filterediter():
170 170 for i in xrange(len(self)):
171 171 if i not in self.filteredrevs:
172 172 yield i
173 173
174 174 return filterediter()
175 175
176 176 def revs(self, start=0, stop=None):
177 177 """filtered version of revlog.revs"""
178 178 for i in super(changelog, self).revs(start, stop):
179 179 if i not in self.filteredrevs:
180 180 yield i
181 181
182 182 @util.propertycache
183 183 def nodemap(self):
184 184 # XXX need filtering too
185 185 self.rev(self.node(0))
186 186 return self._nodecache
187 187
188 188 def reachableroots(self, minroot, heads, roots, includepath=False):
189 return revset.baseset(sorted(
190 self.index.reachableroots2(minroot, heads, roots, includepath)))
189 rroots = self.index.reachableroots2(minroot, heads, roots, includepath)
190 rroots = revset.baseset(rroots)
191 rroots.sort()
192 return rroots
191 193
192 194 def headrevs(self):
193 195 if self.filteredrevs:
194 196 try:
195 197 return self.index.headrevsfiltered(self.filteredrevs)
196 198 # AttributeError covers non-c-extension environments and
197 199 # old c extensions without filter handling.
198 200 except AttributeError:
199 201 return self._headrevs()
200 202
201 203 return super(changelog, self).headrevs()
202 204
203 205 def strip(self, *args, **kwargs):
204 206 # XXX make something better than assert
205 207 # We can't expect proper strip behavior if we are filtered.
206 208 assert not self.filteredrevs
207 209 super(changelog, self).strip(*args, **kwargs)
208 210
209 211 def rev(self, node):
210 212 """filtered version of revlog.rev"""
211 213 r = super(changelog, self).rev(node)
212 214 if r in self.filteredrevs:
213 215 raise error.FilteredLookupError(hex(node), self.indexfile,
214 216 _('filtered node'))
215 217 return r
216 218
217 219 def node(self, rev):
218 220 """filtered version of revlog.node"""
219 221 if rev in self.filteredrevs:
220 222 raise error.FilteredIndexError(rev)
221 223 return super(changelog, self).node(rev)
222 224
223 225 def linkrev(self, rev):
224 226 """filtered version of revlog.linkrev"""
225 227 if rev in self.filteredrevs:
226 228 raise error.FilteredIndexError(rev)
227 229 return super(changelog, self).linkrev(rev)
228 230
229 231 def parentrevs(self, rev):
230 232 """filtered version of revlog.parentrevs"""
231 233 if rev in self.filteredrevs:
232 234 raise error.FilteredIndexError(rev)
233 235 return super(changelog, self).parentrevs(rev)
234 236
235 237 def flags(self, rev):
236 238 """filtered version of revlog.flags"""
237 239 if rev in self.filteredrevs:
238 240 raise error.FilteredIndexError(rev)
239 241 return super(changelog, self).flags(rev)
240 242
241 243 def delayupdate(self, tr):
242 244 "delay visibility of index updates to other readers"
243 245
244 246 if not self._delayed:
245 247 if len(self) == 0:
246 248 self._divert = True
247 249 if self._realopener.exists(self.indexfile + '.a'):
248 250 self._realopener.unlink(self.indexfile + '.a')
249 251 self.opener = _divertopener(self._realopener, self.indexfile)
250 252 else:
251 253 self._delaybuf = []
252 254 self.opener = _delayopener(self._realopener, self.indexfile,
253 255 self._delaybuf)
254 256 self._delayed = True
255 257 tr.addpending('cl-%i' % id(self), self._writepending)
256 258 tr.addfinalize('cl-%i' % id(self), self._finalize)
257 259
258 260 def _finalize(self, tr):
259 261 "finalize index updates"
260 262 self._delayed = False
261 263 self.opener = self._realopener
262 264 # move redirected index data back into place
263 265 if self._divert:
264 266 assert not self._delaybuf
265 267 tmpname = self.indexfile + ".a"
266 268 nfile = self.opener.open(tmpname)
267 269 nfile.close()
268 270 self.opener.rename(tmpname, self.indexfile)
269 271 elif self._delaybuf:
270 272 fp = self.opener(self.indexfile, 'a')
271 273 fp.write("".join(self._delaybuf))
272 274 fp.close()
273 275 self._delaybuf = None
274 276 self._divert = False
275 277 # split when we're done
276 278 self.checkinlinesize(tr)
277 279
278 280 def readpending(self, file):
279 281 """read index data from a "pending" file
280 282
281 283 During a transaction, the actual changeset data is already stored in the
282 284 main file, but not yet finalized in the on-disk index. Instead, a
283 285 "pending" index is written by the transaction logic. If this function
284 286 is running, we are likely in a subprocess invoked in a hook. The
285 287 subprocess is informed that it is within a transaction and needs to
286 288 access its content.
287 289
288 290 This function will read all the index data out of the pending file and
289 291 overwrite the main index."""
290 292
291 293 if not self.opener.exists(file):
292 294 return # no pending data for changelog
293 295 r = revlog.revlog(self.opener, file)
294 296 self.index = r.index
295 297 self.nodemap = r.nodemap
296 298 self._nodecache = r._nodecache
297 299 self._chunkcache = r._chunkcache
298 300
299 301 def _writepending(self, tr):
300 302 "create a file containing the unfinalized state for pretxnchangegroup"
301 303 if self._delaybuf:
302 304 # make a temporary copy of the index
303 305 fp1 = self._realopener(self.indexfile)
304 306 pendingfilename = self.indexfile + ".a"
305 307 # register as a temp file to ensure cleanup on failure
306 308 tr.registertmp(pendingfilename)
307 309 # write existing data
308 310 fp2 = self._realopener(pendingfilename, "w")
309 311 fp2.write(fp1.read())
310 312 # add pending data
311 313 fp2.write("".join(self._delaybuf))
312 314 fp2.close()
313 315 # switch modes so finalize can simply rename
314 316 self._delaybuf = None
315 317 self._divert = True
316 318 self.opener = _divertopener(self._realopener, self.indexfile)
317 319
318 320 if self._divert:
319 321 return True
320 322
321 323 return False
322 324
323 325 def checkinlinesize(self, tr, fp=None):
324 326 if not self._delayed:
325 327 revlog.revlog.checkinlinesize(self, tr, fp)
326 328
327 329 def read(self, node):
328 330 """
329 331 format used:
330 332 nodeid\n : manifest node in ascii
331 333 user\n : user, no \n or \r allowed
332 334 time tz extra\n : date (time is int or float, timezone is int)
333 335 : extra is metadata, encoded and separated by '\0'
334 336 : older versions ignore it
335 337 files\n\n : files modified by the cset, no \n or \r allowed
336 338 (.*) : comment (free text, ideally utf-8)
337 339
338 340 changelog v0 doesn't use extra
339 341 """
340 342 text = self.revision(node)
341 343 if not text:
342 344 return (nullid, "", (0, 0), [], "", _defaultextra)
343 345 last = text.index("\n\n")
344 346 desc = encoding.tolocal(text[last + 2:])
345 347 l = text[:last].split('\n')
346 348 manifest = bin(l[0])
347 349 user = encoding.tolocal(l[1])
348 350
349 351 tdata = l[2].split(' ', 2)
350 352 if len(tdata) != 3:
351 353 time = float(tdata[0])
352 354 try:
353 355 # various tools did silly things with the time zone field.
354 356 timezone = int(tdata[1])
355 357 except ValueError:
356 358 timezone = 0
357 359 extra = _defaultextra
358 360 else:
359 361 time, timezone = float(tdata[0]), int(tdata[1])
360 362 extra = decodeextra(tdata[2])
361 363
362 364 files = l[3:]
363 365 return (manifest, user, (time, timezone), files, desc, extra)
364 366
365 367 def add(self, manifest, files, desc, transaction, p1, p2,
366 368 user, date=None, extra=None):
367 369 # Convert to UTF-8 encoded bytestrings as the very first
368 370 # thing: calling any method on a localstr object will turn it
369 371 # into a str object and the cached UTF-8 string is thus lost.
370 372 user, desc = encoding.fromlocal(user), encoding.fromlocal(desc)
371 373
372 374 user = user.strip()
373 375 # An empty username or a username with a "\n" will make the
374 376 # revision text contain two "\n\n" sequences -> corrupt
375 377 # repository since read cannot unpack the revision.
376 378 if not user:
377 379 raise error.RevlogError(_("empty username"))
378 380 if "\n" in user:
379 381 raise error.RevlogError(_("username %s contains a newline")
380 382 % repr(user))
381 383
382 384 desc = stripdesc(desc)
383 385
384 386 if date:
385 387 parseddate = "%d %d" % util.parsedate(date)
386 388 else:
387 389 parseddate = "%d %d" % util.makedate()
388 390 if extra:
389 391 branch = extra.get("branch")
390 392 if branch in ("default", ""):
391 393 del extra["branch"]
392 394 elif branch in (".", "null", "tip"):
393 395 raise error.RevlogError(_('the name \'%s\' is reserved')
394 396 % branch)
395 397 if extra:
396 398 extra = encodeextra(extra)
397 399 parseddate = "%s %s" % (parseddate, extra)
398 400 l = [hex(manifest), user, parseddate] + sorted(files) + ["", desc]
399 401 text = "\n".join(l)
400 402 return self.addrevision(text, transaction, len(self), p1, p2)
401 403
402 404 def branchinfo(self, rev):
403 405 """return the branch name and open/close state of a revision
404 406
405 407 This function exists because creating a changectx object
406 408 just to access this is costly."""
407 409 extra = self.read(rev)[5]
408 410 return encoding.tolocal(extra.get("branch")), 'close' in extra
@@ -1,185 +1,185
1 1 revlog.parseindex must be able to parse the index file even if
2 2 an index entry is split between two 64k blocks. The ideal test
3 3 would be to create an index file with inline data where
4 4 64k < size < 64k + 64 (64k is the size of the read buffer, 64 is
5 5 the size of an index entry) and with an index entry starting right
6 6 before the 64k block boundary, and try to read it.
7 7 We approximate that by reducing the read buffer to 1 byte.
8 8
9 9 $ hg init a
10 10 $ cd a
11 11 $ echo abc > foo
12 12 $ hg add foo
13 13 $ hg commit -m 'add foo'
14 14 $ echo >> foo
15 15 $ hg commit -m 'change foo'
16 16 $ hg log -r 0:
17 17 changeset: 0:7c31755bf9b5
18 18 user: test
19 19 date: Thu Jan 01 00:00:00 1970 +0000
20 20 summary: add foo
21 21
22 22 changeset: 1:26333235a41c
23 23 tag: tip
24 24 user: test
25 25 date: Thu Jan 01 00:00:00 1970 +0000
26 26 summary: change foo
27 27
28 28 $ cat >> test.py << EOF
29 29 > from mercurial import changelog, scmutil
30 30 > from mercurial.node import *
31 31 >
32 32 > class singlebyteread(object):
33 33 > def __init__(self, real):
34 34 > self.real = real
35 35 >
36 36 > def read(self, size=-1):
37 37 > if size == 65536:
38 38 > size = 1
39 39 > return self.real.read(size)
40 40 >
41 41 > def __getattr__(self, key):
42 42 > return getattr(self.real, key)
43 43 >
44 44 > def opener(*args):
45 45 > o = scmutil.opener(*args)
46 46 > def wrapper(*a):
47 47 > f = o(*a)
48 48 > return singlebyteread(f)
49 49 > return wrapper
50 50 >
51 51 > cl = changelog.changelog(opener('.hg/store'))
52 52 > print len(cl), 'revisions:'
53 53 > for r in cl:
54 54 > print short(cl.node(r))
55 55 > EOF
56 56 $ python test.py
57 57 2 revisions:
58 58 7c31755bf9b5
59 59 26333235a41c
60 60
61 61 $ cd ..
62 62
63 63 #if no-pure
64 64
65 65 Test SEGV caused by bad revision passed to reachableroots() (issue4775):
66 66
67 67 $ cd a
68 68
69 69 $ python <<EOF
70 70 > from mercurial import changelog, scmutil
71 71 > cl = changelog.changelog(scmutil.vfs('.hg/store'))
72 72 > print 'good heads:'
73 73 > for head in [0, len(cl) - 1, -1]:
74 74 > print'%s: %r' % (head, cl.reachableroots(0, [head], [0]))
75 75 > print 'bad heads:'
76 76 > for head in [len(cl), 10000, -2, -10000, None]:
77 77 > print '%s:' % head,
78 78 > try:
79 79 > cl.reachableroots(0, [head], [0])
80 80 > print 'uncaught buffer overflow?'
81 81 > except (IndexError, TypeError) as inst:
82 82 > print inst
83 83 > print 'good roots:'
84 84 > for root in [0, len(cl) - 1, -1]:
85 85 > print '%s: %r' % (root, cl.reachableroots(root, [len(cl) - 1], [root]))
86 86 > print 'out-of-range roots are ignored:'
87 87 > for root in [len(cl), 10000, -2, -10000]:
88 88 > print '%s: %r' % (root, cl.reachableroots(root, [len(cl) - 1], [root]))
89 89 > print 'bad roots:'
90 90 > for root in [None]:
91 91 > print '%s:' % root,
92 92 > try:
93 93 > cl.reachableroots(root, [len(cl) - 1], [root])
94 94 > print 'uncaught error?'
95 95 > except TypeError as inst:
96 96 > print inst
97 97 > EOF
98 98 good heads:
99 0: <baseset [0]>
100 1: <baseset [0]>
101 -1: <baseset []>
99 0: <baseset+ [0]>
100 1: <baseset+ [0]>
101 -1: <baseset+ []>
102 102 bad heads:
103 103 2: head out of range
104 104 10000: head out of range
105 105 -2: head out of range
106 106 -10000: head out of range
107 107 None: an integer is required
108 108 good roots:
109 0: <baseset [0]>
110 1: <baseset [1]>
111 -1: <baseset [-1]>
109 0: <baseset+ [0]>
110 1: <baseset+ [1]>
111 -1: <baseset+ [-1]>
112 112 out-of-range roots are ignored:
113 2: <baseset []>
114 10000: <baseset []>
115 -2: <baseset []>
116 -10000: <baseset []>
113 2: <baseset+ []>
114 10000: <baseset+ []>
115 -2: <baseset+ []>
116 -10000: <baseset+ []>
117 117 bad roots:
118 118 None: an integer is required
119 119
120 120 $ cd ..
121 121
122 122 Test corrupted p1/p2 fields that could cause SEGV at parsers.c:
123 123
124 124 $ mkdir invalidparent
125 125 $ cd invalidparent
126 126
127 127 $ hg clone --pull -q --config phases.publish=False ../a limit
128 128 $ hg clone --pull -q --config phases.publish=False ../a segv
129 129 $ rm -R limit/.hg/cache segv/.hg/cache
130 130
131 131 $ python <<EOF
132 132 > data = open("limit/.hg/store/00changelog.i", "rb").read()
133 133 > for n, p in [('limit', '\0\0\0\x02'), ('segv', '\0\x01\0\0')]:
134 134 > # corrupt p1 at rev0 and p2 at rev1
135 135 > d = data[:24] + p + data[28:127 + 28] + p + data[127 + 32:]
136 136 > open(n + "/.hg/store/00changelog.i", "wb").write(d)
137 137 > EOF
138 138
139 139 $ hg debugindex -f1 limit/.hg/store/00changelog.i
140 140 rev flag offset length size base link p1 p2 nodeid
141 141 0 0000 0 63 62 0 0 2 -1 7c31755bf9b5
142 142 1 0000 63 66 65 1 1 0 2 26333235a41c
143 143 $ hg debugindex -f1 segv/.hg/store/00changelog.i
144 144 rev flag offset length size base link p1 p2 nodeid
145 145 0 0000 0 63 62 0 0 65536 -1 7c31755bf9b5
146 146 1 0000 63 66 65 1 1 0 65536 26333235a41c
147 147
148 148 $ cat <<EOF > test.py
149 149 > import sys
150 150 > from mercurial import changelog, scmutil
151 151 > cl = changelog.changelog(scmutil.vfs(sys.argv[1]))
152 152 > n0, n1 = cl.node(0), cl.node(1)
153 153 > ops = [
154 154 > ('reachableroots',
155 155 > lambda: cl.index.reachableroots2(0, [1], [0], False)),
156 156 > ('compute_phases_map_sets', lambda: cl.computephases([[0], []])),
157 157 > ('index_headrevs', lambda: cl.headrevs()),
158 158 > ('find_gca_candidates', lambda: cl.commonancestorsheads(n0, n1)),
159 159 > ('find_deepest', lambda: cl.ancestor(n0, n1)),
160 160 > ]
161 161 > for l, f in ops:
162 162 > print l + ':',
163 163 > try:
164 164 > f()
165 165 > print 'uncaught buffer overflow?'
166 166 > except ValueError, inst:
167 167 > print inst
168 168 > EOF
169 169
170 170 $ python test.py limit/.hg/store
171 171 reachableroots: parent out of range
172 172 compute_phases_map_sets: parent out of range
173 173 index_headrevs: parent out of range
174 174 find_gca_candidates: parent out of range
175 175 find_deepest: parent out of range
176 176 $ python test.py segv/.hg/store
177 177 reachableroots: parent out of range
178 178 compute_phases_map_sets: parent out of range
179 179 index_headrevs: parent out of range
180 180 find_gca_candidates: parent out of range
181 181 find_deepest: parent out of range
182 182
183 183 $ cd ..
184 184
185 185 #endif
@@ -1,2169 +1,2169
1 1 $ HGENCODING=utf-8
2 2 $ export HGENCODING
3 3 $ cat > testrevset.py << EOF
4 4 > import mercurial.revset
5 5 >
6 6 > baseset = mercurial.revset.baseset
7 7 >
8 8 > def r3232(repo, subset, x):
9 9 > """"simple revset that return [3,2,3,2]
10 10 >
11 11 > revisions duplicated on purpose.
12 12 > """
13 13 > if 3 not in subset:
14 14 > if 2 in subset:
15 15 > return baseset([2,2])
16 16 > return baseset()
17 17 > return baseset([3,3,2,2])
18 18 >
19 19 > mercurial.revset.symbols['r3232'] = r3232
20 20 > EOF
21 21 $ cat >> $HGRCPATH << EOF
22 22 > [extensions]
23 23 > testrevset=$TESTTMP/testrevset.py
24 24 > EOF
25 25
26 26 $ try() {
27 27 > hg debugrevspec --debug "$@"
28 28 > }
29 29
30 30 $ log() {
31 31 > hg log --template '{rev}\n' -r "$1"
32 32 > }
33 33
34 34 $ hg init repo
35 35 $ cd repo
36 36
37 37 $ echo a > a
38 38 $ hg branch a
39 39 marked working directory as branch a
40 40 (branches are permanent and global, did you want a bookmark?)
41 41 $ hg ci -Aqm0
42 42
43 43 $ echo b > b
44 44 $ hg branch b
45 45 marked working directory as branch b
46 46 $ hg ci -Aqm1
47 47
48 48 $ rm a
49 49 $ hg branch a-b-c-
50 50 marked working directory as branch a-b-c-
51 51 $ hg ci -Aqm2 -u Bob
52 52
53 53 $ hg log -r "extra('branch', 'a-b-c-')" --template '{rev}\n'
54 54 2
55 55 $ hg log -r "extra('branch')" --template '{rev}\n'
56 56 0
57 57 1
58 58 2
59 59 $ hg log -r "extra('branch', 're:a')" --template '{rev} {branch}\n'
60 60 0 a
61 61 2 a-b-c-
62 62
63 63 $ hg co 1
64 64 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
65 65 $ hg branch +a+b+c+
66 66 marked working directory as branch +a+b+c+
67 67 $ hg ci -Aqm3
68 68
69 69 $ hg co 2 # interleave
70 70 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
71 71 $ echo bb > b
72 72 $ hg branch -- -a-b-c-
73 73 marked working directory as branch -a-b-c-
74 74 $ hg ci -Aqm4 -d "May 12 2005"
75 75
76 76 $ hg co 3
77 77 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
78 78 $ hg branch !a/b/c/
79 79 marked working directory as branch !a/b/c/
80 80 $ hg ci -Aqm"5 bug"
81 81
82 82 $ hg merge 4
83 83 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
84 84 (branch merge, don't forget to commit)
85 85 $ hg branch _a_b_c_
86 86 marked working directory as branch _a_b_c_
87 87 $ hg ci -Aqm"6 issue619"
88 88
89 89 $ hg branch .a.b.c.
90 90 marked working directory as branch .a.b.c.
91 91 $ hg ci -Aqm7
92 92
93 93 $ hg branch all
94 94 marked working directory as branch all
95 95
96 96 $ hg co 4
97 97 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
98 98 $ hg branch é
99 99 marked working directory as branch \xc3\xa9 (esc)
100 100 $ hg ci -Aqm9
101 101
102 102 $ hg tag -r6 1.0
103 103 $ hg bookmark -r6 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
104 104
105 105 $ hg clone --quiet -U -r 7 . ../remote1
106 106 $ hg clone --quiet -U -r 8 . ../remote2
107 107 $ echo "[paths]" >> .hg/hgrc
108 108 $ echo "default = ../remote1" >> .hg/hgrc
109 109
110 110 trivial
111 111
112 112 $ try 0:1
113 113 (range
114 114 ('symbol', '0')
115 115 ('symbol', '1'))
116 116 * set:
117 117 <spanset+ 0:1>
118 118 0
119 119 1
120 120 $ try --optimize :
121 121 (rangeall
122 122 None)
123 123 * optimized:
124 124 (range
125 125 ('string', '0')
126 126 ('string', 'tip'))
127 127 * set:
128 128 <spanset+ 0:9>
129 129 0
130 130 1
131 131 2
132 132 3
133 133 4
134 134 5
135 135 6
136 136 7
137 137 8
138 138 9
139 139 $ try 3::6
140 140 (dagrange
141 141 ('symbol', '3')
142 142 ('symbol', '6'))
143 143 * set:
144 <baseset [3, 5, 6]>
144 <baseset+ [3, 5, 6]>
145 145 3
146 146 5
147 147 6
148 148 $ try '0|1|2'
149 149 (or
150 150 ('symbol', '0')
151 151 ('symbol', '1')
152 152 ('symbol', '2'))
153 153 * set:
154 154 <baseset [0, 1, 2]>
155 155 0
156 156 1
157 157 2
158 158
159 159 names that should work without quoting
160 160
161 161 $ try a
162 162 ('symbol', 'a')
163 163 * set:
164 164 <baseset [0]>
165 165 0
166 166 $ try b-a
167 167 (minus
168 168 ('symbol', 'b')
169 169 ('symbol', 'a'))
170 170 * set:
171 171 <filteredset
172 172 <baseset [1]>>
173 173 1
174 174 $ try _a_b_c_
175 175 ('symbol', '_a_b_c_')
176 176 * set:
177 177 <baseset [6]>
178 178 6
179 179 $ try _a_b_c_-a
180 180 (minus
181 181 ('symbol', '_a_b_c_')
182 182 ('symbol', 'a'))
183 183 * set:
184 184 <filteredset
185 185 <baseset [6]>>
186 186 6
187 187 $ try .a.b.c.
188 188 ('symbol', '.a.b.c.')
189 189 * set:
190 190 <baseset [7]>
191 191 7
192 192 $ try .a.b.c.-a
193 193 (minus
194 194 ('symbol', '.a.b.c.')
195 195 ('symbol', 'a'))
196 196 * set:
197 197 <filteredset
198 198 <baseset [7]>>
199 199 7
200 200
201 201 names that should be caught by fallback mechanism
202 202
203 203 $ try -- '-a-b-c-'
204 204 ('symbol', '-a-b-c-')
205 205 * set:
206 206 <baseset [4]>
207 207 4
208 208 $ log -a-b-c-
209 209 4
210 210 $ try '+a+b+c+'
211 211 ('symbol', '+a+b+c+')
212 212 * set:
213 213 <baseset [3]>
214 214 3
215 215 $ try '+a+b+c+:'
216 216 (rangepost
217 217 ('symbol', '+a+b+c+'))
218 218 * set:
219 219 <spanset+ 3:9>
220 220 3
221 221 4
222 222 5
223 223 6
224 224 7
225 225 8
226 226 9
227 227 $ try ':+a+b+c+'
228 228 (rangepre
229 229 ('symbol', '+a+b+c+'))
230 230 * set:
231 231 <spanset+ 0:3>
232 232 0
233 233 1
234 234 2
235 235 3
236 236 $ try -- '-a-b-c-:+a+b+c+'
237 237 (range
238 238 ('symbol', '-a-b-c-')
239 239 ('symbol', '+a+b+c+'))
240 240 * set:
241 241 <spanset- 3:4>
242 242 4
243 243 3
244 244 $ log '-a-b-c-:+a+b+c+'
245 245 4
246 246 3
247 247
248 248 $ try -- -a-b-c--a # complains
249 249 (minus
250 250 (minus
251 251 (minus
252 252 (negate
253 253 ('symbol', 'a'))
254 254 ('symbol', 'b'))
255 255 ('symbol', 'c'))
256 256 (negate
257 257 ('symbol', 'a')))
258 258 abort: unknown revision '-a'!
259 259 [255]
260 260 $ try é
261 261 ('symbol', '\xc3\xa9')
262 262 * set:
263 263 <baseset [9]>
264 264 9
265 265
266 266 no quoting needed
267 267
268 268 $ log ::a-b-c-
269 269 0
270 270 1
271 271 2
272 272
273 273 quoting needed
274 274
275 275 $ try '"-a-b-c-"-a'
276 276 (minus
277 277 ('string', '-a-b-c-')
278 278 ('symbol', 'a'))
279 279 * set:
280 280 <filteredset
281 281 <baseset [4]>>
282 282 4
283 283
284 284 $ log '1 or 2'
285 285 1
286 286 2
287 287 $ log '1|2'
288 288 1
289 289 2
290 290 $ log '1 and 2'
291 291 $ log '1&2'
292 292 $ try '1&2|3' # precedence - and is higher
293 293 (or
294 294 (and
295 295 ('symbol', '1')
296 296 ('symbol', '2'))
297 297 ('symbol', '3'))
298 298 * set:
299 299 <addset
300 300 <baseset []>,
301 301 <baseset [3]>>
302 302 3
303 303 $ try '1|2&3'
304 304 (or
305 305 ('symbol', '1')
306 306 (and
307 307 ('symbol', '2')
308 308 ('symbol', '3')))
309 309 * set:
310 310 <addset
311 311 <baseset [1]>,
312 312 <baseset []>>
313 313 1
314 314 $ try '1&2&3' # associativity
315 315 (and
316 316 (and
317 317 ('symbol', '1')
318 318 ('symbol', '2'))
319 319 ('symbol', '3'))
320 320 * set:
321 321 <baseset []>
322 322 $ try '1|(2|3)'
323 323 (or
324 324 ('symbol', '1')
325 325 (group
326 326 (or
327 327 ('symbol', '2')
328 328 ('symbol', '3'))))
329 329 * set:
330 330 <addset
331 331 <baseset [1]>,
332 332 <baseset [2, 3]>>
333 333 1
334 334 2
335 335 3
336 336 $ log '1.0' # tag
337 337 6
338 338 $ log 'a' # branch
339 339 0
340 340 $ log '2785f51ee'
341 341 0
342 342 $ log 'date(2005)'
343 343 4
344 344 $ log 'date(this is a test)'
345 345 hg: parse error at 10: unexpected token: symbol
346 346 [255]
347 347 $ log 'date()'
348 348 hg: parse error: date requires a string
349 349 [255]
350 350 $ log 'date'
351 351 abort: unknown revision 'date'!
352 352 [255]
353 353 $ log 'date('
354 354 hg: parse error at 5: not a prefix: end
355 355 [255]
356 356 $ log 'date(tip)'
357 357 abort: invalid date: 'tip'
358 358 [255]
359 359 $ log '0:date'
360 360 abort: unknown revision 'date'!
361 361 [255]
362 362 $ log '::"date"'
363 363 abort: unknown revision 'date'!
364 364 [255]
365 365 $ hg book date -r 4
366 366 $ log '0:date'
367 367 0
368 368 1
369 369 2
370 370 3
371 371 4
372 372 $ log '::date'
373 373 0
374 374 1
375 375 2
376 376 4
377 377 $ log '::"date"'
378 378 0
379 379 1
380 380 2
381 381 4
382 382 $ log 'date(2005) and 1::'
383 383 4
384 384 $ hg book -d date
385 385
386 386 keyword arguments
387 387
388 388 $ log 'extra(branch, value=a)'
389 389 0
390 390
391 391 $ log 'extra(branch, a, b)'
392 392 hg: parse error: extra takes at most 2 arguments
393 393 [255]
394 394 $ log 'extra(a, label=b)'
395 395 hg: parse error: extra got multiple values for keyword argument 'label'
396 396 [255]
397 397 $ log 'extra(label=branch, default)'
398 398 hg: parse error: extra got an invalid argument
399 399 [255]
400 400 $ log 'extra(branch, foo+bar=baz)'
401 401 hg: parse error: extra got an invalid argument
402 402 [255]
403 403 $ log 'extra(unknown=branch)'
404 404 hg: parse error: extra got an unexpected keyword argument 'unknown'
405 405 [255]
406 406
407 407 $ try 'foo=bar|baz'
408 408 (keyvalue
409 409 ('symbol', 'foo')
410 410 (or
411 411 ('symbol', 'bar')
412 412 ('symbol', 'baz')))
413 413 hg: parse error: can't use a key-value pair in this context
414 414 [255]
415 415
416 416 Test that symbols only get parsed as functions if there's an opening
417 417 parenthesis.
418 418
419 419 $ hg book only -r 9
420 420 $ log 'only(only)' # Outer "only" is a function, inner "only" is the bookmark
421 421 8
422 422 9
423 423
424 424 ancestor can accept 0 or more arguments
425 425
426 426 $ log 'ancestor()'
427 427 $ log 'ancestor(1)'
428 428 1
429 429 $ log 'ancestor(4,5)'
430 430 1
431 431 $ log 'ancestor(4,5) and 4'
432 432 $ log 'ancestor(0,0,1,3)'
433 433 0
434 434 $ log 'ancestor(3,1,5,3,5,1)'
435 435 1
436 436 $ log 'ancestor(0,1,3,5)'
437 437 0
438 438 $ log 'ancestor(1,2,3,4,5)'
439 439 1
440 440
441 441 test ancestors
442 442
443 443 $ log 'ancestors(5)'
444 444 0
445 445 1
446 446 3
447 447 5
448 448 $ log 'ancestor(ancestors(5))'
449 449 0
450 450 $ log '::r3232()'
451 451 0
452 452 1
453 453 2
454 454 3
455 455
456 456 $ log 'author(bob)'
457 457 2
458 458 $ log 'author("re:bob|test")'
459 459 0
460 460 1
461 461 2
462 462 3
463 463 4
464 464 5
465 465 6
466 466 7
467 467 8
468 468 9
469 469 $ log 'branch(é)'
470 470 8
471 471 9
472 472 $ log 'branch(a)'
473 473 0
474 474 $ hg log -r 'branch("re:a")' --template '{rev} {branch}\n'
475 475 0 a
476 476 2 a-b-c-
477 477 3 +a+b+c+
478 478 4 -a-b-c-
479 479 5 !a/b/c/
480 480 6 _a_b_c_
481 481 7 .a.b.c.
482 482 $ log 'children(ancestor(4,5))'
483 483 2
484 484 3
485 485 $ log 'closed()'
486 486 $ log 'contains(a)'
487 487 0
488 488 1
489 489 3
490 490 5
491 491 $ log 'contains("../repo/a")'
492 492 0
493 493 1
494 494 3
495 495 5
496 496 $ log 'desc(B)'
497 497 5
498 498 $ log 'descendants(2 or 3)'
499 499 2
500 500 3
501 501 4
502 502 5
503 503 6
504 504 7
505 505 8
506 506 9
507 507 $ log 'file("b*")'
508 508 1
509 509 4
510 510 $ log 'filelog("b")'
511 511 1
512 512 4
513 513 $ log 'filelog("../repo/b")'
514 514 1
515 515 4
516 516 $ log 'follow()'
517 517 0
518 518 1
519 519 2
520 520 4
521 521 8
522 522 9
523 523 $ log 'grep("issue\d+")'
524 524 6
525 525 $ try 'grep("(")' # invalid regular expression
526 526 (func
527 527 ('symbol', 'grep')
528 528 ('string', '('))
529 529 hg: parse error: invalid match pattern: unbalanced parenthesis
530 530 [255]
531 531 $ try 'grep("\bissue\d+")'
532 532 (func
533 533 ('symbol', 'grep')
534 534 ('string', '\x08issue\\d+'))
535 535 * set:
536 536 <filteredset
537 537 <fullreposet+ 0:9>>
538 538 $ try 'grep(r"\bissue\d+")'
539 539 (func
540 540 ('symbol', 'grep')
541 541 ('string', '\\bissue\\d+'))
542 542 * set:
543 543 <filteredset
544 544 <fullreposet+ 0:9>>
545 545 6
546 546 $ try 'grep(r"\")'
547 547 hg: parse error at 7: unterminated string
548 548 [255]
549 549 $ log 'head()'
550 550 0
551 551 1
552 552 2
553 553 3
554 554 4
555 555 5
556 556 6
557 557 7
558 558 9
559 559 $ log 'heads(6::)'
560 560 7
561 561 $ log 'keyword(issue)'
562 562 6
563 563 $ log 'keyword("test a")'
564 564 $ log 'limit(head(), 1)'
565 565 0
566 566 $ log 'matching(6)'
567 567 6
568 568 $ log 'matching(6:7, "phase parents user date branch summary files description substate")'
569 569 6
570 570 7
571 571
572 572 Testing min and max
573 573
574 574 max: simple
575 575
576 576 $ log 'max(contains(a))'
577 577 5
578 578
579 579 max: simple on unordered set)
580 580
581 581 $ log 'max((4+0+2+5+7) and contains(a))'
582 582 5
583 583
584 584 max: no result
585 585
586 586 $ log 'max(contains(stringthatdoesnotappearanywhere))'
587 587
588 588 max: no result on unordered set
589 589
590 590 $ log 'max((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
591 591
592 592 min: simple
593 593
594 594 $ log 'min(contains(a))'
595 595 0
596 596
597 597 min: simple on unordered set
598 598
599 599 $ log 'min((4+0+2+5+7) and contains(a))'
600 600 0
601 601
602 602 min: empty
603 603
604 604 $ log 'min(contains(stringthatdoesnotappearanywhere))'
605 605
606 606 min: empty on unordered set
607 607
608 608 $ log 'min((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
609 609
610 610
611 611 $ log 'merge()'
612 612 6
613 613 $ log 'branchpoint()'
614 614 1
615 615 4
616 616 $ log 'modifies(b)'
617 617 4
618 618 $ log 'modifies("path:b")'
619 619 4
620 620 $ log 'modifies("*")'
621 621 4
622 622 6
623 623 $ log 'modifies("set:modified()")'
624 624 4
625 625 $ log 'id(5)'
626 626 2
627 627 $ log 'only(9)'
628 628 8
629 629 9
630 630 $ log 'only(8)'
631 631 8
632 632 $ log 'only(9, 5)'
633 633 2
634 634 4
635 635 8
636 636 9
637 637 $ log 'only(7 + 9, 5 + 2)'
638 638 4
639 639 6
640 640 7
641 641 8
642 642 9
643 643
644 644 Test empty set input
645 645 $ log 'only(p2())'
646 646 $ log 'only(p1(), p2())'
647 647 0
648 648 1
649 649 2
650 650 4
651 651 8
652 652 9
653 653
654 654 Test '%' operator
655 655
656 656 $ log '9%'
657 657 8
658 658 9
659 659 $ log '9%5'
660 660 2
661 661 4
662 662 8
663 663 9
664 664 $ log '(7 + 9)%(5 + 2)'
665 665 4
666 666 6
667 667 7
668 668 8
669 669 9
670 670
671 671 Test opreand of '%' is optimized recursively (issue4670)
672 672
673 673 $ try --optimize '8:9-8%'
674 674 (onlypost
675 675 (minus
676 676 (range
677 677 ('symbol', '8')
678 678 ('symbol', '9'))
679 679 ('symbol', '8')))
680 680 * optimized:
681 681 (func
682 682 ('symbol', 'only')
683 683 (and
684 684 (range
685 685 ('symbol', '8')
686 686 ('symbol', '9'))
687 687 (not
688 688 ('symbol', '8'))))
689 689 * set:
690 690 <baseset+ [8, 9]>
691 691 8
692 692 9
693 693 $ try --optimize '(9)%(5)'
694 694 (only
695 695 (group
696 696 ('symbol', '9'))
697 697 (group
698 698 ('symbol', '5')))
699 699 * optimized:
700 700 (func
701 701 ('symbol', 'only')
702 702 (list
703 703 ('symbol', '9')
704 704 ('symbol', '5')))
705 705 * set:
706 706 <baseset+ [8, 9, 2, 4]>
707 707 2
708 708 4
709 709 8
710 710 9
711 711
712 712 Test the order of operations
713 713
714 714 $ log '7 + 9%5 + 2'
715 715 7
716 716 2
717 717 4
718 718 8
719 719 9
720 720
721 721 Test explicit numeric revision
722 722 $ log 'rev(-2)'
723 723 $ log 'rev(-1)'
724 724 -1
725 725 $ log 'rev(0)'
726 726 0
727 727 $ log 'rev(9)'
728 728 9
729 729 $ log 'rev(10)'
730 730 $ log 'rev(tip)'
731 731 hg: parse error: rev expects a number
732 732 [255]
733 733
734 734 Test hexadecimal revision
735 735 $ log 'id(2)'
736 736 abort: 00changelog.i@2: ambiguous identifier!
737 737 [255]
738 738 $ log 'id(23268)'
739 739 4
740 740 $ log 'id(2785f51eece)'
741 741 0
742 742 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532c)'
743 743 8
744 744 $ log 'id(d5d0dcbdc4a)'
745 745 $ log 'id(d5d0dcbdc4w)'
746 746 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532d)'
747 747 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532q)'
748 748 $ log 'id(1.0)'
749 749 $ log 'id(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)'
750 750
751 751 Test null revision
752 752 $ log '(null)'
753 753 -1
754 754 $ log '(null:0)'
755 755 -1
756 756 0
757 757 $ log '(0:null)'
758 758 0
759 759 -1
760 760 $ log 'null::0'
761 761 -1
762 762 0
763 763 $ log 'null:tip - 0:'
764 764 -1
765 765 $ log 'null: and null::' | head -1
766 766 -1
767 767 $ log 'null: or 0:' | head -2
768 768 -1
769 769 0
770 770 $ log 'ancestors(null)'
771 771 -1
772 772 $ log 'reverse(null:)' | tail -2
773 773 0
774 774 -1
775 775 BROKEN: should be '-1'
776 776 $ log 'first(null:)'
777 777 BROKEN: should be '-1'
778 778 $ log 'min(null:)'
779 779 $ log 'tip:null and all()' | tail -2
780 780 1
781 781 0
782 782
783 783 Test working-directory revision
784 784 $ hg debugrevspec 'wdir()'
785 785 2147483647
786 786 $ hg debugrevspec 'tip or wdir()'
787 787 9
788 788 2147483647
789 789 $ hg debugrevspec '0:tip and wdir()'
790 790 $ log '0:wdir()' | tail -3
791 791 8
792 792 9
793 793 2147483647
794 794 $ log 'wdir():0' | head -3
795 795 2147483647
796 796 9
797 797 8
798 798 $ log 'wdir():wdir()'
799 799 2147483647
800 800 $ log '(all() + wdir()) & min(. + wdir())'
801 801 9
802 802 $ log '(all() + wdir()) & max(. + wdir())'
803 803 2147483647
804 804 $ log '(all() + wdir()) & first(wdir() + .)'
805 805 2147483647
806 806 $ log '(all() + wdir()) & last(. + wdir())'
807 807 2147483647
808 808
809 809 $ log 'outgoing()'
810 810 8
811 811 9
812 812 $ log 'outgoing("../remote1")'
813 813 8
814 814 9
815 815 $ log 'outgoing("../remote2")'
816 816 3
817 817 5
818 818 6
819 819 7
820 820 9
821 821 $ log 'p1(merge())'
822 822 5
823 823 $ log 'p2(merge())'
824 824 4
825 825 $ log 'parents(merge())'
826 826 4
827 827 5
828 828 $ log 'p1(branchpoint())'
829 829 0
830 830 2
831 831 $ log 'p2(branchpoint())'
832 832 $ log 'parents(branchpoint())'
833 833 0
834 834 2
835 835 $ log 'removes(a)'
836 836 2
837 837 6
838 838 $ log 'roots(all())'
839 839 0
840 840 $ log 'reverse(2 or 3 or 4 or 5)'
841 841 5
842 842 4
843 843 3
844 844 2
845 845 $ log 'reverse(all())'
846 846 9
847 847 8
848 848 7
849 849 6
850 850 5
851 851 4
852 852 3
853 853 2
854 854 1
855 855 0
856 856 $ log 'reverse(all()) & filelog(b)'
857 857 4
858 858 1
859 859 $ log 'rev(5)'
860 860 5
861 861 $ log 'sort(limit(reverse(all()), 3))'
862 862 7
863 863 8
864 864 9
865 865 $ log 'sort(2 or 3 or 4 or 5, date)'
866 866 2
867 867 3
868 868 5
869 869 4
870 870 $ log 'tagged()'
871 871 6
872 872 $ log 'tag()'
873 873 6
874 874 $ log 'tag(1.0)'
875 875 6
876 876 $ log 'tag(tip)'
877 877 9
878 878
879 879 test sort revset
880 880 --------------------------------------------
881 881
882 882 test when adding two unordered revsets
883 883
884 884 $ log 'sort(keyword(issue) or modifies(b))'
885 885 4
886 886 6
887 887
888 888 test when sorting a reversed collection in the same way it is
889 889
890 890 $ log 'sort(reverse(all()), -rev)'
891 891 9
892 892 8
893 893 7
894 894 6
895 895 5
896 896 4
897 897 3
898 898 2
899 899 1
900 900 0
901 901
902 902 test when sorting a reversed collection
903 903
904 904 $ log 'sort(reverse(all()), rev)'
905 905 0
906 906 1
907 907 2
908 908 3
909 909 4
910 910 5
911 911 6
912 912 7
913 913 8
914 914 9
915 915
916 916
917 917 test sorting two sorted collections in different orders
918 918
919 919 $ log 'sort(outgoing() or reverse(removes(a)), rev)'
920 920 2
921 921 6
922 922 8
923 923 9
924 924
925 925 test sorting two sorted collections in different orders backwards
926 926
927 927 $ log 'sort(outgoing() or reverse(removes(a)), -rev)'
928 928 9
929 929 8
930 930 6
931 931 2
932 932
933 933 test subtracting something from an addset
934 934
935 935 $ log '(outgoing() or removes(a)) - removes(a)'
936 936 8
937 937 9
938 938
939 939 test intersecting something with an addset
940 940
941 941 $ log 'parents(outgoing() or removes(a))'
942 942 1
943 943 4
944 944 5
945 945 8
946 946
947 947 test that `or` operation combines elements in the right order:
948 948
949 949 $ log '3:4 or 2:5'
950 950 3
951 951 4
952 952 2
953 953 5
954 954 $ log '3:4 or 5:2'
955 955 3
956 956 4
957 957 5
958 958 2
959 959 $ log 'sort(3:4 or 2:5)'
960 960 2
961 961 3
962 962 4
963 963 5
964 964 $ log 'sort(3:4 or 5:2)'
965 965 2
966 966 3
967 967 4
968 968 5
969 969
970 970 test that more than one `-r`s are combined in the right order and deduplicated:
971 971
972 972 $ hg log -T '{rev}\n' -r 3 -r 3 -r 4 -r 5:2 -r 'ancestors(4)'
973 973 3
974 974 4
975 975 5
976 976 2
977 977 0
978 978 1
979 979
980 980 test that `or` operation skips duplicated revisions from right-hand side
981 981
982 982 $ try 'reverse(1::5) or ancestors(4)'
983 983 (or
984 984 (func
985 985 ('symbol', 'reverse')
986 986 (dagrange
987 987 ('symbol', '1')
988 988 ('symbol', '5')))
989 989 (func
990 990 ('symbol', 'ancestors')
991 991 ('symbol', '4')))
992 992 * set:
993 993 <addset
994 <baseset [5, 3, 1]>,
994 <baseset- [1, 3, 5]>,
995 995 <generatorset+>>
996 996 5
997 997 3
998 998 1
999 999 0
1000 1000 2
1001 1001 4
1002 1002 $ try 'sort(ancestors(4) or reverse(1::5))'
1003 1003 (func
1004 1004 ('symbol', 'sort')
1005 1005 (or
1006 1006 (func
1007 1007 ('symbol', 'ancestors')
1008 1008 ('symbol', '4'))
1009 1009 (func
1010 1010 ('symbol', 'reverse')
1011 1011 (dagrange
1012 1012 ('symbol', '1')
1013 1013 ('symbol', '5')))))
1014 1014 * set:
1015 1015 <addset+
1016 1016 <generatorset+>,
1017 <baseset [5, 3, 1]>>
1017 <baseset- [1, 3, 5]>>
1018 1018 0
1019 1019 1
1020 1020 2
1021 1021 3
1022 1022 4
1023 1023 5
1024 1024
1025 1025 test optimization of trivial `or` operation
1026 1026
1027 1027 $ try --optimize '0|(1)|"2"|-2|tip|null'
1028 1028 (or
1029 1029 ('symbol', '0')
1030 1030 (group
1031 1031 ('symbol', '1'))
1032 1032 ('string', '2')
1033 1033 (negate
1034 1034 ('symbol', '2'))
1035 1035 ('symbol', 'tip')
1036 1036 ('symbol', 'null'))
1037 1037 * optimized:
1038 1038 (func
1039 1039 ('symbol', '_list')
1040 1040 ('string', '0\x001\x002\x00-2\x00tip\x00null'))
1041 1041 * set:
1042 1042 <baseset [0, 1, 2, 8, 9, -1]>
1043 1043 0
1044 1044 1
1045 1045 2
1046 1046 8
1047 1047 9
1048 1048 -1
1049 1049
1050 1050 $ try --optimize '0|1|2:3'
1051 1051 (or
1052 1052 ('symbol', '0')
1053 1053 ('symbol', '1')
1054 1054 (range
1055 1055 ('symbol', '2')
1056 1056 ('symbol', '3')))
1057 1057 * optimized:
1058 1058 (or
1059 1059 (func
1060 1060 ('symbol', '_list')
1061 1061 ('string', '0\x001'))
1062 1062 (range
1063 1063 ('symbol', '2')
1064 1064 ('symbol', '3')))
1065 1065 * set:
1066 1066 <addset
1067 1067 <baseset [0, 1]>,
1068 1068 <spanset+ 2:3>>
1069 1069 0
1070 1070 1
1071 1071 2
1072 1072 3
1073 1073
1074 1074 $ try --optimize '0:1|2|3:4|5|6'
1075 1075 (or
1076 1076 (range
1077 1077 ('symbol', '0')
1078 1078 ('symbol', '1'))
1079 1079 ('symbol', '2')
1080 1080 (range
1081 1081 ('symbol', '3')
1082 1082 ('symbol', '4'))
1083 1083 ('symbol', '5')
1084 1084 ('symbol', '6'))
1085 1085 * optimized:
1086 1086 (or
1087 1087 (range
1088 1088 ('symbol', '0')
1089 1089 ('symbol', '1'))
1090 1090 ('symbol', '2')
1091 1091 (range
1092 1092 ('symbol', '3')
1093 1093 ('symbol', '4'))
1094 1094 (func
1095 1095 ('symbol', '_list')
1096 1096 ('string', '5\x006')))
1097 1097 * set:
1098 1098 <addset
1099 1099 <addset
1100 1100 <spanset+ 0:1>,
1101 1101 <baseset [2]>>,
1102 1102 <addset
1103 1103 <spanset+ 3:4>,
1104 1104 <baseset [5, 6]>>>
1105 1105 0
1106 1106 1
1107 1107 2
1108 1108 3
1109 1109 4
1110 1110 5
1111 1111 6
1112 1112
1113 1113 test that `_list` should be narrowed by provided `subset`
1114 1114
1115 1115 $ log '0:2 and (null|1|2|3)'
1116 1116 1
1117 1117 2
1118 1118
1119 1119 test that `_list` should remove duplicates
1120 1120
1121 1121 $ log '0|1|2|1|2|-1|tip'
1122 1122 0
1123 1123 1
1124 1124 2
1125 1125 9
1126 1126
1127 1127 test unknown revision in `_list`
1128 1128
1129 1129 $ log '0|unknown'
1130 1130 abort: unknown revision 'unknown'!
1131 1131 [255]
1132 1132
1133 1133 test integer range in `_list`
1134 1134
1135 1135 $ log '-1|-10'
1136 1136 9
1137 1137 0
1138 1138
1139 1139 $ log '-10|-11'
1140 1140 abort: unknown revision '-11'!
1141 1141 [255]
1142 1142
1143 1143 $ log '9|10'
1144 1144 abort: unknown revision '10'!
1145 1145 [255]
1146 1146
1147 1147 test '0000' != '0' in `_list`
1148 1148
1149 1149 $ log '0|0000'
1150 1150 0
1151 1151 -1
1152 1152
1153 1153 test that chained `or` operations make balanced addsets
1154 1154
1155 1155 $ try '0:1|1:2|2:3|3:4|4:5'
1156 1156 (or
1157 1157 (range
1158 1158 ('symbol', '0')
1159 1159 ('symbol', '1'))
1160 1160 (range
1161 1161 ('symbol', '1')
1162 1162 ('symbol', '2'))
1163 1163 (range
1164 1164 ('symbol', '2')
1165 1165 ('symbol', '3'))
1166 1166 (range
1167 1167 ('symbol', '3')
1168 1168 ('symbol', '4'))
1169 1169 (range
1170 1170 ('symbol', '4')
1171 1171 ('symbol', '5')))
1172 1172 * set:
1173 1173 <addset
1174 1174 <addset
1175 1175 <spanset+ 0:1>,
1176 1176 <spanset+ 1:2>>,
1177 1177 <addset
1178 1178 <spanset+ 2:3>,
1179 1179 <addset
1180 1180 <spanset+ 3:4>,
1181 1181 <spanset+ 4:5>>>>
1182 1182 0
1183 1183 1
1184 1184 2
1185 1185 3
1186 1186 4
1187 1187 5
1188 1188
1189 1189 no crash by empty group "()" while optimizing `or` operations
1190 1190
1191 1191 $ try --optimize '0|()'
1192 1192 (or
1193 1193 ('symbol', '0')
1194 1194 (group
1195 1195 None))
1196 1196 * optimized:
1197 1197 (or
1198 1198 ('symbol', '0')
1199 1199 None)
1200 1200 hg: parse error: missing argument
1201 1201 [255]
1202 1202
1203 1203 test that chained `or` operations never eat up stack (issue4624)
1204 1204 (uses `0:1` instead of `0` to avoid future optimization of trivial revisions)
1205 1205
1206 1206 $ hg log -T '{rev}\n' -r "`python -c "print '|'.join(['0:1'] * 500)"`"
1207 1207 0
1208 1208 1
1209 1209
1210 1210 test that repeated `-r` options never eat up stack (issue4565)
1211 1211 (uses `-r 0::1` to avoid possible optimization at old-style parser)
1212 1212
1213 1213 $ hg log -T '{rev}\n' `python -c "for i in xrange(500): print '-r 0::1 ',"`
1214 1214 0
1215 1215 1
1216 1216
1217 1217 check that conversion to only works
1218 1218 $ try --optimize '::3 - ::1'
1219 1219 (minus
1220 1220 (dagrangepre
1221 1221 ('symbol', '3'))
1222 1222 (dagrangepre
1223 1223 ('symbol', '1')))
1224 1224 * optimized:
1225 1225 (func
1226 1226 ('symbol', 'only')
1227 1227 (list
1228 1228 ('symbol', '3')
1229 1229 ('symbol', '1')))
1230 1230 * set:
1231 1231 <baseset+ [3]>
1232 1232 3
1233 1233 $ try --optimize 'ancestors(1) - ancestors(3)'
1234 1234 (minus
1235 1235 (func
1236 1236 ('symbol', 'ancestors')
1237 1237 ('symbol', '1'))
1238 1238 (func
1239 1239 ('symbol', 'ancestors')
1240 1240 ('symbol', '3')))
1241 1241 * optimized:
1242 1242 (func
1243 1243 ('symbol', 'only')
1244 1244 (list
1245 1245 ('symbol', '1')
1246 1246 ('symbol', '3')))
1247 1247 * set:
1248 1248 <baseset+ []>
1249 1249 $ try --optimize 'not ::2 and ::6'
1250 1250 (and
1251 1251 (not
1252 1252 (dagrangepre
1253 1253 ('symbol', '2')))
1254 1254 (dagrangepre
1255 1255 ('symbol', '6')))
1256 1256 * optimized:
1257 1257 (func
1258 1258 ('symbol', 'only')
1259 1259 (list
1260 1260 ('symbol', '6')
1261 1261 ('symbol', '2')))
1262 1262 * set:
1263 1263 <baseset+ [3, 4, 5, 6]>
1264 1264 3
1265 1265 4
1266 1266 5
1267 1267 6
1268 1268 $ try --optimize 'ancestors(6) and not ancestors(4)'
1269 1269 (and
1270 1270 (func
1271 1271 ('symbol', 'ancestors')
1272 1272 ('symbol', '6'))
1273 1273 (not
1274 1274 (func
1275 1275 ('symbol', 'ancestors')
1276 1276 ('symbol', '4'))))
1277 1277 * optimized:
1278 1278 (func
1279 1279 ('symbol', 'only')
1280 1280 (list
1281 1281 ('symbol', '6')
1282 1282 ('symbol', '4')))
1283 1283 * set:
1284 1284 <baseset+ [3, 5, 6]>
1285 1285 3
1286 1286 5
1287 1287 6
1288 1288
1289 1289 no crash by empty group "()" while optimizing to "only()"
1290 1290
1291 1291 $ try --optimize '::1 and ()'
1292 1292 (and
1293 1293 (dagrangepre
1294 1294 ('symbol', '1'))
1295 1295 (group
1296 1296 None))
1297 1297 * optimized:
1298 1298 (and
1299 1299 None
1300 1300 (func
1301 1301 ('symbol', 'ancestors')
1302 1302 ('symbol', '1')))
1303 1303 hg: parse error: missing argument
1304 1304 [255]
1305 1305
1306 1306 we can use patterns when searching for tags
1307 1307
1308 1308 $ log 'tag("1..*")'
1309 1309 abort: tag '1..*' does not exist!
1310 1310 [255]
1311 1311 $ log 'tag("re:1..*")'
1312 1312 6
1313 1313 $ log 'tag("re:[0-9].[0-9]")'
1314 1314 6
1315 1315 $ log 'tag("literal:1.0")'
1316 1316 6
1317 1317 $ log 'tag("re:0..*")'
1318 1318
1319 1319 $ log 'tag(unknown)'
1320 1320 abort: tag 'unknown' does not exist!
1321 1321 [255]
1322 1322 $ log 'tag("re:unknown")'
1323 1323 $ log 'present(tag("unknown"))'
1324 1324 $ log 'present(tag("re:unknown"))'
1325 1325 $ log 'branch(unknown)'
1326 1326 abort: unknown revision 'unknown'!
1327 1327 [255]
1328 1328 $ log 'branch("re:unknown")'
1329 1329 $ log 'present(branch("unknown"))'
1330 1330 $ log 'present(branch("re:unknown"))'
1331 1331 $ log 'user(bob)'
1332 1332 2
1333 1333
1334 1334 $ log '4::8'
1335 1335 4
1336 1336 8
1337 1337 $ log '4:8'
1338 1338 4
1339 1339 5
1340 1340 6
1341 1341 7
1342 1342 8
1343 1343
1344 1344 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
1345 1345 4
1346 1346 2
1347 1347 5
1348 1348
1349 1349 $ log 'not 0 and 0:2'
1350 1350 1
1351 1351 2
1352 1352 $ log 'not 1 and 0:2'
1353 1353 0
1354 1354 2
1355 1355 $ log 'not 2 and 0:2'
1356 1356 0
1357 1357 1
1358 1358 $ log '(1 and 2)::'
1359 1359 $ log '(1 and 2):'
1360 1360 $ log '(1 and 2):3'
1361 1361 $ log 'sort(head(), -rev)'
1362 1362 9
1363 1363 7
1364 1364 6
1365 1365 5
1366 1366 4
1367 1367 3
1368 1368 2
1369 1369 1
1370 1370 0
1371 1371 $ log '4::8 - 8'
1372 1372 4
1373 1373 $ log 'matching(1 or 2 or 3) and (2 or 3 or 1)'
1374 1374 2
1375 1375 3
1376 1376 1
1377 1377
1378 1378 $ log 'named("unknown")'
1379 1379 abort: namespace 'unknown' does not exist!
1380 1380 [255]
1381 1381 $ log 'named("re:unknown")'
1382 1382 abort: no namespace exists that match 'unknown'!
1383 1383 [255]
1384 1384 $ log 'present(named("unknown"))'
1385 1385 $ log 'present(named("re:unknown"))'
1386 1386
1387 1387 $ log 'tag()'
1388 1388 6
1389 1389 $ log 'named("tags")'
1390 1390 6
1391 1391
1392 1392 issue2437
1393 1393
1394 1394 $ log '3 and p1(5)'
1395 1395 3
1396 1396 $ log '4 and p2(6)'
1397 1397 4
1398 1398 $ log '1 and parents(:2)'
1399 1399 1
1400 1400 $ log '2 and children(1:)'
1401 1401 2
1402 1402 $ log 'roots(all()) or roots(all())'
1403 1403 0
1404 1404 $ hg debugrevspec 'roots(all()) or roots(all())'
1405 1405 0
1406 1406 $ log 'heads(branch(é)) or heads(branch(é))'
1407 1407 9
1408 1408 $ log 'ancestors(8) and (heads(branch("-a-b-c-")) or heads(branch(é)))'
1409 1409 4
1410 1410
1411 1411 issue2654: report a parse error if the revset was not completely parsed
1412 1412
1413 1413 $ log '1 OR 2'
1414 1414 hg: parse error at 2: invalid token
1415 1415 [255]
1416 1416
1417 1417 or operator should preserve ordering:
1418 1418 $ log 'reverse(2::4) or tip'
1419 1419 4
1420 1420 2
1421 1421 9
1422 1422
1423 1423 parentrevspec
1424 1424
1425 1425 $ log 'merge()^0'
1426 1426 6
1427 1427 $ log 'merge()^'
1428 1428 5
1429 1429 $ log 'merge()^1'
1430 1430 5
1431 1431 $ log 'merge()^2'
1432 1432 4
1433 1433 $ log 'merge()^^'
1434 1434 3
1435 1435 $ log 'merge()^1^'
1436 1436 3
1437 1437 $ log 'merge()^^^'
1438 1438 1
1439 1439
1440 1440 $ log 'merge()~0'
1441 1441 6
1442 1442 $ log 'merge()~1'
1443 1443 5
1444 1444 $ log 'merge()~2'
1445 1445 3
1446 1446 $ log 'merge()~2^1'
1447 1447 1
1448 1448 $ log 'merge()~3'
1449 1449 1
1450 1450
1451 1451 $ log '(-3:tip)^'
1452 1452 4
1453 1453 6
1454 1454 8
1455 1455
1456 1456 $ log 'tip^foo'
1457 1457 hg: parse error: ^ expects a number 0, 1, or 2
1458 1458 [255]
1459 1459
1460 1460 Bogus function gets suggestions
1461 1461 $ log 'add()'
1462 1462 hg: parse error: unknown identifier: add
1463 1463 (did you mean 'adds'?)
1464 1464 [255]
1465 1465 $ log 'added()'
1466 1466 hg: parse error: unknown identifier: added
1467 1467 (did you mean 'adds'?)
1468 1468 [255]
1469 1469 $ log 'remo()'
1470 1470 hg: parse error: unknown identifier: remo
1471 1471 (did you mean one of remote, removes?)
1472 1472 [255]
1473 1473 $ log 'babar()'
1474 1474 hg: parse error: unknown identifier: babar
1475 1475 [255]
1476 1476
1477 1477 Bogus function with a similar internal name doesn't suggest the internal name
1478 1478 $ log 'matches()'
1479 1479 hg: parse error: unknown identifier: matches
1480 1480 (did you mean 'matching'?)
1481 1481 [255]
1482 1482
1483 1483 Undocumented functions aren't suggested as similar either
1484 1484 $ log 'wdir2()'
1485 1485 hg: parse error: unknown identifier: wdir2
1486 1486 [255]
1487 1487
1488 1488 multiple revspecs
1489 1489
1490 1490 $ hg log -r 'tip~1:tip' -r 'tip~2:tip~1' --template '{rev}\n'
1491 1491 8
1492 1492 9
1493 1493 4
1494 1494 5
1495 1495 6
1496 1496 7
1497 1497
1498 1498 test usage in revpair (with "+")
1499 1499
1500 1500 (real pair)
1501 1501
1502 1502 $ hg diff -r 'tip^^' -r 'tip'
1503 1503 diff -r 2326846efdab -r 24286f4ae135 .hgtags
1504 1504 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1505 1505 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
1506 1506 @@ -0,0 +1,1 @@
1507 1507 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1508 1508 $ hg diff -r 'tip^^::tip'
1509 1509 diff -r 2326846efdab -r 24286f4ae135 .hgtags
1510 1510 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1511 1511 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
1512 1512 @@ -0,0 +1,1 @@
1513 1513 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1514 1514
1515 1515 (single rev)
1516 1516
1517 1517 $ hg diff -r 'tip^' -r 'tip^'
1518 1518 $ hg diff -r 'tip^:tip^'
1519 1519
1520 1520 (single rev that does not looks like a range)
1521 1521
1522 1522 $ hg diff -r 'tip^::tip^ or tip^'
1523 1523 diff -r d5d0dcbdc4d9 .hgtags
1524 1524 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1525 1525 +++ b/.hgtags * (glob)
1526 1526 @@ -0,0 +1,1 @@
1527 1527 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1528 1528 $ hg diff -r 'tip^ or tip^'
1529 1529 diff -r d5d0dcbdc4d9 .hgtags
1530 1530 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1531 1531 +++ b/.hgtags * (glob)
1532 1532 @@ -0,0 +1,1 @@
1533 1533 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1534 1534
1535 1535 (no rev)
1536 1536
1537 1537 $ hg diff -r 'author("babar") or author("celeste")'
1538 1538 abort: empty revision range
1539 1539 [255]
1540 1540
1541 1541 aliases:
1542 1542
1543 1543 $ echo '[revsetalias]' >> .hg/hgrc
1544 1544 $ echo 'm = merge()' >> .hg/hgrc
1545 1545 (revset aliases can override builtin revsets)
1546 1546 $ echo 'p2($1) = p1($1)' >> .hg/hgrc
1547 1547 $ echo 'sincem = descendants(m)' >> .hg/hgrc
1548 1548 $ echo 'd($1) = reverse(sort($1, date))' >> .hg/hgrc
1549 1549 $ echo 'rs(ARG1, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
1550 1550 $ echo 'rs4(ARG1, ARGA, ARGB, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
1551 1551
1552 1552 $ try m
1553 1553 ('symbol', 'm')
1554 1554 (func
1555 1555 ('symbol', 'merge')
1556 1556 None)
1557 1557 * set:
1558 1558 <filteredset
1559 1559 <fullreposet+ 0:9>>
1560 1560 6
1561 1561
1562 1562 $ HGPLAIN=1
1563 1563 $ export HGPLAIN
1564 1564 $ try m
1565 1565 ('symbol', 'm')
1566 1566 abort: unknown revision 'm'!
1567 1567 [255]
1568 1568
1569 1569 $ HGPLAINEXCEPT=revsetalias
1570 1570 $ export HGPLAINEXCEPT
1571 1571 $ try m
1572 1572 ('symbol', 'm')
1573 1573 (func
1574 1574 ('symbol', 'merge')
1575 1575 None)
1576 1576 * set:
1577 1577 <filteredset
1578 1578 <fullreposet+ 0:9>>
1579 1579 6
1580 1580
1581 1581 $ unset HGPLAIN
1582 1582 $ unset HGPLAINEXCEPT
1583 1583
1584 1584 $ try 'p2(.)'
1585 1585 (func
1586 1586 ('symbol', 'p2')
1587 1587 ('symbol', '.'))
1588 1588 (func
1589 1589 ('symbol', 'p1')
1590 1590 ('symbol', '.'))
1591 1591 * set:
1592 1592 <baseset+ [8]>
1593 1593 8
1594 1594
1595 1595 $ HGPLAIN=1
1596 1596 $ export HGPLAIN
1597 1597 $ try 'p2(.)'
1598 1598 (func
1599 1599 ('symbol', 'p2')
1600 1600 ('symbol', '.'))
1601 1601 * set:
1602 1602 <baseset+ []>
1603 1603
1604 1604 $ HGPLAINEXCEPT=revsetalias
1605 1605 $ export HGPLAINEXCEPT
1606 1606 $ try 'p2(.)'
1607 1607 (func
1608 1608 ('symbol', 'p2')
1609 1609 ('symbol', '.'))
1610 1610 (func
1611 1611 ('symbol', 'p1')
1612 1612 ('symbol', '.'))
1613 1613 * set:
1614 1614 <baseset+ [8]>
1615 1615 8
1616 1616
1617 1617 $ unset HGPLAIN
1618 1618 $ unset HGPLAINEXCEPT
1619 1619
1620 1620 test alias recursion
1621 1621
1622 1622 $ try sincem
1623 1623 ('symbol', 'sincem')
1624 1624 (func
1625 1625 ('symbol', 'descendants')
1626 1626 (func
1627 1627 ('symbol', 'merge')
1628 1628 None))
1629 1629 * set:
1630 1630 <addset+
1631 1631 <filteredset
1632 1632 <fullreposet+ 0:9>>,
1633 1633 <generatorset+>>
1634 1634 6
1635 1635 7
1636 1636
1637 1637 test infinite recursion
1638 1638
1639 1639 $ echo 'recurse1 = recurse2' >> .hg/hgrc
1640 1640 $ echo 'recurse2 = recurse1' >> .hg/hgrc
1641 1641 $ try recurse1
1642 1642 ('symbol', 'recurse1')
1643 1643 hg: parse error: infinite expansion of revset alias "recurse1" detected
1644 1644 [255]
1645 1645
1646 1646 $ echo 'level1($1, $2) = $1 or $2' >> .hg/hgrc
1647 1647 $ echo 'level2($1, $2) = level1($2, $1)' >> .hg/hgrc
1648 1648 $ try "level2(level1(1, 2), 3)"
1649 1649 (func
1650 1650 ('symbol', 'level2')
1651 1651 (list
1652 1652 (func
1653 1653 ('symbol', 'level1')
1654 1654 (list
1655 1655 ('symbol', '1')
1656 1656 ('symbol', '2')))
1657 1657 ('symbol', '3')))
1658 1658 (or
1659 1659 ('symbol', '3')
1660 1660 (or
1661 1661 ('symbol', '1')
1662 1662 ('symbol', '2')))
1663 1663 * set:
1664 1664 <addset
1665 1665 <baseset [3]>,
1666 1666 <baseset [1, 2]>>
1667 1667 3
1668 1668 1
1669 1669 2
1670 1670
1671 1671 test nesting and variable passing
1672 1672
1673 1673 $ echo 'nested($1) = nested2($1)' >> .hg/hgrc
1674 1674 $ echo 'nested2($1) = nested3($1)' >> .hg/hgrc
1675 1675 $ echo 'nested3($1) = max($1)' >> .hg/hgrc
1676 1676 $ try 'nested(2:5)'
1677 1677 (func
1678 1678 ('symbol', 'nested')
1679 1679 (range
1680 1680 ('symbol', '2')
1681 1681 ('symbol', '5')))
1682 1682 (func
1683 1683 ('symbol', 'max')
1684 1684 (range
1685 1685 ('symbol', '2')
1686 1686 ('symbol', '5')))
1687 1687 * set:
1688 1688 <baseset [5]>
1689 1689 5
1690 1690
1691 1691 test chained `or` operations are flattened at parsing phase
1692 1692
1693 1693 $ echo 'chainedorops($1, $2, $3) = $1|$2|$3' >> .hg/hgrc
1694 1694 $ try 'chainedorops(0:1, 1:2, 2:3)'
1695 1695 (func
1696 1696 ('symbol', 'chainedorops')
1697 1697 (list
1698 1698 (list
1699 1699 (range
1700 1700 ('symbol', '0')
1701 1701 ('symbol', '1'))
1702 1702 (range
1703 1703 ('symbol', '1')
1704 1704 ('symbol', '2')))
1705 1705 (range
1706 1706 ('symbol', '2')
1707 1707 ('symbol', '3'))))
1708 1708 (or
1709 1709 (range
1710 1710 ('symbol', '0')
1711 1711 ('symbol', '1'))
1712 1712 (range
1713 1713 ('symbol', '1')
1714 1714 ('symbol', '2'))
1715 1715 (range
1716 1716 ('symbol', '2')
1717 1717 ('symbol', '3')))
1718 1718 * set:
1719 1719 <addset
1720 1720 <spanset+ 0:1>,
1721 1721 <addset
1722 1722 <spanset+ 1:2>,
1723 1723 <spanset+ 2:3>>>
1724 1724 0
1725 1725 1
1726 1726 2
1727 1727 3
1728 1728
1729 1729 test variable isolation, variable placeholders are rewritten as string
1730 1730 then parsed and matched again as string. Check they do not leak too
1731 1731 far away.
1732 1732
1733 1733 $ echo 'injectparamasstring = max("$1")' >> .hg/hgrc
1734 1734 $ echo 'callinjection($1) = descendants(injectparamasstring)' >> .hg/hgrc
1735 1735 $ try 'callinjection(2:5)'
1736 1736 (func
1737 1737 ('symbol', 'callinjection')
1738 1738 (range
1739 1739 ('symbol', '2')
1740 1740 ('symbol', '5')))
1741 1741 (func
1742 1742 ('symbol', 'descendants')
1743 1743 (func
1744 1744 ('symbol', 'max')
1745 1745 ('string', '$1')))
1746 1746 abort: unknown revision '$1'!
1747 1747 [255]
1748 1748
1749 1749 $ echo 'injectparamasstring2 = max(_aliasarg("$1"))' >> .hg/hgrc
1750 1750 $ echo 'callinjection2($1) = descendants(injectparamasstring2)' >> .hg/hgrc
1751 1751 $ try 'callinjection2(2:5)'
1752 1752 (func
1753 1753 ('symbol', 'callinjection2')
1754 1754 (range
1755 1755 ('symbol', '2')
1756 1756 ('symbol', '5')))
1757 1757 abort: failed to parse the definition of revset alias "injectparamasstring2": unknown identifier: _aliasarg
1758 1758 [255]
1759 1759 $ hg debugrevspec --debug --config revsetalias.anotherbadone='branch(' "tip"
1760 1760 ('symbol', 'tip')
1761 1761 warning: failed to parse the definition of revset alias "anotherbadone": at 7: not a prefix: end
1762 1762 warning: failed to parse the definition of revset alias "injectparamasstring2": unknown identifier: _aliasarg
1763 1763 * set:
1764 1764 <baseset [9]>
1765 1765 9
1766 1766 >>> data = file('.hg/hgrc', 'rb').read()
1767 1767 >>> file('.hg/hgrc', 'wb').write(data.replace('_aliasarg', ''))
1768 1768
1769 1769 $ try 'tip'
1770 1770 ('symbol', 'tip')
1771 1771 * set:
1772 1772 <baseset [9]>
1773 1773 9
1774 1774
1775 1775 $ hg debugrevspec --debug --config revsetalias.'bad name'='tip' "tip"
1776 1776 ('symbol', 'tip')
1777 1777 warning: failed to parse the declaration of revset alias "bad name": at 4: invalid token
1778 1778 * set:
1779 1779 <baseset [9]>
1780 1780 9
1781 1781 $ echo 'strictreplacing($1, $10) = $10 or desc("$1")' >> .hg/hgrc
1782 1782 $ try 'strictreplacing("foo", tip)'
1783 1783 (func
1784 1784 ('symbol', 'strictreplacing')
1785 1785 (list
1786 1786 ('string', 'foo')
1787 1787 ('symbol', 'tip')))
1788 1788 (or
1789 1789 ('symbol', 'tip')
1790 1790 (func
1791 1791 ('symbol', 'desc')
1792 1792 ('string', '$1')))
1793 1793 * set:
1794 1794 <addset
1795 1795 <baseset [9]>,
1796 1796 <filteredset
1797 1797 <fullreposet+ 0:9>>>
1798 1798 9
1799 1799
1800 1800 $ try 'd(2:5)'
1801 1801 (func
1802 1802 ('symbol', 'd')
1803 1803 (range
1804 1804 ('symbol', '2')
1805 1805 ('symbol', '5')))
1806 1806 (func
1807 1807 ('symbol', 'reverse')
1808 1808 (func
1809 1809 ('symbol', 'sort')
1810 1810 (list
1811 1811 (range
1812 1812 ('symbol', '2')
1813 1813 ('symbol', '5'))
1814 1814 ('symbol', 'date'))))
1815 1815 * set:
1816 1816 <baseset [4, 5, 3, 2]>
1817 1817 4
1818 1818 5
1819 1819 3
1820 1820 2
1821 1821 $ try 'rs(2 or 3, date)'
1822 1822 (func
1823 1823 ('symbol', 'rs')
1824 1824 (list
1825 1825 (or
1826 1826 ('symbol', '2')
1827 1827 ('symbol', '3'))
1828 1828 ('symbol', 'date')))
1829 1829 (func
1830 1830 ('symbol', 'reverse')
1831 1831 (func
1832 1832 ('symbol', 'sort')
1833 1833 (list
1834 1834 (or
1835 1835 ('symbol', '2')
1836 1836 ('symbol', '3'))
1837 1837 ('symbol', 'date'))))
1838 1838 * set:
1839 1839 <baseset [3, 2]>
1840 1840 3
1841 1841 2
1842 1842 $ try 'rs()'
1843 1843 (func
1844 1844 ('symbol', 'rs')
1845 1845 None)
1846 1846 hg: parse error: invalid number of arguments: 0
1847 1847 [255]
1848 1848 $ try 'rs(2)'
1849 1849 (func
1850 1850 ('symbol', 'rs')
1851 1851 ('symbol', '2'))
1852 1852 hg: parse error: invalid number of arguments: 1
1853 1853 [255]
1854 1854 $ try 'rs(2, data, 7)'
1855 1855 (func
1856 1856 ('symbol', 'rs')
1857 1857 (list
1858 1858 (list
1859 1859 ('symbol', '2')
1860 1860 ('symbol', 'data'))
1861 1861 ('symbol', '7')))
1862 1862 hg: parse error: invalid number of arguments: 3
1863 1863 [255]
1864 1864 $ try 'rs4(2 or 3, x, x, date)'
1865 1865 (func
1866 1866 ('symbol', 'rs4')
1867 1867 (list
1868 1868 (list
1869 1869 (list
1870 1870 (or
1871 1871 ('symbol', '2')
1872 1872 ('symbol', '3'))
1873 1873 ('symbol', 'x'))
1874 1874 ('symbol', 'x'))
1875 1875 ('symbol', 'date')))
1876 1876 (func
1877 1877 ('symbol', 'reverse')
1878 1878 (func
1879 1879 ('symbol', 'sort')
1880 1880 (list
1881 1881 (or
1882 1882 ('symbol', '2')
1883 1883 ('symbol', '3'))
1884 1884 ('symbol', 'date'))))
1885 1885 * set:
1886 1886 <baseset [3, 2]>
1887 1887 3
1888 1888 2
1889 1889
1890 1890 issue4553: check that revset aliases override existing hash prefix
1891 1891
1892 1892 $ hg log -qr e
1893 1893 6:e0cc66ef77e8
1894 1894
1895 1895 $ hg log -qr e --config revsetalias.e="all()"
1896 1896 0:2785f51eece5
1897 1897 1:d75937da8da0
1898 1898 2:5ed5505e9f1c
1899 1899 3:8528aa5637f2
1900 1900 4:2326846efdab
1901 1901 5:904fa392b941
1902 1902 6:e0cc66ef77e8
1903 1903 7:013af1973af4
1904 1904 8:d5d0dcbdc4d9
1905 1905 9:24286f4ae135
1906 1906
1907 1907 $ hg log -qr e: --config revsetalias.e="0"
1908 1908 0:2785f51eece5
1909 1909 1:d75937da8da0
1910 1910 2:5ed5505e9f1c
1911 1911 3:8528aa5637f2
1912 1912 4:2326846efdab
1913 1913 5:904fa392b941
1914 1914 6:e0cc66ef77e8
1915 1915 7:013af1973af4
1916 1916 8:d5d0dcbdc4d9
1917 1917 9:24286f4ae135
1918 1918
1919 1919 $ hg log -qr :e --config revsetalias.e="9"
1920 1920 0:2785f51eece5
1921 1921 1:d75937da8da0
1922 1922 2:5ed5505e9f1c
1923 1923 3:8528aa5637f2
1924 1924 4:2326846efdab
1925 1925 5:904fa392b941
1926 1926 6:e0cc66ef77e8
1927 1927 7:013af1973af4
1928 1928 8:d5d0dcbdc4d9
1929 1929 9:24286f4ae135
1930 1930
1931 1931 $ hg log -qr e:
1932 1932 6:e0cc66ef77e8
1933 1933 7:013af1973af4
1934 1934 8:d5d0dcbdc4d9
1935 1935 9:24286f4ae135
1936 1936
1937 1937 $ hg log -qr :e
1938 1938 0:2785f51eece5
1939 1939 1:d75937da8da0
1940 1940 2:5ed5505e9f1c
1941 1941 3:8528aa5637f2
1942 1942 4:2326846efdab
1943 1943 5:904fa392b941
1944 1944 6:e0cc66ef77e8
1945 1945
1946 1946 issue2549 - correct optimizations
1947 1947
1948 1948 $ log 'limit(1 or 2 or 3, 2) and not 2'
1949 1949 1
1950 1950 $ log 'max(1 or 2) and not 2'
1951 1951 $ log 'min(1 or 2) and not 1'
1952 1952 $ log 'last(1 or 2, 1) and not 2'
1953 1953
1954 1954 issue4289 - ordering of built-ins
1955 1955 $ hg log -M -q -r 3:2
1956 1956 3:8528aa5637f2
1957 1957 2:5ed5505e9f1c
1958 1958
1959 1959 test revsets started with 40-chars hash (issue3669)
1960 1960
1961 1961 $ ISSUE3669_TIP=`hg tip --template '{node}'`
1962 1962 $ hg log -r "${ISSUE3669_TIP}" --template '{rev}\n'
1963 1963 9
1964 1964 $ hg log -r "${ISSUE3669_TIP}^" --template '{rev}\n'
1965 1965 8
1966 1966
1967 1967 test or-ed indirect predicates (issue3775)
1968 1968
1969 1969 $ log '6 or 6^1' | sort
1970 1970 5
1971 1971 6
1972 1972 $ log '6^1 or 6' | sort
1973 1973 5
1974 1974 6
1975 1975 $ log '4 or 4~1' | sort
1976 1976 2
1977 1977 4
1978 1978 $ log '4~1 or 4' | sort
1979 1979 2
1980 1980 4
1981 1981 $ log '(0 or 2):(4 or 6) or 0 or 6' | sort
1982 1982 0
1983 1983 1
1984 1984 2
1985 1985 3
1986 1986 4
1987 1987 5
1988 1988 6
1989 1989 $ log '0 or 6 or (0 or 2):(4 or 6)' | sort
1990 1990 0
1991 1991 1
1992 1992 2
1993 1993 3
1994 1994 4
1995 1995 5
1996 1996 6
1997 1997
1998 1998 tests for 'remote()' predicate:
1999 1999 #. (csets in remote) (id) (remote)
2000 2000 1. less than local current branch "default"
2001 2001 2. same with local specified "default"
2002 2002 3. more than local specified specified
2003 2003
2004 2004 $ hg clone --quiet -U . ../remote3
2005 2005 $ cd ../remote3
2006 2006 $ hg update -q 7
2007 2007 $ echo r > r
2008 2008 $ hg ci -Aqm 10
2009 2009 $ log 'remote()'
2010 2010 7
2011 2011 $ log 'remote("a-b-c-")'
2012 2012 2
2013 2013 $ cd ../repo
2014 2014 $ log 'remote(".a.b.c.", "../remote3")'
2015 2015
2016 2016 tests for concatenation of strings/symbols by "##"
2017 2017
2018 2018 $ try "278 ## '5f5' ## 1ee ## 'ce5'"
2019 2019 (_concat
2020 2020 (_concat
2021 2021 (_concat
2022 2022 ('symbol', '278')
2023 2023 ('string', '5f5'))
2024 2024 ('symbol', '1ee'))
2025 2025 ('string', 'ce5'))
2026 2026 ('string', '2785f51eece5')
2027 2027 * set:
2028 2028 <baseset [0]>
2029 2029 0
2030 2030
2031 2031 $ echo 'cat4($1, $2, $3, $4) = $1 ## $2 ## $3 ## $4' >> .hg/hgrc
2032 2032 $ try "cat4(278, '5f5', 1ee, 'ce5')"
2033 2033 (func
2034 2034 ('symbol', 'cat4')
2035 2035 (list
2036 2036 (list
2037 2037 (list
2038 2038 ('symbol', '278')
2039 2039 ('string', '5f5'))
2040 2040 ('symbol', '1ee'))
2041 2041 ('string', 'ce5')))
2042 2042 (_concat
2043 2043 (_concat
2044 2044 (_concat
2045 2045 ('symbol', '278')
2046 2046 ('string', '5f5'))
2047 2047 ('symbol', '1ee'))
2048 2048 ('string', 'ce5'))
2049 2049 ('string', '2785f51eece5')
2050 2050 * set:
2051 2051 <baseset [0]>
2052 2052 0
2053 2053
2054 2054 (check concatenation in alias nesting)
2055 2055
2056 2056 $ echo 'cat2($1, $2) = $1 ## $2' >> .hg/hgrc
2057 2057 $ echo 'cat2x2($1, $2, $3, $4) = cat2($1 ## $2, $3 ## $4)' >> .hg/hgrc
2058 2058 $ log "cat2x2(278, '5f5', 1ee, 'ce5')"
2059 2059 0
2060 2060
2061 2061 (check operator priority)
2062 2062
2063 2063 $ echo 'cat2n2($1, $2, $3, $4) = $1 ## $2 or $3 ## $4~2' >> .hg/hgrc
2064 2064 $ log "cat2n2(2785f5, 1eece5, 24286f, 4ae135)"
2065 2065 0
2066 2066 4
2067 2067
2068 2068 $ cd ..
2069 2069
2070 2070 prepare repository that has "default" branches of multiple roots
2071 2071
2072 2072 $ hg init namedbranch
2073 2073 $ cd namedbranch
2074 2074
2075 2075 $ echo default0 >> a
2076 2076 $ hg ci -Aqm0
2077 2077 $ echo default1 >> a
2078 2078 $ hg ci -m1
2079 2079
2080 2080 $ hg branch -q stable
2081 2081 $ echo stable2 >> a
2082 2082 $ hg ci -m2
2083 2083 $ echo stable3 >> a
2084 2084 $ hg ci -m3
2085 2085
2086 2086 $ hg update -q null
2087 2087 $ echo default4 >> a
2088 2088 $ hg ci -Aqm4
2089 2089 $ echo default5 >> a
2090 2090 $ hg ci -m5
2091 2091
2092 2092 "null" revision belongs to "default" branch (issue4683)
2093 2093
2094 2094 $ log 'branch(null)'
2095 2095 0
2096 2096 1
2097 2097 4
2098 2098 5
2099 2099
2100 2100 "null" revision belongs to "default" branch, but it shouldn't appear in set
2101 2101 unless explicitly specified (issue4682)
2102 2102
2103 2103 $ log 'children(branch(default))'
2104 2104 1
2105 2105 2
2106 2106 5
2107 2107
2108 2108 $ cd ..
2109 2109
2110 2110 test author/desc/keyword in problematic encoding
2111 2111 # unicode: cp932:
2112 2112 # u30A2 0x83 0x41(= 'A')
2113 2113 # u30C2 0x83 0x61(= 'a')
2114 2114
2115 2115 $ hg init problematicencoding
2116 2116 $ cd problematicencoding
2117 2117
2118 2118 $ python > setup.sh <<EOF
2119 2119 > print u'''
2120 2120 > echo a > text
2121 2121 > hg add text
2122 2122 > hg --encoding utf-8 commit -u '\u30A2' -m none
2123 2123 > echo b > text
2124 2124 > hg --encoding utf-8 commit -u '\u30C2' -m none
2125 2125 > echo c > text
2126 2126 > hg --encoding utf-8 commit -u none -m '\u30A2'
2127 2127 > echo d > text
2128 2128 > hg --encoding utf-8 commit -u none -m '\u30C2'
2129 2129 > '''.encode('utf-8')
2130 2130 > EOF
2131 2131 $ sh < setup.sh
2132 2132
2133 2133 test in problematic encoding
2134 2134 $ python > test.sh <<EOF
2135 2135 > print u'''
2136 2136 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30A2)'
2137 2137 > echo ====
2138 2138 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30C2)'
2139 2139 > echo ====
2140 2140 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30A2)'
2141 2141 > echo ====
2142 2142 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30C2)'
2143 2143 > echo ====
2144 2144 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30A2)'
2145 2145 > echo ====
2146 2146 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30C2)'
2147 2147 > '''.encode('cp932')
2148 2148 > EOF
2149 2149 $ sh < test.sh
2150 2150 0
2151 2151 ====
2152 2152 1
2153 2153 ====
2154 2154 2
2155 2155 ====
2156 2156 3
2157 2157 ====
2158 2158 0
2159 2159 2
2160 2160 ====
2161 2161 1
2162 2162 3
2163 2163
2164 2164 test error message of bad revset
2165 2165 $ hg log -r 'foo\\'
2166 2166 hg: parse error at 3: syntax error in revset 'foo\\'
2167 2167 [255]
2168 2168
2169 2169 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now