1
# Copyright (C) 2005 by Canonical Ltd
2
# -*- coding: utf-8 -*-
1
# Copyright (C) 2005, 2006 Canonical Ltd
4
3
# This program is free software; you can redistribute it and/or modify
5
4
# it under the terms of the GNU General Public License as published by
6
5
# the Free Software Foundation; either version 2 of the License, or
7
6
# (at your option) any later version.
9
8
# This program is distributed in the hope that it will be useful,
10
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
11
# GNU General Public License for more details.
14
13
# You should have received a copy of the GNU General Public License
15
14
# along with this program; if not, write to the Free Software
16
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
"""Black-box tests for bzr pull.
18
"""Black-box tests for bzr pull."""
25
23
from bzrlib.branch import Branch
26
from bzrlib.osutils import abspath
24
from bzrlib.directory_service import directories
25
from bzrlib.osutils import pathjoin
27
26
from bzrlib.tests.blackbox import ExternalBase
28
27
from bzrlib.uncommit import uncommit
28
from bzrlib.workingtree import WorkingTree
29
from bzrlib import urlutils
31
32
class TestPull(ExternalBase):
33
def example_branch(test):
35
file('hello', 'wt').write('foo')
36
test.runbzr('add hello')
37
test.runbzr('commit -m setup hello')
38
file('goodbye', 'wt').write('baz')
39
test.runbzr('add goodbye')
40
test.runbzr('commit -m setup goodbye')
34
def example_branch(self, path='.'):
35
tree = self.make_branch_and_tree(path)
36
self.build_tree_contents([
37
(pathjoin(path, 'hello'), 'foo'),
38
(pathjoin(path, 'goodbye'), 'baz')])
40
tree.commit(message='setup')
42
tree.commit(message='setup')
42
45
def test_pull(self):
43
46
"""Pull changes from one branch to another."""
47
a_tree = self.example_branch('a')
48
self.runbzr('pull', retcode=3)
49
self.runbzr('missing', retcode=3)
50
self.runbzr('missing .')
51
self.runbzr('missing')
52
if sys.platform not in ('win32', 'cygwin'):
53
# This is equivalent to doing "bzr pull ."
54
# Which means that bzr creates 2 branches grabbing
55
# the same location, and tries to pull.
56
# However, 2 branches mean 2 locks on the same file
57
# which ultimately implies a deadlock.
58
# (non windows platforms allow multiple locks on the
59
# same file by the same calling process)
61
self.runbzr('pull /', retcode=3)
62
if sys.platform not in ('win32', 'cygwin'):
49
self.run_bzr('pull', retcode=3)
50
self.run_bzr('missing', retcode=3)
51
self.run_bzr('missing .')
52
self.run_bzr('missing')
53
# this will work on windows because we check for the same branch
54
# in pull - if it fails, it is a regression
56
self.run_bzr('pull /', retcode=3)
57
if sys.platform not in ('win32', 'cygwin'):
66
self.runbzr('branch a b')
61
b_tree = a_tree.bzrdir.sprout('b').open_workingtree()
70
self.runbzr('add subdir')
71
self.runbzr('commit -m blah --unchanged')
74
b = Branch.open('../b')
75
self.assertEquals(a.revision_history(), b.revision_history()[:-1])
76
self.runbzr('pull ../b')
77
self.assertEquals(a.revision_history(), b.revision_history())
78
self.runbzr('commit -m blah2 --unchanged')
80
self.runbzr('commit -m blah3 --unchanged')
66
b_tree.commit(message='blah', allow_pointless=True)
71
self.assertEqual(a.revision_history(), b.revision_history()[:-1])
74
self.run_bzr('pull ../b')
75
self.assertEqual(a.revision_history(), b.revision_history())
76
a_tree.commit(message='blah2', allow_pointless=True)
77
b_tree.commit(message='blah3', allow_pointless=True)
82
self.runbzr('pull ../a', retcode=3)
80
self.run_bzr('pull ../a', retcode=3)
84
self.runbzr('branch b overwriteme')
82
b_tree.bzrdir.sprout('overwriteme')
85
83
os.chdir('overwriteme')
86
self.runbzr('pull --overwrite ../a')
84
self.run_bzr('pull --overwrite ../a')
87
85
overwritten = Branch.open('.')
88
86
self.assertEqual(overwritten.revision_history(),
89
87
a.revision_history())
91
self.runbzr('merge ../b')
92
self.runbzr('commit -m blah4 --unchanged')
88
a_tree.merge_from_branch(b_tree.branch)
89
a_tree.commit(message="blah4", allow_pointless=True)
93
90
os.chdir('../b/subdir')
94
self.runbzr('pull ../../a')
95
self.assertEquals(a.revision_history()[-1], b.revision_history()[-1])
96
self.runbzr('commit -m blah5 --unchanged')
97
self.runbzr('commit -m blah6 --unchanged')
91
self.run_bzr('pull ../../a')
92
self.assertEqual(a.revision_history()[-1], b.revision_history()[-1])
93
sub_tree = WorkingTree.open_containing('.')[0]
94
sub_tree.commit(message="blah5", allow_pointless=True)
95
sub_tree.commit(message="blah6", allow_pointless=True)
99
self.runbzr('pull ../a')
97
self.run_bzr('pull ../a')
101
self.runbzr('commit -m blah7 --unchanged')
102
self.runbzr('merge ../b')
103
self.runbzr('commit -m blah8 --unchanged')
104
self.runbzr('pull ../b')
105
self.runbzr('pull ../b')
99
a_tree.commit(message="blah7", allow_pointless=True)
100
a_tree.merge_from_branch(b_tree.branch)
101
a_tree.commit(message="blah8", allow_pointless=True)
102
self.run_bzr('pull ../b')
103
self.run_bzr('pull ../b')
105
def test_pull_dash_d(self):
106
self.example_branch('a')
107
self.make_branch_and_tree('b')
108
self.make_branch_and_tree('c')
109
# pull into that branch
110
self.run_bzr('pull -d b a')
111
# pull into a branch specified by a url
112
c_url = urlutils.local_path_to_url('c')
113
self.assertStartsWith(c_url, 'file://')
114
self.run_bzr(['pull', '-d', c_url, 'a'])
107
116
def test_pull_revision(self):
108
117
"""Pull some changes from one branch to another."""
112
self.example_branch()
113
file('hello2', 'wt').write('foo')
114
self.runbzr('add hello2')
115
self.runbzr('commit -m setup hello2')
116
file('goodbye2', 'wt').write('baz')
117
self.runbzr('add goodbye2')
118
self.runbzr('commit -m setup goodbye2')
121
self.runbzr('branch -r 1 a b')
118
a_tree = self.example_branch('a')
119
self.build_tree_contents([
121
('a/goodbye2', 'baz')])
123
a_tree.commit(message="setup")
124
a_tree.add('goodbye2')
125
a_tree.commit(message="setup")
127
b_tree = a_tree.bzrdir.sprout('b',
128
revision_id=a_tree.branch.get_rev_id(1)).open_workingtree()
123
self.runbzr('pull -r 2')
130
self.run_bzr('pull -r 2')
124
131
a = Branch.open('../a')
125
132
b = Branch.open('.')
126
self.assertEquals(a.revno(),4)
127
self.assertEquals(b.revno(),2)
128
self.runbzr('pull -r 3')
129
self.assertEquals(b.revno(),3)
130
self.runbzr('pull -r 4')
131
self.assertEquals(a.revision_history(), b.revision_history())
133
self.assertEqual(a.revno(),4)
134
self.assertEqual(b.revno(),2)
135
self.run_bzr('pull -r 3')
136
self.assertEqual(b.revno(),3)
137
self.run_bzr('pull -r 4')
138
self.assertEqual(a.revision_history(), b.revision_history())
134
141
def test_overwrite_uptodate(self):
135
142
# Make sure pull --overwrite overwrites
136
143
# even if the target branch has merged
137
144
# everything already.
140
def get_rh(expected_len):
141
rh = self.capture('revision-history')
142
# Make sure we don't have trailing empty revisions
143
rh = rh.strip().split('\n')
144
self.assertEqual(len(rh), expected_len)
150
open('foo', 'wb').write('original\n')
152
bzr('commit', '-m', 'initial commit')
155
bzr('branch', 'a', 'b')
158
open('foo', 'wb').write('changed\n')
159
bzr('commit', '-m', 'later change')
161
open('foo', 'wb').write('another\n')
162
bzr('commit', '-m', 'a third change')
164
rev_history_a = get_rh(3)
168
bzr('commit', '-m', 'merge')
170
rev_history_b = get_rh(2)
172
bzr('pull', '--overwrite', '../a')
173
rev_history_b = get_rh(3)
145
a_tree = self.make_branch_and_tree('a')
146
self.build_tree_contents([('a/foo', 'original\n')])
148
a_tree.commit(message='initial commit')
150
b_tree = a_tree.bzrdir.sprout('b').open_workingtree()
152
self.build_tree_contents([('a/foo', 'changed\n')])
153
a_tree.commit(message='later change')
155
self.build_tree_contents([('a/foo', 'a third change')])
156
a_tree.commit(message='a third change')
158
rev_history_a = a_tree.branch.revision_history()
159
self.assertEqual(len(rev_history_a), 3)
161
b_tree.merge_from_branch(a_tree.branch)
162
b_tree.commit(message='merge')
164
self.assertEqual(len(b_tree.branch.revision_history()), 2)
167
self.run_bzr('pull --overwrite ../a')
168
rev_history_b = b_tree.branch.revision_history()
169
self.assertEqual(len(rev_history_b), 3)
175
171
self.assertEqual(rev_history_b, rev_history_a)
177
173
def test_overwrite_children(self):
178
174
# Make sure pull --overwrite sets the revision-history
179
175
# to be identical to the pull source, even if we have convergence
182
def get_rh(expected_len):
183
rh = self.capture('revision-history')
184
# Make sure we don't have trailing empty revisions
185
rh = rh.strip().split('\n')
186
self.assertEqual(len(rh), expected_len)
192
open('foo', 'wb').write('original\n')
194
bzr('commit', '-m', 'initial commit')
197
bzr('branch', 'a', 'b')
200
open('foo', 'wb').write('changed\n')
201
bzr('commit', '-m', 'later change')
203
open('foo', 'wb').write('another\n')
204
bzr('commit', '-m', 'a third change')
206
rev_history_a = get_rh(3)
210
bzr('commit', '-m', 'merge')
212
rev_history_b = get_rh(2)
215
open('foo', 'wb').write('a fourth change\n')
216
bzr('commit', '-m', 'a fourth change')
218
rev_history_a = get_rh(4)
176
a_tree = self.make_branch_and_tree('a')
177
self.build_tree_contents([('a/foo', 'original\n')])
179
a_tree.commit(message='initial commit')
181
b_tree = a_tree.bzrdir.sprout('b').open_workingtree()
183
self.build_tree_contents([('a/foo', 'changed\n')])
184
a_tree.commit(message='later change')
186
self.build_tree_contents([('a/foo', 'a third change')])
187
a_tree.commit(message='a third change')
189
self.assertEqual(len(a_tree.branch.revision_history()), 3)
191
b_tree.merge_from_branch(a_tree.branch)
192
b_tree.commit(message='merge')
194
self.assertEqual(len(b_tree.branch.revision_history()), 2)
196
self.build_tree_contents([('a/foo', 'a fourth change\n')])
197
a_tree.commit(message='a fourth change')
199
rev_history_a = a_tree.branch.revision_history()
200
self.assertEqual(len(rev_history_a), 4)
220
202
# With convergence, we could just pull over the
221
203
# new change, but with --overwrite, we want to switch our history
223
bzr('pull', '--overwrite', '../a')
224
rev_history_b = get_rh(4)
205
self.run_bzr('pull --overwrite ../a')
206
rev_history_b = b_tree.branch.revision_history()
207
self.assertEqual(len(rev_history_b), 4)
226
209
self.assertEqual(rev_history_b, rev_history_a)
246
229
self.assertEqual(None, branch_b.get_parent())
247
230
# test pull for failure without parent set
248
231
os.chdir('branch_b')
249
out = self.runbzr('pull', retcode=3)
250
self.assertEquals(out,
232
out = self.run_bzr('pull', retcode=3)
233
self.assertEqual(out,
251
234
('','bzr: ERROR: No pull location known or specified.\n'))
252
235
# test implicit --remember when no parent set, this pull conflicts
253
236
self.build_tree(['d'])
255
238
tree_b.commit('commit d')
256
out = self.runbzr('pull ../branch_a', retcode=3)
257
self.assertEquals(out,
258
('','bzr: ERROR: These branches have diverged. Try merge.\n'))
259
self.assertEquals(abspath(branch_b.get_parent()), abspath(parent))
239
out = self.run_bzr('pull ../branch_a', retcode=3)
240
self.assertEqual(out,
241
('','bzr: ERROR: These branches have diverged.'
242
' Use the merge command to reconcile them.\n'))
243
self.assertEqual(branch_b.get_parent(), parent)
260
244
# test implicit --remember after resolving previous failure
261
245
uncommit(branch=branch_b, tree=tree_b)
262
246
transport.delete('branch_b/d')
264
self.assertEquals(abspath(branch_b.get_parent()), abspath(parent))
248
self.assertEqual(branch_b.get_parent(), parent)
265
249
# test explicit --remember
266
self.runbzr('pull ../branch_c --remember')
267
self.assertEquals(abspath(branch_b.get_parent()),
268
abspath(branch_c.bzrdir.root_transport.base))
250
self.run_bzr('pull ../branch_c --remember')
251
self.assertEqual(branch_b.get_parent(),
252
branch_c.bzrdir.root_transport.base)
254
def test_pull_bundle(self):
255
from bzrlib.testament import Testament
256
# Build up 2 trees and prepare for a pull
257
tree_a = self.make_branch_and_tree('branch_a')
258
f = open('branch_a/a', 'wb')
262
tree_a.commit('message')
264
tree_b = tree_a.bzrdir.sprout('branch_b').open_workingtree()
266
# Make a change to 'a' that 'b' can pull
267
f = open('branch_a/a', 'wb')
270
tree_a.commit('message')
272
# Create the bundle for 'b' to pull
274
self.run_bzr('bundle ../branch_b -o ../bundle')
276
os.chdir('../branch_b')
277
out, err = self.run_bzr('pull ../bundle')
278
self.assertEqual(out,
279
'Now on revision 2.\n')
280
self.assertEqual(err,
281
' M a\nAll changes applied successfully.\n')
283
self.assertEqualDiff(tree_a.branch.revision_history(),
284
tree_b.branch.revision_history())
286
testament_a = Testament.from_revision(tree_a.branch.repository,
287
tree_a.get_parent_ids()[0])
288
testament_b = Testament.from_revision(tree_b.branch.repository,
289
tree_b.get_parent_ids()[0])
290
self.assertEqualDiff(testament_a.as_text(),
291
testament_b.as_text())
293
# it is legal to attempt to pull an already-merged bundle
294
out, err = self.run_bzr('pull ../bundle')
295
self.assertEqual(err, '')
296
self.assertEqual(out, 'No revisions to pull.\n')
298
def test_pull_verbose_no_files(self):
299
"""Pull --verbose should not list modified files"""
300
tree_a = self.make_branch_and_tree('tree_a')
301
self.build_tree(['tree_a/foo'])
304
tree_b = self.make_branch_and_tree('tree_b')
305
out = self.run_bzr('pull --verbose -d tree_b tree_a')[0]
306
self.assertContainsRe(out, 'bar')
307
self.assertNotContainsRe(out, 'added:')
308
self.assertNotContainsRe(out, 'foo')
310
def test_pull_quiet(self):
311
"""Check that bzr pull --quiet does not print anything"""
312
tree_a = self.make_branch_and_tree('tree_a')
313
self.build_tree(['tree_a/foo'])
315
revision_id = tree_a.commit('bar')
316
tree_b = tree_a.bzrdir.sprout('tree_b').open_workingtree()
317
out, err = self.run_bzr('pull --quiet -d tree_b')
318
self.assertEqual(out, '')
319
self.assertEqual(err, '')
320
self.assertEqual(tree_b.last_revision(), revision_id)
321
self.build_tree(['tree_a/moo'])
323
revision_id = tree_a.commit('quack')
324
out, err = self.run_bzr('pull --quiet -d tree_b')
325
self.assertEqual(out, '')
326
self.assertEqual(err, '')
327
self.assertEqual(tree_b.last_revision(), revision_id)
329
def test_pull_from_directory_service(self):
330
source = self.make_branch_and_tree('source')
331
source.commit('commit 1')
332
target = source.bzrdir.sprout('target').open_workingtree()
333
source_last = source.commit('commit 2')
334
class FooService(object):
335
"""A directory service that always returns source"""
337
def look_up(self, name, url):
339
directories.register('foo:', FooService, 'Testing directory service')
340
self.addCleanup(lambda: directories.remove('foo:'))
341
self.run_bzr('pull foo:bar -d target')
342
self.assertEqual(source_last, target.last_revision())