/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
1553.5.48 by Martin Pool
Fix some LockableFiles deprecation warnings
1
# Copyright (C) 2005, 2006 Canonical Ltd
1534.4.39 by Robert Collins
Basic BzrDir support.
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
"""BzrDir logic. The BzrDir is the basic control directory used by bzr.
18
19
At format 7 this was split out into Branch, Repository and Checkout control
20
directories.
21
"""
22
23
from copy import deepcopy
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
24
import os
1534.4.39 by Robert Collins
Basic BzrDir support.
25
from cStringIO import StringIO
26
from unittest import TestSuite
27
28
import bzrlib
29
import bzrlib.errors as errors
1553.5.48 by Martin Pool
Fix some LockableFiles deprecation warnings
30
from bzrlib.lockable_files import LockableFiles, TransportLock
1553.5.69 by Martin Pool
BzrDirFormat subclasses can now control what kind of overall lock is used.
31
from bzrlib.lockdir import LockDir
1534.4.39 by Robert Collins
Basic BzrDir support.
32
from bzrlib.osutils import safe_unicode
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
33
from bzrlib.osutils import (
34
                            abspath,
35
                            pathjoin,
36
                            safe_unicode,
37
                            sha_strings,
38
                            sha_string,
39
                            )
1563.2.28 by Robert Collins
Add total_size to the revision_store api.
40
from bzrlib.store.revision.text import TextRevisionStore
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
41
from bzrlib.store.text import TextStore
1563.2.25 by Robert Collins
Merge in upstream.
42
from bzrlib.store.versioned import WeaveStore
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
43
from bzrlib.symbol_versioning import *
1534.4.39 by Robert Collins
Basic BzrDir support.
44
from bzrlib.trace import mutter
1563.2.34 by Robert Collins
Remove the commit and rollback transaction methods as misleading, and implement a WriteTransaction
45
from bzrlib.transactions import WriteTransaction
1608.1.1 by Martin Pool
[patch] LocalTransport.list_dir should return url-quoted strings (ddaa)
46
from bzrlib.transport import get_transport, urlunescape
1534.4.42 by Robert Collins
add working tree to the BzrDir facilities.
47
from bzrlib.transport.local import LocalTransport
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
48
from bzrlib.weave import Weave
49
from bzrlib.xml4 import serializer_v4
50
from bzrlib.xml5 import serializer_v5
1534.4.39 by Robert Collins
Basic BzrDir support.
51
52
53
class BzrDir(object):
54
    """A .bzr control diretory.
55
    
56
    BzrDir instances let you create or open any of the things that can be
57
    found within .bzr - checkouts, branches and repositories.
58
    
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
59
    transport
60
        the transport which this bzr dir is rooted at (i.e. file:///.../.bzr/)
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
61
    root_transport
62
        a transport connected to the directory this bzr was opened from.
1534.4.39 by Robert Collins
Basic BzrDir support.
63
    """
64
1687.1.12 by Robert Collins
Hook in the full break-lock ui.
65
    def break_lock(self):
66
        """Invoke break_lock on the first object in the bzrdir.
67
68
        If there is a tree, the tree is opened and break_lock() called.
69
        Otherwise, branch is tried, and finally repository.
70
        """
71
        try:
72
            thing_to_unlock = self.open_workingtree()
73
        except (errors.NotLocalUrl, errors.NoWorkingTree):
74
            try:
75
                thing_to_unlock = self.open_branch()
76
            except errors.NotBranchError:
77
                try:
78
                    thing_to_unlock = self.open_repository()
79
                except errors.NoRepositoryPresent:
80
                    return
81
        thing_to_unlock.break_lock()
82
1534.5.16 by Robert Collins
Review feedback.
83
    def can_convert_format(self):
84
        """Return true if this bzrdir is one whose format we can convert from."""
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
85
        return True
86
1596.2.1 by Robert Collins
Fix BzrDir.open_containing of unsupported branches.
87
    @staticmethod
88
    def _check_supported(format, allow_unsupported):
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
89
        """Check whether format is a supported format.
90
91
        If allow_unsupported is True, this is a no-op.
92
        """
93
        if not allow_unsupported and not format.is_supported():
1596.2.1 by Robert Collins
Fix BzrDir.open_containing of unsupported branches.
94
            # see open_downlevel to open legacy branches.
95
            raise errors.UnsupportedFormatError(
96
                    'sorry, format %s not supported' % format,
97
                    ['use a different bzr version',
98
                     'or remove the .bzr directory'
99
                     ' and "bzr init" again'])
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
100
1534.6.6 by Robert Collins
Move find_repository to bzrdir, its not quite ideal there but its simpler and until someone chooses to vary the search by branch type its completely sufficient.
101
    def clone(self, url, revision_id=None, basis=None, force_new_repo=False):
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
102
        """Clone this bzrdir and its contents to url verbatim.
103
104
        If urls last component does not exist, it will be created.
105
106
        if revision_id is not None, then the clone operation may tune
107
            itself to download less data.
1534.6.6 by Robert Collins
Move find_repository to bzrdir, its not quite ideal there but its simpler and until someone chooses to vary the search by branch type its completely sufficient.
108
        :param force_new_repo: Do not use a shared repository for the target 
109
                               even if one is available.
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
110
        """
111
        self._make_tail(url)
1534.6.6 by Robert Collins
Move find_repository to bzrdir, its not quite ideal there but its simpler and until someone chooses to vary the search by branch type its completely sufficient.
112
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
113
        result = self._format.initialize(url)
114
        try:
1534.6.6 by Robert Collins
Move find_repository to bzrdir, its not quite ideal there but its simpler and until someone chooses to vary the search by branch type its completely sufficient.
115
            local_repo = self.find_repository()
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
116
        except errors.NoRepositoryPresent:
1534.6.6 by Robert Collins
Move find_repository to bzrdir, its not quite ideal there but its simpler and until someone chooses to vary the search by branch type its completely sufficient.
117
            local_repo = None
118
        if local_repo:
119
            # may need to copy content in
120
            if force_new_repo:
121
                local_repo.clone(result, revision_id=revision_id, basis=basis_repo)
122
            else:
123
                try:
124
                    result_repo = result.find_repository()
125
                    # fetch content this dir needs.
126
                    if basis_repo:
127
                        # XXX FIXME RBC 20060214 need tests for this when the basis
128
                        # is incomplete
129
                        result_repo.fetch(basis_repo, revision_id=revision_id)
130
                    result_repo.fetch(local_repo, revision_id=revision_id)
131
                except errors.NoRepositoryPresent:
132
                    # needed to make one anyway.
133
                    local_repo.clone(result, revision_id=revision_id, basis=basis_repo)
134
        # 1 if there is a branch present
135
        #   make sure its content is available in the target repository
136
        #   clone it.
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
137
        try:
138
            self.open_branch().clone(result, revision_id=revision_id)
139
        except errors.NotBranchError:
140
            pass
141
        try:
142
            self.open_workingtree().clone(result, basis=basis_tree)
1508.1.19 by Robert Collins
Give format3 working trees their own last-revision marker.
143
        except (errors.NoWorkingTree, errors.NotLocalUrl):
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
144
            pass
145
        return result
146
147
    def _get_basis_components(self, basis):
148
        """Retrieve the basis components that are available at basis."""
149
        if basis is None:
150
            return None, None, None
151
        try:
152
            basis_tree = basis.open_workingtree()
153
            basis_branch = basis_tree.branch
154
            basis_repo = basis_branch.repository
155
        except (errors.NoWorkingTree, errors.NotLocalUrl):
156
            basis_tree = None
157
            try:
158
                basis_branch = basis.open_branch()
159
                basis_repo = basis_branch.repository
160
            except errors.NotBranchError:
161
                basis_branch = None
162
                try:
163
                    basis_repo = basis.open_repository()
164
                except errors.NoRepositoryPresent:
165
                    basis_repo = None
166
        return basis_repo, basis_branch, basis_tree
167
168
    def _make_tail(self, url):
169
        segments = url.split('/')
170
        if segments and segments[-1] not in ('', '.'):
171
            parent = '/'.join(segments[:-1])
172
            t = bzrlib.transport.get_transport(parent)
173
            try:
174
                t.mkdir(segments[-1])
175
            except errors.FileExists:
176
                pass
177
1553.5.71 by Martin Pool
Change branch format 5 to use LockDirs, not transport locks
178
    @classmethod
179
    def create(cls, base):
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
180
        """Create a new BzrDir at the url 'base'.
1534.4.39 by Robert Collins
Basic BzrDir support.
181
        
182
        This will call the current default formats initialize with base
183
        as the only parameter.
184
185
        If you need a specific format, consider creating an instance
186
        of that and calling initialize().
187
        """
1553.5.71 by Martin Pool
Change branch format 5 to use LockDirs, not transport locks
188
        if cls is not BzrDir:
189
            raise AssertionError("BzrDir.create always creates the default format, "
190
                    "not one of %r" % cls)
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
191
        segments = base.split('/')
192
        if segments and segments[-1] not in ('', '.'):
193
            parent = '/'.join(segments[:-1])
194
            t = bzrlib.transport.get_transport(parent)
195
            try:
196
                t.mkdir(segments[-1])
197
            except errors.FileExists:
198
                pass
1534.4.39 by Robert Collins
Basic BzrDir support.
199
        return BzrDirFormat.get_default_format().initialize(safe_unicode(base))
200
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
201
    def create_branch(self):
202
        """Create a branch in this BzrDir.
203
204
        The bzrdirs format will control what branch format is created.
205
        For more control see BranchFormatXX.create(a_bzrdir).
206
        """
207
        raise NotImplementedError(self.create_branch)
208
209
    @staticmethod
1534.6.6 by Robert Collins
Move find_repository to bzrdir, its not quite ideal there but its simpler and until someone chooses to vary the search by branch type its completely sufficient.
210
    def create_branch_and_repo(base, force_new_repo=False):
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
211
        """Create a new BzrDir, Branch and Repository at the url 'base'.
212
213
        This will use the current default BzrDirFormat, and use whatever 
214
        repository format that that uses via bzrdir.create_branch and
1534.6.6 by Robert Collins
Move find_repository to bzrdir, its not quite ideal there but its simpler and until someone chooses to vary the search by branch type its completely sufficient.
215
        create_repository. If a shared repository is available that is used
216
        preferentially.
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
217
218
        The created Branch object is returned.
1534.6.6 by Robert Collins
Move find_repository to bzrdir, its not quite ideal there but its simpler and until someone chooses to vary the search by branch type its completely sufficient.
219
220
        :param base: The URL to create the branch at.
221
        :param force_new_repo: If True a new repository is always created.
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
222
        """
223
        bzrdir = BzrDir.create(base)
1534.6.11 by Robert Collins
Review feedback.
224
        bzrdir._find_or_create_repository(force_new_repo)
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
225
        return bzrdir.create_branch()
1534.6.11 by Robert Collins
Review feedback.
226
227
    def _find_or_create_repository(self, force_new_repo):
228
        """Create a new repository if needed, returning the repository."""
229
        if force_new_repo:
230
            return self.create_repository()
231
        try:
232
            return self.find_repository()
233
        except errors.NoRepositoryPresent:
234
            return self.create_repository()
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
235
        
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
236
    @staticmethod
1558.5.3 by Aaron Bentley
Init command can produce sharing branches
237
    def create_branch_convenience(base, force_new_repo=False,
238
                                  force_new_tree=None, format=None):
1534.6.10 by Robert Collins
Finish use of repositories support.
239
        """Create a new BzrDir, Branch and Repository at the url 'base'.
240
241
        This is a convenience function - it will use an existing repository
242
        if possible, can be told explicitly whether to create a working tree or
1534.6.12 by Robert Collins
Typo found by John Meinel.
243
        not.
1534.6.10 by Robert Collins
Finish use of repositories support.
244
245
        This will use the current default BzrDirFormat, and use whatever 
246
        repository format that that uses via bzrdir.create_branch and
247
        create_repository. If a shared repository is available that is used
248
        preferentially. Whatever repository is used, its tree creation policy
249
        is followed.
250
251
        The created Branch object is returned.
252
        If a working tree cannot be made due to base not being a file:// url,
1563.1.6 by Robert Collins
Add tests for sftp push, and NonLocalTets for BzrDir.create_branch_convenience, before fixing the failure of it to work on non-local urls.
253
        no error is raised unless force_new_tree is True, in which case no 
254
        data is created on disk and NotLocalUrl is raised.
1534.6.10 by Robert Collins
Finish use of repositories support.
255
256
        :param base: The URL to create the branch at.
257
        :param force_new_repo: If True a new repository is always created.
258
        :param force_new_tree: If True or False force creation of a tree or 
259
                               prevent such creation respectively.
1558.5.3 by Aaron Bentley
Init command can produce sharing branches
260
        :param format: Override for the for the bzrdir format to create
1534.6.10 by Robert Collins
Finish use of repositories support.
261
        """
1563.1.6 by Robert Collins
Add tests for sftp push, and NonLocalTets for BzrDir.create_branch_convenience, before fixing the failure of it to work on non-local urls.
262
        if force_new_tree:
263
            # check for non local urls
264
            t = get_transport(safe_unicode(base))
265
            if not isinstance(t, LocalTransport):
266
                raise errors.NotLocalUrl(base)
1558.5.3 by Aaron Bentley
Init command can produce sharing branches
267
        if format is None:
268
            bzrdir = BzrDir.create(base)
269
        else:
270
            bzrdir = format.initialize(base)
1534.6.11 by Robert Collins
Review feedback.
271
        repo = bzrdir._find_or_create_repository(force_new_repo)
1534.6.10 by Robert Collins
Finish use of repositories support.
272
        result = bzrdir.create_branch()
273
        if force_new_tree or (repo.make_working_trees() and 
274
                              force_new_tree is None):
1563.1.6 by Robert Collins
Add tests for sftp push, and NonLocalTets for BzrDir.create_branch_convenience, before fixing the failure of it to work on non-local urls.
275
            try:
276
                bzrdir.create_workingtree()
277
            except errors.NotLocalUrl:
278
                pass
1534.6.10 by Robert Collins
Finish use of repositories support.
279
        return result
280
        
281
    @staticmethod
1534.6.1 by Robert Collins
allow API creation of shared repositories
282
    def create_repository(base, shared=False):
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
283
        """Create a new BzrDir and Repository at the url 'base'.
284
285
        This will use the current default BzrDirFormat, and use whatever 
286
        repository format that that uses for bzrdirformat.create_repository.
287
1534.6.1 by Robert Collins
allow API creation of shared repositories
288
        ;param shared: Create a shared repository rather than a standalone
289
                       repository.
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
290
        The Repository object is returned.
291
292
        This must be overridden as an instance method in child classes, where
293
        it should take no parameters and construct whatever repository format
294
        that child class desires.
295
        """
296
        bzrdir = BzrDir.create(base)
297
        return bzrdir.create_repository()
298
1534.4.42 by Robert Collins
add working tree to the BzrDir facilities.
299
    @staticmethod
300
    def create_standalone_workingtree(base):
301
        """Create a new BzrDir, WorkingTree, Branch and Repository at 'base'.
302
303
        'base' must be a local path or a file:// url.
304
305
        This will use the current default BzrDirFormat, and use whatever 
306
        repository format that that uses for bzrdirformat.create_workingtree,
307
        create_branch and create_repository.
308
309
        The WorkingTree object is returned.
310
        """
1534.4.46 by Robert Collins
Nearly complete .bzr/checkout splitout.
311
        t = get_transport(safe_unicode(base))
1534.4.42 by Robert Collins
add working tree to the BzrDir facilities.
312
        if not isinstance(t, LocalTransport):
313
            raise errors.NotLocalUrl(base)
1534.6.10 by Robert Collins
Finish use of repositories support.
314
        bzrdir = BzrDir.create_branch_and_repo(safe_unicode(base),
315
                                               force_new_repo=True).bzrdir
1534.4.42 by Robert Collins
add working tree to the BzrDir facilities.
316
        return bzrdir.create_workingtree()
317
1508.1.21 by Robert Collins
Implement -r limit for checkout command.
318
    def create_workingtree(self, revision_id=None):
319
        """Create a working tree at this BzrDir.
320
        
321
        revision_id: create it as of this revision id.
322
        """
1534.4.42 by Robert Collins
add working tree to the BzrDir facilities.
323
        raise NotImplementedError(self.create_workingtree)
324
1534.6.6 by Robert Collins
Move find_repository to bzrdir, its not quite ideal there but its simpler and until someone chooses to vary the search by branch type its completely sufficient.
325
    def find_repository(self):
326
        """Find the repository that should be used for a_bzrdir.
327
328
        This does not require a branch as we use it to find the repo for
329
        new branches as well as to hook existing branches up to their
330
        repository.
331
        """
332
        try:
333
            return self.open_repository()
334
        except errors.NoRepositoryPresent:
335
            pass
336
        next_transport = self.root_transport.clone('..')
337
        while True:
338
            try:
1534.6.11 by Robert Collins
Review feedback.
339
                found_bzrdir = BzrDir.open_containing_from_transport(
1534.6.6 by Robert Collins
Move find_repository to bzrdir, its not quite ideal there but its simpler and until someone chooses to vary the search by branch type its completely sufficient.
340
                    next_transport)[0]
341
            except errors.NotBranchError:
342
                raise errors.NoRepositoryPresent(self)
343
            try:
344
                repository = found_bzrdir.open_repository()
345
            except errors.NoRepositoryPresent:
346
                next_transport = found_bzrdir.root_transport.clone('..')
347
                continue
348
            if ((found_bzrdir.root_transport.base == 
349
                 self.root_transport.base) or repository.is_shared()):
350
                return repository
351
            else:
352
                raise errors.NoRepositoryPresent(self)
353
        raise errors.NoRepositoryPresent(self)
354
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
355
    def get_branch_transport(self, branch_format):
356
        """Get the transport for use by branch format in this BzrDir.
357
358
        Note that bzr dirs that do not support format strings will raise
359
        IncompatibleFormat if the branch format they are given has
360
        a format string, and vice verca.
361
362
        If branch_format is None, the transport is returned with no 
363
        checking. if it is not None, then the returned transport is
364
        guaranteed to point to an existing directory ready for use.
365
        """
366
        raise NotImplementedError(self.get_branch_transport)
367
        
1534.4.47 by Robert Collins
Split out repository into .bzr/repository
368
    def get_repository_transport(self, repository_format):
369
        """Get the transport for use by repository format in this BzrDir.
370
371
        Note that bzr dirs that do not support format strings will raise
372
        IncompatibleFormat if the repository format they are given has
373
        a format string, and vice verca.
374
375
        If repository_format is None, the transport is returned with no 
376
        checking. if it is not None, then the returned transport is
377
        guaranteed to point to an existing directory ready for use.
378
        """
379
        raise NotImplementedError(self.get_repository_transport)
380
        
1534.4.53 by Robert Collins
Review feedback from John Meinel.
381
    def get_workingtree_transport(self, tree_format):
1534.4.45 by Robert Collins
Start WorkingTree -> .bzr/checkout transition
382
        """Get the transport for use by workingtree format in this BzrDir.
383
384
        Note that bzr dirs that do not support format strings will raise
385
        IncompatibleFormat if the workingtree format they are given has
386
        a format string, and vice verca.
387
388
        If workingtree_format is None, the transport is returned with no 
389
        checking. if it is not None, then the returned transport is
390
        guaranteed to point to an existing directory ready for use.
391
        """
392
        raise NotImplementedError(self.get_workingtree_transport)
393
        
1534.4.39 by Robert Collins
Basic BzrDir support.
394
    def __init__(self, _transport, _format):
395
        """Initialize a Bzr control dir object.
396
        
397
        Only really common logic should reside here, concrete classes should be
398
        made with varying behaviours.
399
1534.4.53 by Robert Collins
Review feedback from John Meinel.
400
        :param _format: the format that is creating this BzrDir instance.
401
        :param _transport: the transport this dir is based at.
1534.4.39 by Robert Collins
Basic BzrDir support.
402
        """
403
        self._format = _format
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
404
        self.transport = _transport.clone('.bzr')
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
405
        self.root_transport = _transport
1534.4.39 by Robert Collins
Basic BzrDir support.
406
1534.5.16 by Robert Collins
Review feedback.
407
    def needs_format_conversion(self, format=None):
408
        """Return true if this bzrdir needs convert_format run on it.
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
409
        
410
        For instance, if the repository format is out of date but the 
411
        branch and working tree are not, this should return True.
1534.5.13 by Robert Collins
Correct buggy test.
412
413
        :param format: Optional parameter indicating a specific desired
1534.5.16 by Robert Collins
Review feedback.
414
                       format we plan to arrive at.
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
415
        """
1556.1.4 by Robert Collins
Add a new format for what will become knit, and the surrounding logic to upgrade repositories within metadirs, and tests for the same.
416
        raise NotImplementedError(self.needs_format_conversion)
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
417
1534.4.39 by Robert Collins
Basic BzrDir support.
418
    @staticmethod
419
    def open_unsupported(base):
420
        """Open a branch which is not supported."""
421
        return BzrDir.open(base, _unsupported=True)
422
        
423
    @staticmethod
424
    def open(base, _unsupported=False):
1534.4.53 by Robert Collins
Review feedback from John Meinel.
425
        """Open an existing bzrdir, rooted at 'base' (url)
1534.4.39 by Robert Collins
Basic BzrDir support.
426
        
427
        _unsupported is a private parameter to the BzrDir class.
428
        """
429
        t = get_transport(base)
430
        mutter("trying to open %r with transport %r", base, t)
431
        format = BzrDirFormat.find_format(t)
1596.2.1 by Robert Collins
Fix BzrDir.open_containing of unsupported branches.
432
        BzrDir._check_supported(format, _unsupported)
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
433
        return format.open(t, _found=True)
434
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
435
    def open_branch(self, unsupported=False):
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
436
        """Open the branch object at this BzrDir if one is present.
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
437
438
        If unsupported is True, then no longer supported branch formats can
439
        still be opened.
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
440
        
441
        TODO: static convenience version of this?
442
        """
443
        raise NotImplementedError(self.open_branch)
1534.4.39 by Robert Collins
Basic BzrDir support.
444
445
    @staticmethod
446
    def open_containing(url):
447
        """Open an existing branch which contains url.
448
        
1534.6.3 by Robert Collins
find_repository sufficiently robust.
449
        :param url: url to search from.
1534.6.11 by Robert Collins
Review feedback.
450
        See open_containing_from_transport for more detail.
1534.6.3 by Robert Collins
find_repository sufficiently robust.
451
        """
1534.6.11 by Robert Collins
Review feedback.
452
        return BzrDir.open_containing_from_transport(get_transport(url))
1534.6.3 by Robert Collins
find_repository sufficiently robust.
453
    
454
    @staticmethod
1534.6.11 by Robert Collins
Review feedback.
455
    def open_containing_from_transport(a_transport):
1534.6.3 by Robert Collins
find_repository sufficiently robust.
456
        """Open an existing branch which contains a_transport.base
457
458
        This probes for a branch at a_transport, and searches upwards from there.
1534.4.39 by Robert Collins
Basic BzrDir support.
459
460
        Basically we keep looking up until we find the control directory or
461
        run into the root.  If there isn't one, raises NotBranchError.
462
        If there is one and it is either an unrecognised format or an unsupported 
463
        format, UnknownFormatError or UnsupportedFormatError are raised.
464
        If there is one, it is returned, along with the unused portion of url.
465
        """
466
        # this gets the normalised url back. I.e. '.' -> the full path.
1534.6.3 by Robert Collins
find_repository sufficiently robust.
467
        url = a_transport.base
1534.4.39 by Robert Collins
Basic BzrDir support.
468
        while True:
469
            try:
1534.6.3 by Robert Collins
find_repository sufficiently robust.
470
                format = BzrDirFormat.find_format(a_transport)
1596.2.1 by Robert Collins
Fix BzrDir.open_containing of unsupported branches.
471
                BzrDir._check_supported(format, False)
1534.6.3 by Robert Collins
find_repository sufficiently robust.
472
                return format.open(a_transport), a_transport.relpath(url)
1534.4.39 by Robert Collins
Basic BzrDir support.
473
            except errors.NotBranchError, e:
1534.6.3 by Robert Collins
find_repository sufficiently robust.
474
                mutter('not a branch in: %r %s', a_transport.base, e)
475
            new_t = a_transport.clone('..')
476
            if new_t.base == a_transport.base:
1534.4.39 by Robert Collins
Basic BzrDir support.
477
                # reached the root, whatever that may be
478
                raise errors.NotBranchError(path=url)
1534.6.3 by Robert Collins
find_repository sufficiently robust.
479
            a_transport = new_t
1534.4.39 by Robert Collins
Basic BzrDir support.
480
1534.4.47 by Robert Collins
Split out repository into .bzr/repository
481
    def open_repository(self, _unsupported=False):
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
482
        """Open the repository object at this BzrDir if one is present.
1534.4.47 by Robert Collins
Split out repository into .bzr/repository
483
484
        This will not follow the Branch object pointer - its strictly a direct
485
        open facility. Most client code should use open_branch().repository to
486
        get at a repository.
487
488
        _unsupported is a private parameter, not part of the api.
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
489
        TODO: static convenience version of this?
490
        """
491
        raise NotImplementedError(self.open_repository)
492
1534.4.46 by Robert Collins
Nearly complete .bzr/checkout splitout.
493
    def open_workingtree(self, _unsupported=False):
1534.4.42 by Robert Collins
add working tree to the BzrDir facilities.
494
        """Open the workingtree object at this BzrDir if one is present.
495
        
496
        TODO: static convenience version of this?
497
        """
498
        raise NotImplementedError(self.open_workingtree)
499
1662.1.19 by Martin Pool
Better error message when initting existing tree
500
    def has_branch(self):
501
        """Tell if this bzrdir contains a branch.
502
        
503
        Note: if you're going to open the branch, you should just go ahead
504
        and try, and not ask permission first.  (This method just opens the 
505
        branch and discards it, and that's somewhat expensive.) 
506
        """
507
        try:
508
            self.open_branch()
509
            return True
510
        except errors.NotBranchError:
511
            return False
512
513
    def has_workingtree(self):
514
        """Tell if this bzrdir contains a working tree.
515
516
        This will still raise an exception if the bzrdir has a workingtree that
517
        is remote & inaccessible.
518
        
519
        Note: if you're going to open the working tree, you should just go ahead
520
        and try, and not ask permission first.  (This method just opens the 
521
        workingtree and discards it, and that's somewhat expensive.) 
522
        """
523
        try:
524
            self.open_workingtree()
525
            return True
526
        except errors.NoWorkingTree:
527
            return False
528
1534.6.9 by Robert Collins
sprouting into shared repositories
529
    def sprout(self, url, revision_id=None, basis=None, force_new_repo=False):
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
530
        """Create a copy of this bzrdir prepared for use as a new line of
531
        development.
532
533
        If urls last component does not exist, it will be created.
534
535
        Attributes related to the identity of the source branch like
536
        branch nickname will be cleaned, a working tree is created
537
        whether one existed before or not; and a local branch is always
538
        created.
539
540
        if revision_id is not None, then the clone operation may tune
541
            itself to download less data.
542
        """
543
        self._make_tail(url)
544
        result = self._format.initialize(url)
545
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
546
        try:
547
            source_branch = self.open_branch()
548
            source_repository = source_branch.repository
549
        except errors.NotBranchError:
550
            source_branch = None
551
            try:
552
                source_repository = self.open_repository()
553
            except errors.NoRepositoryPresent:
1534.6.9 by Robert Collins
sprouting into shared repositories
554
                # copy the entire basis one if there is one
555
                # but there is no repository.
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
556
                source_repository = basis_repo
1534.6.9 by Robert Collins
sprouting into shared repositories
557
        if force_new_repo:
558
            result_repo = None
559
        else:
560
            try:
561
                result_repo = result.find_repository()
562
            except errors.NoRepositoryPresent:
563
                result_repo = None
564
        if source_repository is None and result_repo is not None:
565
            pass
566
        elif source_repository is None and result_repo is None:
567
            # no repo available, make a new one
568
            result.create_repository()
569
        elif source_repository is not None and result_repo is None:
570
            # have soure, and want to make a new target repo
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
571
            source_repository.clone(result,
572
                                    revision_id=revision_id,
573
                                    basis=basis_repo)
574
        else:
1534.6.9 by Robert Collins
sprouting into shared repositories
575
            # fetch needed content into target.
576
            if basis_repo:
577
                # XXX FIXME RBC 20060214 need tests for this when the basis
578
                # is incomplete
579
                result_repo.fetch(basis_repo, revision_id=revision_id)
580
            result_repo.fetch(source_repository, revision_id=revision_id)
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
581
        if source_branch is not None:
582
            source_branch.sprout(result, revision_id=revision_id)
583
        else:
584
            result.create_branch()
1558.5.8 by Aaron Bentley
Bugfix when result_repo is None
585
        if result_repo is None or result_repo.make_working_trees():
1558.5.7 by Aaron Bentley
Don't create unwanted working trees in branch
586
            result.create_workingtree()
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
587
        return result
588
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
589
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
590
class BzrDirPreSplitOut(BzrDir):
591
    """A common class for the all-in-one formats."""
592
1534.5.3 by Robert Collins
Make format 4/5/6 branches share a single LockableFiles instance across wt/branch/repository.
593
    def __init__(self, _transport, _format):
594
        """See BzrDir.__init__."""
595
        super(BzrDirPreSplitOut, self).__init__(_transport, _format)
1553.5.69 by Martin Pool
BzrDirFormat subclasses can now control what kind of overall lock is used.
596
        assert self._format._lock_class == TransportLock
597
        assert self._format._lock_file_name == 'branch-lock'
1534.5.3 by Robert Collins
Make format 4/5/6 branches share a single LockableFiles instance across wt/branch/repository.
598
        self._control_files = LockableFiles(self.get_branch_transport(None),
1553.5.69 by Martin Pool
BzrDirFormat subclasses can now control what kind of overall lock is used.
599
                                            self._format._lock_file_name,
600
                                            self._format._lock_class)
1534.5.3 by Robert Collins
Make format 4/5/6 branches share a single LockableFiles instance across wt/branch/repository.
601
1687.1.12 by Robert Collins
Hook in the full break-lock ui.
602
    def break_lock(self):
603
        """Pre-splitout bzrdirs do not suffer from stale locks."""
604
        raise NotImplementedError(self.break_lock)
605
1534.6.8 by Robert Collins
Test the use of clone on empty bzrdir with force_new_repo.
606
    def clone(self, url, revision_id=None, basis=None, force_new_repo=False):
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
607
        """See BzrDir.clone()."""
608
        from bzrlib.workingtree import WorkingTreeFormat2
609
        self._make_tail(url)
1651.1.6 by Martin Pool
Clean up clone-bzrdir code
610
        result = self._format._initialize_for_clone(url)
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
611
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
612
        self.open_repository().clone(result, revision_id=revision_id, basis=basis_repo)
1692.7.9 by Martin Pool
Don't create broken standalone branches over sftp (Malone #43064)
613
        from_branch = self.open_branch()
614
        from_branch.clone(result, revision_id=revision_id)
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
615
        try:
616
            self.open_workingtree().clone(result, basis=basis_tree)
617
        except errors.NotLocalUrl:
618
            # make a new one, this format always has to have one.
1563.2.38 by Robert Collins
make push preserve tree formats.
619
            try:
620
                WorkingTreeFormat2().initialize(result)
621
            except errors.NotLocalUrl:
1692.7.9 by Martin Pool
Don't create broken standalone branches over sftp (Malone #43064)
622
                # but we cannot do it for remote trees.
623
                to_branch = result.open_branch()
624
                WorkingTreeFormat2().stub_initialize_remote(to_branch.control_files)
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
625
        return result
626
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
627
    def create_branch(self):
628
        """See BzrDir.create_branch."""
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
629
        return self.open_branch()
630
1534.6.1 by Robert Collins
allow API creation of shared repositories
631
    def create_repository(self, shared=False):
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
632
        """See BzrDir.create_repository."""
1534.6.1 by Robert Collins
allow API creation of shared repositories
633
        if shared:
634
            raise errors.IncompatibleFormat('shared repository', self._format)
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
635
        return self.open_repository()
636
1508.1.21 by Robert Collins
Implement -r limit for checkout command.
637
    def create_workingtree(self, revision_id=None):
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
638
        """See BzrDir.create_workingtree."""
1508.1.21 by Robert Collins
Implement -r limit for checkout command.
639
        # this looks buggy but is not -really-
640
        # clone and sprout will have set the revision_id
641
        # and that will have set it for us, its only
642
        # specific uses of create_workingtree in isolation
643
        # that can do wonky stuff here, and that only
644
        # happens for creating checkouts, which cannot be 
645
        # done on this format anyway. So - acceptable wart.
646
        result = self.open_workingtree()
1508.1.24 by Robert Collins
Add update command for use with checkouts.
647
        if revision_id is not None:
648
            result.set_last_revision(revision_id)
1508.1.21 by Robert Collins
Implement -r limit for checkout command.
649
        return result
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
650
651
    def get_branch_transport(self, branch_format):
652
        """See BzrDir.get_branch_transport()."""
653
        if branch_format is None:
654
            return self.transport
655
        try:
656
            branch_format.get_format_string()
657
        except NotImplementedError:
658
            return self.transport
659
        raise errors.IncompatibleFormat(branch_format, self._format)
660
1534.4.47 by Robert Collins
Split out repository into .bzr/repository
661
    def get_repository_transport(self, repository_format):
662
        """See BzrDir.get_repository_transport()."""
663
        if repository_format is None:
664
            return self.transport
665
        try:
666
            repository_format.get_format_string()
667
        except NotImplementedError:
668
            return self.transport
669
        raise errors.IncompatibleFormat(repository_format, self._format)
670
1534.4.45 by Robert Collins
Start WorkingTree -> .bzr/checkout transition
671
    def get_workingtree_transport(self, workingtree_format):
672
        """See BzrDir.get_workingtree_transport()."""
673
        if workingtree_format is None:
674
            return self.transport
675
        try:
676
            workingtree_format.get_format_string()
677
        except NotImplementedError:
678
            return self.transport
679
        raise errors.IncompatibleFormat(workingtree_format, self._format)
680
1556.1.4 by Robert Collins
Add a new format for what will become knit, and the surrounding logic to upgrade repositories within metadirs, and tests for the same.
681
    def needs_format_conversion(self, format=None):
682
        """See BzrDir.needs_format_conversion()."""
683
        # if the format is not the same as the system default,
684
        # an upgrade is needed.
685
        if format is None:
686
            format = BzrDirFormat.get_default_format()
687
        return not isinstance(self._format, format.__class__)
688
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
689
    def open_branch(self, unsupported=False):
690
        """See BzrDir.open_branch."""
691
        from bzrlib.branch import BzrBranchFormat4
692
        format = BzrBranchFormat4()
693
        self._check_supported(format, unsupported)
694
        return format.open(self, _found=True)
695
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
696
    def sprout(self, url, revision_id=None, basis=None):
697
        """See BzrDir.sprout()."""
698
        from bzrlib.workingtree import WorkingTreeFormat2
699
        self._make_tail(url)
1651.1.6 by Martin Pool
Clean up clone-bzrdir code
700
        result = self._format._initialize_for_clone(url)
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
701
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
702
        try:
703
            self.open_repository().clone(result, revision_id=revision_id, basis=basis_repo)
704
        except errors.NoRepositoryPresent:
705
            pass
706
        try:
707
            self.open_branch().sprout(result, revision_id=revision_id)
708
        except errors.NotBranchError:
709
            pass
1587.1.5 by Robert Collins
Put bzr branch behaviour back to the 0.7 ignore-working-tree state.
710
        # we always want a working tree
711
        WorkingTreeFormat2().initialize(result)
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
712
        return result
713
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
714
715
class BzrDir4(BzrDirPreSplitOut):
1508.1.25 by Robert Collins
Update per review comments.
716
    """A .bzr version 4 control object.
717
    
718
    This is a deprecated format and may be removed after sept 2006.
719
    """
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
720
1534.6.1 by Robert Collins
allow API creation of shared repositories
721
    def create_repository(self, shared=False):
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
722
        """See BzrDir.create_repository."""
1556.1.4 by Robert Collins
Add a new format for what will become knit, and the surrounding logic to upgrade repositories within metadirs, and tests for the same.
723
        return self._format.repository_format.initialize(self, shared)
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
724
1534.5.16 by Robert Collins
Review feedback.
725
    def needs_format_conversion(self, format=None):
726
        """Format 4 dirs are always in need of conversion."""
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
727
        return True
728
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
729
    def open_repository(self):
730
        """See BzrDir.open_repository."""
731
        from bzrlib.repository import RepositoryFormat4
732
        return RepositoryFormat4().open(self, _found=True)
733
734
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
735
class BzrDir5(BzrDirPreSplitOut):
1508.1.25 by Robert Collins
Update per review comments.
736
    """A .bzr version 5 control object.
737
738
    This is a deprecated format and may be removed after sept 2006.
739
    """
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
740
741
    def open_repository(self):
742
        """See BzrDir.open_repository."""
743
        from bzrlib.repository import RepositoryFormat5
744
        return RepositoryFormat5().open(self, _found=True)
745
1534.4.46 by Robert Collins
Nearly complete .bzr/checkout splitout.
746
    def open_workingtree(self, _unsupported=False):
1534.4.42 by Robert Collins
add working tree to the BzrDir facilities.
747
        """See BzrDir.create_workingtree."""
748
        from bzrlib.workingtree import WorkingTreeFormat2
749
        return WorkingTreeFormat2().open(self, _found=True)
750
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
751
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
752
class BzrDir6(BzrDirPreSplitOut):
1508.1.25 by Robert Collins
Update per review comments.
753
    """A .bzr version 6 control object.
754
755
    This is a deprecated format and may be removed after sept 2006.
756
    """
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
757
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
758
    def open_repository(self):
759
        """See BzrDir.open_repository."""
760
        from bzrlib.repository import RepositoryFormat6
761
        return RepositoryFormat6().open(self, _found=True)
762
1534.4.46 by Robert Collins
Nearly complete .bzr/checkout splitout.
763
    def open_workingtree(self, _unsupported=False):
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
764
        """See BzrDir.create_workingtree."""
765
        from bzrlib.workingtree import WorkingTreeFormat2
766
        return WorkingTreeFormat2().open(self, _found=True)
767
768
769
class BzrDirMeta1(BzrDir):
770
    """A .bzr meta version 1 control object.
771
    
772
    This is the first control object where the 
1553.5.67 by Martin Pool
doc
773
    individual aspects are really split out: there are separate repository,
774
    workingtree and branch subdirectories and any subset of the three can be
775
    present within a BzrDir.
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
776
    """
777
1534.5.16 by Robert Collins
Review feedback.
778
    def can_convert_format(self):
779
        """See BzrDir.can_convert_format()."""
1556.1.4 by Robert Collins
Add a new format for what will become knit, and the surrounding logic to upgrade repositories within metadirs, and tests for the same.
780
        return True
1534.5.10 by Robert Collins
Make upgrade driver unaware of the specific formats in play.
781
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
782
    def create_branch(self):
783
        """See BzrDir.create_branch."""
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
784
        from bzrlib.branch import BranchFormat
785
        return BranchFormat.get_default_format().initialize(self)
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
786
1534.6.1 by Robert Collins
allow API creation of shared repositories
787
    def create_repository(self, shared=False):
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
788
        """See BzrDir.create_repository."""
1556.1.4 by Robert Collins
Add a new format for what will become knit, and the surrounding logic to upgrade repositories within metadirs, and tests for the same.
789
        return self._format.repository_format.initialize(self, shared)
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
790
1508.1.21 by Robert Collins
Implement -r limit for checkout command.
791
    def create_workingtree(self, revision_id=None):
1534.4.42 by Robert Collins
add working tree to the BzrDir facilities.
792
        """See BzrDir.create_workingtree."""
1534.4.46 by Robert Collins
Nearly complete .bzr/checkout splitout.
793
        from bzrlib.workingtree import WorkingTreeFormat
1508.1.21 by Robert Collins
Implement -r limit for checkout command.
794
        return WorkingTreeFormat.get_default_format().initialize(self, revision_id)
1534.4.42 by Robert Collins
add working tree to the BzrDir facilities.
795
1666.1.4 by Robert Collins
* 'Metadir' is now the default disk format. This improves behaviour in
796
    def _get_mkdir_mode(self):
797
        """Figure out the mode to use when creating a bzrdir subdir."""
798
        temp_control = LockableFiles(self.transport, '', TransportLock)
799
        return temp_control._dir_mode
800
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
801
    def get_branch_transport(self, branch_format):
802
        """See BzrDir.get_branch_transport()."""
803
        if branch_format is None:
804
            return self.transport.clone('branch')
805
        try:
806
            branch_format.get_format_string()
807
        except NotImplementedError:
808
            raise errors.IncompatibleFormat(branch_format, self._format)
809
        try:
1666.1.4 by Robert Collins
* 'Metadir' is now the default disk format. This improves behaviour in
810
            self.transport.mkdir('branch', mode=self._get_mkdir_mode())
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
811
        except errors.FileExists:
812
            pass
813
        return self.transport.clone('branch')
814
1534.4.47 by Robert Collins
Split out repository into .bzr/repository
815
    def get_repository_transport(self, repository_format):
816
        """See BzrDir.get_repository_transport()."""
817
        if repository_format is None:
818
            return self.transport.clone('repository')
819
        try:
820
            repository_format.get_format_string()
821
        except NotImplementedError:
822
            raise errors.IncompatibleFormat(repository_format, self._format)
823
        try:
1666.1.4 by Robert Collins
* 'Metadir' is now the default disk format. This improves behaviour in
824
            self.transport.mkdir('repository', mode=self._get_mkdir_mode())
1534.4.47 by Robert Collins
Split out repository into .bzr/repository
825
        except errors.FileExists:
826
            pass
827
        return self.transport.clone('repository')
828
1534.4.45 by Robert Collins
Start WorkingTree -> .bzr/checkout transition
829
    def get_workingtree_transport(self, workingtree_format):
830
        """See BzrDir.get_workingtree_transport()."""
831
        if workingtree_format is None:
832
            return self.transport.clone('checkout')
833
        try:
834
            workingtree_format.get_format_string()
835
        except NotImplementedError:
836
            raise errors.IncompatibleFormat(workingtree_format, self._format)
837
        try:
1666.1.4 by Robert Collins
* 'Metadir' is now the default disk format. This improves behaviour in
838
            self.transport.mkdir('checkout', mode=self._get_mkdir_mode())
1534.4.45 by Robert Collins
Start WorkingTree -> .bzr/checkout transition
839
        except errors.FileExists:
840
            pass
841
        return self.transport.clone('checkout')
842
1534.5.16 by Robert Collins
Review feedback.
843
    def needs_format_conversion(self, format=None):
844
        """See BzrDir.needs_format_conversion()."""
1556.1.4 by Robert Collins
Add a new format for what will become knit, and the surrounding logic to upgrade repositories within metadirs, and tests for the same.
845
        if format is None:
846
            format = BzrDirFormat.get_default_format()
847
        if not isinstance(self._format, format.__class__):
848
            # it is not a meta dir format, conversion is needed.
849
            return True
850
        # we might want to push this down to the repository?
851
        try:
852
            if not isinstance(self.open_repository()._format,
853
                              format.repository_format.__class__):
854
                # the repository needs an upgrade.
855
                return True
856
        except errors.NoRepositoryPresent:
857
            pass
858
        # currently there are no other possible conversions for meta1 formats.
1534.5.10 by Robert Collins
Make upgrade driver unaware of the specific formats in play.
859
        return False
860
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
861
    def open_branch(self, unsupported=False):
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
862
        """See BzrDir.open_branch."""
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
863
        from bzrlib.branch import BranchFormat
864
        format = BranchFormat.find_format(self)
865
        self._check_supported(format, unsupported)
866
        return format.open(self, _found=True)
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
867
1534.4.47 by Robert Collins
Split out repository into .bzr/repository
868
    def open_repository(self, unsupported=False):
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
869
        """See BzrDir.open_repository."""
1534.4.47 by Robert Collins
Split out repository into .bzr/repository
870
        from bzrlib.repository import RepositoryFormat
871
        format = RepositoryFormat.find_format(self)
872
        self._check_supported(format, unsupported)
873
        return format.open(self, _found=True)
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
874
1534.4.46 by Robert Collins
Nearly complete .bzr/checkout splitout.
875
    def open_workingtree(self, unsupported=False):
1508.1.21 by Robert Collins
Implement -r limit for checkout command.
876
        """See BzrDir.open_workingtree."""
1534.4.46 by Robert Collins
Nearly complete .bzr/checkout splitout.
877
        from bzrlib.workingtree import WorkingTreeFormat
878
        format = WorkingTreeFormat.find_format(self)
879
        self._check_supported(format, unsupported)
880
        return format.open(self, _found=True)
1534.4.42 by Robert Collins
add working tree to the BzrDir facilities.
881
1534.4.39 by Robert Collins
Basic BzrDir support.
882
883
class BzrDirFormat(object):
884
    """An encapsulation of the initialization and open routines for a format.
885
886
    Formats provide three things:
887
     * An initialization routine,
888
     * a format string,
889
     * an open routine.
890
891
    Formats are placed in an dict by their format string for reference 
892
    during bzrdir opening. These should be subclasses of BzrDirFormat
893
    for consistency.
894
895
    Once a format is deprecated, just deprecate the initialize and open
896
    methods on the format class. Do not deprecate the object, as the 
897
    object will be created every system load.
898
    """
899
900
    _default_format = None
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
901
    """The default format used for new .bzr dirs."""
1534.4.39 by Robert Collins
Basic BzrDir support.
902
903
    _formats = {}
904
    """The known formats."""
905
1553.5.69 by Martin Pool
BzrDirFormat subclasses can now control what kind of overall lock is used.
906
    _lock_file_name = 'branch-lock'
907
908
    # _lock_class must be set in subclasses to the lock type, typ.
909
    # TransportLock or LockDir
910
1534.4.39 by Robert Collins
Basic BzrDir support.
911
    @classmethod
912
    def find_format(klass, transport):
913
        """Return the format registered for URL."""
914
        try:
915
            format_string = transport.get(".bzr/branch-format").read()
916
            return klass._formats[format_string]
917
        except errors.NoSuchFile:
918
            raise errors.NotBranchError(path=transport.base)
919
        except KeyError:
920
            raise errors.UnknownFormatError(format_string)
921
922
    @classmethod
923
    def get_default_format(klass):
924
        """Return the current default format."""
925
        return klass._default_format
926
927
    def get_format_string(self):
928
        """Return the ASCII format string that identifies this format."""
929
        raise NotImplementedError(self.get_format_string)
930
1624.3.19 by Olaf Conradi
New call get_format_description to give a user-friendly description of a
931
    def get_format_description(self):
932
        """Return the short description for this format."""
933
        raise NotImplementedError(self.get_format_description)
934
1534.5.16 by Robert Collins
Review feedback.
935
    def get_converter(self, format=None):
936
        """Return the converter to use to convert bzrdirs needing converts.
1534.5.10 by Robert Collins
Make upgrade driver unaware of the specific formats in play.
937
938
        This returns a bzrlib.bzrdir.Converter object.
939
940
        This should return the best upgrader to step this format towards the
941
        current default format. In the case of plugins we can/shouold provide
942
        some means for them to extend the range of returnable converters.
1534.5.13 by Robert Collins
Correct buggy test.
943
944
        :param format: Optional format to override the default foramt of the 
945
                       library.
1534.5.10 by Robert Collins
Make upgrade driver unaware of the specific formats in play.
946
        """
1534.5.16 by Robert Collins
Review feedback.
947
        raise NotImplementedError(self.get_converter)
1534.5.10 by Robert Collins
Make upgrade driver unaware of the specific formats in play.
948
1651.1.6 by Martin Pool
Clean up clone-bzrdir code
949
    def initialize(self, url):
1608.2.8 by Martin Pool
Separate out BzrDir.initialize_on_transport so it
950
        """Create a bzr control dir at this url and return an opened copy.
951
        
952
        Subclasses should typically override initialize_on_transport
953
        instead of this method.
954
        """
1651.1.6 by Martin Pool
Clean up clone-bzrdir code
955
        return self.initialize_on_transport(get_transport(url))
1608.2.8 by Martin Pool
Separate out BzrDir.initialize_on_transport so it
956
1651.1.6 by Martin Pool
Clean up clone-bzrdir code
957
    def initialize_on_transport(self, transport):
1608.2.8 by Martin Pool
Separate out BzrDir.initialize_on_transport so it
958
        """Initialize a new bzrdir in the base directory of a Transport."""
959
        # Since we don'transport have a .bzr directory, inherit the
1534.4.39 by Robert Collins
Basic BzrDir support.
960
        # mode from the root directory
1608.2.8 by Martin Pool
Separate out BzrDir.initialize_on_transport so it
961
        temp_control = LockableFiles(transport, '', TransportLock)
1534.4.39 by Robert Collins
Basic BzrDir support.
962
        temp_control._transport.mkdir('.bzr',
963
                                      # FIXME: RBC 20060121 dont peek under
964
                                      # the covers
965
                                      mode=temp_control._dir_mode)
966
        file_mode = temp_control._file_mode
967
        del temp_control
1608.2.8 by Martin Pool
Separate out BzrDir.initialize_on_transport so it
968
        mutter('created control directory in ' + transport.base)
969
        control = transport.clone('.bzr')
1534.4.39 by Robert Collins
Basic BzrDir support.
970
        utf8_files = [('README', 
971
                       "This is a Bazaar-NG control directory.\n"
972
                       "Do not change any files in this directory.\n"),
973
                      ('branch-format', self.get_format_string()),
974
                      ]
975
        # NB: no need to escape relative paths that are url safe.
1608.2.8 by Martin Pool
Separate out BzrDir.initialize_on_transport so it
976
        control_files = LockableFiles(control, self._lock_file_name, 
977
                                      self._lock_class)
1553.5.60 by Martin Pool
New LockableFiles.create_lock() method
978
        control_files.create_lock()
1534.4.39 by Robert Collins
Basic BzrDir support.
979
        control_files.lock_write()
980
        try:
981
            for file, content in utf8_files:
982
                control_files.put_utf8(file, content)
983
        finally:
984
            control_files.unlock()
1608.2.8 by Martin Pool
Separate out BzrDir.initialize_on_transport so it
985
        return self.open(transport, _found=True)
1534.4.39 by Robert Collins
Basic BzrDir support.
986
987
    def is_supported(self):
988
        """Is this format supported?
989
990
        Supported formats must be initializable and openable.
991
        Unsupported formats may not support initialization or committing or 
992
        some other features depending on the reason for not being supported.
993
        """
994
        return True
995
996
    def open(self, transport, _found=False):
997
        """Return an instance of this format for the dir transport points at.
998
        
999
        _found is a private parameter, do not use it.
1000
        """
1001
        if not _found:
1002
            assert isinstance(BzrDirFormat.find_format(transport),
1003
                              self.__class__)
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
1004
        return self._open(transport)
1005
1006
    def _open(self, transport):
1007
        """Template method helper for opening BzrDirectories.
1008
1009
        This performs the actual open and any additional logic or parameter
1010
        passing.
1011
        """
1012
        raise NotImplementedError(self._open)
1534.4.39 by Robert Collins
Basic BzrDir support.
1013
1014
    @classmethod
1015
    def register_format(klass, format):
1016
        klass._formats[format.get_format_string()] = format
1017
1018
    @classmethod
1019
    def set_default_format(klass, format):
1020
        klass._default_format = format
1021
1534.5.1 by Robert Collins
Give info some reasonable output and tests.
1022
    def __str__(self):
1023
        return self.get_format_string()[:-1]
1024
1534.4.39 by Robert Collins
Basic BzrDir support.
1025
    @classmethod
1026
    def unregister_format(klass, format):
1027
        assert klass._formats[format.get_format_string()] is format
1028
        del klass._formats[format.get_format_string()]
1029
1030
1031
class BzrDirFormat4(BzrDirFormat):
1032
    """Bzr dir format 4.
1033
1034
    This format is a combined format for working tree, branch and repository.
1035
    It has:
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
1036
     - Format 1 working trees [always]
1037
     - Format 4 branches [always]
1038
     - Format 4 repositories [always]
1534.4.39 by Robert Collins
Basic BzrDir support.
1039
1040
    This format is deprecated: it indexes texts using a text it which is
1041
    removed in format 5; write support for this format has been removed.
1042
    """
1043
1553.5.69 by Martin Pool
BzrDirFormat subclasses can now control what kind of overall lock is used.
1044
    _lock_class = TransportLock
1045
1534.4.39 by Robert Collins
Basic BzrDir support.
1046
    def get_format_string(self):
1047
        """See BzrDirFormat.get_format_string()."""
1048
        return "Bazaar-NG branch, format 0.0.4\n"
1049
1624.3.19 by Olaf Conradi
New call get_format_description to give a user-friendly description of a
1050
    def get_format_description(self):
1051
        """See BzrDirFormat.get_format_description()."""
1052
        return "All-in-one format 4"
1053
1534.5.16 by Robert Collins
Review feedback.
1054
    def get_converter(self, format=None):
1055
        """See BzrDirFormat.get_converter()."""
1534.5.13 by Robert Collins
Correct buggy test.
1056
        # there is one and only one upgrade path here.
1534.5.10 by Robert Collins
Make upgrade driver unaware of the specific formats in play.
1057
        return ConvertBzrDir4To5()
1058
        
1651.1.6 by Martin Pool
Clean up clone-bzrdir code
1059
    def initialize_on_transport(self, transport):
1534.4.39 by Robert Collins
Basic BzrDir support.
1060
        """Format 4 branches cannot be created."""
1061
        raise errors.UninitializableFormat(self)
1062
1063
    def is_supported(self):
1064
        """Format 4 is not supported.
1065
1066
        It is not supported because the model changed from 4 to 5 and the
1067
        conversion logic is expensive - so doing it on the fly was not 
1068
        feasible.
1069
        """
1070
        return False
1071
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
1072
    def _open(self, transport):
1073
        """See BzrDirFormat._open."""
1074
        return BzrDir4(transport, self)
1075
1556.1.4 by Robert Collins
Add a new format for what will become knit, and the surrounding logic to upgrade repositories within metadirs, and tests for the same.
1076
    def __return_repository_format(self):
1077
        """Circular import protection."""
1078
        from bzrlib.repository import RepositoryFormat4
1079
        return RepositoryFormat4(self)
1080
    repository_format = property(__return_repository_format)
1081
1534.4.39 by Robert Collins
Basic BzrDir support.
1082
1083
class BzrDirFormat5(BzrDirFormat):
1084
    """Bzr control format 5.
1085
1086
    This format is a combined format for working tree, branch and repository.
1087
    It has:
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
1088
     - Format 2 working trees [always] 
1089
     - Format 4 branches [always] 
1534.4.53 by Robert Collins
Review feedback from John Meinel.
1090
     - Format 5 repositories [always]
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
1091
       Unhashed stores in the repository.
1534.4.39 by Robert Collins
Basic BzrDir support.
1092
    """
1093
1553.5.69 by Martin Pool
BzrDirFormat subclasses can now control what kind of overall lock is used.
1094
    _lock_class = TransportLock
1095
1534.4.39 by Robert Collins
Basic BzrDir support.
1096
    def get_format_string(self):
1097
        """See BzrDirFormat.get_format_string()."""
1098
        return "Bazaar-NG branch, format 5\n"
1099
1624.3.19 by Olaf Conradi
New call get_format_description to give a user-friendly description of a
1100
    def get_format_description(self):
1101
        """See BzrDirFormat.get_format_description()."""
1102
        return "All-in-one format 5"
1103
1534.5.16 by Robert Collins
Review feedback.
1104
    def get_converter(self, format=None):
1105
        """See BzrDirFormat.get_converter()."""
1534.5.13 by Robert Collins
Correct buggy test.
1106
        # there is one and only one upgrade path here.
1534.5.10 by Robert Collins
Make upgrade driver unaware of the specific formats in play.
1107
        return ConvertBzrDir5To6()
1651.1.6 by Martin Pool
Clean up clone-bzrdir code
1108
1109
    def _initialize_for_clone(self, url):
1110
        return self.initialize_on_transport(get_transport(url), _cloning=True)
1534.5.10 by Robert Collins
Make upgrade driver unaware of the specific formats in play.
1111
        
1608.2.8 by Martin Pool
Separate out BzrDir.initialize_on_transport so it
1112
    def initialize_on_transport(self, transport, _cloning=False):
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
1113
        """Format 5 dirs always have working tree, branch and repository.
1114
        
1115
        Except when they are being cloned.
1116
        """
1117
        from bzrlib.branch import BzrBranchFormat4
1118
        from bzrlib.repository import RepositoryFormat5
1119
        from bzrlib.workingtree import WorkingTreeFormat2
1651.1.6 by Martin Pool
Clean up clone-bzrdir code
1120
        result = (super(BzrDirFormat5, self).initialize_on_transport(transport))
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
1121
        RepositoryFormat5().initialize(result, _internal=True)
1122
        if not _cloning:
1123
            BzrBranchFormat4().initialize(result)
1124
            WorkingTreeFormat2().initialize(result)
1125
        return result
1126
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
1127
    def _open(self, transport):
1128
        """See BzrDirFormat._open."""
1129
        return BzrDir5(transport, self)
1130
1556.1.4 by Robert Collins
Add a new format for what will become knit, and the surrounding logic to upgrade repositories within metadirs, and tests for the same.
1131
    def __return_repository_format(self):
1132
        """Circular import protection."""
1133
        from bzrlib.repository import RepositoryFormat5
1134
        return RepositoryFormat5(self)
1135
    repository_format = property(__return_repository_format)
1136
1534.4.39 by Robert Collins
Basic BzrDir support.
1137
1138
class BzrDirFormat6(BzrDirFormat):
1139
    """Bzr control format 6.
1140
1141
    This format is a combined format for working tree, branch and repository.
1142
    It has:
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
1143
     - Format 2 working trees [always] 
1144
     - Format 4 branches [always] 
1145
     - Format 6 repositories [always]
1534.4.39 by Robert Collins
Basic BzrDir support.
1146
    """
1147
1553.5.69 by Martin Pool
BzrDirFormat subclasses can now control what kind of overall lock is used.
1148
    _lock_class = TransportLock
1149
1534.4.39 by Robert Collins
Basic BzrDir support.
1150
    def get_format_string(self):
1151
        """See BzrDirFormat.get_format_string()."""
1152
        return "Bazaar-NG branch, format 6\n"
1153
1624.3.19 by Olaf Conradi
New call get_format_description to give a user-friendly description of a
1154
    def get_format_description(self):
1155
        """See BzrDirFormat.get_format_description()."""
1156
        return "All-in-one format 6"
1157
1534.5.16 by Robert Collins
Review feedback.
1158
    def get_converter(self, format=None):
1159
        """See BzrDirFormat.get_converter()."""
1534.5.13 by Robert Collins
Correct buggy test.
1160
        # there is one and only one upgrade path here.
1534.5.10 by Robert Collins
Make upgrade driver unaware of the specific formats in play.
1161
        return ConvertBzrDir6ToMeta()
1162
        
1651.1.6 by Martin Pool
Clean up clone-bzrdir code
1163
    def _initialize_for_clone(self, url):
1164
        return self.initialize_on_transport(get_transport(url), _cloning=True)
1165
1608.2.8 by Martin Pool
Separate out BzrDir.initialize_on_transport so it
1166
    def initialize_on_transport(self, transport, _cloning=False):
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
1167
        """Format 6 dirs always have working tree, branch and repository.
1168
        
1169
        Except when they are being cloned.
1170
        """
1171
        from bzrlib.branch import BzrBranchFormat4
1172
        from bzrlib.repository import RepositoryFormat6
1173
        from bzrlib.workingtree import WorkingTreeFormat2
1651.1.6 by Martin Pool
Clean up clone-bzrdir code
1174
        result = super(BzrDirFormat6, self).initialize_on_transport(transport)
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
1175
        RepositoryFormat6().initialize(result, _internal=True)
1176
        if not _cloning:
1177
            BzrBranchFormat4().initialize(result)
1178
            try:
1179
                WorkingTreeFormat2().initialize(result)
1180
            except errors.NotLocalUrl:
1181
                # emulate pre-check behaviour for working tree and silently 
1182
                # fail.
1183
                pass
1184
        return result
1185
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
1186
    def _open(self, transport):
1187
        """See BzrDirFormat._open."""
1188
        return BzrDir6(transport, self)
1189
1556.1.4 by Robert Collins
Add a new format for what will become knit, and the surrounding logic to upgrade repositories within metadirs, and tests for the same.
1190
    def __return_repository_format(self):
1191
        """Circular import protection."""
1192
        from bzrlib.repository import RepositoryFormat6
1193
        return RepositoryFormat6(self)
1194
    repository_format = property(__return_repository_format)
1195
1534.4.39 by Robert Collins
Basic BzrDir support.
1196
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
1197
class BzrDirMetaFormat1(BzrDirFormat):
1198
    """Bzr meta control format 1
1199
1200
    This is the first format with split out working tree, branch and repository
1201
    disk storage.
1202
    It has:
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
1203
     - Format 3 working trees [optional]
1204
     - Format 5 branches [optional]
1205
     - Format 7 repositories [optional]
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
1206
    """
1207
1553.5.69 by Martin Pool
BzrDirFormat subclasses can now control what kind of overall lock is used.
1208
    _lock_class = LockDir
1209
1556.1.4 by Robert Collins
Add a new format for what will become knit, and the surrounding logic to upgrade repositories within metadirs, and tests for the same.
1210
    def get_converter(self, format=None):
1211
        """See BzrDirFormat.get_converter()."""
1212
        if format is None:
1213
            format = BzrDirFormat.get_default_format()
1214
        if not isinstance(self, format.__class__):
1215
            # converting away from metadir is not implemented
1216
            raise NotImplementedError(self.get_converter)
1217
        return ConvertMetaToMeta(format)
1218
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
1219
    def get_format_string(self):
1220
        """See BzrDirFormat.get_format_string()."""
1221
        return "Bazaar-NG meta directory, format 1\n"
1222
1624.3.19 by Olaf Conradi
New call get_format_description to give a user-friendly description of a
1223
    def get_format_description(self):
1224
        """See BzrDirFormat.get_format_description()."""
1225
        return "Meta directory format 1"
1226
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
1227
    def _open(self, transport):
1228
        """See BzrDirFormat._open."""
1229
        return BzrDirMeta1(transport, self)
1230
1556.1.4 by Robert Collins
Add a new format for what will become knit, and the surrounding logic to upgrade repositories within metadirs, and tests for the same.
1231
    def __return_repository_format(self):
1232
        """Circular import protection."""
1233
        if getattr(self, '_repository_format', None):
1234
            return self._repository_format
1235
        from bzrlib.repository import RepositoryFormat
1236
        return RepositoryFormat.get_default_format()
1237
1238
    def __set_repository_format(self, value):
1239
        """Allow changint the repository format for metadir formats."""
1240
        self._repository_format = value
1553.5.72 by Martin Pool
Clean up test for Branch5 lockdirs
1241
1556.1.4 by Robert Collins
Add a new format for what will become knit, and the surrounding logic to upgrade repositories within metadirs, and tests for the same.
1242
    repository_format = property(__return_repository_format, __set_repository_format)
1243
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
1244
1534.4.39 by Robert Collins
Basic BzrDir support.
1245
BzrDirFormat.register_format(BzrDirFormat4())
1246
BzrDirFormat.register_format(BzrDirFormat5())
1666.1.4 by Robert Collins
* 'Metadir' is now the default disk format. This improves behaviour in
1247
BzrDirFormat.register_format(BzrDirFormat6())
1248
__default_format = BzrDirMetaFormat1()
1534.4.39 by Robert Collins
Basic BzrDir support.
1249
BzrDirFormat.register_format(__default_format)
1250
BzrDirFormat.set_default_format(__default_format)
1251
1252
1253
class BzrDirTestProviderAdapter(object):
1254
    """A tool to generate a suite testing multiple bzrdir formats at once.
1255
1256
    This is done by copying the test once for each transport and injecting
1257
    the transport_server, transport_readonly_server, and bzrdir_format
1258
    classes into each copy. Each copy is also given a new id() to make it
1259
    easy to identify.
1260
    """
1261
1262
    def __init__(self, transport_server, transport_readonly_server, formats):
1263
        self._transport_server = transport_server
1264
        self._transport_readonly_server = transport_readonly_server
1265
        self._formats = formats
1266
    
1267
    def adapt(self, test):
1268
        result = TestSuite()
1269
        for format in self._formats:
1270
            new_test = deepcopy(test)
1271
            new_test.transport_server = self._transport_server
1272
            new_test.transport_readonly_server = self._transport_readonly_server
1273
            new_test.bzrdir_format = format
1274
            def make_new_test_id():
1275
                new_id = "%s(%s)" % (new_test.id(), format.__class__.__name__)
1276
                return lambda: new_id
1277
            new_test.id = make_new_test_id()
1278
            result.addTest(new_test)
1279
        return result
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
1280
1281
1282
class ScratchDir(BzrDir6):
1283
    """Special test class: a bzrdir that cleans up itself..
1284
1285
    >>> d = ScratchDir()
1286
    >>> base = d.transport.base
1287
    >>> isdir(base)
1288
    True
1289
    >>> b.transport.__del__()
1290
    >>> isdir(base)
1291
    False
1292
    """
1293
1294
    def __init__(self, files=[], dirs=[], transport=None):
1295
        """Make a test branch.
1296
1297
        This creates a temporary directory and runs init-tree in it.
1298
1299
        If any files are listed, they are created in the working copy.
1300
        """
1301
        if transport is None:
1302
            transport = bzrlib.transport.local.ScratchTransport()
1303
            # local import for scope restriction
1304
            BzrDirFormat6().initialize(transport.base)
1305
            super(ScratchDir, self).__init__(transport, BzrDirFormat6())
1306
            self.create_repository()
1307
            self.create_branch()
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
1308
            self.create_workingtree()
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
1309
        else:
1310
            super(ScratchDir, self).__init__(transport, BzrDirFormat6())
1311
1312
        # BzrBranch creates a clone to .bzr and then forgets about the
1313
        # original transport. A ScratchTransport() deletes itself and
1314
        # everything underneath it when it goes away, so we need to
1315
        # grab a local copy to prevent that from happening
1316
        self._transport = transport
1317
1318
        for d in dirs:
1319
            self._transport.mkdir(d)
1320
            
1321
        for f in files:
1322
            self._transport.put(f, 'content of %s' % f)
1323
1324
    def clone(self):
1325
        """
1326
        >>> orig = ScratchDir(files=["file1", "file2"])
1327
        >>> os.listdir(orig.base)
1328
        [u'.bzr', u'file1', u'file2']
1329
        >>> clone = orig.clone()
1330
        >>> if os.name != 'nt':
1331
        ...   os.path.samefile(orig.base, clone.base)
1332
        ... else:
1333
        ...   orig.base == clone.base
1334
        ...
1335
        False
1336
        >>> os.listdir(clone.base)
1337
        [u'.bzr', u'file1', u'file2']
1338
        """
1339
        from shutil import copytree
1340
        from bzrlib.osutils import mkdtemp
1341
        base = mkdtemp()
1342
        os.rmdir(base)
1343
        copytree(self.base, base, symlinks=True)
1344
        return ScratchDir(
1345
            transport=bzrlib.transport.local.ScratchTransport(base))
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
1346
1347
1348
class Converter(object):
1349
    """Converts a disk format object from one format to another."""
1350
1534.5.10 by Robert Collins
Make upgrade driver unaware of the specific formats in play.
1351
    def convert(self, to_convert, pb):
1352
        """Perform the conversion of to_convert, giving feedback via pb.
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
1353
1534.5.10 by Robert Collins
Make upgrade driver unaware of the specific formats in play.
1354
        :param to_convert: The disk object to convert.
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
1355
        :param pb: a progress bar to use for progress information.
1356
        """
1357
1556.1.4 by Robert Collins
Add a new format for what will become knit, and the surrounding logic to upgrade repositories within metadirs, and tests for the same.
1358
    def step(self, message):
1359
        """Update the pb by a step."""
1360
        self.count +=1
1361
        self.pb.update(message, self.count, self.total)
1362
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
1363
1364
class ConvertBzrDir4To5(Converter):
1365
    """Converts format 4 bzr dirs to format 5."""
1366
1534.5.10 by Robert Collins
Make upgrade driver unaware of the specific formats in play.
1367
    def __init__(self):
1368
        super(ConvertBzrDir4To5, self).__init__()
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
1369
        self.converted_revs = set()
1370
        self.absent_revisions = set()
1371
        self.text_count = 0
1372
        self.revisions = {}
1373
        
1534.5.10 by Robert Collins
Make upgrade driver unaware of the specific formats in play.
1374
    def convert(self, to_convert, pb):
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
1375
        """See Converter.convert()."""
1534.5.10 by Robert Collins
Make upgrade driver unaware of the specific formats in play.
1376
        self.bzrdir = to_convert
1377
        self.pb = pb
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
1378
        self.pb.note('starting upgrade from format 4 to 5')
1379
        if isinstance(self.bzrdir.transport, LocalTransport):
1380
            self.bzrdir.get_workingtree_transport(None).delete('stat-cache')
1381
        self._convert_to_weaves()
1382
        return BzrDir.open(self.bzrdir.root_transport.base)
1383
1384
    def _convert_to_weaves(self):
1385
        self.pb.note('note: upgrade may be faster if all store files are ungzipped first')
1386
        try:
1387
            # TODO permissions
1388
            stat = self.bzrdir.transport.stat('weaves')
1389
            if not S_ISDIR(stat.st_mode):
1390
                self.bzrdir.transport.delete('weaves')
1391
                self.bzrdir.transport.mkdir('weaves')
1392
        except errors.NoSuchFile:
1393
            self.bzrdir.transport.mkdir('weaves')
1563.2.10 by Robert Collins
Change weave store to be a versioned store, using WeaveFiles which maintain integrity without needing explicit 'put' operations.
1394
        # deliberately not a WeaveFile as we want to build it up slowly.
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
1395
        self.inv_weave = Weave('inventory')
1396
        # holds in-memory weaves for all files
1397
        self.text_weaves = {}
1398
        self.bzrdir.transport.delete('branch-format')
1399
        self.branch = self.bzrdir.open_branch()
1400
        self._convert_working_inv()
1401
        rev_history = self.branch.revision_history()
1402
        # to_read is a stack holding the revisions we still need to process;
1403
        # appending to it adds new highest-priority revisions
1404
        self.known_revisions = set(rev_history)
1405
        self.to_read = rev_history[-1:]
1406
        while self.to_read:
1407
            rev_id = self.to_read.pop()
1408
            if (rev_id not in self.revisions
1409
                and rev_id not in self.absent_revisions):
1410
                self._load_one_rev(rev_id)
1411
        self.pb.clear()
1412
        to_import = self._make_order()
1413
        for i, rev_id in enumerate(to_import):
1414
            self.pb.update('converting revision', i, len(to_import))
1415
            self._convert_one_rev(rev_id)
1416
        self.pb.clear()
1417
        self._write_all_weaves()
1418
        self._write_all_revs()
1419
        self.pb.note('upgraded to weaves:')
1420
        self.pb.note('  %6d revisions and inventories', len(self.revisions))
1421
        self.pb.note('  %6d revisions not present', len(self.absent_revisions))
1422
        self.pb.note('  %6d texts', self.text_count)
1423
        self._cleanup_spare_files_after_format4()
1424
        self.branch.control_files.put_utf8('branch-format', BzrDirFormat5().get_format_string())
1425
1426
    def _cleanup_spare_files_after_format4(self):
1427
        # FIXME working tree upgrade foo.
1428
        for n in 'merged-patches', 'pending-merged-patches':
1429
            try:
1430
                ## assert os.path.getsize(p) == 0
1431
                self.bzrdir.transport.delete(n)
1432
            except errors.NoSuchFile:
1433
                pass
1434
        self.bzrdir.transport.delete_tree('inventory-store')
1435
        self.bzrdir.transport.delete_tree('text-store')
1436
1437
    def _convert_working_inv(self):
1438
        inv = serializer_v4.read_inventory(self.branch.control_files.get('inventory'))
1439
        new_inv_xml = serializer_v5.write_inventory_to_string(inv)
1440
        # FIXME inventory is a working tree change.
1441
        self.branch.control_files.put('inventory', new_inv_xml)
1442
1443
    def _write_all_weaves(self):
1444
        controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)
1445
        weave_transport = self.bzrdir.transport.clone('weaves')
1446
        weaves = WeaveStore(weave_transport, prefixed=False)
1563.2.34 by Robert Collins
Remove the commit and rollback transaction methods as misleading, and implement a WriteTransaction
1447
        transaction = WriteTransaction()
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
1448
1449
        try:
1563.2.10 by Robert Collins
Change weave store to be a versioned store, using WeaveFiles which maintain integrity without needing explicit 'put' operations.
1450
            i = 0
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
1451
            for file_id, file_weave in self.text_weaves.items():
1452
                self.pb.update('writing weave', i, len(self.text_weaves))
1563.2.10 by Robert Collins
Change weave store to be a versioned store, using WeaveFiles which maintain integrity without needing explicit 'put' operations.
1453
                weaves._put_weave(file_id, file_weave, transaction)
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
1454
                i += 1
1563.2.10 by Robert Collins
Change weave store to be a versioned store, using WeaveFiles which maintain integrity without needing explicit 'put' operations.
1455
            self.pb.update('inventory', 0, 1)
1456
            controlweaves._put_weave('inventory', self.inv_weave, transaction)
1457
            self.pb.update('inventory', 1, 1)
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
1458
        finally:
1459
            self.pb.clear()
1460
1461
    def _write_all_revs(self):
1462
        """Write all revisions out in new form."""
1463
        self.bzrdir.transport.delete_tree('revision-store')
1464
        self.bzrdir.transport.mkdir('revision-store')
1465
        revision_transport = self.bzrdir.transport.clone('revision-store')
1466
        # TODO permissions
1563.2.28 by Robert Collins
Add total_size to the revision_store api.
1467
        _revision_store = TextRevisionStore(TextStore(revision_transport,
1468
                                                      prefixed=False,
1469
                                                      compressed=True))
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
1470
        try:
1563.2.34 by Robert Collins
Remove the commit and rollback transaction methods as misleading, and implement a WriteTransaction
1471
            transaction = bzrlib.transactions.WriteTransaction()
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
1472
            for i, rev_id in enumerate(self.converted_revs):
1473
                self.pb.update('write revision', i, len(self.converted_revs))
1563.2.28 by Robert Collins
Add total_size to the revision_store api.
1474
                _revision_store.add_revision(self.revisions[rev_id], transaction)
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
1475
        finally:
1476
            self.pb.clear()
1477
            
1478
    def _load_one_rev(self, rev_id):
1479
        """Load a revision object into memory.
1480
1481
        Any parents not either loaded or abandoned get queued to be
1482
        loaded."""
1483
        self.pb.update('loading revision',
1484
                       len(self.revisions),
1485
                       len(self.known_revisions))
1563.2.22 by Robert Collins
Move responsibility for repository.has_revision into RevisionStore
1486
        if not self.branch.repository.has_revision(rev_id):
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
1487
            self.pb.clear()
1488
            self.pb.note('revision {%s} not present in branch; '
1489
                         'will be converted as a ghost',
1490
                         rev_id)
1491
            self.absent_revisions.add(rev_id)
1492
        else:
1563.2.28 by Robert Collins
Add total_size to the revision_store api.
1493
            rev = self.branch.repository._revision_store.get_revision(rev_id,
1494
                self.branch.repository.get_transaction())
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
1495
            for parent_id in rev.parent_ids:
1496
                self.known_revisions.add(parent_id)
1497
                self.to_read.append(parent_id)
1498
            self.revisions[rev_id] = rev
1499
1500
    def _load_old_inventory(self, rev_id):
1501
        assert rev_id not in self.converted_revs
1502
        old_inv_xml = self.branch.repository.inventory_store.get(rev_id).read()
1503
        inv = serializer_v4.read_inventory_from_string(old_inv_xml)
1504
        rev = self.revisions[rev_id]
1505
        if rev.inventory_sha1:
1506
            assert rev.inventory_sha1 == sha_string(old_inv_xml), \
1507
                'inventory sha mismatch for {%s}' % rev_id
1508
        return inv
1509
1510
    def _load_updated_inventory(self, rev_id):
1511
        assert rev_id in self.converted_revs
1512
        inv_xml = self.inv_weave.get_text(rev_id)
1513
        inv = serializer_v5.read_inventory_from_string(inv_xml)
1514
        return inv
1515
1516
    def _convert_one_rev(self, rev_id):
1517
        """Convert revision and all referenced objects to new format."""
1518
        rev = self.revisions[rev_id]
1519
        inv = self._load_old_inventory(rev_id)
1520
        present_parents = [p for p in rev.parent_ids
1521
                           if p not in self.absent_revisions]
1522
        self._convert_revision_contents(rev, inv, present_parents)
1523
        self._store_new_weave(rev, inv, present_parents)
1524
        self.converted_revs.add(rev_id)
1525
1526
    def _store_new_weave(self, rev, inv, present_parents):
1527
        # the XML is now updated with text versions
1528
        if __debug__:
1529
            for file_id in inv:
1530
                ie = inv[file_id]
1531
                if ie.kind == 'root_directory':
1532
                    continue
1533
                assert hasattr(ie, 'revision'), \
1534
                    'no revision on {%s} in {%s}' % \
1535
                    (file_id, rev.revision_id)
1536
        new_inv_xml = serializer_v5.write_inventory_to_string(inv)
1537
        new_inv_sha1 = sha_string(new_inv_xml)
1563.2.28 by Robert Collins
Add total_size to the revision_store api.
1538
        self.inv_weave.add_lines(rev.revision_id, 
1539
                                 present_parents,
1540
                                 new_inv_xml.splitlines(True))
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
1541
        rev.inventory_sha1 = new_inv_sha1
1542
1543
    def _convert_revision_contents(self, rev, inv, present_parents):
1544
        """Convert all the files within a revision.
1545
1546
        Also upgrade the inventory to refer to the text revision ids."""
1547
        rev_id = rev.revision_id
1548
        mutter('converting texts of revision {%s}',
1549
               rev_id)
1550
        parent_invs = map(self._load_updated_inventory, present_parents)
1551
        for file_id in inv:
1552
            ie = inv[file_id]
1553
            self._convert_file_version(rev, ie, parent_invs)
1554
1555
    def _convert_file_version(self, rev, ie, parent_invs):
1556
        """Convert one version of one file.
1557
1558
        The file needs to be added into the weave if it is a merge
1559
        of >=2 parents or if it's changed from its parent.
1560
        """
1561
        if ie.kind == 'root_directory':
1562
            return
1563
        file_id = ie.file_id
1564
        rev_id = rev.revision_id
1565
        w = self.text_weaves.get(file_id)
1566
        if w is None:
1567
            w = Weave(file_id)
1568
            self.text_weaves[file_id] = w
1569
        text_changed = False
1596.2.20 by Robert Collins
optimise commit to only access weaves for merged, or altered files during commit.
1570
        previous_entries = ie.find_previous_heads(parent_invs,
1571
                                                  None,
1572
                                                  None,
1573
                                                  entry_vf=w)
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
1574
        for old_revision in previous_entries:
1575
                # if this fails, its a ghost ?
1576
                assert old_revision in self.converted_revs 
1577
        self.snapshot_ie(previous_entries, ie, w, rev_id)
1578
        del ie.text_id
1579
        assert getattr(ie, 'revision', None) is not None
1580
1581
    def snapshot_ie(self, previous_revisions, ie, w, rev_id):
1582
        # TODO: convert this logic, which is ~= snapshot to
1583
        # a call to:. This needs the path figured out. rather than a work_tree
1584
        # a v4 revision_tree can be given, or something that looks enough like
1585
        # one to give the file content to the entry if it needs it.
1586
        # and we need something that looks like a weave store for snapshot to 
1587
        # save against.
1588
        #ie.snapshot(rev, PATH, previous_revisions, REVISION_TREE, InMemoryWeaveStore(self.text_weaves))
1589
        if len(previous_revisions) == 1:
1590
            previous_ie = previous_revisions.values()[0]
1591
            if ie._unchanged(previous_ie):
1592
                ie.revision = previous_ie.revision
1593
                return
1594
        if ie.has_text():
1595
            text = self.branch.repository.text_store.get(ie.text_id)
1596
            file_lines = text.readlines()
1597
            assert sha_strings(file_lines) == ie.text_sha1
1598
            assert sum(map(len, file_lines)) == ie.text_size
1563.2.18 by Robert Collins
get knit repositories really using knits for text storage.
1599
            w.add_lines(rev_id, previous_revisions, file_lines)
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
1600
            self.text_count += 1
1601
        else:
1563.2.18 by Robert Collins
get knit repositories really using knits for text storage.
1602
            w.add_lines(rev_id, previous_revisions, [])
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
1603
        ie.revision = rev_id
1604
1605
    def _make_order(self):
1606
        """Return a suitable order for importing revisions.
1607
1608
        The order must be such that an revision is imported after all
1609
        its (present) parents.
1610
        """
1611
        todo = set(self.revisions.keys())
1612
        done = self.absent_revisions.copy()
1534.5.11 by Robert Collins
Implement upgrades to Metaformat trees.
1613
        order = []
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
1614
        while todo:
1615
            # scan through looking for a revision whose parents
1616
            # are all done
1617
            for rev_id in sorted(list(todo)):
1618
                rev = self.revisions[rev_id]
1619
                parent_ids = set(rev.parent_ids)
1620
                if parent_ids.issubset(done):
1621
                    # can take this one now
1534.5.11 by Robert Collins
Implement upgrades to Metaformat trees.
1622
                    order.append(rev_id)
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
1623
                    todo.remove(rev_id)
1624
                    done.add(rev_id)
1534.5.11 by Robert Collins
Implement upgrades to Metaformat trees.
1625
        return order
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
1626
1627
1628
class ConvertBzrDir5To6(Converter):
1629
    """Converts format 5 bzr dirs to format 6."""
1630
1534.5.10 by Robert Collins
Make upgrade driver unaware of the specific formats in play.
1631
    def convert(self, to_convert, pb):
1632
        """See Converter.convert()."""
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
1633
        self.bzrdir = to_convert
1534.5.10 by Robert Collins
Make upgrade driver unaware of the specific formats in play.
1634
        self.pb = pb
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
1635
        self.pb.note('starting upgrade from format 5 to 6')
1636
        self._convert_to_prefixed()
1637
        return BzrDir.open(self.bzrdir.root_transport.base)
1638
1639
    def _convert_to_prefixed(self):
1608.2.1 by Martin Pool
[merge] Storage filename escaping
1640
        from bzrlib.store import TransportStore
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
1641
        self.bzrdir.transport.delete('branch-format')
1642
        for store_name in ["weaves", "revision-store"]:
1608.2.1 by Martin Pool
[merge] Storage filename escaping
1643
            self.pb.note("adding prefixes to %s" % store_name)
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
1644
            store_transport = self.bzrdir.transport.clone(store_name)
1608.2.1 by Martin Pool
[merge] Storage filename escaping
1645
            store = TransportStore(store_transport, prefixed=True)
1608.1.1 by Martin Pool
[patch] LocalTransport.list_dir should return url-quoted strings (ddaa)
1646
            for urlfilename in store_transport.list_dir('.'):
1647
                filename = urlunescape(urlfilename)
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
1648
                if (filename.endswith(".weave") or
1649
                    filename.endswith(".gz") or
1650
                    filename.endswith(".sig")):
1651
                    file_id = os.path.splitext(filename)[0]
1652
                else:
1653
                    file_id = filename
1608.2.1 by Martin Pool
[merge] Storage filename escaping
1654
                prefix_dir = store.hash_prefix(file_id)
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
1655
                # FIXME keep track of the dirs made RBC 20060121
1656
                try:
1657
                    store_transport.move(filename, prefix_dir + '/' + filename)
1658
                except errors.NoSuchFile: # catches missing dirs strangely enough
1659
                    store_transport.mkdir(prefix_dir)
1660
                    store_transport.move(filename, prefix_dir + '/' + filename)
1661
        self.bzrdir._control_files.put_utf8('branch-format', BzrDirFormat6().get_format_string())
1662
1663
1534.5.10 by Robert Collins
Make upgrade driver unaware of the specific formats in play.
1664
class ConvertBzrDir6ToMeta(Converter):
1665
    """Converts format 6 bzr dirs to metadirs."""
1666
1667
    def convert(self, to_convert, pb):
1668
        """See Converter.convert()."""
1669
        self.bzrdir = to_convert
1670
        self.pb = pb
1534.5.11 by Robert Collins
Implement upgrades to Metaformat trees.
1671
        self.count = 0
1672
        self.total = 20 # the steps we know about
1673
        self.garbage_inventories = []
1674
1534.5.13 by Robert Collins
Correct buggy test.
1675
        self.pb.note('starting upgrade from format 6 to metadir')
1534.5.11 by Robert Collins
Implement upgrades to Metaformat trees.
1676
        self.bzrdir._control_files.put_utf8('branch-format', "Converting to format 6")
1677
        # its faster to move specific files around than to open and use the apis...
1678
        # first off, nuke ancestry.weave, it was never used.
1679
        try:
1680
            self.step('Removing ancestry.weave')
1681
            self.bzrdir.transport.delete('ancestry.weave')
1682
        except errors.NoSuchFile:
1683
            pass
1684
        # find out whats there
1685
        self.step('Finding branch files')
1666.1.3 by Robert Collins
Fix and test upgrades from bzrdir 6 over SFTP.
1686
        last_revision = self.bzrdir.open_branch().last_revision()
1534.5.11 by Robert Collins
Implement upgrades to Metaformat trees.
1687
        bzrcontents = self.bzrdir.transport.list_dir('.')
1688
        for name in bzrcontents:
1689
            if name.startswith('basis-inventory.'):
1690
                self.garbage_inventories.append(name)
1691
        # create new directories for repository, working tree and branch
1553.5.79 by Martin Pool
upgrade to metadir should create LockDirs not files
1692
        self.dir_mode = self.bzrdir._control_files._dir_mode
1534.5.11 by Robert Collins
Implement upgrades to Metaformat trees.
1693
        self.file_mode = self.bzrdir._control_files._file_mode
1694
        repository_names = [('inventory.weave', True),
1695
                            ('revision-store', True),
1696
                            ('weaves', True)]
1697
        self.step('Upgrading repository  ')
1553.5.79 by Martin Pool
upgrade to metadir should create LockDirs not files
1698
        self.bzrdir.transport.mkdir('repository', mode=self.dir_mode)
1534.5.11 by Robert Collins
Implement upgrades to Metaformat trees.
1699
        self.make_lock('repository')
1700
        # we hard code the formats here because we are converting into
1701
        # the meta format. The meta format upgrader can take this to a 
1702
        # future format within each component.
1703
        self.put_format('repository', bzrlib.repository.RepositoryFormat7())
1704
        for entry in repository_names:
1705
            self.move_entry('repository', entry)
1706
1707
        self.step('Upgrading branch      ')
1553.5.79 by Martin Pool
upgrade to metadir should create LockDirs not files
1708
        self.bzrdir.transport.mkdir('branch', mode=self.dir_mode)
1534.5.11 by Robert Collins
Implement upgrades to Metaformat trees.
1709
        self.make_lock('branch')
1710
        self.put_format('branch', bzrlib.branch.BzrBranchFormat5())
1711
        branch_files = [('revision-history', True),
1712
                        ('branch-name', True),
1713
                        ('parent', False)]
1714
        for entry in branch_files:
1715
            self.move_entry('branch', entry)
1716
1717
        self.step('Upgrading working tree')
1553.5.79 by Martin Pool
upgrade to metadir should create LockDirs not files
1718
        self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
1534.5.11 by Robert Collins
Implement upgrades to Metaformat trees.
1719
        self.make_lock('checkout')
1720
        self.put_format('checkout', bzrlib.workingtree.WorkingTreeFormat3())
1721
        self.bzrdir.transport.delete_multi(self.garbage_inventories, self.pb)
1722
        checkout_files = [('pending-merges', True),
1723
                          ('inventory', True),
1724
                          ('stat-cache', False)]
1725
        for entry in checkout_files:
1726
            self.move_entry('checkout', entry)
1534.5.14 by Robert Collins
Bugfix upgrades to metadir to set the last-revision correctly.
1727
        if last_revision is not None:
1728
            self.bzrdir._control_files.put_utf8('checkout/last-revision',
1729
                                                last_revision)
1534.5.11 by Robert Collins
Implement upgrades to Metaformat trees.
1730
        self.bzrdir._control_files.put_utf8('branch-format', BzrDirMetaFormat1().get_format_string())
1534.5.10 by Robert Collins
Make upgrade driver unaware of the specific formats in play.
1731
        return BzrDir.open(self.bzrdir.root_transport.base)
1732
1534.5.11 by Robert Collins
Implement upgrades to Metaformat trees.
1733
    def make_lock(self, name):
1734
        """Make a lock for the new control dir name."""
1735
        self.step('Make %s lock' % name)
1553.5.79 by Martin Pool
upgrade to metadir should create LockDirs not files
1736
        ld = LockDir(self.bzrdir.transport, 
1737
                     '%s/lock' % name,
1738
                     file_modebits=self.file_mode,
1739
                     dir_modebits=self.dir_mode)
1740
        ld.create()
1534.5.11 by Robert Collins
Implement upgrades to Metaformat trees.
1741
1742
    def move_entry(self, new_dir, entry):
1743
        """Move then entry name into new_dir."""
1744
        name = entry[0]
1745
        mandatory = entry[1]
1746
        self.step('Moving %s' % name)
1747
        try:
1748
            self.bzrdir.transport.move(name, '%s/%s' % (new_dir, name))
1749
        except errors.NoSuchFile:
1750
            if mandatory:
1751
                raise
1752
1753
    def put_format(self, dirname, format):
1754
        self.bzrdir._control_files.put_utf8('%s/format' % dirname, format.get_format_string())
1755
1556.1.4 by Robert Collins
Add a new format for what will become knit, and the surrounding logic to upgrade repositories within metadirs, and tests for the same.
1756
1757
class ConvertMetaToMeta(Converter):
1758
    """Converts the components of metadirs."""
1759
1760
    def __init__(self, target_format):
1761
        """Create a metadir to metadir converter.
1762
1763
        :param target_format: The final metadir format that is desired.
1764
        """
1765
        self.target_format = target_format
1766
1767
    def convert(self, to_convert, pb):
1768
        """See Converter.convert()."""
1769
        self.bzrdir = to_convert
1770
        self.pb = pb
1771
        self.count = 0
1772
        self.total = 1
1773
        self.step('checking repository format')
1774
        try:
1775
            repo = self.bzrdir.open_repository()
1776
        except errors.NoRepositoryPresent:
1777
            pass
1778
        else:
1779
            if not isinstance(repo._format, self.target_format.repository_format.__class__):
1780
                from bzrlib.repository import CopyConverter
1781
                self.pb.note('starting repository conversion')
1782
                converter = CopyConverter(self.target_format.repository_format)
1783
                converter.convert(repo, pb)
1784
        return to_convert