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')
106
124
def make_entry(self, file_id, path):
107
from bzrlib.inventory import (InventoryEntry, InventoryFile
108
, InventoryDirectory, InventoryLink)
125
from ..bzr.inventory import (InventoryFile, InventoryDirectory,
127
if not isinstance(file_id, bytes):
128
raise TypeError(file_id)
109
129
name = os.path.basename(path)
110
kind = self.get_file_kind(file_id)
130
kind = self.kind(path, file_id)
111
131
parent_id = self.parent_id(file_id)
112
text_sha_1, text_size = self.contents_stats(file_id)
132
text_sha_1, text_size = self.contents_stats(path, file_id)
113
133
if kind == 'directory':
114
134
ie = InventoryDirectory(file_id, name, parent_id)
115
135
elif kind == 'file':
116
136
ie = InventoryFile(file_id, name, parent_id)
137
ie.text_sha1 = text_sha_1
138
ie.text_size = text_size
117
139
elif kind == 'symlink':
118
140
ie = InventoryLink(file_id, name, parent_id)
120
142
raise errors.BzrError('unknown kind %r' % kind)
121
ie.text_sha1 = text_sha_1
122
ie.text_size = text_size
125
145
def add_dir(self, file_id, path):
146
if not isinstance(file_id, bytes):
147
raise TypeError(file_id)
126
148
self.paths[file_id] = path
127
149
self.ids[path] = file_id
129
151
def add_file(self, file_id, path, contents):
152
if not isinstance(file_id, bytes):
153
raise TypeError(file_id)
130
154
self.add_dir(file_id, path)
131
155
self.contents[file_id] = contents
172
216
self.assertEqual(btree.old_path("grandparent/parent/file"),
173
217
"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)
219
self.assertEqual(btree.id2path(b"a"), "grandparent")
220
self.assertEqual(btree.id2path(b"b"), "grandparent/parent")
221
self.assertEqual(btree.id2path(b"c"), "grandparent/parent/file")
223
self.assertEqual(btree.path2id("grandparent"), b"a")
224
self.assertEqual(btree.path2id("grandparent/parent"), b"b")
225
self.assertEqual(btree.path2id("grandparent/parent/file"), b"c")
227
self.assertIs(btree.path2id("grandparent2"), None)
228
self.assertIs(btree.path2id("grandparent2/parent"), None)
229
self.assertIs(btree.path2id("grandparent2/parent/file"), None)
187
231
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")
232
self.assertIs(btree.old_path("grandparent"), None)
233
self.assertIs(btree.old_path("grandparent/parent"), None)
234
self.assertIs(btree.old_path("grandparent/parent/file"), None)
236
self.assertEqual(btree.id2path(b"a"), "grandparent2")
237
self.assertEqual(btree.id2path(b"b"), "grandparent2/parent")
238
self.assertEqual(btree.id2path(b"c"), "grandparent2/parent/file")
240
self.assertEqual(btree.path2id("grandparent2"), b"a")
241
self.assertEqual(btree.path2id("grandparent2/parent"), b"b")
242
self.assertEqual(btree.path2id("grandparent2/parent/file"), b"c")
200
244
self.assertTrue(btree.path2id("grandparent") is None)
201
245
self.assertTrue(btree.path2id("grandparent/parent") is None)
202
246
self.assertTrue(btree.path2id("grandparent/parent/file") is None)
204
248
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")
249
self.assertEqual(btree.id2path(b"a"), "grandparent2")
250
self.assertEqual(btree.id2path(b"b"), "grandparent2/parent2")
251
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")
253
self.assertEqual(btree.path2id("grandparent2"), b"a")
254
self.assertEqual(btree.path2id("grandparent2/parent2"), b"b")
255
self.assertEqual(btree.path2id("grandparent2/parent2/file"), b"c")
213
257
self.assertTrue(btree.path2id("grandparent2/parent") is None)
214
258
self.assertTrue(btree.path2id("grandparent2/parent/file") is None)
216
260
btree.note_rename("grandparent/parent/file",
217
261
"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")
262
self.assertEqual(btree.id2path(b"a"), "grandparent2")
263
self.assertEqual(btree.id2path(b"b"), "grandparent2/parent2")
264
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")
266
self.assertEqual(btree.path2id("grandparent2"), b"a")
267
self.assertEqual(btree.path2id("grandparent2/parent2"), b"b")
268
self.assertEqual(btree.path2id("grandparent2/parent2/file2"), b"c")
226
270
self.assertTrue(btree.path2id("grandparent2/parent2/file") is None)
230
274
btree = self.make_tree_1()[0]
231
275
btree.note_rename("grandparent/parent/file",
232
276
"grandparent/alt_parent/file")
233
self.assertEqual(btree.id2path("c"), "grandparent/alt_parent/file")
234
self.assertEqual(btree.path2id("grandparent/alt_parent/file"), "c")
277
self.assertEqual(btree.id2path(b"c"), "grandparent/alt_parent/file")
278
self.assertEqual(btree.path2id("grandparent/alt_parent/file"), b"c")
235
279
self.assertTrue(btree.path2id("grandparent/parent/file") is None)
237
281
def unified_diff(self, old, new):
239
283
diff.internal_diff("old", old, "new", new, out)
241
285
return out.read()
243
287
def make_tree_2(self):
244
288
btree = self.make_tree_1()[0]
245
289
btree.note_rename("grandparent/parent/file",
246
290
"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")
291
self.assertTrue(btree.id2path(b"e") is None)
292
self.assertFalse(btree.is_versioned("grandparent/parent/file"))
293
btree.note_id(b"e", "grandparent/parent/file")
252
296
def test_adds(self):
253
297
"""File/inventory adds"""
254
298
btree = self.make_tree_2()
255
add_patch = self.unified_diff([], ["Extra cheese\n"])
299
add_patch = self.unified_diff([], [b"Extra cheese\n"])
256
300
btree.note_patch("grandparent/parent/file", add_patch)
257
btree.note_id('f', 'grandparent/parent/symlink', kind='symlink')
301
btree.note_id(b'f', 'grandparent/parent/symlink', kind='symlink')
258
302
btree.note_target('grandparent/parent/symlink', 'venus')
259
303
self.adds_test(btree)
261
305
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')
306
self.assertEqual(btree.id2path(b"e"), "grandparent/parent/file")
307
self.assertEqual(btree.path2id("grandparent/parent/file"), b"e")
308
with btree.get_file("grandparent/parent/file") as f:
309
self.assertEqual(f.read(), b"Extra cheese\n")
311
btree.get_symlink_target('grandparent/parent/symlink'), 'venus')
267
313
def test_adds2(self):
268
314
"""File/inventory adds, with patch-compatibile renames"""
269
315
btree = self.make_tree_2()
270
316
btree.contents_by_id = False
271
add_patch = self.unified_diff(["Hello\n"], ["Extra cheese\n"])
317
add_patch = self.unified_diff([b"Hello\n"], [b"Extra cheese\n"])
272
318
btree.note_patch("grandparent/parent/file", add_patch)
273
btree.note_id('f', 'grandparent/parent/symlink', kind='symlink')
319
btree.note_id(b'f', 'grandparent/parent/symlink', kind='symlink')
274
320
btree.note_target('grandparent/parent/symlink', 'venus')
275
321
self.adds_test(btree)
277
323
def make_tree_3(self):
278
324
btree, mtree = self.make_tree_1()
279
mtree.add_file("e", "grandparent/parent/topping", "Anchovies\n")
325
mtree.add_file(b"e", "grandparent/parent/topping", b"Anchovies\n")
280
326
btree.note_rename("grandparent/parent/file",
281
327
"grandparent/alt_parent/file")
282
328
btree.note_rename("grandparent/parent/topping",
286
332
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")
333
with btree.get_file(btree.id2path(b"e")) as f:
334
self.assertEqual(f.read(), b"Lemon\n")
335
with btree.get_file(btree.id2path(b"c")) as f:
336
self.assertEqual(f.read(), b"Hello\n")
290
338
def test_get_file(self):
291
339
"""Get file contents"""
292
340
btree = self.make_tree_3()
293
mod_patch = self.unified_diff(["Anchovies\n"], ["Lemon\n"])
341
mod_patch = self.unified_diff([b"Anchovies\n"], [b"Lemon\n"])
294
342
btree.note_patch("grandparent/alt_parent/stopping", mod_patch)
295
343
self.get_file_test(btree)
297
345
def test_get_file2(self):
298
"""Get file contents, with patch-compatibile renames"""
346
"""Get file contents, with patch-compatible renames"""
299
347
btree = self.make_tree_3()
300
348
btree.contents_by_id = False
301
mod_patch = self.unified_diff([], ["Lemon\n"])
349
mod_patch = self.unified_diff([], [b"Lemon\n"])
302
350
btree.note_patch("grandparent/alt_parent/stopping", mod_patch)
303
mod_patch = self.unified_diff([], ["Hello\n"])
351
mod_patch = self.unified_diff([], [b"Hello\n"])
304
352
btree.note_patch("grandparent/alt_parent/file", mod_patch)
305
353
self.get_file_test(btree)
307
355
def test_delete(self):
308
356
"Deletion by bundle"
309
357
btree = self.make_tree_1()[0]
310
self.assertEqual(btree.get_file("c").read(), "Hello\n")
358
with btree.get_file(btree.id2path(b"c")) as f:
359
self.assertEqual(f.read(), b"Hello\n")
311
360
btree.note_deletion("grandparent/parent/file")
312
self.assertTrue(btree.id2path("c") is None)
313
self.assertTrue(btree.path2id("grandparent/parent/file") is None)
361
self.assertTrue(btree.id2path(b"c") is None)
362
self.assertFalse(btree.is_versioned("grandparent/parent/file"))
315
364
def sorted_ids(self, tree):
365
ids = sorted(tree.all_file_ids())
320
368
def test_iteration(self):
321
369
"""Ensure that iteration through ids works properly"""
322
370
btree = self.make_tree_1()[0]
323
371
self.assertEqual(self.sorted_ids(btree),
324
[inventory.ROOT_ID, 'a', 'b', 'c', 'd'])
372
[inventory.ROOT_ID, b'a', b'b', b'c', b'd'])
325
373
btree.note_deletion("grandparent/parent/file")
326
btree.note_id("e", "grandparent/alt_parent/fool", kind="directory")
374
btree.note_id(b"e", "grandparent/alt_parent/fool", kind="directory")
327
375
btree.note_last_changed("grandparent/alt_parent/fool",
328
376
"revisionidiguess")
329
377
self.assertEqual(self.sorted_ids(btree),
330
[inventory.ROOT_ID, 'a', 'b', 'd', 'e'])
378
[inventory.ROOT_ID, b'a', b'b', b'd', b'e'])
333
381
class BundleTester1(tests.TestCaseWithTransport):
628
672
tt = TreeTransform(self.tree1)
629
trans_id = tt.trans_id_tree_file_id('exe-1')
673
trans_id = tt.trans_id_tree_path('executable')
630
674
tt.set_executability(False, trans_id)
632
self.tree1.commit('removed', rev_id='a@cset-0-3')
676
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')
678
bundle = self.get_valid_bundle(b'a@cset-0-2', b'a@cset-0-3')
635
679
self.assertRaises((errors.TestamentMismatch,
636
680
errors.VersionedFileInvalidChecksum,
637
681
errors.BadBundle), self.get_invalid_bundle,
638
'a@cset-0-2', 'a@cset-0-3')
682
b'a@cset-0-2', b'a@cset-0-3')
639
683
# Check a rollup bundle
640
bundle = self.get_valid_bundle('null:', 'a@cset-0-3')
684
bundle = self.get_valid_bundle(b'null:', b'a@cset-0-3')
642
686
# Now move the directory
643
687
self.tree1.rename_one('dir', 'sub/dir')
644
self.tree1.commit('rename dir', rev_id='a@cset-0-4')
688
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')
690
bundle = self.get_valid_bundle(b'a@cset-0-3', b'a@cset-0-4')
647
691
# Check a rollup bundle
648
bundle = self.get_valid_bundle('null:', 'a@cset-0-4')
692
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')
695
with open('b1/sub/dir/WithCaps.txt', 'ab') as f: f.write(b'\nAdding some text\n')
696
with open('b1/sub/dir/ pre space', 'ab') as f: f.write(
697
b'\r\nAdding some\r\nDOS format lines\r\n')
698
with open('b1/sub/dir/nolastnewline.txt', 'ab') as f: f.write(b'\n')
655
699
self.tree1.rename_one('sub/dir/ pre space',
656
700
'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')
701
self.tree1.commit('Modified files', rev_id=b'a@cset-0-5')
702
bundle = self.get_valid_bundle(b'a@cset-0-4', b'a@cset-0-5')
660
704
self.tree1.rename_one('sub/dir/WithCaps.txt', 'temp')
661
705
self.tree1.rename_one('with space.txt', 'WithCaps.txt')
662
706
self.tree1.rename_one('temp', 'with space.txt')
663
self.tree1.commit(u'swap filenames', rev_id='a@cset-0-6',
707
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')
709
bundle = self.get_valid_bundle(b'a@cset-0-5', b'a@cset-0-6')
710
other = self.get_checkout(b'a@cset-0-5')
667
711
tree1_inv = get_inventory_text(self.tree1.branch.repository,
669
713
tree2_inv = get_inventory_text(other.branch.repository,
671
715
self.assertEqualDiff(tree1_inv, tree2_inv)
672
716
other.rename_one('sub/dir/nolastnewline.txt', 'sub/nolastnewline.txt')
673
other.commit('rename file', rev_id='a@cset-0-6b')
717
other.commit('rename file', rev_id=b'a@cset-0-6b')
674
718
self.tree1.merge_from_branch(other.branch)
675
self.tree1.commit(u'Merge', rev_id='a@cset-0-7',
719
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')
721
bundle = self.get_valid_bundle(b'a@cset-0-6', b'a@cset-0-7')
679
723
def _test_symlink_bundle(self, link_name, link_target, new_link_target):
682
self.requireFeature(tests.SymlinkFeature)
726
self.requireFeature(features.SymlinkFeature)
683
727
self.tree1 = self.make_branch_and_tree('b1')
684
728
self.b1 = self.tree1.branch
686
730
tt = TreeTransform(self.tree1)
687
731
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:
733
self.tree1.commit('add symlink', rev_id=b'l@cset-0-1')
734
bundle = self.get_valid_bundle(b'null:', b'l@cset-0-1')
735
if getattr(bundle, 'revision_tree', None) is not None:
692
736
# 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))
737
bund_tree = bundle.revision_tree(self.b1.repository, b'l@cset-0-1')
738
self.assertEqual(link_target, bund_tree.get_symlink_target(link_name))
696
740
tt = TreeTransform(self.tree1)
697
trans_id = tt.trans_id_tree_file_id(link_id)
741
trans_id = tt.trans_id_tree_path(link_name)
698
742
tt.adjust_path('link2', tt.root, trans_id)
699
743
tt.delete_contents(trans_id)
700
744
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:
746
self.tree1.commit('rename and change symlink', rev_id=b'l@cset-0-2')
747
bundle = self.get_valid_bundle(b'l@cset-0-1', b'l@cset-0-2')
748
if getattr(bundle, 'revision_tree', None) is not None:
705
749
# Not all bundle formats supports revision_tree
706
bund_tree = bundle.revision_tree(self.b1.repository, 'l@cset-0-2')
750
bund_tree = bundle.revision_tree(self.b1.repository, b'l@cset-0-2')
707
751
self.assertEqual(new_link_target,
708
bund_tree.get_symlink_target(link_id))
752
bund_tree.get_symlink_target('link2'))
710
754
tt = TreeTransform(self.tree1)
711
trans_id = tt.trans_id_tree_file_id(link_id)
755
trans_id = tt.trans_id_tree_path('link2')
712
756
tt.delete_contents(trans_id)
713
757
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')
759
self.tree1.commit('just change symlink target', rev_id=b'l@cset-0-3')
760
bundle = self.get_valid_bundle(b'l@cset-0-2', b'l@cset-0-3')
718
762
tt = TreeTransform(self.tree1)
719
trans_id = tt.trans_id_tree_file_id(link_id)
763
trans_id = tt.trans_id_tree_path('link2')
720
764
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')
766
self.tree1.commit('Delete symlink', rev_id=b'l@cset-0-4')
767
bundle = self.get_valid_bundle(b'l@cset-0-3', b'l@cset-0-4')
725
769
def test_symlink_bundle(self):
726
770
self._test_symlink_bundle('link', 'bar/foo', 'mars')
728
772
def test_unicode_symlink_bundle(self):
729
self.requireFeature(tests.UnicodeFilenameFeature)
773
self.requireFeature(features.UnicodeFilenameFeature)
730
774
self._test_symlink_bundle(u'\N{Euro Sign}link',
731
775
u'bar/\N{Euro Sign}foo',
732
776
u'mars\N{Euro Sign}')
737
781
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',
784
tt.new_file('file', tt.root, [b'\x00\n\x00\r\x01\n\x02\r\xff'], b'binary-1')
785
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')
788
self.tree1.commit('add binary', rev_id=b'b@cset-0-1')
789
self.get_valid_bundle(b'null:', b'b@cset-0-1')
748
792
tt = TreeTransform(self.tree1)
749
trans_id = tt.trans_id_tree_file_id('binary-1')
793
trans_id = tt.trans_id_tree_path('file')
750
794
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')
796
self.tree1.commit('delete binary', rev_id=b'b@cset-0-2')
797
self.get_valid_bundle(b'b@cset-0-1', b'b@cset-0-2')
755
799
# Rename & modify
756
800
tt = TreeTransform(self.tree1)
757
trans_id = tt.trans_id_tree_file_id('binary-2')
801
trans_id = tt.trans_id_tree_path('file2')
758
802
tt.adjust_path('file3', tt.root, trans_id)
759
803
tt.delete_contents(trans_id)
760
tt.create_file('file\rcontents\x00\n\x00', trans_id)
804
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')
806
self.tree1.commit('rename and modify binary', rev_id=b'b@cset-0-3')
807
self.get_valid_bundle(b'b@cset-0-2', b'b@cset-0-3')
766
810
tt = TreeTransform(self.tree1)
767
trans_id = tt.trans_id_tree_file_id('binary-2')
811
trans_id = tt.trans_id_tree_path('file3')
768
812
tt.delete_contents(trans_id)
769
tt.create_file('\x00file\rcontents', trans_id)
813
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')
815
self.tree1.commit('just modify binary', rev_id=b'b@cset-0-4')
816
self.get_valid_bundle(b'b@cset-0-3', b'b@cset-0-4')
775
self.get_valid_bundle('null:', 'b@cset-0-4')
819
self.get_valid_bundle(b'null:', b'b@cset-0-4')
777
821
def test_last_modified(self):
778
822
self.tree1 = self.make_branch_and_tree('b1')
779
823
self.b1 = self.tree1.branch
780
824
tt = TreeTransform(self.tree1)
781
tt.new_file('file', tt.root, 'file', 'file')
825
tt.new_file('file', tt.root, [b'file'], b'file')
783
self.tree1.commit('create file', rev_id='a@lmod-0-1')
827
self.tree1.commit('create file', rev_id=b'a@lmod-0-1')
785
829
tt = TreeTransform(self.tree1)
786
trans_id = tt.trans_id_tree_file_id('file')
830
trans_id = tt.trans_id_tree_path('file')
787
831
tt.delete_contents(trans_id)
788
tt.create_file('file2', trans_id)
832
tt.create_file([b'file2'], trans_id)
790
self.tree1.commit('modify text', rev_id='a@lmod-0-2a')
834
self.tree1.commit('modify text', rev_id=b'a@lmod-0-2a')
792
other = self.get_checkout('a@lmod-0-1')
836
other = self.get_checkout(b'a@lmod-0-1')
793
837
tt = TreeTransform(other)
794
trans_id = tt.trans_id_tree_file_id('file')
838
trans_id = tt.trans_id_tree_path('file2')
795
839
tt.delete_contents(trans_id)
796
tt.create_file('file2', trans_id)
840
tt.create_file([b'file2'], trans_id)
798
other.commit('modify text in another tree', rev_id='a@lmod-0-2b')
842
other.commit('modify text in another tree', rev_id=b'a@lmod-0-2b')
799
843
self.tree1.merge_from_branch(other.branch)
800
self.tree1.commit(u'Merge', rev_id='a@lmod-0-3',
844
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')
846
self.tree1.commit(u'Merge', rev_id=b'a@lmod-0-4')
847
bundle = self.get_valid_bundle(b'a@lmod-0-2a', b'a@lmod-0-4')
805
849
def test_hide_history(self):
806
850
self.tree1 = self.make_branch_and_tree('b1')
807
851
self.b1 = self.tree1.branch
809
open('b1/one', 'wb').write('one\n')
853
with open('b1/one', 'wb') as f: f.write(b'one\n')
810
854
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')
855
self.tree1.commit('add file', rev_id=b'a@cset-0-1')
856
with open('b1/one', 'wb') as f: f.write(b'two\n')
857
self.tree1.commit('modify', rev_id=b'a@cset-0-2')
858
with open('b1/one', 'wb') as f: f.write(b'three\n')
859
self.tree1.commit('modify', rev_id=b'a@cset-0-3')
860
bundle_file = BytesIO()
861
rev_ids = write_bundle(self.tree1.branch.repository, b'a@cset-0-3',
862
b'a@cset-0-1', bundle_file, format=self.format)
863
self.assertNotContainsRe(bundle_file.getvalue(), b'\btwo\b')
864
self.assertContainsRe(self.get_raw(bundle_file), b'one')
865
self.assertContainsRe(self.get_raw(bundle_file), b'three')
823
867
def test_bundle_same_basis(self):
824
868
"""Ensure using the basis as the target doesn't cause an error"""
825
869
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)
870
self.tree1.commit('add file', rev_id=b'a@cset-0-1')
871
bundle_file = BytesIO()
872
rev_ids = write_bundle(self.tree1.branch.repository, b'a@cset-0-1',
873
b'a@cset-0-1', bundle_file)
832
876
def get_raw(bundle_file):
833
877
return bundle_file.getvalue()
835
879
def test_unicode_bundle(self):
836
self.requireFeature(tests.UnicodeFilenameFeature)
880
self.requireFeature(features.UnicodeFilenameFeature)
837
881
# Handle international characters
839
883
f = open(u'b1/with Dod\N{Euro Sign}', 'wb')
846
890
u'William Dod\xe9\n').encode('utf-8'))
849
self.tree1.add([u'with Dod\N{Euro Sign}'], ['withdod-id'])
893
self.tree1.add([u'with Dod\N{Euro Sign}'], [b'withdod-id'])
850
894
self.tree1.commit(u'i18n commit from William Dod\xe9',
851
rev_id='i18n-1', committer=u'William Dod\xe9')
895
rev_id=b'i18n-1', committer=u'William Dod\xe9')
854
bundle = self.get_valid_bundle('null:', 'i18n-1')
898
bundle = self.get_valid_bundle(b'null:', b'i18n-1')
857
901
f = open(u'b1/with Dod\N{Euro Sign}', 'wb')
858
902
f.write(u'Modified \xb5\n'.encode('utf8'))
860
self.tree1.commit(u'modified', rev_id='i18n-2')
904
self.tree1.commit(u'modified', rev_id=b'i18n-2')
862
bundle = self.get_valid_bundle('i18n-1', 'i18n-2')
906
bundle = self.get_valid_bundle(b'i18n-1', b'i18n-2')
865
909
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',
910
self.tree1.commit(u'renamed, the new i18n man', rev_id=b'i18n-3',
867
911
committer=u'Erik B\xe5gfors')
869
bundle = self.get_valid_bundle('i18n-2', 'i18n-3')
913
bundle = self.get_valid_bundle(b'i18n-2', b'i18n-3')
872
916
self.tree1.remove([u'B\N{Euro Sign}gfors'])
873
self.tree1.commit(u'removed', rev_id='i18n-4')
917
self.tree1.commit(u'removed', rev_id=b'i18n-4')
875
bundle = self.get_valid_bundle('i18n-3', 'i18n-4')
919
bundle = self.get_valid_bundle(b'i18n-3', b'i18n-4')
878
bundle = self.get_valid_bundle('null:', 'i18n-4')
922
bundle = self.get_valid_bundle(b'null:', b'i18n-4')
881
925
def test_whitespace_bundle(self):
891
935
# once we actually support them
894
self.tree1.commit('funky whitespace', rev_id='white-1')
938
self.tree1.commit('funky whitespace', rev_id=b'white-1')
896
bundle = self.get_valid_bundle('null:', 'white-1')
940
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')
943
with open('b1/trailing space ', 'ab') as f: f.write(b'add some text\n')
944
self.tree1.commit('add text', rev_id=b'white-2')
902
bundle = self.get_valid_bundle('white-1', 'white-2')
946
bundle = self.get_valid_bundle(b'white-1', b'white-2')
905
949
self.tree1.rename_one('trailing space ', ' start and end space ')
906
self.tree1.commit('rename', rev_id='white-3')
950
self.tree1.commit('rename', rev_id=b'white-3')
908
bundle = self.get_valid_bundle('white-2', 'white-3')
952
bundle = self.get_valid_bundle(b'white-2', b'white-3')
911
955
self.tree1.remove([' start and end space '])
912
self.tree1.commit('removed', rev_id='white-4')
956
self.tree1.commit('removed', rev_id=b'white-4')
914
bundle = self.get_valid_bundle('white-3', 'white-4')
958
bundle = self.get_valid_bundle(b'white-3', b'white-4')
916
960
# Now test a complet roll-up
917
bundle = self.get_valid_bundle('null:', 'white-4')
961
bundle = self.get_valid_bundle(b'null:', b'white-4')
919
963
def test_alt_timezone_bundle(self):
920
964
self.tree1 = self.make_branch_and_memory_tree('b1')
941
985
def test_bundle_root_id(self):
942
986
self.tree1 = self.make_branch_and_tree('b1')
943
987
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)
988
self.tree1.commit('message', rev_id=b'revid1')
989
bundle = self.get_valid_bundle(b'null:', b'revid1')
990
tree = self.get_bundle_tree(bundle, b'revid1')
991
root_revision = tree.get_file_revision(u'', tree.get_root_id())
992
self.assertEqual(b'revid1', root_revision)
949
994
def test_install_revisions(self):
950
995
self.tree1 = self.make_branch_and_tree('b1')
951
996
self.b1 = self.tree1.branch
952
self.tree1.commit('message', rev_id='rev2a')
953
bundle = self.get_valid_bundle('null:', 'rev2a')
997
self.tree1.commit('message', rev_id=b'rev2a')
998
bundle = self.get_valid_bundle(b'null:', b'rev2a')
954
999
branch2 = self.make_branch('b2')
955
self.assertFalse(branch2.repository.has_revision('rev2a'))
1000
self.assertFalse(branch2.repository.has_revision(b'rev2a'))
956
1001
target_revision = bundle.install_revisions(branch2.repository)
957
self.assertTrue(branch2.repository.has_revision('rev2a'))
958
self.assertEqual('rev2a', target_revision)
1002
self.assertTrue(branch2.repository.has_revision(b'rev2a'))
1003
self.assertEqual(b'rev2a', target_revision)
960
1005
def test_bundle_empty_property(self):
961
1006
"""Test serializing revision properties with an empty value."""
962
1007
tree = self.make_branch_and_memory_tree('tree')
963
1008
tree.lock_write()
964
1009
self.addCleanup(tree.unlock)
965
tree.add([''], ['TREE_ROOT'])
966
tree.commit('One', revprops={'one':'two', 'empty':''}, rev_id='rev1')
1010
tree.add([''], [b'TREE_ROOT'])
1011
tree.commit('One', revprops={u'one': 'two', u'empty': ''}, rev_id=b'rev1')
967
1012
self.b1 = tree.branch
968
bundle_sio, revision_ids = self.create_bundle_text('null:', 'rev1')
1013
bundle_sio, revision_ids = self.create_bundle_text(b'null:', b'rev1')
969
1014
bundle = read_bundle(bundle_sio)
970
1015
revision_info = bundle.revisions[0]
971
self.assertEqual('rev1', revision_info.revision_id)
1016
self.assertEqual(b'rev1', revision_info.revision_id)
972
1017
rev = revision_info.as_revision()
973
1018
self.assertEqual({'branch-nick':'tree', 'empty':'', 'one':'two'},
1035
1080
def test_across_serializers(self):
1036
1081
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])
1082
tree.commit('hello', rev_id=b'rev1')
1083
tree.commit('hello', rev_id=b'rev2')
1084
bundle = read_bundle(self.create_bundle_text(b'null:', b'rev2')[0])
1040
1085
repo = self.make_repository('repo', format='dirstate-with-subtree')
1041
1086
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"')
1087
inv_text = repo._get_inventory_xml(b'rev2')
1088
self.assertNotContainsRe(inv_text, b'format="5"')
1089
self.assertContainsRe(inv_text, b'format="7"')
1046
1091
def make_repo_with_installed_revisions(self):
1047
1092
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])
1093
tree.commit('hello', rev_id=b'rev1')
1094
tree.commit('hello', rev_id=b'rev2')
1095
bundle = read_bundle(self.create_bundle_text(b'null:', b'rev2')[0])
1051
1096
repo = self.make_repository('repo', format='dirstate-with-subtree')
1052
1097
bundle.install_revisions(repo)
1055
1100
def test_across_models(self):
1056
1101
repo = self.make_repo_with_installed_revisions()
1057
inv = repo.get_inventory('rev2')
1058
self.assertEqual('rev2', inv.root.revision)
1102
inv = repo.get_inventory(b'rev2')
1103
self.assertEqual(b'rev2', inv.root.revision)
1059
1104
root_id = inv.root.file_id
1060
1105
repo.lock_read()
1061
1106
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')]))
1107
self.assertEqual({(root_id, b'rev1'):(),
1108
(root_id, b'rev2'):((root_id, b'rev1'),)},
1109
repo.texts.get_parent_map([(root_id, b'rev1'), (root_id, b'rev2')]))
1066
1111
def test_inv_hash_across_serializers(self):
1067
1112
repo = self.make_repo_with_installed_revisions()
1068
recorded_inv_sha1 = repo.get_revision('rev2').inventory_sha1
1069
xml = repo._get_inventory_xml('rev2')
1113
recorded_inv_sha1 = repo.get_revision(b'rev2').inventory_sha1
1114
xml = repo._get_inventory_xml(b'rev2')
1070
1115
self.assertEqual(osutils.sha_string(xml), recorded_inv_sha1)
1072
1117
def test_across_models_incompatible(self):
1073
1118
tree = self.make_simple_tree('dirstate-with-subtree')
1074
tree.commit('hello', rev_id='rev1')
1075
tree.commit('hello', rev_id='rev2')
1119
tree.commit('hello', rev_id=b'rev1')
1120
tree.commit('hello', rev_id=b'rev2')
1077
bundle = read_bundle(self.create_bundle_text('null:', 'rev1')[0])
1122
bundle = read_bundle(self.create_bundle_text(b'null:', b'rev1')[0])
1078
1123
except errors.IncompatibleBundleFormat:
1079
1124
raise tests.TestSkipped("Format 0.8 doesn't work with knit3")
1080
1125
repo = self.make_repository('repo', format='knit')
1081
1126
bundle.install_revisions(repo)
1083
bundle = read_bundle(self.create_bundle_text('null:', 'rev2')[0])
1128
bundle = read_bundle(self.create_bundle_text(b'null:', b'rev2')[0])
1084
1129
self.assertRaises(errors.IncompatibleRevision,
1085
1130
bundle.install_revisions, repo)
1087
1132
def test_get_merge_request(self):
1088
1133
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])
1134
tree.commit('hello', rev_id=b'rev1')
1135
tree.commit('hello', rev_id=b'rev2')
1136
bundle = read_bundle(self.create_bundle_text(b'null:', b'rev1')[0])
1092
1137
result = bundle.get_merge_request(tree.branch.repository)
1093
self.assertEqual((None, 'rev1', 'inapplicable'), result)
1138
self.assertEqual((None, b'rev1', 'inapplicable'), result)
1095
1140
def test_with_subtree(self):
1096
1141
tree = self.make_branch_and_tree('tree',
1116
1161
self.tree1 = self.make_branch_and_tree('tree')
1117
1162
self.b1 = self.tree1.branch
1119
self.tree1.commit('Revision/id/with/slashes', rev_id='rev/id')
1164
self.tree1.commit('Revision/id/with/slashes', rev_id=b'rev/id')
1120
1165
except ValueError:
1121
1166
raise tests.TestSkipped(
1122
1167
"Repository doesn't support revision ids with slashes")
1123
bundle = self.get_valid_bundle('null:', 'rev/id')
1168
bundle = self.get_valid_bundle(b'null:', b'rev/id')
1125
1170
def test_skip_file(self):
1126
1171
"""Make sure we don't accidentally write to the wrong versionedfile"""
1127
1172
self.tree1 = self.make_branch_and_tree('tree')
1128
1173
self.b1 = self.tree1.branch
1129
1174
# 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')])
1175
self.build_tree_contents([('tree/file2', b'contents1')])
1176
self.tree1.add('file2', b'file2-id')
1177
self.tree1.commit('rev1', rev_id=b'reva')
1178
self.build_tree_contents([('tree/file3', b'contents2')])
1134
1179
# rev2 is present in bundle, and done by fetch
1135
1180
# having file1 in the bunle causes file1's versionedfile to be opened.
1136
self.tree1.add('file3', 'file3-id')
1137
self.tree1.commit('rev2')
1181
self.tree1.add('file3', b'file3-id')
1182
rev2 = self.tree1.commit('rev2')
1138
1183
# 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')
1184
target = self.tree1.controldir.sprout('target').open_workingtree()
1185
self.build_tree_contents([('tree/file2', b'contents3')])
1186
self.tree1.commit('rev3', rev_id=b'rev3')
1187
bundle = self.get_valid_bundle(b'reva', b'rev3')
1143
1188
if getattr(bundle, 'get_bundle_reader', None) is None:
1144
1189
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')
1191
(f, r) for b, m, k, r, f in bundle.get_bundle_reader().iter_records()
1193
self.assertEqual({(b'file2-id', b'rev3'), (b'file3-id', rev2)}, file_ids)
1150
1194
bundle.install_revisions(target.branch.repository)
1332
1376
:return: The in-memory bundle
1334
from bzrlib.bundle import serializer
1378
from ..bundle import serializer
1335
1379
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()
1380
new_text = self.get_raw(BytesIO(b''.join(bundle_txt)))
1381
new_text = new_text.replace(b'<file file_id="exe-1"',
1382
b'<file executable="y" file_id="exe-1"')
1383
new_text = new_text.replace(b'B260', b'B275')
1384
bundle_txt = BytesIO()
1341
1385
bundle_txt.write(serializer._get_bundle_header('4'))
1342
bundle_txt.write('\n')
1343
bundle_txt.write(new_text.encode('bz2'))
1386
bundle_txt.write(b'\n')
1387
bundle_txt.write(bz2.compress(new_text))
1344
1388
bundle_txt.seek(0)
1345
1389
bundle = read_bundle(bundle_txt)
1346
1390
self.valid_apply_bundle(base_rev_id, bundle)
1349
1393
def create_bundle_text(self, base_rev_id, rev_id):
1350
bundle_txt = StringIO()
1394
bundle_txt = BytesIO()
1351
1395
rev_ids = write_bundle(self.b1.repository, rev_id, base_rev_id,
1352
1396
bundle_txt, format=self.format)
1353
1397
bundle_txt.seek(0)
1354
1398
self.assertEqual(bundle_txt.readline(),
1355
'# Bazaar revision bundle v%s\n' % self.format)
1356
self.assertEqual(bundle_txt.readline(), '#\n')
1399
b'# Bazaar revision bundle v%s\n' % self.format.encode('ascii'))
1400
self.assertEqual(bundle_txt.readline(), b'#\n')
1357
1401
rev = self.b1.repository.get_revision(rev_id)
1358
1402
bundle_txt.seek(0)
1359
1403
return bundle_txt, rev_ids
1380
1425
target_repo.lock_read()
1381
1426
self.addCleanup(target_repo.unlock)
1382
1427
# Turn the 'iterators_of_bytes' back into simple strings for comparison
1383
repo_texts = dict((i, ''.join(content)) for i, content
1428
repo_texts = dict((i, b''.join(content)) for i, content
1384
1429
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'},
1430
[(b'fileid-2', b'rev1', '1'),
1431
(b'fileid-2', b'rev2', '2')]))
1432
self.assertEqual({'1':b'contents1\nstatic\n',
1433
'2':b'contents2\nstatic\n'},
1390
rtree = target_repo.revision_tree('rev2')
1435
rtree = target_repo.revision_tree(b'rev2')
1391
1436
inventory_vf = target_repo.inventories
1392
1437
# If the inventory store has a graph, it must match the revision graph.
1393
1438
self.assertSubset(
1394
[inventory_vf.get_parent_map([('rev2',)])[('rev2',)]],
1395
[None, (('rev1',),)])
1439
[inventory_vf.get_parent_map([(b'rev2',)])[(b'rev2',)]],
1440
[None, ((b'rev1',),)])
1396
1441
self.assertEqual('changed file',
1397
target_repo.get_revision('rev2').message)
1442
target_repo.get_revision(b'rev2').message)
1400
1445
def get_raw(bundle_file):
1402
1447
line = bundle_file.readline()
1403
1448
line = bundle_file.readline()
1404
1449
lines = bundle_file.readlines()
1405
return ''.join(lines).decode('bz2')
1450
return bz2.decompress(b''.join(lines))
1407
1452
def test_copy_signatures(self):
1408
1453
tree_a = self.make_branch_and_tree('tree_a')
1410
import bzrlib.commit as commit
1411
oldstrategy = bzrlib.gpg.GPGStrategy
1455
import breezy.commit as commit
1456
oldstrategy = breezy.gpg.GPGStrategy
1412
1457
branch = tree_a.branch
1413
1458
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'))
1459
tree_a.commit("base", allow_pointless=True, rev_id=b'A')
1460
self.assertFalse(branch.repository.has_signature_for_revision_id(b'A'))
1417
from bzrlib.testament import Testament
1462
from ..testament import Testament
1418
1463
# 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",
1464
breezy.gpg.GPGStrategy = breezy.gpg.LoopbackGPGStrategy
1465
new_config = test_commit.MustSignConfig()
1466
commit.Commit(config_stack=new_config).commit(message="base",
1422
1467
allow_pointless=True,
1424
1469
working_tree=tree_a)
1425
1470
def sign(text):
1426
return bzrlib.gpg.LoopbackGPGStrategy(None).sign(text)
1427
self.assertTrue(repo_a.has_signature_for_revision_id('B'))
1471
return breezy.gpg.LoopbackGPGStrategy(None).sign(text)
1472
self.assertTrue(repo_a.has_signature_for_revision_id(b'B'))
1429
bzrlib.gpg.GPGStrategy = oldstrategy
1474
breezy.gpg.GPGStrategy = oldstrategy
1430
1475
tree_b = self.make_branch_and_tree('tree_b')
1431
1476
repo_b = tree_b.branch.repository
1433
1478
serializer = BundleSerializerV4('4')
1434
serializer.write(tree_a.branch.repository, ['A', 'B'], {}, s)
1479
with tree_a.lock_read():
1480
serializer.write_bundle(tree_a.branch.repository, b'B', b'null:', s)
1436
1482
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'))
1483
self.assertTrue(repo_b.has_signature_for_revision_id(b'B'))
1484
self.assertEqual(repo_b.get_signature_text(b'B'),
1485
repo_a.get_signature_text(b'B'))
1441
1487
# ensure repeat installs are harmless
1442
1488
install_bundle(repo_b, serializer.read(s))
1445
class V4WeaveBundleTester(V4BundleTester):
1447
def bzrdir_format(self):
1451
1491
class V4_2aBundleTester(V4BundleTester):
1453
1493
def bzrdir_format(self):
1480
1520
def make_merged_branch(self):
1481
1521
builder = self.make_branch_builder('source')
1482
1522
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')),
1523
builder.build_snapshot(None, [
1524
('add', ('', b'root-id', 'directory', None)),
1525
('add', ('file', b'file-id', 'file', b'original content\n')),
1526
], revision_id=b'a@cset-0-1')
1527
builder.build_snapshot([b'a@cset-0-1'], [
1528
('modify', ('file', b'new-content\n')),
1529
], revision_id=b'a@cset-0-2a')
1530
builder.build_snapshot([b'a@cset-0-1'], [
1531
('add', ('other-file', b'file2-id', 'file', b'file2-content\n')),
1532
], revision_id=b'a@cset-0-2b')
1533
builder.build_snapshot([b'a@cset-0-2a', b'a@cset-0-2b'], [
1534
('add', ('other-file', b'file2-id', 'file', b'file2-content\n')),
1535
], revision_id=b'a@cset-0-3')
1496
1536
builder.finish_series()
1497
1537
self.b1 = builder.get_branch()
1498
1538
self.b1.lock_read()
1513
1553
def test_single_inventory_multiple_parents_as_xml(self):
1514
1554
self.make_merged_branch()
1515
sio = self.make_bundle_just_inventories('a@cset-0-1', 'a@cset-0-3',
1555
sio = self.make_bundle_just_inventories(b'a@cset-0-1', b'a@cset-0-3',
1517
1557
reader = v4.BundleReader(sio, stream_input=False)
1518
1558
records = list(reader.iter_records())
1519
1559
self.assertEqual(1, len(records))
1520
1560
(bytes, metadata, repo_kind, revision_id,
1521
1561
file_id) = records[0]
1522
1562
self.assertIs(None, file_id)
1523
self.assertEqual('a@cset-0-3', revision_id)
1563
self.assertEqual(b'a@cset-0-3', revision_id)
1524
1564
self.assertEqual('inventory', repo_kind)
1525
self.assertEqual({'parents': ['a@cset-0-2a', 'a@cset-0-2b'],
1526
'sha1': '09c53b0c4de0895e11a2aacc34fef60a6e70865c',
1527
'storage_kind': 'mpdiff',
1565
self.assertEqual({b'parents': [b'a@cset-0-2a', b'a@cset-0-2b'],
1566
b'sha1': b'09c53b0c4de0895e11a2aacc34fef60a6e70865c',
1567
b'storage_kind': b'mpdiff',
1529
1569
# We should have an mpdiff that takes some lines from both parents.
1530
1570
self.assertEqualDiff(
1532
'<inventory format="10" revision_id="a@cset-0-3">\n'
1535
'c 1 3 3 2\n', bytes)
1572
b'<inventory format="10" revision_id="a@cset-0-3">\n'
1575
b'c 1 3 3 2\n', bytes)
1537
1577
def test_single_inv_no_parents_as_xml(self):
1538
1578
self.make_merged_branch()
1539
sio = self.make_bundle_just_inventories('null:', 'a@cset-0-1',
1579
sio = self.make_bundle_just_inventories(b'null:', b'a@cset-0-1',
1541
1581
reader = v4.BundleReader(sio, stream_input=False)
1542
1582
records = list(reader.iter_records())
1543
1583
self.assertEqual(1, len(records))
1544
1584
(bytes, metadata, repo_kind, revision_id,
1545
1585
file_id) = records[0]
1546
1586
self.assertIs(None, file_id)
1547
self.assertEqual('a@cset-0-1', revision_id)
1587
self.assertEqual(b'a@cset-0-1', revision_id)
1548
1588
self.assertEqual('inventory', repo_kind)
1549
self.assertEqual({'parents': [],
1550
'sha1': 'a13f42b142d544aac9b085c42595d304150e31a2',
1551
'storage_kind': 'mpdiff',
1589
self.assertEqual({b'parents': [],
1590
b'sha1': b'a13f42b142d544aac9b085c42595d304150e31a2',
1591
b'storage_kind': b'mpdiff',
1553
1593
# We should have an mpdiff that takes some lines from both parents.
1554
1594
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'
1596
b'<inventory format="10" revision_id="a@cset-0-1">\n'
1597
b'<directory file_id="root-id" name=""'
1598
b' revision="a@cset-0-1" />\n'
1599
b'<file file_id="file-id" name="file" parent_id="root-id"'
1600
b' revision="a@cset-0-1"'
1601
b' text_sha1="09c2f8647e14e49e922b955c194102070597c2d1"'
1602
b' text_size="17" />\n'
1566
1606
def test_multiple_inventories_as_xml(self):
1567
1607
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'])
1608
sio = self.make_bundle_just_inventories(b'a@cset-0-1', b'a@cset-0-3',
1609
[b'a@cset-0-2a', b'a@cset-0-2b', b'a@cset-0-3'])
1570
1610
reader = v4.BundleReader(sio, stream_input=False)
1571
1611
records = list(reader.iter_records())
1572
1612
self.assertEqual(3, len(records))
1573
1613
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'],
1614
self.assertEqual([b'a@cset-0-2a', b'a@cset-0-2b', b'a@cset-0-3'],
1576
1616
metadata_2a = records[0][1]
1577
self.assertEqual({'parents': ['a@cset-0-1'],
1578
'sha1': '1e105886d62d510763e22885eec733b66f5f09bf',
1579
'storage_kind': 'mpdiff',
1617
self.assertEqual({b'parents': [b'a@cset-0-1'],
1618
b'sha1': b'1e105886d62d510763e22885eec733b66f5f09bf',
1619
b'storage_kind': b'mpdiff',
1580
1620
}, metadata_2a)
1581
1621
metadata_2b = records[1][1]
1582
self.assertEqual({'parents': ['a@cset-0-1'],
1583
'sha1': 'f03f12574bdb5ed2204c28636c98a8547544ccd8',
1584
'storage_kind': 'mpdiff',
1622
self.assertEqual({b'parents': [b'a@cset-0-1'],
1623
b'sha1': b'f03f12574bdb5ed2204c28636c98a8547544ccd8',
1624
b'storage_kind': b'mpdiff',
1585
1625
}, metadata_2b)
1586
1626
metadata_3 = records[2][1]
1587
self.assertEqual({'parents': ['a@cset-0-2a', 'a@cset-0-2b'],
1588
'sha1': '09c53b0c4de0895e11a2aacc34fef60a6e70865c',
1589
'storage_kind': 'mpdiff',
1627
self.assertEqual({b'parents': [b'a@cset-0-2a', b'a@cset-0-2b'],
1628
b'sha1': b'09c53b0c4de0895e11a2aacc34fef60a6e70865c',
1629
b'storage_kind': b'mpdiff',
1591
1631
bytes_2a = records[0][0]
1592
1632
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)
1634
b'<inventory format="10" revision_id="a@cset-0-2a">\n'
1638
b'<file file_id="file-id" name="file" parent_id="root-id"'
1639
b' revision="a@cset-0-2a"'
1640
b' text_sha1="50f545ff40e57b6924b1f3174b267ffc4576e9a9"'
1641
b' text_size="12" />\n'
1643
b'c 0 3 3 1\n', bytes_2a)
1604
1644
bytes_2b = records[1][0]
1605
1645
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)
1647
b'<inventory format="10" revision_id="a@cset-0-2b">\n'
1651
b'<file file_id="file2-id" name="other-file" parent_id="root-id"'
1652
b' revision="a@cset-0-2b"'
1653
b' text_sha1="b46c0c8ea1e5ef8e46fc8894bfd4752a88ec939e"'
1654
b' text_size="14" />\n'
1656
b'c 0 3 4 1\n', bytes_2b)
1617
1657
bytes_3 = records[2][0]
1618
1658
self.assertEqualDiff(
1620
'<inventory format="10" revision_id="a@cset-0-3">\n'
1623
'c 1 3 3 2\n', bytes_3)
1660
b'<inventory format="10" revision_id="a@cset-0-3">\n'
1663
b'c 1 3 3 2\n', bytes_3)
1625
1665
def test_creating_bundle_preserves_chk_pages(self):
1626
1666
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)
1667
target = self.b1.controldir.sprout('target',
1668
revision_id=b'a@cset-0-2a').open_branch()
1669
bundle_txt, rev_ids = self.create_bundle_text(b'a@cset-0-2a',
1671
self.assertEqual(set([b'a@cset-0-2b', b'a@cset-0-3']), set(rev_ids))
1632
1672
bundle = read_bundle(bundle_txt)
1633
1673
target.lock_write()
1634
1674
self.addCleanup(target.unlock)
1635
1675
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')
1676
inv1 = next(self.b1.repository.inventories.get_record_stream([
1677
(b'a@cset-0-3',)], 'unordered',
1678
True)).get_bytes_as('fulltext')
1679
inv2 = next(target.repository.inventories.get_record_stream([
1680
(b'a@cset-0-3',)], 'unordered',
1681
True)).get_bytes_as('fulltext')
1642
1682
self.assertEqualDiff(inv1, inv2)
1740
1780
class TestBundleWriterReader(tests.TestCase):
1742
1782
def test_roundtrip_record(self):
1743
fileobj = StringIO()
1744
1784
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')
1786
writer.add_info_record({b'foo': b'bar'})
1787
writer._add_record(b"Record body", {b'parents': [b'1', b'3'],
1788
b'storage_kind': b'fulltext'}, 'file', b'revid', b'fileid')
1750
1790
fileobj.seek(0)
1751
1791
reader = v4.BundleReader(fileobj, stream_input=True)
1752
1792
record_iter = reader.iter_records()
1753
record = record_iter.next()
1754
self.assertEqual((None, {'foo': 'bar', 'storage_kind': 'header'},
1793
record = next(record_iter)
1794
self.assertEqual((None, {b'foo': b'bar', b'storage_kind': b'header'},
1755
1795
'info', None, None), record)
1756
record = record_iter.next()
1757
self.assertEqual(("Record body", {'storage_kind': 'fulltext',
1758
'parents': ['1', '3']}, 'file', 'revid', 'fileid'),
1796
record = next(record_iter)
1797
self.assertEqual((b"Record body", {b'storage_kind': b'fulltext',
1798
b'parents': [b'1', b'3']}, 'file', b'revid', b'fileid'),
1761
1801
def test_roundtrip_record_memory_hungry(self):
1762
fileobj = StringIO()
1763
1803
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')
1805
writer.add_info_record({b'foo': b'bar'})
1806
writer._add_record(b"Record body", {b'parents': [b'1', b'3'],
1807
b'storage_kind': b'fulltext'}, 'file', b'revid', b'fileid')
1769
1809
fileobj.seek(0)
1770
1810
reader = v4.BundleReader(fileobj, stream_input=False)
1771
1811
record_iter = reader.iter_records()
1772
record = record_iter.next()
1773
self.assertEqual((None, {'foo': 'bar', 'storage_kind': 'header'},
1812
record = next(record_iter)
1813
self.assertEqual((None, {b'foo': b'bar', b'storage_kind': b'header'},
1774
1814
'info', None, None), record)
1775
record = record_iter.next()
1776
self.assertEqual(("Record body", {'storage_kind': 'fulltext',
1777
'parents': ['1', '3']}, 'file', 'revid', 'fileid'),
1815
record = next(record_iter)
1816
self.assertEqual((b"Record body", {b'storage_kind': b'fulltext',
1817
b'parents': [b'1', b'3']}, 'file', b'revid', b'fileid'),
1780
1820
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',
1821
self.assertEqual(b'revision/rev1',
1822
v4.BundleWriter.encode_name('revision', b'rev1'))
1823
self.assertEqual(b'file/rev//1/file-id-1',
1824
v4.BundleWriter.encode_name('file', b'rev/1', b'file-id-1'))
1825
self.assertEqual(b'info',
1786
1826
v4.BundleWriter.encode_name('info', None, None))
1788
1828
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'))
1829
self.assertEqual(('revision', b'rev1', None),
1830
v4.BundleReader.decode_name(b'revision/rev1'))
1831
self.assertEqual(('file', b'rev/1', b'file-id-1'),
1832
v4.BundleReader.decode_name(b'file/rev//1/file-id-1'))
1793
1833
self.assertEqual(('info', None, None),
1794
v4.BundleReader.decode_name('info'))
1834
v4.BundleReader.decode_name(b'info'))
1796
1836
def test_too_many_names(self):
1797
fileobj = StringIO()
1798
1838
writer = v4.BundleWriter(fileobj)
1800
writer.add_info_record(foo='bar')
1801
writer._container.add_bytes_record('blah', ['two', 'names'])
1840
writer.add_info_record({b'foo': b'bar'})
1841
writer._container.add_bytes_record(b'blah', [(b'two', ), (b'names', )])
1803
1843
fileobj.seek(0)
1804
1844
record_iter = v4.BundleReader(fileobj).iter_records()
1805
record = record_iter.next()
1806
self.assertEqual((None, {'foo': 'bar', 'storage_kind': 'header'},
1845
record = next(record_iter)
1846
self.assertEqual((None, {b'foo': b'bar', b'storage_kind': b'header'},
1807
1847
'info', None, None), record)
1808
self.assertRaises(errors.BadBundle, record_iter.next)
1848
self.assertRaises(errors.BadBundle, next, record_iter)
1811
1851
class TestReadMergeableFromUrl(tests.TestCaseWithTransport):