/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/reconfigure.py

  • Committer: John Arbash Meinel
  • Date: 2009-04-21 23:54:16 UTC
  • mto: (4300.1.7 groupcompress_info)
  • mto: This revision was merged to the branch mainline in revision 4301.
  • Revision ID: john@arbash-meinel.com-20090421235416-f0cz6ilf5cufbugi
Fix bug #364900, properly remove the 64kB that was just encoded in the copy.
Also, stop supporting None as a copy length in 'encode_copy_instruction'.
It was only used by the test suite, and it is good to pull that sort of thing out of
production code. (Besides, setting the copy to 64kB has the same effect.)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2007 Canonical Ltd
 
2
#
 
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.
 
7
#
 
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.
 
12
#
 
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
"""Reconfigure a bzrdir into a new tree/branch/repository layout"""
 
18
 
 
19
from bzrlib import (
 
20
    branch,
 
21
    bzrdir,
 
22
    errors,
 
23
    )
 
24
 
 
25
class Reconfigure(object):
 
26
 
 
27
    def __init__(self, bzrdir, new_bound_location=None):
 
28
        self.bzrdir = bzrdir
 
29
        self.new_bound_location = new_bound_location
 
30
        try:
 
31
            self.repository = self.bzrdir.find_repository()
 
32
        except errors.NoRepositoryPresent:
 
33
            self.repository = None
 
34
        else:
 
35
            if (self.repository.bzrdir.root_transport.base ==
 
36
                self.bzrdir.root_transport.base):
 
37
                self.local_repository = self.repository
 
38
            else:
 
39
                self.local_repository = None
 
40
        try:
 
41
            branch = self.bzrdir.open_branch()
 
42
            if branch.bzrdir.root_transport.base == bzrdir.root_transport.base:
 
43
                self.local_branch = branch
 
44
                self.referenced_branch = None
 
45
            else:
 
46
                self.local_branch = None
 
47
                self.referenced_branch = branch
 
48
        except errors.NotBranchError:
 
49
            self.local_branch = None
 
50
            self.referenced_branch = None
 
51
        try:
 
52
            self.tree = bzrdir.open_workingtree()
 
53
        except errors.NoWorkingTree:
 
54
            self.tree = None
 
55
        self._unbind = False
 
56
        self._bind = False
 
57
        self._destroy_reference = False
 
58
        self._create_reference = False
 
59
        self._destroy_branch = False
 
60
        self._create_branch = False
 
61
        self._destroy_tree = False
 
62
        self._create_tree = False
 
63
        self._create_repository = False
 
64
        self._destroy_repository = False
 
65
        self._repository_trees = None
 
66
 
 
67
    @staticmethod
 
68
    def to_branch(bzrdir):
 
69
        """Return a Reconfiguration to convert this bzrdir into a branch
 
70
 
 
71
        :param bzrdir: The bzrdir to reconfigure
 
72
        :raise errors.AlreadyBranch: if bzrdir is already a branch
 
73
        """
 
74
        reconfiguration = Reconfigure(bzrdir)
 
75
        reconfiguration._plan_changes(want_tree=False, want_branch=True,
 
76
                                      want_bound=False, want_reference=False)
 
77
        if not reconfiguration.changes_planned():
 
78
            raise errors.AlreadyBranch(bzrdir)
 
79
        return reconfiguration
 
80
 
 
81
    @staticmethod
 
82
    def to_tree(bzrdir):
 
83
        """Return a Reconfiguration to convert this bzrdir into a tree
 
84
 
 
85
        :param bzrdir: The bzrdir to reconfigure
 
86
        :raise errors.AlreadyTree: if bzrdir is already a tree
 
87
        """
 
88
        reconfiguration = Reconfigure(bzrdir)
 
89
        reconfiguration._plan_changes(want_tree=True, want_branch=True,
 
90
                                      want_bound=False, want_reference=False)
 
91
        if not reconfiguration.changes_planned():
 
92
            raise errors.AlreadyTree(bzrdir)
 
93
        return reconfiguration
 
94
 
 
95
    @staticmethod
 
96
    def to_checkout(bzrdir, bound_location=None):
 
97
        """Return a Reconfiguration to convert this bzrdir into a checkout
 
98
 
 
99
        :param bzrdir: The bzrdir to reconfigure
 
100
        :param bound_location: The location the checkout should be bound to.
 
101
        :raise errors.AlreadyCheckout: if bzrdir is already a checkout
 
102
        """
 
103
        reconfiguration = Reconfigure(bzrdir, bound_location)
 
104
        reconfiguration._plan_changes(want_tree=True, want_branch=True,
 
105
                                      want_bound=True, want_reference=False)
 
106
        if not reconfiguration.changes_planned():
 
107
            raise errors.AlreadyCheckout(bzrdir)
 
108
        return reconfiguration
 
109
 
 
110
    @classmethod
 
111
    def to_lightweight_checkout(klass, bzrdir, reference_location=None):
 
112
        """Make a Reconfiguration to convert bzrdir into a lightweight checkout
 
113
 
 
114
        :param bzrdir: The bzrdir to reconfigure
 
115
        :param bound_location: The location the checkout should be bound to.
 
116
        :raise errors.AlreadyLightweightCheckout: if bzrdir is already a
 
117
            lightweight checkout
 
118
        """
 
119
        reconfiguration = klass(bzrdir, reference_location)
 
120
        reconfiguration._plan_changes(want_tree=True, want_branch=False,
 
121
                                      want_bound=False, want_reference=True)
 
122
        if not reconfiguration.changes_planned():
 
123
            raise errors.AlreadyLightweightCheckout(bzrdir)
 
124
        return reconfiguration
 
125
 
 
126
    @classmethod
 
127
    def to_use_shared(klass, bzrdir):
 
128
        """Convert a standalone branch into a repository branch"""
 
129
        reconfiguration = klass(bzrdir)
 
130
        reconfiguration._set_use_shared(use_shared=True)
 
131
        if not reconfiguration.changes_planned():
 
132
            raise errors.AlreadyUsingShared(bzrdir)
 
133
        return reconfiguration
 
134
 
 
135
    @classmethod
 
136
    def to_standalone(klass, bzrdir):
 
137
        """Convert a repository branch into a standalone branch"""
 
138
        reconfiguration = klass(bzrdir)
 
139
        reconfiguration._set_use_shared(use_shared=False)
 
140
        if not reconfiguration.changes_planned():
 
141
            raise errors.AlreadyStandalone(bzrdir)
 
142
        return reconfiguration
 
143
 
 
144
    @classmethod
 
145
    def set_repository_trees(klass, bzrdir, with_trees):
 
146
        """Adjust a repository's working tree presence default"""
 
147
        reconfiguration = klass(bzrdir)
 
148
        if not reconfiguration.repository.is_shared():
 
149
            raise errors.ReconfigurationNotSupported(reconfiguration.bzrdir)
 
150
        if with_trees and reconfiguration.repository.make_working_trees():
 
151
            raise errors.AlreadyWithTrees(bzrdir)
 
152
        elif (not with_trees
 
153
              and not reconfiguration.repository.make_working_trees()):
 
154
            raise errors.AlreadyWithNoTrees(bzrdir)
 
155
        else:
 
156
            reconfiguration._repository_trees = with_trees
 
157
        return reconfiguration
 
158
 
 
159
    def _plan_changes(self, want_tree, want_branch, want_bound,
 
160
                      want_reference):
 
161
        """Determine which changes are needed to assume the configuration"""
 
162
        if not want_branch and not want_reference:
 
163
            raise errors.ReconfigurationNotSupported(self.bzrdir)
 
164
        if want_branch and want_reference:
 
165
            raise errors.ReconfigurationNotSupported(self.bzrdir)
 
166
        if self.repository is None:
 
167
            if not want_reference:
 
168
                self._create_repository = True
 
169
        else:
 
170
            if want_reference and (self.repository.bzrdir.root_transport.base
 
171
                                   == self.bzrdir.root_transport.base):
 
172
                if not self.repository.is_shared():
 
173
                    self._destroy_repository = True
 
174
        if self.referenced_branch is None:
 
175
            if want_reference:
 
176
                self._create_reference = True
 
177
                if self.local_branch is not None:
 
178
                    self._destroy_branch = True
 
179
        else:
 
180
            if not want_reference:
 
181
                self._destroy_reference = True
 
182
        if self.local_branch is None:
 
183
            if want_branch is True:
 
184
                self._create_branch = True
 
185
                if want_bound:
 
186
                    self._bind = True
 
187
        else:
 
188
            if want_bound:
 
189
                if self.local_branch.get_bound_location() is None:
 
190
                    self._bind = True
 
191
            else:
 
192
                if self.local_branch.get_bound_location() is not None:
 
193
                    self._unbind = True
 
194
        if not want_tree and self.tree is not None:
 
195
            self._destroy_tree = True
 
196
        if want_tree and self.tree is None:
 
197
            self._create_tree = True
 
198
 
 
199
    def _set_use_shared(self, use_shared=None):
 
200
        if use_shared is None:
 
201
            return
 
202
        if use_shared:
 
203
            if self.local_repository is not None:
 
204
                self._destroy_repository = True
 
205
        else:
 
206
            if self.local_repository is None:
 
207
                self._create_repository = True
 
208
 
 
209
    def changes_planned(self):
 
210
        """Return True if changes are planned, False otherwise"""
 
211
        return (self._unbind or self._bind or self._destroy_tree
 
212
                or self._create_tree or self._destroy_reference
 
213
                or self._create_branch or self._create_repository
 
214
                or self._create_reference or self._destroy_repository)
 
215
 
 
216
    def _check(self):
 
217
        """Raise if reconfiguration would destroy local changes"""
 
218
        if self._destroy_tree:
 
219
            changes = self.tree.changes_from(self.tree.basis_tree())
 
220
            if changes.has_changed():
 
221
                raise errors.UncommittedChanges(self.tree)
 
222
        if self._create_reference and self.local_branch is not None:
 
223
            reference_branch = branch.Branch.open(self._select_bind_location())
 
224
            if (reference_branch.last_revision() !=
 
225
                self.local_branch.last_revision()):
 
226
                raise errors.UnsyncedBranches(self.bzrdir, reference_branch)
 
227
 
 
228
    def _select_bind_location(self):
 
229
        """Select a location to bind or create a reference to.
 
230
 
 
231
        Preference is:
 
232
        1. user specified location
 
233
        2. branch reference location (it's a kind of bind location)
 
234
        3. current bind location
 
235
        4. previous bind location (it was a good choice once)
 
236
        5. push location (it's writeable, so committable)
 
237
        6. parent location (it's pullable, so update-from-able)
 
238
        """
 
239
        if self.new_bound_location is not None:
 
240
            return self.new_bound_location
 
241
        if self.local_branch is not None:
 
242
            bound = self.local_branch.get_bound_location()
 
243
            if bound is not None:
 
244
                return bound
 
245
            old_bound = self.local_branch.get_old_bound_location()
 
246
            if old_bound is not None:
 
247
                return old_bound
 
248
            push_location = self.local_branch.get_push_location()
 
249
            if push_location is not None:
 
250
                return push_location
 
251
            parent = self.local_branch.get_parent()
 
252
            if parent is not None:
 
253
                return parent
 
254
        elif self.referenced_branch is not None:
 
255
            return self.referenced_branch.base
 
256
        raise errors.NoBindLocation(self.bzrdir)
 
257
 
 
258
    def apply(self, force=False):
 
259
        """Apply the reconfiguration
 
260
 
 
261
        :param force: If true, the reconfiguration is applied even if it will
 
262
            destroy local changes.
 
263
        :raise errors.UncommittedChanges: if the local tree is to be destroyed
 
264
            but contains uncommitted changes.
 
265
        :raise errors.NoBindLocation: if no bind location was specified and
 
266
            none could be autodetected.
 
267
        """
 
268
        if not force:
 
269
            self._check()
 
270
        if self._create_repository:
 
271
            repo = self.bzrdir.create_repository()
 
272
            if self.local_branch and not self._destroy_branch:
 
273
                repo.fetch(self.local_branch.repository,
 
274
                           self.local_branch.last_revision())
 
275
        else:
 
276
            repo = self.repository
 
277
        if self._create_branch and self.referenced_branch is not None:
 
278
            repo.fetch(self.referenced_branch.repository,
 
279
                       self.referenced_branch.last_revision())
 
280
        if self._create_reference:
 
281
            reference_branch = branch.Branch.open(self._select_bind_location())
 
282
        if self._destroy_repository:
 
283
            if self._create_reference:
 
284
                reference_branch.repository.fetch(self.repository)
 
285
            elif self.local_branch is not None and not self._destroy_branch:
 
286
                up = self.local_branch.bzrdir.root_transport.clone('..')
 
287
                up_bzrdir = bzrdir.BzrDir.open_containing_from_transport(up)[0]
 
288
                new_repo = up_bzrdir.find_repository()
 
289
                new_repo.fetch(self.repository)
 
290
        last_revision_info = None
 
291
        if self._destroy_reference:
 
292
            last_revision_info = self.referenced_branch.last_revision_info()
 
293
            self.bzrdir.destroy_branch()
 
294
        if self._destroy_branch:
 
295
            last_revision_info = self.local_branch.last_revision_info()
 
296
            if self._create_reference:
 
297
                self.local_branch.tags.merge_to(reference_branch.tags)
 
298
            self.bzrdir.destroy_branch()
 
299
        if self._create_branch:
 
300
            local_branch = self.bzrdir.create_branch()
 
301
            if last_revision_info is not None:
 
302
                local_branch.set_last_revision_info(*last_revision_info)
 
303
            if self._destroy_reference:
 
304
                self.referenced_branch.tags.merge_to(local_branch.tags)
 
305
        else:
 
306
            local_branch = self.local_branch
 
307
        if self._create_reference:
 
308
            format = branch.BranchReferenceFormat().initialize(self.bzrdir,
 
309
                reference_branch)
 
310
        if self._destroy_tree:
 
311
            self.bzrdir.destroy_workingtree()
 
312
        if self._create_tree:
 
313
            self.bzrdir.create_workingtree()
 
314
        if self._unbind:
 
315
            self.local_branch.unbind()
 
316
        if self._bind:
 
317
            bind_location = self._select_bind_location()
 
318
            local_branch.bind(branch.Branch.open(bind_location))
 
319
        if self._destroy_repository:
 
320
            self.bzrdir.destroy_repository()
 
321
        if self._repository_trees is not None:
 
322
            repo.set_make_working_trees(self._repository_trees)