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