1
# Copyright (C) 2005, 2007 Canonical Ltd
 
 
3
# This program is free software; you can redistribute it and/or modify
 
 
4
# it under the terms of the GNU General Public License as published by
 
 
5
# the Free Software Foundation; either version 2 of the License, or
 
 
6
# (at your option) any later version.
 
 
8
# This program is distributed in the hope that it will be useful,
 
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
 
11
# GNU General Public License for more details.
 
 
13
# You should have received a copy of the GNU General Public License
 
 
14
# along with this program; if not, write to the Free Software
 
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
 
18
"""Black-box tests for bzr push."""
 
 
26
from bzrlib.branch import Branch
 
 
27
from bzrlib.bzrdir import BzrDirMetaFormat1
 
 
28
from bzrlib.osutils import abspath
 
 
29
from bzrlib.repofmt.knitrepo import RepositoryFormatKnit1
 
 
30
from bzrlib.tests.blackbox import ExternalBase
 
 
31
from bzrlib.uncommit import uncommit
 
 
32
from bzrlib.urlutils import local_path_from_url
 
 
33
from bzrlib.workingtree import WorkingTree
 
 
36
class TestPush(ExternalBase):
 
 
38
    def test_push_remember(self):
 
 
39
        """Push changes from one branch to another and test push location."""
 
 
40
        transport = self.get_transport()
 
 
41
        tree_a = self.make_branch_and_tree('branch_a')
 
 
42
        branch_a = tree_a.branch
 
 
43
        self.build_tree(['branch_a/a'])
 
 
45
        tree_a.commit('commit a')
 
 
46
        tree_b = branch_a.bzrdir.sprout('branch_b').open_workingtree()
 
 
47
        branch_b = tree_b.branch
 
 
48
        tree_c = branch_a.bzrdir.sprout('branch_c').open_workingtree()
 
 
49
        branch_c = tree_c.branch
 
 
50
        self.build_tree(['branch_a/b'])
 
 
52
        tree_a.commit('commit b')
 
 
53
        self.build_tree(['branch_b/c'])
 
 
55
        tree_b.commit('commit c')
 
 
56
        # initial push location must be empty
 
 
57
        self.assertEqual(None, branch_b.get_push_location())
 
 
59
        # test push for failure without push location set
 
 
61
        out = self.run_bzr('push', retcode=3)
 
 
62
        self.assertEquals(out,
 
 
63
                ('','bzr: ERROR: No push location known or specified.\n'))
 
 
65
        # test not remembered if cannot actually push
 
 
66
        self.run_bzr('push', '../path/which/doesnt/exist', retcode=3)
 
 
67
        out = self.run_bzr('push', retcode=3)
 
 
69
                ('', 'bzr: ERROR: No push location known or specified.\n'),
 
 
72
        # test implicit --remember when no push location set, push fails
 
 
73
        out = self.run_bzr('push', '../branch_b', retcode=3)
 
 
74
        self.assertEquals(out,
 
 
75
                ('','bzr: ERROR: These branches have diverged.  '
 
 
76
                    'Try using "merge" and then "push".\n'))
 
 
77
        self.assertEquals(abspath(branch_a.get_push_location()),
 
 
78
                          abspath(branch_b.bzrdir.root_transport.base))
 
 
80
        # test implicit --remember after resolving previous failure
 
 
81
        uncommit(branch=branch_b, tree=tree_b)
 
 
82
        transport.delete('branch_b/c')
 
 
83
        out, err = self.run_bzr('push')
 
 
84
        path = branch_a.get_push_location()
 
 
85
        self.assertEquals(out,
 
 
86
                          'Using saved location: %s\n' 
 
 
87
                          'Pushed up to revision 2.\n'
 
 
88
                          % local_path_from_url(path))
 
 
90
                         'All changes applied successfully.\n')
 
 
91
        self.assertEqual(path,
 
 
92
                         branch_b.bzrdir.root_transport.base)
 
 
93
        # test explicit --remember
 
 
94
        self.run_bzr('push', '../branch_c', '--remember')
 
 
95
        self.assertEquals(branch_a.get_push_location(),
 
 
96
                          branch_c.bzrdir.root_transport.base)
 
 
98
    def test_push_without_tree(self):
 
 
99
        # bzr push from a branch that does not have a checkout should work.
 
 
100
        b = self.make_branch('.')
 
 
101
        out, err = self.run_bzr('push', 'pushed-location')
 
 
102
        self.assertEqual('', out)
 
 
103
        self.assertEqual('Created new branch.\n', err)
 
 
104
        b2 = Branch.open('pushed-location')
 
 
105
        self.assertEndsWith(b2.base, 'pushed-location/')
 
 
107
    def test_push_new_branch_revision_count(self):
 
 
108
        # bzr push of a branch with revisions to a new location 
 
 
109
        # should print the number of revisions equal to the length of the 
 
 
111
        t = self.make_branch_and_tree('tree')
 
 
112
        self.build_tree(['tree/file'])
 
 
116
        out, err = self.run_bzr('push', 'pushed-to')
 
 
118
        self.assertEqual('', out)
 
 
119
        self.assertEqual('Created new branch.\n', err)
 
 
121
    def test_push_only_pushes_history(self):
 
 
122
        # Knit branches should only push the history for the current revision.
 
 
123
        format = BzrDirMetaFormat1()
 
 
124
        format.repository_format = RepositoryFormatKnit1()
 
 
125
        shared_repo = self.make_repository('repo', format=format, shared=True)
 
 
126
        shared_repo.set_make_working_trees(True)
 
 
128
        def make_shared_tree(path):
 
 
129
            shared_repo.bzrdir.root_transport.mkdir(path)
 
 
130
            shared_repo.bzrdir.create_branch_convenience('repo/' + path)
 
 
131
            return WorkingTree.open('repo/' + path)
 
 
132
        tree_a = make_shared_tree('a')
 
 
133
        self.build_tree(['repo/a/file'])
 
 
135
        tree_a.commit('commit a-1', rev_id='a-1')
 
 
136
        f = open('repo/a/file', 'ab')
 
 
137
        f.write('more stuff\n')
 
 
139
        tree_a.commit('commit a-2', rev_id='a-2')
 
 
141
        tree_b = make_shared_tree('b')
 
 
142
        self.build_tree(['repo/b/file'])
 
 
144
        tree_b.commit('commit b-1', rev_id='b-1')
 
 
146
        self.assertTrue(shared_repo.has_revision('a-1'))
 
 
147
        self.assertTrue(shared_repo.has_revision('a-2'))
 
 
148
        self.assertTrue(shared_repo.has_revision('b-1'))
 
 
150
        # Now that we have a repository with shared files, make sure
 
 
151
        # that things aren't copied out by a 'push'
 
 
153
        self.run_bzr('push', '../../push-b')
 
 
154
        pushed_tree = WorkingTree.open('../../push-b')
 
 
155
        pushed_repo = pushed_tree.branch.repository
 
 
156
        self.assertFalse(pushed_repo.has_revision('a-1'))
 
 
157
        self.assertFalse(pushed_repo.has_revision('a-2'))
 
 
158
        self.assertTrue(pushed_repo.has_revision('b-1'))
 
 
160
    def test_push_funky_id(self):
 
 
161
        t = self.make_branch_and_tree('tree')
 
 
163
        self.build_tree(['filename'])
 
 
164
        t.add('filename', 'funky-chars<>%&;"\'')
 
 
165
        t.commit('commit filename')
 
 
166
        self.run_bzr('push', '../new-tree')
 
 
168
    def test_push_dash_d(self):
 
 
169
        t = self.make_branch_and_tree('from')
 
 
170
        t.commit(allow_pointless=True,
 
 
171
                message='first commit')
 
 
172
        self.run_bzr('push -d from to-one')
 
 
173
        self.failUnlessExists('to-one')
 
 
174
        self.run_bzr('push -d %s %s' 
 
 
175
            % tuple(map(urlutils.local_path_to_url, ['from', 'to-two'])))
 
 
176
        self.failUnlessExists('to-two')
 
 
178
    def create_simple_tree(self):
 
 
179
        tree = self.make_branch_and_tree('tree')
 
 
180
        self.build_tree(['tree/a'])
 
 
181
        tree.add(['a'], ['a-id'])
 
 
182
        tree.commit('one', rev_id='r1')
 
 
185
    def test_push_create_prefix(self):
 
 
186
        """'bzr push --create-prefix' will create leading directories."""
 
 
187
        tree = self.create_simple_tree()
 
 
189
        self.run_bzr_error(['Parent directory of ../new/tree does not exist'],
 
 
190
                           'push', '../new/tree',
 
 
192
        self.run_bzr('push', '../new/tree', '--create-prefix',
 
 
194
        new_tree = WorkingTree.open('new/tree')
 
 
195
        self.assertEqual(tree.last_revision(), new_tree.last_revision())
 
 
196
        self.failUnlessExists('new/tree/a')
 
 
198
    def test_push_use_existing(self):
 
 
199
        """'bzr push --use-existing-dir' can push into an existing dir.
 
 
201
        By default, 'bzr push' will not use an existing, non-versioned dir.
 
 
203
        tree = self.create_simple_tree()
 
 
204
        self.build_tree(['target/'])
 
 
206
        self.run_bzr_error(['Target directory ../target already exists',
 
 
207
                            'Supply --use-existing-dir',
 
 
208
                           ], 'push', '../target',
 
 
211
        self.run_bzr('push', '--use-existing-dir', '../target',
 
 
214
        new_tree = WorkingTree.open('target')
 
 
215
        self.assertEqual(tree.last_revision(), new_tree.last_revision())
 
 
216
        # The push should have created target/a
 
 
217
        self.failUnlessExists('target/a')
 
 
219
    def test_push_onto_repo(self):
 
 
220
        """We should be able to 'bzr push' into an existing bzrdir."""
 
 
221
        tree = self.create_simple_tree()
 
 
222
        repo = self.make_repository('repo', shared=True)
 
 
224
        self.run_bzr('push', '../repo',
 
 
227
        # Pushing onto an existing bzrdir will create a repository and
 
 
228
        # branch as needed, but will only create a working tree if there was
 
 
230
        self.assertRaises(errors.NoWorkingTree, WorkingTree.open, 'repo')
 
 
231
        new_branch = Branch.open('repo')
 
 
232
        self.assertEqual(tree.last_revision(), new_branch.last_revision())
 
 
234
    def test_push_onto_just_bzrdir(self):
 
 
235
        """We don't handle when the target is just a bzrdir.
 
 
237
        Because you shouldn't be able to create *just* a bzrdir in the wild.
 
 
239
        # TODO: jam 20070109 Maybe it would be better to create the repository
 
 
241
        tree = self.create_simple_tree()
 
 
242
        a_bzrdir = self.make_bzrdir('dir')
 
 
244
        self.run_bzr_error(['At ../dir you have a valid .bzr control'],