~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/bzrdir.py

Merge from bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
46
46
    registry,
47
47
    revision as _mod_revision,
48
48
    symbol_versioning,
 
49
    ui,
49
50
    urlutils,
50
51
    xml4,
51
52
    xml5,
61
62
from bzrlib.store.text import TextStore
62
63
from bzrlib.store.versioned import WeaveStore
63
64
from bzrlib.transactions import WriteTransaction
64
 
from bzrlib.transport import get_transport
 
65
from bzrlib.transport import (
 
66
    do_catching_redirections,
 
67
    get_transport,
 
68
    )
65
69
from bzrlib.weave import Weave
66
70
""")
67
71
 
68
 
from bzrlib.trace import mutter, note
 
72
from bzrlib.trace import (
 
73
    mutter,
 
74
    note,
 
75
    )
69
76
from bzrlib.transport.local import LocalTransport
70
77
 
71
78
 
109
116
        source_repo_format.check_conversion_target(target_repo_format)
110
117
 
111
118
    @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.
 
119
    def _check_supported(format, allow_unsupported,
 
120
        recommend_upgrade=True,
 
121
        basedir=None):
 
122
        """Give an error or warning on old formats.
 
123
 
 
124
        :param format: may be any kind of format - workingtree, branch, 
 
125
        or repository.
 
126
 
 
127
        :param allow_unsupported: If true, allow opening 
 
128
        formats that are strongly deprecated, and which may 
 
129
        have limited functionality.
 
130
 
 
131
        :param recommend_upgrade: If true (default), warn
 
132
        the user through the ui object that they may wish
 
133
        to upgrade the object.
116
134
        """
 
135
        # TODO: perhaps move this into a base Format class; it's not BzrDir
 
136
        # specific. mbp 20070323
117
137
        if not allow_unsupported and not format.is_supported():
118
138
            # see open_downlevel to open legacy branches.
119
139
            raise errors.UnsupportedFormatError(format=format)
 
140
        if recommend_upgrade \
 
141
            and getattr(format, 'upgrade_recommended', False):
 
142
            ui.ui_factory.recommend_upgrade(
 
143
                format.get_format_description(),
 
144
                basedir)
120
145
 
121
 
    def clone(self, url, revision_id=None, basis=None, force_new_repo=False):
 
146
    def clone(self, url, revision_id=None, force_new_repo=False):
122
147
        """Clone this bzrdir and its contents to url verbatim.
123
148
 
124
149
        If urls last component does not exist, it will be created.
129
154
                               even if one is available.
130
155
        """
131
156
        self._make_tail(url)
132
 
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
133
157
        result = self._format.initialize(url)
134
158
        try:
135
159
            local_repo = self.find_repository()
140
164
            if force_new_repo:
141
165
                result_repo = local_repo.clone(
142
166
                    result,
143
 
                    revision_id=revision_id,
144
 
                    basis=basis_repo)
 
167
                    revision_id=revision_id)
145
168
                result_repo.set_make_working_trees(local_repo.make_working_trees())
146
169
            else:
147
170
                try:
148
171
                    result_repo = result.find_repository()
149
172
                    # 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
173
                    result_repo.fetch(local_repo, revision_id=revision_id)
155
174
                except errors.NoRepositoryPresent:
156
175
                    # needed to make one anyway.
157
176
                    result_repo = local_repo.clone(
158
177
                        result,
159
 
                        revision_id=revision_id,
160
 
                        basis=basis_repo)
 
178
                        revision_id=revision_id)
161
179
                    result_repo.set_make_working_trees(local_repo.make_working_trees())
162
180
        # 1 if there is a branch present
163
181
        #   make sure its content is available in the target repository
167
185
        except errors.NotBranchError:
168
186
            pass
169
187
        try:
170
 
            self.open_workingtree().clone(result, basis=basis_tree)
 
188
            self.open_workingtree().clone(result)
171
189
        except (errors.NoWorkingTree, errors.NotLocalUrl):
172
190
            pass
173
191
        return result
174
192
 
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
193
    # TODO: This should be given a Transport, and should chdir up; otherwise
197
194
    # this will open a new connection.
198
195
    def _make_tail(self, url):
526
523
        :param transport: Transport containing the bzrdir.
527
524
        :param _unsupported: private.
528
525
        """
529
 
        format = BzrDirFormat.find_format(transport)
 
526
        base = transport.base
 
527
 
 
528
        def find_format(transport):
 
529
            return transport, BzrDirFormat.find_format(transport)
 
530
 
 
531
        def redirected(transport, e, redirection_notice):
 
532
            qualified_source = e.get_source_url()
 
533
            relpath = transport.relpath(qualified_source)
 
534
            if not e.target.endswith(relpath):
 
535
                # Not redirected to a branch-format, not a branch
 
536
                raise errors.NotBranchError(path=e.target)
 
537
            target = e.target[:-len(relpath)]
 
538
            note('%s is%s redirected to %s',
 
539
                 transport.base, e.permanently, target)
 
540
            # Let's try with a new transport
 
541
            qualified_target = e.get_target_url()[:-len(relpath)]
 
542
            # FIXME: If 'transport' has a qualifier, this should
 
543
            # be applied again to the new transport *iff* the
 
544
            # schemes used are the same. It's a bit tricky to
 
545
            # verify, so I'll punt for now
 
546
            # -- vila20070212
 
547
            return get_transport(target)
 
548
 
 
549
        try:
 
550
            transport, format = do_catching_redirections(find_format,
 
551
                                                         transport,
 
552
                                                         redirected)
 
553
        except errors.TooManyRedirections:
 
554
            raise errors.NotBranchError(base)
 
555
 
530
556
        BzrDir._check_supported(format, _unsupported)
531
557
        return format.open(transport, _found=True)
532
558
 
641
667
        workingtree and discards it, and that's somewhat expensive.) 
642
668
        """
643
669
        try:
644
 
            self.open_workingtree()
 
670
            self.open_workingtree(recommend_upgrade=False)
645
671
            return True
646
672
        except errors.NoWorkingTree:
647
673
            return False
648
674
 
649
 
    def _cloning_metadir(self, basis=None):
650
 
        def related_repository(bzrdir):
 
675
    def _cloning_metadir(self):
 
676
        result_format = self._format.__class__()
 
677
        try:
651
678
            try:
652
 
                branch = bzrdir.open_branch()
653
 
                return branch.repository
 
679
                branch = self.open_branch()
 
680
                source_repository = branch.repository
654
681
            except errors.NotBranchError:
655
682
                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)
 
683
                source_repository = self.open_repository()
665
684
            result_format.repository_format = source_repository._format
666
685
        except errors.NoRepositoryPresent:
667
686
            source_repository = None
668
687
        try:
669
 
            tree = self.open_workingtree()
 
688
            # TODO: Couldn't we just probe for the format in these cases,
 
689
            # rather than opening the whole tree?  It would be a little
 
690
            # faster. mbp 20070401
 
691
            tree = self.open_workingtree(recommend_upgrade=False)
670
692
        except (errors.NoWorkingTree, errors.NotLocalUrl):
671
693
            result_format.workingtree_format = None
672
694
        else:
673
695
            result_format.workingtree_format = tree._format.__class__()
674
696
        return result_format, source_repository
675
697
 
676
 
    def cloning_metadir(self, basis=None):
 
698
    def cloning_metadir(self):
677
699
        """Produce a metadir suitable for cloning or sprouting with.
678
700
 
679
701
        These operations may produce workingtrees (yes, even though they're
691
713
    def checkout_metadir(self):
692
714
        return self.cloning_metadir()
693
715
 
694
 
    def sprout(self, url, revision_id=None, basis=None, force_new_repo=False,
 
716
    def sprout(self, url, revision_id=None, force_new_repo=False,
695
717
               recurse='down'):
696
718
        """Create a copy of this bzrdir prepared for use as a new line of
697
719
        development.
707
729
            itself to download less data.
708
730
        """
709
731
        self._make_tail(url)
710
 
        cloning_format = self.cloning_metadir(basis)
 
732
        cloning_format = self.cloning_metadir()
711
733
        result = cloning_format.initialize(url)
712
 
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
713
734
        try:
714
735
            source_branch = self.open_branch()
715
736
            source_repository = source_branch.repository
718
739
            try:
719
740
                source_repository = self.open_repository()
720
741
            except errors.NoRepositoryPresent:
721
 
                # copy the entire basis one if there is one
722
 
                # but there is no repository.
723
 
                source_repository = basis_repo
 
742
                source_repository = None
724
743
        if force_new_repo:
725
744
            result_repo = None
726
745
        else:
741
760
            result_repo = result.create_repository()
742
761
        if result_repo is not None:
743
762
            # 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
763
            if source_repository is not None:
749
764
                result_repo.fetch(source_repository, revision_id=revision_id)
750
765
        if source_branch is not None:
810
825
        """Pre-splitout bzrdirs do not suffer from stale locks."""
811
826
        raise NotImplementedError(self.break_lock)
812
827
 
813
 
    def clone(self, url, revision_id=None, basis=None, force_new_repo=False):
 
828
    def clone(self, url, revision_id=None, force_new_repo=False):
814
829
        """See BzrDir.clone()."""
815
830
        from bzrlib.workingtree import WorkingTreeFormat2
816
831
        self._make_tail(url)
817
832
        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)
 
833
        self.open_repository().clone(result, revision_id=revision_id)
820
834
        from_branch = self.open_branch()
821
835
        from_branch.clone(result, revision_id=revision_id)
822
836
        try:
823
 
            self.open_workingtree().clone(result, basis=basis_tree)
 
837
            self.open_workingtree().clone(result)
824
838
        except errors.NotLocalUrl:
825
839
            # make a new one, this format always has to have one.
826
840
            try:
844
858
    def create_workingtree(self, revision_id=None):
845
859
        """See BzrDir.create_workingtree."""
846
860
        # this looks buggy but is not -really-
 
861
        # because this format creates the workingtree when the bzrdir is
 
862
        # created
847
863
        # clone and sprout will have set the revision_id
848
864
        # and that will have set it for us, its only
849
865
        # specific uses of create_workingtree in isolation
850
866
        # that can do wonky stuff here, and that only
851
867
        # happens for creating checkouts, which cannot be 
852
868
        # done on this format anyway. So - acceptable wart.
853
 
        result = self.open_workingtree()
 
869
        result = self.open_workingtree(recommend_upgrade=False)
854
870
        if revision_id is not None:
855
871
            if revision_id == _mod_revision.NULL_REVISION:
856
872
                result.set_parent_ids([])
912
928
        self._check_supported(format, unsupported)
913
929
        return format.open(self, _found=True)
914
930
 
915
 
    def sprout(self, url, revision_id=None, basis=None, force_new_repo=False):
 
931
    def sprout(self, url, revision_id=None, force_new_repo=False):
916
932
        """See BzrDir.sprout()."""
917
933
        from bzrlib.workingtree import WorkingTreeFormat2
918
934
        self._make_tail(url)
919
935
        result = self._format._initialize_for_clone(url)
920
 
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
921
936
        try:
922
 
            self.open_repository().clone(result, revision_id=revision_id, basis=basis_repo)
 
937
            self.open_repository().clone(result, revision_id=revision_id)
923
938
        except errors.NoRepositoryPresent:
924
939
            pass
925
940
        try:
962
977
        from bzrlib.repofmt.weaverepo import RepositoryFormat5
963
978
        return RepositoryFormat5().open(self, _found=True)
964
979
 
965
 
    def open_workingtree(self, _unsupported=False):
 
980
    def open_workingtree(self, _unsupported=False,
 
981
            recommend_upgrade=True):
966
982
        """See BzrDir.create_workingtree."""
967
983
        from bzrlib.workingtree import WorkingTreeFormat2
968
 
        return WorkingTreeFormat2().open(self, _found=True)
 
984
        wt_format = WorkingTreeFormat2()
 
985
        # we don't warn here about upgrades; that ought to be handled for the
 
986
        # bzrdir as a whole
 
987
        return wt_format.open(self, _found=True)
969
988
 
970
989
 
971
990
class BzrDir6(BzrDirPreSplitOut):
979
998
        from bzrlib.repofmt.weaverepo import RepositoryFormat6
980
999
        return RepositoryFormat6().open(self, _found=True)
981
1000
 
982
 
    def open_workingtree(self, _unsupported=False):
 
1001
    def open_workingtree(self, _unsupported=False,
 
1002
        recommend_upgrade=True):
983
1003
        """See BzrDir.create_workingtree."""
 
1004
        # we don't warn here about upgrades; that ought to be handled for the
 
1005
        # bzrdir as a whole
984
1006
        from bzrlib.workingtree import WorkingTreeFormat2
985
1007
        return WorkingTreeFormat2().open(self, _found=True)
986
1008
 
1013
1035
 
1014
1036
    def destroy_workingtree(self):
1015
1037
        """See BzrDir.destroy_workingtree."""
1016
 
        wt = self.open_workingtree()
 
1038
        wt = self.open_workingtree(recommend_upgrade=False)
1017
1039
        repository = wt.branch.repository
1018
1040
        empty = repository.revision_tree(_mod_revision.NULL_REVISION)
1019
1041
        wt.revert([], old_tree=empty)
1093
1115
        except errors.NotBranchError:
1094
1116
            pass
1095
1117
        try:
1096
 
            if not isinstance(self.open_workingtree()._format,
 
1118
            my_wt = self.open_workingtree(recommend_upgrade=False)
 
1119
            if not isinstance(my_wt._format,
1097
1120
                              format.workingtree_format.__class__):
1098
1121
                # the workingtree needs an upgrade.
1099
1122
                return True
1115
1138
        self._check_supported(format, unsupported)
1116
1139
        return format.open(self, _found=True)
1117
1140
 
1118
 
    def open_workingtree(self, unsupported=False):
 
1141
    def open_workingtree(self, unsupported=False,
 
1142
            recommend_upgrade=True):
1119
1143
        """See BzrDir.open_workingtree."""
1120
1144
        from bzrlib.workingtree import WorkingTreeFormat
1121
1145
        format = WorkingTreeFormat.find_format(self)
1122
 
        self._check_supported(format, unsupported)
 
1146
        self._check_supported(format, unsupported,
 
1147
            recommend_upgrade,
 
1148
            basedir=self.root_transport.base)
1123
1149
        return format.open(self, _found=True)
1124
1150
 
1125
1151
 
1306
1332
 
1307
1333
    @classmethod
1308
1334
    def register_control_format(klass, format):
1309
 
        """Register a format that does not use '.bzrdir' for its control dir.
 
1335
        """Register a format that does not use '.bzr' for its control dir.
1310
1336
 
1311
1337
        TODO: This should be pulled up into a 'ControlDirFormat' base class
1312
1338
        which BzrDirFormat can inherit from, and renamed to register_format 
1338
1364
        klass._control_formats.remove(format)
1339
1365
 
1340
1366
 
1341
 
# register BzrDirFormat as a control format
1342
 
BzrDirFormat.register_control_format(BzrDirFormat)
1343
 
 
1344
 
 
1345
1367
class BzrDirFormat4(BzrDirFormat):
1346
1368
    """Bzr dir format 4.
1347
1369
 
1598
1620
                                  __set_workingtree_format)
1599
1621
 
1600
1622
 
 
1623
# Register bzr control format
 
1624
BzrDirFormat.register_control_format(BzrDirFormat)
 
1625
 
 
1626
# Register bzr formats
1601
1627
BzrDirFormat.register_format(BzrDirFormat4())
1602
1628
BzrDirFormat.register_format(BzrDirFormat5())
1603
1629
BzrDirFormat.register_format(BzrDirFormat6())
2109
2135
                branch_converter = _mod_branch.Converter5to6()
2110
2136
                branch_converter.convert(branch)
2111
2137
        try:
2112
 
            tree = self.bzrdir.open_workingtree()
 
2138
            tree = self.bzrdir.open_workingtree(recommend_upgrade=False)
2113
2139
        except (errors.NoWorkingTree, errors.NotLocalUrl):
2114
2140
            pass
2115
2141
        else: