1
# Copyright (C) 2005-2010 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
17
17
from cStringIO import StringIO
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 (
33
from brzlib.bundle import read_mergeable_from_url
34
from brzlib.bundle.apply_bundle import install_bundle, merge_bundle
35
from brzlib.bundle.bundle_data import BundleTree
36
from brzlib.directory_service import directories
37
from brzlib.bundle.serializer import write_bundle, read_bundle, v09, v4
38
from brzlib.bundle.serializer.v08 import BundleSerializerV08
39
from brzlib.bundle.serializer.v09 import BundleSerializerV09
40
from brzlib.bundle.serializer.v4 import BundleSerializerV4
41
from brzlib.repofmt import knitrepo
42
from brzlib.tests import (
50
from bzrlib.transform import TreeTransform
48
from brzlib.transform import TreeTransform
53
51
def get_text(vf, key):
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 brzlib.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')
1332
1348
:return: The in-memory bundle
1334
from bzrlib.bundle import serializer
1350
from brzlib.bundle import serializer
1335
1351
bundle_txt, rev_ids = self.create_bundle_text(base_rev_id, rev_id)
1336
1352
new_text = self.get_raw(StringIO(''.join(bundle_txt)))
1337
1353
new_text = new_text.replace('<file file_id="exe-1"',
1407
1423
def test_copy_signatures(self):
1408
1424
tree_a = self.make_branch_and_tree('tree_a')
1410
import bzrlib.commit as commit
1411
oldstrategy = bzrlib.gpg.GPGStrategy
1426
import brzlib.commit as commit
1427
oldstrategy = brzlib.gpg.GPGStrategy
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
from bzrlib.testament import Testament
1433
from brzlib.testament import Testament
1418
1434
# 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",
1435
brzlib.gpg.GPGStrategy = brzlib.gpg.LoopbackGPGStrategy
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)
1425
1441
def sign(text):
1426
return bzrlib.gpg.LoopbackGPGStrategy(None).sign(text)
1442
return brzlib.gpg.LoopbackGPGStrategy(None).sign(text)
1427
1443
self.assertTrue(repo_a.has_signature_for_revision_id('B'))
1429
bzrlib.gpg.GPGStrategy = oldstrategy
1445
brzlib.gpg.GPGStrategy = oldstrategy
1430
1446
tree_b = self.make_branch_and_tree('tree_b')
1431
1447
repo_b = tree_b.branch.repository
1460
1470
:return: The in-memory bundle
1462
from bzrlib.bundle import serializer
1472
from brzlib.bundle import serializer
1463
1473
bundle_txt, rev_ids = self.create_bundle_text(base_rev_id, rev_id)
1464
1474
new_text = self.get_raw(StringIO(''.join(bundle_txt)))
1465
1475
# We are going to be replacing some text to set the executable bit on a
1828
1838
def test_infinite_redirects_are_not_a_bundle(self):
1829
1839
"""If a URL causes TooManyRedirections then NotABundle is raised.
1831
from bzrlib.tests.blackbox.test_push import RedirectingMemoryServer
1841
from brzlib.tests.blackbox.test_push import RedirectingMemoryServer
1832
1842
server = RedirectingMemoryServer()
1833
1843
self.start_server(server)
1834
1844
url = server.get_url() + 'infinite-loop'
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."""
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)
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,)
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:
1876
"""Return the url of the server"""
1877
return "bzr://%s:%d/" % self.server.server_address