669
671
self.tree1.commit('removed', rev_id=b'a@cset-0-3')
671
bundle = self.get_valid_bundle('a@cset-0-2', 'a@cset-0-3')
673
bundle = self.get_valid_bundle(b'a@cset-0-2', b'a@cset-0-3')
672
674
self.assertRaises((errors.TestamentMismatch,
673
675
errors.VersionedFileInvalidChecksum,
674
676
errors.BadBundle), self.get_invalid_bundle,
675
'a@cset-0-2', 'a@cset-0-3')
677
b'a@cset-0-2', b'a@cset-0-3')
676
678
# Check a rollup bundle
677
bundle = self.get_valid_bundle('null:', 'a@cset-0-3')
679
bundle = self.get_valid_bundle(b'null:', b'a@cset-0-3')
679
681
# Now move the directory
680
682
self.tree1.rename_one('dir', 'sub/dir')
681
683
self.tree1.commit('rename dir', rev_id=b'a@cset-0-4')
683
bundle = self.get_valid_bundle('a@cset-0-3', 'a@cset-0-4')
685
bundle = self.get_valid_bundle(b'a@cset-0-3', b'a@cset-0-4')
684
686
# Check a rollup bundle
685
bundle = self.get_valid_bundle('null:', 'a@cset-0-4')
687
bundle = self.get_valid_bundle(b'null:', b'a@cset-0-4')
688
with open('b1/sub/dir/WithCaps.txt', 'ab') as f: f.write('\nAdding some text\n')
690
with open('b1/sub/dir/WithCaps.txt', 'ab') as f: f.write(b'\nAdding some text\n')
689
691
with open('b1/sub/dir/ pre space', 'ab') as f: f.write(
690
'\r\nAdding some\r\nDOS format lines\r\n')
691
with open('b1/sub/dir/nolastnewline.txt', 'ab') as f: f.write('\n')
692
b'\r\nAdding some\r\nDOS format lines\r\n')
693
with open('b1/sub/dir/nolastnewline.txt', 'ab') as f: f.write(b'\n')
692
694
self.tree1.rename_one('sub/dir/ pre space',
693
695
'sub/ start space')
694
696
self.tree1.commit('Modified files', rev_id=b'a@cset-0-5')
695
bundle = self.get_valid_bundle('a@cset-0-4', 'a@cset-0-5')
697
bundle = self.get_valid_bundle(b'a@cset-0-4', b'a@cset-0-5')
697
699
self.tree1.rename_one('sub/dir/WithCaps.txt', 'temp')
698
700
self.tree1.rename_one('with space.txt', 'WithCaps.txt')
699
701
self.tree1.rename_one('temp', 'with space.txt')
700
702
self.tree1.commit(u'swap filenames', rev_id=b'a@cset-0-6',
702
bundle = self.get_valid_bundle('a@cset-0-5', 'a@cset-0-6')
703
other = self.get_checkout('a@cset-0-5')
704
bundle = self.get_valid_bundle(b'a@cset-0-5', b'a@cset-0-6')
705
other = self.get_checkout(b'a@cset-0-5')
704
706
tree1_inv = get_inventory_text(self.tree1.branch.repository,
706
708
tree2_inv = get_inventory_text(other.branch.repository,
708
710
self.assertEqualDiff(tree1_inv, tree2_inv)
709
711
other.rename_one('sub/dir/nolastnewline.txt', 'sub/nolastnewline.txt')
710
712
other.commit('rename file', rev_id=b'a@cset-0-6b')
711
713
self.tree1.merge_from_branch(other.branch)
712
714
self.tree1.commit(u'Merge', rev_id=b'a@cset-0-7',
714
bundle = self.get_valid_bundle('a@cset-0-6', 'a@cset-0-7')
716
bundle = self.get_valid_bundle(b'a@cset-0-6', b'a@cset-0-7')
716
718
def _test_symlink_bundle(self, link_name, link_target, new_link_target):
719
721
self.requireFeature(features.SymlinkFeature)
720
722
self.tree1 = self.make_branch_and_tree('b1')
851
853
with open('b1/one', 'wb') as f: f.write(b'three\n')
852
854
self.tree1.commit('modify', rev_id=b'a@cset-0-3')
853
855
bundle_file = BytesIO()
854
rev_ids = write_bundle(self.tree1.branch.repository, 'a@cset-0-3',
855
'a@cset-0-1', bundle_file, format=self.format)
856
self.assertNotContainsRe(bundle_file.getvalue(), '\btwo\b')
857
self.assertContainsRe(self.get_raw(bundle_file), 'one')
858
self.assertContainsRe(self.get_raw(bundle_file), 'three')
856
rev_ids = write_bundle(self.tree1.branch.repository, b'a@cset-0-3',
857
b'a@cset-0-1', bundle_file, format=self.format)
858
self.assertNotContainsRe(bundle_file.getvalue(), b'\btwo\b')
859
self.assertContainsRe(self.get_raw(bundle_file), b'one')
860
self.assertContainsRe(self.get_raw(bundle_file), b'three')
860
862
def test_bundle_same_basis(self):
861
863
"""Ensure using the basis as the target doesn't cause an error"""
862
864
self.tree1 = self.make_branch_and_tree('b1')
863
865
self.tree1.commit('add file', rev_id=b'a@cset-0-1')
864
866
bundle_file = BytesIO()
865
rev_ids = write_bundle(self.tree1.branch.repository, 'a@cset-0-1',
866
'a@cset-0-1', bundle_file)
867
rev_ids = write_bundle(self.tree1.branch.repository, b'a@cset-0-1',
868
b'a@cset-0-1', bundle_file)
869
871
def get_raw(bundle_file):
1513
1515
builder = self.make_branch_builder('source')
1514
1516
builder.start_series()
1515
1517
builder.build_snapshot(None, [
1516
('add', ('', 'root-id', 'directory', None)),
1517
('add', ('file', 'file-id', 'file', 'original content\n')),
1518
('add', ('', b'root-id', 'directory', None)),
1519
('add', ('file', b'file-id', 'file', b'original content\n')),
1518
1520
], revision_id=b'a@cset-0-1')
1519
builder.build_snapshot(['a@cset-0-1'], [
1520
('modify', ('file', 'new-content\n')),
1521
builder.build_snapshot([b'a@cset-0-1'], [
1522
('modify', ('file', b'new-content\n')),
1521
1523
], revision_id=b'a@cset-0-2a')
1522
builder.build_snapshot(['a@cset-0-1'], [
1523
('add', ('other-file', 'file2-id', 'file', 'file2-content\n')),
1524
builder.build_snapshot([b'a@cset-0-1'], [
1525
('add', ('other-file', b'file2-id', 'file', b'file2-content\n')),
1524
1526
], revision_id=b'a@cset-0-2b')
1525
builder.build_snapshot(['a@cset-0-2a', 'a@cset-0-2b'], [
1526
('add', ('other-file', 'file2-id', 'file', 'file2-content\n')),
1527
builder.build_snapshot([b'a@cset-0-2a', b'a@cset-0-2b'], [
1528
('add', ('other-file', b'file2-id', 'file', b'file2-content\n')),
1527
1529
], revision_id=b'a@cset-0-3')
1528
1530
builder.finish_series()
1529
1531
self.b1 = builder.get_branch()
1545
1547
def test_single_inventory_multiple_parents_as_xml(self):
1546
1548
self.make_merged_branch()
1547
sio = self.make_bundle_just_inventories('a@cset-0-1', 'a@cset-0-3',
1549
sio = self.make_bundle_just_inventories(b'a@cset-0-1', b'a@cset-0-3',
1549
1551
reader = v4.BundleReader(sio, stream_input=False)
1550
1552
records = list(reader.iter_records())
1551
1553
self.assertEqual(1, len(records))
1552
1554
(bytes, metadata, repo_kind, revision_id,
1553
1555
file_id) = records[0]
1554
1556
self.assertIs(None, file_id)
1555
self.assertEqual('a@cset-0-3', revision_id)
1557
self.assertEqual(b'a@cset-0-3', revision_id)
1556
1558
self.assertEqual('inventory', repo_kind)
1557
self.assertEqual({'parents': ['a@cset-0-2a', 'a@cset-0-2b'],
1558
'sha1': '09c53b0c4de0895e11a2aacc34fef60a6e70865c',
1559
'storage_kind': 'mpdiff',
1559
self.assertEqual({b'parents': [b'a@cset-0-2a', b'a@cset-0-2b'],
1560
b'sha1': b'09c53b0c4de0895e11a2aacc34fef60a6e70865c',
1561
b'storage_kind': b'mpdiff',
1561
1563
# We should have an mpdiff that takes some lines from both parents.
1562
1564
self.assertEqualDiff(
1564
'<inventory format="10" revision_id="a@cset-0-3">\n'
1567
'c 1 3 3 2\n', bytes)
1566
b'<inventory format="10" revision_id="a@cset-0-3">\n'
1569
b'c 1 3 3 2\n', bytes)
1569
1571
def test_single_inv_no_parents_as_xml(self):
1570
1572
self.make_merged_branch()
1571
sio = self.make_bundle_just_inventories('null:', 'a@cset-0-1',
1573
sio = self.make_bundle_just_inventories(b'null:', b'a@cset-0-1',
1573
1575
reader = v4.BundleReader(sio, stream_input=False)
1574
1576
records = list(reader.iter_records())
1575
1577
self.assertEqual(1, len(records))
1576
1578
(bytes, metadata, repo_kind, revision_id,
1577
1579
file_id) = records[0]
1578
1580
self.assertIs(None, file_id)
1579
self.assertEqual('a@cset-0-1', revision_id)
1581
self.assertEqual(b'a@cset-0-1', revision_id)
1580
1582
self.assertEqual('inventory', repo_kind)
1581
self.assertEqual({'parents': [],
1582
'sha1': 'a13f42b142d544aac9b085c42595d304150e31a2',
1583
'storage_kind': 'mpdiff',
1583
self.assertEqual({b'parents': [],
1584
b'sha1': b'a13f42b142d544aac9b085c42595d304150e31a2',
1585
b'storage_kind': b'mpdiff',
1585
1587
# We should have an mpdiff that takes some lines from both parents.
1586
1588
self.assertEqualDiff(
1588
'<inventory format="10" revision_id="a@cset-0-1">\n'
1589
'<directory file_id="root-id" name=""'
1590
' revision="a@cset-0-1" />\n'
1591
'<file file_id="file-id" name="file" parent_id="root-id"'
1592
' revision="a@cset-0-1"'
1593
' text_sha1="09c2f8647e14e49e922b955c194102070597c2d1"'
1594
' text_size="17" />\n'
1590
b'<inventory format="10" revision_id="a@cset-0-1">\n'
1591
b'<directory file_id="root-id" name=""'
1592
b' revision="a@cset-0-1" />\n'
1593
b'<file file_id="file-id" name="file" parent_id="root-id"'
1594
b' revision="a@cset-0-1"'
1595
b' text_sha1="09c2f8647e14e49e922b955c194102070597c2d1"'
1596
b' text_size="17" />\n'
1598
1600
def test_multiple_inventories_as_xml(self):
1599
1601
self.make_merged_branch()
1600
sio = self.make_bundle_just_inventories('a@cset-0-1', 'a@cset-0-3',
1601
['a@cset-0-2a', 'a@cset-0-2b', 'a@cset-0-3'])
1602
sio = self.make_bundle_just_inventories(b'a@cset-0-1', b'a@cset-0-3',
1603
[b'a@cset-0-2a', b'a@cset-0-2b', b'a@cset-0-3'])
1602
1604
reader = v4.BundleReader(sio, stream_input=False)
1603
1605
records = list(reader.iter_records())
1604
1606
self.assertEqual(3, len(records))
1605
1607
revision_ids = [rev_id for b, m, k, rev_id, f in records]
1606
self.assertEqual(['a@cset-0-2a', 'a@cset-0-2b', 'a@cset-0-3'],
1608
self.assertEqual([b'a@cset-0-2a', b'a@cset-0-2b', b'a@cset-0-3'],
1608
1610
metadata_2a = records[0][1]
1609
self.assertEqual({'parents': ['a@cset-0-1'],
1610
'sha1': '1e105886d62d510763e22885eec733b66f5f09bf',
1611
'storage_kind': 'mpdiff',
1611
self.assertEqual({b'parents': [b'a@cset-0-1'],
1612
b'sha1': b'1e105886d62d510763e22885eec733b66f5f09bf',
1613
b'storage_kind': b'mpdiff',
1612
1614
}, metadata_2a)
1613
1615
metadata_2b = records[1][1]
1614
self.assertEqual({'parents': ['a@cset-0-1'],
1615
'sha1': 'f03f12574bdb5ed2204c28636c98a8547544ccd8',
1616
'storage_kind': 'mpdiff',
1616
self.assertEqual({b'parents': [b'a@cset-0-1'],
1617
b'sha1': b'f03f12574bdb5ed2204c28636c98a8547544ccd8',
1618
b'storage_kind': b'mpdiff',
1617
1619
}, metadata_2b)
1618
1620
metadata_3 = records[2][1]
1619
self.assertEqual({'parents': ['a@cset-0-2a', 'a@cset-0-2b'],
1620
'sha1': '09c53b0c4de0895e11a2aacc34fef60a6e70865c',
1621
'storage_kind': 'mpdiff',
1621
self.assertEqual({b'parents': [b'a@cset-0-2a', b'a@cset-0-2b'],
1622
b'sha1': b'09c53b0c4de0895e11a2aacc34fef60a6e70865c',
1623
b'storage_kind': b'mpdiff',
1623
1625
bytes_2a = records[0][0]
1624
1626
self.assertEqualDiff(
1626
'<inventory format="10" revision_id="a@cset-0-2a">\n'
1630
'<file file_id="file-id" name="file" parent_id="root-id"'
1631
' revision="a@cset-0-2a"'
1632
' text_sha1="50f545ff40e57b6924b1f3174b267ffc4576e9a9"'
1633
' text_size="12" />\n'
1635
'c 0 3 3 1\n', bytes_2a)
1628
b'<inventory format="10" revision_id="a@cset-0-2a">\n'
1632
b'<file file_id="file-id" name="file" parent_id="root-id"'
1633
b' revision="a@cset-0-2a"'
1634
b' text_sha1="50f545ff40e57b6924b1f3174b267ffc4576e9a9"'
1635
b' text_size="12" />\n'
1637
b'c 0 3 3 1\n', bytes_2a)
1636
1638
bytes_2b = records[1][0]
1637
1639
self.assertEqualDiff(
1639
'<inventory format="10" revision_id="a@cset-0-2b">\n'
1643
'<file file_id="file2-id" name="other-file" parent_id="root-id"'
1644
' revision="a@cset-0-2b"'
1645
' text_sha1="b46c0c8ea1e5ef8e46fc8894bfd4752a88ec939e"'
1646
' text_size="14" />\n'
1648
'c 0 3 4 1\n', bytes_2b)
1641
b'<inventory format="10" revision_id="a@cset-0-2b">\n'
1645
b'<file file_id="file2-id" name="other-file" parent_id="root-id"'
1646
b' revision="a@cset-0-2b"'
1647
b' text_sha1="b46c0c8ea1e5ef8e46fc8894bfd4752a88ec939e"'
1648
b' text_size="14" />\n'
1650
b'c 0 3 4 1\n', bytes_2b)
1649
1651
bytes_3 = records[2][0]
1650
1652
self.assertEqualDiff(
1652
'<inventory format="10" revision_id="a@cset-0-3">\n'
1655
'c 1 3 3 2\n', bytes_3)
1654
b'<inventory format="10" revision_id="a@cset-0-3">\n'
1657
b'c 1 3 3 2\n', bytes_3)
1657
1659
def test_creating_bundle_preserves_chk_pages(self):
1658
1660
self.make_merged_branch()
1659
1661
target = self.b1.controldir.sprout('target',
1660
1662
revision_id=b'a@cset-0-2a').open_branch()
1661
bundle_txt, rev_ids = self.create_bundle_text('a@cset-0-2a',
1663
self.assertEqual(['a@cset-0-2b', 'a@cset-0-3'], rev_ids)
1663
bundle_txt, rev_ids = self.create_bundle_text(b'a@cset-0-2a',
1665
self.assertEqual([b'a@cset-0-2b', b'a@cset-0-3'], rev_ids)
1664
1666
bundle = read_bundle(bundle_txt)
1665
1667
target.lock_write()
1666
1668
self.addCleanup(target.unlock)
1667
1669
install_bundle(target.repository, bundle)
1668
1670
inv1 = self.b1.repository.inventories.get_record_stream([
1669
('a@cset-0-3',)], 'unordered',
1671
(b'a@cset-0-3',)], 'unordered',
1670
1672
True).next().get_bytes_as('fulltext')
1671
1673
inv2 = target.repository.inventories.get_record_stream([
1672
('a@cset-0-3',)], 'unordered',
1674
(b'a@cset-0-3',)], 'unordered',
1673
1675
True).next().get_bytes_as('fulltext')
1674
1676
self.assertEqualDiff(inv1, inv2)
1775
1777
fileobj = BytesIO()
1776
1778
writer = v4.BundleWriter(fileobj)
1778
writer.add_info_record(foo='bar')
1779
writer._add_record("Record body", {'parents': ['1', '3'],
1780
'storage_kind':'fulltext'}, 'file', 'revid', 'fileid')
1780
writer.add_info_record({b'foo': b'bar'})
1781
writer._add_record("Record body", {b'parents': [b'1', b'3'],
1782
b'storage_kind': b'fulltext'}, 'file', b'revid', b'fileid')
1782
1784
fileobj.seek(0)
1783
1785
reader = v4.BundleReader(fileobj, stream_input=True)
1784
1786
record_iter = reader.iter_records()
1785
1787
record = next(record_iter)
1786
self.assertEqual((None, {'foo': 'bar', 'storage_kind': 'header'},
1788
self.assertEqual((None, {b'foo': b'bar', b'storage_kind': b'header'},
1787
1789
'info', None, None), record)
1788
1790
record = next(record_iter)
1789
self.assertEqual(("Record body", {'storage_kind': 'fulltext',
1790
'parents': ['1', '3']}, 'file', 'revid', 'fileid'),
1791
self.assertEqual(("Record body", {b'storage_kind': b'fulltext',
1792
b'parents': [b'1', b'3']}, 'file', b'revid', b'fileid'),
1793
1795
def test_roundtrip_record_memory_hungry(self):
1794
1796
fileobj = BytesIO()
1795
1797
writer = v4.BundleWriter(fileobj)
1797
writer.add_info_record(foo='bar')
1798
writer._add_record("Record body", {'parents': ['1', '3'],
1799
'storage_kind':'fulltext'}, 'file', 'revid', 'fileid')
1799
writer.add_info_record({b'foo': b'bar'})
1800
writer._add_record("Record body", {b'parents': [b'1', b'3'],
1801
b'storage_kind': b'fulltext'}, 'file', b'revid', b'fileid')
1801
1803
fileobj.seek(0)
1802
1804
reader = v4.BundleReader(fileobj, stream_input=False)
1803
1805
record_iter = reader.iter_records()
1804
1806
record = next(record_iter)
1805
self.assertEqual((None, {'foo': 'bar', 'storage_kind': 'header'},
1807
self.assertEqual((None, {b'foo': b'bar', b'storage_kind': b'header'},
1806
1808
'info', None, None), record)
1807
1809
record = next(record_iter)
1808
self.assertEqual(("Record body", {'storage_kind': 'fulltext',
1809
'parents': ['1', '3']}, 'file', 'revid', 'fileid'),
1810
self.assertEqual(("Record body", {b'storage_kind': b'fulltext',
1811
b'parents': [b'1', b'3']}, 'file', b'revid', b'fileid'),
1812
1814
def test_encode_name(self):
1813
self.assertEqual('revision/rev1',
1814
v4.BundleWriter.encode_name('revision', 'rev1'))
1815
self.assertEqual('file/rev//1/file-id-1',
1816
v4.BundleWriter.encode_name('file', 'rev/1', 'file-id-1'))
1817
self.assertEqual('info',
1815
self.assertEqual(b'revision/rev1',
1816
v4.BundleWriter.encode_name('revision', b'rev1'))
1817
self.assertEqual(b'file/rev//1/file-id-1',
1818
v4.BundleWriter.encode_name('file', b'rev/1', b'file-id-1'))
1819
self.assertEqual(b'info',
1818
1820
v4.BundleWriter.encode_name('info', None, None))
1820
1822
def test_decode_name(self):
1821
self.assertEqual(('revision', 'rev1', None),
1822
v4.BundleReader.decode_name('revision/rev1'))
1823
self.assertEqual(('file', 'rev/1', 'file-id-1'),
1824
v4.BundleReader.decode_name('file/rev//1/file-id-1'))
1823
self.assertEqual(('revision', b'rev1', None),
1824
v4.BundleReader.decode_name(b'revision/rev1'))
1825
self.assertEqual(('file', b'rev/1', b'file-id-1'),
1826
v4.BundleReader.decode_name(b'file/rev//1/file-id-1'))
1825
1827
self.assertEqual(('info', None, None),
1826
v4.BundleReader.decode_name('info'))
1828
v4.BundleReader.decode_name(b'info'))
1828
1830
def test_too_many_names(self):
1829
1831
fileobj = BytesIO()
1830
1832
writer = v4.BundleWriter(fileobj)
1832
writer.add_info_record(foo='bar')
1833
writer._container.add_bytes_record('blah', ['two', 'names'])
1834
writer.add_info_record({b'foo': b'bar'})
1835
writer._container.add_bytes_record(b'blah', [b'two', b'names'])
1835
1837
fileobj.seek(0)
1836
1838
record_iter = v4.BundleReader(fileobj).iter_records()
1837
1839
record = next(record_iter)
1838
self.assertEqual((None, {'foo': 'bar', 'storage_kind': 'header'},
1840
self.assertEqual((None, {b'foo': b'bar', b'storage_kind': b'header'},
1839
1841
'info', None, None), record)
1840
1842
self.assertRaises(errors.BadBundle, next, record_iter)