1
# Copyright (C) 2007-2010 Canonical Ltd
2
# -*- coding: utf-8 -*-
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
# GNU General Public License for more details.
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
"""Tests for the switch command of bzr."""
23
from bzrlib.bzrdir import BzrDir
29
from bzrlib.workingtree import WorkingTree
30
from bzrlib.tests import (
31
TestCaseWithTransport,
34
from bzrlib.tests.features import UnicodeFilenameFeature
35
from bzrlib.directory_service import directories
38
class TestSwitch(TestCaseWithTransport):
40
def _create_sample_tree(self):
41
tree = self.make_branch_and_tree('branch-1')
42
self.build_tree(['branch-1/file-1', 'branch-1/file-2'])
49
def test_switch_up_to_date_light_checkout(self):
50
self.make_branch_and_tree('branch')
51
self.run_bzr('branch branch branch2')
52
self.run_bzr('checkout --lightweight branch checkout')
54
out, err = self.run_bzr('switch ../branch2')
55
self.assertContainsRe(err, 'Tree is up to date at revision 0.\n')
56
self.assertContainsRe(err, 'Switched to branch: .*/branch2.\n')
57
self.assertEqual('', out)
59
def test_switch_out_of_date_light_checkout(self):
60
self.make_branch_and_tree('branch')
61
self.run_bzr('branch branch branch2')
62
self.build_tree(['branch2/file'])
63
self.run_bzr('add branch2/file')
64
self.run_bzr('commit -m add-file branch2')
65
self.run_bzr('checkout --lightweight branch checkout')
67
out, err = self.run_bzr('switch ../branch2')
68
#self.assertContainsRe(err, '\+N file')
69
self.assertContainsRe(err, 'Updated to revision 1.\n')
70
self.assertContainsRe(err, 'Switched to branch: .*/branch2.\n')
71
self.assertEqual('', out)
73
def _test_switch_nick(self, lightweight):
74
"""Check that the nick gets switched too."""
75
tree1 = self.make_branch_and_tree('branch1')
76
tree2 = self.make_branch_and_tree('branch2')
77
tree2.pull(tree1.branch)
78
checkout = tree1.branch.create_checkout('checkout',
79
lightweight=lightweight)
80
self.assertEqual(checkout.branch.nick, tree1.branch.nick)
81
self.assertEqual(checkout.branch.get_config().has_explicit_nickname(),
83
self.run_bzr('switch branch2', working_dir='checkout')
85
# we need to get the tree again, otherwise we don't get the new branch
86
checkout = WorkingTree.open('checkout')
87
self.assertEqual(checkout.branch.nick, tree2.branch.nick)
88
self.assertEqual(checkout.branch.get_config().has_explicit_nickname(),
91
def test_switch_nick(self):
92
self._test_switch_nick(lightweight=False)
94
def test_switch_nick_lightweight(self):
95
self._test_switch_nick(lightweight=True)
97
def _test_switch_explicit_nick(self, lightweight):
98
"""Check that the nick gets switched too."""
99
tree1 = self.make_branch_and_tree('branch1')
100
tree2 = self.make_branch_and_tree('branch2')
101
tree2.pull(tree1.branch)
102
checkout = tree1.branch.create_checkout('checkout',
103
lightweight=lightweight)
104
self.assertEqual(checkout.branch.nick, tree1.branch.nick)
105
checkout.branch.nick = "explicit_nick"
106
self.assertEqual(checkout.branch.nick, "explicit_nick")
107
self.assertEqual(checkout.branch.get_config()._get_explicit_nickname(),
109
self.run_bzr('switch branch2', working_dir='checkout')
111
# we need to get the tree again, otherwise we don't get the new branch
112
checkout = WorkingTree.open('checkout')
113
self.assertEqual(checkout.branch.nick, tree2.branch.nick)
114
self.assertEqual(checkout.branch.get_config()._get_explicit_nickname(),
117
def test_switch_explicit_nick(self):
118
self._test_switch_explicit_nick(lightweight=False)
120
def test_switch_explicit_nick_lightweight(self):
121
self._test_switch_explicit_nick(lightweight=True)
123
def test_switch_finds_relative_branch(self):
124
"""Switch will find 'foo' relative to the branch the checkout is of."""
125
self.build_tree(['repo/'])
126
tree1 = self.make_branch_and_tree('repo/brancha')
128
tree2 = self.make_branch_and_tree('repo/branchb')
129
tree2.pull(tree1.branch)
130
branchb_id = tree2.commit('bar')
131
checkout = tree1.branch.create_checkout('checkout', lightweight=True)
132
self.run_bzr(['switch', 'branchb'], working_dir='checkout')
133
self.assertEqual(branchb_id, checkout.last_revision())
134
checkout = checkout.bzrdir.open_workingtree()
135
self.assertEqual(tree2.branch.base, checkout.branch.base)
137
def test_switch_finds_relative_bound_branch(self):
138
"""Using switch on a heavy checkout should find master sibling
140
The behaviour of lighweight and heavy checkouts should be
141
consistent when using the convenient "switch to sibling" feature
142
Both should switch to a sibling of the branch
143
they are bound to, and not a sibling of themself"""
145
self.build_tree(['repo/',
147
tree1 = self.make_branch_and_tree('repo/brancha')
149
tree2 = self.make_branch_and_tree('repo/branchb')
150
tree2.pull(tree1.branch)
151
branchb_id = tree2.commit('bar')
152
checkout = tree1.branch.create_checkout('heavyco/a', lightweight=False)
153
self.run_bzr(['switch', 'branchb'], working_dir='heavyco/a')
154
self.assertEqual(branchb_id, checkout.last_revision())
155
self.assertEqual(tree2.branch.base, checkout.branch.get_bound_location())
157
def test_switch_finds_relative_unicode_branch(self):
158
"""Switch will find 'foo' relative to the branch the checkout is of."""
159
self.requireFeature(UnicodeFilenameFeature)
160
self.build_tree(['repo/'])
161
tree1 = self.make_branch_and_tree('repo/brancha')
163
tree2 = self.make_branch_and_tree(u'repo/branch\xe9')
164
tree2.pull(tree1.branch)
165
branchb_id = tree2.commit('bar')
166
checkout = tree1.branch.create_checkout('checkout', lightweight=True)
167
self.run_bzr(['switch', u'branch\xe9'], working_dir='checkout')
168
self.assertEqual(branchb_id, checkout.last_revision())
169
checkout = checkout.bzrdir.open_workingtree()
170
self.assertEqual(tree2.branch.base, checkout.branch.base)
172
def test_switch_revision(self):
173
tree = self._create_sample_tree()
174
checkout = tree.branch.create_checkout('checkout', lightweight=True)
175
self.run_bzr(['switch', 'branch-1', '-r1'], working_dir='checkout')
176
self.assertPathExists('checkout/file-1')
177
self.assertPathDoesNotExist('checkout/file-2')
179
def test_switch_existing_colocated(self):
180
# Create a branch branch-1 that initially is a checkout of 'foo'
181
# Use switch to change it to 'anotherbranch'
182
repo = self.make_repository('branch-1', format='development-colo')
183
target_branch = repo.bzrdir.create_branch(name='foo')
184
branch.BranchReferenceFormat().initialize(
185
repo.bzrdir, target_branch=target_branch)
186
tree = repo.bzrdir.create_workingtree()
187
self.build_tree(['branch-1/file-1', 'branch-1/file-2'])
189
revid1 = tree.commit('rev1')
191
revid2 = tree.commit('rev2')
192
otherbranch = tree.bzrdir.create_branch(name='anotherbranch')
193
otherbranch.generate_revision_history(revid1)
194
self.run_bzr(['switch', 'anotherbranch'], working_dir='branch-1')
195
tree = WorkingTree.open("branch-1")
196
self.assertEquals(tree.last_revision(), revid1)
197
self.assertEquals(tree.branch.control_url, otherbranch.control_url)
199
def test_switch_new_colocated(self):
200
# Create a branch branch-1 that initially is a checkout of 'foo'
201
# Use switch to create 'anotherbranch' which derives from that
202
repo = self.make_repository('branch-1', format='development-colo')
203
target_branch = repo.bzrdir.create_branch(name='foo')
204
branch.BranchReferenceFormat().initialize(
205
repo.bzrdir, target_branch=target_branch)
206
tree = repo.bzrdir.create_workingtree()
207
self.build_tree(['branch-1/file-1', 'branch-1/file-2'])
209
revid1 = tree.commit('rev1')
210
self.run_bzr(['switch', '-b', 'anotherbranch'], working_dir='branch-1')
211
bzrdir = BzrDir.open("branch-1")
213
set([b.name for b in bzrdir.list_branches()]),
214
set(["foo", "anotherbranch"]))
215
self.assertEquals(bzrdir.open_branch().name, "anotherbranch")
216
self.assertEquals(bzrdir.open_branch().last_revision(), revid1)
218
def test_switch_new_colocated_unicode(self):
219
# Create a branch branch-1 that initially is a checkout of 'foo'
220
# Use switch to create 'branch\xe9' which derives from that
221
self.requireFeature(UnicodeFilenameFeature)
222
repo = self.make_repository('branch-1', format='development-colo')
223
target_branch = repo.bzrdir.create_branch(name='foo')
224
branch.BranchReferenceFormat().initialize(
225
repo.bzrdir, target_branch=target_branch)
226
tree = repo.bzrdir.create_workingtree()
227
self.build_tree(['branch-1/file-1', 'branch-1/file-2'])
229
revid1 = tree.commit('rev1')
230
self.run_bzr(['switch', '-b', u'branch\xe9'], working_dir='branch-1')
231
bzrdir = BzrDir.open("branch-1")
233
set([b.name for b in bzrdir.list_branches()]),
234
set(["foo", u"branch\xe9"]))
235
self.assertEquals(bzrdir.open_branch().name, u"branch\xe9")
236
self.assertEquals(bzrdir.open_branch().last_revision(), revid1)
238
def test_switch_only_revision(self):
239
tree = self._create_sample_tree()
240
checkout = tree.branch.create_checkout('checkout', lightweight=True)
241
self.assertPathExists('checkout/file-1')
242
self.assertPathExists('checkout/file-2')
243
self.run_bzr(['switch', '-r1'], working_dir='checkout')
244
self.assertPathExists('checkout/file-1')
245
self.assertPathDoesNotExist('checkout/file-2')
246
# Check that we don't accept a range
248
['bzr switch --revision takes exactly one revision identifier'],
249
['switch', '-r0..2'], working_dir='checkout')
251
def prepare_lightweight_switch(self):
252
branch = self.make_branch('branch')
253
branch.create_checkout('tree', lightweight=True)
254
osutils.rename('branch', 'branch1')
256
def test_switch_lightweight_after_branch_moved(self):
257
self.prepare_lightweight_switch()
258
self.run_bzr('switch --force ../branch1', working_dir='tree')
259
branch_location = WorkingTree.open('tree').branch.base
260
self.assertEndsWith(branch_location, 'branch1/')
262
def test_switch_lightweight_after_branch_moved_relative(self):
263
self.prepare_lightweight_switch()
264
self.run_bzr('switch --force branch1', working_dir='tree')
265
branch_location = WorkingTree.open('tree').branch.base
266
self.assertEndsWith(branch_location, 'branch1/')
268
def test_create_branch_no_branch(self):
269
self.prepare_lightweight_switch()
270
self.run_bzr_error(['cannot create branch without source branch'],
271
'switch --create-branch ../branch2', working_dir='tree')
273
def test_create_branch(self):
274
branch = self.make_branch('branch')
275
tree = branch.create_checkout('tree', lightweight=True)
276
tree.commit('one', rev_id='rev-1')
277
self.run_bzr('switch --create-branch ../branch2', working_dir='tree')
278
tree = WorkingTree.open('tree')
279
self.assertEndsWith(tree.branch.base, '/branch2/')
281
def test_create_branch_local(self):
282
branch = self.make_branch('branch')
283
tree = branch.create_checkout('tree', lightweight=True)
284
tree.commit('one', rev_id='rev-1')
285
self.run_bzr('switch --create-branch branch2', working_dir='tree')
286
tree = WorkingTree.open('tree')
287
# The new branch should have been created at the same level as
288
# 'branch', because we did not have a '/' segment
289
self.assertEqual(branch.base[:-1] + '2/', tree.branch.base)
291
def test_create_branch_short_name(self):
292
branch = self.make_branch('branch')
293
tree = branch.create_checkout('tree', lightweight=True)
294
tree.commit('one', rev_id='rev-1')
295
self.run_bzr('switch -b branch2', working_dir='tree')
296
tree = WorkingTree.open('tree')
297
# The new branch should have been created at the same level as
298
# 'branch', because we did not have a '/' segment
299
self.assertEqual(branch.base[:-1] + '2/', tree.branch.base)
301
def test_create_branch_directory_services(self):
302
branch = self.make_branch('branch')
303
tree = branch.create_checkout('tree', lightweight=True)
304
class FooLookup(object):
305
def look_up(self, name, url):
307
directories.register('foo:', FooLookup, 'Create branches named foo-')
308
self.addCleanup(directories.remove, 'foo:')
309
self.run_bzr('switch -b foo:branch2', working_dir='tree')
310
tree = WorkingTree.open('tree')
311
self.assertEndsWith(tree.branch.base, 'foo-branch2/')
313
def test_switch_with_post_switch_hook(self):
314
from bzrlib import branch as _mod_branch
316
_mod_branch.Branch.hooks.install_named_hook('post_switch',
318
self.make_branch_and_tree('branch')
319
self.run_bzr('branch branch branch2')
320
self.run_bzr('checkout branch checkout')
322
self.assertLength(0, calls)
323
out, err = self.run_bzr('switch ../branch2')
324
self.assertLength(1, calls)
326
def test_switch_lightweight_co_with_post_switch_hook(self):
327
from bzrlib import branch as _mod_branch
329
_mod_branch.Branch.hooks.install_named_hook('post_switch',
331
self.make_branch_and_tree('branch')
332
self.run_bzr('branch branch branch2')
333
self.run_bzr('checkout --lightweight branch checkout')
335
self.assertLength(0, calls)
336
out, err = self.run_bzr('switch ../branch2')
337
self.assertLength(1, calls)
339
def test_switch_lightweight_directory(self):
340
"""Test --directory option"""
342
# create a source branch
343
a_tree = self.make_branch_and_tree('a')
344
self.build_tree_contents([('a/a', 'initial\n')])
346
a_tree.commit(message='initial')
348
# clone and add a differing revision
349
b_tree = a_tree.bzrdir.sprout('b').open_workingtree()
350
self.build_tree_contents([('b/a', 'initial\nmore\n')])
351
b_tree.commit(message='more')
353
self.run_bzr('checkout --lightweight a checkout')
354
self.run_bzr('switch --directory checkout b')
355
self.assertFileEqual('initial\nmore\n', 'checkout/a')
358
class TestSwitchParentLocationBase(TestCaseWithTransport):
361
"""Set up a repository and branch ready for testing."""
362
super(TestSwitchParentLocationBase, self).setUp()
363
self.script_runner = script.ScriptRunner()
364
self.script_runner.run_script(self, '''
365
$ bzr init-repo --no-trees repo
368
shared repository: repo
369
$ bzr init repo/trunk
370
Created a repository branch...
371
Using shared repository: ...
374
def assertParent(self, expected_parent, branch):
375
"""Verify that the parent is not None and is set correctly."""
376
actual_parent = branch.get_parent()
377
self.assertIsSameRealPath(urlutils.local_path_to_url(expected_parent),
381
class TestSwitchParentLocation(TestSwitchParentLocationBase):
383
def _checkout_and_switch(self, option=''):
384
self.script_runner.run_script(self, '''
385
$ bzr checkout %(option)s repo/trunk checkout
387
$ bzr switch --create-branch switched
388
2>Tree is up to date at revision 0.
389
2>Switched to branch:...switched...
392
bound_branch = branch.Branch.open_containing('checkout')[0]
393
master_branch = branch.Branch.open_containing('repo/switched')[0]
394
return (bound_branch, master_branch)
396
def test_switch_parent_lightweight(self):
397
"""Lightweight checkout using bzr switch."""
398
bb, mb = self._checkout_and_switch(option='--lightweight')
399
self.assertParent('repo/trunk', bb)
400
self.assertParent('repo/trunk', mb)
402
def test_switch_parent_heavyweight(self):
403
"""Heavyweight checkout using bzr switch."""
404
bb, mb = self._checkout_and_switch()
405
self.assertParent('repo/trunk', bb)
406
self.assertParent('repo/trunk', mb)
409
class TestSwitchDoesntOpenMasterBranch(TestCaseWithTransport):
410
# See https://bugs.launchpad.net/bzr/+bug/812285
411
# "bzr switch --create-branch" can point the new branch's parent to the
412
# master branch, but it doesn't have to open it to do so.
414
def test_switch_create_doesnt_open_master_branch(self):
415
master = self.make_branch_and_tree('master')
417
# Note: not a lightweight checkout
418
checkout = master.branch.create_checkout('checkout')
420
def open_hook(branch):
421
# Just append the final directory of the branch
422
name = branch.base.rstrip('/').rsplit('/', 1)[1]
424
branch.Branch.hooks.install_named_hook('open', open_hook,
426
self.run_bzr('switch --create-branch -d checkout feature')
427
# We only open the master branch 1 time.
428
# This test should be cleaner to write, but see bug:
429
# https://bugs.launchpad.net/bzr/+bug/812295
430
self.assertEqual(1, opened.count('master'))