~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/bzrdir.py

  • Committer: Jelmer Vernooij
  • Date: 2011-01-11 04:33:12 UTC
  • mto: (5582.12.2 weave-plugin)
  • mto: This revision was merged to the branch mainline in revision 5718.
  • Revision ID: jelmer@samba.org-20110111043312-g4wx6iuf9662f36d
Move weave formats into bzrlib.plugins.weave_fmt.

Show diffs side-by-side

added added

removed removed

Lines of Context:
982
982
                self.bzrdir)
983
983
 
984
984
 
985
 
class BzrDirPreSplitOut(BzrDir):
986
 
    """A common class for the all-in-one formats."""
987
 
 
988
 
    def __init__(self, _transport, _format):
989
 
        """See BzrDir.__init__."""
990
 
        super(BzrDirPreSplitOut, self).__init__(_transport, _format)
991
 
        self._control_files = lockable_files.LockableFiles(
992
 
                                            self.get_branch_transport(None),
993
 
                                            self._format._lock_file_name,
994
 
                                            self._format._lock_class)
995
 
 
996
 
    def break_lock(self):
997
 
        """Pre-splitout bzrdirs do not suffer from stale locks."""
998
 
        raise NotImplementedError(self.break_lock)
999
 
 
1000
 
    def cloning_metadir(self, require_stacking=False):
1001
 
        """Produce a metadir suitable for cloning with."""
1002
 
        if require_stacking:
1003
 
            return controldir.format_registry.make_bzrdir('1.6')
1004
 
        return self._format.__class__()
1005
 
 
1006
 
    def clone(self, url, revision_id=None, force_new_repo=False,
1007
 
              preserve_stacking=False):
1008
 
        """See BzrDir.clone().
1009
 
 
1010
 
        force_new_repo has no effect, since this family of formats always
1011
 
        require a new repository.
1012
 
        preserve_stacking has no effect, since no source branch using this
1013
 
        family of formats can be stacked, so there is no stacking to preserve.
1014
 
        """
1015
 
        self._make_tail(url)
1016
 
        result = self._format._initialize_for_clone(url)
1017
 
        self.open_repository().clone(result, revision_id=revision_id)
1018
 
        from_branch = self.open_branch()
1019
 
        from_branch.clone(result, revision_id=revision_id)
1020
 
        try:
1021
 
            tree = self.open_workingtree()
1022
 
        except errors.NotLocalUrl:
1023
 
            # make a new one, this format always has to have one.
1024
 
            result._init_workingtree()
1025
 
        else:
1026
 
            tree.clone(result)
1027
 
        return result
1028
 
 
1029
 
    def create_branch(self, name=None, repository=None):
1030
 
        """See BzrDir.create_branch."""
1031
 
        if repository is not None:
1032
 
            raise NotImplementedError(
1033
 
                "create_branch(repository=<not None>) on %r" % (self,))
1034
 
        return self._format.get_branch_format().initialize(self, name=name)
1035
 
 
1036
 
    def destroy_branch(self, name=None):
1037
 
        """See BzrDir.destroy_branch."""
1038
 
        raise errors.UnsupportedOperation(self.destroy_branch, self)
1039
 
 
1040
 
    def create_repository(self, shared=False):
1041
 
        """See BzrDir.create_repository."""
1042
 
        if shared:
1043
 
            raise errors.IncompatibleFormat('shared repository', self._format)
1044
 
        return self.open_repository()
1045
 
 
1046
 
    def destroy_repository(self):
1047
 
        """See BzrDir.destroy_repository."""
1048
 
        raise errors.UnsupportedOperation(self.destroy_repository, self)
1049
 
 
1050
 
    def create_workingtree(self, revision_id=None, from_branch=None,
1051
 
                           accelerator_tree=None, hardlink=False):
1052
 
        """See BzrDir.create_workingtree."""
1053
 
        # The workingtree is sometimes created when the bzrdir is created,
1054
 
        # but not when cloning.
1055
 
 
1056
 
        # this looks buggy but is not -really-
1057
 
        # because this format creates the workingtree when the bzrdir is
1058
 
        # created
1059
 
        # clone and sprout will have set the revision_id
1060
 
        # and that will have set it for us, its only
1061
 
        # specific uses of create_workingtree in isolation
1062
 
        # that can do wonky stuff here, and that only
1063
 
        # happens for creating checkouts, which cannot be
1064
 
        # done on this format anyway. So - acceptable wart.
1065
 
        if hardlink:
1066
 
            warning("can't support hardlinked working trees in %r"
1067
 
                % (self,))
1068
 
        try:
1069
 
            result = self.open_workingtree(recommend_upgrade=False)
1070
 
        except errors.NoSuchFile:
1071
 
            result = self._init_workingtree()
1072
 
        if revision_id is not None:
1073
 
            if revision_id == _mod_revision.NULL_REVISION:
1074
 
                result.set_parent_ids([])
1075
 
            else:
1076
 
                result.set_parent_ids([revision_id])
1077
 
        return result
1078
 
 
1079
 
    def _init_workingtree(self):
1080
 
        from bzrlib.workingtree import WorkingTreeFormat2
1081
 
        try:
1082
 
            return WorkingTreeFormat2().initialize(self)
1083
 
        except errors.NotLocalUrl:
1084
 
            # Even though we can't access the working tree, we need to
1085
 
            # create its control files.
1086
 
            return WorkingTreeFormat2()._stub_initialize_on_transport(
1087
 
                self.transport, self._control_files._file_mode)
1088
 
 
1089
 
    def destroy_workingtree(self):
1090
 
        """See BzrDir.destroy_workingtree."""
1091
 
        raise errors.UnsupportedOperation(self.destroy_workingtree, self)
1092
 
 
1093
 
    def destroy_workingtree_metadata(self):
1094
 
        """See BzrDir.destroy_workingtree_metadata."""
1095
 
        raise errors.UnsupportedOperation(self.destroy_workingtree_metadata,
1096
 
                                          self)
1097
 
 
1098
 
    def get_branch_transport(self, branch_format, name=None):
1099
 
        """See BzrDir.get_branch_transport()."""
1100
 
        if name is not None:
1101
 
            raise errors.NoColocatedBranchSupport(self)
1102
 
        if branch_format is None:
1103
 
            return self.transport
1104
 
        try:
1105
 
            branch_format.get_format_string()
1106
 
        except NotImplementedError:
1107
 
            return self.transport
1108
 
        raise errors.IncompatibleFormat(branch_format, self._format)
1109
 
 
1110
 
    def get_repository_transport(self, repository_format):
1111
 
        """See BzrDir.get_repository_transport()."""
1112
 
        if repository_format is None:
1113
 
            return self.transport
1114
 
        try:
1115
 
            repository_format.get_format_string()
1116
 
        except NotImplementedError:
1117
 
            return self.transport
1118
 
        raise errors.IncompatibleFormat(repository_format, self._format)
1119
 
 
1120
 
    def get_workingtree_transport(self, workingtree_format):
1121
 
        """See BzrDir.get_workingtree_transport()."""
1122
 
        if workingtree_format is None:
1123
 
            return self.transport
1124
 
        try:
1125
 
            workingtree_format.get_format_string()
1126
 
        except NotImplementedError:
1127
 
            return self.transport
1128
 
        raise errors.IncompatibleFormat(workingtree_format, self._format)
1129
 
 
1130
 
    def needs_format_conversion(self, format=None):
1131
 
        """See BzrDir.needs_format_conversion()."""
1132
 
        # if the format is not the same as the system default,
1133
 
        # an upgrade is needed.
1134
 
        if format is None:
1135
 
            symbol_versioning.warn(symbol_versioning.deprecated_in((1, 13, 0))
1136
 
                % 'needs_format_conversion(format=None)')
1137
 
            format = BzrDirFormat.get_default_format()
1138
 
        return not isinstance(self._format, format.__class__)
1139
 
 
1140
 
    def open_branch(self, name=None, unsupported=False,
1141
 
                    ignore_fallbacks=False):
1142
 
        """See BzrDir.open_branch."""
1143
 
        from bzrlib.branch import BzrBranchFormat4
1144
 
        format = BzrBranchFormat4()
1145
 
        self._check_supported(format, unsupported)
1146
 
        return format.open(self, name, _found=True)
1147
 
 
1148
 
    def sprout(self, url, revision_id=None, force_new_repo=False,
1149
 
               possible_transports=None, accelerator_tree=None,
1150
 
               hardlink=False, stacked=False, create_tree_if_local=True,
1151
 
               source_branch=None):
1152
 
        """See BzrDir.sprout()."""
1153
 
        if source_branch is not None:
1154
 
            my_branch = self.open_branch()
1155
 
            if source_branch.base != my_branch.base:
1156
 
                raise AssertionError(
1157
 
                    "source branch %r is not within %r with branch %r" %
1158
 
                    (source_branch, self, my_branch))
1159
 
        if stacked:
1160
 
            raise errors.UnstackableBranchFormat(
1161
 
                self._format, self.root_transport.base)
1162
 
        if not create_tree_if_local:
1163
 
            raise errors.MustHaveWorkingTree(
1164
 
                self._format, self.root_transport.base)
1165
 
        from bzrlib.workingtree import WorkingTreeFormat2
1166
 
        self._make_tail(url)
1167
 
        result = self._format._initialize_for_clone(url)
1168
 
        try:
1169
 
            self.open_repository().clone(result, revision_id=revision_id)
1170
 
        except errors.NoRepositoryPresent:
1171
 
            pass
1172
 
        try:
1173
 
            self.open_branch().sprout(result, revision_id=revision_id)
1174
 
        except errors.NotBranchError:
1175
 
            pass
1176
 
 
1177
 
        # we always want a working tree
1178
 
        WorkingTreeFormat2().initialize(result,
1179
 
                                        accelerator_tree=accelerator_tree,
1180
 
                                        hardlink=hardlink)
1181
 
        return result
1182
 
 
1183
 
 
1184
 
class BzrDir4(BzrDirPreSplitOut):
1185
 
    """A .bzr version 4 control object.
1186
 
 
1187
 
    This is a deprecated format and may be removed after sept 2006.
1188
 
    """
1189
 
 
1190
 
    def create_repository(self, shared=False):
1191
 
        """See BzrDir.create_repository."""
1192
 
        return self._format.repository_format.initialize(self, shared)
1193
 
 
1194
 
    def needs_format_conversion(self, format=None):
1195
 
        """Format 4 dirs are always in need of conversion."""
1196
 
        if format is None:
1197
 
            symbol_versioning.warn(symbol_versioning.deprecated_in((1, 13, 0))
1198
 
                % 'needs_format_conversion(format=None)')
1199
 
        return True
1200
 
 
1201
 
    def open_repository(self):
1202
 
        """See BzrDir.open_repository."""
1203
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat4
1204
 
        return RepositoryFormat4().open(self, _found=True)
1205
 
 
1206
 
 
1207
 
class BzrDir5(BzrDirPreSplitOut):
1208
 
    """A .bzr version 5 control object.
1209
 
 
1210
 
    This is a deprecated format and may be removed after sept 2006.
1211
 
    """
1212
 
 
1213
 
    def has_workingtree(self):
1214
 
        """See BzrDir.has_workingtree."""
1215
 
        return True
1216
 
    
1217
 
    def open_repository(self):
1218
 
        """See BzrDir.open_repository."""
1219
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat5
1220
 
        return RepositoryFormat5().open(self, _found=True)
1221
 
 
1222
 
    def open_workingtree(self, _unsupported=False,
1223
 
            recommend_upgrade=True):
1224
 
        """See BzrDir.create_workingtree."""
1225
 
        from bzrlib.workingtree import WorkingTreeFormat2
1226
 
        wt_format = WorkingTreeFormat2()
1227
 
        # we don't warn here about upgrades; that ought to be handled for the
1228
 
        # bzrdir as a whole
1229
 
        return wt_format.open(self, _found=True)
1230
 
 
1231
 
 
1232
 
class BzrDir6(BzrDirPreSplitOut):
1233
 
    """A .bzr version 6 control object.
1234
 
 
1235
 
    This is a deprecated format and may be removed after sept 2006.
1236
 
    """
1237
 
 
1238
 
    def has_workingtree(self):
1239
 
        """See BzrDir.has_workingtree."""
1240
 
        return True
1241
 
    
1242
 
    def open_repository(self):
1243
 
        """See BzrDir.open_repository."""
1244
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat6
1245
 
        return RepositoryFormat6().open(self, _found=True)
1246
 
 
1247
 
    def open_workingtree(self, _unsupported=False,
1248
 
        recommend_upgrade=True):
1249
 
        """See BzrDir.create_workingtree."""
1250
 
        # we don't warn here about upgrades; that ought to be handled for the
1251
 
        # bzrdir as a whole
1252
 
        from bzrlib.workingtree import WorkingTreeFormat2
1253
 
        return WorkingTreeFormat2().open(self, _found=True)
1254
 
 
1255
 
 
1256
985
class BzrDirMeta1(BzrDir):
1257
986
    """A .bzr meta version 1 control object.
1258
987
 
1732
1461
        controldir.network_format_registry.remove(format.get_format_string())
1733
1462
 
1734
1463
 
1735
 
class BzrDirFormat4(BzrDirFormat):
1736
 
    """Bzr dir format 4.
1737
 
 
1738
 
    This format is a combined format for working tree, branch and repository.
1739
 
    It has:
1740
 
     - Format 1 working trees [always]
1741
 
     - Format 4 branches [always]
1742
 
     - Format 4 repositories [always]
1743
 
 
1744
 
    This format is deprecated: it indexes texts using a text it which is
1745
 
    removed in format 5; write support for this format has been removed.
1746
 
    """
1747
 
 
1748
 
    _lock_class = lockable_files.TransportLock
1749
 
 
1750
 
    def get_format_string(self):
1751
 
        """See BzrDirFormat.get_format_string()."""
1752
 
        return "Bazaar-NG branch, format 0.0.4\n"
1753
 
 
1754
 
    def get_format_description(self):
1755
 
        """See BzrDirFormat.get_format_description()."""
1756
 
        return "All-in-one format 4"
1757
 
 
1758
 
    def get_converter(self, format=None):
1759
 
        """See BzrDirFormat.get_converter()."""
1760
 
        # there is one and only one upgrade path here.
1761
 
        return ConvertBzrDir4To5()
1762
 
 
1763
 
    def initialize_on_transport(self, transport):
1764
 
        """Format 4 branches cannot be created."""
1765
 
        raise errors.UninitializableFormat(self)
1766
 
 
1767
 
    def is_supported(self):
1768
 
        """Format 4 is not supported.
1769
 
 
1770
 
        It is not supported because the model changed from 4 to 5 and the
1771
 
        conversion logic is expensive - so doing it on the fly was not
1772
 
        feasible.
1773
 
        """
1774
 
        return False
1775
 
 
1776
 
    def network_name(self):
1777
 
        return self.get_format_string()
1778
 
 
1779
 
    def _open(self, transport):
1780
 
        """See BzrDirFormat._open."""
1781
 
        return BzrDir4(transport, self)
1782
 
 
1783
 
    def __return_repository_format(self):
1784
 
        """Circular import protection."""
1785
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat4
1786
 
        return RepositoryFormat4()
1787
 
    repository_format = property(__return_repository_format)
1788
 
 
1789
 
 
1790
 
class BzrDirFormatAllInOne(BzrDirFormat):
1791
 
    """Common class for formats before meta-dirs."""
1792
 
 
1793
 
    def initialize_on_transport_ex(self, transport, use_existing_dir=False,
1794
 
        create_prefix=False, force_new_repo=False, stacked_on=None,
1795
 
        stack_on_pwd=None, repo_format_name=None, make_working_trees=None,
1796
 
        shared_repo=False):
1797
 
        """See BzrDirFormat.initialize_on_transport_ex."""
1798
 
        require_stacking = (stacked_on is not None)
1799
 
        # Format 5 cannot stack, but we've been asked to - actually init
1800
 
        # a Meta1Dir
1801
 
        if require_stacking:
1802
 
            format = BzrDirMetaFormat1()
1803
 
            return format.initialize_on_transport_ex(transport,
1804
 
                use_existing_dir=use_existing_dir, create_prefix=create_prefix,
1805
 
                force_new_repo=force_new_repo, stacked_on=stacked_on,
1806
 
                stack_on_pwd=stack_on_pwd, repo_format_name=repo_format_name,
1807
 
                make_working_trees=make_working_trees, shared_repo=shared_repo)
1808
 
        return BzrDirFormat.initialize_on_transport_ex(self, transport,
1809
 
            use_existing_dir=use_existing_dir, create_prefix=create_prefix,
1810
 
            force_new_repo=force_new_repo, stacked_on=stacked_on,
1811
 
            stack_on_pwd=stack_on_pwd, repo_format_name=repo_format_name,
1812
 
            make_working_trees=make_working_trees, shared_repo=shared_repo)
1813
 
 
1814
 
 
1815
 
class BzrDirFormat5(BzrDirFormatAllInOne):
1816
 
    """Bzr control format 5.
1817
 
 
1818
 
    This format is a combined format for working tree, branch and repository.
1819
 
    It has:
1820
 
     - Format 2 working trees [always]
1821
 
     - Format 4 branches [always]
1822
 
     - Format 5 repositories [always]
1823
 
       Unhashed stores in the repository.
1824
 
    """
1825
 
 
1826
 
    _lock_class = lockable_files.TransportLock
1827
 
 
1828
 
    def get_format_string(self):
1829
 
        """See BzrDirFormat.get_format_string()."""
1830
 
        return "Bazaar-NG branch, format 5\n"
1831
 
 
1832
 
    def get_branch_format(self):
1833
 
        from bzrlib import branch
1834
 
        return branch.BzrBranchFormat4()
1835
 
 
1836
 
    def get_format_description(self):
1837
 
        """See BzrDirFormat.get_format_description()."""
1838
 
        return "All-in-one format 5"
1839
 
 
1840
 
    def get_converter(self, format=None):
1841
 
        """See BzrDirFormat.get_converter()."""
1842
 
        # there is one and only one upgrade path here.
1843
 
        return ConvertBzrDir5To6()
1844
 
 
1845
 
    def _initialize_for_clone(self, url):
1846
 
        return self.initialize_on_transport(get_transport(url), _cloning=True)
1847
 
 
1848
 
    def initialize_on_transport(self, transport, _cloning=False):
1849
 
        """Format 5 dirs always have working tree, branch and repository.
1850
 
 
1851
 
        Except when they are being cloned.
1852
 
        """
1853
 
        from bzrlib.branch import BzrBranchFormat4
1854
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat5
1855
 
        result = (super(BzrDirFormat5, self).initialize_on_transport(transport))
1856
 
        RepositoryFormat5().initialize(result, _internal=True)
1857
 
        if not _cloning:
1858
 
            branch = BzrBranchFormat4().initialize(result)
1859
 
            result._init_workingtree()
1860
 
        return result
1861
 
 
1862
 
    def network_name(self):
1863
 
        return self.get_format_string()
1864
 
 
1865
 
    def _open(self, transport):
1866
 
        """See BzrDirFormat._open."""
1867
 
        return BzrDir5(transport, self)
1868
 
 
1869
 
    def __return_repository_format(self):
1870
 
        """Circular import protection."""
1871
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat5
1872
 
        return RepositoryFormat5()
1873
 
    repository_format = property(__return_repository_format)
1874
 
 
1875
 
 
1876
 
class BzrDirFormat6(BzrDirFormatAllInOne):
1877
 
    """Bzr control format 6.
1878
 
 
1879
 
    This format is a combined format for working tree, branch and repository.
1880
 
    It has:
1881
 
     - Format 2 working trees [always]
1882
 
     - Format 4 branches [always]
1883
 
     - Format 6 repositories [always]
1884
 
    """
1885
 
 
1886
 
    _lock_class = lockable_files.TransportLock
1887
 
 
1888
 
    def get_format_string(self):
1889
 
        """See BzrDirFormat.get_format_string()."""
1890
 
        return "Bazaar-NG branch, format 6\n"
1891
 
 
1892
 
    def get_format_description(self):
1893
 
        """See BzrDirFormat.get_format_description()."""
1894
 
        return "All-in-one format 6"
1895
 
 
1896
 
    def get_branch_format(self):
1897
 
        from bzrlib import branch
1898
 
        return branch.BzrBranchFormat4()
1899
 
 
1900
 
    def get_converter(self, format=None):
1901
 
        """See BzrDirFormat.get_converter()."""
1902
 
        # there is one and only one upgrade path here.
1903
 
        return ConvertBzrDir6ToMeta()
1904
 
 
1905
 
    def _initialize_for_clone(self, url):
1906
 
        return self.initialize_on_transport(get_transport(url), _cloning=True)
1907
 
 
1908
 
    def initialize_on_transport(self, transport, _cloning=False):
1909
 
        """Format 6 dirs always have working tree, branch and repository.
1910
 
 
1911
 
        Except when they are being cloned.
1912
 
        """
1913
 
        from bzrlib.branch import BzrBranchFormat4
1914
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat6
1915
 
        result = super(BzrDirFormat6, self).initialize_on_transport(transport)
1916
 
        RepositoryFormat6().initialize(result, _internal=True)
1917
 
        if not _cloning:
1918
 
            branch = BzrBranchFormat4().initialize(result)
1919
 
            result._init_workingtree()
1920
 
        return result
1921
 
 
1922
 
    def network_name(self):
1923
 
        return self.get_format_string()
1924
 
 
1925
 
    def _open(self, transport):
1926
 
        """See BzrDirFormat._open."""
1927
 
        return BzrDir6(transport, self)
1928
 
 
1929
 
    def __return_repository_format(self):
1930
 
        """Circular import protection."""
1931
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat6
1932
 
        return RepositoryFormat6()
1933
 
    repository_format = property(__return_repository_format)
1934
 
 
1935
 
 
1936
1464
class BzrDirMetaFormat1(BzrDirFormat):
1937
1465
    """Bzr meta control format 1
1938
1466
 
2139
1667
 
2140
1668
 
2141
1669
# Register bzr formats
2142
 
BzrDirFormat.register_format(BzrDirFormat4())
2143
 
BzrDirFormat.register_format(BzrDirFormat5())
2144
 
BzrDirFormat.register_format(BzrDirFormat6())
2145
1670
__default_format = BzrDirMetaFormat1()
2146
1671
BzrDirFormat.register_format(__default_format)
2147
1672
controldir.ControlDirFormat._default_format = __default_format
2163
1688
        self.pb.update(message, self.count, self.total)
2164
1689
 
2165
1690
 
2166
 
class ConvertBzrDir4To5(Converter):
2167
 
    """Converts format 4 bzr dirs to format 5."""
2168
 
 
2169
 
    def __init__(self):
2170
 
        super(ConvertBzrDir4To5, self).__init__()
2171
 
        self.converted_revs = set()
2172
 
        self.absent_revisions = set()
2173
 
        self.text_count = 0
2174
 
        self.revisions = {}
2175
 
 
2176
 
    def convert(self, to_convert, pb):
2177
 
        """See Converter.convert()."""
2178
 
        self.bzrdir = to_convert
2179
 
        if pb is not None:
2180
 
            warnings.warn("pb parameter to convert() is deprecated")
2181
 
        self.pb = ui.ui_factory.nested_progress_bar()
2182
 
        try:
2183
 
            ui.ui_factory.note('starting upgrade from format 4 to 5')
2184
 
            if isinstance(self.bzrdir.transport, local.LocalTransport):
2185
 
                self.bzrdir.get_workingtree_transport(None).delete('stat-cache')
2186
 
            self._convert_to_weaves()
2187
 
            return BzrDir.open(self.bzrdir.user_url)
2188
 
        finally:
2189
 
            self.pb.finished()
2190
 
 
2191
 
    def _convert_to_weaves(self):
2192
 
        ui.ui_factory.note('note: upgrade may be faster if all store files are ungzipped first')
2193
 
        try:
2194
 
            # TODO permissions
2195
 
            stat = self.bzrdir.transport.stat('weaves')
2196
 
            if not S_ISDIR(stat.st_mode):
2197
 
                self.bzrdir.transport.delete('weaves')
2198
 
                self.bzrdir.transport.mkdir('weaves')
2199
 
        except errors.NoSuchFile:
2200
 
            self.bzrdir.transport.mkdir('weaves')
2201
 
        # deliberately not a WeaveFile as we want to build it up slowly.
2202
 
        self.inv_weave = Weave('inventory')
2203
 
        # holds in-memory weaves for all files
2204
 
        self.text_weaves = {}
2205
 
        self.bzrdir.transport.delete('branch-format')
2206
 
        self.branch = self.bzrdir.open_branch()
2207
 
        self._convert_working_inv()
2208
 
        rev_history = self.branch.revision_history()
2209
 
        # to_read is a stack holding the revisions we still need to process;
2210
 
        # appending to it adds new highest-priority revisions
2211
 
        self.known_revisions = set(rev_history)
2212
 
        self.to_read = rev_history[-1:]
2213
 
        while self.to_read:
2214
 
            rev_id = self.to_read.pop()
2215
 
            if (rev_id not in self.revisions
2216
 
                and rev_id not in self.absent_revisions):
2217
 
                self._load_one_rev(rev_id)
2218
 
        self.pb.clear()
2219
 
        to_import = self._make_order()
2220
 
        for i, rev_id in enumerate(to_import):
2221
 
            self.pb.update('converting revision', i, len(to_import))
2222
 
            self._convert_one_rev(rev_id)
2223
 
        self.pb.clear()
2224
 
        self._write_all_weaves()
2225
 
        self._write_all_revs()
2226
 
        ui.ui_factory.note('upgraded to weaves:')
2227
 
        ui.ui_factory.note('  %6d revisions and inventories' % len(self.revisions))
2228
 
        ui.ui_factory.note('  %6d revisions not present' % len(self.absent_revisions))
2229
 
        ui.ui_factory.note('  %6d texts' % self.text_count)
2230
 
        self._cleanup_spare_files_after_format4()
2231
 
        self.branch._transport.put_bytes(
2232
 
            'branch-format',
2233
 
            BzrDirFormat5().get_format_string(),
2234
 
            mode=self.bzrdir._get_file_mode())
2235
 
 
2236
 
    def _cleanup_spare_files_after_format4(self):
2237
 
        # FIXME working tree upgrade foo.
2238
 
        for n in 'merged-patches', 'pending-merged-patches':
2239
 
            try:
2240
 
                ## assert os.path.getsize(p) == 0
2241
 
                self.bzrdir.transport.delete(n)
2242
 
            except errors.NoSuchFile:
2243
 
                pass
2244
 
        self.bzrdir.transport.delete_tree('inventory-store')
2245
 
        self.bzrdir.transport.delete_tree('text-store')
2246
 
 
2247
 
    def _convert_working_inv(self):
2248
 
        inv = xml4.serializer_v4.read_inventory(
2249
 
                self.branch._transport.get('inventory'))
2250
 
        new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv, working=True)
2251
 
        self.branch._transport.put_bytes('inventory', new_inv_xml,
2252
 
            mode=self.bzrdir._get_file_mode())
2253
 
 
2254
 
    def _write_all_weaves(self):
2255
 
        controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)
2256
 
        weave_transport = self.bzrdir.transport.clone('weaves')
2257
 
        weaves = WeaveStore(weave_transport, prefixed=False)
2258
 
        transaction = WriteTransaction()
2259
 
 
2260
 
        try:
2261
 
            i = 0
2262
 
            for file_id, file_weave in self.text_weaves.items():
2263
 
                self.pb.update('writing weave', i, len(self.text_weaves))
2264
 
                weaves._put_weave(file_id, file_weave, transaction)
2265
 
                i += 1
2266
 
            self.pb.update('inventory', 0, 1)
2267
 
            controlweaves._put_weave('inventory', self.inv_weave, transaction)
2268
 
            self.pb.update('inventory', 1, 1)
2269
 
        finally:
2270
 
            self.pb.clear()
2271
 
 
2272
 
    def _write_all_revs(self):
2273
 
        """Write all revisions out in new form."""
2274
 
        self.bzrdir.transport.delete_tree('revision-store')
2275
 
        self.bzrdir.transport.mkdir('revision-store')
2276
 
        revision_transport = self.bzrdir.transport.clone('revision-store')
2277
 
        # TODO permissions
2278
 
        from bzrlib.xml5 import serializer_v5
2279
 
        from bzrlib.repofmt.weaverepo import RevisionTextStore
2280
 
        revision_store = RevisionTextStore(revision_transport,
2281
 
            serializer_v5, False, versionedfile.PrefixMapper(),
2282
 
            lambda:True, lambda:True)
2283
 
        try:
2284
 
            for i, rev_id in enumerate(self.converted_revs):
2285
 
                self.pb.update('write revision', i, len(self.converted_revs))
2286
 
                text = serializer_v5.write_revision_to_string(
2287
 
                    self.revisions[rev_id])
2288
 
                key = (rev_id,)
2289
 
                revision_store.add_lines(key, None, osutils.split_lines(text))
2290
 
        finally:
2291
 
            self.pb.clear()
2292
 
 
2293
 
    def _load_one_rev(self, rev_id):
2294
 
        """Load a revision object into memory.
2295
 
 
2296
 
        Any parents not either loaded or abandoned get queued to be
2297
 
        loaded."""
2298
 
        self.pb.update('loading revision',
2299
 
                       len(self.revisions),
2300
 
                       len(self.known_revisions))
2301
 
        if not self.branch.repository.has_revision(rev_id):
2302
 
            self.pb.clear()
2303
 
            ui.ui_factory.note('revision {%s} not present in branch; '
2304
 
                         'will be converted as a ghost' %
2305
 
                         rev_id)
2306
 
            self.absent_revisions.add(rev_id)
2307
 
        else:
2308
 
            rev = self.branch.repository.get_revision(rev_id)
2309
 
            for parent_id in rev.parent_ids:
2310
 
                self.known_revisions.add(parent_id)
2311
 
                self.to_read.append(parent_id)
2312
 
            self.revisions[rev_id] = rev
2313
 
 
2314
 
    def _load_old_inventory(self, rev_id):
2315
 
        f = self.branch.repository.inventory_store.get(rev_id)
2316
 
        try:
2317
 
            old_inv_xml = f.read()
2318
 
        finally:
2319
 
            f.close()
2320
 
        inv = xml4.serializer_v4.read_inventory_from_string(old_inv_xml)
2321
 
        inv.revision_id = rev_id
2322
 
        rev = self.revisions[rev_id]
2323
 
        return inv
2324
 
 
2325
 
    def _load_updated_inventory(self, rev_id):
2326
 
        inv_xml = self.inv_weave.get_text(rev_id)
2327
 
        inv = xml5.serializer_v5.read_inventory_from_string(inv_xml, rev_id)
2328
 
        return inv
2329
 
 
2330
 
    def _convert_one_rev(self, rev_id):
2331
 
        """Convert revision and all referenced objects to new format."""
2332
 
        rev = self.revisions[rev_id]
2333
 
        inv = self._load_old_inventory(rev_id)
2334
 
        present_parents = [p for p in rev.parent_ids
2335
 
                           if p not in self.absent_revisions]
2336
 
        self._convert_revision_contents(rev, inv, present_parents)
2337
 
        self._store_new_inv(rev, inv, present_parents)
2338
 
        self.converted_revs.add(rev_id)
2339
 
 
2340
 
    def _store_new_inv(self, rev, inv, present_parents):
2341
 
        new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
2342
 
        new_inv_sha1 = sha_string(new_inv_xml)
2343
 
        self.inv_weave.add_lines(rev.revision_id,
2344
 
                                 present_parents,
2345
 
                                 new_inv_xml.splitlines(True))
2346
 
        rev.inventory_sha1 = new_inv_sha1
2347
 
 
2348
 
    def _convert_revision_contents(self, rev, inv, present_parents):
2349
 
        """Convert all the files within a revision.
2350
 
 
2351
 
        Also upgrade the inventory to refer to the text revision ids."""
2352
 
        rev_id = rev.revision_id
2353
 
        mutter('converting texts of revision {%s}',
2354
 
               rev_id)
2355
 
        parent_invs = map(self._load_updated_inventory, present_parents)
2356
 
        entries = inv.iter_entries()
2357
 
        entries.next()
2358
 
        for path, ie in entries:
2359
 
            self._convert_file_version(rev, ie, parent_invs)
2360
 
 
2361
 
    def _convert_file_version(self, rev, ie, parent_invs):
2362
 
        """Convert one version of one file.
2363
 
 
2364
 
        The file needs to be added into the weave if it is a merge
2365
 
        of >=2 parents or if it's changed from its parent.
2366
 
        """
2367
 
        file_id = ie.file_id
2368
 
        rev_id = rev.revision_id
2369
 
        w = self.text_weaves.get(file_id)
2370
 
        if w is None:
2371
 
            w = Weave(file_id)
2372
 
            self.text_weaves[file_id] = w
2373
 
        text_changed = False
2374
 
        parent_candiate_entries = ie.parent_candidates(parent_invs)
2375
 
        heads = graph.Graph(self).heads(parent_candiate_entries.keys())
2376
 
        # XXX: Note that this is unordered - and this is tolerable because
2377
 
        # the previous code was also unordered.
2378
 
        previous_entries = dict((head, parent_candiate_entries[head]) for head
2379
 
            in heads)
2380
 
        self.snapshot_ie(previous_entries, ie, w, rev_id)
2381
 
 
2382
 
    def get_parent_map(self, revision_ids):
2383
 
        """See graph.StackedParentsProvider.get_parent_map"""
2384
 
        return dict((revision_id, self.revisions[revision_id])
2385
 
                    for revision_id in revision_ids
2386
 
                     if revision_id in self.revisions)
2387
 
 
2388
 
    def snapshot_ie(self, previous_revisions, ie, w, rev_id):
2389
 
        # TODO: convert this logic, which is ~= snapshot to
2390
 
        # a call to:. This needs the path figured out. rather than a work_tree
2391
 
        # a v4 revision_tree can be given, or something that looks enough like
2392
 
        # one to give the file content to the entry if it needs it.
2393
 
        # and we need something that looks like a weave store for snapshot to
2394
 
        # save against.
2395
 
        #ie.snapshot(rev, PATH, previous_revisions, REVISION_TREE, InMemoryWeaveStore(self.text_weaves))
2396
 
        if len(previous_revisions) == 1:
2397
 
            previous_ie = previous_revisions.values()[0]
2398
 
            if ie._unchanged(previous_ie):
2399
 
                ie.revision = previous_ie.revision
2400
 
                return
2401
 
        if ie.has_text():
2402
 
            f = self.branch.repository._text_store.get(ie.text_id)
2403
 
            try:
2404
 
                file_lines = f.readlines()
2405
 
            finally:
2406
 
                f.close()
2407
 
            w.add_lines(rev_id, previous_revisions, file_lines)
2408
 
            self.text_count += 1
2409
 
        else:
2410
 
            w.add_lines(rev_id, previous_revisions, [])
2411
 
        ie.revision = rev_id
2412
 
 
2413
 
    def _make_order(self):
2414
 
        """Return a suitable order for importing revisions.
2415
 
 
2416
 
        The order must be such that an revision is imported after all
2417
 
        its (present) parents.
2418
 
        """
2419
 
        todo = set(self.revisions.keys())
2420
 
        done = self.absent_revisions.copy()
2421
 
        order = []
2422
 
        while todo:
2423
 
            # scan through looking for a revision whose parents
2424
 
            # are all done
2425
 
            for rev_id in sorted(list(todo)):
2426
 
                rev = self.revisions[rev_id]
2427
 
                parent_ids = set(rev.parent_ids)
2428
 
                if parent_ids.issubset(done):
2429
 
                    # can take this one now
2430
 
                    order.append(rev_id)
2431
 
                    todo.remove(rev_id)
2432
 
                    done.add(rev_id)
2433
 
        return order
2434
 
 
2435
 
 
2436
 
class ConvertBzrDir5To6(Converter):
2437
 
    """Converts format 5 bzr dirs to format 6."""
2438
 
 
2439
 
    def convert(self, to_convert, pb):
2440
 
        """See Converter.convert()."""
2441
 
        self.bzrdir = to_convert
2442
 
        pb = ui.ui_factory.nested_progress_bar()
2443
 
        try:
2444
 
            ui.ui_factory.note('starting upgrade from format 5 to 6')
2445
 
            self._convert_to_prefixed()
2446
 
            return BzrDir.open(self.bzrdir.user_url)
2447
 
        finally:
2448
 
            pb.finished()
2449
 
 
2450
 
    def _convert_to_prefixed(self):
2451
 
        from bzrlib.store import TransportStore
2452
 
        self.bzrdir.transport.delete('branch-format')
2453
 
        for store_name in ["weaves", "revision-store"]:
2454
 
            ui.ui_factory.note("adding prefixes to %s" % store_name)
2455
 
            store_transport = self.bzrdir.transport.clone(store_name)
2456
 
            store = TransportStore(store_transport, prefixed=True)
2457
 
            for urlfilename in store_transport.list_dir('.'):
2458
 
                filename = urlutils.unescape(urlfilename)
2459
 
                if (filename.endswith(".weave") or
2460
 
                    filename.endswith(".gz") or
2461
 
                    filename.endswith(".sig")):
2462
 
                    file_id, suffix = os.path.splitext(filename)
2463
 
                else:
2464
 
                    file_id = filename
2465
 
                    suffix = ''
2466
 
                new_name = store._mapper.map((file_id,)) + suffix
2467
 
                # FIXME keep track of the dirs made RBC 20060121
2468
 
                try:
2469
 
                    store_transport.move(filename, new_name)
2470
 
                except errors.NoSuchFile: # catches missing dirs strangely enough
2471
 
                    store_transport.mkdir(osutils.dirname(new_name))
2472
 
                    store_transport.move(filename, new_name)
2473
 
        self.bzrdir.transport.put_bytes(
2474
 
            'branch-format',
2475
 
            BzrDirFormat6().get_format_string(),
2476
 
            mode=self.bzrdir._get_file_mode())
2477
 
 
2478
 
 
2479
 
class ConvertBzrDir6ToMeta(Converter):
2480
 
    """Converts format 6 bzr dirs to metadirs."""
2481
 
 
2482
 
    def convert(self, to_convert, pb):
2483
 
        """See Converter.convert()."""
2484
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat7
2485
 
        from bzrlib.branch import BzrBranchFormat5
2486
 
        self.bzrdir = to_convert
2487
 
        self.pb = ui.ui_factory.nested_progress_bar()
2488
 
        self.count = 0
2489
 
        self.total = 20 # the steps we know about
2490
 
        self.garbage_inventories = []
2491
 
        self.dir_mode = self.bzrdir._get_dir_mode()
2492
 
        self.file_mode = self.bzrdir._get_file_mode()
2493
 
 
2494
 
        ui.ui_factory.note('starting upgrade from format 6 to metadir')
2495
 
        self.bzrdir.transport.put_bytes(
2496
 
                'branch-format',
2497
 
                "Converting to format 6",
2498
 
                mode=self.file_mode)
2499
 
        # its faster to move specific files around than to open and use the apis...
2500
 
        # first off, nuke ancestry.weave, it was never used.
2501
 
        try:
2502
 
            self.step('Removing ancestry.weave')
2503
 
            self.bzrdir.transport.delete('ancestry.weave')
2504
 
        except errors.NoSuchFile:
2505
 
            pass
2506
 
        # find out whats there
2507
 
        self.step('Finding branch files')
2508
 
        last_revision = self.bzrdir.open_branch().last_revision()
2509
 
        bzrcontents = self.bzrdir.transport.list_dir('.')
2510
 
        for name in bzrcontents:
2511
 
            if name.startswith('basis-inventory.'):
2512
 
                self.garbage_inventories.append(name)
2513
 
        # create new directories for repository, working tree and branch
2514
 
        repository_names = [('inventory.weave', True),
2515
 
                            ('revision-store', True),
2516
 
                            ('weaves', True)]
2517
 
        self.step('Upgrading repository  ')
2518
 
        self.bzrdir.transport.mkdir('repository', mode=self.dir_mode)
2519
 
        self.make_lock('repository')
2520
 
        # we hard code the formats here because we are converting into
2521
 
        # the meta format. The meta format upgrader can take this to a
2522
 
        # future format within each component.
2523
 
        self.put_format('repository', RepositoryFormat7())
2524
 
        for entry in repository_names:
2525
 
            self.move_entry('repository', entry)
2526
 
 
2527
 
        self.step('Upgrading branch      ')
2528
 
        self.bzrdir.transport.mkdir('branch', mode=self.dir_mode)
2529
 
        self.make_lock('branch')
2530
 
        self.put_format('branch', BzrBranchFormat5())
2531
 
        branch_files = [('revision-history', True),
2532
 
                        ('branch-name', True),
2533
 
                        ('parent', False)]
2534
 
        for entry in branch_files:
2535
 
            self.move_entry('branch', entry)
2536
 
 
2537
 
        checkout_files = [('pending-merges', True),
2538
 
                          ('inventory', True),
2539
 
                          ('stat-cache', False)]
2540
 
        # If a mandatory checkout file is not present, the branch does not have
2541
 
        # a functional checkout. Do not create a checkout in the converted
2542
 
        # branch.
2543
 
        for name, mandatory in checkout_files:
2544
 
            if mandatory and name not in bzrcontents:
2545
 
                has_checkout = False
2546
 
                break
2547
 
        else:
2548
 
            has_checkout = True
2549
 
        if not has_checkout:
2550
 
            ui.ui_factory.note('No working tree.')
2551
 
            # If some checkout files are there, we may as well get rid of them.
2552
 
            for name, mandatory in checkout_files:
2553
 
                if name in bzrcontents:
2554
 
                    self.bzrdir.transport.delete(name)
2555
 
        else:
2556
 
            from bzrlib.workingtree import WorkingTreeFormat3
2557
 
            self.step('Upgrading working tree')
2558
 
            self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
2559
 
            self.make_lock('checkout')
2560
 
            self.put_format(
2561
 
                'checkout', WorkingTreeFormat3())
2562
 
            self.bzrdir.transport.delete_multi(
2563
 
                self.garbage_inventories, self.pb)
2564
 
            for entry in checkout_files:
2565
 
                self.move_entry('checkout', entry)
2566
 
            if last_revision is not None:
2567
 
                self.bzrdir.transport.put_bytes(
2568
 
                    'checkout/last-revision', last_revision)
2569
 
        self.bzrdir.transport.put_bytes(
2570
 
            'branch-format',
2571
 
            BzrDirMetaFormat1().get_format_string(),
2572
 
            mode=self.file_mode)
2573
 
        self.pb.finished()
2574
 
        return BzrDir.open(self.bzrdir.user_url)
2575
 
 
2576
 
    def make_lock(self, name):
2577
 
        """Make a lock for the new control dir name."""
2578
 
        self.step('Make %s lock' % name)
2579
 
        ld = lockdir.LockDir(self.bzrdir.transport,
2580
 
                             '%s/lock' % name,
2581
 
                             file_modebits=self.file_mode,
2582
 
                             dir_modebits=self.dir_mode)
2583
 
        ld.create()
2584
 
 
2585
 
    def move_entry(self, new_dir, entry):
2586
 
        """Move then entry name into new_dir."""
2587
 
        name = entry[0]
2588
 
        mandatory = entry[1]
2589
 
        self.step('Moving %s' % name)
2590
 
        try:
2591
 
            self.bzrdir.transport.move(name, '%s/%s' % (new_dir, name))
2592
 
        except errors.NoSuchFile:
2593
 
            if mandatory:
2594
 
                raise
2595
 
 
2596
 
    def put_format(self, dirname, format):
2597
 
        self.bzrdir.transport.put_bytes('%s/format' % dirname,
2598
 
            format.get_format_string(),
2599
 
            self.file_mode)
2600
 
 
2601
 
 
2602
1691
class ConvertMetaToMeta(Converter):
2603
1692
    """Converts the components of metadirs."""
2604
1693
 
3122
2211
    registry.register(key, helper, help, native, deprecated, hidden,
3123
2212
        experimental, alias)
3124
2213
 
3125
 
# The pre-0.8 formats have their repository format network name registered in
3126
 
# repository.py. MetaDir formats have their repository format network name
3127
 
# inferred from their disk format string.
3128
 
controldir.format_registry.register('weave', BzrDirFormat6,
3129
 
    'Pre-0.8 format.  Slower than knit and does not'
3130
 
    ' support checkouts or shared repositories.',
3131
 
    hidden=True,
3132
 
    deprecated=True)
3133
 
register_metadir(controldir.format_registry, 'metaweave',
3134
 
    'bzrlib.repofmt.weaverepo.RepositoryFormat7',
3135
 
    'Transitional format in 0.8.  Slower than knit.',
3136
 
    branch_format='bzrlib.branch.BzrBranchFormat5',
3137
 
    tree_format='bzrlib.workingtree.WorkingTreeFormat3',
3138
 
    hidden=True,
3139
 
    deprecated=True)
3140
2214
register_metadir(controldir.format_registry, 'knit',
3141
2215
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
3142
2216
    'Format using knits.  Recommended for interoperation with bzr <= 0.14.',