/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 bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
22
22
 
23
23
# TODO: remove unittest dependency; put that stuff inside the test suite
24
24
 
25
 
# TODO: The Format probe_transport seems a bit redundant with just trying to
26
 
# open the bzrdir. -- mbp
27
 
#
28
25
# TODO: Can we move specific formats into separate modules to make this file
29
26
# smaller?
30
27
 
31
28
from cStringIO import StringIO
32
29
import os
 
30
import textwrap
33
31
 
34
32
from bzrlib.lazy_import import lazy_import
35
33
lazy_import(globals(), """
42
40
    errors,
43
41
    lockable_files,
44
42
    lockdir,
 
43
    registry,
 
44
    remote,
45
45
    revision as _mod_revision,
46
 
    repository as _mod_repository,
 
46
    symbol_versioning,
 
47
    ui,
47
48
    urlutils,
48
49
    xml4,
49
50
    xml5,
 
51
    workingtree,
 
52
    workingtree_4,
50
53
    )
51
54
from bzrlib.osutils import (
52
55
    safe_unicode,
53
56
    sha_strings,
54
57
    sha_string,
55
58
    )
 
59
from bzrlib.smart.client import _SmartClient
56
60
from bzrlib.store.revision.text import TextRevisionStore
57
61
from bzrlib.store.text import TextStore
58
62
from bzrlib.store.versioned import WeaveStore
59
63
from bzrlib.transactions import WriteTransaction
60
 
from bzrlib.transport import get_transport
 
64
from bzrlib.transport import (
 
65
    do_catching_redirections,
 
66
    get_transport,
 
67
    )
61
68
from bzrlib.weave import Weave
62
69
""")
63
70
 
64
 
from bzrlib.trace import mutter
 
71
from bzrlib.trace import (
 
72
    mutter,
 
73
    note,
 
74
    )
65
75
from bzrlib.transport.local import LocalTransport
66
76
 
67
77
 
83
93
        If there is a tree, the tree is opened and break_lock() called.
84
94
        Otherwise, branch is tried, and finally repository.
85
95
        """
 
96
        # XXX: This seems more like a UI function than something that really
 
97
        # belongs in this class.
86
98
        try:
87
99
            thing_to_unlock = self.open_workingtree()
88
100
        except (errors.NotLocalUrl, errors.NoWorkingTree):
105
117
        source_repo_format.check_conversion_target(target_repo_format)
106
118
 
107
119
    @staticmethod
108
 
    def _check_supported(format, allow_unsupported):
109
 
        """Check whether format is a supported format.
110
 
 
111
 
        If allow_unsupported is True, this is a no-op.
 
120
    def _check_supported(format, allow_unsupported,
 
121
        recommend_upgrade=True,
 
122
        basedir=None):
 
123
        """Give an error or warning on old formats.
 
124
 
 
125
        :param format: may be any kind of format - workingtree, branch, 
 
126
        or repository.
 
127
 
 
128
        :param allow_unsupported: If true, allow opening 
 
129
        formats that are strongly deprecated, and which may 
 
130
        have limited functionality.
 
131
 
 
132
        :param recommend_upgrade: If true (default), warn
 
133
        the user through the ui object that they may wish
 
134
        to upgrade the object.
112
135
        """
 
136
        # TODO: perhaps move this into a base Format class; it's not BzrDir
 
137
        # specific. mbp 20070323
113
138
        if not allow_unsupported and not format.is_supported():
114
139
            # see open_downlevel to open legacy branches.
115
140
            raise errors.UnsupportedFormatError(format=format)
 
141
        if recommend_upgrade \
 
142
            and getattr(format, 'upgrade_recommended', False):
 
143
            ui.ui_factory.recommend_upgrade(
 
144
                format.get_format_description(),
 
145
                basedir)
116
146
 
117
 
    def clone(self, url, revision_id=None, basis=None, force_new_repo=False):
 
147
    def clone(self, url, revision_id=None, force_new_repo=False):
118
148
        """Clone this bzrdir and its contents to url verbatim.
119
149
 
120
150
        If urls last component does not exist, it will be created.
125
155
                               even if one is available.
126
156
        """
127
157
        self._make_tail(url)
128
 
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
129
158
        result = self._format.initialize(url)
130
159
        try:
131
160
            local_repo = self.find_repository()
136
165
            if force_new_repo:
137
166
                result_repo = local_repo.clone(
138
167
                    result,
139
 
                    revision_id=revision_id,
140
 
                    basis=basis_repo)
 
168
                    revision_id=revision_id)
141
169
                result_repo.set_make_working_trees(local_repo.make_working_trees())
142
170
            else:
143
171
                try:
144
172
                    result_repo = result.find_repository()
145
173
                    # fetch content this dir needs.
146
 
                    if basis_repo:
147
 
                        # XXX FIXME RBC 20060214 need tests for this when the basis
148
 
                        # is incomplete
149
 
                        result_repo.fetch(basis_repo, revision_id=revision_id)
150
174
                    result_repo.fetch(local_repo, revision_id=revision_id)
151
175
                except errors.NoRepositoryPresent:
152
176
                    # needed to make one anyway.
153
177
                    result_repo = local_repo.clone(
154
178
                        result,
155
 
                        revision_id=revision_id,
156
 
                        basis=basis_repo)
 
179
                        revision_id=revision_id)
157
180
                    result_repo.set_make_working_trees(local_repo.make_working_trees())
158
181
        # 1 if there is a branch present
159
182
        #   make sure its content is available in the target repository
163
186
        except errors.NotBranchError:
164
187
            pass
165
188
        try:
166
 
            self.open_workingtree().clone(result, basis=basis_tree)
 
189
            self.open_workingtree().clone(result)
167
190
        except (errors.NoWorkingTree, errors.NotLocalUrl):
168
191
            pass
169
192
        return result
170
193
 
171
 
    def _get_basis_components(self, basis):
172
 
        """Retrieve the basis components that are available at basis."""
173
 
        if basis is None:
174
 
            return None, None, None
175
 
        try:
176
 
            basis_tree = basis.open_workingtree()
177
 
            basis_branch = basis_tree.branch
178
 
            basis_repo = basis_branch.repository
179
 
        except (errors.NoWorkingTree, errors.NotLocalUrl):
180
 
            basis_tree = None
181
 
            try:
182
 
                basis_branch = basis.open_branch()
183
 
                basis_repo = basis_branch.repository
184
 
            except errors.NotBranchError:
185
 
                basis_branch = None
186
 
                try:
187
 
                    basis_repo = basis.open_repository()
188
 
                except errors.NoRepositoryPresent:
189
 
                    basis_repo = None
190
 
        return basis_repo, basis_branch, basis_tree
191
 
 
192
194
    # TODO: This should be given a Transport, and should chdir up; otherwise
193
195
    # this will open a new connection.
194
196
    def _make_tail(self, url):
202
204
 
203
205
    # TODO: Should take a Transport
204
206
    @classmethod
205
 
    def create(cls, base):
 
207
    def create(cls, base, format=None):
206
208
        """Create a new BzrDir at the url 'base'.
207
209
        
208
210
        This will call the current default formats initialize with base
209
211
        as the only parameter.
210
212
 
211
 
        If you need a specific format, consider creating an instance
212
 
        of that and calling initialize().
 
213
        :param format: If supplied, the format of branch to create.  If not
 
214
            supplied, the default is used.
213
215
        """
214
216
        if cls is not BzrDir:
215
 
            raise AssertionError("BzrDir.create always creates the default format, "
216
 
                    "not one of %r" % cls)
 
217
            raise AssertionError("BzrDir.create always creates the default"
 
218
                " format, not one of %r" % cls)
217
219
        head, tail = urlutils.split(base)
218
220
        if tail and tail != '.':
219
221
            t = get_transport(head)
221
223
                t.mkdir(tail)
222
224
            except errors.FileExists:
223
225
                pass
224
 
        return BzrDirFormat.get_default_format().initialize(safe_unicode(base))
 
226
        if format is None:
 
227
            format = BzrDirFormat.get_default_format()
 
228
        return format.initialize(safe_unicode(base))
225
229
 
226
230
    def create_branch(self):
227
231
        """Create a branch in this BzrDir.
232
236
        raise NotImplementedError(self.create_branch)
233
237
 
234
238
    @staticmethod
235
 
    def create_branch_and_repo(base, force_new_repo=False):
 
239
    def create_branch_and_repo(base, force_new_repo=False, format=None):
236
240
        """Create a new BzrDir, Branch and Repository at the url 'base'.
237
241
 
238
242
        This will use the current default BzrDirFormat, and use whatever 
245
249
        :param base: The URL to create the branch at.
246
250
        :param force_new_repo: If True a new repository is always created.
247
251
        """
248
 
        bzrdir = BzrDir.create(base)
 
252
        bzrdir = BzrDir.create(base, format)
249
253
        bzrdir._find_or_create_repository(force_new_repo)
250
254
        return bzrdir.create_branch()
251
255
 
289
293
            t = get_transport(safe_unicode(base))
290
294
            if not isinstance(t, LocalTransport):
291
295
                raise errors.NotLocalUrl(base)
292
 
        if format is None:
293
 
            bzrdir = BzrDir.create(base)
294
 
        else:
295
 
            bzrdir = format.initialize(base)
 
296
        bzrdir = BzrDir.create(base, format)
296
297
        repo = bzrdir._find_or_create_repository(force_new_repo)
297
298
        result = bzrdir.create_branch()
298
299
        if force_new_tree or (repo.make_working_trees() and 
304
305
        return result
305
306
        
306
307
    @staticmethod
307
 
    def create_repository(base, shared=False):
 
308
    def create_repository(base, shared=False, format=None):
308
309
        """Create a new BzrDir and Repository at the url 'base'.
309
310
 
310
 
        This will use the current default BzrDirFormat, and use whatever 
311
 
        repository format that that uses for bzrdirformat.create_repository.
 
311
        If no format is supplied, this will default to the current default
 
312
        BzrDirFormat by default, and use whatever repository format that that
 
313
        uses for bzrdirformat.create_repository.
312
314
 
313
315
        :param shared: Create a shared repository rather than a standalone
314
316
                       repository.
318
320
        it should take no parameters and construct whatever repository format
319
321
        that child class desires.
320
322
        """
321
 
        bzrdir = BzrDir.create(base)
 
323
        bzrdir = BzrDir.create(base, format)
322
324
        return bzrdir.create_repository(shared)
323
325
 
324
326
    @staticmethod
325
 
    def create_standalone_workingtree(base):
 
327
    def create_standalone_workingtree(base, format=None):
326
328
        """Create a new BzrDir, WorkingTree, Branch and Repository at 'base'.
327
329
 
328
330
        'base' must be a local path or a file:// url.
337
339
        if not isinstance(t, LocalTransport):
338
340
            raise errors.NotLocalUrl(base)
339
341
        bzrdir = BzrDir.create_branch_and_repo(safe_unicode(base),
340
 
                                               force_new_repo=True).bzrdir
 
342
                                               force_new_repo=True,
 
343
                                               format=format).bzrdir
341
344
        return bzrdir.create_workingtree()
342
345
 
343
346
    def create_workingtree(self, revision_id=None):
347
350
        """
348
351
        raise NotImplementedError(self.create_workingtree)
349
352
 
 
353
    def retire_bzrdir(self):
 
354
        """Permanently disable the bzrdir.
 
355
 
 
356
        This is done by renaming it to give the user some ability to recover
 
357
        if there was a problem.
 
358
 
 
359
        This will have horrible consequences if anyone has anything locked or
 
360
        in use.
 
361
        """
 
362
        for i in xrange(10000):
 
363
            try:
 
364
                to_path = '.bzr.retired.%d' % i
 
365
                self.root_transport.rename('.bzr', to_path)
 
366
                note("renamed %s to %s"
 
367
                    % (self.root_transport.abspath('.bzr'), to_path))
 
368
                break
 
369
            except (errors.TransportError, IOError, errors.PathError):
 
370
                pass
 
371
 
350
372
    def destroy_workingtree(self):
351
373
        """Destroy the working tree at this BzrDir.
352
374
 
392
414
                    break
393
415
                else:
394
416
                    continue
395
 
            if ((found_bzrdir.root_transport.base == 
 
417
            if ((found_bzrdir.root_transport.base ==
396
418
                 self.root_transport.base) or repository.is_shared()):
397
419
                return repository
398
420
            else:
399
421
                raise errors.NoRepositoryPresent(self)
400
422
        raise errors.NoRepositoryPresent(self)
401
423
 
 
424
    def get_branch_reference(self):
 
425
        """Return the referenced URL for the branch in this bzrdir.
 
426
 
 
427
        :raises NotBranchError: If there is no Branch.
 
428
        :return: The URL the branch in this bzrdir references if it is a
 
429
            reference branch, or None for regular branches.
 
430
        """
 
431
        return None
 
432
 
402
433
    def get_branch_transport(self, branch_format):
403
434
        """Get the transport for use by branch format in this BzrDir.
404
435
 
429
460
        """Get the transport for use by workingtree format in this BzrDir.
430
461
 
431
462
        Note that bzr dirs that do not support format strings will raise
432
 
        IncompatibleFormat if the workingtree format they are given has
433
 
        a format string, and vice versa.
 
463
        IncompatibleFormat if the workingtree format they are given has a
 
464
        format string, and vice versa.
434
465
 
435
466
        If workingtree_format is None, the transport is returned with no 
436
467
        checking. if it is not None, then the returned transport is
496
527
        return BzrDir.open_from_transport(t, _unsupported=_unsupported)
497
528
 
498
529
    @staticmethod
499
 
    def open_from_transport(transport, _unsupported=False):
 
530
    def open_from_transport(transport, _unsupported=False,
 
531
                            _server_formats=True):
500
532
        """Open a bzrdir within a particular directory.
501
533
 
502
534
        :param transport: Transport containing the bzrdir.
503
535
        :param _unsupported: private.
504
536
        """
505
 
        format = BzrDirFormat.find_format(transport)
 
537
        base = transport.base
 
538
 
 
539
        def find_format(transport):
 
540
            return transport, BzrDirFormat.find_format(
 
541
                transport, _server_formats=_server_formats)
 
542
 
 
543
        def redirected(transport, e, redirection_notice):
 
544
            qualified_source = e.get_source_url()
 
545
            relpath = transport.relpath(qualified_source)
 
546
            if not e.target.endswith(relpath):
 
547
                # Not redirected to a branch-format, not a branch
 
548
                raise errors.NotBranchError(path=e.target)
 
549
            target = e.target[:-len(relpath)]
 
550
            note('%s is%s redirected to %s',
 
551
                 transport.base, e.permanently, target)
 
552
            # Let's try with a new transport
 
553
            qualified_target = e.get_target_url()[:-len(relpath)]
 
554
            # FIXME: If 'transport' has a qualifier, this should
 
555
            # be applied again to the new transport *iff* the
 
556
            # schemes used are the same. It's a bit tricky to
 
557
            # verify, so I'll punt for now
 
558
            # -- vila20070212
 
559
            return get_transport(target)
 
560
 
 
561
        try:
 
562
            transport, format = do_catching_redirections(find_format,
 
563
                                                         transport,
 
564
                                                         redirected)
 
565
        except errors.TooManyRedirections:
 
566
            raise errors.NotBranchError(base)
 
567
 
506
568
        BzrDir._check_supported(format, _unsupported)
507
569
        return format.open(transport, _found=True)
508
570
 
548
610
                return result, urlutils.unescape(a_transport.relpath(url))
549
611
            except errors.NotBranchError, e:
550
612
                pass
551
 
            new_t = a_transport.clone('..')
 
613
            try:
 
614
                new_t = a_transport.clone('..')
 
615
            except errors.InvalidURLJoin:
 
616
                # reached the root, whatever that may be
 
617
                raise errors.NotBranchError(path=url)
552
618
            if new_t.base == a_transport.base:
553
619
                # reached the root, whatever that may be
554
620
                raise errors.NotBranchError(path=url)
555
621
            a_transport = new_t
556
622
 
 
623
    @classmethod
 
624
    def open_containing_tree_or_branch(klass, location):
 
625
        """Return the branch and working tree contained by a location.
 
626
 
 
627
        Returns (tree, branch, relpath).
 
628
        If there is no tree at containing the location, tree will be None.
 
629
        If there is no branch containing the location, an exception will be
 
630
        raised
 
631
        relpath is the portion of the path that is contained by the branch.
 
632
        """
 
633
        bzrdir, relpath = klass.open_containing(location)
 
634
        try:
 
635
            tree = bzrdir.open_workingtree()
 
636
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
637
            tree = None
 
638
            branch = bzrdir.open_branch()
 
639
        else:
 
640
            branch = tree.branch
 
641
        return tree, branch, relpath
 
642
 
557
643
    def open_repository(self, _unsupported=False):
558
644
        """Open the repository object at this BzrDir if one is present.
559
645
 
566
652
        """
567
653
        raise NotImplementedError(self.open_repository)
568
654
 
569
 
    def open_workingtree(self, _unsupported=False):
 
655
    def open_workingtree(self, _unsupported=False,
 
656
            recommend_upgrade=True):
570
657
        """Open the workingtree object at this BzrDir if one is present.
571
 
        
572
 
        TODO: static convenience version of this?
 
658
 
 
659
        :param recommend_upgrade: Optional keyword parameter, when True (the
 
660
            default), emit through the ui module a recommendation that the user
 
661
            upgrade the working tree when the workingtree being opened is old
 
662
            (but still fully supported).
573
663
        """
574
664
        raise NotImplementedError(self.open_workingtree)
575
665
 
597
687
        workingtree and discards it, and that's somewhat expensive.) 
598
688
        """
599
689
        try:
600
 
            self.open_workingtree()
 
690
            self.open_workingtree(recommend_upgrade=False)
601
691
            return True
602
692
        except errors.NoWorkingTree:
603
693
            return False
604
694
 
605
 
    def cloning_metadir(self, basis=None):
 
695
    def _cloning_metadir(self):
606
696
        """Produce a metadir suitable for cloning with"""
607
 
        def related_repository(bzrdir):
 
697
        result_format = self._format.__class__()
 
698
        try:
608
699
            try:
609
 
                branch = bzrdir.open_branch()
610
 
                return branch.repository
 
700
                branch = self.open_branch()
 
701
                source_repository = branch.repository
611
702
            except errors.NotBranchError:
612
703
                source_branch = None
613
 
                return bzrdir.open_repository()
614
 
        result_format = self._format.__class__()
 
704
                source_repository = self.open_repository()
 
705
        except errors.NoRepositoryPresent:
 
706
            source_repository = None
 
707
        else:
 
708
            # XXX TODO: This isinstance is here because we have not implemented
 
709
            # the fix recommended in bug # 103195 - to delegate this choice the
 
710
            # repository itself.
 
711
            repo_format = source_repository._format
 
712
            if not isinstance(repo_format, remote.RemoteRepositoryFormat):
 
713
                result_format.repository_format = repo_format
615
714
        try:
616
 
            try:
617
 
                source_repository = related_repository(self)
618
 
            except errors.NoRepositoryPresent:
619
 
                if basis is None:
620
 
                    raise
621
 
                source_repository = related_repository(self)
622
 
            result_format.repository_format = source_repository._format
623
 
        except errors.NoRepositoryPresent:
624
 
            pass
625
 
        return result_format
626
 
 
627
 
    def sprout(self, url, revision_id=None, basis=None, force_new_repo=False):
 
715
            # TODO: Couldn't we just probe for the format in these cases,
 
716
            # rather than opening the whole tree?  It would be a little
 
717
            # faster. mbp 20070401
 
718
            tree = self.open_workingtree(recommend_upgrade=False)
 
719
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
720
            result_format.workingtree_format = None
 
721
        else:
 
722
            result_format.workingtree_format = tree._format.__class__()
 
723
        return result_format, source_repository
 
724
 
 
725
    def cloning_metadir(self):
 
726
        """Produce a metadir suitable for cloning or sprouting with.
 
727
 
 
728
        These operations may produce workingtrees (yes, even though they're
 
729
        "cloning" something that doesn't have a tree, so a viable workingtree
 
730
        format must be selected.
 
731
        """
 
732
        format, repository = self._cloning_metadir()
 
733
        if format._workingtree_format is None:
 
734
            if repository is None:
 
735
                return format
 
736
            tree_format = repository._format._matchingbzrdir.workingtree_format
 
737
            format.workingtree_format = tree_format.__class__()
 
738
        return format
 
739
 
 
740
    def checkout_metadir(self):
 
741
        return self.cloning_metadir()
 
742
 
 
743
    def sprout(self, url, revision_id=None, force_new_repo=False,
 
744
               recurse='down'):
628
745
        """Create a copy of this bzrdir prepared for use as a new line of
629
746
        development.
630
747
 
639
756
            itself to download less data.
640
757
        """
641
758
        self._make_tail(url)
642
 
        cloning_format = self.cloning_metadir(basis)
 
759
        cloning_format = self.cloning_metadir()
643
760
        result = cloning_format.initialize(url)
644
 
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
645
761
        try:
646
762
            source_branch = self.open_branch()
647
763
            source_repository = source_branch.repository
650
766
            try:
651
767
                source_repository = self.open_repository()
652
768
            except errors.NoRepositoryPresent:
653
 
                # copy the entire basis one if there is one
654
 
                # but there is no repository.
655
 
                source_repository = basis_repo
 
769
                source_repository = None
656
770
        if force_new_repo:
657
771
            result_repo = None
658
772
        else:
673
787
            result_repo = result.create_repository()
674
788
        if result_repo is not None:
675
789
            # fetch needed content into target.
676
 
            if basis_repo:
677
 
                # XXX FIXME RBC 20060214 need tests for this when the basis
678
 
                # is incomplete
679
 
                result_repo.fetch(basis_repo, revision_id=revision_id)
680
790
            if source_repository is not None:
681
791
                result_repo.fetch(source_repository, revision_id=revision_id)
682
792
        if source_branch is not None:
687
797
        #       case that the newly sprouted branch is a remote one
688
798
        if result_repo is None or result_repo.make_working_trees():
689
799
            wt = result.create_workingtree()
690
 
            if wt.inventory.root is None:
691
 
                try:
692
 
                    wt.set_root_id(self.open_workingtree.get_root_id())
693
 
                except errors.NoWorkingTree:
694
 
                    pass
 
800
            wt.lock_write()
 
801
            try:
 
802
                if wt.path2id('') is None:
 
803
                    try:
 
804
                        wt.set_root_id(self.open_workingtree.get_root_id())
 
805
                    except errors.NoWorkingTree:
 
806
                        pass
 
807
            finally:
 
808
                wt.unlock()
 
809
        else:
 
810
            wt = None
 
811
        if recurse == 'down':
 
812
            if wt is not None:
 
813
                basis = wt.basis_tree()
 
814
                basis.lock_read()
 
815
                subtrees = basis.iter_references()
 
816
                recurse_branch = wt.branch
 
817
            elif source_branch is not None:
 
818
                basis = source_branch.basis_tree()
 
819
                basis.lock_read()
 
820
                subtrees = basis.iter_references()
 
821
                recurse_branch = source_branch
 
822
            else:
 
823
                subtrees = []
 
824
                basis = None
 
825
            try:
 
826
                for path, file_id in subtrees:
 
827
                    target = urlutils.join(url, urlutils.escape(path))
 
828
                    sublocation = source_branch.reference_parent(file_id, path)
 
829
                    sublocation.bzrdir.sprout(target,
 
830
                        basis.get_reference_revision(file_id, path),
 
831
                        force_new_repo=force_new_repo, recurse=recurse)
 
832
            finally:
 
833
                if basis is not None:
 
834
                    basis.unlock()
695
835
        return result
696
836
 
697
837
 
712
852
        """Pre-splitout bzrdirs do not suffer from stale locks."""
713
853
        raise NotImplementedError(self.break_lock)
714
854
 
715
 
    def clone(self, url, revision_id=None, basis=None, force_new_repo=False):
 
855
    def clone(self, url, revision_id=None, force_new_repo=False):
716
856
        """See BzrDir.clone()."""
717
857
        from bzrlib.workingtree import WorkingTreeFormat2
718
858
        self._make_tail(url)
719
859
        result = self._format._initialize_for_clone(url)
720
 
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
721
 
        self.open_repository().clone(result, revision_id=revision_id, basis=basis_repo)
 
860
        self.open_repository().clone(result, revision_id=revision_id)
722
861
        from_branch = self.open_branch()
723
862
        from_branch.clone(result, revision_id=revision_id)
724
863
        try:
725
 
            self.open_workingtree().clone(result, basis=basis_tree)
 
864
            self.open_workingtree().clone(result)
726
865
        except errors.NotLocalUrl:
727
866
            # make a new one, this format always has to have one.
728
867
            try:
746
885
    def create_workingtree(self, revision_id=None):
747
886
        """See BzrDir.create_workingtree."""
748
887
        # this looks buggy but is not -really-
 
888
        # because this format creates the workingtree when the bzrdir is
 
889
        # created
749
890
        # clone and sprout will have set the revision_id
750
891
        # and that will have set it for us, its only
751
892
        # specific uses of create_workingtree in isolation
752
893
        # that can do wonky stuff here, and that only
753
894
        # happens for creating checkouts, which cannot be 
754
895
        # done on this format anyway. So - acceptable wart.
755
 
        result = self.open_workingtree()
 
896
        result = self.open_workingtree(recommend_upgrade=False)
756
897
        if revision_id is not None:
757
898
            if revision_id == _mod_revision.NULL_REVISION:
758
899
                result.set_parent_ids([])
814
955
        self._check_supported(format, unsupported)
815
956
        return format.open(self, _found=True)
816
957
 
817
 
    def sprout(self, url, revision_id=None, basis=None, force_new_repo=False):
 
958
    def sprout(self, url, revision_id=None, force_new_repo=False):
818
959
        """See BzrDir.sprout()."""
819
960
        from bzrlib.workingtree import WorkingTreeFormat2
820
961
        self._make_tail(url)
821
962
        result = self._format._initialize_for_clone(url)
822
 
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
823
963
        try:
824
 
            self.open_repository().clone(result, revision_id=revision_id, basis=basis_repo)
 
964
            self.open_repository().clone(result, revision_id=revision_id)
825
965
        except errors.NoRepositoryPresent:
826
966
            pass
827
967
        try:
849
989
 
850
990
    def open_repository(self):
851
991
        """See BzrDir.open_repository."""
852
 
        from bzrlib.repository import RepositoryFormat4
 
992
        from bzrlib.repofmt.weaverepo import RepositoryFormat4
853
993
        return RepositoryFormat4().open(self, _found=True)
854
994
 
855
995
 
861
1001
 
862
1002
    def open_repository(self):
863
1003
        """See BzrDir.open_repository."""
864
 
        from bzrlib.repository import RepositoryFormat5
 
1004
        from bzrlib.repofmt.weaverepo import RepositoryFormat5
865
1005
        return RepositoryFormat5().open(self, _found=True)
866
1006
 
867
 
    def open_workingtree(self, _unsupported=False):
 
1007
    def open_workingtree(self, _unsupported=False,
 
1008
            recommend_upgrade=True):
868
1009
        """See BzrDir.create_workingtree."""
869
1010
        from bzrlib.workingtree import WorkingTreeFormat2
870
 
        return WorkingTreeFormat2().open(self, _found=True)
 
1011
        wt_format = WorkingTreeFormat2()
 
1012
        # we don't warn here about upgrades; that ought to be handled for the
 
1013
        # bzrdir as a whole
 
1014
        return wt_format.open(self, _found=True)
871
1015
 
872
1016
 
873
1017
class BzrDir6(BzrDirPreSplitOut):
878
1022
 
879
1023
    def open_repository(self):
880
1024
        """See BzrDir.open_repository."""
881
 
        from bzrlib.repository import RepositoryFormat6
 
1025
        from bzrlib.repofmt.weaverepo import RepositoryFormat6
882
1026
        return RepositoryFormat6().open(self, _found=True)
883
1027
 
884
 
    def open_workingtree(self, _unsupported=False):
 
1028
    def open_workingtree(self, _unsupported=False,
 
1029
        recommend_upgrade=True):
885
1030
        """See BzrDir.create_workingtree."""
 
1031
        # we don't warn here about upgrades; that ought to be handled for the
 
1032
        # bzrdir as a whole
886
1033
        from bzrlib.workingtree import WorkingTreeFormat2
887
1034
        return WorkingTreeFormat2().open(self, _found=True)
888
1035
 
902
1049
 
903
1050
    def create_branch(self):
904
1051
        """See BzrDir.create_branch."""
905
 
        from bzrlib.branch import BranchFormat
906
 
        return BranchFormat.get_default_format().initialize(self)
 
1052
        return self._format.get_branch_format().initialize(self)
907
1053
 
908
1054
    def create_repository(self, shared=False):
909
1055
        """See BzrDir.create_repository."""
912
1058
    def create_workingtree(self, revision_id=None):
913
1059
        """See BzrDir.create_workingtree."""
914
1060
        from bzrlib.workingtree import WorkingTreeFormat
915
 
        return WorkingTreeFormat.get_default_format().initialize(self, revision_id)
 
1061
        return self._format.workingtree_format.initialize(self, revision_id)
916
1062
 
917
1063
    def destroy_workingtree(self):
918
1064
        """See BzrDir.destroy_workingtree."""
919
 
        wt = self.open_workingtree()
 
1065
        wt = self.open_workingtree(recommend_upgrade=False)
920
1066
        repository = wt.branch.repository
921
1067
        empty = repository.revision_tree(_mod_revision.NULL_REVISION)
922
1068
        wt.revert([], old_tree=empty)
925
1071
    def destroy_workingtree_metadata(self):
926
1072
        self.transport.delete_tree('checkout')
927
1073
 
 
1074
    def find_branch_format(self):
 
1075
        """Find the branch 'format' for this bzrdir.
 
1076
 
 
1077
        This might be a synthetic object for e.g. RemoteBranch and SVN.
 
1078
        """
 
1079
        from bzrlib.branch import BranchFormat
 
1080
        return BranchFormat.find_format(self)
 
1081
 
928
1082
    def _get_mkdir_mode(self):
929
1083
        """Figure out the mode to use when creating a bzrdir subdir."""
930
1084
        temp_control = lockable_files.LockableFiles(self.transport, '',
931
1085
                                     lockable_files.TransportLock)
932
1086
        return temp_control._dir_mode
933
1087
 
 
1088
    def get_branch_reference(self):
 
1089
        """See BzrDir.get_branch_reference()."""
 
1090
        from bzrlib.branch import BranchFormat
 
1091
        format = BranchFormat.find_format(self)
 
1092
        return format.get_reference(self)
 
1093
 
934
1094
    def get_branch_transport(self, branch_format):
935
1095
        """See BzrDir.get_branch_transport()."""
936
1096
        if branch_format is None:
988
1148
                return True
989
1149
        except errors.NoRepositoryPresent:
990
1150
            pass
991
 
        # currently there are no other possible conversions for meta1 formats.
 
1151
        try:
 
1152
            if not isinstance(self.open_branch()._format,
 
1153
                              format.get_branch_format().__class__):
 
1154
                # the branch needs an upgrade.
 
1155
                return True
 
1156
        except errors.NotBranchError:
 
1157
            pass
 
1158
        try:
 
1159
            my_wt = self.open_workingtree(recommend_upgrade=False)
 
1160
            if not isinstance(my_wt._format,
 
1161
                              format.workingtree_format.__class__):
 
1162
                # the workingtree needs an upgrade.
 
1163
                return True
 
1164
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
1165
            pass
992
1166
        return False
993
1167
 
994
1168
    def open_branch(self, unsupported=False):
995
1169
        """See BzrDir.open_branch."""
996
 
        from bzrlib.branch import BranchFormat
997
 
        format = BranchFormat.find_format(self)
 
1170
        format = self.find_branch_format()
998
1171
        self._check_supported(format, unsupported)
999
1172
        return format.open(self, _found=True)
1000
1173
 
1005
1178
        self._check_supported(format, unsupported)
1006
1179
        return format.open(self, _found=True)
1007
1180
 
1008
 
    def open_workingtree(self, unsupported=False):
 
1181
    def open_workingtree(self, unsupported=False,
 
1182
            recommend_upgrade=True):
1009
1183
        """See BzrDir.open_workingtree."""
1010
1184
        from bzrlib.workingtree import WorkingTreeFormat
1011
1185
        format = WorkingTreeFormat.find_format(self)
1012
 
        self._check_supported(format, unsupported)
 
1186
        self._check_supported(format, unsupported,
 
1187
            recommend_upgrade,
 
1188
            basedir=self.root_transport.base)
1013
1189
        return format.open(self, _found=True)
1014
1190
 
1015
1191
 
1042
1218
    This is a list of BzrDirFormat objects.
1043
1219
    """
1044
1220
 
 
1221
    _control_server_formats = []
 
1222
    """The registered control server formats, e.g. RemoteBzrDirs.
 
1223
 
 
1224
    This is a list of BzrDirFormat objects.
 
1225
    """
 
1226
 
1045
1227
    _lock_file_name = 'branch-lock'
1046
1228
 
1047
1229
    # _lock_class must be set in subclasses to the lock type, typ.
1048
1230
    # TransportLock or LockDir
1049
1231
 
1050
1232
    @classmethod
1051
 
    def find_format(klass, transport):
 
1233
    def find_format(klass, transport, _server_formats=True):
1052
1234
        """Return the format present at transport."""
1053
 
        for format in klass._control_formats:
 
1235
        if _server_formats:
 
1236
            formats = klass._control_server_formats + klass._control_formats
 
1237
        else:
 
1238
            formats = klass._control_formats
 
1239
        for format in formats:
1054
1240
            try:
1055
1241
                return format.probe_transport(transport)
1056
1242
            except errors.NotBranchError:
1060
1246
 
1061
1247
    @classmethod
1062
1248
    def probe_transport(klass, transport):
1063
 
        """Return the .bzrdir style transport present at URL."""
 
1249
        """Return the .bzrdir style format present in a directory."""
1064
1250
        try:
1065
1251
            format_string = transport.get(".bzr/branch-format").read()
1066
1252
        except errors.NoSuchFile:
1196
1382
 
1197
1383
    @classmethod
1198
1384
    def register_control_format(klass, format):
1199
 
        """Register a format that does not use '.bzrdir' for its control dir.
 
1385
        """Register a format that does not use '.bzr' for its control dir.
1200
1386
 
1201
1387
        TODO: This should be pulled up into a 'ControlDirFormat' base class
1202
1388
        which BzrDirFormat can inherit from, and renamed to register_format 
1206
1392
        klass._control_formats.append(format)
1207
1393
 
1208
1394
    @classmethod
 
1395
    def register_control_server_format(klass, format):
 
1396
        """Register a control format for client-server environments.
 
1397
 
 
1398
        These formats will be tried before ones registered with
 
1399
        register_control_format.  This gives implementations that decide to the
 
1400
        chance to grab it before anything looks at the contents of the format
 
1401
        file.
 
1402
        """
 
1403
        klass._control_server_formats.append(format)
 
1404
 
 
1405
    @classmethod
 
1406
    @symbol_versioning.deprecated_method(symbol_versioning.zero_fourteen)
1209
1407
    def set_default_format(klass, format):
 
1408
        klass._set_default_format(format)
 
1409
 
 
1410
    @classmethod
 
1411
    def _set_default_format(klass, format):
 
1412
        """Set default format (for testing behavior of defaults only)"""
1210
1413
        klass._default_format = format
1211
1414
 
1212
1415
    def __str__(self):
1222
1425
        klass._control_formats.remove(format)
1223
1426
 
1224
1427
 
1225
 
# register BzrDirFormat as a control format
1226
 
BzrDirFormat.register_control_format(BzrDirFormat)
1227
 
 
1228
 
 
1229
1428
class BzrDirFormat4(BzrDirFormat):
1230
1429
    """Bzr dir format 4.
1231
1430
 
1273
1472
 
1274
1473
    def __return_repository_format(self):
1275
1474
        """Circular import protection."""
1276
 
        from bzrlib.repository import RepositoryFormat4
 
1475
        from bzrlib.repofmt.weaverepo import RepositoryFormat4
1277
1476
        return RepositoryFormat4()
1278
1477
    repository_format = property(__return_repository_format)
1279
1478
 
1313
1512
        Except when they are being cloned.
1314
1513
        """
1315
1514
        from bzrlib.branch import BzrBranchFormat4
1316
 
        from bzrlib.repository import RepositoryFormat5
 
1515
        from bzrlib.repofmt.weaverepo import RepositoryFormat5
1317
1516
        from bzrlib.workingtree import WorkingTreeFormat2
1318
1517
        result = (super(BzrDirFormat5, self).initialize_on_transport(transport))
1319
1518
        RepositoryFormat5().initialize(result, _internal=True)
1333
1532
 
1334
1533
    def __return_repository_format(self):
1335
1534
        """Circular import protection."""
1336
 
        from bzrlib.repository import RepositoryFormat5
 
1535
        from bzrlib.repofmt.weaverepo import RepositoryFormat5
1337
1536
        return RepositoryFormat5()
1338
1537
    repository_format = property(__return_repository_format)
1339
1538
 
1372
1571
        Except when they are being cloned.
1373
1572
        """
1374
1573
        from bzrlib.branch import BzrBranchFormat4
1375
 
        from bzrlib.repository import RepositoryFormat6
 
1574
        from bzrlib.repofmt.weaverepo import RepositoryFormat6
1376
1575
        from bzrlib.workingtree import WorkingTreeFormat2
1377
1576
        result = super(BzrDirFormat6, self).initialize_on_transport(transport)
1378
1577
        RepositoryFormat6().initialize(result, _internal=True)
1392
1591
 
1393
1592
    def __return_repository_format(self):
1394
1593
        """Circular import protection."""
1395
 
        from bzrlib.repository import RepositoryFormat6
 
1594
        from bzrlib.repofmt.weaverepo import RepositoryFormat6
1396
1595
        return RepositoryFormat6()
1397
1596
    repository_format = property(__return_repository_format)
1398
1597
 
1410
1609
 
1411
1610
    _lock_class = lockdir.LockDir
1412
1611
 
 
1612
    def __init__(self):
 
1613
        self._workingtree_format = None
 
1614
        self._branch_format = None
 
1615
 
 
1616
    def __eq__(self, other):
 
1617
        if other.__class__ is not self.__class__:
 
1618
            return False
 
1619
        if other.repository_format != self.repository_format:
 
1620
            return False
 
1621
        if other.workingtree_format != self.workingtree_format:
 
1622
            return False
 
1623
        return True
 
1624
 
 
1625
    def __ne__(self, other):
 
1626
        return not self == other
 
1627
 
 
1628
    def get_branch_format(self):
 
1629
        if self._branch_format is None:
 
1630
            from bzrlib.branch import BranchFormat
 
1631
            self._branch_format = BranchFormat.get_default_format()
 
1632
        return self._branch_format
 
1633
 
 
1634
    def set_branch_format(self, format):
 
1635
        self._branch_format = format
 
1636
 
1413
1637
    def get_converter(self, format=None):
1414
1638
        """See BzrDirFormat.get_converter()."""
1415
1639
        if format is None:
1444
1668
 
1445
1669
    repository_format = property(__return_repository_format, __set_repository_format)
1446
1670
 
1447
 
 
 
1671
    def __get_workingtree_format(self):
 
1672
        if self._workingtree_format is None:
 
1673
            from bzrlib.workingtree import WorkingTreeFormat
 
1674
            self._workingtree_format = WorkingTreeFormat.get_default_format()
 
1675
        return self._workingtree_format
 
1676
 
 
1677
    def __set_workingtree_format(self, wt_format):
 
1678
        self._workingtree_format = wt_format
 
1679
 
 
1680
    workingtree_format = property(__get_workingtree_format,
 
1681
                                  __set_workingtree_format)
 
1682
 
 
1683
 
 
1684
# Register bzr control format
 
1685
BzrDirFormat.register_control_format(BzrDirFormat)
 
1686
 
 
1687
# Register bzr formats
1448
1688
BzrDirFormat.register_format(BzrDirFormat4())
1449
1689
BzrDirFormat.register_format(BzrDirFormat5())
1450
1690
BzrDirFormat.register_format(BzrDirFormat6())
1451
1691
__default_format = BzrDirMetaFormat1()
1452
1692
BzrDirFormat.register_format(__default_format)
1453
 
BzrDirFormat.set_default_format(__default_format)
 
1693
BzrDirFormat._default_format = __default_format
1454
1694
 
1455
1695
 
1456
1696
class BzrDirTestProviderAdapter(object):
1462
1702
    easy to identify.
1463
1703
    """
1464
1704
 
1465
 
    def __init__(self, transport_server, transport_readonly_server, formats):
 
1705
    def __init__(self, vfs_factory, transport_server, transport_readonly_server,
 
1706
        formats):
 
1707
        """Create an object to adapt tests.
 
1708
 
 
1709
        :param vfs_server: A factory to create a Transport Server which has
 
1710
            all the VFS methods working, and is writable.
 
1711
        """
 
1712
        self._vfs_factory = vfs_factory
1466
1713
        self._transport_server = transport_server
1467
1714
        self._transport_readonly_server = transport_readonly_server
1468
1715
        self._formats = formats
1471
1718
        result = unittest.TestSuite()
1472
1719
        for format in self._formats:
1473
1720
            new_test = deepcopy(test)
 
1721
            new_test.vfs_transport_factory = self._vfs_factory
1474
1722
            new_test.transport_server = self._transport_server
1475
1723
            new_test.transport_readonly_server = self._transport_readonly_server
1476
1724
            new_test.bzrdir_format = format
1804
2052
 
1805
2053
    def convert(self, to_convert, pb):
1806
2054
        """See Converter.convert()."""
 
2055
        from bzrlib.repofmt.weaverepo import RepositoryFormat7
1807
2056
        from bzrlib.branch import BzrBranchFormat5
1808
2057
        self.bzrdir = to_convert
1809
2058
        self.pb = pb
1839
2088
        # we hard code the formats here because we are converting into
1840
2089
        # the meta format. The meta format upgrader can take this to a 
1841
2090
        # future format within each component.
1842
 
        self.put_format('repository', _mod_repository.RepositoryFormat7())
 
2091
        self.put_format('repository', RepositoryFormat7())
1843
2092
        for entry in repository_names:
1844
2093
            self.move_entry('repository', entry)
1845
2094
 
1940
2189
                self.pb.note('starting repository conversion')
1941
2190
                converter = CopyConverter(self.target_format.repository_format)
1942
2191
                converter.convert(repo, pb)
 
2192
        try:
 
2193
            branch = self.bzrdir.open_branch()
 
2194
        except errors.NotBranchError:
 
2195
            pass
 
2196
        else:
 
2197
            # TODO: conversions of Branch and Tree should be done by
 
2198
            # InterXFormat lookups
 
2199
            # Avoid circular imports
 
2200
            from bzrlib import branch as _mod_branch
 
2201
            if (branch._format.__class__ is _mod_branch.BzrBranchFormat5 and
 
2202
                self.target_format.get_branch_format().__class__ is
 
2203
                _mod_branch.BzrBranchFormat6):
 
2204
                branch_converter = _mod_branch.Converter5to6()
 
2205
                branch_converter.convert(branch)
 
2206
        try:
 
2207
            tree = self.bzrdir.open_workingtree(recommend_upgrade=False)
 
2208
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
2209
            pass
 
2210
        else:
 
2211
            # TODO: conversions of Branch and Tree should be done by
 
2212
            # InterXFormat lookups
 
2213
            if (isinstance(tree, workingtree.WorkingTree3) and
 
2214
                not isinstance(tree, workingtree_4.WorkingTree4) and
 
2215
                isinstance(self.target_format.workingtree_format,
 
2216
                    workingtree_4.WorkingTreeFormat4)):
 
2217
                workingtree_4.Converter3to4().convert(tree)
1943
2218
        return to_convert
 
2219
 
 
2220
 
 
2221
# This is not in remote.py because it's small, and needs to be registered.
 
2222
# Putting it in remote.py creates a circular import problem.
 
2223
# we can make it a lazy object if the control formats is turned into something
 
2224
# like a registry.
 
2225
class RemoteBzrDirFormat(BzrDirMetaFormat1):
 
2226
    """Format representing bzrdirs accessed via a smart server"""
 
2227
 
 
2228
    def get_format_description(self):
 
2229
        return 'bzr remote bzrdir'
 
2230
    
 
2231
    @classmethod
 
2232
    def probe_transport(klass, transport):
 
2233
        """Return a RemoteBzrDirFormat object if it looks possible."""
 
2234
        try:
 
2235
            transport.get_smart_client()
 
2236
        except (NotImplementedError, AttributeError,
 
2237
                errors.TransportNotPossible):
 
2238
            # no smart server, so not a branch for this format type.
 
2239
            raise errors.NotBranchError(path=transport.base)
 
2240
        else:
 
2241
            return klass()
 
2242
 
 
2243
    def initialize_on_transport(self, transport):
 
2244
        try:
 
2245
            # hand off the request to the smart server
 
2246
            medium = transport.get_smart_medium()
 
2247
        except errors.NoSmartMedium:
 
2248
            # TODO: lookup the local format from a server hint.
 
2249
            local_dir_format = BzrDirMetaFormat1()
 
2250
            return local_dir_format.initialize_on_transport(transport)
 
2251
        client = _SmartClient(medium)
 
2252
        path = client.remote_path_from_transport(transport)
 
2253
        response = _SmartClient(medium).call('BzrDirFormat.initialize', path)
 
2254
        assert response[0] in ('ok', ), 'unexpected response code %s' % (response,)
 
2255
        return remote.RemoteBzrDir(transport)
 
2256
 
 
2257
    def _open(self, transport):
 
2258
        return remote.RemoteBzrDir(transport)
 
2259
 
 
2260
    def __eq__(self, other):
 
2261
        if not isinstance(other, RemoteBzrDirFormat):
 
2262
            return False
 
2263
        return self.get_format_description() == other.get_format_description()
 
2264
 
 
2265
 
 
2266
BzrDirFormat.register_control_server_format(RemoteBzrDirFormat)
 
2267
 
 
2268
 
 
2269
class BzrDirFormatInfo(object):
 
2270
 
 
2271
    def __init__(self, native, deprecated, hidden):
 
2272
        self.deprecated = deprecated
 
2273
        self.native = native
 
2274
        self.hidden = hidden
 
2275
 
 
2276
 
 
2277
class BzrDirFormatRegistry(registry.Registry):
 
2278
    """Registry of user-selectable BzrDir subformats.
 
2279
    
 
2280
    Differs from BzrDirFormat._control_formats in that it provides sub-formats,
 
2281
    e.g. BzrDirMeta1 with weave repository.  Also, it's more user-oriented.
 
2282
    """
 
2283
 
 
2284
    def register_metadir(self, key,
 
2285
             repository_format, help, native=True, deprecated=False,
 
2286
             branch_format=None,
 
2287
             tree_format=None,
 
2288
             hidden=False):
 
2289
        """Register a metadir subformat.
 
2290
 
 
2291
        These all use a BzrDirMetaFormat1 bzrdir, but can be parameterized
 
2292
        by the Repository format.
 
2293
 
 
2294
        :param repository_format: The fully-qualified repository format class
 
2295
            name as a string.
 
2296
        :param branch_format: Fully-qualified branch format class name as
 
2297
            a string.
 
2298
        :param tree_format: Fully-qualified tree format class name as
 
2299
            a string.
 
2300
        """
 
2301
        # This should be expanded to support setting WorkingTree and Branch
 
2302
        # formats, once BzrDirMetaFormat1 supports that.
 
2303
        def _load(full_name):
 
2304
            mod_name, factory_name = full_name.rsplit('.', 1)
 
2305
            try:
 
2306
                mod = __import__(mod_name, globals(), locals(),
 
2307
                        [factory_name])
 
2308
            except ImportError, e:
 
2309
                raise ImportError('failed to load %s: %s' % (full_name, e))
 
2310
            try:
 
2311
                factory = getattr(mod, factory_name)
 
2312
            except AttributeError:
 
2313
                raise AttributeError('no factory %s in module %r'
 
2314
                    % (full_name, mod))
 
2315
            return factory()
 
2316
 
 
2317
        def helper():
 
2318
            bd = BzrDirMetaFormat1()
 
2319
            if branch_format is not None:
 
2320
                bd.set_branch_format(_load(branch_format))
 
2321
            if tree_format is not None:
 
2322
                bd.workingtree_format = _load(tree_format)
 
2323
            if repository_format is not None:
 
2324
                bd.repository_format = _load(repository_format)
 
2325
            return bd
 
2326
        self.register(key, helper, help, native, deprecated, hidden)
 
2327
 
 
2328
    def register(self, key, factory, help, native=True, deprecated=False,
 
2329
                 hidden=False):
 
2330
        """Register a BzrDirFormat factory.
 
2331
        
 
2332
        The factory must be a callable that takes one parameter: the key.
 
2333
        It must produce an instance of the BzrDirFormat when called.
 
2334
 
 
2335
        This function mainly exists to prevent the info object from being
 
2336
        supplied directly.
 
2337
        """
 
2338
        registry.Registry.register(self, key, factory, help, 
 
2339
            BzrDirFormatInfo(native, deprecated, hidden))
 
2340
 
 
2341
    def register_lazy(self, key, module_name, member_name, help, native=True,
 
2342
                      deprecated=False, hidden=False):
 
2343
        registry.Registry.register_lazy(self, key, module_name, member_name, 
 
2344
            help, BzrDirFormatInfo(native, deprecated, hidden))
 
2345
 
 
2346
    def set_default(self, key):
 
2347
        """Set the 'default' key to be a clone of the supplied key.
 
2348
        
 
2349
        This method must be called once and only once.
 
2350
        """
 
2351
        registry.Registry.register(self, 'default', self.get(key), 
 
2352
            self.get_help(key), info=self.get_info(key))
 
2353
 
 
2354
    def set_default_repository(self, key):
 
2355
        """Set the FormatRegistry default and Repository default.
 
2356
        
 
2357
        This is a transitional method while Repository.set_default_format
 
2358
        is deprecated.
 
2359
        """
 
2360
        if 'default' in self:
 
2361
            self.remove('default')
 
2362
        self.set_default(key)
 
2363
        format = self.get('default')()
 
2364
        assert isinstance(format, BzrDirMetaFormat1)
 
2365
 
 
2366
    def make_bzrdir(self, key):
 
2367
        return self.get(key)()
 
2368
 
 
2369
    def help_topic(self, topic):
 
2370
        output = textwrap.dedent("""\
 
2371
            Bazaar directory formats
 
2372
            ------------------------
 
2373
 
 
2374
            These formats can be used for creating branches, working trees, and
 
2375
            repositories.
 
2376
 
 
2377
            """)
 
2378
        default_help = self.get_help('default')
 
2379
        help_pairs = []
 
2380
        for key in self.keys():
 
2381
            if key == 'default':
 
2382
                continue
 
2383
            help = self.get_help(key)
 
2384
            if help == default_help:
 
2385
                default_realkey = key
 
2386
            else:
 
2387
                help_pairs.append((key, help))
 
2388
 
 
2389
        def wrapped(key, help, info):
 
2390
            if info.native:
 
2391
                help = '(native) ' + help
 
2392
            return '  %s:\n%s\n\n' % (key, 
 
2393
                    textwrap.fill(help, initial_indent='    ', 
 
2394
                    subsequent_indent='    '))
 
2395
        output += wrapped('%s/default' % default_realkey, default_help,
 
2396
                          self.get_info('default'))
 
2397
        deprecated_pairs = []
 
2398
        for key, help in help_pairs:
 
2399
            info = self.get_info(key)
 
2400
            if info.hidden:
 
2401
                continue
 
2402
            elif info.deprecated:
 
2403
                deprecated_pairs.append((key, help))
 
2404
            else:
 
2405
                output += wrapped(key, help, info)
 
2406
        if len(deprecated_pairs) > 0:
 
2407
            output += "Deprecated formats\n------------------\n\n"
 
2408
            for key, help in deprecated_pairs:
 
2409
                info = self.get_info(key)
 
2410
                output += wrapped(key, help, info)
 
2411
 
 
2412
        return output
 
2413
 
 
2414
 
 
2415
format_registry = BzrDirFormatRegistry()
 
2416
format_registry.register('weave', BzrDirFormat6,
 
2417
    'Pre-0.8 format.  Slower than knit and does not'
 
2418
    ' support checkouts or shared repositories.',
 
2419
    deprecated=True)
 
2420
format_registry.register_metadir('knit',
 
2421
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
 
2422
    'Format using knits.  Recommended for interoperation with bzr <= 0.14.',
 
2423
    branch_format='bzrlib.branch.BzrBranchFormat5',
 
2424
    tree_format='bzrlib.workingtree.WorkingTreeFormat3')
 
2425
format_registry.register_metadir('metaweave',
 
2426
    'bzrlib.repofmt.weaverepo.RepositoryFormat7',
 
2427
    'Transitional format in 0.8.  Slower than knit.',
 
2428
    branch_format='bzrlib.branch.BzrBranchFormat5',
 
2429
    tree_format='bzrlib.workingtree.WorkingTreeFormat3',
 
2430
    deprecated=True)
 
2431
format_registry.register_metadir('dirstate',
 
2432
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
 
2433
    help='New in 0.15: Fast local operations. Compatible with bzr 0.8 and '
 
2434
        'above when accessed over the network.',
 
2435
    branch_format='bzrlib.branch.BzrBranchFormat5',
 
2436
    # this uses bzrlib.workingtree.WorkingTreeFormat4 because importing
 
2437
    # directly from workingtree_4 triggers a circular import.
 
2438
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
2439
    )
 
2440
format_registry.register_metadir('dirstate-tags',
 
2441
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
 
2442
    help='New in 0.15: Fast local operations and improved scaling for '
 
2443
        'network operations. Additionally adds support for tags.'
 
2444
        ' Incompatible with bzr < 0.15.',
 
2445
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
2446
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
2447
    )
 
2448
format_registry.register_metadir('dirstate-with-subtree',
 
2449
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
 
2450
    help='New in 0.15: Fast local operations and improved scaling for '
 
2451
        'network operations. Additionally adds support for versioning nested '
 
2452
        'bzr branches. Incompatible with bzr < 0.15.',
 
2453
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
2454
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
2455
    hidden=True,
 
2456
    )
 
2457
format_registry.set_default('dirstate')