Show More
@@ -96,6 +96,14 class filelog(object): | |||||
96 | def emitrevisiondeltas(self, requests): |
|
96 | def emitrevisiondeltas(self, requests): | |
97 | return self._revlog.emitrevisiondeltas(requests) |
|
97 | return self._revlog.emitrevisiondeltas(requests) | |
98 |
|
98 | |||
|
99 | def emitrevisions(self, nodes, nodesorder=None, | |||
|
100 | revisiondata=False, assumehaveparentrevisions=False, | |||
|
101 | deltaprevious=False): | |||
|
102 | return self._revlog.emitrevisions( | |||
|
103 | nodes, nodesorder=nodesorder, revisiondata=revisiondata, | |||
|
104 | assumehaveparentrevisions=assumehaveparentrevisions, | |||
|
105 | deltaprevious=deltaprevious) | |||
|
106 | ||||
99 | def addrevision(self, revisiondata, transaction, linkrev, p1, p2, |
|
107 | def addrevision(self, revisiondata, transaction, linkrev, p1, p2, | |
100 | node=None, flags=revlog.REVIDX_DEFAULT_FLAGS, |
|
108 | node=None, flags=revlog.REVIDX_DEFAULT_FLAGS, | |
101 | cachedelta=None): |
|
109 | cachedelta=None): |
@@ -1565,6 +1565,14 class manifestrevlog(object): | |||||
1565 | def emitrevisiondeltas(self, requests): |
|
1565 | def emitrevisiondeltas(self, requests): | |
1566 | return self._revlog.emitrevisiondeltas(requests) |
|
1566 | return self._revlog.emitrevisiondeltas(requests) | |
1567 |
|
1567 | |||
|
1568 | def emitrevisions(self, nodes, nodesorder=None, | |||
|
1569 | revisiondata=False, assumehaveparentrevisions=False, | |||
|
1570 | deltaprevious=False): | |||
|
1571 | return self._revlog.emitrevisions( | |||
|
1572 | nodes, nodesorder=nodesorder, revisiondata=revisiondata, | |||
|
1573 | assumehaveparentrevisions=assumehaveparentrevisions, | |||
|
1574 | deltaprevious=deltaprevious) | |||
|
1575 | ||||
1568 | def addgroup(self, deltas, linkmapper, transaction, addrevisioncb=None): |
|
1576 | def addgroup(self, deltas, linkmapper, transaction, addrevisioncb=None): | |
1569 | return self._revlog.addgroup(deltas, linkmapper, transaction, |
|
1577 | return self._revlog.addgroup(deltas, linkmapper, transaction, | |
1570 | addrevisioncb=addrevisioncb) |
|
1578 | addrevisioncb=addrevisioncb) |
@@ -654,6 +654,59 class ifiledata(interfaceutil.Interface) | |||||
654 | delta against a censored revision. |
|
654 | delta against a censored revision. | |
655 | """ |
|
655 | """ | |
656 |
|
656 | |||
|
657 | def emitrevisions(nodes, | |||
|
658 | nodesorder=None, | |||
|
659 | revisiondata=False, | |||
|
660 | assumehaveparentrevisions=False, | |||
|
661 | deltaprevious=False): | |||
|
662 | """Produce ``irevisiondelta`` for revisions. | |||
|
663 | ||||
|
664 | Given an iterable of nodes, emits objects conforming to the | |||
|
665 | ``irevisiondelta`` interface that describe revisions in storage. | |||
|
666 | ||||
|
667 | This method is a generator. | |||
|
668 | ||||
|
669 | The input nodes may be unordered. Implementations must ensure that a | |||
|
670 | node's parents are emitted before the node itself. Transitively, this | |||
|
671 | means that a node may only be emitted once all its ancestors in | |||
|
672 | ``nodes`` have also been emitted. | |||
|
673 | ||||
|
674 | By default, emits "index" data (the ``node``, ``p1node``, and | |||
|
675 | ``p2node`` attributes). If ``revisiondata`` is set, revision data | |||
|
676 | will also be present on the emitted objects. | |||
|
677 | ||||
|
678 | With default argument values, implementations can choose to emit | |||
|
679 | either fulltext revision data or a delta. When emitting deltas, | |||
|
680 | implementations must consider whether the delta's base revision | |||
|
681 | fulltext is available to the receiver. | |||
|
682 | ||||
|
683 | The base revision fulltext is guaranteed to be available if any of | |||
|
684 | the following are met: | |||
|
685 | ||||
|
686 | * Its fulltext revision was emitted by this method call. | |||
|
687 | * A delta for that revision was emitted by this method call. | |||
|
688 | * ``assumehaveparentrevisions`` is True and the base revision is a | |||
|
689 | parent of the node. | |||
|
690 | ||||
|
691 | ``nodesorder`` can be used to control the order that revisions are | |||
|
692 | emitted. By default, revisions can be reordered as long as they are | |||
|
693 | in DAG topological order (see above). If the value is ``nodes``, | |||
|
694 | the iteration order from ``nodes`` should be used. If the value is | |||
|
695 | ``storage``, then the native order from the backing storage layer | |||
|
696 | is used. (Not all storage layers will have strong ordering and behavior | |||
|
697 | of this mode is storage-dependent.) ``nodes`` ordering can force | |||
|
698 | revisions to be emitted before their ancestors, so consumers should | |||
|
699 | use it with care. | |||
|
700 | ||||
|
701 | The ``linknode`` attribute on the returned ``irevisiondelta`` may not | |||
|
702 | be set and it is the caller's responsibility to resolve it, if needed. | |||
|
703 | ||||
|
704 | If ``deltaprevious`` is True and revision data is requested, all | |||
|
705 | revision data should be emitted as deltas against the revision | |||
|
706 | emitted just prior. The initial revision should be a delta against | |||
|
707 | its 1st parent. | |||
|
708 | """ | |||
|
709 | ||||
657 | class ifilemutation(interfaceutil.Interface): |
|
710 | class ifilemutation(interfaceutil.Interface): | |
658 | """Storage interface for mutation events of a tracked file.""" |
|
711 | """Storage interface for mutation events of a tracked file.""" | |
659 |
|
712 | |||
@@ -1127,6 +1180,15 class imanifeststorage(interfaceutil.Int | |||||
1127 | See the documentation for ``ifiledata`` for more. |
|
1180 | See the documentation for ``ifiledata`` for more. | |
1128 | """ |
|
1181 | """ | |
1129 |
|
1182 | |||
|
1183 | def emitrevisions(nodes, | |||
|
1184 | nodesorder=None, | |||
|
1185 | revisiondata=False, | |||
|
1186 | assumehaveparentrevisions=False): | |||
|
1187 | """Produce ``irevisiondelta`` describing revisions. | |||
|
1188 | ||||
|
1189 | See the documentation for ``ifiledata`` for more. | |||
|
1190 | """ | |||
|
1191 | ||||
1130 | def addgroup(deltas, linkmapper, transaction, addrevisioncb=None): |
|
1192 | def addgroup(deltas, linkmapper, transaction, addrevisioncb=None): | |
1131 | """Process a series of deltas for storage. |
|
1193 | """Process a series of deltas for storage. | |
1132 |
|
1194 |
@@ -59,6 +59,7 from .thirdparty import ( | |||||
59 | ) |
|
59 | ) | |
60 | from . import ( |
|
60 | from . import ( | |
61 | ancestor, |
|
61 | ancestor, | |
|
62 | dagop, | |||
62 | error, |
|
63 | error, | |
63 | mdiff, |
|
64 | mdiff, | |
64 | policy, |
|
65 | policy, | |
@@ -242,17 +243,17 class _revisioninfo(object): | |||||
242 | flags = attr.ib() |
|
243 | flags = attr.ib() | |
243 |
|
244 | |||
244 | @interfaceutil.implementer(repository.irevisiondelta) |
|
245 | @interfaceutil.implementer(repository.irevisiondelta) | |
245 |
@attr.s(slots=True |
|
246 | @attr.s(slots=True) | |
246 | class revlogrevisiondelta(object): |
|
247 | class revlogrevisiondelta(object): | |
247 | node = attr.ib() |
|
248 | node = attr.ib() | |
248 | p1node = attr.ib() |
|
249 | p1node = attr.ib() | |
249 | p2node = attr.ib() |
|
250 | p2node = attr.ib() | |
250 | basenode = attr.ib() |
|
251 | basenode = attr.ib() | |
251 | linknode = attr.ib() |
|
|||
252 | flags = attr.ib() |
|
252 | flags = attr.ib() | |
253 | baserevisionsize = attr.ib() |
|
253 | baserevisionsize = attr.ib() | |
254 | revision = attr.ib() |
|
254 | revision = attr.ib() | |
255 | delta = attr.ib() |
|
255 | delta = attr.ib() | |
|
256 | linknode = attr.ib(default=None) | |||
256 |
|
257 | |||
257 | @interfaceutil.implementer(repository.iverifyproblem) |
|
258 | @interfaceutil.implementer(repository.iverifyproblem) | |
258 | @attr.s(frozen=True) |
|
259 | @attr.s(frozen=True) | |
@@ -2374,6 +2375,122 class revlog(object): | |||||
2374 |
|
2375 | |||
2375 | prevrev = rev |
|
2376 | prevrev = rev | |
2376 |
|
2377 | |||
|
2378 | def emitrevisions(self, nodes, nodesorder=None, revisiondata=False, | |||
|
2379 | assumehaveparentrevisions=False, deltaprevious=False): | |||
|
2380 | if nodesorder not in ('nodes', 'storage', None): | |||
|
2381 | raise error.ProgrammingError('unhandled value for nodesorder: %s' % | |||
|
2382 | nodesorder) | |||
|
2383 | ||||
|
2384 | if nodesorder is None and not self._generaldelta: | |||
|
2385 | nodesorder = 'storage' | |||
|
2386 | ||||
|
2387 | frev = self.rev | |||
|
2388 | fnode = self.node | |||
|
2389 | ||||
|
2390 | if nodesorder == 'nodes': | |||
|
2391 | revs = [frev(n) for n in nodes] | |||
|
2392 | elif nodesorder == 'storage': | |||
|
2393 | revs = sorted(frev(n) for n in nodes) | |||
|
2394 | else: | |||
|
2395 | assert self._generaldelta | |||
|
2396 | revs = set(frev(n) for n in nodes) | |||
|
2397 | revs = dagop.linearize(revs, self.parentrevs) | |||
|
2398 | ||||
|
2399 | prevrev = None | |||
|
2400 | ||||
|
2401 | if deltaprevious or assumehaveparentrevisions: | |||
|
2402 | prevrev = self.parentrevs(revs[0])[0] | |||
|
2403 | ||||
|
2404 | # Set of revs available to delta against. | |||
|
2405 | available = set() | |||
|
2406 | ||||
|
2407 | for rev in revs: | |||
|
2408 | if rev == nullrev: | |||
|
2409 | continue | |||
|
2410 | ||||
|
2411 | node = fnode(rev) | |||
|
2412 | deltaparentrev = self.deltaparent(rev) | |||
|
2413 | p1rev, p2rev = self.parentrevs(rev) | |||
|
2414 | ||||
|
2415 | # Forced delta against previous mode. | |||
|
2416 | if deltaprevious: | |||
|
2417 | baserev = prevrev | |||
|
2418 | ||||
|
2419 | # Revlog is configured to use full snapshots. Stick to that. | |||
|
2420 | elif not self._storedeltachains: | |||
|
2421 | baserev = nullrev | |||
|
2422 | ||||
|
2423 | # There is a delta in storage. We try to use that because it | |||
|
2424 | # amounts to effectively copying data from storage and is | |||
|
2425 | # therefore the fastest. | |||
|
2426 | elif deltaparentrev != nullrev: | |||
|
2427 | # Base revision was already emitted in this group. We can | |||
|
2428 | # always safely use the delta. | |||
|
2429 | if deltaparentrev in available: | |||
|
2430 | baserev = deltaparentrev | |||
|
2431 | ||||
|
2432 | # Base revision is a parent that hasn't been emitted already. | |||
|
2433 | # Use it if we can assume the receiver has the parent revision. | |||
|
2434 | elif (assumehaveparentrevisions | |||
|
2435 | and deltaparentrev in (p1rev, p2rev)): | |||
|
2436 | baserev = deltaparentrev | |||
|
2437 | ||||
|
2438 | # No guarantee the receiver has the delta parent. Send delta | |||
|
2439 | # against last revision (if possible), which in the common case | |||
|
2440 | # should be similar enough to this revision that the delta is | |||
|
2441 | # reasonable. | |||
|
2442 | elif prevrev is not None: | |||
|
2443 | baserev = prevrev | |||
|
2444 | else: | |||
|
2445 | baserev = nullrev | |||
|
2446 | ||||
|
2447 | # Storage has a fulltext revision. | |||
|
2448 | ||||
|
2449 | # Let's use the previous revision, which is as good a guess as any. | |||
|
2450 | # There is definitely room to improve this logic. | |||
|
2451 | elif prevrev is not None: | |||
|
2452 | baserev = prevrev | |||
|
2453 | else: | |||
|
2454 | baserev = nullrev | |||
|
2455 | ||||
|
2456 | # But we can't actually use our chosen delta base for whatever | |||
|
2457 | # reason. Reset to fulltext. | |||
|
2458 | if baserev != nullrev and not self.candelta(baserev, rev): | |||
|
2459 | baserev = nullrev | |||
|
2460 | ||||
|
2461 | revision = None | |||
|
2462 | delta = None | |||
|
2463 | baserevisionsize = None | |||
|
2464 | ||||
|
2465 | if revisiondata: | |||
|
2466 | if self.iscensored(baserev) or self.iscensored(rev): | |||
|
2467 | try: | |||
|
2468 | revision = self.revision(node, raw=True) | |||
|
2469 | except error.CensoredNodeError as e: | |||
|
2470 | revision = e.tombstone | |||
|
2471 | ||||
|
2472 | if baserev != nullrev: | |||
|
2473 | baserevisionsize = self.rawsize(baserev) | |||
|
2474 | ||||
|
2475 | elif baserev == nullrev and not deltaprevious: | |||
|
2476 | revision = self.revision(node, raw=True) | |||
|
2477 | available.add(rev) | |||
|
2478 | else: | |||
|
2479 | delta = self.revdiff(baserev, rev) | |||
|
2480 | available.add(rev) | |||
|
2481 | ||||
|
2482 | yield revlogrevisiondelta( | |||
|
2483 | node=node, | |||
|
2484 | p1node=fnode(p1rev), | |||
|
2485 | p2node=fnode(p2rev), | |||
|
2486 | basenode=fnode(baserev), | |||
|
2487 | flags=self.flags(rev), | |||
|
2488 | baserevisionsize=baserevisionsize, | |||
|
2489 | revision=revision, | |||
|
2490 | delta=delta) | |||
|
2491 | ||||
|
2492 | prevrev = rev | |||
|
2493 | ||||
2377 | DELTAREUSEALWAYS = 'always' |
|
2494 | DELTAREUSEALWAYS = 'always' | |
2378 | DELTAREUSESAMEREVS = 'samerevs' |
|
2495 | DELTAREUSESAMEREVS = 'samerevs' | |
2379 | DELTAREUSENEVER = 'never' |
|
2496 | DELTAREUSENEVER = 'never' |
@@ -500,6 +500,20 class ifiledatatests(basetestcase): | |||||
500 | with self.assertRaises(StopIteration): |
|
500 | with self.assertRaises(StopIteration): | |
501 | next(gen) |
|
501 | next(gen) | |
502 |
|
502 | |||
|
503 | # Emitting empty list is an empty generator. | |||
|
504 | gen = f.emitrevisions([]) | |||
|
505 | with self.assertRaises(StopIteration): | |||
|
506 | next(gen) | |||
|
507 | ||||
|
508 | # Emitting null node yields nothing. | |||
|
509 | gen = f.emitrevisions([nullid]) | |||
|
510 | with self.assertRaises(StopIteration): | |||
|
511 | next(gen) | |||
|
512 | ||||
|
513 | # Requesting unknown node fails. | |||
|
514 | with self.assertRaises(error.LookupError): | |||
|
515 | list(f.emitrevisions([b'\x01' * 20])) | |||
|
516 | ||||
503 | def testsinglerevision(self): |
|
517 | def testsinglerevision(self): | |
504 | fulltext = b'initial' |
|
518 | fulltext = b'initial' | |
505 |
|
519 | |||
@@ -566,6 +580,42 class ifiledatatests(basetestcase): | |||||
566 | with self.assertRaises(StopIteration): |
|
580 | with self.assertRaises(StopIteration): | |
567 | next(gen) |
|
581 | next(gen) | |
568 |
|
582 | |||
|
583 | # Emitting a single revision works. | |||
|
584 | gen = f.emitrevisions([node]) | |||
|
585 | rev = next(gen) | |||
|
586 | ||||
|
587 | self.assertEqual(rev.node, node) | |||
|
588 | self.assertEqual(rev.p1node, nullid) | |||
|
589 | self.assertEqual(rev.p2node, nullid) | |||
|
590 | self.assertIsNone(rev.linknode) | |||
|
591 | self.assertEqual(rev.basenode, nullid) | |||
|
592 | self.assertIsNone(rev.baserevisionsize) | |||
|
593 | self.assertIsNone(rev.revision) | |||
|
594 | self.assertIsNone(rev.delta) | |||
|
595 | ||||
|
596 | with self.assertRaises(StopIteration): | |||
|
597 | next(gen) | |||
|
598 | ||||
|
599 | # Requesting revision data works. | |||
|
600 | gen = f.emitrevisions([node], revisiondata=True) | |||
|
601 | rev = next(gen) | |||
|
602 | ||||
|
603 | self.assertEqual(rev.node, node) | |||
|
604 | self.assertEqual(rev.p1node, nullid) | |||
|
605 | self.assertEqual(rev.p2node, nullid) | |||
|
606 | self.assertIsNone(rev.linknode) | |||
|
607 | self.assertEqual(rev.basenode, nullid) | |||
|
608 | self.assertIsNone(rev.baserevisionsize) | |||
|
609 | self.assertEqual(rev.revision, fulltext) | |||
|
610 | self.assertIsNone(rev.delta) | |||
|
611 | ||||
|
612 | with self.assertRaises(StopIteration): | |||
|
613 | next(gen) | |||
|
614 | ||||
|
615 | # Emitting an unknown node after a known revision results in error. | |||
|
616 | with self.assertRaises(error.LookupError): | |||
|
617 | list(f.emitrevisions([node, b'\x01' * 20])) | |||
|
618 | ||||
569 | def testmultiplerevisions(self): |
|
619 | def testmultiplerevisions(self): | |
570 | fulltext0 = b'x' * 1024 |
|
620 | fulltext0 = b'x' * 1024 | |
571 | fulltext1 = fulltext0 + b'y' |
|
621 | fulltext1 = fulltext0 + b'y' | |
@@ -697,6 +747,208 class ifiledatatests(basetestcase): | |||||
697 | with self.assertRaises(StopIteration): |
|
747 | with self.assertRaises(StopIteration): | |
698 | next(gen) |
|
748 | next(gen) | |
699 |
|
749 | |||
|
750 | # Nodes should be emitted in order. | |||
|
751 | gen = f.emitrevisions([node0, node1, node2], revisiondata=True) | |||
|
752 | ||||
|
753 | rev = next(gen) | |||
|
754 | ||||
|
755 | self.assertEqual(rev.node, node0) | |||
|
756 | self.assertEqual(rev.p1node, nullid) | |||
|
757 | self.assertEqual(rev.p2node, nullid) | |||
|
758 | self.assertIsNone(rev.linknode) | |||
|
759 | self.assertEqual(rev.basenode, nullid) | |||
|
760 | self.assertIsNone(rev.baserevisionsize) | |||
|
761 | self.assertEqual(rev.revision, fulltext0) | |||
|
762 | self.assertIsNone(rev.delta) | |||
|
763 | ||||
|
764 | rev = next(gen) | |||
|
765 | ||||
|
766 | self.assertEqual(rev.node, node1) | |||
|
767 | self.assertEqual(rev.p1node, node0) | |||
|
768 | self.assertEqual(rev.p2node, nullid) | |||
|
769 | self.assertIsNone(rev.linknode) | |||
|
770 | self.assertEqual(rev.basenode, node0) | |||
|
771 | self.assertIsNone(rev.baserevisionsize) | |||
|
772 | self.assertIsNone(rev.revision) | |||
|
773 | self.assertEqual(rev.delta, | |||
|
774 | b'\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x01' + | |||
|
775 | fulltext1) | |||
|
776 | ||||
|
777 | rev = next(gen) | |||
|
778 | ||||
|
779 | self.assertEqual(rev.node, node2) | |||
|
780 | self.assertEqual(rev.p1node, node1) | |||
|
781 | self.assertEqual(rev.p2node, nullid) | |||
|
782 | self.assertIsNone(rev.linknode) | |||
|
783 | self.assertEqual(rev.basenode, node1) | |||
|
784 | self.assertIsNone(rev.baserevisionsize) | |||
|
785 | self.assertIsNone(rev.revision) | |||
|
786 | self.assertEqual(rev.delta, | |||
|
787 | b'\x00\x00\x00\x00\x00\x00\x04\x01\x00\x00\x04\x02' + | |||
|
788 | fulltext2) | |||
|
789 | ||||
|
790 | with self.assertRaises(StopIteration): | |||
|
791 | next(gen) | |||
|
792 | ||||
|
793 | # Request not in DAG order is reordered to be in DAG order. | |||
|
794 | gen = f.emitrevisions([node2, node1, node0], revisiondata=True) | |||
|
795 | ||||
|
796 | rev = next(gen) | |||
|
797 | ||||
|
798 | self.assertEqual(rev.node, node0) | |||
|
799 | self.assertEqual(rev.p1node, nullid) | |||
|
800 | self.assertEqual(rev.p2node, nullid) | |||
|
801 | self.assertIsNone(rev.linknode) | |||
|
802 | self.assertEqual(rev.basenode, nullid) | |||
|
803 | self.assertIsNone(rev.baserevisionsize) | |||
|
804 | self.assertEqual(rev.revision, fulltext0) | |||
|
805 | self.assertIsNone(rev.delta) | |||
|
806 | ||||
|
807 | rev = next(gen) | |||
|
808 | ||||
|
809 | self.assertEqual(rev.node, node1) | |||
|
810 | self.assertEqual(rev.p1node, node0) | |||
|
811 | self.assertEqual(rev.p2node, nullid) | |||
|
812 | self.assertIsNone(rev.linknode) | |||
|
813 | self.assertEqual(rev.basenode, node0) | |||
|
814 | self.assertIsNone(rev.baserevisionsize) | |||
|
815 | self.assertIsNone(rev.revision) | |||
|
816 | self.assertEqual(rev.delta, | |||
|
817 | b'\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x01' + | |||
|
818 | fulltext1) | |||
|
819 | ||||
|
820 | rev = next(gen) | |||
|
821 | ||||
|
822 | self.assertEqual(rev.node, node2) | |||
|
823 | self.assertEqual(rev.p1node, node1) | |||
|
824 | self.assertEqual(rev.p2node, nullid) | |||
|
825 | self.assertIsNone(rev.linknode) | |||
|
826 | self.assertEqual(rev.basenode, node1) | |||
|
827 | self.assertIsNone(rev.baserevisionsize) | |||
|
828 | self.assertIsNone(rev.revision) | |||
|
829 | self.assertEqual(rev.delta, | |||
|
830 | b'\x00\x00\x00\x00\x00\x00\x04\x01\x00\x00\x04\x02' + | |||
|
831 | fulltext2) | |||
|
832 | ||||
|
833 | with self.assertRaises(StopIteration): | |||
|
834 | next(gen) | |||
|
835 | ||||
|
836 | # Unrecognized nodesorder value raises ProgrammingError. | |||
|
837 | with self.assertRaises(error.ProgrammingError): | |||
|
838 | list(f.emitrevisions([], nodesorder='bad')) | |||
|
839 | ||||
|
840 | # nodesorder=storage is recognized. But we can't test it thoroughly | |||
|
841 | # because behavior is storage-dependent. | |||
|
842 | res = list(f.emitrevisions([node2, node1, node0], | |||
|
843 | nodesorder='storage')) | |||
|
844 | self.assertEqual(len(res), 3) | |||
|
845 | self.assertEqual({o.node for o in res}, {node0, node1, node2}) | |||
|
846 | ||||
|
847 | # nodesorder=nodes forces the order. | |||
|
848 | gen = f.emitrevisions([node2, node0], nodesorder='nodes', | |||
|
849 | revisiondata=True) | |||
|
850 | ||||
|
851 | rev = next(gen) | |||
|
852 | self.assertEqual(rev.node, node2) | |||
|
853 | self.assertEqual(rev.p1node, node1) | |||
|
854 | self.assertEqual(rev.p2node, nullid) | |||
|
855 | self.assertEqual(rev.basenode, nullid) | |||
|
856 | self.assertIsNone(rev.baserevisionsize) | |||
|
857 | self.assertEqual(rev.revision, fulltext2) | |||
|
858 | self.assertIsNone(rev.delta) | |||
|
859 | ||||
|
860 | rev = next(gen) | |||
|
861 | self.assertEqual(rev.node, node0) | |||
|
862 | self.assertEqual(rev.p1node, nullid) | |||
|
863 | self.assertEqual(rev.p2node, nullid) | |||
|
864 | # Delta behavior is storage dependent, so we can't easily test it. | |||
|
865 | ||||
|
866 | with self.assertRaises(StopIteration): | |||
|
867 | next(gen) | |||
|
868 | ||||
|
869 | # assumehaveparentrevisions=False (the default) won't send a delta for | |||
|
870 | # the first revision. | |||
|
871 | gen = f.emitrevisions({node2, node1}, revisiondata=True) | |||
|
872 | ||||
|
873 | rev = next(gen) | |||
|
874 | self.assertEqual(rev.node, node1) | |||
|
875 | self.assertEqual(rev.p1node, node0) | |||
|
876 | self.assertEqual(rev.p2node, nullid) | |||
|
877 | self.assertEqual(rev.basenode, nullid) | |||
|
878 | self.assertIsNone(rev.baserevisionsize) | |||
|
879 | self.assertEqual(rev.revision, fulltext1) | |||
|
880 | self.assertIsNone(rev.delta) | |||
|
881 | ||||
|
882 | rev = next(gen) | |||
|
883 | self.assertEqual(rev.node, node2) | |||
|
884 | self.assertEqual(rev.p1node, node1) | |||
|
885 | self.assertEqual(rev.p2node, nullid) | |||
|
886 | self.assertEqual(rev.basenode, node1) | |||
|
887 | self.assertIsNone(rev.baserevisionsize) | |||
|
888 | self.assertIsNone(rev.revision) | |||
|
889 | self.assertEqual(rev.delta, | |||
|
890 | b'\x00\x00\x00\x00\x00\x00\x04\x01\x00\x00\x04\x02' + | |||
|
891 | fulltext2) | |||
|
892 | ||||
|
893 | with self.assertRaises(StopIteration): | |||
|
894 | next(gen) | |||
|
895 | ||||
|
896 | # assumehaveparentrevisions=True allows delta against initial revision. | |||
|
897 | gen = f.emitrevisions([node2, node1], | |||
|
898 | revisiondata=True, assumehaveparentrevisions=True) | |||
|
899 | ||||
|
900 | rev = next(gen) | |||
|
901 | self.assertEqual(rev.node, node1) | |||
|
902 | self.assertEqual(rev.p1node, node0) | |||
|
903 | self.assertEqual(rev.p2node, nullid) | |||
|
904 | self.assertEqual(rev.basenode, node0) | |||
|
905 | self.assertIsNone(rev.baserevisionsize) | |||
|
906 | self.assertIsNone(rev.revision) | |||
|
907 | self.assertEqual(rev.delta, | |||
|
908 | b'\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x01' + | |||
|
909 | fulltext1) | |||
|
910 | ||||
|
911 | # forceprevious=True forces a delta against the previous revision. | |||
|
912 | # Special case for initial revision. | |||
|
913 | gen = f.emitrevisions([node0], revisiondata=True, deltaprevious=True) | |||
|
914 | ||||
|
915 | rev = next(gen) | |||
|
916 | self.assertEqual(rev.node, node0) | |||
|
917 | self.assertEqual(rev.p1node, nullid) | |||
|
918 | self.assertEqual(rev.p2node, nullid) | |||
|
919 | self.assertEqual(rev.basenode, nullid) | |||
|
920 | self.assertIsNone(rev.baserevisionsize) | |||
|
921 | self.assertIsNone(rev.revision) | |||
|
922 | self.assertEqual(rev.delta, | |||
|
923 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00' + | |||
|
924 | fulltext0) | |||
|
925 | ||||
|
926 | with self.assertRaises(StopIteration): | |||
|
927 | next(gen) | |||
|
928 | ||||
|
929 | gen = f.emitrevisions([node0, node2], revisiondata=True, | |||
|
930 | deltaprevious=True) | |||
|
931 | ||||
|
932 | rev = next(gen) | |||
|
933 | self.assertEqual(rev.node, node0) | |||
|
934 | self.assertEqual(rev.p1node, nullid) | |||
|
935 | self.assertEqual(rev.p2node, nullid) | |||
|
936 | self.assertEqual(rev.basenode, nullid) | |||
|
937 | self.assertIsNone(rev.baserevisionsize) | |||
|
938 | self.assertIsNone(rev.revision) | |||
|
939 | self.assertEqual(rev.delta, | |||
|
940 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00' + | |||
|
941 | fulltext0) | |||
|
942 | ||||
|
943 | rev = next(gen) | |||
|
944 | self.assertEqual(rev.node, node2) | |||
|
945 | self.assertEqual(rev.p1node, node1) | |||
|
946 | self.assertEqual(rev.p2node, nullid) | |||
|
947 | self.assertEqual(rev.basenode, node0) | |||
|
948 | ||||
|
949 | with self.assertRaises(StopIteration): | |||
|
950 | next(gen) | |||
|
951 | ||||
700 | def testrenamed(self): |
|
952 | def testrenamed(self): | |
701 | fulltext0 = b'foo' |
|
953 | fulltext0 = b'foo' | |
702 | fulltext1 = b'bar' |
|
954 | fulltext1 = b'bar' |
General Comments 0
You need to be logged in to leave comments.
Login now