~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/bzrdir.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2011-03-22 09:57:11 UTC
  • mfrom: (5724.1.4 jam-integration)
  • Revision ID: pqm@pqm.ubuntu.com-20110322095711-9bggm9tnxnw9frow
(jameinel) Fix tar exporters to always write to binary streams. (John A
 Meinel)

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
objects returned.
26
26
"""
27
27
 
28
 
# TODO: Move old formats into a plugin to make this file smaller.
29
 
 
30
 
import os
31
28
import sys
32
 
import warnings
33
29
 
34
30
from bzrlib.lazy_import import lazy_import
35
31
lazy_import(globals(), """
55
51
    win32utils,
56
52
    workingtree,
57
53
    workingtree_4,
58
 
    xml4,
59
 
    xml5,
60
54
    )
61
55
from bzrlib.repofmt import pack_repo
62
 
from bzrlib.smart.client import _SmartClient
63
 
from bzrlib.store.versioned import VersionedFileStore
64
 
from bzrlib.transactions import WriteTransaction
65
56
from bzrlib.transport import (
66
57
    do_catching_redirections,
67
58
    local,
68
59
    )
69
 
from bzrlib.weave import (
70
 
    WeaveFile,
71
 
    Weave,
72
 
    )
73
60
""")
74
61
 
75
62
from bzrlib.trace import (
76
 
    mutter,
77
63
    note,
78
 
    warning,
79
64
    )
80
65
 
81
66
from bzrlib import (
82
67
    hooks,
 
68
    registry,
83
69
    )
84
70
from bzrlib.symbol_versioning import (
85
71
    deprecated_in,
1016
1002
                self.bzrdir)
1017
1003
 
1018
1004
 
1019
 
class BzrDirPreSplitOut(BzrDir):
1020
 
    """A common class for the all-in-one formats."""
1021
 
 
1022
 
    def __init__(self, _transport, _format):
1023
 
        """See BzrDir.__init__."""
1024
 
        super(BzrDirPreSplitOut, self).__init__(_transport, _format)
1025
 
        self._control_files = lockable_files.LockableFiles(
1026
 
                                            self.get_branch_transport(None),
1027
 
                                            self._format._lock_file_name,
1028
 
                                            self._format._lock_class)
1029
 
 
1030
 
    def break_lock(self):
1031
 
        """Pre-splitout bzrdirs do not suffer from stale locks."""
1032
 
        raise NotImplementedError(self.break_lock)
1033
 
 
1034
 
    def cloning_metadir(self, require_stacking=False):
1035
 
        """Produce a metadir suitable for cloning with."""
1036
 
        if require_stacking:
1037
 
            return controldir.format_registry.make_bzrdir('1.6')
1038
 
        return self._format.__class__()
1039
 
 
1040
 
    def clone(self, url, revision_id=None, force_new_repo=False,
1041
 
              preserve_stacking=False):
1042
 
        """See BzrDir.clone().
1043
 
 
1044
 
        force_new_repo has no effect, since this family of formats always
1045
 
        require a new repository.
1046
 
        preserve_stacking has no effect, since no source branch using this
1047
 
        family of formats can be stacked, so there is no stacking to preserve.
1048
 
        """
1049
 
        self._make_tail(url)
1050
 
        result = self._format._initialize_for_clone(url)
1051
 
        self.open_repository().clone(result, revision_id=revision_id)
1052
 
        from_branch = self.open_branch()
1053
 
        from_branch.clone(result, revision_id=revision_id)
1054
 
        try:
1055
 
            tree = self.open_workingtree()
1056
 
        except errors.NotLocalUrl:
1057
 
            # make a new one, this format always has to have one.
1058
 
            result._init_workingtree()
1059
 
        else:
1060
 
            tree.clone(result)
1061
 
        return result
1062
 
 
1063
 
    def create_branch(self, name=None, repository=None):
1064
 
        """See BzrDir.create_branch."""
1065
 
        if repository is not None:
1066
 
            raise NotImplementedError(
1067
 
                "create_branch(repository=<not None>) on %r" % (self,))
1068
 
        return self._format.get_branch_format().initialize(self, name=name)
1069
 
 
1070
 
    def destroy_branch(self, name=None):
1071
 
        """See BzrDir.destroy_branch."""
1072
 
        raise errors.UnsupportedOperation(self.destroy_branch, self)
1073
 
 
1074
 
    def create_repository(self, shared=False):
1075
 
        """See BzrDir.create_repository."""
1076
 
        if shared:
1077
 
            raise errors.IncompatibleFormat('shared repository', self._format)
1078
 
        return self.open_repository()
1079
 
 
1080
 
    def destroy_repository(self):
1081
 
        """See BzrDir.destroy_repository."""
1082
 
        raise errors.UnsupportedOperation(self.destroy_repository, self)
1083
 
 
1084
 
    def create_workingtree(self, revision_id=None, from_branch=None,
1085
 
                           accelerator_tree=None, hardlink=False):
1086
 
        """See BzrDir.create_workingtree."""
1087
 
        # The workingtree is sometimes created when the bzrdir is created,
1088
 
        # but not when cloning.
1089
 
 
1090
 
        # this looks buggy but is not -really-
1091
 
        # because this format creates the workingtree when the bzrdir is
1092
 
        # created
1093
 
        # clone and sprout will have set the revision_id
1094
 
        # and that will have set it for us, its only
1095
 
        # specific uses of create_workingtree in isolation
1096
 
        # that can do wonky stuff here, and that only
1097
 
        # happens for creating checkouts, which cannot be
1098
 
        # done on this format anyway. So - acceptable wart.
1099
 
        if hardlink:
1100
 
            warning("can't support hardlinked working trees in %r"
1101
 
                % (self,))
1102
 
        try:
1103
 
            result = self.open_workingtree(recommend_upgrade=False)
1104
 
        except errors.NoSuchFile:
1105
 
            result = self._init_workingtree()
1106
 
        if revision_id is not None:
1107
 
            if revision_id == _mod_revision.NULL_REVISION:
1108
 
                result.set_parent_ids([])
1109
 
            else:
1110
 
                result.set_parent_ids([revision_id])
1111
 
        return result
1112
 
 
1113
 
    def _init_workingtree(self):
1114
 
        from bzrlib.workingtree_2 import WorkingTreeFormat2
1115
 
        try:
1116
 
            return WorkingTreeFormat2().initialize(self)
1117
 
        except errors.NotLocalUrl:
1118
 
            # Even though we can't access the working tree, we need to
1119
 
            # create its control files.
1120
 
            return WorkingTreeFormat2()._stub_initialize_on_transport(
1121
 
                self.transport, self._control_files._file_mode)
1122
 
 
1123
 
    def destroy_workingtree(self):
1124
 
        """See BzrDir.destroy_workingtree."""
1125
 
        raise errors.UnsupportedOperation(self.destroy_workingtree, self)
1126
 
 
1127
 
    def destroy_workingtree_metadata(self):
1128
 
        """See BzrDir.destroy_workingtree_metadata."""
1129
 
        raise errors.UnsupportedOperation(self.destroy_workingtree_metadata,
1130
 
                                          self)
1131
 
 
1132
 
    def get_branch_transport(self, branch_format, name=None):
1133
 
        """See BzrDir.get_branch_transport()."""
1134
 
        if name is not None:
1135
 
            raise errors.NoColocatedBranchSupport(self)
1136
 
        if branch_format is None:
1137
 
            return self.transport
1138
 
        try:
1139
 
            branch_format.get_format_string()
1140
 
        except NotImplementedError:
1141
 
            return self.transport
1142
 
        raise errors.IncompatibleFormat(branch_format, self._format)
1143
 
 
1144
 
    def get_repository_transport(self, repository_format):
1145
 
        """See BzrDir.get_repository_transport()."""
1146
 
        if repository_format is None:
1147
 
            return self.transport
1148
 
        try:
1149
 
            repository_format.get_format_string()
1150
 
        except NotImplementedError:
1151
 
            return self.transport
1152
 
        raise errors.IncompatibleFormat(repository_format, self._format)
1153
 
 
1154
 
    def get_workingtree_transport(self, workingtree_format):
1155
 
        """See BzrDir.get_workingtree_transport()."""
1156
 
        if workingtree_format is None:
1157
 
            return self.transport
1158
 
        try:
1159
 
            workingtree_format.get_format_string()
1160
 
        except NotImplementedError:
1161
 
            return self.transport
1162
 
        raise errors.IncompatibleFormat(workingtree_format, self._format)
1163
 
 
1164
 
    def needs_format_conversion(self, format):
1165
 
        """See BzrDir.needs_format_conversion()."""
1166
 
        return not isinstance(self._format, format.__class__)
1167
 
 
1168
 
    def open_branch(self, name=None, unsupported=False,
1169
 
                    ignore_fallbacks=False):
1170
 
        """See BzrDir.open_branch."""
1171
 
        from bzrlib.branch_weave import BzrBranchFormat4
1172
 
        format = BzrBranchFormat4()
1173
 
        self._check_supported(format, unsupported)
1174
 
        return format.open(self, name, _found=True)
1175
 
 
1176
 
    def sprout(self, url, revision_id=None, force_new_repo=False,
1177
 
               possible_transports=None, accelerator_tree=None,
1178
 
               hardlink=False, stacked=False, create_tree_if_local=True,
1179
 
               source_branch=None):
1180
 
        """See BzrDir.sprout()."""
1181
 
        if source_branch is not None:
1182
 
            my_branch = self.open_branch()
1183
 
            if source_branch.base != my_branch.base:
1184
 
                raise AssertionError(
1185
 
                    "source branch %r is not within %r with branch %r" %
1186
 
                    (source_branch, self, my_branch))
1187
 
        if stacked:
1188
 
            raise errors.UnstackableBranchFormat(
1189
 
                self._format, self.root_transport.base)
1190
 
        if not create_tree_if_local:
1191
 
            raise errors.MustHaveWorkingTree(
1192
 
                self._format, self.root_transport.base)
1193
 
        from bzrlib.workingtree_2 import WorkingTreeFormat2
1194
 
        self._make_tail(url)
1195
 
        result = self._format._initialize_for_clone(url)
1196
 
        try:
1197
 
            self.open_repository().clone(result, revision_id=revision_id)
1198
 
        except errors.NoRepositoryPresent:
1199
 
            pass
1200
 
        try:
1201
 
            self.open_branch().sprout(result, revision_id=revision_id)
1202
 
        except errors.NotBranchError:
1203
 
            pass
1204
 
 
1205
 
        # we always want a working tree
1206
 
        WorkingTreeFormat2().initialize(result,
1207
 
                                        accelerator_tree=accelerator_tree,
1208
 
                                        hardlink=hardlink)
1209
 
        return result
1210
 
 
1211
 
 
1212
 
class BzrDir4(BzrDirPreSplitOut):
1213
 
    """A .bzr version 4 control object.
1214
 
 
1215
 
    This is a deprecated format and may be removed after sept 2006.
1216
 
    """
1217
 
 
1218
 
    def create_repository(self, shared=False):
1219
 
        """See BzrDir.create_repository."""
1220
 
        return self._format.repository_format.initialize(self, shared)
1221
 
 
1222
 
    def needs_format_conversion(self, format):
1223
 
        """Format 4 dirs are always in need of conversion."""
1224
 
        return True
1225
 
 
1226
 
    def open_repository(self):
1227
 
        """See BzrDir.open_repository."""
1228
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat4
1229
 
        return RepositoryFormat4().open(self, _found=True)
1230
 
 
1231
 
 
1232
 
class BzrDir5(BzrDirPreSplitOut):
1233
 
    """A .bzr version 5 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 RepositoryFormat5
1245
 
        return RepositoryFormat5().open(self, _found=True)
1246
 
 
1247
 
    def open_workingtree(self, _unsupported=False,
1248
 
            recommend_upgrade=True):
1249
 
        """See BzrDir.create_workingtree."""
1250
 
        from bzrlib.workingtree_2 import WorkingTreeFormat2
1251
 
        wt_format = WorkingTreeFormat2()
1252
 
        # we don't warn here about upgrades; that ought to be handled for the
1253
 
        # bzrdir as a whole
1254
 
        return wt_format.open(self, _found=True)
1255
 
 
1256
 
 
1257
 
class BzrDir6(BzrDirPreSplitOut):
1258
 
    """A .bzr version 6 control object.
1259
 
 
1260
 
    This is a deprecated format and may be removed after sept 2006.
1261
 
    """
1262
 
 
1263
 
    def has_workingtree(self):
1264
 
        """See BzrDir.has_workingtree."""
1265
 
        return True
1266
 
    
1267
 
    def open_repository(self):
1268
 
        """See BzrDir.open_repository."""
1269
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat6
1270
 
        return RepositoryFormat6().open(self, _found=True)
1271
 
 
1272
 
    def open_workingtree(self, _unsupported=False,
1273
 
        recommend_upgrade=True):
1274
 
        """See BzrDir.create_workingtree."""
1275
 
        # we don't warn here about upgrades; that ought to be handled for the
1276
 
        # bzrdir as a whole
1277
 
        from bzrlib.workingtree_2 import WorkingTreeFormat2
1278
 
        return WorkingTreeFormat2().open(self, _found=True)
1279
 
 
1280
 
 
1281
1005
class BzrDirMeta1(BzrDir):
1282
1006
    """A .bzr meta version 1 control object.
1283
1007
 
1473
1197
class BzrProber(controldir.Prober):
1474
1198
    """Prober for formats that use a .bzr/ control directory."""
1475
1199
 
1476
 
    _formats = {}
 
1200
    formats = registry.FormatRegistry(controldir.network_format_registry)
1477
1201
    """The known .bzr formats."""
1478
1202
 
1479
1203
    @classmethod
 
1204
    @deprecated_method(deprecated_in((2, 4, 0)))
1480
1205
    def register_bzrdir_format(klass, format):
1481
 
        klass._formats[format.get_format_string()] = format
 
1206
        klass.formats.register(format.get_format_string(), format)
1482
1207
 
1483
1208
    @classmethod
 
1209
    @deprecated_method(deprecated_in((2, 4, 0)))
1484
1210
    def unregister_bzrdir_format(klass, format):
1485
 
        del klass._formats[format.get_format_string()]
 
1211
        klass.formats.remove(format.get_format_string())
1486
1212
 
1487
1213
    @classmethod
1488
1214
    def probe_transport(klass, transport):
1492
1218
        except errors.NoSuchFile:
1493
1219
            raise errors.NotBranchError(path=transport.base)
1494
1220
        try:
1495
 
            return klass._formats[format_string]
 
1221
            return klass.formats.get(format_string)
1496
1222
        except KeyError:
1497
1223
            raise errors.UnknownFormatError(format=format_string, kind='bzrdir')
1498
1224
 
 
1225
    @classmethod
 
1226
    def known_formats(cls):
 
1227
        result = set()
 
1228
        for name, format in cls.formats.iteritems():
 
1229
            if callable(format):
 
1230
                format = format()
 
1231
            result.add(format)
 
1232
        return result
 
1233
 
1499
1234
 
1500
1235
controldir.ControlDirFormat.register_prober(BzrProber)
1501
1236
 
1525
1260
                    raise errors.NotBranchError(path=transport.base)
1526
1261
                if server_version != '2':
1527
1262
                    raise errors.NotBranchError(path=transport.base)
 
1263
            from bzrlib.remote import RemoteBzrDirFormat
1528
1264
            return RemoteBzrDirFormat()
1529
1265
 
 
1266
    @classmethod
 
1267
    def known_formats(cls):
 
1268
        from bzrlib.remote import RemoteBzrDirFormat
 
1269
        return set([RemoteBzrDirFormat()])
 
1270
 
1530
1271
 
1531
1272
class BzrDirFormat(controldir.ControlDirFormat):
1532
1273
    """ControlDirFormat base class for .bzr/ directories.
1545
1286
    # _lock_class must be set in subclasses to the lock type, typ.
1546
1287
    # TransportLock or LockDir
1547
1288
 
1548
 
    def get_format_string(self):
 
1289
    @classmethod
 
1290
    def get_format_string(cls):
1549
1291
        """Return the ASCII format string that identifies this format."""
1550
1292
        raise NotImplementedError(self.get_format_string)
1551
1293
 
1563
1305
            # metadir1
1564
1306
            if type(self) != BzrDirMetaFormat1:
1565
1307
                return self._initialize_on_transport_vfs(transport)
 
1308
            from bzrlib.remote import RemoteBzrDirFormat
1566
1309
            remote_format = RemoteBzrDirFormat()
1567
1310
            self._supply_sub_formats_to(remote_format)
1568
1311
            return remote_format.initialize_on_transport(transport)
1606
1349
            except errors.NoSmartMedium:
1607
1350
                pass
1608
1351
            else:
 
1352
                from bzrlib.remote import RemoteBzrDirFormat
1609
1353
                # TODO: lookup the local format from a server hint.
1610
1354
                remote_dir_format = RemoteBzrDirFormat()
1611
1355
                remote_dir_format._network_name = self.network_name()
1726
1470
        """
1727
1471
        raise NotImplementedError(self._open)
1728
1472
 
1729
 
    @classmethod
1730
 
    def register_format(klass, format):
1731
 
        BzrProber.register_bzrdir_format(format)
1732
 
        # bzr native formats have a network name of their format string.
1733
 
        controldir.network_format_registry.register(format.get_format_string(), format.__class__)
1734
 
        controldir.ControlDirFormat.register_format(format)
1735
 
 
1736
1473
    def _supply_sub_formats_to(self, other_format):
1737
1474
        """Give other_format the same values for sub formats as this has.
1738
1475
 
1745
1482
        :return: None.
1746
1483
        """
1747
1484
 
1748
 
    @classmethod
1749
 
    def unregister_format(klass, format):
1750
 
        BzrProber.unregister_bzrdir_format(format)
1751
 
        controldir.ControlDirFormat.unregister_format(format)
1752
 
        controldir.network_format_registry.remove(format.get_format_string())
1753
 
 
1754
 
 
1755
 
class BzrDirFormat4(BzrDirFormat):
1756
 
    """Bzr dir format 4.
1757
 
 
1758
 
    This format is a combined format for working tree, branch and repository.
1759
 
    It has:
1760
 
     - Format 1 working trees [always]
1761
 
     - Format 4 branches [always]
1762
 
     - Format 4 repositories [always]
1763
 
 
1764
 
    This format is deprecated: it indexes texts using a text it which is
1765
 
    removed in format 5; write support for this format has been removed.
1766
 
    """
1767
 
 
1768
 
    _lock_class = lockable_files.TransportLock
1769
 
 
1770
 
    fixed_components = True
1771
 
 
1772
 
    def get_format_string(self):
1773
 
        """See BzrDirFormat.get_format_string()."""
1774
 
        return "Bazaar-NG branch, format 0.0.4\n"
1775
 
 
1776
 
    def get_format_description(self):
1777
 
        """See BzrDirFormat.get_format_description()."""
1778
 
        return "All-in-one format 4"
1779
 
 
1780
 
    def get_converter(self, format=None):
1781
 
        """See BzrDirFormat.get_converter()."""
1782
 
        # there is one and only one upgrade path here.
1783
 
        return ConvertBzrDir4To5()
1784
 
 
1785
 
    def initialize_on_transport(self, transport):
1786
 
        """Format 4 branches cannot be created."""
1787
 
        raise errors.UninitializableFormat(self)
1788
 
 
1789
 
    def is_supported(self):
1790
 
        """Format 4 is not supported.
1791
 
 
1792
 
        It is not supported because the model changed from 4 to 5 and the
1793
 
        conversion logic is expensive - so doing it on the fly was not
1794
 
        feasible.
1795
 
        """
1796
 
        return False
1797
 
 
1798
 
    def network_name(self):
1799
 
        return self.get_format_string()
1800
 
 
1801
 
    def _open(self, transport):
1802
 
        """See BzrDirFormat._open."""
1803
 
        return BzrDir4(transport, self)
1804
 
 
1805
 
    def __return_repository_format(self):
1806
 
        """Circular import protection."""
1807
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat4
1808
 
        return RepositoryFormat4()
1809
 
    repository_format = property(__return_repository_format)
1810
 
 
1811
 
 
1812
 
class BzrDirFormatAllInOne(BzrDirFormat):
1813
 
    """Common class for formats before meta-dirs."""
1814
 
 
1815
 
    fixed_components = True
1816
 
 
1817
 
    def initialize_on_transport_ex(self, transport, use_existing_dir=False,
1818
 
        create_prefix=False, force_new_repo=False, stacked_on=None,
1819
 
        stack_on_pwd=None, repo_format_name=None, make_working_trees=None,
1820
 
        shared_repo=False):
1821
 
        """See BzrDirFormat.initialize_on_transport_ex."""
1822
 
        require_stacking = (stacked_on is not None)
1823
 
        # Format 5 cannot stack, but we've been asked to - actually init
1824
 
        # a Meta1Dir
1825
 
        if require_stacking:
1826
 
            format = BzrDirMetaFormat1()
1827
 
            return format.initialize_on_transport_ex(transport,
1828
 
                use_existing_dir=use_existing_dir, create_prefix=create_prefix,
1829
 
                force_new_repo=force_new_repo, stacked_on=stacked_on,
1830
 
                stack_on_pwd=stack_on_pwd, repo_format_name=repo_format_name,
1831
 
                make_working_trees=make_working_trees, shared_repo=shared_repo)
1832
 
        return BzrDirFormat.initialize_on_transport_ex(self, transport,
1833
 
            use_existing_dir=use_existing_dir, create_prefix=create_prefix,
1834
 
            force_new_repo=force_new_repo, stacked_on=stacked_on,
1835
 
            stack_on_pwd=stack_on_pwd, repo_format_name=repo_format_name,
1836
 
            make_working_trees=make_working_trees, shared_repo=shared_repo)
1837
 
 
1838
 
 
1839
 
class BzrDirFormat5(BzrDirFormatAllInOne):
1840
 
    """Bzr control format 5.
1841
 
 
1842
 
    This format is a combined format for working tree, branch and repository.
1843
 
    It has:
1844
 
     - Format 2 working trees [always]
1845
 
     - Format 4 branches [always]
1846
 
     - Format 5 repositories [always]
1847
 
       Unhashed stores in the repository.
1848
 
    """
1849
 
 
1850
 
    _lock_class = lockable_files.TransportLock
1851
 
 
1852
 
    def get_format_string(self):
1853
 
        """See BzrDirFormat.get_format_string()."""
1854
 
        return "Bazaar-NG branch, format 5\n"
1855
 
 
1856
 
    def get_branch_format(self):
1857
 
        from bzrlib import branch_weave
1858
 
        return branch_weave.BzrBranchFormat4()
1859
 
 
1860
 
    def get_format_description(self):
1861
 
        """See BzrDirFormat.get_format_description()."""
1862
 
        return "All-in-one format 5"
1863
 
 
1864
 
    def get_converter(self, format=None):
1865
 
        """See BzrDirFormat.get_converter()."""
1866
 
        # there is one and only one upgrade path here.
1867
 
        return ConvertBzrDir5To6()
1868
 
 
1869
 
    def _initialize_for_clone(self, url):
1870
 
        return self.initialize_on_transport(
1871
 
            _mod_transport.get_transport(url), _cloning=True)
1872
 
 
1873
 
    def initialize_on_transport(self, transport, _cloning=False):
1874
 
        """Format 5 dirs always have working tree, branch and repository.
1875
 
 
1876
 
        Except when they are being cloned.
1877
 
        """
1878
 
        from bzrlib.branch_weave import BzrBranchFormat4
1879
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat5
1880
 
        result = (super(BzrDirFormat5, self).initialize_on_transport(transport))
1881
 
        RepositoryFormat5().initialize(result, _internal=True)
1882
 
        if not _cloning:
1883
 
            branch = BzrBranchFormat4().initialize(result)
1884
 
            result._init_workingtree()
1885
 
        return result
1886
 
 
1887
 
    def network_name(self):
1888
 
        return self.get_format_string()
1889
 
 
1890
 
    def _open(self, transport):
1891
 
        """See BzrDirFormat._open."""
1892
 
        return BzrDir5(transport, self)
1893
 
 
1894
 
    def __return_repository_format(self):
1895
 
        """Circular import protection."""
1896
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat5
1897
 
        return RepositoryFormat5()
1898
 
    repository_format = property(__return_repository_format)
1899
 
 
1900
 
 
1901
 
class BzrDirFormat6(BzrDirFormatAllInOne):
1902
 
    """Bzr control format 6.
1903
 
 
1904
 
    This format is a combined format for working tree, branch and repository.
1905
 
    It has:
1906
 
     - Format 2 working trees [always]
1907
 
     - Format 4 branches [always]
1908
 
     - Format 6 repositories [always]
1909
 
    """
1910
 
 
1911
 
    _lock_class = lockable_files.TransportLock
1912
 
 
1913
 
    def get_format_string(self):
1914
 
        """See BzrDirFormat.get_format_string()."""
1915
 
        return "Bazaar-NG branch, format 6\n"
1916
 
 
1917
 
    def get_format_description(self):
1918
 
        """See BzrDirFormat.get_format_description()."""
1919
 
        return "All-in-one format 6"
1920
 
 
1921
 
    def get_branch_format(self):
1922
 
        from bzrlib import branch_weave
1923
 
        return branch_weave.BzrBranchFormat4()
1924
 
 
1925
 
    def get_converter(self, format=None):
1926
 
        """See BzrDirFormat.get_converter()."""
1927
 
        # there is one and only one upgrade path here.
1928
 
        return ConvertBzrDir6ToMeta()
1929
 
 
1930
 
    def _initialize_for_clone(self, url):
1931
 
        return self.initialize_on_transport(
1932
 
            _mod_transport.get_transport(url), _cloning=True)
1933
 
 
1934
 
    def initialize_on_transport(self, transport, _cloning=False):
1935
 
        """Format 6 dirs always have working tree, branch and repository.
1936
 
 
1937
 
        Except when they are being cloned.
1938
 
        """
1939
 
        from bzrlib.branch_weave import BzrBranchFormat4
1940
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat6
1941
 
        result = super(BzrDirFormat6, self).initialize_on_transport(transport)
1942
 
        RepositoryFormat6().initialize(result, _internal=True)
1943
 
        if not _cloning:
1944
 
            branch = BzrBranchFormat4().initialize(result)
1945
 
            result._init_workingtree()
1946
 
        return result
1947
 
 
1948
 
    def network_name(self):
1949
 
        return self.get_format_string()
1950
 
 
1951
 
    def _open(self, transport):
1952
 
        """See BzrDirFormat._open."""
1953
 
        return BzrDir6(transport, self)
1954
 
 
1955
 
    def __return_repository_format(self):
1956
 
        """Circular import protection."""
1957
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat6
1958
 
        return RepositoryFormat6()
1959
 
    repository_format = property(__return_repository_format)
1960
 
 
1961
1485
 
1962
1486
class BzrDirMetaFormat1(BzrDirFormat):
1963
1487
    """Bzr meta control format 1
2102
1626
            raise NotImplementedError(self.get_converter)
2103
1627
        return ConvertMetaToMeta(format)
2104
1628
 
2105
 
    def get_format_string(self):
 
1629
    @classmethod
 
1630
    def get_format_string(cls):
2106
1631
        """See BzrDirFormat.get_format_string()."""
2107
1632
        return "Bazaar-NG meta directory, format 1\n"
2108
1633
 
2170
1695
 
2171
1696
 
2172
1697
# Register bzr formats
2173
 
BzrDirFormat.register_format(BzrDirFormat4())
2174
 
BzrDirFormat.register_format(BzrDirFormat5())
2175
 
BzrDirFormat.register_format(BzrDirFormat6())
2176
 
__default_format = BzrDirMetaFormat1()
2177
 
BzrDirFormat.register_format(__default_format)
2178
 
controldir.ControlDirFormat._default_format = __default_format
2179
 
 
2180
 
 
2181
 
class ConvertBzrDir4To5(controldir.Converter):
2182
 
    """Converts format 4 bzr dirs to format 5."""
2183
 
 
2184
 
    def __init__(self):
2185
 
        super(ConvertBzrDir4To5, self).__init__()
2186
 
        self.converted_revs = set()
2187
 
        self.absent_revisions = set()
2188
 
        self.text_count = 0
2189
 
        self.revisions = {}
2190
 
 
2191
 
    def convert(self, to_convert, pb):
2192
 
        """See Converter.convert()."""
2193
 
        self.bzrdir = to_convert
2194
 
        if pb is not None:
2195
 
            warnings.warn("pb parameter to convert() is deprecated")
2196
 
        self.pb = ui.ui_factory.nested_progress_bar()
2197
 
        try:
2198
 
            ui.ui_factory.note('starting upgrade from format 4 to 5')
2199
 
            if isinstance(self.bzrdir.transport, local.LocalTransport):
2200
 
                self.bzrdir.get_workingtree_transport(None).delete('stat-cache')
2201
 
            self._convert_to_weaves()
2202
 
            return BzrDir.open(self.bzrdir.user_url)
2203
 
        finally:
2204
 
            self.pb.finished()
2205
 
 
2206
 
    def _convert_to_weaves(self):
2207
 
        ui.ui_factory.note('note: upgrade may be faster if all store files are ungzipped first')
2208
 
        try:
2209
 
            # TODO permissions
2210
 
            stat = self.bzrdir.transport.stat('weaves')
2211
 
            if not S_ISDIR(stat.st_mode):
2212
 
                self.bzrdir.transport.delete('weaves')
2213
 
                self.bzrdir.transport.mkdir('weaves')
2214
 
        except errors.NoSuchFile:
2215
 
            self.bzrdir.transport.mkdir('weaves')
2216
 
        # deliberately not a WeaveFile as we want to build it up slowly.
2217
 
        self.inv_weave = Weave('inventory')
2218
 
        # holds in-memory weaves for all files
2219
 
        self.text_weaves = {}
2220
 
        self.bzrdir.transport.delete('branch-format')
2221
 
        self.branch = self.bzrdir.open_branch()
2222
 
        self._convert_working_inv()
2223
 
        rev_history = self.branch.revision_history()
2224
 
        # to_read is a stack holding the revisions we still need to process;
2225
 
        # appending to it adds new highest-priority revisions
2226
 
        self.known_revisions = set(rev_history)
2227
 
        self.to_read = rev_history[-1:]
2228
 
        while self.to_read:
2229
 
            rev_id = self.to_read.pop()
2230
 
            if (rev_id not in self.revisions
2231
 
                and rev_id not in self.absent_revisions):
2232
 
                self._load_one_rev(rev_id)
2233
 
        self.pb.clear()
2234
 
        to_import = self._make_order()
2235
 
        for i, rev_id in enumerate(to_import):
2236
 
            self.pb.update('converting revision', i, len(to_import))
2237
 
            self._convert_one_rev(rev_id)
2238
 
        self.pb.clear()
2239
 
        self._write_all_weaves()
2240
 
        self._write_all_revs()
2241
 
        ui.ui_factory.note('upgraded to weaves:')
2242
 
        ui.ui_factory.note('  %6d revisions and inventories' % len(self.revisions))
2243
 
        ui.ui_factory.note('  %6d revisions not present' % len(self.absent_revisions))
2244
 
        ui.ui_factory.note('  %6d texts' % self.text_count)
2245
 
        self._cleanup_spare_files_after_format4()
2246
 
        self.branch._transport.put_bytes(
2247
 
            'branch-format',
2248
 
            BzrDirFormat5().get_format_string(),
2249
 
            mode=self.bzrdir._get_file_mode())
2250
 
 
2251
 
    def _cleanup_spare_files_after_format4(self):
2252
 
        # FIXME working tree upgrade foo.
2253
 
        for n in 'merged-patches', 'pending-merged-patches':
2254
 
            try:
2255
 
                ## assert os.path.getsize(p) == 0
2256
 
                self.bzrdir.transport.delete(n)
2257
 
            except errors.NoSuchFile:
2258
 
                pass
2259
 
        self.bzrdir.transport.delete_tree('inventory-store')
2260
 
        self.bzrdir.transport.delete_tree('text-store')
2261
 
 
2262
 
    def _convert_working_inv(self):
2263
 
        inv = xml4.serializer_v4.read_inventory(
2264
 
                self.branch._transport.get('inventory'))
2265
 
        new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv, working=True)
2266
 
        self.branch._transport.put_bytes('inventory', new_inv_xml,
2267
 
            mode=self.bzrdir._get_file_mode())
2268
 
 
2269
 
    def _write_all_weaves(self):
2270
 
        controlweaves = VersionedFileStore(self.bzrdir.transport, prefixed=False,
2271
 
                                           versionedfile_class=WeaveFile)
2272
 
        weave_transport = self.bzrdir.transport.clone('weaves')
2273
 
        weaves = VersionedFileStore(weave_transport, prefixed=False,
2274
 
                            versionedfile_class=WeaveFile)
2275
 
        transaction = WriteTransaction()
2276
 
 
2277
 
        try:
2278
 
            i = 0
2279
 
            for file_id, file_weave in self.text_weaves.items():
2280
 
                self.pb.update('writing weave', i, len(self.text_weaves))
2281
 
                weaves._put_weave(file_id, file_weave, transaction)
2282
 
                i += 1
2283
 
            self.pb.update('inventory', 0, 1)
2284
 
            controlweaves._put_weave('inventory', self.inv_weave, transaction)
2285
 
            self.pb.update('inventory', 1, 1)
2286
 
        finally:
2287
 
            self.pb.clear()
2288
 
 
2289
 
    def _write_all_revs(self):
2290
 
        """Write all revisions out in new form."""
2291
 
        self.bzrdir.transport.delete_tree('revision-store')
2292
 
        self.bzrdir.transport.mkdir('revision-store')
2293
 
        revision_transport = self.bzrdir.transport.clone('revision-store')
2294
 
        # TODO permissions
2295
 
        from bzrlib.xml5 import serializer_v5
2296
 
        from bzrlib.repofmt.weaverepo import RevisionTextStore
2297
 
        revision_store = RevisionTextStore(revision_transport,
2298
 
            serializer_v5, False, versionedfile.PrefixMapper(),
2299
 
            lambda:True, lambda:True)
2300
 
        try:
2301
 
            for i, rev_id in enumerate(self.converted_revs):
2302
 
                self.pb.update('write revision', i, len(self.converted_revs))
2303
 
                text = serializer_v5.write_revision_to_string(
2304
 
                    self.revisions[rev_id])
2305
 
                key = (rev_id,)
2306
 
                revision_store.add_lines(key, None, osutils.split_lines(text))
2307
 
        finally:
2308
 
            self.pb.clear()
2309
 
 
2310
 
    def _load_one_rev(self, rev_id):
2311
 
        """Load a revision object into memory.
2312
 
 
2313
 
        Any parents not either loaded or abandoned get queued to be
2314
 
        loaded."""
2315
 
        self.pb.update('loading revision',
2316
 
                       len(self.revisions),
2317
 
                       len(self.known_revisions))
2318
 
        if not self.branch.repository.has_revision(rev_id):
2319
 
            self.pb.clear()
2320
 
            ui.ui_factory.note('revision {%s} not present in branch; '
2321
 
                         'will be converted as a ghost' %
2322
 
                         rev_id)
2323
 
            self.absent_revisions.add(rev_id)
2324
 
        else:
2325
 
            rev = self.branch.repository.get_revision(rev_id)
2326
 
            for parent_id in rev.parent_ids:
2327
 
                self.known_revisions.add(parent_id)
2328
 
                self.to_read.append(parent_id)
2329
 
            self.revisions[rev_id] = rev
2330
 
 
2331
 
    def _load_old_inventory(self, rev_id):
2332
 
        f = self.branch.repository.inventory_store.get(rev_id)
2333
 
        try:
2334
 
            old_inv_xml = f.read()
2335
 
        finally:
2336
 
            f.close()
2337
 
        inv = xml4.serializer_v4.read_inventory_from_string(old_inv_xml)
2338
 
        inv.revision_id = rev_id
2339
 
        rev = self.revisions[rev_id]
2340
 
        return inv
2341
 
 
2342
 
    def _load_updated_inventory(self, rev_id):
2343
 
        inv_xml = self.inv_weave.get_text(rev_id)
2344
 
        inv = xml5.serializer_v5.read_inventory_from_string(inv_xml, rev_id)
2345
 
        return inv
2346
 
 
2347
 
    def _convert_one_rev(self, rev_id):
2348
 
        """Convert revision and all referenced objects to new format."""
2349
 
        rev = self.revisions[rev_id]
2350
 
        inv = self._load_old_inventory(rev_id)
2351
 
        present_parents = [p for p in rev.parent_ids
2352
 
                           if p not in self.absent_revisions]
2353
 
        self._convert_revision_contents(rev, inv, present_parents)
2354
 
        self._store_new_inv(rev, inv, present_parents)
2355
 
        self.converted_revs.add(rev_id)
2356
 
 
2357
 
    def _store_new_inv(self, rev, inv, present_parents):
2358
 
        new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
2359
 
        new_inv_sha1 = osutils.sha_string(new_inv_xml)
2360
 
        self.inv_weave.add_lines(rev.revision_id,
2361
 
                                 present_parents,
2362
 
                                 new_inv_xml.splitlines(True))
2363
 
        rev.inventory_sha1 = new_inv_sha1
2364
 
 
2365
 
    def _convert_revision_contents(self, rev, inv, present_parents):
2366
 
        """Convert all the files within a revision.
2367
 
 
2368
 
        Also upgrade the inventory to refer to the text revision ids."""
2369
 
        rev_id = rev.revision_id
2370
 
        mutter('converting texts of revision {%s}',
2371
 
               rev_id)
2372
 
        parent_invs = map(self._load_updated_inventory, present_parents)
2373
 
        entries = inv.iter_entries()
2374
 
        entries.next()
2375
 
        for path, ie in entries:
2376
 
            self._convert_file_version(rev, ie, parent_invs)
2377
 
 
2378
 
    def _convert_file_version(self, rev, ie, parent_invs):
2379
 
        """Convert one version of one file.
2380
 
 
2381
 
        The file needs to be added into the weave if it is a merge
2382
 
        of >=2 parents or if it's changed from its parent.
2383
 
        """
2384
 
        file_id = ie.file_id
2385
 
        rev_id = rev.revision_id
2386
 
        w = self.text_weaves.get(file_id)
2387
 
        if w is None:
2388
 
            w = Weave(file_id)
2389
 
            self.text_weaves[file_id] = w
2390
 
        text_changed = False
2391
 
        parent_candiate_entries = ie.parent_candidates(parent_invs)
2392
 
        heads = graph.Graph(self).heads(parent_candiate_entries.keys())
2393
 
        # XXX: Note that this is unordered - and this is tolerable because
2394
 
        # the previous code was also unordered.
2395
 
        previous_entries = dict((head, parent_candiate_entries[head]) for head
2396
 
            in heads)
2397
 
        self.snapshot_ie(previous_entries, ie, w, rev_id)
2398
 
 
2399
 
    def get_parent_map(self, revision_ids):
2400
 
        """See graph.StackedParentsProvider.get_parent_map"""
2401
 
        return dict((revision_id, self.revisions[revision_id])
2402
 
                    for revision_id in revision_ids
2403
 
                     if revision_id in self.revisions)
2404
 
 
2405
 
    def snapshot_ie(self, previous_revisions, ie, w, rev_id):
2406
 
        # TODO: convert this logic, which is ~= snapshot to
2407
 
        # a call to:. This needs the path figured out. rather than a work_tree
2408
 
        # a v4 revision_tree can be given, or something that looks enough like
2409
 
        # one to give the file content to the entry if it needs it.
2410
 
        # and we need something that looks like a weave store for snapshot to
2411
 
        # save against.
2412
 
        #ie.snapshot(rev, PATH, previous_revisions, REVISION_TREE, InMemoryWeaveStore(self.text_weaves))
2413
 
        if len(previous_revisions) == 1:
2414
 
            previous_ie = previous_revisions.values()[0]
2415
 
            if ie._unchanged(previous_ie):
2416
 
                ie.revision = previous_ie.revision
2417
 
                return
2418
 
        if ie.has_text():
2419
 
            f = self.branch.repository._text_store.get(ie.text_id)
2420
 
            try:
2421
 
                file_lines = f.readlines()
2422
 
            finally:
2423
 
                f.close()
2424
 
            w.add_lines(rev_id, previous_revisions, file_lines)
2425
 
            self.text_count += 1
2426
 
        else:
2427
 
            w.add_lines(rev_id, previous_revisions, [])
2428
 
        ie.revision = rev_id
2429
 
 
2430
 
    def _make_order(self):
2431
 
        """Return a suitable order for importing revisions.
2432
 
 
2433
 
        The order must be such that an revision is imported after all
2434
 
        its (present) parents.
2435
 
        """
2436
 
        todo = set(self.revisions.keys())
2437
 
        done = self.absent_revisions.copy()
2438
 
        order = []
2439
 
        while todo:
2440
 
            # scan through looking for a revision whose parents
2441
 
            # are all done
2442
 
            for rev_id in sorted(list(todo)):
2443
 
                rev = self.revisions[rev_id]
2444
 
                parent_ids = set(rev.parent_ids)
2445
 
                if parent_ids.issubset(done):
2446
 
                    # can take this one now
2447
 
                    order.append(rev_id)
2448
 
                    todo.remove(rev_id)
2449
 
                    done.add(rev_id)
2450
 
        return order
2451
 
 
2452
 
 
2453
 
class ConvertBzrDir5To6(controldir.Converter):
2454
 
    """Converts format 5 bzr dirs to format 6."""
2455
 
 
2456
 
    def convert(self, to_convert, pb):
2457
 
        """See Converter.convert()."""
2458
 
        self.bzrdir = to_convert
2459
 
        pb = ui.ui_factory.nested_progress_bar()
2460
 
        try:
2461
 
            ui.ui_factory.note('starting upgrade from format 5 to 6')
2462
 
            self._convert_to_prefixed()
2463
 
            return BzrDir.open(self.bzrdir.user_url)
2464
 
        finally:
2465
 
            pb.finished()
2466
 
 
2467
 
    def _convert_to_prefixed(self):
2468
 
        from bzrlib.store import TransportStore
2469
 
        self.bzrdir.transport.delete('branch-format')
2470
 
        for store_name in ["weaves", "revision-store"]:
2471
 
            ui.ui_factory.note("adding prefixes to %s" % store_name)
2472
 
            store_transport = self.bzrdir.transport.clone(store_name)
2473
 
            store = TransportStore(store_transport, prefixed=True)
2474
 
            for urlfilename in store_transport.list_dir('.'):
2475
 
                filename = urlutils.unescape(urlfilename)
2476
 
                if (filename.endswith(".weave") or
2477
 
                    filename.endswith(".gz") or
2478
 
                    filename.endswith(".sig")):
2479
 
                    file_id, suffix = os.path.splitext(filename)
2480
 
                else:
2481
 
                    file_id = filename
2482
 
                    suffix = ''
2483
 
                new_name = store._mapper.map((file_id,)) + suffix
2484
 
                # FIXME keep track of the dirs made RBC 20060121
2485
 
                try:
2486
 
                    store_transport.move(filename, new_name)
2487
 
                except errors.NoSuchFile: # catches missing dirs strangely enough
2488
 
                    store_transport.mkdir(osutils.dirname(new_name))
2489
 
                    store_transport.move(filename, new_name)
2490
 
        self.bzrdir.transport.put_bytes(
2491
 
            'branch-format',
2492
 
            BzrDirFormat6().get_format_string(),
2493
 
            mode=self.bzrdir._get_file_mode())
2494
 
 
2495
 
 
2496
 
class ConvertBzrDir6ToMeta(controldir.Converter):
2497
 
    """Converts format 6 bzr dirs to metadirs."""
2498
 
 
2499
 
    def convert(self, to_convert, pb):
2500
 
        """See Converter.convert()."""
2501
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat7
2502
 
        from bzrlib.branch import BzrBranchFormat5
2503
 
        self.bzrdir = to_convert
2504
 
        self.pb = ui.ui_factory.nested_progress_bar()
2505
 
        self.count = 0
2506
 
        self.total = 20 # the steps we know about
2507
 
        self.garbage_inventories = []
2508
 
        self.dir_mode = self.bzrdir._get_dir_mode()
2509
 
        self.file_mode = self.bzrdir._get_file_mode()
2510
 
 
2511
 
        ui.ui_factory.note('starting upgrade from format 6 to metadir')
2512
 
        self.bzrdir.transport.put_bytes(
2513
 
                'branch-format',
2514
 
                "Converting to format 6",
2515
 
                mode=self.file_mode)
2516
 
        # its faster to move specific files around than to open and use the apis...
2517
 
        # first off, nuke ancestry.weave, it was never used.
2518
 
        try:
2519
 
            self.step('Removing ancestry.weave')
2520
 
            self.bzrdir.transport.delete('ancestry.weave')
2521
 
        except errors.NoSuchFile:
2522
 
            pass
2523
 
        # find out whats there
2524
 
        self.step('Finding branch files')
2525
 
        last_revision = self.bzrdir.open_branch().last_revision()
2526
 
        bzrcontents = self.bzrdir.transport.list_dir('.')
2527
 
        for name in bzrcontents:
2528
 
            if name.startswith('basis-inventory.'):
2529
 
                self.garbage_inventories.append(name)
2530
 
        # create new directories for repository, working tree and branch
2531
 
        repository_names = [('inventory.weave', True),
2532
 
                            ('revision-store', True),
2533
 
                            ('weaves', True)]
2534
 
        self.step('Upgrading repository  ')
2535
 
        self.bzrdir.transport.mkdir('repository', mode=self.dir_mode)
2536
 
        self.make_lock('repository')
2537
 
        # we hard code the formats here because we are converting into
2538
 
        # the meta format. The meta format upgrader can take this to a
2539
 
        # future format within each component.
2540
 
        self.put_format('repository', RepositoryFormat7())
2541
 
        for entry in repository_names:
2542
 
            self.move_entry('repository', entry)
2543
 
 
2544
 
        self.step('Upgrading branch      ')
2545
 
        self.bzrdir.transport.mkdir('branch', mode=self.dir_mode)
2546
 
        self.make_lock('branch')
2547
 
        self.put_format('branch', BzrBranchFormat5())
2548
 
        branch_files = [('revision-history', True),
2549
 
                        ('branch-name', True),
2550
 
                        ('parent', False)]
2551
 
        for entry in branch_files:
2552
 
            self.move_entry('branch', entry)
2553
 
 
2554
 
        checkout_files = [('pending-merges', True),
2555
 
                          ('inventory', True),
2556
 
                          ('stat-cache', False)]
2557
 
        # If a mandatory checkout file is not present, the branch does not have
2558
 
        # a functional checkout. Do not create a checkout in the converted
2559
 
        # branch.
2560
 
        for name, mandatory in checkout_files:
2561
 
            if mandatory and name not in bzrcontents:
2562
 
                has_checkout = False
2563
 
                break
2564
 
        else:
2565
 
            has_checkout = True
2566
 
        if not has_checkout:
2567
 
            ui.ui_factory.note('No working tree.')
2568
 
            # If some checkout files are there, we may as well get rid of them.
2569
 
            for name, mandatory in checkout_files:
2570
 
                if name in bzrcontents:
2571
 
                    self.bzrdir.transport.delete(name)
2572
 
        else:
2573
 
            from bzrlib.workingtree import WorkingTreeFormat3
2574
 
            self.step('Upgrading working tree')
2575
 
            self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
2576
 
            self.make_lock('checkout')
2577
 
            self.put_format(
2578
 
                'checkout', WorkingTreeFormat3())
2579
 
            self.bzrdir.transport.delete_multi(
2580
 
                self.garbage_inventories, self.pb)
2581
 
            for entry in checkout_files:
2582
 
                self.move_entry('checkout', entry)
2583
 
            if last_revision is not None:
2584
 
                self.bzrdir.transport.put_bytes(
2585
 
                    'checkout/last-revision', last_revision)
2586
 
        self.bzrdir.transport.put_bytes(
2587
 
            'branch-format',
2588
 
            BzrDirMetaFormat1().get_format_string(),
2589
 
            mode=self.file_mode)
2590
 
        self.pb.finished()
2591
 
        return BzrDir.open(self.bzrdir.user_url)
2592
 
 
2593
 
    def make_lock(self, name):
2594
 
        """Make a lock for the new control dir name."""
2595
 
        self.step('Make %s lock' % name)
2596
 
        ld = lockdir.LockDir(self.bzrdir.transport,
2597
 
                             '%s/lock' % name,
2598
 
                             file_modebits=self.file_mode,
2599
 
                             dir_modebits=self.dir_mode)
2600
 
        ld.create()
2601
 
 
2602
 
    def move_entry(self, new_dir, entry):
2603
 
        """Move then entry name into new_dir."""
2604
 
        name = entry[0]
2605
 
        mandatory = entry[1]
2606
 
        self.step('Moving %s' % name)
2607
 
        try:
2608
 
            self.bzrdir.transport.move(name, '%s/%s' % (new_dir, name))
2609
 
        except errors.NoSuchFile:
2610
 
            if mandatory:
2611
 
                raise
2612
 
 
2613
 
    def put_format(self, dirname, format):
2614
 
        self.bzrdir.transport.put_bytes('%s/format' % dirname,
2615
 
            format.get_format_string(),
2616
 
            self.file_mode)
 
1698
BzrProber.formats.register(BzrDirMetaFormat1.get_format_string(),
 
1699
    BzrDirMetaFormat1)
 
1700
controldir.ControlDirFormat._default_format = BzrDirMetaFormat1()
2617
1701
 
2618
1702
 
2619
1703
class ConvertMetaToMeta(controldir.Converter):
2695
1779
        return to_convert
2696
1780
 
2697
1781
 
2698
 
# This is not in remote.py because it's relatively small, and needs to be
2699
 
# registered. Putting it in remote.py creates a circular import problem.
2700
 
# we can make it a lazy object if the control formats is turned into something
2701
 
# like a registry.
2702
 
class RemoteBzrDirFormat(BzrDirMetaFormat1):
2703
 
    """Format representing bzrdirs accessed via a smart server"""
2704
 
 
2705
 
    supports_workingtrees = False
2706
 
 
2707
 
    def __init__(self):
2708
 
        BzrDirMetaFormat1.__init__(self)
2709
 
        # XXX: It's a bit ugly that the network name is here, because we'd
2710
 
        # like to believe that format objects are stateless or at least
2711
 
        # immutable,  However, we do at least avoid mutating the name after
2712
 
        # it's returned.  See <https://bugs.launchpad.net/bzr/+bug/504102>
2713
 
        self._network_name = None
2714
 
 
2715
 
    def __repr__(self):
2716
 
        return "%s(_network_name=%r)" % (self.__class__.__name__,
2717
 
            self._network_name)
2718
 
 
2719
 
    def get_format_description(self):
2720
 
        if self._network_name:
2721
 
            real_format = controldir.network_format_registry.get(self._network_name)
2722
 
            return 'Remote: ' + real_format.get_format_description()
2723
 
        return 'bzr remote bzrdir'
2724
 
 
2725
 
    def get_format_string(self):
2726
 
        raise NotImplementedError(self.get_format_string)
2727
 
 
2728
 
    def network_name(self):
2729
 
        if self._network_name:
2730
 
            return self._network_name
2731
 
        else:
2732
 
            raise AssertionError("No network name set.")
2733
 
 
2734
 
    def initialize_on_transport(self, transport):
2735
 
        try:
2736
 
            # hand off the request to the smart server
2737
 
            client_medium = transport.get_smart_medium()
2738
 
        except errors.NoSmartMedium:
2739
 
            # TODO: lookup the local format from a server hint.
2740
 
            local_dir_format = BzrDirMetaFormat1()
2741
 
            return local_dir_format.initialize_on_transport(transport)
2742
 
        client = _SmartClient(client_medium)
2743
 
        path = client.remote_path_from_transport(transport)
2744
 
        try:
2745
 
            response = client.call('BzrDirFormat.initialize', path)
2746
 
        except errors.ErrorFromSmartServer, err:
2747
 
            remote._translate_error(err, path=path)
2748
 
        if response[0] != 'ok':
2749
 
            raise errors.SmartProtocolError('unexpected response code %s' % (response,))
2750
 
        format = RemoteBzrDirFormat()
2751
 
        self._supply_sub_formats_to(format)
2752
 
        return remote.RemoteBzrDir(transport, format)
2753
 
 
2754
 
    def parse_NoneTrueFalse(self, arg):
2755
 
        if not arg:
2756
 
            return None
2757
 
        if arg == 'False':
2758
 
            return False
2759
 
        if arg == 'True':
2760
 
            return True
2761
 
        raise AssertionError("invalid arg %r" % arg)
2762
 
 
2763
 
    def _serialize_NoneTrueFalse(self, arg):
2764
 
        if arg is False:
2765
 
            return 'False'
2766
 
        if arg:
2767
 
            return 'True'
2768
 
        return ''
2769
 
 
2770
 
    def _serialize_NoneString(self, arg):
2771
 
        return arg or ''
2772
 
 
2773
 
    def initialize_on_transport_ex(self, transport, use_existing_dir=False,
2774
 
        create_prefix=False, force_new_repo=False, stacked_on=None,
2775
 
        stack_on_pwd=None, repo_format_name=None, make_working_trees=None,
2776
 
        shared_repo=False):
2777
 
        try:
2778
 
            # hand off the request to the smart server
2779
 
            client_medium = transport.get_smart_medium()
2780
 
        except errors.NoSmartMedium:
2781
 
            do_vfs = True
2782
 
        else:
2783
 
            # Decline to open it if the server doesn't support our required
2784
 
            # version (3) so that the VFS-based transport will do it.
2785
 
            if client_medium.should_probe():
2786
 
                try:
2787
 
                    server_version = client_medium.protocol_version()
2788
 
                    if server_version != '2':
2789
 
                        do_vfs = True
2790
 
                    else:
2791
 
                        do_vfs = False
2792
 
                except errors.SmartProtocolError:
2793
 
                    # Apparently there's no usable smart server there, even though
2794
 
                    # the medium supports the smart protocol.
2795
 
                    do_vfs = True
2796
 
            else:
2797
 
                do_vfs = False
2798
 
        if not do_vfs:
2799
 
            client = _SmartClient(client_medium)
2800
 
            path = client.remote_path_from_transport(transport)
2801
 
            if client_medium._is_remote_before((1, 16)):
2802
 
                do_vfs = True
2803
 
        if do_vfs:
2804
 
            # TODO: lookup the local format from a server hint.
2805
 
            local_dir_format = BzrDirMetaFormat1()
2806
 
            self._supply_sub_formats_to(local_dir_format)
2807
 
            return local_dir_format.initialize_on_transport_ex(transport,
2808
 
                use_existing_dir=use_existing_dir, create_prefix=create_prefix,
2809
 
                force_new_repo=force_new_repo, stacked_on=stacked_on,
2810
 
                stack_on_pwd=stack_on_pwd, repo_format_name=repo_format_name,
2811
 
                make_working_trees=make_working_trees, shared_repo=shared_repo,
2812
 
                vfs_only=True)
2813
 
        return self._initialize_on_transport_ex_rpc(client, path, transport,
2814
 
            use_existing_dir, create_prefix, force_new_repo, stacked_on,
2815
 
            stack_on_pwd, repo_format_name, make_working_trees, shared_repo)
2816
 
 
2817
 
    def _initialize_on_transport_ex_rpc(self, client, path, transport,
2818
 
        use_existing_dir, create_prefix, force_new_repo, stacked_on,
2819
 
        stack_on_pwd, repo_format_name, make_working_trees, shared_repo):
2820
 
        args = []
2821
 
        args.append(self._serialize_NoneTrueFalse(use_existing_dir))
2822
 
        args.append(self._serialize_NoneTrueFalse(create_prefix))
2823
 
        args.append(self._serialize_NoneTrueFalse(force_new_repo))
2824
 
        args.append(self._serialize_NoneString(stacked_on))
2825
 
        # stack_on_pwd is often/usually our transport
2826
 
        if stack_on_pwd:
2827
 
            try:
2828
 
                stack_on_pwd = transport.relpath(stack_on_pwd)
2829
 
                if not stack_on_pwd:
2830
 
                    stack_on_pwd = '.'
2831
 
            except errors.PathNotChild:
2832
 
                pass
2833
 
        args.append(self._serialize_NoneString(stack_on_pwd))
2834
 
        args.append(self._serialize_NoneString(repo_format_name))
2835
 
        args.append(self._serialize_NoneTrueFalse(make_working_trees))
2836
 
        args.append(self._serialize_NoneTrueFalse(shared_repo))
2837
 
        request_network_name = self._network_name or \
2838
 
            BzrDirFormat.get_default_format().network_name()
2839
 
        try:
2840
 
            response = client.call('BzrDirFormat.initialize_ex_1.16',
2841
 
                request_network_name, path, *args)
2842
 
        except errors.UnknownSmartMethod:
2843
 
            client._medium._remember_remote_is_before((1,16))
2844
 
            local_dir_format = BzrDirMetaFormat1()
2845
 
            self._supply_sub_formats_to(local_dir_format)
2846
 
            return local_dir_format.initialize_on_transport_ex(transport,
2847
 
                use_existing_dir=use_existing_dir, create_prefix=create_prefix,
2848
 
                force_new_repo=force_new_repo, stacked_on=stacked_on,
2849
 
                stack_on_pwd=stack_on_pwd, repo_format_name=repo_format_name,
2850
 
                make_working_trees=make_working_trees, shared_repo=shared_repo,
2851
 
                vfs_only=True)
2852
 
        except errors.ErrorFromSmartServer, err:
2853
 
            remote._translate_error(err, path=path)
2854
 
        repo_path = response[0]
2855
 
        bzrdir_name = response[6]
2856
 
        require_stacking = response[7]
2857
 
        require_stacking = self.parse_NoneTrueFalse(require_stacking)
2858
 
        format = RemoteBzrDirFormat()
2859
 
        format._network_name = bzrdir_name
2860
 
        self._supply_sub_formats_to(format)
2861
 
        bzrdir = remote.RemoteBzrDir(transport, format, _client=client)
2862
 
        if repo_path:
2863
 
            repo_format = remote.response_tuple_to_repo_format(response[1:])
2864
 
            if repo_path == '.':
2865
 
                repo_path = ''
2866
 
            if repo_path:
2867
 
                repo_bzrdir_format = RemoteBzrDirFormat()
2868
 
                repo_bzrdir_format._network_name = response[5]
2869
 
                repo_bzr = remote.RemoteBzrDir(transport.clone(repo_path),
2870
 
                    repo_bzrdir_format)
2871
 
            else:
2872
 
                repo_bzr = bzrdir
2873
 
            final_stack = response[8] or None
2874
 
            final_stack_pwd = response[9] or None
2875
 
            if final_stack_pwd:
2876
 
                final_stack_pwd = urlutils.join(
2877
 
                    transport.base, final_stack_pwd)
2878
 
            remote_repo = remote.RemoteRepository(repo_bzr, repo_format)
2879
 
            if len(response) > 10:
2880
 
                # Updated server verb that locks remotely.
2881
 
                repo_lock_token = response[10] or None
2882
 
                remote_repo.lock_write(repo_lock_token, _skip_rpc=True)
2883
 
                if repo_lock_token:
2884
 
                    remote_repo.dont_leave_lock_in_place()
2885
 
            else:
2886
 
                remote_repo.lock_write()
2887
 
            policy = UseExistingRepository(remote_repo, final_stack,
2888
 
                final_stack_pwd, require_stacking)
2889
 
            policy.acquire_repository()
2890
 
        else:
2891
 
            remote_repo = None
2892
 
            policy = None
2893
 
        bzrdir._format.set_branch_format(self.get_branch_format())
2894
 
        if require_stacking:
2895
 
            # The repo has already been created, but we need to make sure that
2896
 
            # we'll make a stackable branch.
2897
 
            bzrdir._format.require_stacking(_skip_repo=True)
2898
 
        return remote_repo, bzrdir, require_stacking, policy
2899
 
 
2900
 
    def _open(self, transport):
2901
 
        return remote.RemoteBzrDir(transport, self)
2902
 
 
2903
 
    def __eq__(self, other):
2904
 
        if not isinstance(other, RemoteBzrDirFormat):
2905
 
            return False
2906
 
        return self.get_format_description() == other.get_format_description()
2907
 
 
2908
 
    def __return_repository_format(self):
2909
 
        # Always return a RemoteRepositoryFormat object, but if a specific bzr
2910
 
        # repository format has been asked for, tell the RemoteRepositoryFormat
2911
 
        # that it should use that for init() etc.
2912
 
        result = remote.RemoteRepositoryFormat()
2913
 
        custom_format = getattr(self, '_repository_format', None)
2914
 
        if custom_format:
2915
 
            if isinstance(custom_format, remote.RemoteRepositoryFormat):
2916
 
                return custom_format
2917
 
            else:
2918
 
                # We will use the custom format to create repositories over the
2919
 
                # wire; expose its details like rich_root_data for code to
2920
 
                # query
2921
 
                result._custom_format = custom_format
2922
 
        return result
2923
 
 
2924
 
    def get_branch_format(self):
2925
 
        result = BzrDirMetaFormat1.get_branch_format(self)
2926
 
        if not isinstance(result, remote.RemoteBranchFormat):
2927
 
            new_result = remote.RemoteBranchFormat()
2928
 
            new_result._custom_format = result
2929
 
            # cache the result
2930
 
            self.set_branch_format(new_result)
2931
 
            result = new_result
2932
 
        return result
2933
 
 
2934
 
    repository_format = property(__return_repository_format,
2935
 
        BzrDirMetaFormat1._set_repository_format) #.im_func)
2936
 
 
2937
 
 
2938
1782
controldir.ControlDirFormat.register_server_prober(RemoteBzrProber)
2939
1783
 
2940
1784
 
3139
1983
    registry.register(key, helper, help, native, deprecated, hidden,
3140
1984
        experimental, alias)
3141
1985
 
3142
 
# The pre-0.8 formats have their repository format network name registered in
3143
 
# repository.py. MetaDir formats have their repository format network name
3144
 
# inferred from their disk format string.
3145
 
controldir.format_registry.register('weave', BzrDirFormat6,
3146
 
    'Pre-0.8 format.  Slower than knit and does not'
3147
 
    ' support checkouts or shared repositories.',
3148
 
    hidden=True,
3149
 
    deprecated=True)
3150
 
register_metadir(controldir.format_registry, 'metaweave',
3151
 
    'bzrlib.repofmt.weaverepo.RepositoryFormat7',
3152
 
    'Transitional format in 0.8.  Slower than knit.',
3153
 
    branch_format='bzrlib.branch.BzrBranchFormat5',
3154
 
    tree_format='bzrlib.workingtree.WorkingTreeFormat3',
3155
 
    hidden=True,
3156
 
    deprecated=True)
3157
1986
register_metadir(controldir.format_registry, 'knit',
3158
1987
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
3159
1988
    'Format using knits.  Recommended for interoperation with bzr <= 0.14.',