810
793
present within a BzrDir.
813
def _get_branch_path(self, name):
814
"""Obtain the branch path to use.
816
This uses the API specified branch name first, and then falls back to
817
the branch name specified in the URL. If neither of those is specified,
818
it uses the default branch.
820
:param name: Optional branch name to use
821
:return: Relative path to branch
825
return urlutils.join('branches', name.encode("utf-8"))
827
def _read_branch_list(self):
828
"""Read the branch list.
830
:return: List of utf-8 encoded branch names.
833
f = self.control_transport.get('branch-list')
834
except errors.NoSuchFile:
840
ret.append(name.rstrip("\n"))
845
def _write_branch_list(self, branches):
846
"""Write out the branch list.
848
:param branches: List of utf-8 branch names to write
850
self.transport.put_bytes('branch-list',
851
"".join([name+"\n" for name in branches]))
853
def __init__(self, _transport, _format):
854
super(BzrDirMeta1, self).__init__(_transport, _format)
855
self.control_files = lockable_files.LockableFiles(
856
self.control_transport, self._format._lock_file_name,
857
self._format._lock_class)
859
796
def can_convert_format(self):
860
797
"""See BzrDir.can_convert_format()."""
863
800
def create_branch(self, name=None, repository=None,
864
801
append_revisions_only=None):
865
"""See ControlDir.create_branch."""
802
"""See BzrDir.create_branch."""
867
804
name = self._get_selected_branch()
868
805
return self._format.get_branch_format().initialize(self, name=name,
940
861
def get_branch_reference(self, name=None):
941
862
"""See BzrDir.get_branch_reference()."""
942
from bzrlib.branch import BranchFormatMetadir
943
format = BranchFormatMetadir.find_format(self, name=name)
863
from bzrlib.branch import BranchFormat
864
format = BranchFormat.find_format(self, name=name)
944
865
return format.get_reference(self, name=name)
946
def set_branch_reference(self, target_branch, name=None):
947
format = _mod_branch.BranchReferenceFormat()
948
return format.initialize(self, target_branch=target_branch, name=name)
950
867
def get_branch_transport(self, branch_format, name=None):
951
868
"""See BzrDir.get_branch_transport()."""
953
name = self._get_selected_branch()
954
path = self._get_branch_path(name)
870
raise errors.NoColocatedBranchSupport(self)
955
871
# XXX: this shouldn't implicitly create the directory if it's just
956
872
# promising to get a transport -- mbp 20090727
957
873
if branch_format is None:
958
return self.transport.clone(path)
874
return self.transport.clone('branch')
960
876
branch_format.get_format_string()
961
877
except NotImplementedError:
962
878
raise errors.IncompatibleFormat(branch_format, self._format)
964
branches = self._read_branch_list()
965
utf8_name = name.encode("utf-8")
966
if not utf8_name in branches:
967
self.control_files.lock_write()
969
branches = self._read_branch_list()
970
dirname = urlutils.dirname(utf8_name)
971
if dirname != "" and dirname in branches:
972
raise errors.ParentBranchExists(name)
974
b.startswith(utf8_name+"/") for b in branches]
975
if any(child_branches):
976
raise errors.AlreadyBranchError(name)
977
branches.append(utf8_name)
978
self._write_branch_list(branches)
980
self.control_files.unlock()
981
branch_transport = self.transport.clone(path)
982
mode = self._get_mkdir_mode()
983
branch_transport.create_prefix(mode=mode)
985
self.transport.mkdir(path, mode=mode)
880
self.transport.mkdir('branch', mode=self._get_mkdir_mode())
986
881
except errors.FileExists:
988
return self.transport.clone(path)
883
return self.transport.clone('branch')
990
885
def get_repository_transport(self, repository_format):
991
886
"""See BzrDir.get_repository_transport()."""
1101
983
return config.TransportConfig(self.transport, 'control.conf')
1104
class BzrFormat(object):
1105
"""Base class for all formats of things living in metadirs.
1107
This class manages the format string that is stored in the 'format'
1108
or 'branch-format' file.
1110
All classes for (branch-, repository-, workingtree-) formats that
1111
live in meta directories and have their own 'format' file
1112
(i.e. different from .bzr/branch-format) derive from this class,
1113
as well as the relevant base class for their kind
1114
(BranchFormat, WorkingTreeFormat, RepositoryFormat).
1116
Each format is identified by a "format" or "branch-format" file with a
1117
single line containing the base format name and then an optional list of
1120
Feature flags are supported as of bzr 2.5. Setting feature flags on formats
1121
will render them inaccessible to older versions of bzr.
1123
:ivar features: Dictionary mapping feature names to their necessity
986
class BzrDirMeta1Colo(BzrDirMeta1):
987
"""BzrDirMeta1 with support for colocated branches.
989
This format is experimental, and will eventually be merged back into
1126
_present_features = set()
1132
def register_feature(cls, name):
1133
"""Register a feature as being present.
1135
:param name: Name of the feature
1138
raise ValueError("spaces are not allowed in feature names")
1139
if name in cls._present_features:
1140
raise errors.FeatureAlreadyRegistered(name)
1141
cls._present_features.add(name)
1144
def unregister_feature(cls, name):
1145
"""Unregister a feature."""
1146
cls._present_features.remove(name)
1148
def check_support_status(self, allow_unsupported, recommend_upgrade=True,
1150
for name, necessity in self.features.iteritems():
1151
if name in self._present_features:
1153
if necessity == "optional":
1154
mutter("ignoring optional missing feature %s", name)
1156
elif necessity == "required":
1157
raise errors.MissingFeature(name)
1159
mutter("treating unknown necessity as require for %s",
1161
raise errors.MissingFeature(name)
1164
def get_format_string(cls):
1165
"""Return the ASCII format string that identifies this format."""
1166
raise NotImplementedError(cls.get_format_string)
1169
def from_string(cls, text):
1170
format_string = cls.get_format_string()
1171
if not text.startswith(format_string):
1172
raise AssertionError("Invalid format header %r for %r" % (text, cls))
1173
lines = text[len(format_string):].splitlines()
1175
for lineno, line in enumerate(lines):
1177
(necessity, feature) = line.split(" ", 1)
1179
raise errors.ParseFormatError(format=cls, lineno=lineno+2,
1180
line=line, text=text)
1181
ret.features[feature] = necessity
1184
def as_string(self):
1185
"""Return the string representation of this format.
1187
lines = [self.get_format_string()]
1188
lines.extend([("%s %s\n" % (item[1], item[0])) for item in
1189
self.features.iteritems()])
1190
return "".join(lines)
1193
def _find_format(klass, registry, kind, format_string):
1195
first_line = format_string[:format_string.index("\n")+1]
1197
first_line = format_string
1199
cls = registry.get(first_line)
1201
raise errors.UnknownFormatError(format=first_line, kind=kind)
1202
return cls.from_string(format_string)
1204
def network_name(self):
1205
"""A simple byte string uniquely identifying this format for RPC calls.
1207
Metadir branch formats use their format string.
1209
return self.as_string()
1211
def __eq__(self, other):
1212
return (self.__class__ is other.__class__ and
1213
self.features == other.features)
1215
def _update_feature_flags(self, updated_flags):
1216
"""Update the feature flags in this format.
1218
:param updated_flags: Updated feature flags
1220
for name, necessity in updated_flags.iteritems():
1221
if necessity is None:
1223
del self.features[name]
1227
self.features[name] = necessity
993
def __init__(self, _transport, _format):
994
super(BzrDirMeta1Colo, self).__init__(_transport, _format)
995
self.control_files = lockable_files.LockableFiles(self.control_transport,
996
self._format._lock_file_name, self._format._lock_class)
998
def _get_branch_path(self, name):
999
"""Obtain the branch path to use.
1001
This uses the API specified branch name first, and then falls back to
1002
the branch name specified in the URL. If neither of those is specified,
1003
it uses the default branch.
1005
:param name: Optional branch name to use
1006
:return: Relative path to branch
1010
return urlutils.join('branches', name.encode("utf-8"))
1012
def _read_branch_list(self):
1013
"""Read the branch list.
1015
:return: List of utf-8 encoded branch names.
1018
f = self.control_transport.get('branch-list')
1019
except errors.NoSuchFile:
1025
ret.append(name.rstrip("\n"))
1030
def _write_branch_list(self, branches):
1031
"""Write out the branch list.
1033
:param branches: List of utf-8 branch names to write
1035
self.transport.put_bytes('branch-list',
1036
"".join([name+"\n" for name in branches]))
1038
def destroy_branch(self, name=None):
1039
"""See BzrDir.create_branch."""
1041
name = self._get_selected_branch()
1042
path = self._get_branch_path(name)
1043
if name is not None:
1044
self.control_files.lock_write()
1046
branches = self._read_branch_list()
1048
branches.remove(name.encode("utf-8"))
1050
raise errors.NotBranchError(name)
1051
self._write_branch_list(branches)
1053
self.control_files.unlock()
1054
self.transport.delete_tree(path)
1056
def list_branches(self):
1057
"""See ControlDir.list_branches."""
1061
ret.append(self.open_branch())
1062
except (errors.NotBranchError, errors.NoRepositoryPresent):
1065
# colocated branches
1066
ret.extend([self.open_branch(name.decode("utf-8")) for name in
1067
self._read_branch_list()])
1071
def get_branch_transport(self, branch_format, name=None):
1072
"""See BzrDir.get_branch_transport()."""
1073
path = self._get_branch_path(name)
1074
# XXX: this shouldn't implicitly create the directory if it's just
1075
# promising to get a transport -- mbp 20090727
1076
if branch_format is None:
1077
return self.transport.clone(path)
1079
branch_format.get_format_string()
1080
except NotImplementedError:
1081
raise errors.IncompatibleFormat(branch_format, self._format)
1082
if name is not None:
1084
self.transport.mkdir('branches', mode=self._get_mkdir_mode())
1085
except errors.FileExists:
1087
branches = self._read_branch_list()
1088
utf8_name = name.encode("utf-8")
1089
if not utf8_name in branches:
1090
self.control_files.lock_write()
1092
branches = self._read_branch_list()
1093
branches.append(utf8_name)
1094
self._write_branch_list(branches)
1096
self.control_files.unlock()
1098
self.transport.mkdir(path, mode=self._get_mkdir_mode())
1099
except errors.FileExists:
1101
return self.transport.clone(path)
1230
1104
class BzrProber(controldir.Prober):