1
# Copyright (C) 2005-2013, 2016 Canonical Ltd
1
# Copyright (C) 2005-2010 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')
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)
1849
1839
bundle, then the ConnectionReset error should be propagated.
1851
1841
# Instantiate a server that will provoke a ConnectionReset
1852
sock_server = DisconnectingServer()
1842
sock_server = _DisconnectingTCPServer()
1853
1843
self.start_server(sock_server)
1854
1844
# We don't really care what the url is since the server will close the
1855
1845
# connection without interpreting it
1857
1847
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)
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)
1875
1868
def get_url(self):
1876
"""Return the url of the server"""
1877
return "bzr://%s:%d/" % self.server.server_address
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: