116
116
tree_a.add('vla', 'file2')
117
117
tree_a.commit('rev2', rev_id='rev2')
119
delta = tree_a.branch.get_revision_delta(1)
119
delta = self.applyDeprecated(symbol_versioning.deprecated_in(
120
(2, 5, 0)), tree_a.branch.get_revision_delta, 1)
120
121
self.assertIsInstance(delta, _mod_delta.TreeDelta)
121
122
self.assertEqual([('foo', 'file1', 'file')], delta.added)
122
delta = tree_a.branch.get_revision_delta(2)
123
delta = self.applyDeprecated(symbol_versioning.deprecated_in(
124
(2, 5, 0)), tree_a.branch.get_revision_delta, 2)
123
125
self.assertIsInstance(delta, _mod_delta.TreeDelta)
124
126
self.assertEqual([('vla', 'file2', 'file')], delta.added)
247
255
self.get_branch().repository.get_revision,
251
# compare the gpg-to-sign info for a commit with a ghost and
252
# an identical tree without a ghost
253
# fetch missing should rewrite the TOC of weaves to list newly available parents.
255
def test_sign_existing_revision(self):
256
wt = self.make_branch_and_tree('.')
258
wt.commit("base", allow_pointless=True, rev_id='A')
259
from bzrlib.testament import Testament
260
strategy = gpg.LoopbackGPGStrategy(None)
261
branch.repository.lock_write()
262
branch.repository.start_write_group()
263
branch.repository.sign_revision('A', strategy)
264
branch.repository.commit_write_group()
265
branch.repository.unlock()
266
self.assertEqual('-----BEGIN PSEUDO-SIGNED CONTENT-----\n' +
267
Testament.from_revision(branch.repository,
268
'A').as_short_text() +
269
'-----END PSEUDO-SIGNED CONTENT-----\n',
270
branch.repository.get_signature_text('A'))
272
def test_store_signature(self):
273
wt = self.make_branch_and_tree('.')
277
branch.repository.start_write_group()
279
branch.repository.store_revision_signature(
280
gpg.LoopbackGPGStrategy(None), 'FOO', 'A')
282
branch.repository.abort_write_group()
285
branch.repository.commit_write_group()
288
# A signature without a revision should not be accessible.
289
self.assertRaises(errors.NoSuchRevision,
290
branch.repository.has_signature_for_revision_id,
292
wt.commit("base", allow_pointless=True, rev_id='A')
293
self.assertEqual('-----BEGIN PSEUDO-SIGNED CONTENT-----\n'
294
'FOO-----END PSEUDO-SIGNED CONTENT-----\n',
295
branch.repository.get_signature_text('A'))
297
def test_branch_keeps_signatures(self):
298
wt = self.make_branch_and_tree('source')
299
wt.commit('A', allow_pointless=True, rev_id='A')
300
repo = wt.branch.repository
302
repo.start_write_group()
303
repo.sign_revision('A', gpg.LoopbackGPGStrategy(None))
304
repo.commit_write_group()
306
#FIXME: clone should work to urls,
307
# wt.clone should work to disks.
308
self.build_tree(['target/'])
309
d2 = repo.bzrdir.clone(urlutils.local_path_to_url('target'))
310
self.assertEqual(repo.get_signature_text('A'),
311
d2.open_repository().get_signature_text('A'))
313
def test_missing_revisions(self):
314
t1 = self.make_branch_and_tree('b1')
315
rev1 = t1.commit('one')
316
t2 = t1.bzrdir.sprout('b2').open_workingtree()
317
rev2 = t1.commit('two')
318
rev3 = t1.commit('three')
320
self.assertEqual([rev2, rev3],
321
self.applyDeprecated(deprecated_in((1, 6, 0)),
322
t2.branch.missing_revisions, t1.branch))
325
self.applyDeprecated(deprecated_in((1, 6, 0)),
326
t2.branch.missing_revisions, t1.branch, stop_revision=1))
327
self.assertEqual([rev2],
328
self.applyDeprecated(deprecated_in((1, 6, 0)),
329
t2.branch.missing_revisions, t1.branch, stop_revision=2))
330
self.assertEqual([rev2, rev3],
331
self.applyDeprecated(deprecated_in((1, 6, 0)),
332
t2.branch.missing_revisions, t1.branch, stop_revision=3))
334
self.assertRaises(errors.NoSuchRevision,
335
self.applyDeprecated, deprecated_in((1, 6, 0)),
336
t2.branch.missing_revisions, t1.branch, stop_revision=4)
338
rev4 = t2.commit('four')
339
self.assertRaises(errors.DivergedBranches,
340
self.applyDeprecated, deprecated_in((1, 6, 0)),
341
t2.branch.missing_revisions, t1.branch)
343
def test_nicks(self):
344
"""Test explicit and implicit branch nicknames.
258
def test_nicks_bzr(self):
259
"""Test the behaviour of branch nicks specific to bzr branches.
346
261
Nicknames are implicitly the name of the branch's directory, unless an
347
262
explicit nickname is set. That is, an explicit nickname always
348
263
overrides the implicit one.
350
t = transport.get_transport(self.get_url())
266
t = self.get_transport()
351
267
branch = self.make_branch('bzr.dev')
268
if not isinstance(branch, _mod_branch.BzrBranch):
269
raise tests.TestNotApplicable("not a bzr branch format")
352
270
# The nick will be 'bzr.dev', because there is no explicit nick set.
353
271
self.assertEqual(branch.nick, 'bzr.dev')
354
272
# Move the branch to a different directory, 'bzr.ab'. Now that branch
385
321
repo = self.make_repository('.', shared=True)
386
322
except errors.IncompatibleFormat:
388
self.assertEquals(0, len(repo.bzrdir.list_branches()))
324
if repo.bzrdir._format.colocated_branches:
325
raise tests.TestNotApplicable(
326
"control dir does not support colocated branches")
327
self.assertEqual(0, len(repo.bzrdir.list_branches()))
328
if not self.bzrdir_format.colocated_branches:
329
raise tests.TestNotApplicable("control dir format does not support "
330
"colocated branches")
390
332
child_branch1 = self.branch_format.initialize(repo.bzrdir,
392
except (errors.UninitializableFormat, errors.NoColocatedBranchSupport):
334
except errors.UninitializableFormat:
393
335
# branch references are not default init'able and
394
336
# not all bzrdirs support colocated branches.
396
self.assertEquals(1, len(repo.bzrdir.list_branches()))
338
self.assertEqual(1, len(repo.bzrdir.list_branches()))
397
339
self.branch_format.initialize(repo.bzrdir, name='branch2')
398
self.assertEquals(2, len(repo.bzrdir.list_branches()))
340
self.assertEqual(2, len(repo.bzrdir.list_branches()))
342
def test_create_append_revisions_only(self):
344
repo = self.make_repository('.', shared=True)
345
except errors.IncompatibleFormat:
347
for val in (True, False):
349
branch = self.branch_format.initialize(repo.bzrdir,
350
append_revisions_only=True)
351
except (errors.UninitializableFormat, errors.UpgradeRequired):
352
# branch references are not default init'able and
353
# not all branches support append_revisions_only
355
self.assertEqual(True, branch.get_append_revisions_only())
356
repo.bzrdir.destroy_branch()
358
def test_get_set_append_revisions_only(self):
359
branch = self.make_branch('.')
360
if branch._format.supports_set_append_revisions_only():
361
branch.set_append_revisions_only(True)
362
self.assertTrue(branch.get_append_revisions_only())
363
branch.set_append_revisions_only(False)
364
self.assertFalse(branch.get_append_revisions_only())
366
self.assertRaises(errors.UpgradeRequired,
367
branch.set_append_revisions_only, True)
368
self.assertFalse(branch.get_append_revisions_only())
400
370
def test_create_open_branch_uses_repository(self):
402
372
repo = self.make_repository('.', shared=True)
403
373
except errors.IncompatibleFormat:
374
raise tests.TestNotApplicable("requires shared repository support")
405
375
child_transport = repo.bzrdir.root_transport.clone('child')
406
376
child_transport.mkdir('.')
407
child_dir = self.bzrdir_format.initialize_on_transport(child_transport)
378
child_dir = self.bzrdir_format.initialize_on_transport(child_transport)
379
except errors.UninitializableFormat:
380
raise tests.TestNotApplicable("control dir format not initializable")
409
382
child_branch = self.branch_format.initialize(child_dir)
410
383
except errors.UninitializableFormat:
433
406
"""Create a fake revision history easily."""
434
407
tree = self.make_branch_and_tree('.')
435
408
rev1 = tree.commit('foo')
436
orig_history = tree.branch.revision_history()
410
self.addCleanup(tree.unlock)
411
graph = tree.branch.repository.get_graph()
413
graph.iter_lefthand_ancestry(
414
tree.branch.last_revision(), [revision.NULL_REVISION]))
437
415
rev2 = tree.commit('bar', allow_pointless=True)
438
416
tree.branch.generate_revision_history(rev1)
439
self.assertEqual(orig_history, tree.branch.revision_history())
417
self.assertEqual(orig_history, list(
418
graph.iter_lefthand_ancestry(
419
tree.branch.last_revision(), [revision.NULL_REVISION])))
441
421
def test_generate_revision_history_NULL_REVISION(self):
442
422
tree = self.make_branch_and_tree('.')
443
423
rev1 = tree.commit('foo')
425
self.addCleanup(tree.unlock)
444
426
tree.branch.generate_revision_history(revision.NULL_REVISION)
445
self.assertEqual([], tree.branch.revision_history())
427
self.assertEqual(revision.NULL_REVISION, tree.branch.last_revision())
447
429
def test_create_checkout(self):
448
430
tree_a = self.make_branch_and_tree('a')
481
467
tree_a = self.make_branch_and_tree('a')
482
468
rev_id = tree_a.commit('put some content in the branch')
483
469
# open the branch via a readonly transport
484
source_branch = _mod_branch.Branch.open(self.get_readonly_url('a'))
470
url = self.get_readonly_url(
471
osutils.basename(tree_a.branch.base.rstrip('/')))
472
t = transport.get_transport_from_url(url)
473
if not tree_a.branch.bzrdir._format.supports_transport(t):
474
raise tests.TestNotApplicable("format does not support transport")
475
source_branch = _mod_branch.Branch.open(url)
485
476
# sanity check that the test will be valid
486
477
self.assertRaises((errors.LockError, errors.TransportNotPossible),
487
478
source_branch.lock_write)
488
479
checkout = source_branch.create_checkout('c')
489
480
self.assertEqual(rev_id, checkout.last_revision())
491
def test_set_revision_history(self):
492
tree = self.make_branch_and_tree('a')
493
tree.commit('a commit', rev_id='rev1')
495
br.set_revision_history(["rev1"])
496
self.assertEquals(br.revision_history(), ["rev1"])
497
br.set_revision_history([])
498
self.assertEquals(br.revision_history(), [])
482
def test_heads_to_fetch(self):
483
# heads_to_fetch is a method that returns a collection of revids that
484
# need to be fetched to copy this branch into another repo. At a
485
# minimum this will include the tip.
486
# (In native formats, this is the tip + tags, but other formats may
487
# have other revs needed)
488
tree = self.make_branch_and_tree('a')
489
tree.commit('first commit', rev_id='rev1')
490
tree.commit('second commit', rev_id='rev2')
491
must_fetch, should_fetch = tree.branch.heads_to_fetch()
492
self.assertTrue('rev2' in must_fetch)
494
def test_heads_to_fetch_not_null_revision(self):
495
# NULL_REVISION does not appear in the result of heads_to_fetch, even
496
# for an empty branch.
497
tree = self.make_branch_and_tree('a')
498
must_fetch, should_fetch = tree.branch.heads_to_fetch()
499
self.assertFalse(revision.NULL_REVISION in must_fetch)
500
self.assertFalse(revision.NULL_REVISION in should_fetch)
501
503
class TestBranchFormat(per_branch.TestCaseWithBranch):
682
695
# they may not be initializable.
684
697
# supported formats must be able to init and open
685
t = transport.get_transport(self.get_url())
686
readonly_t = transport.get_transport(self.get_readonly_url())
698
t = self.get_transport()
699
readonly_t = transport.get_transport_from_url(self.get_readonly_url())
687
700
made_branch = self.make_branch('.')
688
self.failUnless(isinstance(made_branch, _mod_branch.Branch))
701
self.assertIsInstance(made_branch, _mod_branch.Branch)
690
703
# find it via bzrdir opening:
691
opened_control = bzrdir.BzrDir.open(readonly_t.base)
704
opened_control = controldir.ControlDir.open(readonly_t.base)
692
705
direct_opened_branch = opened_control.open_branch()
693
706
self.assertEqual(direct_opened_branch.__class__, made_branch.__class__)
694
707
self.assertEqual(opened_control, direct_opened_branch.bzrdir)
695
self.failUnless(isinstance(direct_opened_branch._format,
696
self.branch_format.__class__))
708
self.assertIsInstance(direct_opened_branch._format,
709
self.branch_format.__class__)
698
711
# find it via Branch.open
699
712
opened_branch = _mod_branch.Branch.open(readonly_t.base)
700
self.failUnless(isinstance(opened_branch, made_branch.__class__))
713
self.assertIsInstance(opened_branch, made_branch.__class__)
701
714
self.assertEqual(made_branch._format.__class__,
702
715
opened_branch._format.__class__)
703
716
# if it has a unique id string, can we probe for it ?
746
759
except errors.UpgradeRequired:
747
760
raise tests.TestNotApplicable('Format does not support binding')
762
def test_unbind_clears_cached_master_branch(self):
763
"""b.unbind clears any cached value of b.get_master_branch."""
764
master = self.make_branch('master')
765
branch = self.make_branch('branch')
768
except errors.UpgradeRequired:
769
raise tests.TestNotApplicable('Format does not support binding')
770
self.addCleanup(branch.lock_write().unlock)
771
self.assertNotEqual(None, branch.get_master_branch())
773
self.assertEqual(None, branch.get_master_branch())
775
def test_bind_clears_cached_master_branch(self):
776
"""b.bind clears any cached value of b.get_master_branch."""
777
master1 = self.make_branch('master1')
778
master2 = self.make_branch('master2')
779
branch = self.make_branch('branch')
782
except errors.UpgradeRequired:
783
raise tests.TestNotApplicable('Format does not support binding')
784
self.addCleanup(branch.lock_write().unlock)
785
self.assertNotEqual(None, branch.get_master_branch())
787
self.assertEqual('.', urlutils.relative_url(self.get_url('master2'),
788
branch.get_master_branch().base))
790
def test_set_bound_location_clears_cached_master_branch(self):
791
"""b.set_bound_location clears any cached value of b.get_master_branch.
793
master1 = self.make_branch('master1')
794
master2 = self.make_branch('master2')
795
branch = self.make_branch('branch')
798
except errors.UpgradeRequired:
799
raise tests.TestNotApplicable('Format does not support binding')
800
self.addCleanup(branch.lock_write().unlock)
801
self.assertNotEqual(None, branch.get_master_branch())
802
branch.set_bound_location(self.get_url('master2'))
803
self.assertEqual('.', urlutils.relative_url(self.get_url('master2'),
804
branch.get_master_branch().base))
750
807
class TestStrict(per_branch.TestCaseWithBranch):
999
1061
# above the control dir but we might need to relax that?
1000
1062
self.assertEqual(br.control_url.find(br.user_url), 0)
1001
1063
self.assertEqual(br.control_url, br.control_transport.base)
1066
class FakeShelfCreator(object):
1068
def __init__(self, branch):
1069
self.branch = branch
1071
def write_shelf(self, shelf_file, message=None):
1072
tree = self.branch.repository.revision_tree(revision.NULL_REVISION)
1073
with transform.TransformPreview(tree) as tt:
1074
shelf.ShelfCreator._write_shelf(
1075
shelf_file, tt, revision.NULL_REVISION)
1078
@contextlib.contextmanager
1079
def skip_if_storing_uncommitted_unsupported():
1082
except errors.StoringUncommittedNotSupported:
1083
raise tests.TestNotApplicable('Cannot store uncommitted changes.')
1086
class TestUncommittedChanges(per_branch.TestCaseWithBranch):
1088
def bind(self, branch, master):
1091
except errors.UpgradeRequired:
1092
raise tests.TestNotApplicable('Branch cannot be bound.')
1094
def test_store_uncommitted(self):
1095
tree = self.make_branch_and_tree('b')
1096
branch = tree.branch
1097
creator = FakeShelfCreator(branch)
1098
with skip_if_storing_uncommitted_unsupported():
1099
self.assertIs(None, branch.get_unshelver(tree))
1100
branch.store_uncommitted(creator)
1101
self.assertIsNot(None, branch.get_unshelver(tree))
1103
def test_store_uncommitted_bound(self):
1104
tree = self.make_branch_and_tree('b')
1105
branch = tree.branch
1106
master = self.make_branch('master')
1107
self.bind(branch, master)
1108
creator = FakeShelfCreator(tree.branch)
1109
self.assertIs(None, tree.branch.get_unshelver(tree))
1110
self.assertIs(None, master.get_unshelver(tree))
1111
tree.branch.store_uncommitted(creator)
1112
self.assertIsNot(None, master.get_unshelver(tree))
1114
def test_store_uncommitted_already_stored(self):
1115
branch = self.make_branch('b')
1116
with skip_if_storing_uncommitted_unsupported():
1117
branch.store_uncommitted(FakeShelfCreator(branch))
1118
self.assertRaises(errors.ChangesAlreadyStored,
1119
branch.store_uncommitted, FakeShelfCreator(branch))
1121
def test_store_uncommitted_none(self):
1122
branch = self.make_branch('b')
1123
with skip_if_storing_uncommitted_unsupported():
1124
branch.store_uncommitted(FakeShelfCreator(branch))
1125
branch.store_uncommitted(None)
1126
self.assertIs(None, branch.get_unshelver(None))
1128
def test_get_unshelver(self):
1129
tree = self.make_branch_and_tree('tree')
1131
self.build_tree_contents([('tree/file', 'contents1')])
1133
with skip_if_storing_uncommitted_unsupported():
1134
tree.store_uncommitted()
1135
unshelver = tree.branch.get_unshelver(tree)
1136
self.assertIsNot(None, unshelver)
1138
def test_get_unshelver_bound(self):
1139
tree = self.make_branch_and_tree('tree')
1141
self.build_tree_contents([('tree/file', 'contents1')])
1143
with skip_if_storing_uncommitted_unsupported():
1144
tree.store_uncommitted()
1145
branch = self.make_branch('branch')
1146
self.bind(branch, tree.branch)
1147
unshelver = branch.get_unshelver(tree)
1148
self.assertIsNot(None, unshelver)