1
# Copyright (C) 2004, 2005, 2006, 2007 Canonical Ltd
1
# Copyright (C) 2005-2013, 2016 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
35
33
from bzrlib.bundle import read_mergeable_from_url
36
34
from bzrlib.bundle.apply_bundle import install_bundle, merge_bundle
37
35
from bzrlib.bundle.bundle_data import BundleTree
38
from bzrlib.bzrdir import BzrDir
39
36
from bzrlib.directory_service import directories
40
37
from bzrlib.bundle.serializer import write_bundle, read_bundle, v09, v4
41
38
from bzrlib.bundle.serializer.v08 import BundleSerializerV08
42
39
from bzrlib.bundle.serializer.v09 import BundleSerializerV09
43
40
from bzrlib.bundle.serializer.v4 import BundleSerializerV4
44
from bzrlib.branch import Branch
45
41
from bzrlib.repofmt import knitrepo
46
42
from bzrlib.tests import (
50
48
from bzrlib.transform import TreeTransform
76
75
self.root = InventoryDirectory(ROOT_ID, '', None)
78
77
inventory = property(lambda x:x)
81
return self.paths.iterkeys()
78
root_inventory = property(lambda x:x)
80
def get_root_id(self):
81
return self.root.file_id
83
def all_file_ids(self):
84
return set(self.paths.keys())
86
def is_executable(self, file_id):
87
# Not all the files are executable.
83
90
def __getitem__(self, file_id):
84
91
if file_id == self.root.file_id:
96
103
for path, file_id in self.ids.iteritems():
97
104
yield path, self[file_id]
99
def get_file_kind(self, file_id):
106
def kind(self, file_id):
100
107
if file_id in self.contents:
106
113
def make_entry(self, file_id, path):
107
from bzrlib.inventory import (InventoryEntry, InventoryFile
108
, InventoryDirectory, InventoryLink)
114
from bzrlib.inventory import (InventoryFile , InventoryDirectory,
109
116
name = os.path.basename(path)
110
kind = self.get_file_kind(file_id)
117
kind = self.kind(file_id)
111
118
parent_id = self.parent_id(file_id)
112
119
text_sha_1, text_size = self.contents_stats(file_id)
113
120
if kind == 'directory':
114
121
ie = InventoryDirectory(file_id, name, parent_id)
115
122
elif kind == 'file':
116
123
ie = InventoryFile(file_id, name, parent_id)
124
ie.text_sha1 = text_sha_1
125
ie.text_size = text_size
117
126
elif kind == 'symlink':
118
127
ie = InventoryLink(file_id, name, parent_id)
120
129
raise errors.BzrError('unknown kind %r' % kind)
121
ie.text_sha1 = text_sha_1
122
ie.text_size = text_size
125
132
def add_dir(self, file_id, path):
155
def get_file_revision(self, file_id):
156
return self.inventory[file_id].revision
158
def get_file_size(self, file_id):
159
return self.inventory[file_id].text_size
161
def get_file_sha1(self, file_id):
162
return self.inventory[file_id].text_sha1
148
164
def contents_stats(self, file_id):
149
165
if file_id not in self.contents:
150
166
return None, None
507
523
if not _mod_revision.is_null(rev_id):
508
rh = self.b1.revision_history()
509
tree.branch.set_revision_history(rh[:rh.index(rev_id)+1])
524
tree.branch.generate_revision_history(rev_id)
511
526
delta = tree.changes_from(self.b1.repository.revision_tree(rev_id))
512
527
self.assertFalse(delta.has_changed(),
530
545
original_parents = to_tree.get_parent_ids()
531
546
self.assertIs(repository.has_revision(base_rev_id), True)
532
547
for rev in info.real_revisions:
533
self.assert_(not repository.has_revision(rev.revision_id),
534
'Revision {%s} present before applying bundle'
548
self.assertTrue(not repository.has_revision(rev.revision_id),
549
'Revision {%s} present before applying bundle'
536
551
merge_bundle(info, to_tree, True, merge.Merge3Merger, False, False)
538
553
for rev in info.real_revisions:
539
self.assert_(repository.has_revision(rev.revision_id),
540
'Missing revision {%s} after applying bundle'
554
self.assertTrue(repository.has_revision(rev.revision_id),
555
'Missing revision {%s} after applying bundle'
543
self.assert_(to_tree.branch.repository.has_revision(info.target))
558
self.assertTrue(to_tree.branch.repository.has_revision(info.target))
544
559
# Do we also want to verify that all the texts have been added?
546
561
self.assertEqual(original_parents + [info.target],
547
to_tree.get_parent_ids())
562
to_tree.get_parent_ids())
549
564
rev = info.real_revisions[-1]
550
565
base_tree = self.b1.repository.revision_tree(rev.revision_id)
648
663
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(
666
with open('b1/sub/dir/WithCaps.txt', 'ab') as f: f.write('\nAdding some text\n')
667
with open('b1/sub/dir/ pre space', 'ab') as f: f.write(
653
668
'\r\nAdding some\r\nDOS format lines\r\n')
654
open('b1/sub/dir/nolastnewline.txt', 'ab').write('\n')
669
with open('b1/sub/dir/nolastnewline.txt', 'ab') as f: f.write('\n')
655
670
self.tree1.rename_one('sub/dir/ pre space',
656
671
'sub/ start space')
657
672
self.tree1.commit('Modified files', rev_id='a@cset-0-5')
679
694
def _test_symlink_bundle(self, link_name, link_target, new_link_target):
680
695
link_id = 'link-1'
682
self.requireFeature(tests.SymlinkFeature)
697
self.requireFeature(features.SymlinkFeature)
683
698
self.tree1 = self.make_branch_and_tree('b1')
684
699
self.b1 = self.tree1.branch
726
741
self._test_symlink_bundle('link', 'bar/foo', 'mars')
728
743
def test_unicode_symlink_bundle(self):
729
self.requireFeature(tests.UnicodeFilenameFeature)
744
self.requireFeature(features.UnicodeFilenameFeature)
730
745
self._test_symlink_bundle(u'\N{Euro Sign}link',
731
746
u'bar/\N{Euro Sign}foo',
732
747
u'mars\N{Euro Sign}')
806
821
self.tree1 = self.make_branch_and_tree('b1')
807
822
self.b1 = self.tree1.branch
809
open('b1/one', 'wb').write('one\n')
824
with open('b1/one', 'wb') as f: f.write('one\n')
810
825
self.tree1.add('one')
811
826
self.tree1.commit('add file', rev_id='a@cset-0-1')
812
open('b1/one', 'wb').write('two\n')
827
with open('b1/one', 'wb') as f: f.write('two\n')
813
828
self.tree1.commit('modify', rev_id='a@cset-0-2')
814
open('b1/one', 'wb').write('three\n')
829
with open('b1/one', 'wb') as f: f.write('three\n')
815
830
self.tree1.commit('modify', rev_id='a@cset-0-3')
816
831
bundle_file = StringIO()
817
832
rev_ids = write_bundle(self.tree1.branch.repository, 'a@cset-0-3',
833
848
return bundle_file.getvalue()
835
850
def test_unicode_bundle(self):
836
self.requireFeature(tests.UnicodeFilenameFeature)
851
self.requireFeature(features.UnicodeFilenameFeature)
837
852
# Handle international characters
839
854
f = open(u'b1/with Dod\N{Euro Sign}', 'wb')
896
911
bundle = self.get_valid_bundle('null:', 'white-1')
899
open('b1/trailing space ', 'ab').write('add some text\n')
914
with open('b1/trailing space ', 'ab') as f: f.write('add some text\n')
900
915
self.tree1.commit('add text', rev_id='white-2')
902
917
bundle = self.get_valid_bundle('white-1', 'white-2')
944
959
self.tree1.commit('message', rev_id='revid1')
945
960
bundle = self.get_valid_bundle('null:', 'revid1')
946
961
tree = self.get_bundle_tree(bundle, 'revid1')
947
self.assertEqual('revid1', tree.inventory.root.revision)
962
root_revision = tree.get_file_revision(tree.get_root_id())
963
self.assertEqual('revid1', root_revision)
949
965
def test_install_revisions(self):
950
966
self.tree1 = self.make_branch_and_tree('b1')
1039
1055
bundle = read_bundle(self.create_bundle_text('null:', 'rev2')[0])
1040
1056
repo = self.make_repository('repo', format='dirstate-with-subtree')
1041
1057
bundle.install_revisions(repo)
1042
inv_text = repo.get_inventory_xml('rev2')
1058
inv_text = repo._get_inventory_xml('rev2')
1043
1059
self.assertNotContainsRe(inv_text, 'format="5"')
1044
1060
self.assertContainsRe(inv_text, 'format="7"')
1066
1082
def test_inv_hash_across_serializers(self):
1067
1083
repo = self.make_repo_with_installed_revisions()
1068
recorded_inv_sha1 = repo.get_inventory_sha1('rev2')
1069
xml = repo.get_inventory_xml('rev2')
1084
recorded_inv_sha1 = repo.get_revision('rev2').inventory_sha1
1085
xml = repo._get_inventory_xml('rev2')
1070
1086
self.assertEqual(osutils.sha_string(xml), recorded_inv_sha1)
1072
1088
def test_across_models_incompatible(self):
1412
1428
branch = tree_a.branch
1413
1429
repo_a = branch.repository
1414
1430
tree_a.commit("base", allow_pointless=True, rev_id='A')
1415
self.failIf(branch.repository.has_signature_for_revision_id('A'))
1431
self.assertFalse(branch.repository.has_signature_for_revision_id('A'))
1417
1433
from bzrlib.testament import Testament
1418
1434
# monkey patch gpg signing mechanism
1419
1435
bzrlib.gpg.GPGStrategy = bzrlib.gpg.LoopbackGPGStrategy
1420
new_config = test_commit.MustSignConfig(branch)
1421
commit.Commit(config=new_config).commit(message="base",
1436
new_config = test_commit.MustSignConfig()
1437
commit.Commit(config_stack=new_config).commit(message="base",
1422
1438
allow_pointless=True,
1424
1440
working_tree=tree_a)
1820
1830
def look_up(self, name, url):
1821
1831
return 'source'
1822
1832
directories.register('foo:', FooService, 'Testing directory service')
1823
self.addCleanup(lambda: directories.remove('foo:'))
1833
self.addCleanup(directories.remove, 'foo:')
1824
1834
self.build_tree_contents([('./foo:bar', out.getvalue())])
1825
1835
self.assertRaises(errors.NotABundle, read_mergeable_from_url,
1839
1849
bundle, then the ConnectionReset error should be propagated.
1841
1851
# Instantiate a server that will provoke a ConnectionReset
1842
sock_server = _DisconnectingTCPServer()
1852
sock_server = DisconnectingServer()
1843
1853
self.start_server(sock_server)
1844
1854
# We don't really care what the url is since the server will close the
1845
1855
# connection without interpreting it
1847
1857
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."""
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)
1860
class DisconnectingHandler(SocketServer.BaseRequestHandler):
1861
"""A request handler that immediately closes any connection made to it."""
1864
self.request.close()
1867
class DisconnectingServer(test_server.TestingTCPServerInAThread):
1870
super(DisconnectingServer, self).__init__(
1872
test_server.TestingTCPServer,
1873
DisconnectingHandler)
1868
1875
def get_url(self):
1869
return 'bzr://127.0.0.1:%d/' % (self.port,)
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:
1876
"""Return the url of the server"""
1877
return "bzr://%s:%d/" % self.server.server_address