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
21
import SocketServer as socketserver
31
29
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 (
37
from ..bundle import read_mergeable_from_url
38
from ..bundle.apply_bundle import install_bundle, merge_bundle
39
from ..bundle.bundle_data import BundleTree
40
from ..directory_service import directories
41
from ..bundle.serializer import write_bundle, read_bundle, v09, v4
42
from ..bundle.serializer.v08 import BundleSerializerV08
43
from ..bundle.serializer.v09 import BundleSerializerV09
44
from ..bundle.serializer.v4 import BundleSerializerV4
45
from ..bzr import knitrepo
46
from ..sixish import (
50
from bzrlib.transform import TreeTransform
55
from ..transform import TreeTransform
53
58
def get_text(vf, key):
54
59
"""Get the fulltext for a given revision id that is present in the vf"""
55
60
stream = vf.get_record_stream([key], 'unordered', True)
56
record = stream.next()
57
62
return record.get_bytes_as('fulltext')
106
125
def make_entry(self, file_id, path):
107
from bzrlib.inventory import (InventoryEntry, InventoryFile
108
, InventoryDirectory, InventoryLink)
126
from ..bzr.inventory import (InventoryFile, InventoryDirectory,
109
128
name = os.path.basename(path)
110
kind = self.get_file_kind(file_id)
129
kind = self.kind(path, file_id)
111
130
parent_id = self.parent_id(file_id)
112
text_sha_1, text_size = self.contents_stats(file_id)
131
text_sha_1, text_size = self.contents_stats(path, file_id)
113
132
if kind == 'directory':
114
133
ie = InventoryDirectory(file_id, name, parent_id)
115
134
elif kind == 'file':
116
135
ie = InventoryFile(file_id, name, parent_id)
136
ie.text_sha1 = text_sha_1
137
ie.text_size = text_size
117
138
elif kind == 'symlink':
118
139
ie = InventoryLink(file_id, name, parent_id)
120
141
raise errors.BzrError('unknown kind %r' % kind)
121
ie.text_sha1 = text_sha_1
122
ie.text_size = text_size
125
144
def add_dir(self, file_id, path):
139
158
def has_id(self, file_id):
140
159
return self.id2path(file_id) is not None
142
def get_file(self, file_id):
144
result.write(self.contents[file_id])
161
def get_file(self, path, file_id=None):
163
file_id = self.path2id(path)
166
result.write(self.contents[file_id])
168
raise errors.NoSuchFile(path)
148
def contents_stats(self, file_id):
172
def get_file_revision(self, path, file_id=None):
174
file_id = self.path2id(path)
175
return self.inventory[file_id].revision
177
def get_file_size(self, path, file_id=None):
179
file_id = self.path2id(path)
180
return self.inventory[file_id].text_size
182
def get_file_sha1(self, path, file_id=None):
184
file_id = self.path2id(path)
185
return self.inventory[file_id].text_sha1
187
def contents_stats(self, path, file_id):
149
188
if file_id not in self.contents:
150
189
return None, None
151
text_sha1 = osutils.sha_file(self.get_file(file_id))
190
text_sha1 = osutils.sha_file(self.get_file(path, file_id))
152
191
return text_sha1, len(self.contents[file_id])
172
211
self.assertEqual(btree.old_path("grandparent/parent/file"),
173
212
"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)
214
self.assertEqual(btree.id2path(b"a"), "grandparent")
215
self.assertEqual(btree.id2path(b"b"), "grandparent/parent")
216
self.assertEqual(btree.id2path(b"c"), "grandparent/parent/file")
218
self.assertEqual(btree.path2id("grandparent"), b"a")
219
self.assertEqual(btree.path2id("grandparent/parent"), b"b")
220
self.assertEqual(btree.path2id("grandparent/parent/file"), b"c")
222
self.assertIs(btree.path2id("grandparent2"), None)
223
self.assertIs(btree.path2id("grandparent2/parent"), None)
224
self.assertIs(btree.path2id("grandparent2/parent/file"), None)
187
226
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")
227
self.assertIs(btree.old_path("grandparent"), None)
228
self.assertIs(btree.old_path("grandparent/parent"), None)
229
self.assertIs(btree.old_path("grandparent/parent/file"), None)
231
self.assertEqual(btree.id2path(b"a"), "grandparent2")
232
self.assertEqual(btree.id2path(b"b"), "grandparent2/parent")
233
self.assertEqual(btree.id2path(b"c"), "grandparent2/parent/file")
235
self.assertEqual(btree.path2id("grandparent2"), b"a")
236
self.assertEqual(btree.path2id("grandparent2/parent"), b"b")
237
self.assertEqual(btree.path2id("grandparent2/parent/file"), b"c")
200
239
self.assertTrue(btree.path2id("grandparent") is None)
201
240
self.assertTrue(btree.path2id("grandparent/parent") is None)
202
241
self.assertTrue(btree.path2id("grandparent/parent/file") is None)
204
243
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")
244
self.assertEqual(btree.id2path(b"a"), "grandparent2")
245
self.assertEqual(btree.id2path(b"b"), "grandparent2/parent2")
246
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")
248
self.assertEqual(btree.path2id("grandparent2"), b"a")
249
self.assertEqual(btree.path2id("grandparent2/parent2"), b"b")
250
self.assertEqual(btree.path2id("grandparent2/parent2/file"), b"c")
213
252
self.assertTrue(btree.path2id("grandparent2/parent") is None)
214
253
self.assertTrue(btree.path2id("grandparent2/parent/file") is None)
216
255
btree.note_rename("grandparent/parent/file",
217
256
"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")
257
self.assertEqual(btree.id2path(b"a"), "grandparent2")
258
self.assertEqual(btree.id2path(b"b"), "grandparent2/parent2")
259
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")
261
self.assertEqual(btree.path2id("grandparent2"), b"a")
262
self.assertEqual(btree.path2id("grandparent2/parent2"), b"b")
263
self.assertEqual(btree.path2id("grandparent2/parent2/file2"), b"c")
226
265
self.assertTrue(btree.path2id("grandparent2/parent2/file") is None)
230
269
btree = self.make_tree_1()[0]
231
270
btree.note_rename("grandparent/parent/file",
232
271
"grandparent/alt_parent/file")
233
self.assertEqual(btree.id2path("c"), "grandparent/alt_parent/file")
234
self.assertEqual(btree.path2id("grandparent/alt_parent/file"), "c")
272
self.assertEqual(btree.id2path(b"c"), "grandparent/alt_parent/file")
273
self.assertEqual(btree.path2id("grandparent/alt_parent/file"), b"c")
235
274
self.assertTrue(btree.path2id("grandparent/parent/file") is None)
237
276
def unified_diff(self, old, new):
239
278
diff.internal_diff("old", old, "new", new, out)
241
280
return out.read()
243
282
def make_tree_2(self):
244
283
btree = self.make_tree_1()[0]
245
284
btree.note_rename("grandparent/parent/file",
246
285
"grandparent/alt_parent/file")
247
self.assertTrue(btree.id2path("e") is None)
286
self.assertTrue(btree.id2path(b"e") is None)
248
287
self.assertTrue(btree.path2id("grandparent/parent/file") is None)
249
288
btree.note_id("e", "grandparent/parent/file")
254
293
btree = self.make_tree_2()
255
294
add_patch = self.unified_diff([], ["Extra cheese\n"])
256
295
btree.note_patch("grandparent/parent/file", add_patch)
257
btree.note_id('f', 'grandparent/parent/symlink', kind='symlink')
296
btree.note_id(b'f', 'grandparent/parent/symlink', kind='symlink')
258
297
btree.note_target('grandparent/parent/symlink', 'venus')
259
298
self.adds_test(btree)
261
300
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')
301
self.assertEqual(btree.id2path(b"e"), "grandparent/parent/file")
302
self.assertEqual(btree.path2id("grandparent/parent/file"), b"e")
303
self.assertEqual(btree.get_file("grandparent/parent/file").read(),
306
btree.get_symlink_target('grandparent/parent/symlink'), 'venus')
267
308
def test_adds2(self):
268
309
"""File/inventory adds, with patch-compatibile renames"""
346
386
format.repository_format = knitrepo.RepositoryFormatKnit3()
347
387
serializer = BundleSerializerV09('0.9')
348
388
b = self.make_branch('.', format=format)
349
serializer.write(b.repository, [], {}, StringIO())
389
serializer.write(b.repository, [], {}, BytesIO())
351
391
def test_mismatched_model(self):
352
392
"""Try copying a bundle from knit2 to knit1"""
353
393
format = bzrdir.BzrDirMetaFormat1()
354
394
format.repository_format = knitrepo.RepositoryFormatKnit3()
355
395
source = self.make_branch_and_tree('source', format=format)
356
source.commit('one', rev_id='one-id')
357
source.commit('two', rev_id='two-id')
396
source.commit('one', rev_id=b'one-id')
397
source.commit('two', rev_id=b'two-id')
359
399
write_bundle(source.branch.repository, 'two-id', 'null:', text,
441
481
bundle_txt, rev_ids = self.create_bundle_text(base_rev_id, rev_id)
442
482
new_text = bundle_txt.getvalue().replace('executable:no',
443
483
'executable:yes')
444
bundle_txt = StringIO(new_text)
484
bundle_txt = BytesIO(new_text)
445
485
bundle = read_bundle(bundle_txt)
446
486
self.valid_apply_bundle(base_rev_id, bundle)
449
489
def test_non_bundle(self):
450
490
self.assertRaises(errors.NotABundle,
451
read_bundle, StringIO('#!/bin/sh\n'))
491
read_bundle, BytesIO(b'#!/bin/sh\n'))
453
493
def test_malformed(self):
454
494
self.assertRaises(errors.BadBundle, read_bundle,
455
StringIO('# Bazaar revision bundle v'))
495
BytesIO(b'# Bazaar revision bundle v'))
457
497
def test_crlf_bundle(self):
459
read_bundle(StringIO('# Bazaar revision bundle v0.8\r\n'))
499
read_bundle(BytesIO(b'# Bazaar revision bundle v0.8\r\n'))
460
500
except errors.BadBundle:
461
501
# It is currently permitted for bundles with crlf line endings to
462
502
# make read_bundle raise a BadBundle, but this should be fixed.
530
567
original_parents = to_tree.get_parent_ids()
531
568
self.assertIs(repository.has_revision(base_rev_id), True)
532
569
for rev in info.real_revisions:
533
self.assert_(not repository.has_revision(rev.revision_id),
534
'Revision {%s} present before applying bundle'
570
self.assertTrue(not repository.has_revision(rev.revision_id),
571
'Revision {%s} present before applying bundle'
536
573
merge_bundle(info, to_tree, True, merge.Merge3Merger, False, False)
538
575
for rev in info.real_revisions:
539
self.assert_(repository.has_revision(rev.revision_id),
540
'Missing revision {%s} after applying bundle'
576
self.assertTrue(repository.has_revision(rev.revision_id),
577
'Missing revision {%s} after applying bundle'
543
self.assert_(to_tree.branch.repository.has_revision(info.target))
580
self.assertTrue(to_tree.branch.repository.has_revision(info.target))
544
581
# Do we also want to verify that all the texts have been added?
546
583
self.assertEqual(original_parents + [info.target],
547
to_tree.get_parent_ids())
584
to_tree.get_parent_ids())
549
586
rev = info.real_revisions[-1]
550
587
base_tree = self.b1.repository.revision_tree(rev.revision_id)
562
599
for path, status, kind, fileid, entry in base_files:
563
600
# Check that the meta information is the same
564
self.assertEqual(base_tree.get_file_size(fileid),
565
to_tree.get_file_size(fileid))
566
self.assertEqual(base_tree.get_file_sha1(fileid),
567
to_tree.get_file_sha1(fileid))
601
self.assertEqual(base_tree.get_file_size(path, fileid),
602
to_tree.get_file_size(to_tree.id2path(fileid)))
603
self.assertEqual(base_tree.get_file_sha1(path, fileid),
604
to_tree.get_file_sha1(to_tree.id2path(fileid)))
568
605
# Check that the contents are the same
569
606
# This is pretty expensive
570
607
# self.assertEqual(base_tree.get_file(fileid).read(),
574
611
self.tree1 = self.make_branch_and_tree('b1')
575
612
self.b1 = self.tree1.branch
577
self.build_tree_contents([('b1/one', 'one\n')])
578
self.tree1.add('one', 'one-id')
579
self.tree1.set_root_id('root-id')
580
self.tree1.commit('add one', rev_id='a@cset-0-1')
614
self.build_tree_contents([('b1/one', b'one\n')])
615
self.tree1.add('one', b'one-id')
616
self.tree1.set_root_id(b'root-id')
617
self.tree1.commit('add one', rev_id=b'a@cset-0-1')
582
bundle = self.get_valid_bundle('null:', 'a@cset-0-1')
619
bundle = self.get_valid_bundle('null:', b'a@cset-0-1')
584
621
# Make sure we can handle files with spaces, tabs, other
585
622
# bogus characters
642
679
# Now move the directory
643
680
self.tree1.rename_one('dir', 'sub/dir')
644
self.tree1.commit('rename dir', rev_id='a@cset-0-4')
681
self.tree1.commit('rename dir', rev_id=b'a@cset-0-4')
646
683
bundle = self.get_valid_bundle('a@cset-0-3', 'a@cset-0-4')
647
684
# Check a rollup bundle
648
685
bundle = self.get_valid_bundle('null:', '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(
688
with open('b1/sub/dir/WithCaps.txt', 'ab') as f: f.write('\nAdding some text\n')
689
with open('b1/sub/dir/ pre space', 'ab') as f: f.write(
653
690
'\r\nAdding some\r\nDOS format lines\r\n')
654
open('b1/sub/dir/nolastnewline.txt', 'ab').write('\n')
691
with open('b1/sub/dir/nolastnewline.txt', 'ab') as f: f.write('\n')
655
692
self.tree1.rename_one('sub/dir/ pre space',
656
693
'sub/ start space')
657
self.tree1.commit('Modified files', rev_id='a@cset-0-5')
694
self.tree1.commit('Modified files', rev_id=b'a@cset-0-5')
658
695
bundle = self.get_valid_bundle('a@cset-0-4', 'a@cset-0-5')
660
697
self.tree1.rename_one('sub/dir/WithCaps.txt', 'temp')
661
698
self.tree1.rename_one('with space.txt', 'WithCaps.txt')
662
699
self.tree1.rename_one('temp', 'with space.txt')
663
self.tree1.commit(u'swap filenames', rev_id='a@cset-0-6',
700
self.tree1.commit(u'swap filenames', rev_id=b'a@cset-0-6',
665
702
bundle = self.get_valid_bundle('a@cset-0-5', 'a@cset-0-6')
666
703
other = self.get_checkout('a@cset-0-5')
671
708
self.assertEqualDiff(tree1_inv, tree2_inv)
672
709
other.rename_one('sub/dir/nolastnewline.txt', 'sub/nolastnewline.txt')
673
other.commit('rename file', rev_id='a@cset-0-6b')
710
other.commit('rename file', rev_id=b'a@cset-0-6b')
674
711
self.tree1.merge_from_branch(other.branch)
675
self.tree1.commit(u'Merge', rev_id='a@cset-0-7',
712
self.tree1.commit(u'Merge', rev_id=b'a@cset-0-7',
677
714
bundle = self.get_valid_bundle('a@cset-0-6', 'a@cset-0-7')
679
716
def _test_symlink_bundle(self, link_name, link_target, new_link_target):
680
717
link_id = 'link-1'
682
self.requireFeature(tests.SymlinkFeature)
719
self.requireFeature(features.SymlinkFeature)
683
720
self.tree1 = self.make_branch_and_tree('b1')
684
721
self.b1 = self.tree1.branch
686
723
tt = TreeTransform(self.tree1)
687
724
tt.new_symlink(link_name, tt.root, link_target, link_id)
689
self.tree1.commit('add symlink', rev_id='l@cset-0-1')
726
self.tree1.commit('add symlink', rev_id=b'l@cset-0-1')
690
727
bundle = self.get_valid_bundle('null:', 'l@cset-0-1')
691
if getattr(bundle ,'revision_tree', None) is not None:
728
if getattr(bundle, 'revision_tree', None) is not None:
692
729
# Not all bundle formats supports revision_tree
693
730
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
self.assertEqual(link_target, bund_tree.get_symlink_target(link_name))
696
733
tt = TreeTransform(self.tree1)
697
trans_id = tt.trans_id_tree_file_id(link_id)
734
trans_id = tt.trans_id_tree_path(link_name)
698
735
tt.adjust_path('link2', tt.root, trans_id)
699
736
tt.delete_contents(trans_id)
700
737
tt.create_symlink(new_link_target, trans_id)
702
self.tree1.commit('rename and change symlink', rev_id='l@cset-0-2')
739
self.tree1.commit('rename and change symlink', rev_id=b'l@cset-0-2')
703
740
bundle = self.get_valid_bundle('l@cset-0-1', 'l@cset-0-2')
704
if getattr(bundle ,'revision_tree', None) is not None:
741
if getattr(bundle, 'revision_tree', None) is not None:
705
742
# Not all bundle formats supports revision_tree
706
743
bund_tree = bundle.revision_tree(self.b1.repository, 'l@cset-0-2')
707
744
self.assertEqual(new_link_target,
708
bund_tree.get_symlink_target(link_id))
745
bund_tree.get_symlink_target('link2'))
710
747
tt = TreeTransform(self.tree1)
711
trans_id = tt.trans_id_tree_file_id(link_id)
748
trans_id = tt.trans_id_tree_path('link2')
712
749
tt.delete_contents(trans_id)
713
750
tt.create_symlink('jupiter', trans_id)
715
self.tree1.commit('just change symlink target', rev_id='l@cset-0-3')
752
self.tree1.commit('just change symlink target', rev_id=b'l@cset-0-3')
716
753
bundle = self.get_valid_bundle('l@cset-0-2', 'l@cset-0-3')
718
755
tt = TreeTransform(self.tree1)
719
trans_id = tt.trans_id_tree_file_id(link_id)
756
trans_id = tt.trans_id_tree_path('link2')
720
757
tt.delete_contents(trans_id)
722
self.tree1.commit('Delete symlink', rev_id='l@cset-0-4')
759
self.tree1.commit('Delete symlink', rev_id=b'l@cset-0-4')
723
760
bundle = self.get_valid_bundle('l@cset-0-3', 'l@cset-0-4')
725
762
def test_symlink_bundle(self):
726
763
self._test_symlink_bundle('link', 'bar/foo', 'mars')
728
765
def test_unicode_symlink_bundle(self):
729
self.requireFeature(tests.UnicodeFilenameFeature)
766
self.requireFeature(features.UnicodeFilenameFeature)
730
767
self._test_symlink_bundle(u'\N{Euro Sign}link',
731
768
u'bar/\N{Euro Sign}foo',
732
769
u'mars\N{Euro Sign}')
741
778
tt.new_file('file2', tt.root, '\x01\n\x02\r\x03\n\x04\r\xff',
744
self.tree1.commit('add binary', rev_id='b@cset-0-1')
781
self.tree1.commit('add binary', rev_id=b'b@cset-0-1')
745
782
self.get_valid_bundle('null:', 'b@cset-0-1')
748
785
tt = TreeTransform(self.tree1)
749
trans_id = tt.trans_id_tree_file_id('binary-1')
786
trans_id = tt.trans_id_tree_path('file')
750
787
tt.delete_contents(trans_id)
752
self.tree1.commit('delete binary', rev_id='b@cset-0-2')
789
self.tree1.commit('delete binary', rev_id=b'b@cset-0-2')
753
790
self.get_valid_bundle('b@cset-0-1', 'b@cset-0-2')
755
792
# Rename & modify
756
793
tt = TreeTransform(self.tree1)
757
trans_id = tt.trans_id_tree_file_id('binary-2')
794
trans_id = tt.trans_id_tree_path('file2')
758
795
tt.adjust_path('file3', tt.root, trans_id)
759
796
tt.delete_contents(trans_id)
760
797
tt.create_file('file\rcontents\x00\n\x00', trans_id)
762
self.tree1.commit('rename and modify binary', rev_id='b@cset-0-3')
799
self.tree1.commit('rename and modify binary', rev_id=b'b@cset-0-3')
763
800
self.get_valid_bundle('b@cset-0-2', 'b@cset-0-3')
766
803
tt = TreeTransform(self.tree1)
767
trans_id = tt.trans_id_tree_file_id('binary-2')
804
trans_id = tt.trans_id_tree_path('file3')
768
805
tt.delete_contents(trans_id)
769
806
tt.create_file('\x00file\rcontents', trans_id)
771
self.tree1.commit('just modify binary', rev_id='b@cset-0-4')
808
self.tree1.commit('just modify binary', rev_id=b'b@cset-0-4')
772
809
self.get_valid_bundle('b@cset-0-3', 'b@cset-0-4')
780
817
tt = TreeTransform(self.tree1)
781
818
tt.new_file('file', tt.root, 'file', 'file')
783
self.tree1.commit('create file', rev_id='a@lmod-0-1')
820
self.tree1.commit('create file', rev_id=b'a@lmod-0-1')
785
822
tt = TreeTransform(self.tree1)
786
trans_id = tt.trans_id_tree_file_id('file')
823
trans_id = tt.trans_id_tree_path('file')
787
824
tt.delete_contents(trans_id)
788
825
tt.create_file('file2', trans_id)
790
self.tree1.commit('modify text', rev_id='a@lmod-0-2a')
827
self.tree1.commit('modify text', rev_id=b'a@lmod-0-2a')
792
829
other = self.get_checkout('a@lmod-0-1')
793
830
tt = TreeTransform(other)
794
trans_id = tt.trans_id_tree_file_id('file')
831
trans_id = tt.trans_id_tree_path('file2')
795
832
tt.delete_contents(trans_id)
796
833
tt.create_file('file2', trans_id)
798
other.commit('modify text in another tree', rev_id='a@lmod-0-2b')
835
other.commit('modify text in another tree', rev_id=b'a@lmod-0-2b')
799
836
self.tree1.merge_from_branch(other.branch)
800
self.tree1.commit(u'Merge', rev_id='a@lmod-0-3',
837
self.tree1.commit(u'Merge', rev_id=b'a@lmod-0-3',
802
self.tree1.commit(u'Merge', rev_id='a@lmod-0-4')
839
self.tree1.commit(u'Merge', rev_id=b'a@lmod-0-4')
803
840
bundle = self.get_valid_bundle('a@lmod-0-2a', 'a@lmod-0-4')
805
842
def test_hide_history(self):
806
843
self.tree1 = self.make_branch_and_tree('b1')
807
844
self.b1 = self.tree1.branch
809
open('b1/one', 'wb').write('one\n')
846
with open('b1/one', 'wb') as f: f.write(b'one\n')
810
847
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()
848
self.tree1.commit('add file', rev_id=b'a@cset-0-1')
849
with open('b1/one', 'wb') as f: f.write(b'two\n')
850
self.tree1.commit('modify', rev_id=b'a@cset-0-2')
851
with open('b1/one', 'wb') as f: f.write(b'three\n')
852
self.tree1.commit('modify', rev_id=b'a@cset-0-3')
853
bundle_file = BytesIO()
817
854
rev_ids = write_bundle(self.tree1.branch.repository, 'a@cset-0-3',
818
855
'a@cset-0-1', bundle_file, format=self.format)
819
856
self.assertNotContainsRe(bundle_file.getvalue(), '\btwo\b')
857
894
f = open(u'b1/with Dod\N{Euro Sign}', 'wb')
858
895
f.write(u'Modified \xb5\n'.encode('utf8'))
860
self.tree1.commit(u'modified', rev_id='i18n-2')
897
self.tree1.commit(u'modified', rev_id=b'i18n-2')
862
899
bundle = self.get_valid_bundle('i18n-1', 'i18n-2')
865
902
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',
903
self.tree1.commit(u'renamed, the new i18n man', rev_id=b'i18n-3',
867
904
committer=u'Erik B\xe5gfors')
869
906
bundle = self.get_valid_bundle('i18n-2', 'i18n-3')
872
909
self.tree1.remove([u'B\N{Euro Sign}gfors'])
873
self.tree1.commit(u'removed', rev_id='i18n-4')
910
self.tree1.commit(u'removed', rev_id=b'i18n-4')
875
912
bundle = self.get_valid_bundle('i18n-3', 'i18n-4')
891
928
# once we actually support them
894
self.tree1.commit('funky whitespace', rev_id='white-1')
931
self.tree1.commit('funky whitespace', rev_id=b'white-1')
896
933
bundle = self.get_valid_bundle('null:', 'white-1')
899
open('b1/trailing space ', 'ab').write('add some text\n')
900
self.tree1.commit('add text', rev_id='white-2')
936
with open('b1/trailing space ', 'ab') as f: f.write('add some text\n')
937
self.tree1.commit('add text', rev_id=b'white-2')
902
939
bundle = self.get_valid_bundle('white-1', 'white-2')
905
942
self.tree1.rename_one('trailing space ', ' start and end space ')
906
self.tree1.commit('rename', rev_id='white-3')
943
self.tree1.commit('rename', rev_id=b'white-3')
908
945
bundle = self.get_valid_bundle('white-2', 'white-3')
911
948
self.tree1.remove([' start and end space '])
912
self.tree1.commit('removed', rev_id='white-4')
949
self.tree1.commit('removed', rev_id=b'white-4')
914
951
bundle = self.get_valid_bundle('white-3', 'white-4')
941
978
def test_bundle_root_id(self):
942
979
self.tree1 = self.make_branch_and_tree('b1')
943
980
self.b1 = self.tree1.branch
944
self.tree1.commit('message', rev_id='revid1')
981
self.tree1.commit('message', rev_id=b'revid1')
945
982
bundle = self.get_valid_bundle('null:', 'revid1')
946
983
tree = self.get_bundle_tree(bundle, 'revid1')
947
self.assertEqual('revid1', tree.inventory.root.revision)
984
root_revision = tree.get_file_revision(u'', tree.get_root_id())
985
self.assertEqual('revid1', root_revision)
949
987
def test_install_revisions(self):
950
988
self.tree1 = self.make_branch_and_tree('b1')
951
989
self.b1 = self.tree1.branch
952
self.tree1.commit('message', rev_id='rev2a')
990
self.tree1.commit('message', rev_id=b'rev2a')
953
991
bundle = self.get_valid_bundle('null:', 'rev2a')
954
992
branch2 = self.make_branch('b2')
955
993
self.assertFalse(branch2.repository.has_revision('rev2a'))
1017
1055
def test_bundle_with_ghosts(self):
1018
1056
tree = self.make_branch_and_tree('tree')
1019
1057
self.b1 = tree.branch
1020
self.build_tree_contents([('tree/file', 'content1')])
1058
self.build_tree_contents([('tree/file', b'content1')])
1021
1059
tree.add(['file'])
1022
1060
tree.commit('rev1')
1023
self.build_tree_contents([('tree/file', 'content2')])
1024
tree.add_parent_tree_id('ghost')
1025
tree.commit('rev2', rev_id='rev2')
1026
bundle = self.get_valid_bundle('null:', 'rev2')
1061
self.build_tree_contents([('tree/file', b'content2')])
1062
tree.add_parent_tree_id(b'ghost')
1063
tree.commit('rev2', rev_id=b'rev2')
1064
bundle = self.get_valid_bundle(b'null:', b'rev2')
1028
1066
def make_simple_tree(self, format=None):
1029
1067
tree = self.make_branch_and_tree('b1', format=format)
1127
1165
self.tree1 = self.make_branch_and_tree('tree')
1128
1166
self.b1 = self.tree1.branch
1129
1167
# 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')])
1168
self.build_tree_contents([('tree/file2', b'contents1')])
1169
self.tree1.add('file2', b'file2-id')
1170
self.tree1.commit('rev1', rev_id=b'reva')
1171
self.build_tree_contents([('tree/file3', b'contents2')])
1134
1172
# rev2 is present in bundle, and done by fetch
1135
1173
# having file1 in the bunle causes file1's versionedfile to be opened.
1136
self.tree1.add('file3', 'file3-id')
1174
self.tree1.add('file3', b'file3-id')
1137
1175
self.tree1.commit('rev2')
1138
1176
# 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')
1177
target = self.tree1.controldir.sprout('target').open_workingtree()
1178
self.build_tree_contents([('tree/file2', b'contents3')])
1179
self.tree1.commit('rev3', rev_id=b'rev3')
1142
1180
bundle = self.get_valid_bundle('reva', 'rev3')
1143
1181
if getattr(bundle, 'get_bundle_reader', None) is None:
1144
1182
raise tests.TestSkipped('Bundle format cannot provide reader')
1145
1183
# be sure that file1 comes before file2
1146
1184
for b, m, k, r, f in bundle.get_bundle_reader().iter_records():
1185
if f == b'file3-id':
1149
self.assertNotEqual(f, 'file2-id')
1187
self.assertNotEqual(f, b'file2-id')
1150
1188
bundle.install_revisions(target.branch.repository)
1366
1404
def test_creation(self):
1367
1405
tree = self.make_branch_and_tree('tree')
1368
self.build_tree_contents([('tree/file', 'contents1\nstatic\n')])
1406
self.build_tree_contents([('tree/file', b'contents1\nstatic\n')])
1369
1407
tree.add('file', 'fileid-2')
1370
tree.commit('added file', rev_id='rev1')
1371
self.build_tree_contents([('tree/file', 'contents2\nstatic\n')])
1372
tree.commit('changed file', rev_id='rev2')
1408
tree.commit('added file', rev_id=b'rev1')
1409
self.build_tree_contents([('tree/file', b'contents2\nstatic\n')])
1410
tree.commit('changed file', rev_id=b'rev2')
1374
1412
serializer = BundleSerializerV4('1.0')
1375
1413
serializer.write(tree.branch.repository, ['rev1', 'rev2'], {}, s)
1407
1445
def test_copy_signatures(self):
1408
1446
tree_a = self.make_branch_and_tree('tree_a')
1410
import bzrlib.commit as commit
1411
oldstrategy = bzrlib.gpg.GPGStrategy
1448
import breezy.commit as commit
1449
oldstrategy = breezy.gpg.GPGStrategy
1412
1450
branch = tree_a.branch
1413
1451
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'))
1452
tree_a.commit("base", allow_pointless=True, rev_id=b'A')
1453
self.assertFalse(branch.repository.has_signature_for_revision_id('A'))
1417
from bzrlib.testament import Testament
1455
from ..testament import Testament
1418
1456
# 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",
1457
breezy.gpg.GPGStrategy = breezy.gpg.LoopbackGPGStrategy
1458
new_config = test_commit.MustSignConfig()
1459
commit.Commit(config_stack=new_config).commit(message="base",
1422
1460
allow_pointless=True,
1424
1462
working_tree=tree_a)
1425
1463
def sign(text):
1426
return bzrlib.gpg.LoopbackGPGStrategy(None).sign(text)
1464
return breezy.gpg.LoopbackGPGStrategy(None).sign(text)
1427
1465
self.assertTrue(repo_a.has_signature_for_revision_id('B'))
1429
bzrlib.gpg.GPGStrategy = oldstrategy
1467
breezy.gpg.GPGStrategy = oldstrategy
1430
1468
tree_b = self.make_branch_and_tree('tree_b')
1431
1469
repo_b = tree_b.branch.repository
1433
1471
serializer = BundleSerializerV4('4')
1434
1472
serializer.write(tree_a.branch.repository, ['A', 'B'], {}, s)
1480
1512
def make_merged_branch(self):
1481
1513
builder = self.make_branch_builder('source')
1482
1514
builder.start_series()
1483
builder.build_snapshot('a@cset-0-1', None, [
1515
builder.build_snapshot(None, [
1484
1516
('add', ('', 'root-id', 'directory', None)),
1485
1517
('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')),
1518
], revision_id='a@cset-0-1')
1519
builder.build_snapshot(['a@cset-0-1'], [
1520
('modify', ('file', 'new-content\n')),
1521
], revision_id='a@cset-0-2a')
1522
builder.build_snapshot(['a@cset-0-1'], [
1523
('add', ('other-file', 'file2-id', 'file', 'file2-content\n')),
1524
], revision_id='a@cset-0-2b')
1525
builder.build_snapshot(['a@cset-0-2a', 'a@cset-0-2b'], [
1526
('add', ('other-file', 'file2-id', 'file', 'file2-content\n')),
1527
], revision_id='a@cset-0-3')
1496
1528
builder.finish_series()
1497
1529
self.b1 = builder.get_branch()
1498
1530
self.b1.lock_read()
1750
1782
fileobj.seek(0)
1751
1783
reader = v4.BundleReader(fileobj, stream_input=True)
1752
1784
record_iter = reader.iter_records()
1753
record = record_iter.next()
1785
record = next(record_iter)
1754
1786
self.assertEqual((None, {'foo': 'bar', 'storage_kind': 'header'},
1755
1787
'info', None, None), record)
1756
record = record_iter.next()
1788
record = next(record_iter)
1757
1789
self.assertEqual(("Record body", {'storage_kind': 'fulltext',
1758
1790
'parents': ['1', '3']}, 'file', 'revid', 'fileid'),
1761
1793
def test_roundtrip_record_memory_hungry(self):
1762
fileobj = StringIO()
1763
1795
writer = v4.BundleWriter(fileobj)
1765
1797
writer.add_info_record(foo='bar')
1847
1879
self.assertRaises(errors.ConnectionReset, read_mergeable_from_url, url)
1850
class _DisconnectingTCPServer(object):
1851
"""A TCP server that immediately closes any connection made to it."""
1853
def start_server(self):
1854
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
1855
self.sock.bind(('127.0.0.1', 0))
1857
self.port = self.sock.getsockname()[1]
1858
self.thread = threading.Thread(
1859
name='%s (port %d)' % (self.__class__.__name__, self.port),
1860
target=self.accept_and_close)
1863
def accept_and_close(self):
1864
conn, addr = self.sock.accept()
1865
conn.shutdown(socket.SHUT_RDWR)
1882
class DisconnectingHandler(socketserver.BaseRequestHandler):
1883
"""A request handler that immediately closes any connection made to it."""
1886
self.request.close()
1889
class DisconnectingServer(test_server.TestingTCPServerInAThread):
1892
super(DisconnectingServer, self).__init__(
1894
test_server.TestingTCPServer,
1895
DisconnectingHandler)
1868
1897
def get_url(self):
1869
return 'bzr://127.0.0.1:%d/' % (self.port,)
1871
def stop_server(self):
1873
# make sure the thread dies by connecting to the listening socket,
1874
# just in case the test failed to do so.
1875
conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
1876
conn.connect(self.sock.getsockname())
1878
except socket.error:
1898
"""Return the url of the server"""
1899
return "bzr://%s:%d/" % self.server.server_address