14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
from cStringIO import StringIO
18
from io import BytesIO
23
import SocketServer as socketserver
31
31
revision as _mod_revision,
35
from bzrlib.bundle import read_mergeable_from_url
36
from bzrlib.bundle.apply_bundle import install_bundle, merge_bundle
37
from bzrlib.bundle.bundle_data import BundleTree
38
from bzrlib.bzrdir import BzrDir
39
from bzrlib.directory_service import directories
40
from bzrlib.bundle.serializer import write_bundle, read_bundle, v09, v4
41
from bzrlib.bundle.serializer.v08 import BundleSerializerV08
42
from bzrlib.bundle.serializer.v09 import BundleSerializerV09
43
from bzrlib.bundle.serializer.v4 import BundleSerializerV4
44
from bzrlib.branch import Branch
45
from bzrlib.repofmt import knitrepo
46
from bzrlib.tests import (
39
from ..bundle import read_mergeable_from_url
40
from ..bundle.apply_bundle import install_bundle, merge_bundle
41
from ..bundle.bundle_data import BundleTree
42
from ..directory_service import directories
43
from ..bundle.serializer import write_bundle, read_bundle, v09, v4
44
from ..bundle.serializer.v08 import BundleSerializerV08
45
from ..bundle.serializer.v09 import BundleSerializerV09
46
from ..bundle.serializer.v4 import BundleSerializerV4
47
from ..bzr import knitrepo
50
from bzrlib.transform import TreeTransform
54
from ..transform import TreeTransform
53
57
def get_text(vf, key):
54
58
"""Get the fulltext for a given revision id that is present in the vf"""
55
59
stream = vf.get_record_stream([key], 'unordered', True)
56
record = stream.next()
57
61
return record.get_bytes_as('fulltext')
172
210
self.assertEqual(btree.old_path("grandparent/parent/file"),
173
211
"grandparent/parent/file")
175
self.assertEqual(btree.id2path("a"), "grandparent")
176
self.assertEqual(btree.id2path("b"), "grandparent/parent")
177
self.assertEqual(btree.id2path("c"), "grandparent/parent/file")
179
self.assertEqual(btree.path2id("grandparent"), "a")
180
self.assertEqual(btree.path2id("grandparent/parent"), "b")
181
self.assertEqual(btree.path2id("grandparent/parent/file"), "c")
183
self.assertTrue(btree.path2id("grandparent2") is None)
184
self.assertTrue(btree.path2id("grandparent2/parent") is None)
185
self.assertTrue(btree.path2id("grandparent2/parent/file") is None)
213
self.assertEqual(btree.id2path(b"a"), "grandparent")
214
self.assertEqual(btree.id2path(b"b"), "grandparent/parent")
215
self.assertEqual(btree.id2path(b"c"), "grandparent/parent/file")
217
self.assertEqual(btree.path2id("grandparent"), b"a")
218
self.assertEqual(btree.path2id("grandparent/parent"), b"b")
219
self.assertEqual(btree.path2id("grandparent/parent/file"), b"c")
221
self.assertIs(btree.path2id("grandparent2"), None)
222
self.assertIs(btree.path2id("grandparent2/parent"), None)
223
self.assertIs(btree.path2id("grandparent2/parent/file"), None)
187
225
btree.note_rename("grandparent", "grandparent2")
188
self.assertTrue(btree.old_path("grandparent") is None)
189
self.assertTrue(btree.old_path("grandparent/parent") is None)
190
self.assertTrue(btree.old_path("grandparent/parent/file") is None)
192
self.assertEqual(btree.id2path("a"), "grandparent2")
193
self.assertEqual(btree.id2path("b"), "grandparent2/parent")
194
self.assertEqual(btree.id2path("c"), "grandparent2/parent/file")
196
self.assertEqual(btree.path2id("grandparent2"), "a")
197
self.assertEqual(btree.path2id("grandparent2/parent"), "b")
198
self.assertEqual(btree.path2id("grandparent2/parent/file"), "c")
226
self.assertIs(btree.old_path("grandparent"), None)
227
self.assertIs(btree.old_path("grandparent/parent"), None)
228
self.assertIs(btree.old_path("grandparent/parent/file"), None)
230
self.assertEqual(btree.id2path(b"a"), "grandparent2")
231
self.assertEqual(btree.id2path(b"b"), "grandparent2/parent")
232
self.assertEqual(btree.id2path(b"c"), "grandparent2/parent/file")
234
self.assertEqual(btree.path2id("grandparent2"), b"a")
235
self.assertEqual(btree.path2id("grandparent2/parent"), b"b")
236
self.assertEqual(btree.path2id("grandparent2/parent/file"), b"c")
200
238
self.assertTrue(btree.path2id("grandparent") is None)
201
239
self.assertTrue(btree.path2id("grandparent/parent") is None)
202
240
self.assertTrue(btree.path2id("grandparent/parent/file") is None)
204
242
btree.note_rename("grandparent/parent", "grandparent2/parent2")
205
self.assertEqual(btree.id2path("a"), "grandparent2")
206
self.assertEqual(btree.id2path("b"), "grandparent2/parent2")
207
self.assertEqual(btree.id2path("c"), "grandparent2/parent2/file")
243
self.assertEqual(btree.id2path(b"a"), "grandparent2")
244
self.assertEqual(btree.id2path(b"b"), "grandparent2/parent2")
245
self.assertEqual(btree.id2path(b"c"), "grandparent2/parent2/file")
209
self.assertEqual(btree.path2id("grandparent2"), "a")
210
self.assertEqual(btree.path2id("grandparent2/parent2"), "b")
211
self.assertEqual(btree.path2id("grandparent2/parent2/file"), "c")
247
self.assertEqual(btree.path2id("grandparent2"), b"a")
248
self.assertEqual(btree.path2id("grandparent2/parent2"), b"b")
249
self.assertEqual(btree.path2id("grandparent2/parent2/file"), b"c")
213
251
self.assertTrue(btree.path2id("grandparent2/parent") is None)
214
252
self.assertTrue(btree.path2id("grandparent2/parent/file") is None)
216
254
btree.note_rename("grandparent/parent/file",
217
255
"grandparent2/parent2/file2")
218
self.assertEqual(btree.id2path("a"), "grandparent2")
219
self.assertEqual(btree.id2path("b"), "grandparent2/parent2")
220
self.assertEqual(btree.id2path("c"), "grandparent2/parent2/file2")
256
self.assertEqual(btree.id2path(b"a"), "grandparent2")
257
self.assertEqual(btree.id2path(b"b"), "grandparent2/parent2")
258
self.assertEqual(btree.id2path(b"c"), "grandparent2/parent2/file2")
222
self.assertEqual(btree.path2id("grandparent2"), "a")
223
self.assertEqual(btree.path2id("grandparent2/parent2"), "b")
224
self.assertEqual(btree.path2id("grandparent2/parent2/file2"), "c")
260
self.assertEqual(btree.path2id("grandparent2"), b"a")
261
self.assertEqual(btree.path2id("grandparent2/parent2"), b"b")
262
self.assertEqual(btree.path2id("grandparent2/parent2/file2"), b"c")
226
264
self.assertTrue(btree.path2id("grandparent2/parent2/file") is None)
230
268
btree = self.make_tree_1()[0]
231
269
btree.note_rename("grandparent/parent/file",
232
270
"grandparent/alt_parent/file")
233
self.assertEqual(btree.id2path("c"), "grandparent/alt_parent/file")
234
self.assertEqual(btree.path2id("grandparent/alt_parent/file"), "c")
271
self.assertEqual(btree.id2path(b"c"), "grandparent/alt_parent/file")
272
self.assertEqual(btree.path2id("grandparent/alt_parent/file"), b"c")
235
273
self.assertTrue(btree.path2id("grandparent/parent/file") is None)
237
275
def unified_diff(self, old, new):
239
277
diff.internal_diff("old", old, "new", new, out)
241
279
return out.read()
243
281
def make_tree_2(self):
244
282
btree = self.make_tree_1()[0]
245
283
btree.note_rename("grandparent/parent/file",
246
284
"grandparent/alt_parent/file")
247
self.assertTrue(btree.id2path("e") is None)
248
self.assertTrue(btree.path2id("grandparent/parent/file") is None)
249
btree.note_id("e", "grandparent/parent/file")
285
self.assertTrue(btree.id2path(b"e") is None)
286
self.assertFalse(btree.is_versioned("grandparent/parent/file"))
287
btree.note_id(b"e", "grandparent/parent/file")
252
290
def test_adds(self):
253
291
"""File/inventory adds"""
254
292
btree = self.make_tree_2()
255
add_patch = self.unified_diff([], ["Extra cheese\n"])
293
add_patch = self.unified_diff([], [b"Extra cheese\n"])
256
294
btree.note_patch("grandparent/parent/file", add_patch)
257
btree.note_id('f', 'grandparent/parent/symlink', kind='symlink')
295
btree.note_id(b'f', 'grandparent/parent/symlink', kind='symlink')
258
296
btree.note_target('grandparent/parent/symlink', 'venus')
259
297
self.adds_test(btree)
261
299
def adds_test(self, btree):
262
self.assertEqual(btree.id2path("e"), "grandparent/parent/file")
263
self.assertEqual(btree.path2id("grandparent/parent/file"), "e")
264
self.assertEqual(btree.get_file("e").read(), "Extra cheese\n")
265
self.assertEqual(btree.get_symlink_target('f'), 'venus')
300
self.assertEqual(btree.id2path(b"e"), "grandparent/parent/file")
301
self.assertEqual(btree.path2id("grandparent/parent/file"), b"e")
302
with btree.get_file("grandparent/parent/file") as f:
303
self.assertEqual(f.read(), b"Extra cheese\n")
305
btree.get_symlink_target('grandparent/parent/symlink'), 'venus')
267
307
def test_adds2(self):
268
308
"""File/inventory adds, with patch-compatibile renames"""
269
309
btree = self.make_tree_2()
270
310
btree.contents_by_id = False
271
add_patch = self.unified_diff(["Hello\n"], ["Extra cheese\n"])
311
add_patch = self.unified_diff([b"Hello\n"], [b"Extra cheese\n"])
272
312
btree.note_patch("grandparent/parent/file", add_patch)
273
btree.note_id('f', 'grandparent/parent/symlink', kind='symlink')
313
btree.note_id(b'f', 'grandparent/parent/symlink', kind='symlink')
274
314
btree.note_target('grandparent/parent/symlink', 'venus')
275
315
self.adds_test(btree)
286
326
def get_file_test(self, btree):
287
self.assertEqual(btree.get_file("e").read(), "Lemon\n")
288
self.assertEqual(btree.get_file("c").read(), "Hello\n")
327
with btree.get_file(btree.id2path(b"e")) as f:
328
self.assertEqual(f.read(), b"Lemon\n")
329
with btree.get_file(btree.id2path(b"c")) as f:
330
self.assertEqual(f.read(), b"Hello\n")
290
332
def test_get_file(self):
291
333
"""Get file contents"""
292
334
btree = self.make_tree_3()
293
mod_patch = self.unified_diff(["Anchovies\n"], ["Lemon\n"])
335
mod_patch = self.unified_diff([b"Anchovies\n"], [b"Lemon\n"])
294
336
btree.note_patch("grandparent/alt_parent/stopping", mod_patch)
295
337
self.get_file_test(btree)
297
339
def test_get_file2(self):
298
"""Get file contents, with patch-compatibile renames"""
340
"""Get file contents, with patch-compatible renames"""
299
341
btree = self.make_tree_3()
300
342
btree.contents_by_id = False
301
mod_patch = self.unified_diff([], ["Lemon\n"])
343
mod_patch = self.unified_diff([], [b"Lemon\n"])
302
344
btree.note_patch("grandparent/alt_parent/stopping", mod_patch)
303
mod_patch = self.unified_diff([], ["Hello\n"])
345
mod_patch = self.unified_diff([], [b"Hello\n"])
304
346
btree.note_patch("grandparent/alt_parent/file", mod_patch)
305
347
self.get_file_test(btree)
307
349
def test_delete(self):
308
350
"Deletion by bundle"
309
351
btree = self.make_tree_1()[0]
310
self.assertEqual(btree.get_file("c").read(), "Hello\n")
352
with btree.get_file(btree.id2path(b"c")) as f:
353
self.assertEqual(f.read(), b"Hello\n")
311
354
btree.note_deletion("grandparent/parent/file")
312
self.assertTrue(btree.id2path("c") is None)
313
self.assertTrue(btree.path2id("grandparent/parent/file") is None)
355
self.assertTrue(btree.id2path(b"c") is None)
356
self.assertFalse(btree.is_versioned("grandparent/parent/file"))
315
358
def sorted_ids(self, tree):
359
ids = sorted(tree.all_file_ids())
320
362
def test_iteration(self):
321
363
"""Ensure that iteration through ids works properly"""
322
364
btree = self.make_tree_1()[0]
323
365
self.assertEqual(self.sorted_ids(btree),
324
[inventory.ROOT_ID, 'a', 'b', 'c', 'd'])
366
[inventory.ROOT_ID, b'a', b'b', b'c', b'd'])
325
367
btree.note_deletion("grandparent/parent/file")
326
btree.note_id("e", "grandparent/alt_parent/fool", kind="directory")
368
btree.note_id(b"e", "grandparent/alt_parent/fool", kind="directory")
327
369
btree.note_last_changed("grandparent/alt_parent/fool",
328
370
"revisionidiguess")
329
371
self.assertEqual(self.sorted_ids(btree),
330
[inventory.ROOT_ID, 'a', 'b', 'd', 'e'])
372
[inventory.ROOT_ID, b'a', b'b', b'd', b'e'])
333
375
class BundleTester1(tests.TestCaseWithTransport):
628
666
tt = TreeTransform(self.tree1)
629
trans_id = tt.trans_id_tree_file_id('exe-1')
667
trans_id = tt.trans_id_tree_path('executable')
630
668
tt.set_executability(False, trans_id)
632
self.tree1.commit('removed', rev_id='a@cset-0-3')
670
self.tree1.commit('removed', rev_id=b'a@cset-0-3')
634
bundle = self.get_valid_bundle('a@cset-0-2', 'a@cset-0-3')
672
bundle = self.get_valid_bundle(b'a@cset-0-2', b'a@cset-0-3')
635
673
self.assertRaises((errors.TestamentMismatch,
636
674
errors.VersionedFileInvalidChecksum,
637
675
errors.BadBundle), self.get_invalid_bundle,
638
'a@cset-0-2', 'a@cset-0-3')
676
b'a@cset-0-2', b'a@cset-0-3')
639
677
# Check a rollup bundle
640
bundle = self.get_valid_bundle('null:', 'a@cset-0-3')
678
bundle = self.get_valid_bundle(b'null:', b'a@cset-0-3')
642
680
# Now move the directory
643
681
self.tree1.rename_one('dir', 'sub/dir')
644
self.tree1.commit('rename dir', rev_id='a@cset-0-4')
682
self.tree1.commit('rename dir', rev_id=b'a@cset-0-4')
646
bundle = self.get_valid_bundle('a@cset-0-3', 'a@cset-0-4')
684
bundle = self.get_valid_bundle(b'a@cset-0-3', b'a@cset-0-4')
647
685
# Check a rollup bundle
648
bundle = self.get_valid_bundle('null:', 'a@cset-0-4')
686
bundle = self.get_valid_bundle(b'null:', b'a@cset-0-4')
651
open('b1/sub/dir/WithCaps.txt', 'ab').write('\nAdding some text\n')
652
open('b1/sub/dir/ pre space', 'ab').write(
653
'\r\nAdding some\r\nDOS format lines\r\n')
654
open('b1/sub/dir/nolastnewline.txt', 'ab').write('\n')
689
with open('b1/sub/dir/WithCaps.txt', 'ab') as f: f.write(b'\nAdding some text\n')
690
with open('b1/sub/dir/ pre space', 'ab') as f: f.write(
691
b'\r\nAdding some\r\nDOS format lines\r\n')
692
with open('b1/sub/dir/nolastnewline.txt', 'ab') as f: f.write(b'\n')
655
693
self.tree1.rename_one('sub/dir/ pre space',
656
694
'sub/ start space')
657
self.tree1.commit('Modified files', rev_id='a@cset-0-5')
658
bundle = self.get_valid_bundle('a@cset-0-4', 'a@cset-0-5')
695
self.tree1.commit('Modified files', rev_id=b'a@cset-0-5')
696
bundle = self.get_valid_bundle(b'a@cset-0-4', b'a@cset-0-5')
660
698
self.tree1.rename_one('sub/dir/WithCaps.txt', 'temp')
661
699
self.tree1.rename_one('with space.txt', 'WithCaps.txt')
662
700
self.tree1.rename_one('temp', 'with space.txt')
663
self.tree1.commit(u'swap filenames', rev_id='a@cset-0-6',
701
self.tree1.commit(u'swap filenames', rev_id=b'a@cset-0-6',
665
bundle = self.get_valid_bundle('a@cset-0-5', 'a@cset-0-6')
666
other = self.get_checkout('a@cset-0-5')
703
bundle = self.get_valid_bundle(b'a@cset-0-5', b'a@cset-0-6')
704
other = self.get_checkout(b'a@cset-0-5')
667
705
tree1_inv = get_inventory_text(self.tree1.branch.repository,
669
707
tree2_inv = get_inventory_text(other.branch.repository,
671
709
self.assertEqualDiff(tree1_inv, tree2_inv)
672
710
other.rename_one('sub/dir/nolastnewline.txt', 'sub/nolastnewline.txt')
673
other.commit('rename file', rev_id='a@cset-0-6b')
711
other.commit('rename file', rev_id=b'a@cset-0-6b')
674
712
self.tree1.merge_from_branch(other.branch)
675
self.tree1.commit(u'Merge', rev_id='a@cset-0-7',
713
self.tree1.commit(u'Merge', rev_id=b'a@cset-0-7',
677
bundle = self.get_valid_bundle('a@cset-0-6', 'a@cset-0-7')
715
bundle = self.get_valid_bundle(b'a@cset-0-6', b'a@cset-0-7')
679
717
def _test_symlink_bundle(self, link_name, link_target, new_link_target):
682
self.requireFeature(tests.SymlinkFeature)
720
self.requireFeature(features.SymlinkFeature)
683
721
self.tree1 = self.make_branch_and_tree('b1')
684
722
self.b1 = self.tree1.branch
686
724
tt = TreeTransform(self.tree1)
687
725
tt.new_symlink(link_name, tt.root, link_target, link_id)
689
self.tree1.commit('add symlink', rev_id='l@cset-0-1')
690
bundle = self.get_valid_bundle('null:', 'l@cset-0-1')
691
if getattr(bundle ,'revision_tree', None) is not None:
727
self.tree1.commit('add symlink', rev_id=b'l@cset-0-1')
728
bundle = self.get_valid_bundle(b'null:', b'l@cset-0-1')
729
if getattr(bundle, 'revision_tree', None) is not None:
692
730
# Not all bundle formats supports revision_tree
693
bund_tree = bundle.revision_tree(self.b1.repository, 'l@cset-0-1')
694
self.assertEqual(link_target, bund_tree.get_symlink_target(link_id))
731
bund_tree = bundle.revision_tree(self.b1.repository, b'l@cset-0-1')
732
self.assertEqual(link_target, bund_tree.get_symlink_target(link_name))
696
734
tt = TreeTransform(self.tree1)
697
trans_id = tt.trans_id_tree_file_id(link_id)
735
trans_id = tt.trans_id_tree_path(link_name)
698
736
tt.adjust_path('link2', tt.root, trans_id)
699
737
tt.delete_contents(trans_id)
700
738
tt.create_symlink(new_link_target, trans_id)
702
self.tree1.commit('rename and change symlink', rev_id='l@cset-0-2')
703
bundle = self.get_valid_bundle('l@cset-0-1', 'l@cset-0-2')
704
if getattr(bundle ,'revision_tree', None) is not None:
740
self.tree1.commit('rename and change symlink', rev_id=b'l@cset-0-2')
741
bundle = self.get_valid_bundle(b'l@cset-0-1', b'l@cset-0-2')
742
if getattr(bundle, 'revision_tree', None) is not None:
705
743
# Not all bundle formats supports revision_tree
706
bund_tree = bundle.revision_tree(self.b1.repository, 'l@cset-0-2')
744
bund_tree = bundle.revision_tree(self.b1.repository, b'l@cset-0-2')
707
745
self.assertEqual(new_link_target,
708
bund_tree.get_symlink_target(link_id))
746
bund_tree.get_symlink_target('link2'))
710
748
tt = TreeTransform(self.tree1)
711
trans_id = tt.trans_id_tree_file_id(link_id)
749
trans_id = tt.trans_id_tree_path('link2')
712
750
tt.delete_contents(trans_id)
713
751
tt.create_symlink('jupiter', trans_id)
715
self.tree1.commit('just change symlink target', rev_id='l@cset-0-3')
716
bundle = self.get_valid_bundle('l@cset-0-2', 'l@cset-0-3')
753
self.tree1.commit('just change symlink target', rev_id=b'l@cset-0-3')
754
bundle = self.get_valid_bundle(b'l@cset-0-2', b'l@cset-0-3')
718
756
tt = TreeTransform(self.tree1)
719
trans_id = tt.trans_id_tree_file_id(link_id)
757
trans_id = tt.trans_id_tree_path('link2')
720
758
tt.delete_contents(trans_id)
722
self.tree1.commit('Delete symlink', rev_id='l@cset-0-4')
723
bundle = self.get_valid_bundle('l@cset-0-3', 'l@cset-0-4')
760
self.tree1.commit('Delete symlink', rev_id=b'l@cset-0-4')
761
bundle = self.get_valid_bundle(b'l@cset-0-3', b'l@cset-0-4')
725
763
def test_symlink_bundle(self):
726
764
self._test_symlink_bundle('link', 'bar/foo', 'mars')
728
766
def test_unicode_symlink_bundle(self):
729
self.requireFeature(tests.UnicodeFilenameFeature)
767
self.requireFeature(features.UnicodeFilenameFeature)
730
768
self._test_symlink_bundle(u'\N{Euro Sign}link',
731
769
u'bar/\N{Euro Sign}foo',
732
770
u'mars\N{Euro Sign}')
737
775
tt = TreeTransform(self.tree1)
740
tt.new_file('file', tt.root, '\x00\n\x00\r\x01\n\x02\r\xff', 'binary-1')
741
tt.new_file('file2', tt.root, '\x01\n\x02\r\x03\n\x04\r\xff',
778
tt.new_file('file', tt.root, [b'\x00\n\x00\r\x01\n\x02\r\xff'], b'binary-1')
779
tt.new_file('file2', tt.root, [b'\x01\n\x02\r\x03\n\x04\r\xff'],
744
self.tree1.commit('add binary', rev_id='b@cset-0-1')
745
self.get_valid_bundle('null:', 'b@cset-0-1')
782
self.tree1.commit('add binary', rev_id=b'b@cset-0-1')
783
self.get_valid_bundle(b'null:', b'b@cset-0-1')
748
786
tt = TreeTransform(self.tree1)
749
trans_id = tt.trans_id_tree_file_id('binary-1')
787
trans_id = tt.trans_id_tree_path('file')
750
788
tt.delete_contents(trans_id)
752
self.tree1.commit('delete binary', rev_id='b@cset-0-2')
753
self.get_valid_bundle('b@cset-0-1', 'b@cset-0-2')
790
self.tree1.commit('delete binary', rev_id=b'b@cset-0-2')
791
self.get_valid_bundle(b'b@cset-0-1', b'b@cset-0-2')
755
793
# Rename & modify
756
794
tt = TreeTransform(self.tree1)
757
trans_id = tt.trans_id_tree_file_id('binary-2')
795
trans_id = tt.trans_id_tree_path('file2')
758
796
tt.adjust_path('file3', tt.root, trans_id)
759
797
tt.delete_contents(trans_id)
760
tt.create_file('file\rcontents\x00\n\x00', trans_id)
798
tt.create_file([b'file\rcontents\x00\n\x00'], trans_id)
762
self.tree1.commit('rename and modify binary', rev_id='b@cset-0-3')
763
self.get_valid_bundle('b@cset-0-2', 'b@cset-0-3')
800
self.tree1.commit('rename and modify binary', rev_id=b'b@cset-0-3')
801
self.get_valid_bundle(b'b@cset-0-2', b'b@cset-0-3')
766
804
tt = TreeTransform(self.tree1)
767
trans_id = tt.trans_id_tree_file_id('binary-2')
805
trans_id = tt.trans_id_tree_path('file3')
768
806
tt.delete_contents(trans_id)
769
tt.create_file('\x00file\rcontents', trans_id)
807
tt.create_file([b'\x00file\rcontents'], trans_id)
771
self.tree1.commit('just modify binary', rev_id='b@cset-0-4')
772
self.get_valid_bundle('b@cset-0-3', 'b@cset-0-4')
809
self.tree1.commit('just modify binary', rev_id=b'b@cset-0-4')
810
self.get_valid_bundle(b'b@cset-0-3', b'b@cset-0-4')
775
self.get_valid_bundle('null:', 'b@cset-0-4')
813
self.get_valid_bundle(b'null:', b'b@cset-0-4')
777
815
def test_last_modified(self):
778
816
self.tree1 = self.make_branch_and_tree('b1')
779
817
self.b1 = self.tree1.branch
780
818
tt = TreeTransform(self.tree1)
781
tt.new_file('file', tt.root, 'file', 'file')
819
tt.new_file('file', tt.root, [b'file'], b'file')
783
self.tree1.commit('create file', rev_id='a@lmod-0-1')
821
self.tree1.commit('create file', rev_id=b'a@lmod-0-1')
785
823
tt = TreeTransform(self.tree1)
786
trans_id = tt.trans_id_tree_file_id('file')
824
trans_id = tt.trans_id_tree_path('file')
787
825
tt.delete_contents(trans_id)
788
tt.create_file('file2', trans_id)
826
tt.create_file([b'file2'], trans_id)
790
self.tree1.commit('modify text', rev_id='a@lmod-0-2a')
828
self.tree1.commit('modify text', rev_id=b'a@lmod-0-2a')
792
other = self.get_checkout('a@lmod-0-1')
830
other = self.get_checkout(b'a@lmod-0-1')
793
831
tt = TreeTransform(other)
794
trans_id = tt.trans_id_tree_file_id('file')
832
trans_id = tt.trans_id_tree_path('file2')
795
833
tt.delete_contents(trans_id)
796
tt.create_file('file2', trans_id)
834
tt.create_file([b'file2'], trans_id)
798
other.commit('modify text in another tree', rev_id='a@lmod-0-2b')
836
other.commit('modify text in another tree', rev_id=b'a@lmod-0-2b')
799
837
self.tree1.merge_from_branch(other.branch)
800
self.tree1.commit(u'Merge', rev_id='a@lmod-0-3',
838
self.tree1.commit(u'Merge', rev_id=b'a@lmod-0-3',
802
self.tree1.commit(u'Merge', rev_id='a@lmod-0-4')
803
bundle = self.get_valid_bundle('a@lmod-0-2a', 'a@lmod-0-4')
840
self.tree1.commit(u'Merge', rev_id=b'a@lmod-0-4')
841
bundle = self.get_valid_bundle(b'a@lmod-0-2a', b'a@lmod-0-4')
805
843
def test_hide_history(self):
806
844
self.tree1 = self.make_branch_and_tree('b1')
807
845
self.b1 = self.tree1.branch
809
open('b1/one', 'wb').write('one\n')
847
with open('b1/one', 'wb') as f: f.write(b'one\n')
810
848
self.tree1.add('one')
811
self.tree1.commit('add file', rev_id='a@cset-0-1')
812
open('b1/one', 'wb').write('two\n')
813
self.tree1.commit('modify', rev_id='a@cset-0-2')
814
open('b1/one', 'wb').write('three\n')
815
self.tree1.commit('modify', rev_id='a@cset-0-3')
816
bundle_file = StringIO()
817
rev_ids = write_bundle(self.tree1.branch.repository, 'a@cset-0-3',
818
'a@cset-0-1', bundle_file, format=self.format)
819
self.assertNotContainsRe(bundle_file.getvalue(), '\btwo\b')
820
self.assertContainsRe(self.get_raw(bundle_file), 'one')
821
self.assertContainsRe(self.get_raw(bundle_file), 'three')
849
self.tree1.commit('add file', rev_id=b'a@cset-0-1')
850
with open('b1/one', 'wb') as f: f.write(b'two\n')
851
self.tree1.commit('modify', rev_id=b'a@cset-0-2')
852
with open('b1/one', 'wb') as f: f.write(b'three\n')
853
self.tree1.commit('modify', rev_id=b'a@cset-0-3')
854
bundle_file = BytesIO()
855
rev_ids = write_bundle(self.tree1.branch.repository, b'a@cset-0-3',
856
b'a@cset-0-1', bundle_file, format=self.format)
857
self.assertNotContainsRe(bundle_file.getvalue(), b'\btwo\b')
858
self.assertContainsRe(self.get_raw(bundle_file), b'one')
859
self.assertContainsRe(self.get_raw(bundle_file), b'three')
823
861
def test_bundle_same_basis(self):
824
862
"""Ensure using the basis as the target doesn't cause an error"""
825
863
self.tree1 = self.make_branch_and_tree('b1')
826
self.tree1.commit('add file', rev_id='a@cset-0-1')
827
bundle_file = StringIO()
828
rev_ids = write_bundle(self.tree1.branch.repository, 'a@cset-0-1',
829
'a@cset-0-1', bundle_file)
864
self.tree1.commit('add file', rev_id=b'a@cset-0-1')
865
bundle_file = BytesIO()
866
rev_ids = write_bundle(self.tree1.branch.repository, b'a@cset-0-1',
867
b'a@cset-0-1', bundle_file)
832
870
def get_raw(bundle_file):
833
871
return bundle_file.getvalue()
835
873
def test_unicode_bundle(self):
836
self.requireFeature(tests.UnicodeFilenameFeature)
874
self.requireFeature(features.UnicodeFilenameFeature)
837
875
# Handle international characters
839
877
f = open(u'b1/with Dod\N{Euro Sign}', 'wb')
846
884
u'William Dod\xe9\n').encode('utf-8'))
849
self.tree1.add([u'with Dod\N{Euro Sign}'], ['withdod-id'])
887
self.tree1.add([u'with Dod\N{Euro Sign}'], [b'withdod-id'])
850
888
self.tree1.commit(u'i18n commit from William Dod\xe9',
851
rev_id='i18n-1', committer=u'William Dod\xe9')
889
rev_id=b'i18n-1', committer=u'William Dod\xe9')
854
bundle = self.get_valid_bundle('null:', 'i18n-1')
892
bundle = self.get_valid_bundle(b'null:', b'i18n-1')
857
895
f = open(u'b1/with Dod\N{Euro Sign}', 'wb')
858
896
f.write(u'Modified \xb5\n'.encode('utf8'))
860
self.tree1.commit(u'modified', rev_id='i18n-2')
898
self.tree1.commit(u'modified', rev_id=b'i18n-2')
862
bundle = self.get_valid_bundle('i18n-1', 'i18n-2')
900
bundle = self.get_valid_bundle(b'i18n-1', b'i18n-2')
865
903
self.tree1.rename_one(u'with Dod\N{Euro Sign}', u'B\N{Euro Sign}gfors')
866
self.tree1.commit(u'renamed, the new i18n man', rev_id='i18n-3',
904
self.tree1.commit(u'renamed, the new i18n man', rev_id=b'i18n-3',
867
905
committer=u'Erik B\xe5gfors')
869
bundle = self.get_valid_bundle('i18n-2', 'i18n-3')
907
bundle = self.get_valid_bundle(b'i18n-2', b'i18n-3')
872
910
self.tree1.remove([u'B\N{Euro Sign}gfors'])
873
self.tree1.commit(u'removed', rev_id='i18n-4')
911
self.tree1.commit(u'removed', rev_id=b'i18n-4')
875
bundle = self.get_valid_bundle('i18n-3', 'i18n-4')
913
bundle = self.get_valid_bundle(b'i18n-3', b'i18n-4')
878
bundle = self.get_valid_bundle('null:', 'i18n-4')
916
bundle = self.get_valid_bundle(b'null:', b'i18n-4')
881
919
def test_whitespace_bundle(self):
891
929
# once we actually support them
894
self.tree1.commit('funky whitespace', rev_id='white-1')
932
self.tree1.commit('funky whitespace', rev_id=b'white-1')
896
bundle = self.get_valid_bundle('null:', 'white-1')
934
bundle = self.get_valid_bundle(b'null:', b'white-1')
899
open('b1/trailing space ', 'ab').write('add some text\n')
900
self.tree1.commit('add text', rev_id='white-2')
937
with open('b1/trailing space ', 'ab') as f: f.write(b'add some text\n')
938
self.tree1.commit('add text', rev_id=b'white-2')
902
bundle = self.get_valid_bundle('white-1', 'white-2')
940
bundle = self.get_valid_bundle(b'white-1', b'white-2')
905
943
self.tree1.rename_one('trailing space ', ' start and end space ')
906
self.tree1.commit('rename', rev_id='white-3')
944
self.tree1.commit('rename', rev_id=b'white-3')
908
bundle = self.get_valid_bundle('white-2', 'white-3')
946
bundle = self.get_valid_bundle(b'white-2', b'white-3')
911
949
self.tree1.remove([' start and end space '])
912
self.tree1.commit('removed', rev_id='white-4')
950
self.tree1.commit('removed', rev_id=b'white-4')
914
bundle = self.get_valid_bundle('white-3', 'white-4')
952
bundle = self.get_valid_bundle(b'white-3', b'white-4')
916
954
# Now test a complet roll-up
917
bundle = self.get_valid_bundle('null:', 'white-4')
955
bundle = self.get_valid_bundle(b'null:', b'white-4')
919
957
def test_alt_timezone_bundle(self):
920
958
self.tree1 = self.make_branch_and_memory_tree('b1')
941
979
def test_bundle_root_id(self):
942
980
self.tree1 = self.make_branch_and_tree('b1')
943
981
self.b1 = self.tree1.branch
944
self.tree1.commit('message', rev_id='revid1')
945
bundle = self.get_valid_bundle('null:', 'revid1')
946
tree = self.get_bundle_tree(bundle, 'revid1')
947
self.assertEqual('revid1', tree.inventory.root.revision)
982
self.tree1.commit('message', rev_id=b'revid1')
983
bundle = self.get_valid_bundle(b'null:', b'revid1')
984
tree = self.get_bundle_tree(bundle, b'revid1')
985
root_revision = tree.get_file_revision(u'', tree.get_root_id())
986
self.assertEqual(b'revid1', root_revision)
949
988
def test_install_revisions(self):
950
989
self.tree1 = self.make_branch_and_tree('b1')
951
990
self.b1 = self.tree1.branch
952
self.tree1.commit('message', rev_id='rev2a')
953
bundle = self.get_valid_bundle('null:', 'rev2a')
991
self.tree1.commit('message', rev_id=b'rev2a')
992
bundle = self.get_valid_bundle(b'null:', b'rev2a')
954
993
branch2 = self.make_branch('b2')
955
self.assertFalse(branch2.repository.has_revision('rev2a'))
994
self.assertFalse(branch2.repository.has_revision(b'rev2a'))
956
995
target_revision = bundle.install_revisions(branch2.repository)
957
self.assertTrue(branch2.repository.has_revision('rev2a'))
958
self.assertEqual('rev2a', target_revision)
996
self.assertTrue(branch2.repository.has_revision(b'rev2a'))
997
self.assertEqual(b'rev2a', target_revision)
960
999
def test_bundle_empty_property(self):
961
1000
"""Test serializing revision properties with an empty value."""
962
1001
tree = self.make_branch_and_memory_tree('tree')
963
1002
tree.lock_write()
964
1003
self.addCleanup(tree.unlock)
965
tree.add([''], ['TREE_ROOT'])
966
tree.commit('One', revprops={'one':'two', 'empty':''}, rev_id='rev1')
1004
tree.add([''], [b'TREE_ROOT'])
1005
tree.commit('One', revprops={u'one': 'two', u'empty': ''}, rev_id=b'rev1')
967
1006
self.b1 = tree.branch
968
bundle_sio, revision_ids = self.create_bundle_text('null:', 'rev1')
1007
bundle_sio, revision_ids = self.create_bundle_text(b'null:', b'rev1')
969
1008
bundle = read_bundle(bundle_sio)
970
1009
revision_info = bundle.revisions[0]
971
self.assertEqual('rev1', revision_info.revision_id)
1010
self.assertEqual(b'rev1', revision_info.revision_id)
972
1011
rev = revision_info.as_revision()
973
1012
self.assertEqual({'branch-nick':'tree', 'empty':'', 'one':'two'},
1035
1074
def test_across_serializers(self):
1036
1075
tree = self.make_simple_tree('knit')
1037
tree.commit('hello', rev_id='rev1')
1038
tree.commit('hello', rev_id='rev2')
1039
bundle = read_bundle(self.create_bundle_text('null:', 'rev2')[0])
1076
tree.commit('hello', rev_id=b'rev1')
1077
tree.commit('hello', rev_id=b'rev2')
1078
bundle = read_bundle(self.create_bundle_text(b'null:', b'rev2')[0])
1040
1079
repo = self.make_repository('repo', format='dirstate-with-subtree')
1041
1080
bundle.install_revisions(repo)
1042
inv_text = repo._get_inventory_xml('rev2')
1043
self.assertNotContainsRe(inv_text, 'format="5"')
1044
self.assertContainsRe(inv_text, 'format="7"')
1081
inv_text = repo._get_inventory_xml(b'rev2')
1082
self.assertNotContainsRe(inv_text, b'format="5"')
1083
self.assertContainsRe(inv_text, b'format="7"')
1046
1085
def make_repo_with_installed_revisions(self):
1047
1086
tree = self.make_simple_tree('knit')
1048
tree.commit('hello', rev_id='rev1')
1049
tree.commit('hello', rev_id='rev2')
1050
bundle = read_bundle(self.create_bundle_text('null:', 'rev2')[0])
1087
tree.commit('hello', rev_id=b'rev1')
1088
tree.commit('hello', rev_id=b'rev2')
1089
bundle = read_bundle(self.create_bundle_text(b'null:', b'rev2')[0])
1051
1090
repo = self.make_repository('repo', format='dirstate-with-subtree')
1052
1091
bundle.install_revisions(repo)
1055
1094
def test_across_models(self):
1056
1095
repo = self.make_repo_with_installed_revisions()
1057
inv = repo.get_inventory('rev2')
1058
self.assertEqual('rev2', inv.root.revision)
1096
inv = repo.get_inventory(b'rev2')
1097
self.assertEqual(b'rev2', inv.root.revision)
1059
1098
root_id = inv.root.file_id
1060
1099
repo.lock_read()
1061
1100
self.addCleanup(repo.unlock)
1062
self.assertEqual({(root_id, 'rev1'):(),
1063
(root_id, 'rev2'):((root_id, 'rev1'),)},
1064
repo.texts.get_parent_map([(root_id, 'rev1'), (root_id, 'rev2')]))
1101
self.assertEqual({(root_id, b'rev1'):(),
1102
(root_id, b'rev2'):((root_id, b'rev1'),)},
1103
repo.texts.get_parent_map([(root_id, b'rev1'), (root_id, b'rev2')]))
1066
1105
def test_inv_hash_across_serializers(self):
1067
1106
repo = self.make_repo_with_installed_revisions()
1068
recorded_inv_sha1 = repo.get_revision('rev2').inventory_sha1
1069
xml = repo._get_inventory_xml('rev2')
1107
recorded_inv_sha1 = repo.get_revision(b'rev2').inventory_sha1
1108
xml = repo._get_inventory_xml(b'rev2')
1070
1109
self.assertEqual(osutils.sha_string(xml), recorded_inv_sha1)
1072
1111
def test_across_models_incompatible(self):
1073
1112
tree = self.make_simple_tree('dirstate-with-subtree')
1074
tree.commit('hello', rev_id='rev1')
1075
tree.commit('hello', rev_id='rev2')
1113
tree.commit('hello', rev_id=b'rev1')
1114
tree.commit('hello', rev_id=b'rev2')
1077
bundle = read_bundle(self.create_bundle_text('null:', 'rev1')[0])
1116
bundle = read_bundle(self.create_bundle_text(b'null:', b'rev1')[0])
1078
1117
except errors.IncompatibleBundleFormat:
1079
1118
raise tests.TestSkipped("Format 0.8 doesn't work with knit3")
1080
1119
repo = self.make_repository('repo', format='knit')
1081
1120
bundle.install_revisions(repo)
1083
bundle = read_bundle(self.create_bundle_text('null:', 'rev2')[0])
1122
bundle = read_bundle(self.create_bundle_text(b'null:', b'rev2')[0])
1084
1123
self.assertRaises(errors.IncompatibleRevision,
1085
1124
bundle.install_revisions, repo)
1087
1126
def test_get_merge_request(self):
1088
1127
tree = self.make_simple_tree()
1089
tree.commit('hello', rev_id='rev1')
1090
tree.commit('hello', rev_id='rev2')
1091
bundle = read_bundle(self.create_bundle_text('null:', 'rev1')[0])
1128
tree.commit('hello', rev_id=b'rev1')
1129
tree.commit('hello', rev_id=b'rev2')
1130
bundle = read_bundle(self.create_bundle_text(b'null:', b'rev1')[0])
1092
1131
result = bundle.get_merge_request(tree.branch.repository)
1093
self.assertEqual((None, 'rev1', 'inapplicable'), result)
1132
self.assertEqual((None, b'rev1', 'inapplicable'), result)
1095
1134
def test_with_subtree(self):
1096
1135
tree = self.make_branch_and_tree('tree',
1116
1155
self.tree1 = self.make_branch_and_tree('tree')
1117
1156
self.b1 = self.tree1.branch
1119
self.tree1.commit('Revision/id/with/slashes', rev_id='rev/id')
1158
self.tree1.commit('Revision/id/with/slashes', rev_id=b'rev/id')
1120
1159
except ValueError:
1121
1160
raise tests.TestSkipped(
1122
1161
"Repository doesn't support revision ids with slashes")
1123
bundle = self.get_valid_bundle('null:', 'rev/id')
1162
bundle = self.get_valid_bundle(b'null:', b'rev/id')
1125
1164
def test_skip_file(self):
1126
1165
"""Make sure we don't accidentally write to the wrong versionedfile"""
1127
1166
self.tree1 = self.make_branch_and_tree('tree')
1128
1167
self.b1 = self.tree1.branch
1129
1168
# rev1 is not present in bundle, done by fetch
1130
self.build_tree_contents([('tree/file2', 'contents1')])
1131
self.tree1.add('file2', 'file2-id')
1132
self.tree1.commit('rev1', rev_id='reva')
1133
self.build_tree_contents([('tree/file3', 'contents2')])
1169
self.build_tree_contents([('tree/file2', b'contents1')])
1170
self.tree1.add('file2', b'file2-id')
1171
self.tree1.commit('rev1', rev_id=b'reva')
1172
self.build_tree_contents([('tree/file3', b'contents2')])
1134
1173
# rev2 is present in bundle, and done by fetch
1135
1174
# having file1 in the bunle causes file1's versionedfile to be opened.
1136
self.tree1.add('file3', 'file3-id')
1137
self.tree1.commit('rev2')
1175
self.tree1.add('file3', b'file3-id')
1176
rev2 = self.tree1.commit('rev2')
1138
1177
# Updating file2 should not cause an attempt to add to file1's vf
1139
target = self.tree1.bzrdir.sprout('target').open_workingtree()
1140
self.build_tree_contents([('tree/file2', 'contents3')])
1141
self.tree1.commit('rev3', rev_id='rev3')
1142
bundle = self.get_valid_bundle('reva', 'rev3')
1178
target = self.tree1.controldir.sprout('target').open_workingtree()
1179
self.build_tree_contents([('tree/file2', b'contents3')])
1180
self.tree1.commit('rev3', rev_id=b'rev3')
1181
bundle = self.get_valid_bundle(b'reva', b'rev3')
1143
1182
if getattr(bundle, 'get_bundle_reader', None) is None:
1144
1183
raise tests.TestSkipped('Bundle format cannot provide reader')
1145
# be sure that file1 comes before file2
1146
for b, m, k, r, f in bundle.get_bundle_reader().iter_records():
1149
self.assertNotEqual(f, 'file2-id')
1185
(f, r) for b, m, k, r, f in bundle.get_bundle_reader().iter_records()
1187
self.assertEqual({(b'file2-id', b'rev3'), (b'file3-id', rev2)}, file_ids)
1150
1188
bundle.install_revisions(target.branch.repository)
1332
1370
:return: The in-memory bundle
1334
from bzrlib.bundle import serializer
1372
from ..bundle import serializer
1335
1373
bundle_txt, rev_ids = self.create_bundle_text(base_rev_id, rev_id)
1336
new_text = self.get_raw(StringIO(''.join(bundle_txt)))
1337
new_text = new_text.replace('<file file_id="exe-1"',
1338
'<file executable="y" file_id="exe-1"')
1339
new_text = new_text.replace('B260', 'B275')
1340
bundle_txt = StringIO()
1374
new_text = self.get_raw(BytesIO(b''.join(bundle_txt)))
1375
new_text = new_text.replace(b'<file file_id="exe-1"',
1376
b'<file executable="y" file_id="exe-1"')
1377
new_text = new_text.replace(b'B260', b'B275')
1378
bundle_txt = BytesIO()
1341
1379
bundle_txt.write(serializer._get_bundle_header('4'))
1342
bundle_txt.write('\n')
1343
bundle_txt.write(new_text.encode('bz2'))
1380
bundle_txt.write(b'\n')
1381
bundle_txt.write(bz2.compress(new_text))
1344
1382
bundle_txt.seek(0)
1345
1383
bundle = read_bundle(bundle_txt)
1346
1384
self.valid_apply_bundle(base_rev_id, bundle)
1349
1387
def create_bundle_text(self, base_rev_id, rev_id):
1350
bundle_txt = StringIO()
1388
bundle_txt = BytesIO()
1351
1389
rev_ids = write_bundle(self.b1.repository, rev_id, base_rev_id,
1352
1390
bundle_txt, format=self.format)
1353
1391
bundle_txt.seek(0)
1354
1392
self.assertEqual(bundle_txt.readline(),
1355
'# Bazaar revision bundle v%s\n' % self.format)
1356
self.assertEqual(bundle_txt.readline(), '#\n')
1393
b'# Bazaar revision bundle v%s\n' % self.format.encode('ascii'))
1394
self.assertEqual(bundle_txt.readline(), b'#\n')
1357
1395
rev = self.b1.repository.get_revision(rev_id)
1358
1396
bundle_txt.seek(0)
1359
1397
return bundle_txt, rev_ids
1380
1419
target_repo.lock_read()
1381
1420
self.addCleanup(target_repo.unlock)
1382
1421
# Turn the 'iterators_of_bytes' back into simple strings for comparison
1383
repo_texts = dict((i, ''.join(content)) for i, content
1422
repo_texts = dict((i, b''.join(content)) for i, content
1384
1423
in target_repo.iter_files_bytes(
1385
[('fileid-2', 'rev1', '1'),
1386
('fileid-2', 'rev2', '2')]))
1387
self.assertEqual({'1':'contents1\nstatic\n',
1388
'2':'contents2\nstatic\n'},
1424
[(b'fileid-2', b'rev1', '1'),
1425
(b'fileid-2', b'rev2', '2')]))
1426
self.assertEqual({'1':b'contents1\nstatic\n',
1427
'2':b'contents2\nstatic\n'},
1390
rtree = target_repo.revision_tree('rev2')
1429
rtree = target_repo.revision_tree(b'rev2')
1391
1430
inventory_vf = target_repo.inventories
1392
1431
# If the inventory store has a graph, it must match the revision graph.
1393
1432
self.assertSubset(
1394
[inventory_vf.get_parent_map([('rev2',)])[('rev2',)]],
1395
[None, (('rev1',),)])
1433
[inventory_vf.get_parent_map([(b'rev2',)])[(b'rev2',)]],
1434
[None, ((b'rev1',),)])
1396
1435
self.assertEqual('changed file',
1397
target_repo.get_revision('rev2').message)
1436
target_repo.get_revision(b'rev2').message)
1400
1439
def get_raw(bundle_file):
1402
1441
line = bundle_file.readline()
1403
1442
line = bundle_file.readline()
1404
1443
lines = bundle_file.readlines()
1405
return ''.join(lines).decode('bz2')
1444
return bz2.decompress(b''.join(lines))
1407
1446
def test_copy_signatures(self):
1408
1447
tree_a = self.make_branch_and_tree('tree_a')
1410
import bzrlib.commit as commit
1411
oldstrategy = bzrlib.gpg.GPGStrategy
1449
import breezy.commit as commit
1450
oldstrategy = breezy.gpg.GPGStrategy
1412
1451
branch = tree_a.branch
1413
1452
repo_a = branch.repository
1414
tree_a.commit("base", allow_pointless=True, rev_id='A')
1415
self.failIf(branch.repository.has_signature_for_revision_id('A'))
1453
tree_a.commit("base", allow_pointless=True, rev_id=b'A')
1454
self.assertFalse(branch.repository.has_signature_for_revision_id(b'A'))
1417
from bzrlib.testament import Testament
1456
from ..testament import Testament
1418
1457
# monkey patch gpg signing mechanism
1419
bzrlib.gpg.GPGStrategy = bzrlib.gpg.LoopbackGPGStrategy
1420
new_config = test_commit.MustSignConfig(branch)
1421
commit.Commit(config=new_config).commit(message="base",
1458
breezy.gpg.GPGStrategy = breezy.gpg.LoopbackGPGStrategy
1459
new_config = test_commit.MustSignConfig()
1460
commit.Commit(config_stack=new_config).commit(message="base",
1422
1461
allow_pointless=True,
1424
1463
working_tree=tree_a)
1425
1464
def sign(text):
1426
return bzrlib.gpg.LoopbackGPGStrategy(None).sign(text)
1427
self.assertTrue(repo_a.has_signature_for_revision_id('B'))
1465
return breezy.gpg.LoopbackGPGStrategy(None).sign(text)
1466
self.assertTrue(repo_a.has_signature_for_revision_id(b'B'))
1429
bzrlib.gpg.GPGStrategy = oldstrategy
1468
breezy.gpg.GPGStrategy = oldstrategy
1430
1469
tree_b = self.make_branch_and_tree('tree_b')
1431
1470
repo_b = tree_b.branch.repository
1433
1472
serializer = BundleSerializerV4('4')
1434
serializer.write(tree_a.branch.repository, ['A', 'B'], {}, s)
1473
with tree_a.lock_read():
1474
serializer.write_bundle(tree_a.branch.repository, b'B', b'null:', s)
1436
1476
install_bundle(repo_b, serializer.read(s))
1437
self.assertTrue(repo_b.has_signature_for_revision_id('B'))
1438
self.assertEqual(repo_b.get_signature_text('B'),
1439
repo_a.get_signature_text('B'))
1477
self.assertTrue(repo_b.has_signature_for_revision_id(b'B'))
1478
self.assertEqual(repo_b.get_signature_text(b'B'),
1479
repo_a.get_signature_text(b'B'))
1441
1481
# ensure repeat installs are harmless
1442
1482
install_bundle(repo_b, serializer.read(s))
1445
class V4WeaveBundleTester(V4BundleTester):
1447
def bzrdir_format(self):
1451
1485
class V4_2aBundleTester(V4BundleTester):
1453
1487
def bzrdir_format(self):
1480
1514
def make_merged_branch(self):
1481
1515
builder = self.make_branch_builder('source')
1482
1516
builder.start_series()
1483
builder.build_snapshot('a@cset-0-1', None, [
1484
('add', ('', 'root-id', 'directory', None)),
1485
('add', ('file', 'file-id', 'file', 'original content\n')),
1487
builder.build_snapshot('a@cset-0-2a', ['a@cset-0-1'], [
1488
('modify', ('file-id', 'new-content\n')),
1490
builder.build_snapshot('a@cset-0-2b', ['a@cset-0-1'], [
1491
('add', ('other-file', 'file2-id', 'file', 'file2-content\n')),
1493
builder.build_snapshot('a@cset-0-3', ['a@cset-0-2a', 'a@cset-0-2b'], [
1494
('add', ('other-file', 'file2-id', 'file', 'file2-content\n')),
1517
builder.build_snapshot(None, [
1518
('add', ('', b'root-id', 'directory', None)),
1519
('add', ('file', b'file-id', 'file', b'original content\n')),
1520
], revision_id=b'a@cset-0-1')
1521
builder.build_snapshot([b'a@cset-0-1'], [
1522
('modify', ('file', b'new-content\n')),
1523
], revision_id=b'a@cset-0-2a')
1524
builder.build_snapshot([b'a@cset-0-1'], [
1525
('add', ('other-file', b'file2-id', 'file', b'file2-content\n')),
1526
], revision_id=b'a@cset-0-2b')
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')),
1529
], revision_id=b'a@cset-0-3')
1496
1530
builder.finish_series()
1497
1531
self.b1 = builder.get_branch()
1498
1532
self.b1.lock_read()
1513
1547
def test_single_inventory_multiple_parents_as_xml(self):
1514
1548
self.make_merged_branch()
1515
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',
1517
1551
reader = v4.BundleReader(sio, stream_input=False)
1518
1552
records = list(reader.iter_records())
1519
1553
self.assertEqual(1, len(records))
1520
1554
(bytes, metadata, repo_kind, revision_id,
1521
1555
file_id) = records[0]
1522
1556
self.assertIs(None, file_id)
1523
self.assertEqual('a@cset-0-3', revision_id)
1557
self.assertEqual(b'a@cset-0-3', revision_id)
1524
1558
self.assertEqual('inventory', repo_kind)
1525
self.assertEqual({'parents': ['a@cset-0-2a', 'a@cset-0-2b'],
1526
'sha1': '09c53b0c4de0895e11a2aacc34fef60a6e70865c',
1527
'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',
1529
1563
# We should have an mpdiff that takes some lines from both parents.
1530
1564
self.assertEqualDiff(
1532
'<inventory format="10" revision_id="a@cset-0-3">\n'
1535
'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)
1537
1571
def test_single_inv_no_parents_as_xml(self):
1538
1572
self.make_merged_branch()
1539
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',
1541
1575
reader = v4.BundleReader(sio, stream_input=False)
1542
1576
records = list(reader.iter_records())
1543
1577
self.assertEqual(1, len(records))
1544
1578
(bytes, metadata, repo_kind, revision_id,
1545
1579
file_id) = records[0]
1546
1580
self.assertIs(None, file_id)
1547
self.assertEqual('a@cset-0-1', revision_id)
1581
self.assertEqual(b'a@cset-0-1', revision_id)
1548
1582
self.assertEqual('inventory', repo_kind)
1549
self.assertEqual({'parents': [],
1550
'sha1': 'a13f42b142d544aac9b085c42595d304150e31a2',
1551
'storage_kind': 'mpdiff',
1583
self.assertEqual({b'parents': [],
1584
b'sha1': b'a13f42b142d544aac9b085c42595d304150e31a2',
1585
b'storage_kind': b'mpdiff',
1553
1587
# We should have an mpdiff that takes some lines from both parents.
1554
1588
self.assertEqualDiff(
1556
'<inventory format="10" revision_id="a@cset-0-1">\n'
1557
'<directory file_id="root-id" name=""'
1558
' revision="a@cset-0-1" />\n'
1559
'<file file_id="file-id" name="file" parent_id="root-id"'
1560
' revision="a@cset-0-1"'
1561
' text_sha1="09c2f8647e14e49e922b955c194102070597c2d1"'
1562
' 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'
1566
1600
def test_multiple_inventories_as_xml(self):
1567
1601
self.make_merged_branch()
1568
sio = self.make_bundle_just_inventories('a@cset-0-1', 'a@cset-0-3',
1569
['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'])
1570
1604
reader = v4.BundleReader(sio, stream_input=False)
1571
1605
records = list(reader.iter_records())
1572
1606
self.assertEqual(3, len(records))
1573
1607
revision_ids = [rev_id for b, m, k, rev_id, f in records]
1574
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'],
1576
1610
metadata_2a = records[0][1]
1577
self.assertEqual({'parents': ['a@cset-0-1'],
1578
'sha1': '1e105886d62d510763e22885eec733b66f5f09bf',
1579
'storage_kind': 'mpdiff',
1611
self.assertEqual({b'parents': [b'a@cset-0-1'],
1612
b'sha1': b'1e105886d62d510763e22885eec733b66f5f09bf',
1613
b'storage_kind': b'mpdiff',
1580
1614
}, metadata_2a)
1581
1615
metadata_2b = records[1][1]
1582
self.assertEqual({'parents': ['a@cset-0-1'],
1583
'sha1': 'f03f12574bdb5ed2204c28636c98a8547544ccd8',
1584
'storage_kind': 'mpdiff',
1616
self.assertEqual({b'parents': [b'a@cset-0-1'],
1617
b'sha1': b'f03f12574bdb5ed2204c28636c98a8547544ccd8',
1618
b'storage_kind': b'mpdiff',
1585
1619
}, metadata_2b)
1586
1620
metadata_3 = records[2][1]
1587
self.assertEqual({'parents': ['a@cset-0-2a', 'a@cset-0-2b'],
1588
'sha1': '09c53b0c4de0895e11a2aacc34fef60a6e70865c',
1589
'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',
1591
1625
bytes_2a = records[0][0]
1592
1626
self.assertEqualDiff(
1594
'<inventory format="10" revision_id="a@cset-0-2a">\n'
1598
'<file file_id="file-id" name="file" parent_id="root-id"'
1599
' revision="a@cset-0-2a"'
1600
' text_sha1="50f545ff40e57b6924b1f3174b267ffc4576e9a9"'
1601
' text_size="12" />\n'
1603
'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)
1604
1638
bytes_2b = records[1][0]
1605
1639
self.assertEqualDiff(
1607
'<inventory format="10" revision_id="a@cset-0-2b">\n'
1611
'<file file_id="file2-id" name="other-file" parent_id="root-id"'
1612
' revision="a@cset-0-2b"'
1613
' text_sha1="b46c0c8ea1e5ef8e46fc8894bfd4752a88ec939e"'
1614
' text_size="14" />\n'
1616
'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)
1617
1651
bytes_3 = records[2][0]
1618
1652
self.assertEqualDiff(
1620
'<inventory format="10" revision_id="a@cset-0-3">\n'
1623
'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)
1625
1659
def test_creating_bundle_preserves_chk_pages(self):
1626
1660
self.make_merged_branch()
1627
target = self.b1.bzrdir.sprout('target',
1628
revision_id='a@cset-0-2a').open_branch()
1629
bundle_txt, rev_ids = self.create_bundle_text('a@cset-0-2a',
1631
self.assertEqual(['a@cset-0-2b', 'a@cset-0-3'], rev_ids)
1661
target = self.b1.controldir.sprout('target',
1662
revision_id=b'a@cset-0-2a').open_branch()
1663
bundle_txt, rev_ids = self.create_bundle_text(b'a@cset-0-2a',
1665
self.assertEqual(set([b'a@cset-0-2b', b'a@cset-0-3']), set(rev_ids))
1632
1666
bundle = read_bundle(bundle_txt)
1633
1667
target.lock_write()
1634
1668
self.addCleanup(target.unlock)
1635
1669
install_bundle(target.repository, bundle)
1636
inv1 = self.b1.repository.inventories.get_record_stream([
1637
('a@cset-0-3',)], 'unordered',
1638
True).next().get_bytes_as('fulltext')
1639
inv2 = target.repository.inventories.get_record_stream([
1640
('a@cset-0-3',)], 'unordered',
1641
True).next().get_bytes_as('fulltext')
1670
inv1 = next(self.b1.repository.inventories.get_record_stream([
1671
(b'a@cset-0-3',)], 'unordered',
1672
True)).get_bytes_as('fulltext')
1673
inv2 = next(target.repository.inventories.get_record_stream([
1674
(b'a@cset-0-3',)], 'unordered',
1675
True)).get_bytes_as('fulltext')
1642
1676
self.assertEqualDiff(inv1, inv2)
1740
1774
class TestBundleWriterReader(tests.TestCase):
1742
1776
def test_roundtrip_record(self):
1743
fileobj = StringIO()
1744
1778
writer = v4.BundleWriter(fileobj)
1746
writer.add_info_record(foo='bar')
1747
writer._add_record("Record body", {'parents': ['1', '3'],
1748
'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')
1750
1784
fileobj.seek(0)
1751
1785
reader = v4.BundleReader(fileobj, stream_input=True)
1752
1786
record_iter = reader.iter_records()
1753
record = record_iter.next()
1754
self.assertEqual((None, {'foo': 'bar', 'storage_kind': 'header'},
1787
record = next(record_iter)
1788
self.assertEqual((None, {b'foo': b'bar', b'storage_kind': b'header'},
1755
1789
'info', None, None), record)
1756
record = record_iter.next()
1757
self.assertEqual(("Record body", {'storage_kind': 'fulltext',
1758
'parents': ['1', '3']}, 'file', 'revid', 'fileid'),
1790
record = next(record_iter)
1791
self.assertEqual(("Record body", {b'storage_kind': b'fulltext',
1792
b'parents': [b'1', b'3']}, 'file', b'revid', b'fileid'),
1761
1795
def test_roundtrip_record_memory_hungry(self):
1762
fileobj = StringIO()
1763
1797
writer = v4.BundleWriter(fileobj)
1765
writer.add_info_record(foo='bar')
1766
writer._add_record("Record body", {'parents': ['1', '3'],
1767
'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')
1769
1803
fileobj.seek(0)
1770
1804
reader = v4.BundleReader(fileobj, stream_input=False)
1771
1805
record_iter = reader.iter_records()
1772
record = record_iter.next()
1773
self.assertEqual((None, {'foo': 'bar', 'storage_kind': 'header'},
1806
record = next(record_iter)
1807
self.assertEqual((None, {b'foo': b'bar', b'storage_kind': b'header'},
1774
1808
'info', None, None), record)
1775
record = record_iter.next()
1776
self.assertEqual(("Record body", {'storage_kind': 'fulltext',
1777
'parents': ['1', '3']}, 'file', 'revid', 'fileid'),
1809
record = next(record_iter)
1810
self.assertEqual(("Record body", {b'storage_kind': b'fulltext',
1811
b'parents': [b'1', b'3']}, 'file', b'revid', b'fileid'),
1780
1814
def test_encode_name(self):
1781
self.assertEqual('revision/rev1',
1782
v4.BundleWriter.encode_name('revision', 'rev1'))
1783
self.assertEqual('file/rev//1/file-id-1',
1784
v4.BundleWriter.encode_name('file', 'rev/1', 'file-id-1'))
1785
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',
1786
1820
v4.BundleWriter.encode_name('info', None, None))
1788
1822
def test_decode_name(self):
1789
self.assertEqual(('revision', 'rev1', None),
1790
v4.BundleReader.decode_name('revision/rev1'))
1791
self.assertEqual(('file', 'rev/1', 'file-id-1'),
1792
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'))
1793
1827
self.assertEqual(('info', None, None),
1794
v4.BundleReader.decode_name('info'))
1828
v4.BundleReader.decode_name(b'info'))
1796
1830
def test_too_many_names(self):
1797
fileobj = StringIO()
1798
1832
writer = v4.BundleWriter(fileobj)
1800
writer.add_info_record(foo='bar')
1801
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'])
1803
1837
fileobj.seek(0)
1804
1838
record_iter = v4.BundleReader(fileobj).iter_records()
1805
record = record_iter.next()
1806
self.assertEqual((None, {'foo': 'bar', 'storage_kind': 'header'},
1839
record = next(record_iter)
1840
self.assertEqual((None, {b'foo': b'bar', b'storage_kind': b'header'},
1807
1841
'info', None, None), record)
1808
self.assertRaises(errors.BadBundle, record_iter.next)
1842
self.assertRaises(errors.BadBundle, next, record_iter)
1811
1845
class TestReadMergeableFromUrl(tests.TestCaseWithTransport):