/brz/remove-bazaar

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

« back to all changes in this revision

Viewing changes to bzrlib/bzrdir.py

Merge up bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 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
Note: This module has a lot of ``open`` functions/methods that return
 
23
references to in-memory objects. As a rule, there are no matching ``close``
 
24
methods. To free any associated resources, simply stop referencing the
 
25
objects returned.
 
26
"""
 
27
 
 
28
# TODO: Move old formats into a plugin to make this file smaller.
 
29
 
 
30
from cStringIO import StringIO
 
31
import os
 
32
import sys
 
33
 
 
34
from bzrlib.lazy_import import lazy_import
 
35
lazy_import(globals(), """
 
36
from stat import S_ISDIR
 
37
import textwrap
 
38
from warnings import warn
 
39
 
 
40
import bzrlib
 
41
from bzrlib import (
 
42
    errors,
 
43
    graph,
 
44
    lockable_files,
 
45
    lockdir,
 
46
    osutils,
 
47
    registry,
 
48
    remote,
 
49
    revision as _mod_revision,
 
50
    symbol_versioning,
 
51
    ui,
 
52
    urlutils,
 
53
    win32utils,
 
54
    workingtree,
 
55
    workingtree_4,
 
56
    xml4,
 
57
    xml5,
 
58
    )
 
59
from bzrlib.osutils import (
 
60
    sha_strings,
 
61
    sha_string,
 
62
    )
 
63
from bzrlib.smart.client import _SmartClient
 
64
from bzrlib.smart import protocol
 
65
from bzrlib.store.revision.text import TextRevisionStore
 
66
from bzrlib.store.text import TextStore
 
67
from bzrlib.store.versioned import WeaveStore
 
68
from bzrlib.transactions import WriteTransaction
 
69
from bzrlib.transport import (
 
70
    do_catching_redirections,
 
71
    get_transport,
 
72
    )
 
73
from bzrlib.weave import Weave
 
74
""")
 
75
 
 
76
from bzrlib.trace import (
 
77
    mutter,
 
78
    note,
 
79
    )
 
80
from bzrlib.transport.local import LocalTransport
 
81
from bzrlib.symbol_versioning import (
 
82
    deprecated_function,
 
83
    deprecated_method,
 
84
    )
 
85
 
 
86
 
 
87
class BzrDir(object):
 
88
    """A .bzr control diretory.
 
89
    
 
90
    BzrDir instances let you create or open any of the things that can be
 
91
    found within .bzr - checkouts, branches and repositories.
 
92
    
 
93
    transport
 
94
        the transport which this bzr dir is rooted at (i.e. file:///.../.bzr/)
 
95
    root_transport
 
96
        a transport connected to the directory this bzr was opened from
 
97
        (i.e. the parent directory holding the .bzr directory).
 
98
    """
 
99
 
 
100
    def break_lock(self):
 
101
        """Invoke break_lock on the first object in the bzrdir.
 
102
 
 
103
        If there is a tree, the tree is opened and break_lock() called.
 
104
        Otherwise, branch is tried, and finally repository.
 
105
        """
 
106
        # XXX: This seems more like a UI function than something that really
 
107
        # belongs in this class.
 
108
        try:
 
109
            thing_to_unlock = self.open_workingtree()
 
110
        except (errors.NotLocalUrl, errors.NoWorkingTree):
 
111
            try:
 
112
                thing_to_unlock = self.open_branch()
 
113
            except errors.NotBranchError:
 
114
                try:
 
115
                    thing_to_unlock = self.open_repository()
 
116
                except errors.NoRepositoryPresent:
 
117
                    return
 
118
        thing_to_unlock.break_lock()
 
119
 
 
120
    def can_convert_format(self):
 
121
        """Return true if this bzrdir is one whose format we can convert from."""
 
122
        return True
 
123
 
 
124
    def check_conversion_target(self, target_format):
 
125
        target_repo_format = target_format.repository_format
 
126
        source_repo_format = self._format.repository_format
 
127
        source_repo_format.check_conversion_target(target_repo_format)
 
128
 
 
129
    @staticmethod
 
130
    def _check_supported(format, allow_unsupported,
 
131
        recommend_upgrade=True,
 
132
        basedir=None):
 
133
        """Give an error or warning on old formats.
 
134
 
 
135
        :param format: may be any kind of format - workingtree, branch, 
 
136
        or repository.
 
137
 
 
138
        :param allow_unsupported: If true, allow opening 
 
139
        formats that are strongly deprecated, and which may 
 
140
        have limited functionality.
 
141
 
 
142
        :param recommend_upgrade: If true (default), warn
 
143
        the user through the ui object that they may wish
 
144
        to upgrade the object.
 
145
        """
 
146
        # TODO: perhaps move this into a base Format class; it's not BzrDir
 
147
        # specific. mbp 20070323
 
148
        if not allow_unsupported and not format.is_supported():
 
149
            # see open_downlevel to open legacy branches.
 
150
            raise errors.UnsupportedFormatError(format=format)
 
151
        if recommend_upgrade \
 
152
            and getattr(format, 'upgrade_recommended', False):
 
153
            ui.ui_factory.recommend_upgrade(
 
154
                format.get_format_description(),
 
155
                basedir)
 
156
 
 
157
    def clone(self, url, revision_id=None, force_new_repo=False):
 
158
        """Clone this bzrdir and its contents to url verbatim.
 
159
 
 
160
        If url's last component does not exist, it will be created.
 
161
 
 
162
        if revision_id is not None, then the clone operation may tune
 
163
            itself to download less data.
 
164
        :param force_new_repo: Do not use a shared repository for the target 
 
165
                               even if one is available.
 
166
        """
 
167
        return self.clone_on_transport(get_transport(url),
 
168
                                       revision_id=revision_id,
 
169
                                       force_new_repo=force_new_repo)
 
170
 
 
171
    def clone_on_transport(self, transport, revision_id=None,
 
172
                           force_new_repo=False):
 
173
        """Clone this bzrdir and its contents to transport verbatim.
 
174
 
 
175
        If the target directory does not exist, it will be created.
 
176
 
 
177
        if revision_id is not None, then the clone operation may tune
 
178
            itself to download less data.
 
179
        :param force_new_repo: Do not use a shared repository for the target 
 
180
                               even if one is available.
 
181
        """
 
182
        transport.ensure_base()
 
183
        result = self.cloning_metadir().initialize_on_transport(transport)
 
184
        repository_policy = None
 
185
        try:
 
186
            local_repo = self.find_repository()
 
187
        except errors.NoRepositoryPresent:
 
188
            local_repo = None
 
189
        if local_repo:
 
190
            # may need to copy content in
 
191
            repository_policy = result.determine_repository_policy(
 
192
                force_new_repo)
 
193
            make_working_trees = local_repo.make_working_trees()
 
194
            result_repo = repository_policy.acquire_repository(
 
195
                make_working_trees, local_repo.is_shared())
 
196
            result_repo.fetch(local_repo, revision_id=revision_id)
 
197
        # 1 if there is a branch present
 
198
        #   make sure its content is available in the target repository
 
199
        #   clone it.
 
200
        try:
 
201
            local_branch = self.open_branch()
 
202
        except errors.NotBranchError:
 
203
            pass
 
204
        else:
 
205
            result_branch = local_branch.clone(result, revision_id=revision_id)
 
206
            if repository_policy is not None:
 
207
                repository_policy.configure_branch(result_branch)
 
208
        try:
 
209
            result_repo = result.find_repository()
 
210
        except errors.NoRepositoryPresent:
 
211
            result_repo = None
 
212
        if result_repo is None or result_repo.make_working_trees():
 
213
            try:
 
214
                self.open_workingtree().clone(result)
 
215
            except (errors.NoWorkingTree, errors.NotLocalUrl):
 
216
                pass
 
217
        return result
 
218
 
 
219
    # TODO: This should be given a Transport, and should chdir up; otherwise
 
220
    # this will open a new connection.
 
221
    def _make_tail(self, url):
 
222
        t = get_transport(url)
 
223
        t.ensure_base()
 
224
 
 
225
    @classmethod
 
226
    def create(cls, base, format=None, possible_transports=None):
 
227
        """Create a new BzrDir at the url 'base'.
 
228
        
 
229
        :param format: If supplied, the format of branch to create.  If not
 
230
            supplied, the default is used.
 
231
        :param possible_transports: If supplied, a list of transports that 
 
232
            can be reused to share a remote connection.
 
233
        """
 
234
        if cls is not BzrDir:
 
235
            raise AssertionError("BzrDir.create always creates the default"
 
236
                " format, not one of %r" % cls)
 
237
        t = get_transport(base, possible_transports)
 
238
        t.ensure_base()
 
239
        if format is None:
 
240
            format = BzrDirFormat.get_default_format()
 
241
        return format.initialize_on_transport(t)
 
242
 
 
243
    @staticmethod
 
244
    def find_bzrdirs(transport, evaluate=None, list_current=None):
 
245
        """Find bzrdirs recursively from current location.
 
246
 
 
247
        This is intended primarily as a building block for more sophisticated
 
248
        functionality, like finding trees under a directory, or finding
 
249
        branches that use a given repository.
 
250
        :param evaluate: An optional callable that yields recurse, value,
 
251
            where recurse controls whether this bzrdir is recursed into
 
252
            and value is the value to yield.  By default, all bzrdirs
 
253
            are recursed into, and the return value is the bzrdir.
 
254
        :param list_current: if supplied, use this function to list the current
 
255
            directory, instead of Transport.list_dir
 
256
        :return: a generator of found bzrdirs, or whatever evaluate returns.
 
257
        """
 
258
        if list_current is None:
 
259
            def list_current(transport):
 
260
                return transport.list_dir('')
 
261
        if evaluate is None:
 
262
            def evaluate(bzrdir):
 
263
                return True, bzrdir
 
264
 
 
265
        pending = [transport]
 
266
        while len(pending) > 0:
 
267
            current_transport = pending.pop()
 
268
            recurse = True
 
269
            try:
 
270
                bzrdir = BzrDir.open_from_transport(current_transport)
 
271
            except errors.NotBranchError:
 
272
                pass
 
273
            else:
 
274
                recurse, value = evaluate(bzrdir)
 
275
                yield value
 
276
            try:
 
277
                subdirs = list_current(current_transport)
 
278
            except errors.NoSuchFile:
 
279
                continue
 
280
            if recurse:
 
281
                for subdir in sorted(subdirs, reverse=True):
 
282
                    pending.append(current_transport.clone(subdir))
 
283
 
 
284
    @staticmethod
 
285
    def find_branches(transport):
 
286
        """Find all branches under a transport.
 
287
 
 
288
        This will find all branches below the transport, including branches
 
289
        inside other branches.  Where possible, it will use
 
290
        Repository.find_branches.
 
291
 
 
292
        To list all the branches that use a particular Repository, see
 
293
        Repository.find_branches
 
294
        """
 
295
        def evaluate(bzrdir):
 
296
            try:
 
297
                repository = bzrdir.open_repository()
 
298
            except errors.NoRepositoryPresent:
 
299
                pass
 
300
            else:
 
301
                return False, (None, repository)
 
302
            try:
 
303
                branch = bzrdir.open_branch()
 
304
            except errors.NotBranchError:
 
305
                return True, (None, None)
 
306
            else:
 
307
                return True, (branch, None)
 
308
        branches = []
 
309
        for branch, repo in BzrDir.find_bzrdirs(transport, evaluate=evaluate):
 
310
            if repo is not None:
 
311
                branches.extend(repo.find_branches())
 
312
            if branch is not None:
 
313
                branches.append(branch)
 
314
        return branches
 
315
 
 
316
 
 
317
    def destroy_repository(self):
 
318
        """Destroy the repository in this BzrDir"""
 
319
        raise NotImplementedError(self.destroy_repository)
 
320
 
 
321
    def create_branch(self):
 
322
        """Create a branch in this BzrDir.
 
323
 
 
324
        The bzrdir's format will control what branch format is created.
 
325
        For more control see BranchFormatXX.create(a_bzrdir).
 
326
        """
 
327
        raise NotImplementedError(self.create_branch)
 
328
 
 
329
    def destroy_branch(self):
 
330
        """Destroy the branch in this BzrDir"""
 
331
        raise NotImplementedError(self.destroy_branch)
 
332
 
 
333
    @staticmethod
 
334
    def create_branch_and_repo(base, force_new_repo=False, format=None):
 
335
        """Create a new BzrDir, Branch and Repository at the url 'base'.
 
336
 
 
337
        This will use the current default BzrDirFormat unless one is
 
338
        specified, and use whatever 
 
339
        repository format that that uses via bzrdir.create_branch and
 
340
        create_repository. If a shared repository is available that is used
 
341
        preferentially.
 
342
 
 
343
        The created Branch object is returned.
 
344
 
 
345
        :param base: The URL to create the branch at.
 
346
        :param force_new_repo: If True a new repository is always created.
 
347
        :param format: If supplied, the format of branch to create.  If not
 
348
            supplied, the default is used.
 
349
        """
 
350
        bzrdir = BzrDir.create(base, format)
 
351
        bzrdir._find_or_create_repository(force_new_repo)
 
352
        return bzrdir.create_branch()
 
353
 
 
354
    def determine_repository_policy(self, force_new_repo=False):
 
355
        """Return an object representing a policy to use.
 
356
 
 
357
        This controls whether a new repository is created, or a shared
 
358
        repository used instead.
 
359
        """
 
360
        def repository_policy(found_bzrdir):
 
361
            stop = False
 
362
            # does it have a repository ?
 
363
            try:
 
364
                repository = found_bzrdir.open_repository()
 
365
            except errors.NoRepositoryPresent:
 
366
                repository = None
 
367
            else:
 
368
                if ((found_bzrdir.root_transport.base !=
 
369
                     self.root_transport.base) and not repository.is_shared()):
 
370
                    repository = None
 
371
                else:
 
372
                    stop = True
 
373
            if not stop:
 
374
                return None, False
 
375
            if repository:
 
376
                return UseExistingRepository(repository), True
 
377
            else:
 
378
                return CreateRepository(self), True
 
379
 
 
380
        if not force_new_repo:
 
381
            policy = self._find_containing(repository_policy)
 
382
            if policy is not None:
 
383
                return policy
 
384
        return CreateRepository(self)
 
385
 
 
386
    def _find_or_create_repository(self, force_new_repo):
 
387
        """Create a new repository if needed, returning the repository."""
 
388
        policy = self.determine_repository_policy(force_new_repo)
 
389
        return policy.acquire_repository()
 
390
 
 
391
    @staticmethod
 
392
    def create_branch_convenience(base, force_new_repo=False,
 
393
                                  force_new_tree=None, format=None,
 
394
                                  possible_transports=None):
 
395
        """Create a new BzrDir, Branch and Repository at the url 'base'.
 
396
 
 
397
        This is a convenience function - it will use an existing repository
 
398
        if possible, can be told explicitly whether to create a working tree or
 
399
        not.
 
400
 
 
401
        This will use the current default BzrDirFormat unless one is
 
402
        specified, and use whatever 
 
403
        repository format that that uses via bzrdir.create_branch and
 
404
        create_repository. If a shared repository is available that is used
 
405
        preferentially. Whatever repository is used, its tree creation policy
 
406
        is followed.
 
407
 
 
408
        The created Branch object is returned.
 
409
        If a working tree cannot be made due to base not being a file:// url,
 
410
        no error is raised unless force_new_tree is True, in which case no 
 
411
        data is created on disk and NotLocalUrl is raised.
 
412
 
 
413
        :param base: The URL to create the branch at.
 
414
        :param force_new_repo: If True a new repository is always created.
 
415
        :param force_new_tree: If True or False force creation of a tree or 
 
416
                               prevent such creation respectively.
 
417
        :param format: Override for the bzrdir format to create.
 
418
        :param possible_transports: An optional reusable transports list.
 
419
        """
 
420
        if force_new_tree:
 
421
            # check for non local urls
 
422
            t = get_transport(base, possible_transports)
 
423
            if not isinstance(t, LocalTransport):
 
424
                raise errors.NotLocalUrl(base)
 
425
        bzrdir = BzrDir.create(base, format, possible_transports)
 
426
        repo = bzrdir._find_or_create_repository(force_new_repo)
 
427
        result = bzrdir.create_branch()
 
428
        if force_new_tree or (repo.make_working_trees() and
 
429
                              force_new_tree is None):
 
430
            try:
 
431
                bzrdir.create_workingtree()
 
432
            except errors.NotLocalUrl:
 
433
                pass
 
434
        return result
 
435
 
 
436
    @staticmethod
 
437
    def create_standalone_workingtree(base, format=None):
 
438
        """Create a new BzrDir, WorkingTree, Branch and Repository at 'base'.
 
439
 
 
440
        'base' must be a local path or a file:// url.
 
441
 
 
442
        This will use the current default BzrDirFormat unless one is
 
443
        specified, and use whatever 
 
444
        repository format that that uses for bzrdirformat.create_workingtree,
 
445
        create_branch and create_repository.
 
446
 
 
447
        :param format: Override for the bzrdir format to create.
 
448
        :return: The WorkingTree object.
 
449
        """
 
450
        t = get_transport(base)
 
451
        if not isinstance(t, LocalTransport):
 
452
            raise errors.NotLocalUrl(base)
 
453
        bzrdir = BzrDir.create_branch_and_repo(base,
 
454
                                               force_new_repo=True,
 
455
                                               format=format).bzrdir
 
456
        return bzrdir.create_workingtree()
 
457
 
 
458
    def create_workingtree(self, revision_id=None, from_branch=None,
 
459
        accelerator_tree=None, hardlink=False):
 
460
        """Create a working tree at this BzrDir.
 
461
        
 
462
        :param revision_id: create it as of this revision id.
 
463
        :param from_branch: override bzrdir branch (for lightweight checkouts)
 
464
        :param accelerator_tree: A tree which can be used for retrieving file
 
465
            contents more quickly than the revision tree, i.e. a workingtree.
 
466
            The revision tree will be used for cases where accelerator_tree's
 
467
            content is different.
 
468
        """
 
469
        raise NotImplementedError(self.create_workingtree)
 
470
 
 
471
    def retire_bzrdir(self, limit=10000):
 
472
        """Permanently disable the bzrdir.
 
473
 
 
474
        This is done by renaming it to give the user some ability to recover
 
475
        if there was a problem.
 
476
 
 
477
        This will have horrible consequences if anyone has anything locked or
 
478
        in use.
 
479
        :param limit: number of times to retry
 
480
        """
 
481
        i  = 0
 
482
        while True:
 
483
            try:
 
484
                to_path = '.bzr.retired.%d' % i
 
485
                self.root_transport.rename('.bzr', to_path)
 
486
                note("renamed %s to %s"
 
487
                    % (self.root_transport.abspath('.bzr'), to_path))
 
488
                return
 
489
            except (errors.TransportError, IOError, errors.PathError):
 
490
                i += 1
 
491
                if i > limit:
 
492
                    raise
 
493
                else:
 
494
                    pass
 
495
 
 
496
    def destroy_workingtree(self):
 
497
        """Destroy the working tree at this BzrDir.
 
498
 
 
499
        Formats that do not support this may raise UnsupportedOperation.
 
500
        """
 
501
        raise NotImplementedError(self.destroy_workingtree)
 
502
 
 
503
    def destroy_workingtree_metadata(self):
 
504
        """Destroy the control files for the working tree at this BzrDir.
 
505
 
 
506
        The contents of working tree files are not affected.
 
507
        Formats that do not support this may raise UnsupportedOperation.
 
508
        """
 
509
        raise NotImplementedError(self.destroy_workingtree_metadata)
 
510
 
 
511
    def _find_containing(self, evaluate):
 
512
        """Find something in a containing control directory.
 
513
 
 
514
        This method will scan containing control dirs, until it finds what
 
515
        it is looking for, decides that it will never find it, or runs out
 
516
        of containing control directories to check.
 
517
 
 
518
        It is used to implement find_repository and
 
519
        determine_repository_policy.
 
520
 
 
521
        :param evaluate: A function returning (value, stop).  If stop is True,
 
522
            the value will be returned.
 
523
        """
 
524
        found_bzrdir = self
 
525
        while True:
 
526
            result, stop = evaluate(found_bzrdir)
 
527
            if stop:
 
528
                return result
 
529
            next_transport = found_bzrdir.root_transport.clone('..')
 
530
            if (found_bzrdir.root_transport.base == next_transport.base):
 
531
                # top of the file system
 
532
                return None
 
533
            # find the next containing bzrdir
 
534
            try:
 
535
                found_bzrdir = BzrDir.open_containing_from_transport(
 
536
                    next_transport)[0]
 
537
            except errors.NotBranchError:
 
538
                return None
 
539
 
 
540
    def find_repository(self):
 
541
        """Find the repository that should be used.
 
542
 
 
543
        This does not require a branch as we use it to find the repo for
 
544
        new branches as well as to hook existing branches up to their
 
545
        repository.
 
546
        """
 
547
        def usable_repository(found_bzrdir):
 
548
            # does it have a repository ?
 
549
            try:
 
550
                repository = found_bzrdir.open_repository()
 
551
            except errors.NoRepositoryPresent:
 
552
                return None, False
 
553
            if found_bzrdir.root_transport.base == self.root_transport.base:
 
554
                return repository, True
 
555
            elif repository.is_shared():
 
556
                return repository, True
 
557
            else:
 
558
                return None, True
 
559
 
 
560
        found_repo = self._find_containing(usable_repository)
 
561
        if found_repo is None:
 
562
            raise errors.NoRepositoryPresent(self)
 
563
        return found_repo
 
564
 
 
565
    def get_branch_reference(self):
 
566
        """Return the referenced URL for the branch in this bzrdir.
 
567
 
 
568
        :raises NotBranchError: If there is no Branch.
 
569
        :return: The URL the branch in this bzrdir references if it is a
 
570
            reference branch, or None for regular branches.
 
571
        """
 
572
        return None
 
573
 
 
574
    def get_branch_transport(self, branch_format):
 
575
        """Get the transport for use by branch format in this BzrDir.
 
576
 
 
577
        Note that bzr dirs that do not support format strings will raise
 
578
        IncompatibleFormat if the branch format they are given has
 
579
        a format string, and vice versa.
 
580
 
 
581
        If branch_format is None, the transport is returned with no 
 
582
        checking. If it is not None, then the returned transport is
 
583
        guaranteed to point to an existing directory ready for use.
 
584
        """
 
585
        raise NotImplementedError(self.get_branch_transport)
 
586
        
 
587
    def get_repository_transport(self, repository_format):
 
588
        """Get the transport for use by repository format in this BzrDir.
 
589
 
 
590
        Note that bzr dirs that do not support format strings will raise
 
591
        IncompatibleFormat if the repository format they are given has
 
592
        a format string, and vice versa.
 
593
 
 
594
        If repository_format is None, the transport is returned with no 
 
595
        checking. If it is not None, then the returned transport is
 
596
        guaranteed to point to an existing directory ready for use.
 
597
        """
 
598
        raise NotImplementedError(self.get_repository_transport)
 
599
        
 
600
    def get_workingtree_transport(self, tree_format):
 
601
        """Get the transport for use by workingtree format in this BzrDir.
 
602
 
 
603
        Note that bzr dirs that do not support format strings will raise
 
604
        IncompatibleFormat if the workingtree format they are given has a
 
605
        format string, and vice versa.
 
606
 
 
607
        If workingtree_format is None, the transport is returned with no 
 
608
        checking. If it is not None, then the returned transport is
 
609
        guaranteed to point to an existing directory ready for use.
 
610
        """
 
611
        raise NotImplementedError(self.get_workingtree_transport)
 
612
        
 
613
    def __init__(self, _transport, _format):
 
614
        """Initialize a Bzr control dir object.
 
615
        
 
616
        Only really common logic should reside here, concrete classes should be
 
617
        made with varying behaviours.
 
618
 
 
619
        :param _format: the format that is creating this BzrDir instance.
 
620
        :param _transport: the transport this dir is based at.
 
621
        """
 
622
        self._format = _format
 
623
        self.transport = _transport.clone('.bzr')
 
624
        self.root_transport = _transport
 
625
 
 
626
    def is_control_filename(self, filename):
 
627
        """True if filename is the name of a path which is reserved for bzrdir's.
 
628
        
 
629
        :param filename: A filename within the root transport of this bzrdir.
 
630
 
 
631
        This is true IF and ONLY IF the filename is part of the namespace reserved
 
632
        for bzr control dirs. Currently this is the '.bzr' directory in the root
 
633
        of the root_transport. it is expected that plugins will need to extend
 
634
        this in the future - for instance to make bzr talk with svn working
 
635
        trees.
 
636
        """
 
637
        # this might be better on the BzrDirFormat class because it refers to 
 
638
        # all the possible bzrdir disk formats. 
 
639
        # This method is tested via the workingtree is_control_filename tests- 
 
640
        # it was extracted from WorkingTree.is_control_filename. If the method's
 
641
        # contract is extended beyond the current trivial implementation, please
 
642
        # add new tests for it to the appropriate place.
 
643
        return filename == '.bzr' or filename.startswith('.bzr/')
 
644
 
 
645
    def needs_format_conversion(self, format=None):
 
646
        """Return true if this bzrdir needs convert_format run on it.
 
647
        
 
648
        For instance, if the repository format is out of date but the 
 
649
        branch and working tree are not, this should return True.
 
650
 
 
651
        :param format: Optional parameter indicating a specific desired
 
652
                       format we plan to arrive at.
 
653
        """
 
654
        raise NotImplementedError(self.needs_format_conversion)
 
655
 
 
656
    @staticmethod
 
657
    def open_unsupported(base):
 
658
        """Open a branch which is not supported."""
 
659
        return BzrDir.open(base, _unsupported=True)
 
660
        
 
661
    @staticmethod
 
662
    def open(base, _unsupported=False, possible_transports=None):
 
663
        """Open an existing bzrdir, rooted at 'base' (url).
 
664
        
 
665
        :param _unsupported: a private parameter to the BzrDir class.
 
666
        """
 
667
        t = get_transport(base, possible_transports=possible_transports)
 
668
        return BzrDir.open_from_transport(t, _unsupported=_unsupported)
 
669
 
 
670
    @staticmethod
 
671
    def open_from_transport(transport, _unsupported=False,
 
672
                            _server_formats=True):
 
673
        """Open a bzrdir within a particular directory.
 
674
 
 
675
        :param transport: Transport containing the bzrdir.
 
676
        :param _unsupported: private.
 
677
        """
 
678
        base = transport.base
 
679
 
 
680
        def find_format(transport):
 
681
            return transport, BzrDirFormat.find_format(
 
682
                transport, _server_formats=_server_formats)
 
683
 
 
684
        def redirected(transport, e, redirection_notice):
 
685
            qualified_source = e.get_source_url()
 
686
            relpath = transport.relpath(qualified_source)
 
687
            if not e.target.endswith(relpath):
 
688
                # Not redirected to a branch-format, not a branch
 
689
                raise errors.NotBranchError(path=e.target)
 
690
            target = e.target[:-len(relpath)]
 
691
            note('%s is%s redirected to %s',
 
692
                 transport.base, e.permanently, target)
 
693
            # Let's try with a new transport
 
694
            # FIXME: If 'transport' has a qualifier, this should
 
695
            # be applied again to the new transport *iff* the
 
696
            # schemes used are the same. Uncomment this code
 
697
            # once the function (and tests) exist.
 
698
            # -- vila20070212
 
699
            #target = urlutils.copy_url_qualifiers(original, target)
 
700
            return get_transport(target)
 
701
 
 
702
        try:
 
703
            transport, format = do_catching_redirections(find_format,
 
704
                                                         transport,
 
705
                                                         redirected)
 
706
        except errors.TooManyRedirections:
 
707
            raise errors.NotBranchError(base)
 
708
 
 
709
        BzrDir._check_supported(format, _unsupported)
 
710
        return format.open(transport, _found=True)
 
711
 
 
712
    def open_branch(self, unsupported=False):
 
713
        """Open the branch object at this BzrDir if one is present.
 
714
 
 
715
        If unsupported is True, then no longer supported branch formats can
 
716
        still be opened.
 
717
        
 
718
        TODO: static convenience version of this?
 
719
        """
 
720
        raise NotImplementedError(self.open_branch)
 
721
 
 
722
    @staticmethod
 
723
    def open_containing(url, possible_transports=None):
 
724
        """Open an existing branch which contains url.
 
725
        
 
726
        :param url: url to search from.
 
727
        See open_containing_from_transport for more detail.
 
728
        """
 
729
        transport = get_transport(url, possible_transports)
 
730
        return BzrDir.open_containing_from_transport(transport)
 
731
    
 
732
    @staticmethod
 
733
    def open_containing_from_transport(a_transport):
 
734
        """Open an existing branch which contains a_transport.base.
 
735
 
 
736
        This probes for a branch at a_transport, and searches upwards from there.
 
737
 
 
738
        Basically we keep looking up until we find the control directory or
 
739
        run into the root.  If there isn't one, raises NotBranchError.
 
740
        If there is one and it is either an unrecognised format or an unsupported 
 
741
        format, UnknownFormatError or UnsupportedFormatError are raised.
 
742
        If there is one, it is returned, along with the unused portion of url.
 
743
 
 
744
        :return: The BzrDir that contains the path, and a Unicode path 
 
745
                for the rest of the URL.
 
746
        """
 
747
        # this gets the normalised url back. I.e. '.' -> the full path.
 
748
        url = a_transport.base
 
749
        while True:
 
750
            try:
 
751
                result = BzrDir.open_from_transport(a_transport)
 
752
                return result, urlutils.unescape(a_transport.relpath(url))
 
753
            except errors.NotBranchError, e:
 
754
                pass
 
755
            try:
 
756
                new_t = a_transport.clone('..')
 
757
            except errors.InvalidURLJoin:
 
758
                # reached the root, whatever that may be
 
759
                raise errors.NotBranchError(path=url)
 
760
            if new_t.base == a_transport.base:
 
761
                # reached the root, whatever that may be
 
762
                raise errors.NotBranchError(path=url)
 
763
            a_transport = new_t
 
764
 
 
765
    def _get_tree_branch(self):
 
766
        """Return the branch and tree, if any, for this bzrdir.
 
767
 
 
768
        Return None for tree if not present or inaccessible.
 
769
        Raise NotBranchError if no branch is present.
 
770
        :return: (tree, branch)
 
771
        """
 
772
        try:
 
773
            tree = self.open_workingtree()
 
774
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
775
            tree = None
 
776
            branch = self.open_branch()
 
777
        else:
 
778
            branch = tree.branch
 
779
        return tree, branch
 
780
 
 
781
    @classmethod
 
782
    def open_tree_or_branch(klass, location):
 
783
        """Return the branch and working tree at a location.
 
784
 
 
785
        If there is no tree at the location, tree will be None.
 
786
        If there is no branch at the location, an exception will be
 
787
        raised
 
788
        :return: (tree, branch)
 
789
        """
 
790
        bzrdir = klass.open(location)
 
791
        return bzrdir._get_tree_branch()
 
792
 
 
793
    @classmethod
 
794
    def open_containing_tree_or_branch(klass, location):
 
795
        """Return the branch and working tree contained by a location.
 
796
 
 
797
        Returns (tree, branch, relpath).
 
798
        If there is no tree at containing the location, tree will be None.
 
799
        If there is no branch containing the location, an exception will be
 
800
        raised
 
801
        relpath is the portion of the path that is contained by the branch.
 
802
        """
 
803
        bzrdir, relpath = klass.open_containing(location)
 
804
        tree, branch = bzrdir._get_tree_branch()
 
805
        return tree, branch, relpath
 
806
 
 
807
    def open_repository(self, _unsupported=False):
 
808
        """Open the repository object at this BzrDir if one is present.
 
809
 
 
810
        This will not follow the Branch object pointer - it's strictly a direct
 
811
        open facility. Most client code should use open_branch().repository to
 
812
        get at a repository.
 
813
 
 
814
        :param _unsupported: a private parameter, not part of the api.
 
815
        TODO: static convenience version of this?
 
816
        """
 
817
        raise NotImplementedError(self.open_repository)
 
818
 
 
819
    def open_workingtree(self, _unsupported=False,
 
820
                         recommend_upgrade=True, from_branch=None):
 
821
        """Open the workingtree object at this BzrDir if one is present.
 
822
 
 
823
        :param recommend_upgrade: Optional keyword parameter, when True (the
 
824
            default), emit through the ui module a recommendation that the user
 
825
            upgrade the working tree when the workingtree being opened is old
 
826
            (but still fully supported).
 
827
        :param from_branch: override bzrdir branch (for lightweight checkouts)
 
828
        """
 
829
        raise NotImplementedError(self.open_workingtree)
 
830
 
 
831
    def has_branch(self):
 
832
        """Tell if this bzrdir contains a branch.
 
833
        
 
834
        Note: if you're going to open the branch, you should just go ahead
 
835
        and try, and not ask permission first.  (This method just opens the 
 
836
        branch and discards it, and that's somewhat expensive.) 
 
837
        """
 
838
        try:
 
839
            self.open_branch()
 
840
            return True
 
841
        except errors.NotBranchError:
 
842
            return False
 
843
 
 
844
    def has_workingtree(self):
 
845
        """Tell if this bzrdir contains a working tree.
 
846
 
 
847
        This will still raise an exception if the bzrdir has a workingtree that
 
848
        is remote & inaccessible.
 
849
        
 
850
        Note: if you're going to open the working tree, you should just go ahead
 
851
        and try, and not ask permission first.  (This method just opens the 
 
852
        workingtree and discards it, and that's somewhat expensive.) 
 
853
        """
 
854
        try:
 
855
            self.open_workingtree(recommend_upgrade=False)
 
856
            return True
 
857
        except errors.NoWorkingTree:
 
858
            return False
 
859
 
 
860
    def _cloning_metadir(self):
 
861
        """Produce a metadir suitable for cloning with."""
 
862
        result_format = self._format.__class__()
 
863
        try:
 
864
            try:
 
865
                branch = self.open_branch()
 
866
                source_repository = branch.repository
 
867
            except errors.NotBranchError:
 
868
                source_branch = None
 
869
                source_repository = self.open_repository()
 
870
        except errors.NoRepositoryPresent:
 
871
            source_repository = None
 
872
        else:
 
873
            # XXX TODO: This isinstance is here because we have not implemented
 
874
            # the fix recommended in bug # 103195 - to delegate this choice the
 
875
            # repository itself.
 
876
            repo_format = source_repository._format
 
877
            if not isinstance(repo_format, remote.RemoteRepositoryFormat):
 
878
                result_format.repository_format = repo_format
 
879
        try:
 
880
            # TODO: Couldn't we just probe for the format in these cases,
 
881
            # rather than opening the whole tree?  It would be a little
 
882
            # faster. mbp 20070401
 
883
            tree = self.open_workingtree(recommend_upgrade=False)
 
884
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
885
            result_format.workingtree_format = None
 
886
        else:
 
887
            result_format.workingtree_format = tree._format.__class__()
 
888
        return result_format, source_repository
 
889
 
 
890
    def cloning_metadir(self):
 
891
        """Produce a metadir suitable for cloning or sprouting with.
 
892
 
 
893
        These operations may produce workingtrees (yes, even though they're
 
894
        "cloning" something that doesn't have a tree), so a viable workingtree
 
895
        format must be selected.
 
896
        """
 
897
        format, repository = self._cloning_metadir()
 
898
        if format._workingtree_format is None:
 
899
            if repository is None:
 
900
                return format
 
901
            tree_format = repository._format._matchingbzrdir.workingtree_format
 
902
            format.workingtree_format = tree_format.__class__()
 
903
        return format
 
904
 
 
905
    def checkout_metadir(self):
 
906
        return self.cloning_metadir()
 
907
 
 
908
    def sprout(self, url, revision_id=None, force_new_repo=False,
 
909
               recurse='down', possible_transports=None,
 
910
               accelerator_tree=None, hardlink=False):
 
911
        """Create a copy of this bzrdir prepared for use as a new line of
 
912
        development.
 
913
 
 
914
        If url's last component does not exist, it will be created.
 
915
 
 
916
        Attributes related to the identity of the source branch like
 
917
        branch nickname will be cleaned, a working tree is created
 
918
        whether one existed before or not; and a local branch is always
 
919
        created.
 
920
 
 
921
        if revision_id is not None, then the clone operation may tune
 
922
            itself to download less data.
 
923
        :param accelerator_tree: A tree which can be used for retrieving file
 
924
            contents more quickly than the revision tree, i.e. a workingtree.
 
925
            The revision tree will be used for cases where accelerator_tree's
 
926
            content is different.
 
927
        :param hardlink: If true, hard-link files from accelerator_tree,
 
928
            where possible.
 
929
        """
 
930
        target_transport = get_transport(url, possible_transports)
 
931
        target_transport.ensure_base()
 
932
        cloning_format = self.cloning_metadir()
 
933
        result = cloning_format.initialize_on_transport(target_transport)
 
934
        try:
 
935
            source_branch = self.open_branch()
 
936
            source_repository = source_branch.repository
 
937
        except errors.NotBranchError:
 
938
            source_branch = None
 
939
            try:
 
940
                source_repository = self.open_repository()
 
941
            except errors.NoRepositoryPresent:
 
942
                source_repository = None
 
943
        if force_new_repo:
 
944
            result_repo = None
 
945
        else:
 
946
            try:
 
947
                result_repo = result.find_repository()
 
948
            except errors.NoRepositoryPresent:
 
949
                result_repo = None
 
950
        if source_repository is None and result_repo is not None:
 
951
            pass
 
952
        elif source_repository is None and result_repo is None:
 
953
            # no repo available, make a new one
 
954
            result.create_repository()
 
955
        elif source_repository is not None and result_repo is None:
 
956
            # have source, and want to make a new target repo
 
957
            result_repo = source_repository.sprout(result,
 
958
                                                   revision_id=revision_id)
 
959
        else:
 
960
            # fetch needed content into target.
 
961
            if source_repository is not None:
 
962
                # would rather do 
 
963
                # source_repository.copy_content_into(result_repo,
 
964
                #                                     revision_id=revision_id)
 
965
                # so we can override the copy method
 
966
                result_repo.fetch(source_repository, revision_id=revision_id)
 
967
        if source_branch is not None:
 
968
            source_branch.sprout(result, revision_id=revision_id)
 
969
        else:
 
970
            result.create_branch()
 
971
        if isinstance(target_transport, LocalTransport) and (
 
972
            result_repo is None or result_repo.make_working_trees()):
 
973
            wt = result.create_workingtree(accelerator_tree=accelerator_tree,
 
974
                hardlink=hardlink)
 
975
            wt.lock_write()
 
976
            try:
 
977
                if wt.path2id('') is None:
 
978
                    try:
 
979
                        wt.set_root_id(self.open_workingtree.get_root_id())
 
980
                    except errors.NoWorkingTree:
 
981
                        pass
 
982
            finally:
 
983
                wt.unlock()
 
984
        else:
 
985
            wt = None
 
986
        if recurse == 'down':
 
987
            if wt is not None:
 
988
                basis = wt.basis_tree()
 
989
                basis.lock_read()
 
990
                subtrees = basis.iter_references()
 
991
                recurse_branch = wt.branch
 
992
            elif source_branch is not None:
 
993
                basis = source_branch.basis_tree()
 
994
                basis.lock_read()
 
995
                subtrees = basis.iter_references()
 
996
                recurse_branch = source_branch
 
997
            else:
 
998
                subtrees = []
 
999
                basis = None
 
1000
            try:
 
1001
                for path, file_id in subtrees:
 
1002
                    target = urlutils.join(url, urlutils.escape(path))
 
1003
                    sublocation = source_branch.reference_parent(file_id, path)
 
1004
                    sublocation.bzrdir.sprout(target,
 
1005
                        basis.get_reference_revision(file_id, path),
 
1006
                        force_new_repo=force_new_repo, recurse=recurse)
 
1007
            finally:
 
1008
                if basis is not None:
 
1009
                    basis.unlock()
 
1010
        return result
 
1011
 
 
1012
 
 
1013
class BzrDirPreSplitOut(BzrDir):
 
1014
    """A common class for the all-in-one formats."""
 
1015
 
 
1016
    def __init__(self, _transport, _format):
 
1017
        """See BzrDir.__init__."""
 
1018
        super(BzrDirPreSplitOut, self).__init__(_transport, _format)
 
1019
        self._control_files = lockable_files.LockableFiles(
 
1020
                                            self.get_branch_transport(None),
 
1021
                                            self._format._lock_file_name,
 
1022
                                            self._format._lock_class)
 
1023
 
 
1024
    def break_lock(self):
 
1025
        """Pre-splitout bzrdirs do not suffer from stale locks."""
 
1026
        raise NotImplementedError(self.break_lock)
 
1027
 
 
1028
    def cloning_metadir(self):
 
1029
        """Produce a metadir suitable for cloning with."""
 
1030
        return self._format.__class__()
 
1031
 
 
1032
    def clone(self, url, revision_id=None, force_new_repo=False):
 
1033
        """See BzrDir.clone()."""
 
1034
        from bzrlib.workingtree import WorkingTreeFormat2
 
1035
        self._make_tail(url)
 
1036
        result = self._format._initialize_for_clone(url)
 
1037
        self.open_repository().clone(result, revision_id=revision_id)
 
1038
        from_branch = self.open_branch()
 
1039
        from_branch.clone(result, revision_id=revision_id)
 
1040
        try:
 
1041
            self.open_workingtree().clone(result)
 
1042
        except errors.NotLocalUrl:
 
1043
            # make a new one, this format always has to have one.
 
1044
            try:
 
1045
                WorkingTreeFormat2().initialize(result)
 
1046
            except errors.NotLocalUrl:
 
1047
                # but we cannot do it for remote trees.
 
1048
                to_branch = result.open_branch()
 
1049
                WorkingTreeFormat2().stub_initialize_remote(to_branch.control_files)
 
1050
        return result
 
1051
 
 
1052
    def create_branch(self):
 
1053
        """See BzrDir.create_branch."""
 
1054
        return self.open_branch()
 
1055
 
 
1056
    def destroy_branch(self):
 
1057
        """See BzrDir.destroy_branch."""
 
1058
        raise errors.UnsupportedOperation(self.destroy_branch, self)
 
1059
 
 
1060
    def create_repository(self, shared=False):
 
1061
        """See BzrDir.create_repository."""
 
1062
        if shared:
 
1063
            raise errors.IncompatibleFormat('shared repository', self._format)
 
1064
        return self.open_repository()
 
1065
 
 
1066
    def destroy_repository(self):
 
1067
        """See BzrDir.destroy_repository."""
 
1068
        raise errors.UnsupportedOperation(self.destroy_repository, self)
 
1069
 
 
1070
    def create_workingtree(self, revision_id=None, from_branch=None,
 
1071
                           accelerator_tree=None, hardlink=False):
 
1072
        """See BzrDir.create_workingtree."""
 
1073
        # this looks buggy but is not -really-
 
1074
        # because this format creates the workingtree when the bzrdir is
 
1075
        # created
 
1076
        # clone and sprout will have set the revision_id
 
1077
        # and that will have set it for us, its only
 
1078
        # specific uses of create_workingtree in isolation
 
1079
        # that can do wonky stuff here, and that only
 
1080
        # happens for creating checkouts, which cannot be 
 
1081
        # done on this format anyway. So - acceptable wart.
 
1082
        result = self.open_workingtree(recommend_upgrade=False)
 
1083
        if revision_id is not None:
 
1084
            if revision_id == _mod_revision.NULL_REVISION:
 
1085
                result.set_parent_ids([])
 
1086
            else:
 
1087
                result.set_parent_ids([revision_id])
 
1088
        return result
 
1089
 
 
1090
    def destroy_workingtree(self):
 
1091
        """See BzrDir.destroy_workingtree."""
 
1092
        raise errors.UnsupportedOperation(self.destroy_workingtree, self)
 
1093
 
 
1094
    def destroy_workingtree_metadata(self):
 
1095
        """See BzrDir.destroy_workingtree_metadata."""
 
1096
        raise errors.UnsupportedOperation(self.destroy_workingtree_metadata, 
 
1097
                                          self)
 
1098
 
 
1099
    def get_branch_transport(self, branch_format):
 
1100
        """See BzrDir.get_branch_transport()."""
 
1101
        if branch_format is None:
 
1102
            return self.transport
 
1103
        try:
 
1104
            branch_format.get_format_string()
 
1105
        except NotImplementedError:
 
1106
            return self.transport
 
1107
        raise errors.IncompatibleFormat(branch_format, self._format)
 
1108
 
 
1109
    def get_repository_transport(self, repository_format):
 
1110
        """See BzrDir.get_repository_transport()."""
 
1111
        if repository_format is None:
 
1112
            return self.transport
 
1113
        try:
 
1114
            repository_format.get_format_string()
 
1115
        except NotImplementedError:
 
1116
            return self.transport
 
1117
        raise errors.IncompatibleFormat(repository_format, self._format)
 
1118
 
 
1119
    def get_workingtree_transport(self, workingtree_format):
 
1120
        """See BzrDir.get_workingtree_transport()."""
 
1121
        if workingtree_format is None:
 
1122
            return self.transport
 
1123
        try:
 
1124
            workingtree_format.get_format_string()
 
1125
        except NotImplementedError:
 
1126
            return self.transport
 
1127
        raise errors.IncompatibleFormat(workingtree_format, self._format)
 
1128
 
 
1129
    def needs_format_conversion(self, format=None):
 
1130
        """See BzrDir.needs_format_conversion()."""
 
1131
        # if the format is not the same as the system default,
 
1132
        # an upgrade is needed.
 
1133
        if format is None:
 
1134
            format = BzrDirFormat.get_default_format()
 
1135
        return not isinstance(self._format, format.__class__)
 
1136
 
 
1137
    def open_branch(self, unsupported=False):
 
1138
        """See BzrDir.open_branch."""
 
1139
        from bzrlib.branch import BzrBranchFormat4
 
1140
        format = BzrBranchFormat4()
 
1141
        self._check_supported(format, unsupported)
 
1142
        return format.open(self, _found=True)
 
1143
 
 
1144
    def sprout(self, url, revision_id=None, force_new_repo=False,
 
1145
               possible_transports=None, accelerator_tree=None,
 
1146
               hardlink=False):
 
1147
        """See BzrDir.sprout()."""
 
1148
        from bzrlib.workingtree import WorkingTreeFormat2
 
1149
        self._make_tail(url)
 
1150
        result = self._format._initialize_for_clone(url)
 
1151
        try:
 
1152
            self.open_repository().clone(result, revision_id=revision_id)
 
1153
        except errors.NoRepositoryPresent:
 
1154
            pass
 
1155
        try:
 
1156
            self.open_branch().sprout(result, revision_id=revision_id)
 
1157
        except errors.NotBranchError:
 
1158
            pass
 
1159
        # we always want a working tree
 
1160
        WorkingTreeFormat2().initialize(result,
 
1161
                                        accelerator_tree=accelerator_tree,
 
1162
                                        hardlink=hardlink)
 
1163
        return result
 
1164
 
 
1165
 
 
1166
class BzrDir4(BzrDirPreSplitOut):
 
1167
    """A .bzr version 4 control object.
 
1168
    
 
1169
    This is a deprecated format and may be removed after sept 2006.
 
1170
    """
 
1171
 
 
1172
    def create_repository(self, shared=False):
 
1173
        """See BzrDir.create_repository."""
 
1174
        return self._format.repository_format.initialize(self, shared)
 
1175
 
 
1176
    def needs_format_conversion(self, format=None):
 
1177
        """Format 4 dirs are always in need of conversion."""
 
1178
        return True
 
1179
 
 
1180
    def open_repository(self):
 
1181
        """See BzrDir.open_repository."""
 
1182
        from bzrlib.repofmt.weaverepo import RepositoryFormat4
 
1183
        return RepositoryFormat4().open(self, _found=True)
 
1184
 
 
1185
 
 
1186
class BzrDir5(BzrDirPreSplitOut):
 
1187
    """A .bzr version 5 control object.
 
1188
 
 
1189
    This is a deprecated format and may be removed after sept 2006.
 
1190
    """
 
1191
 
 
1192
    def open_repository(self):
 
1193
        """See BzrDir.open_repository."""
 
1194
        from bzrlib.repofmt.weaverepo import RepositoryFormat5
 
1195
        return RepositoryFormat5().open(self, _found=True)
 
1196
 
 
1197
    def open_workingtree(self, _unsupported=False,
 
1198
            recommend_upgrade=True):
 
1199
        """See BzrDir.create_workingtree."""
 
1200
        from bzrlib.workingtree import WorkingTreeFormat2
 
1201
        wt_format = WorkingTreeFormat2()
 
1202
        # we don't warn here about upgrades; that ought to be handled for the
 
1203
        # bzrdir as a whole
 
1204
        return wt_format.open(self, _found=True)
 
1205
 
 
1206
 
 
1207
class BzrDir6(BzrDirPreSplitOut):
 
1208
    """A .bzr version 6 control object.
 
1209
 
 
1210
    This is a deprecated format and may be removed after sept 2006.
 
1211
    """
 
1212
 
 
1213
    def open_repository(self):
 
1214
        """See BzrDir.open_repository."""
 
1215
        from bzrlib.repofmt.weaverepo import RepositoryFormat6
 
1216
        return RepositoryFormat6().open(self, _found=True)
 
1217
 
 
1218
    def open_workingtree(self, _unsupported=False,
 
1219
        recommend_upgrade=True):
 
1220
        """See BzrDir.create_workingtree."""
 
1221
        # we don't warn here about upgrades; that ought to be handled for the
 
1222
        # bzrdir as a whole
 
1223
        from bzrlib.workingtree import WorkingTreeFormat2
 
1224
        return WorkingTreeFormat2().open(self, _found=True)
 
1225
 
 
1226
 
 
1227
class BzrDirMeta1(BzrDir):
 
1228
    """A .bzr meta version 1 control object.
 
1229
    
 
1230
    This is the first control object where the 
 
1231
    individual aspects are really split out: there are separate repository,
 
1232
    workingtree and branch subdirectories and any subset of the three can be
 
1233
    present within a BzrDir.
 
1234
    """
 
1235
 
 
1236
    def can_convert_format(self):
 
1237
        """See BzrDir.can_convert_format()."""
 
1238
        return True
 
1239
 
 
1240
    def create_branch(self):
 
1241
        """See BzrDir.create_branch."""
 
1242
        return self._format.get_branch_format().initialize(self)
 
1243
 
 
1244
    def destroy_branch(self):
 
1245
        """See BzrDir.create_branch."""
 
1246
        self.transport.delete_tree('branch')
 
1247
 
 
1248
    def create_repository(self, shared=False):
 
1249
        """See BzrDir.create_repository."""
 
1250
        return self._format.repository_format.initialize(self, shared)
 
1251
 
 
1252
    def destroy_repository(self):
 
1253
        """See BzrDir.destroy_repository."""
 
1254
        self.transport.delete_tree('repository')
 
1255
 
 
1256
    def create_workingtree(self, revision_id=None, from_branch=None,
 
1257
                           accelerator_tree=None, hardlink=False):
 
1258
        """See BzrDir.create_workingtree."""
 
1259
        return self._format.workingtree_format.initialize(
 
1260
            self, revision_id, from_branch=from_branch,
 
1261
            accelerator_tree=accelerator_tree, hardlink=hardlink)
 
1262
 
 
1263
    def destroy_workingtree(self):
 
1264
        """See BzrDir.destroy_workingtree."""
 
1265
        wt = self.open_workingtree(recommend_upgrade=False)
 
1266
        repository = wt.branch.repository
 
1267
        empty = repository.revision_tree(_mod_revision.NULL_REVISION)
 
1268
        wt.revert(old_tree=empty)
 
1269
        self.destroy_workingtree_metadata()
 
1270
 
 
1271
    def destroy_workingtree_metadata(self):
 
1272
        self.transport.delete_tree('checkout')
 
1273
 
 
1274
    def find_branch_format(self):
 
1275
        """Find the branch 'format' for this bzrdir.
 
1276
 
 
1277
        This might be a synthetic object for e.g. RemoteBranch and SVN.
 
1278
        """
 
1279
        from bzrlib.branch import BranchFormat
 
1280
        return BranchFormat.find_format(self)
 
1281
 
 
1282
    def _get_mkdir_mode(self):
 
1283
        """Figure out the mode to use when creating a bzrdir subdir."""
 
1284
        temp_control = lockable_files.LockableFiles(self.transport, '',
 
1285
                                     lockable_files.TransportLock)
 
1286
        return temp_control._dir_mode
 
1287
 
 
1288
    def get_branch_reference(self):
 
1289
        """See BzrDir.get_branch_reference()."""
 
1290
        from bzrlib.branch import BranchFormat
 
1291
        format = BranchFormat.find_format(self)
 
1292
        return format.get_reference(self)
 
1293
 
 
1294
    def get_branch_transport(self, branch_format):
 
1295
        """See BzrDir.get_branch_transport()."""
 
1296
        if branch_format is None:
 
1297
            return self.transport.clone('branch')
 
1298
        try:
 
1299
            branch_format.get_format_string()
 
1300
        except NotImplementedError:
 
1301
            raise errors.IncompatibleFormat(branch_format, self._format)
 
1302
        try:
 
1303
            self.transport.mkdir('branch', mode=self._get_mkdir_mode())
 
1304
        except errors.FileExists:
 
1305
            pass
 
1306
        return self.transport.clone('branch')
 
1307
 
 
1308
    def get_repository_transport(self, repository_format):
 
1309
        """See BzrDir.get_repository_transport()."""
 
1310
        if repository_format is None:
 
1311
            return self.transport.clone('repository')
 
1312
        try:
 
1313
            repository_format.get_format_string()
 
1314
        except NotImplementedError:
 
1315
            raise errors.IncompatibleFormat(repository_format, self._format)
 
1316
        try:
 
1317
            self.transport.mkdir('repository', mode=self._get_mkdir_mode())
 
1318
        except errors.FileExists:
 
1319
            pass
 
1320
        return self.transport.clone('repository')
 
1321
 
 
1322
    def get_workingtree_transport(self, workingtree_format):
 
1323
        """See BzrDir.get_workingtree_transport()."""
 
1324
        if workingtree_format is None:
 
1325
            return self.transport.clone('checkout')
 
1326
        try:
 
1327
            workingtree_format.get_format_string()
 
1328
        except NotImplementedError:
 
1329
            raise errors.IncompatibleFormat(workingtree_format, self._format)
 
1330
        try:
 
1331
            self.transport.mkdir('checkout', mode=self._get_mkdir_mode())
 
1332
        except errors.FileExists:
 
1333
            pass
 
1334
        return self.transport.clone('checkout')
 
1335
 
 
1336
    def needs_format_conversion(self, format=None):
 
1337
        """See BzrDir.needs_format_conversion()."""
 
1338
        if format is None:
 
1339
            format = BzrDirFormat.get_default_format()
 
1340
        if not isinstance(self._format, format.__class__):
 
1341
            # it is not a meta dir format, conversion is needed.
 
1342
            return True
 
1343
        # we might want to push this down to the repository?
 
1344
        try:
 
1345
            if not isinstance(self.open_repository()._format,
 
1346
                              format.repository_format.__class__):
 
1347
                # the repository needs an upgrade.
 
1348
                return True
 
1349
        except errors.NoRepositoryPresent:
 
1350
            pass
 
1351
        try:
 
1352
            if not isinstance(self.open_branch()._format,
 
1353
                              format.get_branch_format().__class__):
 
1354
                # the branch needs an upgrade.
 
1355
                return True
 
1356
        except errors.NotBranchError:
 
1357
            pass
 
1358
        try:
 
1359
            my_wt = self.open_workingtree(recommend_upgrade=False)
 
1360
            if not isinstance(my_wt._format,
 
1361
                              format.workingtree_format.__class__):
 
1362
                # the workingtree needs an upgrade.
 
1363
                return True
 
1364
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
1365
            pass
 
1366
        return False
 
1367
 
 
1368
    def open_branch(self, unsupported=False):
 
1369
        """See BzrDir.open_branch."""
 
1370
        format = self.find_branch_format()
 
1371
        self._check_supported(format, unsupported)
 
1372
        return format.open(self, _found=True)
 
1373
 
 
1374
    def open_repository(self, unsupported=False):
 
1375
        """See BzrDir.open_repository."""
 
1376
        from bzrlib.repository import RepositoryFormat
 
1377
        format = RepositoryFormat.find_format(self)
 
1378
        self._check_supported(format, unsupported)
 
1379
        return format.open(self, _found=True)
 
1380
 
 
1381
    def open_workingtree(self, unsupported=False,
 
1382
            recommend_upgrade=True):
 
1383
        """See BzrDir.open_workingtree."""
 
1384
        from bzrlib.workingtree import WorkingTreeFormat
 
1385
        format = WorkingTreeFormat.find_format(self)
 
1386
        self._check_supported(format, unsupported,
 
1387
            recommend_upgrade,
 
1388
            basedir=self.root_transport.base)
 
1389
        return format.open(self, _found=True)
 
1390
 
 
1391
 
 
1392
class BzrDirFormat(object):
 
1393
    """An encapsulation of the initialization and open routines for a format.
 
1394
 
 
1395
    Formats provide three things:
 
1396
     * An initialization routine,
 
1397
     * a format string,
 
1398
     * an open routine.
 
1399
 
 
1400
    Formats are placed in a dict by their format string for reference 
 
1401
    during bzrdir opening. These should be subclasses of BzrDirFormat
 
1402
    for consistency.
 
1403
 
 
1404
    Once a format is deprecated, just deprecate the initialize and open
 
1405
    methods on the format class. Do not deprecate the object, as the 
 
1406
    object will be created every system load.
 
1407
    """
 
1408
 
 
1409
    _default_format = None
 
1410
    """The default format used for new .bzr dirs."""
 
1411
 
 
1412
    _formats = {}
 
1413
    """The known formats."""
 
1414
 
 
1415
    _control_formats = []
 
1416
    """The registered control formats - .bzr, ....
 
1417
    
 
1418
    This is a list of BzrDirFormat objects.
 
1419
    """
 
1420
 
 
1421
    _control_server_formats = []
 
1422
    """The registered control server formats, e.g. RemoteBzrDirs.
 
1423
 
 
1424
    This is a list of BzrDirFormat objects.
 
1425
    """
 
1426
 
 
1427
    _lock_file_name = 'branch-lock'
 
1428
 
 
1429
    # _lock_class must be set in subclasses to the lock type, typ.
 
1430
    # TransportLock or LockDir
 
1431
 
 
1432
    @classmethod
 
1433
    def find_format(klass, transport, _server_formats=True):
 
1434
        """Return the format present at transport."""
 
1435
        if _server_formats:
 
1436
            formats = klass._control_server_formats + klass._control_formats
 
1437
        else:
 
1438
            formats = klass._control_formats
 
1439
        for format in formats:
 
1440
            try:
 
1441
                return format.probe_transport(transport)
 
1442
            except errors.NotBranchError:
 
1443
                # this format does not find a control dir here.
 
1444
                pass
 
1445
        raise errors.NotBranchError(path=transport.base)
 
1446
 
 
1447
    @classmethod
 
1448
    def probe_transport(klass, transport):
 
1449
        """Return the .bzrdir style format present in a directory."""
 
1450
        try:
 
1451
            format_string = transport.get(".bzr/branch-format").read()
 
1452
        except errors.NoSuchFile:
 
1453
            raise errors.NotBranchError(path=transport.base)
 
1454
 
 
1455
        try:
 
1456
            return klass._formats[format_string]
 
1457
        except KeyError:
 
1458
            raise errors.UnknownFormatError(format=format_string, kind='bzrdir')
 
1459
 
 
1460
    @classmethod
 
1461
    def get_default_format(klass):
 
1462
        """Return the current default format."""
 
1463
        return klass._default_format
 
1464
 
 
1465
    def get_format_string(self):
 
1466
        """Return the ASCII format string that identifies this format."""
 
1467
        raise NotImplementedError(self.get_format_string)
 
1468
 
 
1469
    def get_format_description(self):
 
1470
        """Return the short description for this format."""
 
1471
        raise NotImplementedError(self.get_format_description)
 
1472
 
 
1473
    def get_converter(self, format=None):
 
1474
        """Return the converter to use to convert bzrdirs needing converts.
 
1475
 
 
1476
        This returns a bzrlib.bzrdir.Converter object.
 
1477
 
 
1478
        This should return the best upgrader to step this format towards the
 
1479
        current default format. In the case of plugins we can/should provide
 
1480
        some means for them to extend the range of returnable converters.
 
1481
 
 
1482
        :param format: Optional format to override the default format of the 
 
1483
                       library.
 
1484
        """
 
1485
        raise NotImplementedError(self.get_converter)
 
1486
 
 
1487
    def initialize(self, url, possible_transports=None):
 
1488
        """Create a bzr control dir at this url and return an opened copy.
 
1489
        
 
1490
        Subclasses should typically override initialize_on_transport
 
1491
        instead of this method.
 
1492
        """
 
1493
        return self.initialize_on_transport(get_transport(url,
 
1494
                                                          possible_transports))
 
1495
 
 
1496
    def initialize_on_transport(self, transport):
 
1497
        """Initialize a new bzrdir in the base directory of a Transport."""
 
1498
        # Since we don't have a .bzr directory, inherit the
 
1499
        # mode from the root directory
 
1500
        temp_control = lockable_files.LockableFiles(transport,
 
1501
                            '', lockable_files.TransportLock)
 
1502
        temp_control._transport.mkdir('.bzr',
 
1503
                                      # FIXME: RBC 20060121 don't peek under
 
1504
                                      # the covers
 
1505
                                      mode=temp_control._dir_mode)
 
1506
        if sys.platform == 'win32' and isinstance(transport, LocalTransport):
 
1507
            win32utils.set_file_attr_hidden(transport._abspath('.bzr'))
 
1508
        file_mode = temp_control._file_mode
 
1509
        del temp_control
 
1510
        mutter('created control directory in ' + transport.base)
 
1511
        control = transport.clone('.bzr')
 
1512
        utf8_files = [('README', 
 
1513
                       "This is a Bazaar control directory.\n"
 
1514
                       "Do not change any files in this directory.\n"
 
1515
                       "See http://bazaar-vcs.org/ for more information about Bazaar.\n"),
 
1516
                      ('branch-format', self.get_format_string()),
 
1517
                      ]
 
1518
        # NB: no need to escape relative paths that are url safe.
 
1519
        control_files = lockable_files.LockableFiles(control,
 
1520
                            self._lock_file_name, self._lock_class)
 
1521
        control_files.create_lock()
 
1522
        control_files.lock_write()
 
1523
        try:
 
1524
            for file, content in utf8_files:
 
1525
                control_files.put_utf8(file, content)
 
1526
        finally:
 
1527
            control_files.unlock()
 
1528
        return self.open(transport, _found=True)
 
1529
 
 
1530
    def is_supported(self):
 
1531
        """Is this format supported?
 
1532
 
 
1533
        Supported formats must be initializable and openable.
 
1534
        Unsupported formats may not support initialization or committing or 
 
1535
        some other features depending on the reason for not being supported.
 
1536
        """
 
1537
        return True
 
1538
 
 
1539
    def same_model(self, target_format):
 
1540
        return (self.repository_format.rich_root_data == 
 
1541
            target_format.rich_root_data)
 
1542
 
 
1543
    @classmethod
 
1544
    def known_formats(klass):
 
1545
        """Return all the known formats.
 
1546
        
 
1547
        Concrete formats should override _known_formats.
 
1548
        """
 
1549
        # There is double indirection here to make sure that control 
 
1550
        # formats used by more than one dir format will only be probed 
 
1551
        # once. This can otherwise be quite expensive for remote connections.
 
1552
        result = set()
 
1553
        for format in klass._control_formats:
 
1554
            result.update(format._known_formats())
 
1555
        return result
 
1556
    
 
1557
    @classmethod
 
1558
    def _known_formats(klass):
 
1559
        """Return the known format instances for this control format."""
 
1560
        return set(klass._formats.values())
 
1561
 
 
1562
    def open(self, transport, _found=False):
 
1563
        """Return an instance of this format for the dir transport points at.
 
1564
        
 
1565
        _found is a private parameter, do not use it.
 
1566
        """
 
1567
        if not _found:
 
1568
            found_format = BzrDirFormat.find_format(transport)
 
1569
            if not isinstance(found_format, self.__class__):
 
1570
                raise AssertionError("%s was asked to open %s, but it seems to need "
 
1571
                        "format %s" 
 
1572
                        % (self, transport, found_format))
 
1573
        return self._open(transport)
 
1574
 
 
1575
    def _open(self, transport):
 
1576
        """Template method helper for opening BzrDirectories.
 
1577
 
 
1578
        This performs the actual open and any additional logic or parameter
 
1579
        passing.
 
1580
        """
 
1581
        raise NotImplementedError(self._open)
 
1582
 
 
1583
    @classmethod
 
1584
    def register_format(klass, format):
 
1585
        klass._formats[format.get_format_string()] = format
 
1586
 
 
1587
    @classmethod
 
1588
    def register_control_format(klass, format):
 
1589
        """Register a format that does not use '.bzr' for its control dir.
 
1590
 
 
1591
        TODO: This should be pulled up into a 'ControlDirFormat' base class
 
1592
        which BzrDirFormat can inherit from, and renamed to register_format 
 
1593
        there. It has been done without that for now for simplicity of
 
1594
        implementation.
 
1595
        """
 
1596
        klass._control_formats.append(format)
 
1597
 
 
1598
    @classmethod
 
1599
    def register_control_server_format(klass, format):
 
1600
        """Register a control format for client-server environments.
 
1601
 
 
1602
        These formats will be tried before ones registered with
 
1603
        register_control_format.  This gives implementations that decide to the
 
1604
        chance to grab it before anything looks at the contents of the format
 
1605
        file.
 
1606
        """
 
1607
        klass._control_server_formats.append(format)
 
1608
 
 
1609
    @classmethod
 
1610
    def _set_default_format(klass, format):
 
1611
        """Set default format (for testing behavior of defaults only)"""
 
1612
        klass._default_format = format
 
1613
 
 
1614
    def __str__(self):
 
1615
        # Trim the newline
 
1616
        return self.get_format_string().rstrip()
 
1617
 
 
1618
    @classmethod
 
1619
    def unregister_format(klass, format):
 
1620
        del klass._formats[format.get_format_string()]
 
1621
 
 
1622
    @classmethod
 
1623
    def unregister_control_format(klass, format):
 
1624
        klass._control_formats.remove(format)
 
1625
 
 
1626
 
 
1627
class BzrDirFormat4(BzrDirFormat):
 
1628
    """Bzr dir format 4.
 
1629
 
 
1630
    This format is a combined format for working tree, branch and repository.
 
1631
    It has:
 
1632
     - Format 1 working trees [always]
 
1633
     - Format 4 branches [always]
 
1634
     - Format 4 repositories [always]
 
1635
 
 
1636
    This format is deprecated: it indexes texts using a text it which is
 
1637
    removed in format 5; write support for this format has been removed.
 
1638
    """
 
1639
 
 
1640
    _lock_class = lockable_files.TransportLock
 
1641
 
 
1642
    def get_format_string(self):
 
1643
        """See BzrDirFormat.get_format_string()."""
 
1644
        return "Bazaar-NG branch, format 0.0.4\n"
 
1645
 
 
1646
    def get_format_description(self):
 
1647
        """See BzrDirFormat.get_format_description()."""
 
1648
        return "All-in-one format 4"
 
1649
 
 
1650
    def get_converter(self, format=None):
 
1651
        """See BzrDirFormat.get_converter()."""
 
1652
        # there is one and only one upgrade path here.
 
1653
        return ConvertBzrDir4To5()
 
1654
        
 
1655
    def initialize_on_transport(self, transport):
 
1656
        """Format 4 branches cannot be created."""
 
1657
        raise errors.UninitializableFormat(self)
 
1658
 
 
1659
    def is_supported(self):
 
1660
        """Format 4 is not supported.
 
1661
 
 
1662
        It is not supported because the model changed from 4 to 5 and the
 
1663
        conversion logic is expensive - so doing it on the fly was not 
 
1664
        feasible.
 
1665
        """
 
1666
        return False
 
1667
 
 
1668
    def _open(self, transport):
 
1669
        """See BzrDirFormat._open."""
 
1670
        return BzrDir4(transport, self)
 
1671
 
 
1672
    def __return_repository_format(self):
 
1673
        """Circular import protection."""
 
1674
        from bzrlib.repofmt.weaverepo import RepositoryFormat4
 
1675
        return RepositoryFormat4()
 
1676
    repository_format = property(__return_repository_format)
 
1677
 
 
1678
 
 
1679
class BzrDirFormat5(BzrDirFormat):
 
1680
    """Bzr control format 5.
 
1681
 
 
1682
    This format is a combined format for working tree, branch and repository.
 
1683
    It has:
 
1684
     - Format 2 working trees [always] 
 
1685
     - Format 4 branches [always] 
 
1686
     - Format 5 repositories [always]
 
1687
       Unhashed stores in the repository.
 
1688
    """
 
1689
 
 
1690
    _lock_class = lockable_files.TransportLock
 
1691
 
 
1692
    def get_format_string(self):
 
1693
        """See BzrDirFormat.get_format_string()."""
 
1694
        return "Bazaar-NG branch, format 5\n"
 
1695
 
 
1696
    def get_format_description(self):
 
1697
        """See BzrDirFormat.get_format_description()."""
 
1698
        return "All-in-one format 5"
 
1699
 
 
1700
    def get_converter(self, format=None):
 
1701
        """See BzrDirFormat.get_converter()."""
 
1702
        # there is one and only one upgrade path here.
 
1703
        return ConvertBzrDir5To6()
 
1704
 
 
1705
    def _initialize_for_clone(self, url):
 
1706
        return self.initialize_on_transport(get_transport(url), _cloning=True)
 
1707
        
 
1708
    def initialize_on_transport(self, transport, _cloning=False):
 
1709
        """Format 5 dirs always have working tree, branch and repository.
 
1710
        
 
1711
        Except when they are being cloned.
 
1712
        """
 
1713
        from bzrlib.branch import BzrBranchFormat4
 
1714
        from bzrlib.repofmt.weaverepo import RepositoryFormat5
 
1715
        from bzrlib.workingtree import WorkingTreeFormat2
 
1716
        result = (super(BzrDirFormat5, self).initialize_on_transport(transport))
 
1717
        RepositoryFormat5().initialize(result, _internal=True)
 
1718
        if not _cloning:
 
1719
            branch = BzrBranchFormat4().initialize(result)
 
1720
            try:
 
1721
                WorkingTreeFormat2().initialize(result)
 
1722
            except errors.NotLocalUrl:
 
1723
                # Even though we can't access the working tree, we need to
 
1724
                # create its control files.
 
1725
                WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
 
1726
        return result
 
1727
 
 
1728
    def _open(self, transport):
 
1729
        """See BzrDirFormat._open."""
 
1730
        return BzrDir5(transport, self)
 
1731
 
 
1732
    def __return_repository_format(self):
 
1733
        """Circular import protection."""
 
1734
        from bzrlib.repofmt.weaverepo import RepositoryFormat5
 
1735
        return RepositoryFormat5()
 
1736
    repository_format = property(__return_repository_format)
 
1737
 
 
1738
 
 
1739
class BzrDirFormat6(BzrDirFormat):
 
1740
    """Bzr control format 6.
 
1741
 
 
1742
    This format is a combined format for working tree, branch and repository.
 
1743
    It has:
 
1744
     - Format 2 working trees [always] 
 
1745
     - Format 4 branches [always] 
 
1746
     - Format 6 repositories [always]
 
1747
    """
 
1748
 
 
1749
    _lock_class = lockable_files.TransportLock
 
1750
 
 
1751
    def get_format_string(self):
 
1752
        """See BzrDirFormat.get_format_string()."""
 
1753
        return "Bazaar-NG branch, format 6\n"
 
1754
 
 
1755
    def get_format_description(self):
 
1756
        """See BzrDirFormat.get_format_description()."""
 
1757
        return "All-in-one format 6"
 
1758
 
 
1759
    def get_converter(self, format=None):
 
1760
        """See BzrDirFormat.get_converter()."""
 
1761
        # there is one and only one upgrade path here.
 
1762
        return ConvertBzrDir6ToMeta()
 
1763
        
 
1764
    def _initialize_for_clone(self, url):
 
1765
        return self.initialize_on_transport(get_transport(url), _cloning=True)
 
1766
 
 
1767
    def initialize_on_transport(self, transport, _cloning=False):
 
1768
        """Format 6 dirs always have working tree, branch and repository.
 
1769
        
 
1770
        Except when they are being cloned.
 
1771
        """
 
1772
        from bzrlib.branch import BzrBranchFormat4
 
1773
        from bzrlib.repofmt.weaverepo import RepositoryFormat6
 
1774
        from bzrlib.workingtree import WorkingTreeFormat2
 
1775
        result = super(BzrDirFormat6, self).initialize_on_transport(transport)
 
1776
        RepositoryFormat6().initialize(result, _internal=True)
 
1777
        if not _cloning:
 
1778
            branch = BzrBranchFormat4().initialize(result)
 
1779
            try:
 
1780
                WorkingTreeFormat2().initialize(result)
 
1781
            except errors.NotLocalUrl:
 
1782
                # Even though we can't access the working tree, we need to
 
1783
                # create its control files.
 
1784
                WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
 
1785
        return result
 
1786
 
 
1787
    def _open(self, transport):
 
1788
        """See BzrDirFormat._open."""
 
1789
        return BzrDir6(transport, self)
 
1790
 
 
1791
    def __return_repository_format(self):
 
1792
        """Circular import protection."""
 
1793
        from bzrlib.repofmt.weaverepo import RepositoryFormat6
 
1794
        return RepositoryFormat6()
 
1795
    repository_format = property(__return_repository_format)
 
1796
 
 
1797
 
 
1798
class BzrDirMetaFormat1(BzrDirFormat):
 
1799
    """Bzr meta control format 1
 
1800
 
 
1801
    This is the first format with split out working tree, branch and repository
 
1802
    disk storage.
 
1803
    It has:
 
1804
     - Format 3 working trees [optional]
 
1805
     - Format 5 branches [optional]
 
1806
     - Format 7 repositories [optional]
 
1807
    """
 
1808
 
 
1809
    _lock_class = lockdir.LockDir
 
1810
 
 
1811
    def __init__(self):
 
1812
        self._workingtree_format = None
 
1813
        self._branch_format = None
 
1814
 
 
1815
    def __eq__(self, other):
 
1816
        if other.__class__ is not self.__class__:
 
1817
            return False
 
1818
        if other.repository_format != self.repository_format:
 
1819
            return False
 
1820
        if other.workingtree_format != self.workingtree_format:
 
1821
            return False
 
1822
        return True
 
1823
 
 
1824
    def __ne__(self, other):
 
1825
        return not self == other
 
1826
 
 
1827
    def get_branch_format(self):
 
1828
        if self._branch_format is None:
 
1829
            from bzrlib.branch import BranchFormat
 
1830
            self._branch_format = BranchFormat.get_default_format()
 
1831
        return self._branch_format
 
1832
 
 
1833
    def set_branch_format(self, format):
 
1834
        self._branch_format = format
 
1835
 
 
1836
    def get_converter(self, format=None):
 
1837
        """See BzrDirFormat.get_converter()."""
 
1838
        if format is None:
 
1839
            format = BzrDirFormat.get_default_format()
 
1840
        if not isinstance(self, format.__class__):
 
1841
            # converting away from metadir is not implemented
 
1842
            raise NotImplementedError(self.get_converter)
 
1843
        return ConvertMetaToMeta(format)
 
1844
 
 
1845
    def get_format_string(self):
 
1846
        """See BzrDirFormat.get_format_string()."""
 
1847
        return "Bazaar-NG meta directory, format 1\n"
 
1848
 
 
1849
    def get_format_description(self):
 
1850
        """See BzrDirFormat.get_format_description()."""
 
1851
        return "Meta directory format 1"
 
1852
 
 
1853
    def _open(self, transport):
 
1854
        """See BzrDirFormat._open."""
 
1855
        return BzrDirMeta1(transport, self)
 
1856
 
 
1857
    def __return_repository_format(self):
 
1858
        """Circular import protection."""
 
1859
        if getattr(self, '_repository_format', None):
 
1860
            return self._repository_format
 
1861
        from bzrlib.repository import RepositoryFormat
 
1862
        return RepositoryFormat.get_default_format()
 
1863
 
 
1864
    def __set_repository_format(self, value):
 
1865
        """Allow changing the repository format for metadir formats."""
 
1866
        self._repository_format = value
 
1867
 
 
1868
    repository_format = property(__return_repository_format, __set_repository_format)
 
1869
 
 
1870
    def __get_workingtree_format(self):
 
1871
        if self._workingtree_format is None:
 
1872
            from bzrlib.workingtree import WorkingTreeFormat
 
1873
            self._workingtree_format = WorkingTreeFormat.get_default_format()
 
1874
        return self._workingtree_format
 
1875
 
 
1876
    def __set_workingtree_format(self, wt_format):
 
1877
        self._workingtree_format = wt_format
 
1878
 
 
1879
    workingtree_format = property(__get_workingtree_format,
 
1880
                                  __set_workingtree_format)
 
1881
 
 
1882
 
 
1883
# Register bzr control format
 
1884
BzrDirFormat.register_control_format(BzrDirFormat)
 
1885
 
 
1886
# Register bzr formats
 
1887
BzrDirFormat.register_format(BzrDirFormat4())
 
1888
BzrDirFormat.register_format(BzrDirFormat5())
 
1889
BzrDirFormat.register_format(BzrDirFormat6())
 
1890
__default_format = BzrDirMetaFormat1()
 
1891
BzrDirFormat.register_format(__default_format)
 
1892
BzrDirFormat._default_format = __default_format
 
1893
 
 
1894
 
 
1895
class Converter(object):
 
1896
    """Converts a disk format object from one format to another."""
 
1897
 
 
1898
    def convert(self, to_convert, pb):
 
1899
        """Perform the conversion of to_convert, giving feedback via pb.
 
1900
 
 
1901
        :param to_convert: The disk object to convert.
 
1902
        :param pb: a progress bar to use for progress information.
 
1903
        """
 
1904
 
 
1905
    def step(self, message):
 
1906
        """Update the pb by a step."""
 
1907
        self.count +=1
 
1908
        self.pb.update(message, self.count, self.total)
 
1909
 
 
1910
 
 
1911
class ConvertBzrDir4To5(Converter):
 
1912
    """Converts format 4 bzr dirs to format 5."""
 
1913
 
 
1914
    def __init__(self):
 
1915
        super(ConvertBzrDir4To5, self).__init__()
 
1916
        self.converted_revs = set()
 
1917
        self.absent_revisions = set()
 
1918
        self.text_count = 0
 
1919
        self.revisions = {}
 
1920
        
 
1921
    def convert(self, to_convert, pb):
 
1922
        """See Converter.convert()."""
 
1923
        self.bzrdir = to_convert
 
1924
        self.pb = pb
 
1925
        self.pb.note('starting upgrade from format 4 to 5')
 
1926
        if isinstance(self.bzrdir.transport, LocalTransport):
 
1927
            self.bzrdir.get_workingtree_transport(None).delete('stat-cache')
 
1928
        self._convert_to_weaves()
 
1929
        return BzrDir.open(self.bzrdir.root_transport.base)
 
1930
 
 
1931
    def _convert_to_weaves(self):
 
1932
        self.pb.note('note: upgrade may be faster if all store files are ungzipped first')
 
1933
        try:
 
1934
            # TODO permissions
 
1935
            stat = self.bzrdir.transport.stat('weaves')
 
1936
            if not S_ISDIR(stat.st_mode):
 
1937
                self.bzrdir.transport.delete('weaves')
 
1938
                self.bzrdir.transport.mkdir('weaves')
 
1939
        except errors.NoSuchFile:
 
1940
            self.bzrdir.transport.mkdir('weaves')
 
1941
        # deliberately not a WeaveFile as we want to build it up slowly.
 
1942
        self.inv_weave = Weave('inventory')
 
1943
        # holds in-memory weaves for all files
 
1944
        self.text_weaves = {}
 
1945
        self.bzrdir.transport.delete('branch-format')
 
1946
        self.branch = self.bzrdir.open_branch()
 
1947
        self._convert_working_inv()
 
1948
        rev_history = self.branch.revision_history()
 
1949
        # to_read is a stack holding the revisions we still need to process;
 
1950
        # appending to it adds new highest-priority revisions
 
1951
        self.known_revisions = set(rev_history)
 
1952
        self.to_read = rev_history[-1:]
 
1953
        while self.to_read:
 
1954
            rev_id = self.to_read.pop()
 
1955
            if (rev_id not in self.revisions
 
1956
                and rev_id not in self.absent_revisions):
 
1957
                self._load_one_rev(rev_id)
 
1958
        self.pb.clear()
 
1959
        to_import = self._make_order()
 
1960
        for i, rev_id in enumerate(to_import):
 
1961
            self.pb.update('converting revision', i, len(to_import))
 
1962
            self._convert_one_rev(rev_id)
 
1963
        self.pb.clear()
 
1964
        self._write_all_weaves()
 
1965
        self._write_all_revs()
 
1966
        self.pb.note('upgraded to weaves:')
 
1967
        self.pb.note('  %6d revisions and inventories', len(self.revisions))
 
1968
        self.pb.note('  %6d revisions not present', len(self.absent_revisions))
 
1969
        self.pb.note('  %6d texts', self.text_count)
 
1970
        self._cleanup_spare_files_after_format4()
 
1971
        self.branch.control_files.put_utf8('branch-format', BzrDirFormat5().get_format_string())
 
1972
 
 
1973
    def _cleanup_spare_files_after_format4(self):
 
1974
        # FIXME working tree upgrade foo.
 
1975
        for n in 'merged-patches', 'pending-merged-patches':
 
1976
            try:
 
1977
                ## assert os.path.getsize(p) == 0
 
1978
                self.bzrdir.transport.delete(n)
 
1979
            except errors.NoSuchFile:
 
1980
                pass
 
1981
        self.bzrdir.transport.delete_tree('inventory-store')
 
1982
        self.bzrdir.transport.delete_tree('text-store')
 
1983
 
 
1984
    def _convert_working_inv(self):
 
1985
        inv = xml4.serializer_v4.read_inventory(
 
1986
                    self.branch.control_files.get('inventory'))
 
1987
        new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv, working=True)
 
1988
        # FIXME inventory is a working tree change.
 
1989
        self.branch.control_files.put('inventory', StringIO(new_inv_xml))
 
1990
 
 
1991
    def _write_all_weaves(self):
 
1992
        controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)
 
1993
        weave_transport = self.bzrdir.transport.clone('weaves')
 
1994
        weaves = WeaveStore(weave_transport, prefixed=False)
 
1995
        transaction = WriteTransaction()
 
1996
 
 
1997
        try:
 
1998
            i = 0
 
1999
            for file_id, file_weave in self.text_weaves.items():
 
2000
                self.pb.update('writing weave', i, len(self.text_weaves))
 
2001
                weaves._put_weave(file_id, file_weave, transaction)
 
2002
                i += 1
 
2003
            self.pb.update('inventory', 0, 1)
 
2004
            controlweaves._put_weave('inventory', self.inv_weave, transaction)
 
2005
            self.pb.update('inventory', 1, 1)
 
2006
        finally:
 
2007
            self.pb.clear()
 
2008
 
 
2009
    def _write_all_revs(self):
 
2010
        """Write all revisions out in new form."""
 
2011
        self.bzrdir.transport.delete_tree('revision-store')
 
2012
        self.bzrdir.transport.mkdir('revision-store')
 
2013
        revision_transport = self.bzrdir.transport.clone('revision-store')
 
2014
        # TODO permissions
 
2015
        _revision_store = TextRevisionStore(TextStore(revision_transport,
 
2016
                                                      prefixed=False,
 
2017
                                                      compressed=True))
 
2018
        try:
 
2019
            transaction = WriteTransaction()
 
2020
            for i, rev_id in enumerate(self.converted_revs):
 
2021
                self.pb.update('write revision', i, len(self.converted_revs))
 
2022
                _revision_store.add_revision(self.revisions[rev_id], transaction)
 
2023
        finally:
 
2024
            self.pb.clear()
 
2025
            
 
2026
    def _load_one_rev(self, rev_id):
 
2027
        """Load a revision object into memory.
 
2028
 
 
2029
        Any parents not either loaded or abandoned get queued to be
 
2030
        loaded."""
 
2031
        self.pb.update('loading revision',
 
2032
                       len(self.revisions),
 
2033
                       len(self.known_revisions))
 
2034
        if not self.branch.repository.has_revision(rev_id):
 
2035
            self.pb.clear()
 
2036
            self.pb.note('revision {%s} not present in branch; '
 
2037
                         'will be converted as a ghost',
 
2038
                         rev_id)
 
2039
            self.absent_revisions.add(rev_id)
 
2040
        else:
 
2041
            rev = self.branch.repository._revision_store.get_revision(rev_id,
 
2042
                self.branch.repository.get_transaction())
 
2043
            for parent_id in rev.parent_ids:
 
2044
                self.known_revisions.add(parent_id)
 
2045
                self.to_read.append(parent_id)
 
2046
            self.revisions[rev_id] = rev
 
2047
 
 
2048
    def _load_old_inventory(self, rev_id):
 
2049
        old_inv_xml = self.branch.repository.inventory_store.get(rev_id).read()
 
2050
        inv = xml4.serializer_v4.read_inventory_from_string(old_inv_xml)
 
2051
        inv.revision_id = rev_id
 
2052
        rev = self.revisions[rev_id]
 
2053
        return inv
 
2054
 
 
2055
    def _load_updated_inventory(self, rev_id):
 
2056
        inv_xml = self.inv_weave.get_text(rev_id)
 
2057
        inv = xml5.serializer_v5.read_inventory_from_string(inv_xml, rev_id)
 
2058
        return inv
 
2059
 
 
2060
    def _convert_one_rev(self, rev_id):
 
2061
        """Convert revision and all referenced objects to new format."""
 
2062
        rev = self.revisions[rev_id]
 
2063
        inv = self._load_old_inventory(rev_id)
 
2064
        present_parents = [p for p in rev.parent_ids
 
2065
                           if p not in self.absent_revisions]
 
2066
        self._convert_revision_contents(rev, inv, present_parents)
 
2067
        self._store_new_inv(rev, inv, present_parents)
 
2068
        self.converted_revs.add(rev_id)
 
2069
 
 
2070
    def _store_new_inv(self, rev, inv, present_parents):
 
2071
        new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
 
2072
        new_inv_sha1 = sha_string(new_inv_xml)
 
2073
        self.inv_weave.add_lines(rev.revision_id,
 
2074
                                 present_parents,
 
2075
                                 new_inv_xml.splitlines(True))
 
2076
        rev.inventory_sha1 = new_inv_sha1
 
2077
 
 
2078
    def _convert_revision_contents(self, rev, inv, present_parents):
 
2079
        """Convert all the files within a revision.
 
2080
 
 
2081
        Also upgrade the inventory to refer to the text revision ids."""
 
2082
        rev_id = rev.revision_id
 
2083
        mutter('converting texts of revision {%s}',
 
2084
               rev_id)
 
2085
        parent_invs = map(self._load_updated_inventory, present_parents)
 
2086
        entries = inv.iter_entries()
 
2087
        entries.next()
 
2088
        for path, ie in entries:
 
2089
            self._convert_file_version(rev, ie, parent_invs)
 
2090
 
 
2091
    def _convert_file_version(self, rev, ie, parent_invs):
 
2092
        """Convert one version of one file.
 
2093
 
 
2094
        The file needs to be added into the weave if it is a merge
 
2095
        of >=2 parents or if it's changed from its parent.
 
2096
        """
 
2097
        file_id = ie.file_id
 
2098
        rev_id = rev.revision_id
 
2099
        w = self.text_weaves.get(file_id)
 
2100
        if w is None:
 
2101
            w = Weave(file_id)
 
2102
            self.text_weaves[file_id] = w
 
2103
        text_changed = False
 
2104
        parent_candiate_entries = ie.parent_candidates(parent_invs)
 
2105
        heads = graph.Graph(self).heads(parent_candiate_entries.keys())
 
2106
        # XXX: Note that this is unordered - and this is tolerable because 
 
2107
        # the previous code was also unordered.
 
2108
        previous_entries = dict((head, parent_candiate_entries[head]) for head
 
2109
            in heads)
 
2110
        self.snapshot_ie(previous_entries, ie, w, rev_id)
 
2111
        del ie.text_id
 
2112
 
 
2113
    @symbol_versioning.deprecated_method(symbol_versioning.one_one)
 
2114
    def get_parents(self, revision_ids):
 
2115
        for revision_id in revision_ids:
 
2116
            yield self.revisions[revision_id].parent_ids
 
2117
 
 
2118
    def get_parent_map(self, revision_ids):
 
2119
        """See graph._StackedParentsProvider.get_parent_map"""
 
2120
        return dict((revision_id, self.revisions[revision_id])
 
2121
                    for revision_id in revision_ids
 
2122
                     if revision_id in self.revisions)
 
2123
 
 
2124
    def snapshot_ie(self, previous_revisions, ie, w, rev_id):
 
2125
        # TODO: convert this logic, which is ~= snapshot to
 
2126
        # a call to:. This needs the path figured out. rather than a work_tree
 
2127
        # a v4 revision_tree can be given, or something that looks enough like
 
2128
        # one to give the file content to the entry if it needs it.
 
2129
        # and we need something that looks like a weave store for snapshot to 
 
2130
        # save against.
 
2131
        #ie.snapshot(rev, PATH, previous_revisions, REVISION_TREE, InMemoryWeaveStore(self.text_weaves))
 
2132
        if len(previous_revisions) == 1:
 
2133
            previous_ie = previous_revisions.values()[0]
 
2134
            if ie._unchanged(previous_ie):
 
2135
                ie.revision = previous_ie.revision
 
2136
                return
 
2137
        if ie.has_text():
 
2138
            text = self.branch.repository.weave_store.get(ie.text_id)
 
2139
            file_lines = text.readlines()
 
2140
            w.add_lines(rev_id, previous_revisions, file_lines)
 
2141
            self.text_count += 1
 
2142
        else:
 
2143
            w.add_lines(rev_id, previous_revisions, [])
 
2144
        ie.revision = rev_id
 
2145
 
 
2146
    def _make_order(self):
 
2147
        """Return a suitable order for importing revisions.
 
2148
 
 
2149
        The order must be such that an revision is imported after all
 
2150
        its (present) parents.
 
2151
        """
 
2152
        todo = set(self.revisions.keys())
 
2153
        done = self.absent_revisions.copy()
 
2154
        order = []
 
2155
        while todo:
 
2156
            # scan through looking for a revision whose parents
 
2157
            # are all done
 
2158
            for rev_id in sorted(list(todo)):
 
2159
                rev = self.revisions[rev_id]
 
2160
                parent_ids = set(rev.parent_ids)
 
2161
                if parent_ids.issubset(done):
 
2162
                    # can take this one now
 
2163
                    order.append(rev_id)
 
2164
                    todo.remove(rev_id)
 
2165
                    done.add(rev_id)
 
2166
        return order
 
2167
 
 
2168
 
 
2169
class ConvertBzrDir5To6(Converter):
 
2170
    """Converts format 5 bzr dirs to format 6."""
 
2171
 
 
2172
    def convert(self, to_convert, pb):
 
2173
        """See Converter.convert()."""
 
2174
        self.bzrdir = to_convert
 
2175
        self.pb = pb
 
2176
        self.pb.note('starting upgrade from format 5 to 6')
 
2177
        self._convert_to_prefixed()
 
2178
        return BzrDir.open(self.bzrdir.root_transport.base)
 
2179
 
 
2180
    def _convert_to_prefixed(self):
 
2181
        from bzrlib.store import TransportStore
 
2182
        self.bzrdir.transport.delete('branch-format')
 
2183
        for store_name in ["weaves", "revision-store"]:
 
2184
            self.pb.note("adding prefixes to %s" % store_name)
 
2185
            store_transport = self.bzrdir.transport.clone(store_name)
 
2186
            store = TransportStore(store_transport, prefixed=True)
 
2187
            for urlfilename in store_transport.list_dir('.'):
 
2188
                filename = urlutils.unescape(urlfilename)
 
2189
                if (filename.endswith(".weave") or
 
2190
                    filename.endswith(".gz") or
 
2191
                    filename.endswith(".sig")):
 
2192
                    file_id, suffix = os.path.splitext(filename)
 
2193
                else:
 
2194
                    file_id = filename
 
2195
                    suffix = ''
 
2196
                new_name = store._mapper.map((file_id,)) + suffix
 
2197
                # FIXME keep track of the dirs made RBC 20060121
 
2198
                try:
 
2199
                    store_transport.move(filename, new_name)
 
2200
                except errors.NoSuchFile: # catches missing dirs strangely enough
 
2201
                    store_transport.mkdir(osutils.dirname(new_name))
 
2202
                    store_transport.move(filename, new_name)
 
2203
        self.bzrdir._control_files.put_utf8('branch-format', BzrDirFormat6().get_format_string())
 
2204
 
 
2205
 
 
2206
class ConvertBzrDir6ToMeta(Converter):
 
2207
    """Converts format 6 bzr dirs to metadirs."""
 
2208
 
 
2209
    def convert(self, to_convert, pb):
 
2210
        """See Converter.convert()."""
 
2211
        from bzrlib.repofmt.weaverepo import RepositoryFormat7
 
2212
        from bzrlib.branch import BzrBranchFormat5
 
2213
        self.bzrdir = to_convert
 
2214
        self.pb = pb
 
2215
        self.count = 0
 
2216
        self.total = 20 # the steps we know about
 
2217
        self.garbage_inventories = []
 
2218
 
 
2219
        self.pb.note('starting upgrade from format 6 to metadir')
 
2220
        self.bzrdir._control_files.put_utf8('branch-format', "Converting to format 6")
 
2221
        # its faster to move specific files around than to open and use the apis...
 
2222
        # first off, nuke ancestry.weave, it was never used.
 
2223
        try:
 
2224
            self.step('Removing ancestry.weave')
 
2225
            self.bzrdir.transport.delete('ancestry.weave')
 
2226
        except errors.NoSuchFile:
 
2227
            pass
 
2228
        # find out whats there
 
2229
        self.step('Finding branch files')
 
2230
        last_revision = self.bzrdir.open_branch().last_revision()
 
2231
        bzrcontents = self.bzrdir.transport.list_dir('.')
 
2232
        for name in bzrcontents:
 
2233
            if name.startswith('basis-inventory.'):
 
2234
                self.garbage_inventories.append(name)
 
2235
        # create new directories for repository, working tree and branch
 
2236
        self.dir_mode = self.bzrdir._control_files._dir_mode
 
2237
        self.file_mode = self.bzrdir._control_files._file_mode
 
2238
        repository_names = [('inventory.weave', True),
 
2239
                            ('revision-store', True),
 
2240
                            ('weaves', True)]
 
2241
        self.step('Upgrading repository  ')
 
2242
        self.bzrdir.transport.mkdir('repository', mode=self.dir_mode)
 
2243
        self.make_lock('repository')
 
2244
        # we hard code the formats here because we are converting into
 
2245
        # the meta format. The meta format upgrader can take this to a 
 
2246
        # future format within each component.
 
2247
        self.put_format('repository', RepositoryFormat7())
 
2248
        for entry in repository_names:
 
2249
            self.move_entry('repository', entry)
 
2250
 
 
2251
        self.step('Upgrading branch      ')
 
2252
        self.bzrdir.transport.mkdir('branch', mode=self.dir_mode)
 
2253
        self.make_lock('branch')
 
2254
        self.put_format('branch', BzrBranchFormat5())
 
2255
        branch_files = [('revision-history', True),
 
2256
                        ('branch-name', True),
 
2257
                        ('parent', False)]
 
2258
        for entry in branch_files:
 
2259
            self.move_entry('branch', entry)
 
2260
 
 
2261
        checkout_files = [('pending-merges', True),
 
2262
                          ('inventory', True),
 
2263
                          ('stat-cache', False)]
 
2264
        # If a mandatory checkout file is not present, the branch does not have
 
2265
        # a functional checkout. Do not create a checkout in the converted
 
2266
        # branch.
 
2267
        for name, mandatory in checkout_files:
 
2268
            if mandatory and name not in bzrcontents:
 
2269
                has_checkout = False
 
2270
                break
 
2271
        else:
 
2272
            has_checkout = True
 
2273
        if not has_checkout:
 
2274
            self.pb.note('No working tree.')
 
2275
            # If some checkout files are there, we may as well get rid of them.
 
2276
            for name, mandatory in checkout_files:
 
2277
                if name in bzrcontents:
 
2278
                    self.bzrdir.transport.delete(name)
 
2279
        else:
 
2280
            from bzrlib.workingtree import WorkingTreeFormat3
 
2281
            self.step('Upgrading working tree')
 
2282
            self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
 
2283
            self.make_lock('checkout')
 
2284
            self.put_format(
 
2285
                'checkout', WorkingTreeFormat3())
 
2286
            self.bzrdir.transport.delete_multi(
 
2287
                self.garbage_inventories, self.pb)
 
2288
            for entry in checkout_files:
 
2289
                self.move_entry('checkout', entry)
 
2290
            if last_revision is not None:
 
2291
                self.bzrdir._control_files.put_utf8(
 
2292
                    'checkout/last-revision', last_revision)
 
2293
        self.bzrdir._control_files.put_utf8(
 
2294
            'branch-format', BzrDirMetaFormat1().get_format_string())
 
2295
        return BzrDir.open(self.bzrdir.root_transport.base)
 
2296
 
 
2297
    def make_lock(self, name):
 
2298
        """Make a lock for the new control dir name."""
 
2299
        self.step('Make %s lock' % name)
 
2300
        ld = lockdir.LockDir(self.bzrdir.transport,
 
2301
                             '%s/lock' % name,
 
2302
                             file_modebits=self.file_mode,
 
2303
                             dir_modebits=self.dir_mode)
 
2304
        ld.create()
 
2305
 
 
2306
    def move_entry(self, new_dir, entry):
 
2307
        """Move then entry name into new_dir."""
 
2308
        name = entry[0]
 
2309
        mandatory = entry[1]
 
2310
        self.step('Moving %s' % name)
 
2311
        try:
 
2312
            self.bzrdir.transport.move(name, '%s/%s' % (new_dir, name))
 
2313
        except errors.NoSuchFile:
 
2314
            if mandatory:
 
2315
                raise
 
2316
 
 
2317
    def put_format(self, dirname, format):
 
2318
        self.bzrdir._control_files.put_utf8('%s/format' % dirname, format.get_format_string())
 
2319
 
 
2320
 
 
2321
class ConvertMetaToMeta(Converter):
 
2322
    """Converts the components of metadirs."""
 
2323
 
 
2324
    def __init__(self, target_format):
 
2325
        """Create a metadir to metadir converter.
 
2326
 
 
2327
        :param target_format: The final metadir format that is desired.
 
2328
        """
 
2329
        self.target_format = target_format
 
2330
 
 
2331
    def convert(self, to_convert, pb):
 
2332
        """See Converter.convert()."""
 
2333
        self.bzrdir = to_convert
 
2334
        self.pb = pb
 
2335
        self.count = 0
 
2336
        self.total = 1
 
2337
        self.step('checking repository format')
 
2338
        try:
 
2339
            repo = self.bzrdir.open_repository()
 
2340
        except errors.NoRepositoryPresent:
 
2341
            pass
 
2342
        else:
 
2343
            if not isinstance(repo._format, self.target_format.repository_format.__class__):
 
2344
                from bzrlib.repository import CopyConverter
 
2345
                self.pb.note('starting repository conversion')
 
2346
                converter = CopyConverter(self.target_format.repository_format)
 
2347
                converter.convert(repo, pb)
 
2348
        try:
 
2349
            branch = self.bzrdir.open_branch()
 
2350
        except errors.NotBranchError:
 
2351
            pass
 
2352
        else:
 
2353
            # TODO: conversions of Branch and Tree should be done by
 
2354
            # InterXFormat lookups
 
2355
            # Avoid circular imports
 
2356
            from bzrlib import branch as _mod_branch
 
2357
            if (branch._format.__class__ is _mod_branch.BzrBranchFormat5 and
 
2358
                self.target_format.get_branch_format().__class__ is
 
2359
                _mod_branch.BzrBranchFormat6):
 
2360
                branch_converter = _mod_branch.Converter5to6()
 
2361
                branch_converter.convert(branch)
 
2362
        try:
 
2363
            tree = self.bzrdir.open_workingtree(recommend_upgrade=False)
 
2364
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
2365
            pass
 
2366
        else:
 
2367
            # TODO: conversions of Branch and Tree should be done by
 
2368
            # InterXFormat lookups
 
2369
            if (isinstance(tree, workingtree.WorkingTree3) and
 
2370
                not isinstance(tree, workingtree_4.WorkingTree4) and
 
2371
                isinstance(self.target_format.workingtree_format,
 
2372
                    workingtree_4.WorkingTreeFormat4)):
 
2373
                workingtree_4.Converter3to4().convert(tree)
 
2374
        return to_convert
 
2375
 
 
2376
 
 
2377
# This is not in remote.py because it's small, and needs to be registered.
 
2378
# Putting it in remote.py creates a circular import problem.
 
2379
# we can make it a lazy object if the control formats is turned into something
 
2380
# like a registry.
 
2381
class RemoteBzrDirFormat(BzrDirMetaFormat1):
 
2382
    """Format representing bzrdirs accessed via a smart server"""
 
2383
 
 
2384
    def get_format_description(self):
 
2385
        return 'bzr remote bzrdir'
 
2386
    
 
2387
    @classmethod
 
2388
    def probe_transport(klass, transport):
 
2389
        """Return a RemoteBzrDirFormat object if it looks possible."""
 
2390
        try:
 
2391
            medium = transport.get_smart_medium()
 
2392
        except (NotImplementedError, AttributeError,
 
2393
                errors.TransportNotPossible, errors.NoSmartMedium):
 
2394
            # no smart server, so not a branch for this format type.
 
2395
            raise errors.NotBranchError(path=transport.base)
 
2396
        else:
 
2397
            # Decline to open it if the server doesn't support our required
 
2398
            # version (2) so that the VFS-based transport will do it.
 
2399
            try:
 
2400
                server_version = medium.protocol_version()
 
2401
            except errors.SmartProtocolError:
 
2402
                # Apparently there's no usable smart server there, even though
 
2403
                # the medium supports the smart protocol.
 
2404
                raise errors.NotBranchError(path=transport.base)
 
2405
            if server_version != 2:
 
2406
                raise errors.NotBranchError(path=transport.base)
 
2407
            return klass()
 
2408
 
 
2409
    def initialize_on_transport(self, transport):
 
2410
        try:
 
2411
            # hand off the request to the smart server
 
2412
            client_medium = transport.get_smart_medium()
 
2413
        except errors.NoSmartMedium:
 
2414
            # TODO: lookup the local format from a server hint.
 
2415
            local_dir_format = BzrDirMetaFormat1()
 
2416
            return local_dir_format.initialize_on_transport(transport)
 
2417
        client = _SmartClient(client_medium, transport.base)
 
2418
        path = client.remote_path_from_transport(transport)
 
2419
        response = client.call('BzrDirFormat.initialize', path)
 
2420
        if response[0] != 'ok':
 
2421
            raise errors.SmartProtocolError('unexpected response code %s' % (response,))
 
2422
        return remote.RemoteBzrDir(transport)
 
2423
 
 
2424
    def _open(self, transport):
 
2425
        return remote.RemoteBzrDir(transport)
 
2426
 
 
2427
    def __eq__(self, other):
 
2428
        if not isinstance(other, RemoteBzrDirFormat):
 
2429
            return False
 
2430
        return self.get_format_description() == other.get_format_description()
 
2431
 
 
2432
 
 
2433
BzrDirFormat.register_control_server_format(RemoteBzrDirFormat)
 
2434
 
 
2435
 
 
2436
class BzrDirFormatInfo(object):
 
2437
 
 
2438
    def __init__(self, native, deprecated, hidden, experimental):
 
2439
        self.deprecated = deprecated
 
2440
        self.native = native
 
2441
        self.hidden = hidden
 
2442
        self.experimental = experimental
 
2443
 
 
2444
 
 
2445
class BzrDirFormatRegistry(registry.Registry):
 
2446
    """Registry of user-selectable BzrDir subformats.
 
2447
    
 
2448
    Differs from BzrDirFormat._control_formats in that it provides sub-formats,
 
2449
    e.g. BzrDirMeta1 with weave repository.  Also, it's more user-oriented.
 
2450
    """
 
2451
 
 
2452
    def __init__(self):
 
2453
        """Create a BzrDirFormatRegistry."""
 
2454
        self._aliases = set()
 
2455
        super(BzrDirFormatRegistry, self).__init__()
 
2456
 
 
2457
    def aliases(self):
 
2458
        """Return a set of the format names which are aliases."""
 
2459
        return frozenset(self._aliases)
 
2460
 
 
2461
    def register_metadir(self, key,
 
2462
             repository_format, help, native=True, deprecated=False,
 
2463
             branch_format=None,
 
2464
             tree_format=None,
 
2465
             hidden=False,
 
2466
             experimental=False,
 
2467
             alias=False):
 
2468
        """Register a metadir subformat.
 
2469
 
 
2470
        These all use a BzrDirMetaFormat1 bzrdir, but can be parameterized
 
2471
        by the Repository format.
 
2472
 
 
2473
        :param repository_format: The fully-qualified repository format class
 
2474
            name as a string.
 
2475
        :param branch_format: Fully-qualified branch format class name as
 
2476
            a string.
 
2477
        :param tree_format: Fully-qualified tree format class name as
 
2478
            a string.
 
2479
        """
 
2480
        # This should be expanded to support setting WorkingTree and Branch
 
2481
        # formats, once BzrDirMetaFormat1 supports that.
 
2482
        def _load(full_name):
 
2483
            mod_name, factory_name = full_name.rsplit('.', 1)
 
2484
            try:
 
2485
                mod = __import__(mod_name, globals(), locals(),
 
2486
                        [factory_name])
 
2487
            except ImportError, e:
 
2488
                raise ImportError('failed to load %s: %s' % (full_name, e))
 
2489
            try:
 
2490
                factory = getattr(mod, factory_name)
 
2491
            except AttributeError:
 
2492
                raise AttributeError('no factory %s in module %r'
 
2493
                    % (full_name, mod))
 
2494
            return factory()
 
2495
 
 
2496
        def helper():
 
2497
            bd = BzrDirMetaFormat1()
 
2498
            if branch_format is not None:
 
2499
                bd.set_branch_format(_load(branch_format))
 
2500
            if tree_format is not None:
 
2501
                bd.workingtree_format = _load(tree_format)
 
2502
            if repository_format is not None:
 
2503
                bd.repository_format = _load(repository_format)
 
2504
            return bd
 
2505
        self.register(key, helper, help, native, deprecated, hidden,
 
2506
            experimental, alias)
 
2507
 
 
2508
    def register(self, key, factory, help, native=True, deprecated=False,
 
2509
                 hidden=False, experimental=False, alias=False):
 
2510
        """Register a BzrDirFormat factory.
 
2511
        
 
2512
        The factory must be a callable that takes one parameter: the key.
 
2513
        It must produce an instance of the BzrDirFormat when called.
 
2514
 
 
2515
        This function mainly exists to prevent the info object from being
 
2516
        supplied directly.
 
2517
        """
 
2518
        registry.Registry.register(self, key, factory, help,
 
2519
            BzrDirFormatInfo(native, deprecated, hidden, experimental))
 
2520
        if alias:
 
2521
            self._aliases.add(key)
 
2522
 
 
2523
    def register_lazy(self, key, module_name, member_name, help, native=True,
 
2524
        deprecated=False, hidden=False, experimental=False, alias=False):
 
2525
        registry.Registry.register_lazy(self, key, module_name, member_name,
 
2526
            help, BzrDirFormatInfo(native, deprecated, hidden, experimental))
 
2527
        if alias:
 
2528
            self._aliases.add(key)
 
2529
 
 
2530
    def set_default(self, key):
 
2531
        """Set the 'default' key to be a clone of the supplied key.
 
2532
        
 
2533
        This method must be called once and only once.
 
2534
        """
 
2535
        registry.Registry.register(self, 'default', self.get(key),
 
2536
            self.get_help(key), info=self.get_info(key))
 
2537
        self._aliases.add('default')
 
2538
 
 
2539
    def set_default_repository(self, key):
 
2540
        """Set the FormatRegistry default and Repository default.
 
2541
        
 
2542
        This is a transitional method while Repository.set_default_format
 
2543
        is deprecated.
 
2544
        """
 
2545
        if 'default' in self:
 
2546
            self.remove('default')
 
2547
        self.set_default(key)
 
2548
        format = self.get('default')()
 
2549
 
 
2550
    def make_bzrdir(self, key):
 
2551
        return self.get(key)()
 
2552
 
 
2553
    def help_topic(self, topic):
 
2554
        output = textwrap.dedent("""\
 
2555
            These formats can be used for creating branches, working trees, and
 
2556
            repositories.
 
2557
 
 
2558
            """)
 
2559
        default_realkey = None
 
2560
        default_help = self.get_help('default')
 
2561
        help_pairs = []
 
2562
        for key in self.keys():
 
2563
            if key == 'default':
 
2564
                continue
 
2565
            help = self.get_help(key)
 
2566
            if help == default_help:
 
2567
                default_realkey = key
 
2568
            else:
 
2569
                help_pairs.append((key, help))
 
2570
 
 
2571
        def wrapped(key, help, info):
 
2572
            if info.native:
 
2573
                help = '(native) ' + help
 
2574
            return ':%s:\n%s\n\n' % (key, 
 
2575
                    textwrap.fill(help, initial_indent='    ', 
 
2576
                    subsequent_indent='    '))
 
2577
        if default_realkey is not None:
 
2578
            output += wrapped(default_realkey, '(default) %s' % default_help,
 
2579
                              self.get_info('default'))
 
2580
        deprecated_pairs = []
 
2581
        experimental_pairs = []
 
2582
        for key, help in help_pairs:
 
2583
            info = self.get_info(key)
 
2584
            if info.hidden:
 
2585
                continue
 
2586
            elif info.deprecated:
 
2587
                deprecated_pairs.append((key, help))
 
2588
            elif info.experimental:
 
2589
                experimental_pairs.append((key, help))
 
2590
            else:
 
2591
                output += wrapped(key, help, info)
 
2592
        if len(experimental_pairs) > 0:
 
2593
            output += "Experimental formats are shown below.\n\n"
 
2594
            for key, help in experimental_pairs:
 
2595
                info = self.get_info(key)
 
2596
                output += wrapped(key, help, info)
 
2597
        if len(deprecated_pairs) > 0:
 
2598
            output += "Deprecated formats are shown below.\n\n"
 
2599
            for key, help in deprecated_pairs:
 
2600
                info = self.get_info(key)
 
2601
                output += wrapped(key, help, info)
 
2602
 
 
2603
        return output
 
2604
 
 
2605
 
 
2606
class RepositoryAcquisitionPolicy(object):
 
2607
    """Abstract base class for repository acquisition policies.
 
2608
 
 
2609
    A repository acquisition policy decides how a BzrDir acquires a repository
 
2610
    for a branch that is being created.  The most basic policy decision is
 
2611
    whether to create a new repository or use an existing one.
 
2612
    """
 
2613
 
 
2614
    def configure_branch(self, branch):
 
2615
        """Apply any configuration data from this policy to the branch.
 
2616
 
 
2617
        Default implementation does nothing.
 
2618
        """
 
2619
        pass
 
2620
 
 
2621
    def acquire_repository(self, make_working_trees=None, shared=False):
 
2622
        """Acquire a repository for this bzrdir.
 
2623
 
 
2624
        Implementations may create a new repository or use a pre-exising
 
2625
        repository.
 
2626
        :param make_working_trees: If creating a repository, set
 
2627
            make_working_trees to this value (if non-None)
 
2628
        :param shared: If creating a repository, make it shared if True
 
2629
        :return: A repository
 
2630
        """
 
2631
        raise NotImplemented(RepositoryAcquisitionPolicy.acquire_repository)
 
2632
 
 
2633
 
 
2634
class CreateRepository(RepositoryAcquisitionPolicy):
 
2635
    """A policy of creating a new repository"""
 
2636
 
 
2637
    def __init__(self, bzrdir):
 
2638
        RepositoryAcquisitionPolicy.__init__(self)
 
2639
        self._bzrdir = bzrdir
 
2640
 
 
2641
    def acquire_repository(self, make_working_trees=None, shared=False):
 
2642
        """Implementation of RepositoryAcquisitionPolicy.acquire_repository
 
2643
 
 
2644
        Creates the desired repository in the bzrdir we already have.
 
2645
        """
 
2646
        repository = self._bzrdir.create_repository(shared=shared)
 
2647
        if make_working_trees is not None:
 
2648
            repository.set_make_working_trees(make_working_trees)
 
2649
        return repository
 
2650
 
 
2651
 
 
2652
class UseExistingRepository(RepositoryAcquisitionPolicy):
 
2653
    """A policy of reusing an existing repository"""
 
2654
 
 
2655
    def __init__(self, repository):
 
2656
        RepositoryAcquisitionPolicy.__init__(self)
 
2657
        self._repository = repository
 
2658
 
 
2659
    def acquire_repository(self, make_working_trees=None, shared=False):
 
2660
        """Implementation of RepositoryAcquisitionPolicy.acquire_repository
 
2661
 
 
2662
        Returns an existing repository to use
 
2663
        """
 
2664
        return self._repository
 
2665
 
 
2666
 
 
2667
format_registry = BzrDirFormatRegistry()
 
2668
format_registry.register('weave', BzrDirFormat6,
 
2669
    'Pre-0.8 format.  Slower than knit and does not'
 
2670
    ' support checkouts or shared repositories.',
 
2671
    deprecated=True)
 
2672
format_registry.register_metadir('knit',
 
2673
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
 
2674
    'Format using knits.  Recommended for interoperation with bzr <= 0.14.',
 
2675
    branch_format='bzrlib.branch.BzrBranchFormat5',
 
2676
    tree_format='bzrlib.workingtree.WorkingTreeFormat3')
 
2677
format_registry.register_metadir('metaweave',
 
2678
    'bzrlib.repofmt.weaverepo.RepositoryFormat7',
 
2679
    'Transitional format in 0.8.  Slower than knit.',
 
2680
    branch_format='bzrlib.branch.BzrBranchFormat5',
 
2681
    tree_format='bzrlib.workingtree.WorkingTreeFormat3',
 
2682
    deprecated=True)
 
2683
format_registry.register_metadir('dirstate',
 
2684
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
 
2685
    help='New in 0.15: Fast local operations. Compatible with bzr 0.8 and '
 
2686
        'above when accessed over the network.',
 
2687
    branch_format='bzrlib.branch.BzrBranchFormat5',
 
2688
    # this uses bzrlib.workingtree.WorkingTreeFormat4 because importing
 
2689
    # directly from workingtree_4 triggers a circular import.
 
2690
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
2691
    )
 
2692
format_registry.register_metadir('dirstate-tags',
 
2693
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
 
2694
    help='New in 0.15: Fast local operations and improved scaling for '
 
2695
        'network operations. Additionally adds support for tags.'
 
2696
        ' Incompatible with bzr < 0.15.',
 
2697
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
2698
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
2699
    )
 
2700
format_registry.register_metadir('rich-root',
 
2701
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit4',
 
2702
    help='New in 1.0.  Better handling of tree roots.  Incompatible with'
 
2703
        ' bzr < 1.0',
 
2704
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
2705
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
2706
    )
 
2707
format_registry.register_metadir('dirstate-with-subtree',
 
2708
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
 
2709
    help='New in 0.15: Fast local operations and improved scaling for '
 
2710
        'network operations. Additionally adds support for versioning nested '
 
2711
        'bzr branches. Incompatible with bzr < 0.15.',
 
2712
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
2713
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
2714
    experimental=True,
 
2715
    hidden=True,
 
2716
    )
 
2717
format_registry.register_metadir('pack-0.92',
 
2718
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack1',
 
2719
    help='New in 0.92: Pack-based format with data compatible with '
 
2720
        'dirstate-tags format repositories. Interoperates with '
 
2721
        'bzr repositories before 0.92 but cannot be read by bzr < 0.92. '
 
2722
        'Previously called knitpack-experimental.  '
 
2723
        'For more information, see '
 
2724
        'http://doc.bazaar-vcs.org/latest/developers/packrepo.html.',
 
2725
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
2726
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
2727
    )
 
2728
format_registry.register_metadir('pack-0.92-subtree',
 
2729
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack3',
 
2730
    help='New in 0.92: Pack-based format with data compatible with '
 
2731
        'dirstate-with-subtree format repositories. Interoperates with '
 
2732
        'bzr repositories before 0.92 but cannot be read by bzr < 0.92. '
 
2733
        'Previously called knitpack-experimental.  '
 
2734
        'For more information, see '
 
2735
        'http://doc.bazaar-vcs.org/latest/developers/packrepo.html.',
 
2736
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
2737
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
2738
    hidden=True,
 
2739
    experimental=True,
 
2740
    )
 
2741
format_registry.register_metadir('rich-root-pack',
 
2742
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack4',
 
2743
    help='New in 1.0: Pack-based format with data compatible with '
 
2744
        'rich-root format repositories. Incompatible with'
 
2745
        ' bzr < 1.0',
 
2746
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
2747
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
2748
    )
 
2749
# The following two formats should always just be aliases.
 
2750
format_registry.register_metadir('development',
 
2751
    'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment0',
 
2752
    help='Current development format. Can convert data to and from pack-0.92 '
 
2753
        '(and anything compatible with pack-0.92) format repositories. '
 
2754
        'Repositories in this format can only be read by bzr.dev. '
 
2755
        'Please read '
 
2756
        'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
 
2757
        'before use.',
 
2758
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
2759
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
2760
    experimental=True,
 
2761
    alias=True,
 
2762
    )
 
2763
format_registry.register_metadir('development-subtree',
 
2764
    'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment0Subtree',
 
2765
    help='Current development format, subtree variant. Can convert data to and '
 
2766
        'from pack-0.92 (and anything compatible with pack-0.92) format '
 
2767
        'repositories. Repositories in this format can only be read by '
 
2768
        'bzr.dev. Please read '
 
2769
        'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
 
2770
        'before use.',
 
2771
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
2772
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
2773
    experimental=True,
 
2774
    alias=True,
 
2775
    )
 
2776
# And the development formats which the will have aliased one of follow:
 
2777
format_registry.register_metadir('development0',
 
2778
    'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment0',
 
2779
    help='Trivial rename of pack-0.92 to provide a development format. '
 
2780
        'Please read '
 
2781
        'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
 
2782
        'before use.',
 
2783
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
2784
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
2785
    hidden=True,
 
2786
    experimental=True,
 
2787
    )
 
2788
format_registry.register_metadir('development0-subtree',
 
2789
    'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment0Subtree',
 
2790
    help='Trivial rename of pack-0.92-subtree to provide a development format. '
 
2791
        'Please read '
 
2792
        'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
 
2793
        'before use.',
 
2794
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
2795
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
2796
    hidden=True,
 
2797
    experimental=True,
 
2798
    )
 
2799
format_registry.set_default('pack-0.92')