~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/bzrdir.py

  • Committer: Jelmer Vernooij
  • Date: 2012-01-23 19:08:05 UTC
  • mfrom: (6437.3.20 2.5)
  • mto: This revision was merged to the branch mainline in revision 6450.
  • Revision ID: jelmer@samba.org-20120123190805-hlcuihkt2dep44cw
merge bzr 2.5.

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
objects returned.
26
26
"""
27
27
 
 
28
from __future__ import absolute_import
 
29
 
28
30
import sys
29
31
 
30
32
from bzrlib.lazy_import import lazy_import
784
786
    def __repr__(self):
785
787
        return "<%s at %r>" % (self.__class__.__name__, self.user_url)
786
788
 
 
789
    def update_feature_flags(self, updated_flags):
 
790
        """Update the features required by this bzrdir.
 
791
 
 
792
        :param updated_flags: Dictionary mapping feature names to necessities
 
793
            A necessity can be None to indicate the feature should be removed
 
794
        """
 
795
        self.control_files.lock_write()
 
796
        try:
 
797
            self._format._update_feature_flags(updated_flags)
 
798
            self.transport.put_bytes('branch-format', self._format.as_string())
 
799
        finally:
 
800
            self.control_files.unlock()
 
801
 
787
802
 
788
803
class BzrDirMeta1(BzrDir):
789
804
    """A .bzr meta version 1 control object.
794
809
    present within a BzrDir.
795
810
    """
796
811
 
 
812
    def __init__(self, _transport, _format):
 
813
        super(BzrDirMeta1, self).__init__(_transport, _format)
 
814
        self.control_files = lockable_files.LockableFiles(self.control_transport,
 
815
            self._format._lock_file_name, self._format._lock_class)
 
816
 
797
817
    def can_convert_format(self):
798
818
        """See BzrDir.can_convert_format()."""
799
819
        return True
809
829
 
810
830
    def destroy_branch(self, name=None):
811
831
        """See BzrDir.create_branch."""
812
 
        if name is not None:
 
832
        if name is None:
 
833
            name = self._get_selected_branch()
 
834
        if name != "":
813
835
            raise errors.NoColocatedBranchSupport(self)
814
836
        self.transport.delete_tree('branch')
815
837
 
850
872
 
851
873
        This might be a synthetic object for e.g. RemoteBranch and SVN.
852
874
        """
853
 
        from bzrlib.branch import BranchFormat
854
 
        return BranchFormat.find_format(self, name=name)
 
875
        from bzrlib.branch import BranchFormatMetadir
 
876
        return BranchFormatMetadir.find_format(self, name=name)
855
877
 
856
878
    def _get_mkdir_mode(self):
857
879
        """Figure out the mode to use when creating a bzrdir subdir."""
861
883
 
862
884
    def get_branch_reference(self, name=None):
863
885
        """See BzrDir.get_branch_reference()."""
864
 
        from bzrlib.branch import BranchFormat
865
 
        format = BranchFormat.find_format(self, name=name)
 
886
        from bzrlib.branch import BranchFormatMetadir
 
887
        format = BranchFormatMetadir.find_format(self, name=name)
866
888
        return format.get_reference(self, name=name)
867
889
 
 
890
    def set_branch_reference(self, target_branch, name=None):
 
891
        format = _mod_branch.BranchReferenceFormat()
 
892
        return format.initialize(self, target_branch=target_branch, name=name)
 
893
 
868
894
    def get_branch_transport(self, branch_format, name=None):
869
895
        """See BzrDir.get_branch_transport()."""
870
 
        if name is not None:
 
896
        if name is None:
 
897
            name = self._get_selected_branch()
 
898
        if name != "":
871
899
            raise errors.NoColocatedBranchSupport(self)
872
900
        # XXX: this shouldn't implicitly create the directory if it's just
873
901
        # promising to get a transport -- mbp 20090727
917
945
        Note: if you're going to open the working tree, you should just go
918
946
        ahead and try, and not ask permission first.
919
947
        """
920
 
        from bzrlib.workingtree import WorkingTreeFormat
 
948
        from bzrlib.workingtree import WorkingTreeFormatMetaDir
921
949
        try:
922
 
            WorkingTreeFormat.find_format_string(self)
 
950
            WorkingTreeFormatMetaDir.find_format_string(self)
923
951
        except errors.NoWorkingTree:
924
952
            return False
925
953
        return True
966
994
 
967
995
    def open_repository(self, unsupported=False):
968
996
        """See BzrDir.open_repository."""
969
 
        from bzrlib.repository import RepositoryFormat
970
 
        format = RepositoryFormat.find_format(self)
 
997
        from bzrlib.repository import RepositoryFormatMetaDir
 
998
        format = RepositoryFormatMetaDir.find_format(self)
971
999
        format.check_support_status(unsupported)
972
1000
        return format.open(self, _found=True)
973
1001
 
974
1002
    def open_workingtree(self, unsupported=False,
975
1003
            recommend_upgrade=True):
976
1004
        """See BzrDir.open_workingtree."""
977
 
        from bzrlib.workingtree import WorkingTreeFormat
978
 
        format = WorkingTreeFormat.find_format(self)
 
1005
        from bzrlib.workingtree import WorkingTreeFormatMetaDir
 
1006
        format = WorkingTreeFormatMetaDir.find_format(self)
979
1007
        format.check_support_status(unsupported, recommend_upgrade,
980
1008
            basedir=self.root_transport.base)
981
1009
        return format.open(self, _found=True)
991
1019
    BzrDirMeta1.
992
1020
    """
993
1021
 
994
 
    def __init__(self, _transport, _format):
995
 
        super(BzrDirMeta1Colo, self).__init__(_transport, _format)
996
 
        self.control_files = lockable_files.LockableFiles(self.control_transport,
997
 
            self._format._lock_file_name, self._format._lock_class)
998
 
 
999
1022
    def _get_branch_path(self, name):
1000
1023
        """Obtain the branch path to use.
1001
1024
 
1006
1029
        :param name: Optional branch name to use
1007
1030
        :return: Relative path to branch
1008
1031
        """
1009
 
        if name is None:
 
1032
        if name == "":
1010
1033
            return 'branch'
1011
1034
        return urlutils.join('branches', name.encode("utf-8"))
1012
1035
 
1041
1064
        if name is None:
1042
1065
            name = self._get_selected_branch()
1043
1066
        path = self._get_branch_path(name)
1044
 
        if name is not None:
 
1067
        if name != "":
1045
1068
            self.control_files.lock_write()
1046
1069
            try:
1047
1070
                branches = self._read_branch_list()
1054
1077
                self.control_files.unlock()
1055
1078
        self.transport.delete_tree(path)
1056
1079
 
1057
 
    def list_branches(self):
1058
 
        """See ControlDir.list_branches."""
1059
 
        ret = []
1060
 
        # Default branch
 
1080
    def get_branches(self):
 
1081
        """See ControlDir.get_branches."""
 
1082
        ret = {}
1061
1083
        try:
1062
 
            ret.append(self.open_branch())
 
1084
            ret[""] = self.open_branch(name="")
1063
1085
        except (errors.NotBranchError, errors.NoRepositoryPresent):
1064
1086
            pass
1065
1087
 
1066
 
        # colocated branches
1067
 
        ret.extend([self.open_branch(name.decode("utf-8")) for name in
1068
 
                    self._read_branch_list()])
 
1088
        for name in self._read_branch_list():
 
1089
            ret[name] = self.open_branch(name=name.decode('utf-8'))
1069
1090
 
1070
1091
        return ret
1071
1092
 
1072
1093
    def get_branch_transport(self, branch_format, name=None):
1073
1094
        """See BzrDir.get_branch_transport()."""
 
1095
        if name is None:
 
1096
            name = self._get_selected_branch()
1074
1097
        path = self._get_branch_path(name)
1075
1098
        # XXX: this shouldn't implicitly create the directory if it's just
1076
1099
        # promising to get a transport -- mbp 20090727
1080
1103
            branch_format.get_format_string()
1081
1104
        except NotImplementedError:
1082
1105
            raise errors.IncompatibleFormat(branch_format, self._format)
1083
 
        if name is not None:
 
1106
        if name != "":
1084
1107
            try:
1085
1108
                self.transport.mkdir('branches', mode=self._get_mkdir_mode())
1086
1109
            except errors.FileExists:
1102
1125
        return self.transport.clone(path)
1103
1126
 
1104
1127
 
 
1128
class BzrFormat(object):
 
1129
    """Base class for all formats of things living in metadirs.
 
1130
 
 
1131
    This class manages the format string that is stored in the 'format'
 
1132
    or 'branch-format' file.
 
1133
 
 
1134
    All classes for (branch-, repository-, workingtree-) formats that
 
1135
    live in meta directories and have their own 'format' file
 
1136
    (i.e. different from .bzr/branch-format) derive from this class,
 
1137
    as well as the relevant base class for their kind
 
1138
    (BranchFormat, WorkingTreeFormat, RepositoryFormat).
 
1139
 
 
1140
    Each format is identified by a "format" or "branch-format" file with a
 
1141
    single line containing the base format name and then an optional list of
 
1142
    feature flags.
 
1143
 
 
1144
    Feature flags are supported as of bzr 2.5. Setting feature flags on formats
 
1145
    will render them inaccessible to older versions of bzr.
 
1146
 
 
1147
    :ivar features: Dictionary mapping feature names to their necessity
 
1148
    """
 
1149
 
 
1150
    _present_features = set()
 
1151
 
 
1152
    def __init__(self):
 
1153
        self.features = {}
 
1154
 
 
1155
    @classmethod
 
1156
    def register_feature(cls, name):
 
1157
        """Register a feature as being present.
 
1158
 
 
1159
        :param name: Name of the feature
 
1160
        """
 
1161
        if " " in name:
 
1162
            raise ValueError("spaces are not allowed in feature names")
 
1163
        if name in cls._present_features:
 
1164
            raise errors.FeatureAlreadyRegistered(name)
 
1165
        cls._present_features.add(name)
 
1166
 
 
1167
    @classmethod
 
1168
    def unregister_feature(cls, name):
 
1169
        """Unregister a feature."""
 
1170
        cls._present_features.remove(name)
 
1171
 
 
1172
    def check_support_status(self, allow_unsupported, recommend_upgrade=True,
 
1173
            basedir=None):
 
1174
        for name, necessity in self.features.iteritems():
 
1175
            if name in self._present_features:
 
1176
                continue
 
1177
            if necessity == "optional":
 
1178
                mutter("ignoring optional missing feature %s", name)
 
1179
                continue
 
1180
            elif necessity == "required":
 
1181
                raise errors.MissingFeature(name)
 
1182
            else:
 
1183
                mutter("treating unknown necessity as require for %s",
 
1184
                       name)
 
1185
                raise errors.MissingFeature(name)
 
1186
 
 
1187
    @classmethod
 
1188
    def get_format_string(cls):
 
1189
        """Return the ASCII format string that identifies this format."""
 
1190
        raise NotImplementedError(cls.get_format_string)
 
1191
 
 
1192
    @classmethod
 
1193
    def from_string(cls, text):
 
1194
        format_string = cls.get_format_string()
 
1195
        if not text.startswith(format_string):
 
1196
            raise AssertionError("Invalid format header %r for %r" % (text, cls))
 
1197
        lines = text[len(format_string):].splitlines()
 
1198
        ret = cls()
 
1199
        for lineno, line in enumerate(lines):
 
1200
            try:
 
1201
                (necessity, feature) = line.split(" ", 1)
 
1202
            except ValueError:
 
1203
                raise errors.ParseFormatError(format=cls, lineno=lineno+2,
 
1204
                    line=line, text=text)
 
1205
            ret.features[feature] = necessity
 
1206
        return ret
 
1207
 
 
1208
    def as_string(self):
 
1209
        """Return the string representation of this format.
 
1210
        """
 
1211
        lines = [self.get_format_string()]
 
1212
        lines.extend([("%s %s\n" % (item[1], item[0])) for item in
 
1213
            self.features.iteritems()])
 
1214
        return "".join(lines)
 
1215
 
 
1216
    @classmethod
 
1217
    def _find_format(klass, registry, kind, format_string):
 
1218
        try:
 
1219
            first_line = format_string[:format_string.index("\n")+1]
 
1220
        except ValueError:
 
1221
            first_line = format_string
 
1222
        try:
 
1223
            cls = registry.get(first_line)
 
1224
        except KeyError:
 
1225
            raise errors.UnknownFormatError(format=first_line, kind=kind)
 
1226
        return cls.from_string(format_string)
 
1227
 
 
1228
    def network_name(self):
 
1229
        """A simple byte string uniquely identifying this format for RPC calls.
 
1230
 
 
1231
        Metadir branch formats use their format string.
 
1232
        """
 
1233
        return self.as_string()
 
1234
 
 
1235
    def __eq__(self, other):
 
1236
        return (self.__class__ is other.__class__ and
 
1237
                self.features == other.features)
 
1238
 
 
1239
    def _update_feature_flags(self, updated_flags):
 
1240
        """Update the feature flags in this format.
 
1241
 
 
1242
        :param updated_flags: Updated feature flags
 
1243
        """
 
1244
        for name, necessity in updated_flags.iteritems():
 
1245
            if necessity is None:
 
1246
                try:
 
1247
                    del self.features[name]
 
1248
                except KeyError:
 
1249
                    pass
 
1250
            else:
 
1251
                self.features[name] = necessity
 
1252
 
 
1253
 
1105
1254
class BzrProber(controldir.Prober):
1106
1255
    """Prober for formats that use a .bzr/ control directory."""
1107
1256
 
1126
1275
        except errors.NoSuchFile:
1127
1276
            raise errors.NotBranchError(path=transport.base)
1128
1277
        try:
1129
 
            return klass.formats.get(format_string)
 
1278
            first_line = format_string[:format_string.index("\n")+1]
 
1279
        except ValueError:
 
1280
            first_line = format_string
 
1281
        try:
 
1282
            cls = klass.formats.get(first_line)
1130
1283
        except KeyError:
1131
 
            raise errors.UnknownFormatError(format=format_string, kind='bzrdir')
 
1284
            raise errors.UnknownFormatError(format=first_line, kind='bzrdir')
 
1285
        return cls.from_string(format_string)
1132
1286
 
1133
1287
    @classmethod
1134
1288
    def known_formats(cls):
1177
1331
        return set([RemoteBzrDirFormat()])
1178
1332
 
1179
1333
 
1180
 
class BzrDirFormat(controldir.ControlDirFormat):
 
1334
class BzrDirFormat(BzrFormat, controldir.ControlDirFormat):
1181
1335
    """ControlDirFormat base class for .bzr/ directories.
1182
1336
 
1183
1337
    Formats are placed in a dict by their format string for reference
1194
1348
    # _lock_class must be set in subclasses to the lock type, typ.
1195
1349
    # TransportLock or LockDir
1196
1350
 
1197
 
    @classmethod
1198
 
    def get_format_string(cls):
1199
 
        """Return the ASCII format string that identifies this format."""
1200
 
        raise NotImplementedError(cls.get_format_string)
1201
 
 
1202
1351
    def initialize_on_transport(self, transport):
1203
1352
        """Initialize a new bzrdir in the base directory of a Transport."""
1204
1353
        try:
1326
1475
        # mode from the root directory
1327
1476
        temp_control = lockable_files.LockableFiles(transport,
1328
1477
                            '', lockable_files.TransportLock)
1329
 
        temp_control._transport.mkdir('.bzr',
1330
 
                                      # FIXME: RBC 20060121 don't peek under
1331
 
                                      # the covers
1332
 
                                      mode=temp_control._dir_mode)
 
1478
        try:
 
1479
            temp_control._transport.mkdir('.bzr',
 
1480
                # FIXME: RBC 20060121 don't peek under
 
1481
                # the covers
 
1482
                mode=temp_control._dir_mode)
 
1483
        except errors.FileExists:
 
1484
            raise errors.AlreadyControlDirError(transport.base)
1333
1485
        if sys.platform == 'win32' and isinstance(transport, local.LocalTransport):
1334
1486
            win32utils.set_file_attr_hidden(transport._abspath('.bzr'))
1335
1487
        file_mode = temp_control._file_mode
1339
1491
                       "This is a Bazaar control directory.\n"
1340
1492
                       "Do not change any files in this directory.\n"
1341
1493
                       "See http://bazaar.canonical.com/ for more information about Bazaar.\n"),
1342
 
                      ('branch-format', self.get_format_string()),
 
1494
                      ('branch-format', self.as_string()),
1343
1495
                      ]
1344
1496
        # NB: no need to escape relative paths that are url safe.
1345
1497
        control_files = lockable_files.LockableFiles(bzrdir_transport,
1389
1541
            compatible with whatever sub formats are supported by self.
1390
1542
        :return: None.
1391
1543
        """
 
1544
        other_format.features = dict(self.features)
1392
1545
 
1393
1546
    def supports_transport(self, transport):
1394
1547
        # bzr formats can be opened over all known transports
1395
1548
        return True
1396
1549
 
 
1550
    def check_support_status(self, allow_unsupported, recommend_upgrade=True,
 
1551
            basedir=None):
 
1552
        controldir.ControlDirFormat.check_support_status(self,
 
1553
            allow_unsupported=allow_unsupported, recommend_upgrade=recommend_upgrade,
 
1554
            basedir=basedir)
 
1555
        BzrFormat.check_support_status(self, allow_unsupported=allow_unsupported,
 
1556
            recommend_upgrade=recommend_upgrade, basedir=basedir)
 
1557
 
1397
1558
 
1398
1559
class BzrDirMetaFormat1(BzrDirFormat):
1399
1560
    """Bzr meta control format 1
1415
1576
    colocated_branches = False
1416
1577
 
1417
1578
    def __init__(self):
 
1579
        BzrDirFormat.__init__(self)
1418
1580
        self._workingtree_format = None
1419
1581
        self._branch_format = None
1420
1582
        self._repository_format = None
1426
1588
            return False
1427
1589
        if other.workingtree_format != self.workingtree_format:
1428
1590
            return False
 
1591
        if other.features != self.features:
 
1592
            return False
1429
1593
        return True
1430
1594
 
1431
1595
    def __ne__(self, other):
1557
1721
        """See BzrDirFormat.get_format_description()."""
1558
1722
        return "Meta directory format 1"
1559
1723
 
1560
 
    def network_name(self):
1561
 
        return self.get_format_string()
1562
 
 
1563
1724
    def _open(self, transport):
1564
1725
        """See BzrDirFormat._open."""
1565
1726
        # Create a new format instance because otherwise initialisation of new
1594
1755
            compatible with whatever sub formats are supported by self.
1595
1756
        :return: None.
1596
1757
        """
 
1758
        super(BzrDirMetaFormat1, self)._supply_sub_formats_to(other_format)
1597
1759
        if getattr(self, '_repository_format', None) is not None:
1598
1760
            other_format.repository_format = self.repository_format
1599
1761
        if self._branch_format is not None:
1612
1774
    def __set_workingtree_format(self, wt_format):
1613
1775
        self._workingtree_format = wt_format
1614
1776
 
 
1777
    def __repr__(self):
 
1778
        return "<%r>" % (self.__class__.__name__,)
 
1779
 
1615
1780
    workingtree_format = property(__get_workingtree_format,
1616
1781
                                  __set_workingtree_format)
1617
1782
 
1741
1906
    def convert(self, to_convert, pb):
1742
1907
        """See Converter.convert()."""
1743
1908
        to_convert.transport.put_bytes('branch-format',
1744
 
            self.target_format.get_format_string())
 
1909
            self.target_format.as_string())
1745
1910
        return BzrDir.open_from_transport(to_convert.root_transport)
1746
1911
 
1747
1912
 
1767
1932
        finally:
1768
1933
            to_convert.control_files.unlock()
1769
1934
        to_convert.transport.put_bytes('branch-format',
1770
 
            self.target_format.get_format_string())
 
1935
            self.target_format.as_string())
1771
1936
        return BzrDir.open_from_transport(to_convert.root_transport)
1772
1937
 
1773
1938
 
1866
2031
        :return: A repository, is_new_flag (True if the repository was
1867
2032
            created).
1868
2033
        """
1869
 
        raise NotImplemented(RepositoryAcquisitionPolicy.acquire_repository)
 
2034
        raise NotImplementedError(RepositoryAcquisitionPolicy.acquire_repository)
1870
2035
 
1871
2036
 
1872
2037
class CreateRepository(RepositoryAcquisitionPolicy):