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