~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/bzrdir.py

  • Committer: Robert Collins
  • Date: 2007-04-23 02:29:35 UTC
  • mfrom: (2441 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2442.
  • Revision ID: robertc@robertcollins.net-20070423022935-9hhongamvk6bfdso
Resolve conflicts with bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
44
41
    lockable_files,
45
42
    lockdir,
46
43
    registry,
 
44
    remote,
47
45
    revision as _mod_revision,
48
46
    symbol_versioning,
 
47
    ui,
49
48
    urlutils,
50
49
    xml4,
51
50
    xml5,
57
56
    sha_strings,
58
57
    sha_string,
59
58
    )
 
59
from bzrlib.smart.client import _SmartClient
60
60
from bzrlib.store.revision.text import TextRevisionStore
61
61
from bzrlib.store.text import TextStore
62
62
from bzrlib.store.versioned import WeaveStore
63
63
from bzrlib.transactions import WriteTransaction
64
 
from bzrlib.transport import get_transport
 
64
from bzrlib.transport import (
 
65
    do_catching_redirections,
 
66
    get_transport,
 
67
    )
65
68
from bzrlib.weave import Weave
66
69
""")
67
70
 
68
 
from bzrlib.trace import mutter, note
 
71
from bzrlib.trace import (
 
72
    mutter,
 
73
    note,
 
74
    )
69
75
from bzrlib.transport.local import LocalTransport
70
76
 
71
77
 
87
93
        If there is a tree, the tree is opened and break_lock() called.
88
94
        Otherwise, branch is tried, and finally repository.
89
95
        """
 
96
        # XXX: This seems more like a UI function than something that really
 
97
        # belongs in this class.
90
98
        try:
91
99
            thing_to_unlock = self.open_workingtree()
92
100
        except (errors.NotLocalUrl, errors.NoWorkingTree):
109
117
        source_repo_format.check_conversion_target(target_repo_format)
110
118
 
111
119
    @staticmethod
112
 
    def _check_supported(format, allow_unsupported):
113
 
        """Check whether format is a supported format.
114
 
 
115
 
        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.
116
135
        """
 
136
        # TODO: perhaps move this into a base Format class; it's not BzrDir
 
137
        # specific. mbp 20070323
117
138
        if not allow_unsupported and not format.is_supported():
118
139
            # see open_downlevel to open legacy branches.
119
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)
120
146
 
121
 
    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):
122
148
        """Clone this bzrdir and its contents to url verbatim.
123
149
 
124
150
        If urls last component does not exist, it will be created.
129
155
                               even if one is available.
130
156
        """
131
157
        self._make_tail(url)
132
 
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
133
158
        result = self._format.initialize(url)
134
159
        try:
135
160
            local_repo = self.find_repository()
140
165
            if force_new_repo:
141
166
                result_repo = local_repo.clone(
142
167
                    result,
143
 
                    revision_id=revision_id,
144
 
                    basis=basis_repo)
 
168
                    revision_id=revision_id)
145
169
                result_repo.set_make_working_trees(local_repo.make_working_trees())
146
170
            else:
147
171
                try:
148
172
                    result_repo = result.find_repository()
149
173
                    # fetch content this dir needs.
150
 
                    if basis_repo:
151
 
                        # XXX FIXME RBC 20060214 need tests for this when the basis
152
 
                        # is incomplete
153
 
                        result_repo.fetch(basis_repo, revision_id=revision_id)
154
174
                    result_repo.fetch(local_repo, revision_id=revision_id)
155
175
                except errors.NoRepositoryPresent:
156
176
                    # needed to make one anyway.
157
177
                    result_repo = local_repo.clone(
158
178
                        result,
159
 
                        revision_id=revision_id,
160
 
                        basis=basis_repo)
 
179
                        revision_id=revision_id)
161
180
                    result_repo.set_make_working_trees(local_repo.make_working_trees())
162
181
        # 1 if there is a branch present
163
182
        #   make sure its content is available in the target repository
167
186
        except errors.NotBranchError:
168
187
            pass
169
188
        try:
170
 
            self.open_workingtree().clone(result, basis=basis_tree)
 
189
            self.open_workingtree().clone(result)
171
190
        except (errors.NoWorkingTree, errors.NotLocalUrl):
172
191
            pass
173
192
        return result
174
193
 
175
 
    def _get_basis_components(self, basis):
176
 
        """Retrieve the basis components that are available at basis."""
177
 
        if basis is None:
178
 
            return None, None, None
179
 
        try:
180
 
            basis_tree = basis.open_workingtree()
181
 
            basis_branch = basis_tree.branch
182
 
            basis_repo = basis_branch.repository
183
 
        except (errors.NoWorkingTree, errors.NotLocalUrl):
184
 
            basis_tree = None
185
 
            try:
186
 
                basis_branch = basis.open_branch()
187
 
                basis_repo = basis_branch.repository
188
 
            except errors.NotBranchError:
189
 
                basis_branch = None
190
 
                try:
191
 
                    basis_repo = basis.open_repository()
192
 
                except errors.NoRepositoryPresent:
193
 
                    basis_repo = None
194
 
        return basis_repo, basis_branch, basis_tree
195
 
 
196
194
    # TODO: This should be given a Transport, and should chdir up; otherwise
197
195
    # this will open a new connection.
198
196
    def _make_tail(self, url):
416
414
                    break
417
415
                else:
418
416
                    continue
419
 
            if ((found_bzrdir.root_transport.base == 
 
417
            if ((found_bzrdir.root_transport.base ==
420
418
                 self.root_transport.base) or repository.is_shared()):
421
419
                return repository
422
420
            else:
423
421
                raise errors.NoRepositoryPresent(self)
424
422
        raise errors.NoRepositoryPresent(self)
425
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
 
426
433
    def get_branch_transport(self, branch_format):
427
434
        """Get the transport for use by branch format in this BzrDir.
428
435
 
520
527
        return BzrDir.open_from_transport(t, _unsupported=_unsupported)
521
528
 
522
529
    @staticmethod
523
 
    def open_from_transport(transport, _unsupported=False):
 
530
    def open_from_transport(transport, _unsupported=False,
 
531
                            _server_formats=True):
524
532
        """Open a bzrdir within a particular directory.
525
533
 
526
534
        :param transport: Transport containing the bzrdir.
527
535
        :param _unsupported: private.
528
536
        """
529
 
        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
 
530
568
        BzrDir._check_supported(format, _unsupported)
531
569
        return format.open(transport, _found=True)
532
570
 
572
610
                return result, urlutils.unescape(a_transport.relpath(url))
573
611
            except errors.NotBranchError, e:
574
612
                pass
575
 
            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)
576
618
            if new_t.base == a_transport.base:
577
619
                # reached the root, whatever that may be
578
620
                raise errors.NotBranchError(path=url)
610
652
        """
611
653
        raise NotImplementedError(self.open_repository)
612
654
 
613
 
    def open_workingtree(self, _unsupported=False):
 
655
    def open_workingtree(self, _unsupported=False,
 
656
            recommend_upgrade=True):
614
657
        """Open the workingtree object at this BzrDir if one is present.
615
 
        
616
 
        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).
617
663
        """
618
664
        raise NotImplementedError(self.open_workingtree)
619
665
 
641
687
        workingtree and discards it, and that's somewhat expensive.) 
642
688
        """
643
689
        try:
644
 
            self.open_workingtree()
 
690
            self.open_workingtree(recommend_upgrade=False)
645
691
            return True
646
692
        except errors.NoWorkingTree:
647
693
            return False
648
694
 
649
 
    def _cloning_metadir(self, basis=None):
650
 
        def related_repository(bzrdir):
 
695
    def _cloning_metadir(self):
 
696
        """Produce a metadir suitable for cloning with"""
 
697
        result_format = self._format.__class__()
 
698
        try:
651
699
            try:
652
 
                branch = bzrdir.open_branch()
653
 
                return branch.repository
 
700
                branch = self.open_branch()
 
701
                source_repository = branch.repository
654
702
            except errors.NotBranchError:
655
703
                source_branch = None
656
 
                return bzrdir.open_repository()
657
 
        result_format = self._format.__class__()
658
 
        try:
659
 
            try:
660
 
                source_repository = related_repository(self)
661
 
            except errors.NoRepositoryPresent:
662
 
                if basis is None:
663
 
                    raise
664
 
                source_repository = related_repository(self)
665
 
            result_format.repository_format = source_repository._format
 
704
                source_repository = self.open_repository()
666
705
        except errors.NoRepositoryPresent:
667
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
668
714
        try:
669
 
            tree = self.open_workingtree()
 
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)
670
719
        except (errors.NoWorkingTree, errors.NotLocalUrl):
671
720
            result_format.workingtree_format = None
672
721
        else:
673
722
            result_format.workingtree_format = tree._format.__class__()
674
723
        return result_format, source_repository
675
724
 
676
 
    def cloning_metadir(self, basis=None):
 
725
    def cloning_metadir(self):
677
726
        """Produce a metadir suitable for cloning or sprouting with.
678
727
 
679
728
        These operations may produce workingtrees (yes, even though they're
691
740
    def checkout_metadir(self):
692
741
        return self.cloning_metadir()
693
742
 
694
 
    def sprout(self, url, revision_id=None, basis=None, force_new_repo=False,
 
743
    def sprout(self, url, revision_id=None, force_new_repo=False,
695
744
               recurse='down'):
696
745
        """Create a copy of this bzrdir prepared for use as a new line of
697
746
        development.
707
756
            itself to download less data.
708
757
        """
709
758
        self._make_tail(url)
710
 
        cloning_format = self.cloning_metadir(basis)
 
759
        cloning_format = self.cloning_metadir()
711
760
        result = cloning_format.initialize(url)
712
 
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
713
761
        try:
714
762
            source_branch = self.open_branch()
715
763
            source_repository = source_branch.repository
718
766
            try:
719
767
                source_repository = self.open_repository()
720
768
            except errors.NoRepositoryPresent:
721
 
                # copy the entire basis one if there is one
722
 
                # but there is no repository.
723
 
                source_repository = basis_repo
 
769
                source_repository = None
724
770
        if force_new_repo:
725
771
            result_repo = None
726
772
        else:
741
787
            result_repo = result.create_repository()
742
788
        if result_repo is not None:
743
789
            # fetch needed content into target.
744
 
            if basis_repo:
745
 
                # XXX FIXME RBC 20060214 need tests for this when the basis
746
 
                # is incomplete
747
 
                result_repo.fetch(basis_repo, revision_id=revision_id)
748
790
            if source_repository is not None:
749
791
                result_repo.fetch(source_repository, revision_id=revision_id)
750
792
        if source_branch is not None:
810
852
        """Pre-splitout bzrdirs do not suffer from stale locks."""
811
853
        raise NotImplementedError(self.break_lock)
812
854
 
813
 
    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):
814
856
        """See BzrDir.clone()."""
815
857
        from bzrlib.workingtree import WorkingTreeFormat2
816
858
        self._make_tail(url)
817
859
        result = self._format._initialize_for_clone(url)
818
 
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
819
 
        self.open_repository().clone(result, revision_id=revision_id, basis=basis_repo)
 
860
        self.open_repository().clone(result, revision_id=revision_id)
820
861
        from_branch = self.open_branch()
821
862
        from_branch.clone(result, revision_id=revision_id)
822
863
        try:
823
 
            self.open_workingtree().clone(result, basis=basis_tree)
 
864
            self.open_workingtree().clone(result)
824
865
        except errors.NotLocalUrl:
825
866
            # make a new one, this format always has to have one.
826
867
            try:
844
885
    def create_workingtree(self, revision_id=None):
845
886
        """See BzrDir.create_workingtree."""
846
887
        # this looks buggy but is not -really-
 
888
        # because this format creates the workingtree when the bzrdir is
 
889
        # created
847
890
        # clone and sprout will have set the revision_id
848
891
        # and that will have set it for us, its only
849
892
        # specific uses of create_workingtree in isolation
850
893
        # that can do wonky stuff here, and that only
851
894
        # happens for creating checkouts, which cannot be 
852
895
        # done on this format anyway. So - acceptable wart.
853
 
        result = self.open_workingtree()
 
896
        result = self.open_workingtree(recommend_upgrade=False)
854
897
        if revision_id is not None:
855
898
            if revision_id == _mod_revision.NULL_REVISION:
856
899
                result.set_parent_ids([])
912
955
        self._check_supported(format, unsupported)
913
956
        return format.open(self, _found=True)
914
957
 
915
 
    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):
916
959
        """See BzrDir.sprout()."""
917
960
        from bzrlib.workingtree import WorkingTreeFormat2
918
961
        self._make_tail(url)
919
962
        result = self._format._initialize_for_clone(url)
920
 
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
921
963
        try:
922
 
            self.open_repository().clone(result, revision_id=revision_id, basis=basis_repo)
 
964
            self.open_repository().clone(result, revision_id=revision_id)
923
965
        except errors.NoRepositoryPresent:
924
966
            pass
925
967
        try:
962
1004
        from bzrlib.repofmt.weaverepo import RepositoryFormat5
963
1005
        return RepositoryFormat5().open(self, _found=True)
964
1006
 
965
 
    def open_workingtree(self, _unsupported=False):
 
1007
    def open_workingtree(self, _unsupported=False,
 
1008
            recommend_upgrade=True):
966
1009
        """See BzrDir.create_workingtree."""
967
1010
        from bzrlib.workingtree import WorkingTreeFormat2
968
 
        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)
969
1015
 
970
1016
 
971
1017
class BzrDir6(BzrDirPreSplitOut):
979
1025
        from bzrlib.repofmt.weaverepo import RepositoryFormat6
980
1026
        return RepositoryFormat6().open(self, _found=True)
981
1027
 
982
 
    def open_workingtree(self, _unsupported=False):
 
1028
    def open_workingtree(self, _unsupported=False,
 
1029
        recommend_upgrade=True):
983
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
984
1033
        from bzrlib.workingtree import WorkingTreeFormat2
985
1034
        return WorkingTreeFormat2().open(self, _found=True)
986
1035
 
1013
1062
 
1014
1063
    def destroy_workingtree(self):
1015
1064
        """See BzrDir.destroy_workingtree."""
1016
 
        wt = self.open_workingtree()
 
1065
        wt = self.open_workingtree(recommend_upgrade=False)
1017
1066
        repository = wt.branch.repository
1018
1067
        empty = repository.revision_tree(_mod_revision.NULL_REVISION)
1019
1068
        wt.revert([], old_tree=empty)
1022
1071
    def destroy_workingtree_metadata(self):
1023
1072
        self.transport.delete_tree('checkout')
1024
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
 
1025
1082
    def _get_mkdir_mode(self):
1026
1083
        """Figure out the mode to use when creating a bzrdir subdir."""
1027
1084
        temp_control = lockable_files.LockableFiles(self.transport, '',
1028
1085
                                     lockable_files.TransportLock)
1029
1086
        return temp_control._dir_mode
1030
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
 
1031
1094
    def get_branch_transport(self, branch_format):
1032
1095
        """See BzrDir.get_branch_transport()."""
1033
1096
        if branch_format is None:
1093
1156
        except errors.NotBranchError:
1094
1157
            pass
1095
1158
        try:
1096
 
            if not isinstance(self.open_workingtree()._format,
 
1159
            my_wt = self.open_workingtree(recommend_upgrade=False)
 
1160
            if not isinstance(my_wt._format,
1097
1161
                              format.workingtree_format.__class__):
1098
1162
                # the workingtree needs an upgrade.
1099
1163
                return True
1103
1167
 
1104
1168
    def open_branch(self, unsupported=False):
1105
1169
        """See BzrDir.open_branch."""
1106
 
        from bzrlib.branch import BranchFormat
1107
 
        format = BranchFormat.find_format(self)
 
1170
        format = self.find_branch_format()
1108
1171
        self._check_supported(format, unsupported)
1109
1172
        return format.open(self, _found=True)
1110
1173
 
1115
1178
        self._check_supported(format, unsupported)
1116
1179
        return format.open(self, _found=True)
1117
1180
 
1118
 
    def open_workingtree(self, unsupported=False):
 
1181
    def open_workingtree(self, unsupported=False,
 
1182
            recommend_upgrade=True):
1119
1183
        """See BzrDir.open_workingtree."""
1120
1184
        from bzrlib.workingtree import WorkingTreeFormat
1121
1185
        format = WorkingTreeFormat.find_format(self)
1122
 
        self._check_supported(format, unsupported)
 
1186
        self._check_supported(format, unsupported,
 
1187
            recommend_upgrade,
 
1188
            basedir=self.root_transport.base)
1123
1189
        return format.open(self, _found=True)
1124
1190
 
1125
1191
 
1152
1218
    This is a list of BzrDirFormat objects.
1153
1219
    """
1154
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
 
1155
1227
    _lock_file_name = 'branch-lock'
1156
1228
 
1157
1229
    # _lock_class must be set in subclasses to the lock type, typ.
1158
1230
    # TransportLock or LockDir
1159
1231
 
1160
1232
    @classmethod
1161
 
    def find_format(klass, transport):
 
1233
    def find_format(klass, transport, _server_formats=True):
1162
1234
        """Return the format present at transport."""
1163
 
        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:
1164
1240
            try:
1165
1241
                return format.probe_transport(transport)
1166
1242
            except errors.NotBranchError:
1170
1246
 
1171
1247
    @classmethod
1172
1248
    def probe_transport(klass, transport):
1173
 
        """Return the .bzrdir style transport present at URL."""
 
1249
        """Return the .bzrdir style format present in a directory."""
1174
1250
        try:
1175
1251
            format_string = transport.get(".bzr/branch-format").read()
1176
1252
        except errors.NoSuchFile:
1306
1382
 
1307
1383
    @classmethod
1308
1384
    def register_control_format(klass, format):
1309
 
        """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.
1310
1386
 
1311
1387
        TODO: This should be pulled up into a 'ControlDirFormat' base class
1312
1388
        which BzrDirFormat can inherit from, and renamed to register_format 
1316
1392
        klass._control_formats.append(format)
1317
1393
 
1318
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
1319
1406
    @symbol_versioning.deprecated_method(symbol_versioning.zero_fourteen)
1320
1407
    def set_default_format(klass, format):
1321
1408
        klass._set_default_format(format)
1338
1425
        klass._control_formats.remove(format)
1339
1426
 
1340
1427
 
1341
 
# register BzrDirFormat as a control format
1342
 
BzrDirFormat.register_control_format(BzrDirFormat)
1343
 
 
1344
 
 
1345
1428
class BzrDirFormat4(BzrDirFormat):
1346
1429
    """Bzr dir format 4.
1347
1430
 
1598
1681
                                  __set_workingtree_format)
1599
1682
 
1600
1683
 
 
1684
# Register bzr control format
 
1685
BzrDirFormat.register_control_format(BzrDirFormat)
 
1686
 
 
1687
# Register bzr formats
1601
1688
BzrDirFormat.register_format(BzrDirFormat4())
1602
1689
BzrDirFormat.register_format(BzrDirFormat5())
1603
1690
BzrDirFormat.register_format(BzrDirFormat6())
1615
1702
    easy to identify.
1616
1703
    """
1617
1704
 
1618
 
    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
1619
1713
        self._transport_server = transport_server
1620
1714
        self._transport_readonly_server = transport_readonly_server
1621
1715
        self._formats = formats
1624
1718
        result = unittest.TestSuite()
1625
1719
        for format in self._formats:
1626
1720
            new_test = deepcopy(test)
 
1721
            new_test.vfs_transport_factory = self._vfs_factory
1627
1722
            new_test.transport_server = self._transport_server
1628
1723
            new_test.transport_readonly_server = self._transport_readonly_server
1629
1724
            new_test.bzrdir_format = format
2109
2204
                branch_converter = _mod_branch.Converter5to6()
2110
2205
                branch_converter.convert(branch)
2111
2206
        try:
2112
 
            tree = self.bzrdir.open_workingtree()
 
2207
            tree = self.bzrdir.open_workingtree(recommend_upgrade=False)
2113
2208
        except (errors.NoWorkingTree, errors.NotLocalUrl):
2114
2209
            pass
2115
2210
        else:
2123
2218
        return to_convert
2124
2219
 
2125
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
 
2126
2269
class BzrDirFormatInfo(object):
2127
2270
 
2128
 
    def __init__(self, native, deprecated):
 
2271
    def __init__(self, native, deprecated, hidden):
2129
2272
        self.deprecated = deprecated
2130
2273
        self.native = native
 
2274
        self.hidden = hidden
2131
2275
 
2132
2276
 
2133
2277
class BzrDirFormatRegistry(registry.Registry):
2140
2284
    def register_metadir(self, key,
2141
2285
             repository_format, help, native=True, deprecated=False,
2142
2286
             branch_format=None,
2143
 
             tree_format=None):
 
2287
             tree_format=None,
 
2288
             hidden=False):
2144
2289
        """Register a metadir subformat.
2145
2290
 
2146
2291
        These all use a BzrDirMetaFormat1 bzrdir, but can be parameterized
2178
2323
            if repository_format is not None:
2179
2324
                bd.repository_format = _load(repository_format)
2180
2325
            return bd
2181
 
        self.register(key, helper, help, native, deprecated)
 
2326
        self.register(key, helper, help, native, deprecated, hidden)
2182
2327
 
2183
 
    def register(self, key, factory, help, native=True, deprecated=False):
 
2328
    def register(self, key, factory, help, native=True, deprecated=False,
 
2329
                 hidden=False):
2184
2330
        """Register a BzrDirFormat factory.
2185
2331
        
2186
2332
        The factory must be a callable that takes one parameter: the key.
2190
2336
        supplied directly.
2191
2337
        """
2192
2338
        registry.Registry.register(self, key, factory, help, 
2193
 
            BzrDirFormatInfo(native, deprecated))
 
2339
            BzrDirFormatInfo(native, deprecated, hidden))
2194
2340
 
2195
2341
    def register_lazy(self, key, module_name, member_name, help, native=True,
2196
 
                      deprecated=False):
 
2342
                      deprecated=False, hidden=False):
2197
2343
        registry.Registry.register_lazy(self, key, module_name, member_name, 
2198
 
            help, BzrDirFormatInfo(native, deprecated))
 
2344
            help, BzrDirFormatInfo(native, deprecated, hidden))
2199
2345
 
2200
2346
    def set_default(self, key):
2201
2347
        """Set the 'default' key to be a clone of the supplied key.
2251
2397
        deprecated_pairs = []
2252
2398
        for key, help in help_pairs:
2253
2399
            info = self.get_info(key)
2254
 
            if info.deprecated:
 
2400
            if info.hidden:
 
2401
                continue
 
2402
            elif info.deprecated:
2255
2403
                deprecated_pairs.append((key, help))
2256
2404
            else:
2257
2405
                output += wrapped(key, help, info)
2289
2437
    # directly from workingtree_4 triggers a circular import.
2290
2438
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2291
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
    )
2292
2448
format_registry.register_metadir('dirstate-with-subtree',
2293
2449
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
2294
2450
    help='New in 0.15: Fast local operations and improved scaling for '
2296
2452
        'bzr branches. Incompatible with bzr < 0.15.',
2297
2453
    branch_format='bzrlib.branch.BzrBranchFormat6',
2298
2454
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
2455
    hidden=True,
2299
2456
    )
2300
2457
format_registry.set_default('dirstate')