1# Copyright (C) 2017 Breezy Developers 2# 3# This program is free software; you can redistribute it and/or modify 4# it under the terms of the GNU General Public License as published by 5# the Free Software Foundation; either version 2 of the License, or 6# (at your option) any later version. 7# 8# This program is distributed in the hope that it will be useful, 9# but WITHOUT ANY WARRANTY; without even the implied warranty of 10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11# GNU General Public License for more details. 12# 13# You should have received a copy of the GNU General Public License 14# along with this program; if not, write to the Free Software 15# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 16 17from .. import ( 18 config, 19 errors, 20 controldir, 21 pyutils, 22 registry, 23 ) 24 25 26class LineEndingError(errors.BzrError): 27 28 _fmt = ("Line ending corrupted for file: %(file)s; " 29 "Maybe your files got corrupted in transport?") 30 31 def __init__(self, file): 32 self.file = file 33 34 35class BzrProber(controldir.Prober): 36 """Prober for formats that use a .bzr/ control directory.""" 37 38 formats = registry.FormatRegistry(controldir.network_format_registry) 39 """The known .bzr formats.""" 40 41 @classmethod 42 def priority(klass, transport): 43 return 10 44 45 @classmethod 46 def probe_transport(klass, transport): 47 """Return the .bzrdir style format present in a directory.""" 48 try: 49 format_string = transport.get_bytes(".bzr/branch-format") 50 except errors.NoSuchFile: 51 raise errors.NotBranchError(path=transport.base) 52 except errors.BadHttpRequest as e: 53 if e.reason == 'no such method: .bzr': 54 # hgweb 55 raise errors.NotBranchError(path=transport.base) 56 raise 57 58 try: 59 first_line = format_string[:format_string.index(b"\n") + 1] 60 except ValueError: 61 first_line = format_string 62 if (first_line.startswith(b'<!DOCTYPE') or 63 first_line.startswith(b'<html')): 64 raise errors.NotBranchError( 65 path=transport.base, detail="format file looks like HTML") 66 try: 67 cls = klass.formats.get(first_line) 68 except KeyError: 69 if first_line.endswith(b"\r\n"): 70 raise LineEndingError(file=".bzr/branch-format") 71 else: 72 raise errors.UnknownFormatError( 73 format=first_line, kind='bzrdir') 74 return cls.from_string(format_string) 75 76 @classmethod 77 def known_formats(cls): 78 result = [] 79 for name, format in cls.formats.items(): 80 if callable(format): 81 format = format() 82 result.append(format) 83 return result 84 85 86controldir.ControlDirFormat.register_prober(BzrProber) 87 88 89class RemoteBzrProber(controldir.Prober): 90 """Prober for remote servers that provide a Bazaar smart server.""" 91 92 @classmethod 93 def priority(klass, transport): 94 return -10 95 96 @classmethod 97 def probe_transport(klass, transport): 98 """Return a RemoteBzrDirFormat object if it looks possible.""" 99 try: 100 medium = transport.get_smart_medium() 101 except (NotImplementedError, AttributeError, 102 errors.TransportNotPossible, errors.NoSmartMedium, 103 errors.SmartProtocolError): 104 # no smart server, so not a branch for this format type. 105 raise errors.NotBranchError(path=transport.base) 106 else: 107 # Decline to open it if the server doesn't support our required 108 # version (3) so that the VFS-based transport will do it. 109 if medium.should_probe(): 110 try: 111 server_version = medium.protocol_version() 112 except errors.SmartProtocolError: 113 # Apparently there's no usable smart server there, even though 114 # the medium supports the smart protocol. 115 raise errors.NotBranchError(path=transport.base) 116 if server_version != '2': 117 raise errors.NotBranchError(path=transport.base) 118 from .remote import RemoteBzrDirFormat 119 return RemoteBzrDirFormat() 120 121 @classmethod 122 def known_formats(cls): 123 from .remote import RemoteBzrDirFormat 124 return [RemoteBzrDirFormat()] 125 126 127controldir.ControlDirFormat.register_prober(RemoteBzrProber) 128 129# Register bzr formats 130BzrProber.formats.register_lazy( 131 b"Bazaar-NG meta directory, format 1\n", 132 __name__ + '.bzrdir', 'BzrDirMetaFormat1') 133BzrProber.formats.register_lazy( 134 b"Bazaar meta directory, format 1 (with colocated branches)\n", 135 __name__ + '.bzrdir', 'BzrDirMetaFormat1Colo') 136 137 138def register_metadir(registry, key, 139 repository_format, help, native=True, deprecated=False, 140 branch_format=None, 141 tree_format=None, 142 hidden=False, 143 experimental=False, 144 bzrdir_format=None): 145 """Register a metadir subformat. 146 147 These all use a meta bzrdir, but can be parameterized by the 148 Repository/Branch/WorkingTreeformats. 149 150 :param repository_format: The fully-qualified repository format class 151 name as a string. 152 :param branch_format: Fully-qualified branch format class name as 153 a string. 154 :param tree_format: Fully-qualified tree format class name as 155 a string. 156 """ 157 if bzrdir_format is None: 158 bzrdir_format = 'breezy.bzr.bzrdir.BzrDirMetaFormat1' 159 # This should be expanded to support setting WorkingTree and Branch 160 # formats, once the API supports that. 161 162 def _load(full_name): 163 mod_name, factory_name = full_name.rsplit('.', 1) 164 try: 165 factory = pyutils.get_named_object(mod_name, factory_name) 166 except ImportError as e: 167 raise ImportError('failed to load %s: %s' % (full_name, e)) 168 except AttributeError: 169 raise AttributeError('no factory %s in module %r' 170 % (full_name, sys.modules[mod_name])) 171 return factory() 172 173 def helper(): 174 bd = _load(bzrdir_format) 175 if branch_format is not None: 176 bd.set_branch_format(_load(branch_format)) 177 if tree_format is not None: 178 bd.workingtree_format = _load(tree_format) 179 if repository_format is not None: 180 bd.repository_format = _load(repository_format) 181 return bd 182 registry.register(key, helper, help, native, deprecated, hidden, 183 experimental) 184 185 186register_metadir( 187 controldir.format_registry, 'knit', 188 'breezy.bzr.knitrepo.RepositoryFormatKnit1', 189 'Format using knits. Recommended for interoperation with bzr <= 0.14.', 190 branch_format='breezy.bzr.fullhistory.BzrBranchFormat5', 191 tree_format='breezy.bzr.workingtree_3.WorkingTreeFormat3', 192 hidden=True, 193 deprecated=True) 194register_metadir( 195 controldir.format_registry, 'dirstate', 196 'breezy.bzr.knitrepo.RepositoryFormatKnit1', 197 help='Format using dirstate for working trees. ' 198 'Compatible with bzr 0.8 and ' 199 'above when accessed over the network. Introduced in bzr 0.15.', 200 branch_format='breezy.bzr.fullhistory.BzrBranchFormat5', 201 tree_format='breezy.bzr.workingtree_4.WorkingTreeFormat4', 202 hidden=True, 203 deprecated=True) 204register_metadir( 205 controldir.format_registry, 'dirstate-tags', 206 'breezy.bzr.knitrepo.RepositoryFormatKnit1', 207 help='Variant of dirstate with support for tags. ' 208 'Introduced in bzr 0.15.', 209 branch_format='breezy.bzr.branch.BzrBranchFormat6', 210 tree_format='breezy.bzr.workingtree_4.WorkingTreeFormat4', 211 hidden=True, 212 deprecated=True) 213register_metadir( 214 controldir.format_registry, 'rich-root', 215 'breezy.bzr.knitrepo.RepositoryFormatKnit4', 216 help='Variant of dirstate with better handling of tree roots. ' 217 'Introduced in bzr 1.0.', 218 branch_format='breezy.bzr.branch.BzrBranchFormat6', 219 tree_format='breezy.bzr.workingtree_4.WorkingTreeFormat4', 220 hidden=True, 221 deprecated=True) 222register_metadir( 223 controldir.format_registry, 'dirstate-with-subtree', 224 'breezy.bzr.knitrepo.RepositoryFormatKnit3', 225 help='Variant of dirstate with support for nested trees. ' 226 'Introduced in 0.15.', 227 branch_format='breezy.bzr.branch.BzrBranchFormat6', 228 tree_format='breezy.bzr.workingtree_4.WorkingTreeFormat4', 229 experimental=True, 230 hidden=True, 231 ) 232register_metadir( 233 controldir.format_registry, 'pack-0.92', 234 'breezy.bzr.knitpack_repo.RepositoryFormatKnitPack1', 235 help='Pack-based format used in 1.x series. Introduced in 0.92. ' 236 'Interoperates with bzr repositories before 0.92 but cannot be ' 237 'read by bzr < 0.92.', 238 branch_format='breezy.bzr.branch.BzrBranchFormat6', 239 tree_format='breezy.bzr.workingtree_4.WorkingTreeFormat4', 240 deprecated=True, 241 hidden=True, 242 ) 243register_metadir( 244 controldir.format_registry, 'pack-0.92-subtree', 245 'breezy.bzr.knitpack_repo.RepositoryFormatKnitPack3', 246 help='Pack-based format used in 1.x series, with subtree support. ' 247 'Introduced in 0.92. Interoperates with ' 248 'bzr repositories before 0.92 but cannot be read by bzr < 0.92.', 249 branch_format='breezy.bzr.branch.BzrBranchFormat6', 250 tree_format='breezy.bzr.workingtree_4.WorkingTreeFormat4', 251 hidden=True, 252 deprecated=True, 253 experimental=True, 254 ) 255register_metadir( 256 controldir.format_registry, 'rich-root-pack', 257 'breezy.bzr.knitpack_repo.RepositoryFormatKnitPack4', 258 help='A variant of pack-0.92 that supports rich-root data ' 259 '(needed for bzr-svn and bzr-git). Introduced in 1.0.', 260 branch_format='breezy.bzr.branch.BzrBranchFormat6', 261 tree_format='breezy.bzr.workingtree_4.WorkingTreeFormat4', 262 hidden=True, 263 deprecated=True, 264 ) 265register_metadir( 266 controldir.format_registry, '1.6', 267 'breezy.bzr.knitpack_repo.RepositoryFormatKnitPack5', 268 help='A format that allows a branch to indicate that there is another ' 269 '(stacked) repository that should be used to access data that is ' 270 'not present locally.', 271 branch_format='breezy.bzr.branch.BzrBranchFormat7', 272 tree_format='breezy.bzr.workingtree_4.WorkingTreeFormat4', 273 hidden=True, 274 deprecated=True, 275 ) 276register_metadir( 277 controldir.format_registry, '1.6.1-rich-root', 278 'breezy.bzr.knitpack_repo.RepositoryFormatKnitPack5RichRoot', 279 help='A variant of 1.6 that supports rich-root data ' 280 '(needed for bzr-svn and bzr-git).', 281 branch_format='breezy.bzr.branch.BzrBranchFormat7', 282 tree_format='breezy.bzr.workingtree_4.WorkingTreeFormat4', 283 hidden=True, 284 deprecated=True, 285 ) 286register_metadir( 287 controldir.format_registry, '1.9', 288 'breezy.bzr.knitpack_repo.RepositoryFormatKnitPack6', 289 help='A repository format using B+tree indexes. These indexes ' 290 'are smaller in size, have smarter caching and provide faster ' 291 'performance for most operations.', 292 branch_format='breezy.bzr.branch.BzrBranchFormat7', 293 tree_format='breezy.bzr.workingtree_4.WorkingTreeFormat4', 294 hidden=True, 295 deprecated=True, 296 ) 297register_metadir( 298 controldir.format_registry, '1.9-rich-root', 299 'breezy.bzr.knitpack_repo.RepositoryFormatKnitPack6RichRoot', 300 help='A variant of 1.9 that supports rich-root data ' 301 '(needed for bzr-svn and bzr-git).', 302 branch_format='breezy.bzr.branch.BzrBranchFormat7', 303 tree_format='breezy.bzr.workingtree_4.WorkingTreeFormat4', 304 hidden=True, 305 deprecated=True, 306 ) 307register_metadir( 308 controldir.format_registry, '1.14', 309 'breezy.bzr.knitpack_repo.RepositoryFormatKnitPack6', 310 help='A working-tree format that supports content filtering.', 311 branch_format='breezy.bzr.branch.BzrBranchFormat7', 312 tree_format='breezy.bzr.workingtree_4.WorkingTreeFormat5', 313 hidden=True, 314 deprecated=True, 315 ) 316register_metadir( 317 controldir.format_registry, '1.14-rich-root', 318 'breezy.bzr.knitpack_repo.RepositoryFormatKnitPack6RichRoot', 319 help='A variant of 1.14 that supports rich-root data ' 320 '(needed for bzr-svn and bzr-git).', 321 branch_format='breezy.bzr.branch.BzrBranchFormat7', 322 tree_format='breezy.bzr.workingtree_4.WorkingTreeFormat5', 323 hidden=True, 324 deprecated=True, 325 ) 326# The following un-numbered 'development' formats should always just be aliases. 327register_metadir( 328 controldir.format_registry, 'development-subtree', 329 'breezy.bzr.groupcompress_repo.RepositoryFormat2aSubtree', 330 help='Current development format, subtree variant. Can convert data to and ' 331 'from pack-0.92-subtree (and anything compatible with ' 332 'pack-0.92-subtree) format repositories. Repositories and branches in ' 333 'this format can only be read by bzr.dev. Please read ' 334 'https://www.breezy-vcs.org/developers/development-repo.html ' 335 'before use.', 336 branch_format='breezy.bzr.branch.BzrBranchFormat8', 337 tree_format='breezy.bzr.workingtree_4.WorkingTreeFormat6', 338 experimental=True, 339 hidden=True, 340 ) 341register_metadir( 342 controldir.format_registry, 'development5-subtree', 343 'breezy.bzr.knitpack_repo.RepositoryFormatPackDevelopment2Subtree', 344 help='Development format, subtree variant. Can convert data to and ' 345 'from pack-0.92-subtree (and anything compatible with ' 346 'pack-0.92-subtree) format repositories. Repositories and branches in ' 347 'this format can only be read by bzr.dev. Please read ' 348 'https://www.breezy-vcs.org/developers/development-repo.html ' 349 'before use.', 350 branch_format='breezy.bzr.branch.BzrBranchFormat7', 351 tree_format='breezy.bzr.workingtree_4.WorkingTreeFormat6', 352 experimental=True, 353 hidden=True, 354 ) 355 356register_metadir( 357 controldir.format_registry, 'development-colo', 358 'breezy.bzr.groupcompress_repo.RepositoryFormat2a', 359 help='The 2a format with experimental support for colocated branches.\n', 360 branch_format='breezy.bzr.branch.BzrBranchFormat7', 361 tree_format='breezy.bzr.workingtree_4.WorkingTreeFormat6', 362 experimental=True, 363 bzrdir_format='breezy.bzr.bzrdir.BzrDirMetaFormat1Colo', 364 hidden=True, 365 ) 366 367 368# And the development formats above will have aliased one of the following: 369 370# Finally, the current format. 371register_metadir(controldir.format_registry, '2a', 372 'breezy.bzr.groupcompress_repo.RepositoryFormat2a', 373 help='Format for the bzr 2.0 series.\n', 374 branch_format='breezy.bzr.branch.BzrBranchFormat7', 375 tree_format='breezy.bzr.workingtree_4.WorkingTreeFormat6', 376 experimental=False, 377 ) 378 379# The following format should be an alias for the rich root equivalent 380# of the default format 381 382controldir.format_registry.register_alias( 383 'default-rich-root', '2a', hidden=True) 384 385# The following format should is just an alias for the default bzr format. 386controldir.format_registry.register_alias('bzr', '2a') 387 388# The current format that is made on 'bzr init'. 389format_name = config.GlobalStack().get('default_format') 390controldir.format_registry.set_default(format_name) 391