1# Copyright (C) 2010, 2011, 2012 Canonical Ltd 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 17"""ControlDir is the basic control directory class. 18 19The ControlDir class is the base for the control directory used 20by all bzr and foreign formats. For the ".bzr" implementation, 21see breezy.bzrdir.BzrDir. 22 23""" 24 25from .lazy_import import lazy_import 26lazy_import(globals(), """ 27import textwrap 28 29from breezy import ( 30 branch as _mod_branch, 31 hooks, 32 revision as _mod_revision, 33 transport as _mod_transport, 34 trace, 35 ui, 36 urlutils, 37 ) 38from breezy.transport import local 39from breezy.push import ( 40 PushResult, 41 ) 42 43from breezy.i18n import gettext 44""") 45 46from . import ( 47 errors, 48 registry, 49 ) 50 51 52class MustHaveWorkingTree(errors.BzrError): 53 54 _fmt = "Branching '%(url)s'(%(format)s) must create a working tree." 55 56 def __init__(self, format, url): 57 errors.BzrError.__init__(self, format=format, url=url) 58 59 60class BranchReferenceLoop(errors.BzrError): 61 62 _fmt = "Can not create branch reference that points at branch itself." 63 64 def __init__(self, branch): 65 errors.BzrError.__init__(self, branch=branch) 66 67 68class ControlComponent(object): 69 """Abstract base class for control directory components. 70 71 This provides interfaces that are common across controldirs, 72 repositories, branches, and workingtree control directories. 73 74 They all expose two urls and transports: the *user* URL is the 75 one that stops above the control directory (eg .bzr) and that 76 should normally be used in messages, and the *control* URL is 77 under that in eg .bzr/checkout and is used to read the control 78 files. 79 80 This can be used as a mixin and is intended to fit with 81 foreign formats. 82 """ 83 84 @property 85 def control_transport(self): 86 raise NotImplementedError 87 88 @property 89 def control_url(self): 90 return self.control_transport.base 91 92 @property 93 def user_transport(self): 94 raise NotImplementedError 95 96 @property 97 def user_url(self): 98 return self.user_transport.base 99 100 101class ControlDir(ControlComponent): 102 """A control directory. 103 104 While this represents a generic control directory, there are a few 105 features that are present in this interface that are currently only 106 supported by one of its implementations, BzrDir. 107 108 These features (bound branches, stacked branches) are currently only 109 supported by Bazaar, but could be supported by other version control 110 systems as well. Implementations are required to raise the appropriate 111 exceptions when an operation is requested that is not supported. 112 113 This also makes life easier for API users who can rely on the 114 implementation always allowing a particular feature to be requested but 115 raising an exception when it is not supported, rather than requiring the 116 API users to check for magic attributes to see what features are supported. 117 """ 118 119 def can_convert_format(self): 120 """Return true if this controldir is one whose format we can convert 121 from.""" 122 return True 123 124 def list_branches(self): 125 """Return a sequence of all branches local to this control directory. 126 127 """ 128 return list(self.get_branches().values()) 129 130 def branch_names(self): 131 """List all branch names in this control directory. 132 133 :return: List of branch names 134 """ 135 try: 136 self.get_branch_reference() 137 except (errors.NotBranchError, errors.NoRepositoryPresent): 138 return [] 139 else: 140 return [""] 141 142 def get_branches(self): 143 """Get all branches in this control directory, as a dictionary. 144 145 :return: Dictionary mapping branch names to instances. 146 """ 147 try: 148 return {"": self.open_branch()} 149 except (errors.NotBranchError, errors.NoRepositoryPresent): 150 return {} 151 152 def is_control_filename(self, filename): 153 """True if filename is the name of a path which is reserved for 154 controldirs. 155 156 :param filename: A filename within the root transport of this 157 controldir. 158 159 This is true IF and ONLY IF the filename is part of the namespace reserved 160 for bzr control dirs. Currently this is the '.bzr' directory in the root 161 of the root_transport. it is expected that plugins will need to extend 162 this in the future - for instance to make bzr talk with svn working 163 trees. 164 """ 165 return self._format.is_control_filename(filename) 166 167 def needs_format_conversion(self, format=None): 168 """Return true if this controldir needs convert_format run on it. 169 170 For instance, if the repository format is out of date but the 171 branch and working tree are not, this should return True. 172 173 :param format: Optional parameter indicating a specific desired 174 format we plan to arrive at. 175 """ 176 raise NotImplementedError(self.needs_format_conversion) 177 178 def create_repository(self, shared=False): 179 """Create a new repository in this control directory. 180 181 :param shared: If a shared repository should be created 182 :return: The newly created repository 183 """ 184 raise NotImplementedError(self.create_repository) 185 186 def destroy_repository(self): 187 """Destroy the repository in this ControlDir.""" 188 raise NotImplementedError(self.destroy_repository) 189 190 def create_branch(self, name=None, repository=None, 191 append_revisions_only=None): 192 """Create a branch in this ControlDir. 193 194 :param name: Name of the colocated branch to create, None for 195 the user selected branch or "" for the active branch. 196 :param append_revisions_only: Whether this branch should only allow 197 appending new revisions to its history. 198 199 The controldirs format will control what branch format is created. 200 For more control see BranchFormatXX.create(a_controldir). 201 """ 202 raise NotImplementedError(self.create_branch) 203 204 def destroy_branch(self, name=None): 205 """Destroy a branch in this ControlDir. 206 207 :param name: Name of the branch to destroy, None for the 208 user selected branch or "" for the active branch. 209 :raise NotBranchError: When the branch does not exist 210 """ 211 raise NotImplementedError(self.destroy_branch) 212 213 def create_workingtree(self, revision_id=None, from_branch=None, 214 accelerator_tree=None, hardlink=False): 215 """Create a working tree at this ControlDir. 216 217 :param revision_id: create it as of this revision id. 218 :param from_branch: override controldir branch 219 (for lightweight checkouts) 220 :param accelerator_tree: A tree which can be used for retrieving file 221 contents more quickly than the revision tree, i.e. a workingtree. 222 The revision tree will be used for cases where accelerator_tree's 223 content is different. 224 """ 225 raise NotImplementedError(self.create_workingtree) 226 227 def destroy_workingtree(self): 228 """Destroy the working tree at this ControlDir. 229 230 Formats that do not support this may raise UnsupportedOperation. 231 """ 232 raise NotImplementedError(self.destroy_workingtree) 233 234 def destroy_workingtree_metadata(self): 235 """Destroy the control files for the working tree at this ControlDir. 236 237 The contents of working tree files are not affected. 238 Formats that do not support this may raise UnsupportedOperation. 239 """ 240 raise NotImplementedError(self.destroy_workingtree_metadata) 241 242 def find_branch_format(self, name=None): 243 """Find the branch 'format' for this controldir. 244 245 This might be a synthetic object for e.g. RemoteBranch and SVN. 246 """ 247 raise NotImplementedError(self.find_branch_format) 248 249 def get_branch_reference(self, name=None): 250 """Return the referenced URL for the branch in this controldir. 251 252 :param name: Optional colocated branch name 253 :raises NotBranchError: If there is no Branch. 254 :raises NoColocatedBranchSupport: If a branch name was specified 255 but colocated branches are not supported. 256 :return: The URL the branch in this controldir references if it is a 257 reference branch, or None for regular branches. 258 """ 259 if name is not None: 260 raise errors.NoColocatedBranchSupport(self) 261 return None 262 263 def set_branch_reference(self, target_branch, name=None): 264 """Set the referenced URL for the branch in this controldir. 265 266 :param name: Optional colocated branch name 267 :param target_branch: Branch to reference 268 :raises NoColocatedBranchSupport: If a branch name was specified 269 but colocated branches are not supported. 270 :return: The referencing branch 271 """ 272 raise NotImplementedError(self.set_branch_reference) 273 274 def open_branch(self, name=None, unsupported=False, 275 ignore_fallbacks=False, possible_transports=None): 276 """Open the branch object at this ControlDir if one is present. 277 278 :param unsupported: if True, then no longer supported branch formats can 279 still be opened. 280 :param ignore_fallbacks: Whether to open fallback repositories 281 :param possible_transports: Transports to use for opening e.g. 282 fallback repositories. 283 """ 284 raise NotImplementedError(self.open_branch) 285 286 def open_repository(self, _unsupported=False): 287 """Open the repository object at this ControlDir if one is present. 288 289 This will not follow the Branch object pointer - it's strictly a direct 290 open facility. Most client code should use open_branch().repository to 291 get at a repository. 292 293 :param _unsupported: a private parameter, not part of the api. 294 """ 295 raise NotImplementedError(self.open_repository) 296 297 def find_repository(self): 298 """Find the repository that should be used. 299 300 This does not require a branch as we use it to find the repo for 301 new branches as well as to hook existing branches up to their 302 repository. 303 """ 304 raise NotImplementedError(self.find_repository) 305 306 def open_workingtree(self, unsupported=False, 307 recommend_upgrade=True, from_branch=None): 308 """Open the workingtree object at this ControlDir if one is present. 309 310 :param recommend_upgrade: Optional keyword parameter, when True (the 311 default), emit through the ui module a recommendation that the user 312 upgrade the working tree when the workingtree being opened is old 313 (but still fully supported). 314 :param from_branch: override controldir branch (for lightweight 315 checkouts) 316 """ 317 raise NotImplementedError(self.open_workingtree) 318 319 def has_branch(self, name=None): 320 """Tell if this controldir contains a branch. 321 322 Note: if you're going to open the branch, you should just go ahead 323 and try, and not ask permission first. (This method just opens the 324 branch and discards it, and that's somewhat expensive.) 325 """ 326 try: 327 self.open_branch(name, ignore_fallbacks=True) 328 return True 329 except errors.NotBranchError: 330 return False 331 332 def _get_selected_branch(self): 333 """Return the name of the branch selected by the user. 334 335 :return: Name of the branch selected by the user, or "". 336 """ 337 branch = self.root_transport.get_segment_parameters().get("branch") 338 if branch is None: 339 branch = "" 340 return urlutils.unescape(branch) 341 342 def has_workingtree(self): 343 """Tell if this controldir contains a working tree. 344 345 This will still raise an exception if the controldir has a workingtree 346 that is remote & inaccessible. 347 348 Note: if you're going to open the working tree, you should just go ahead 349 and try, and not ask permission first. (This method just opens the 350 workingtree and discards it, and that's somewhat expensive.) 351 """ 352 try: 353 self.open_workingtree(recommend_upgrade=False) 354 return True 355 except errors.NoWorkingTree: 356 return False 357 358 def cloning_metadir(self, require_stacking=False): 359 """Produce a metadir suitable for cloning or sprouting with. 360 361 These operations may produce workingtrees (yes, even though they're 362 "cloning" something that doesn't have a tree), so a viable workingtree 363 format must be selected. 364 365 :require_stacking: If True, non-stackable formats will be upgraded 366 to similar stackable formats. 367 :returns: a ControlDirFormat with all component formats either set 368 appropriately or set to None if that component should not be 369 created. 370 """ 371 raise NotImplementedError(self.cloning_metadir) 372 373 def checkout_metadir(self): 374 """Produce a metadir suitable for checkouts of this controldir. 375 376 :returns: A ControlDirFormat with all component formats 377 either set appropriately or set to None if that component 378 should not be created. 379 """ 380 return self.cloning_metadir() 381 382 def sprout(self, url, revision_id=None, force_new_repo=False, 383 recurse='down', possible_transports=None, 384 accelerator_tree=None, hardlink=False, stacked=False, 385 source_branch=None, create_tree_if_local=True, 386 lossy=False): 387 """Create a copy of this controldir prepared for use as a new line of 388 development. 389 390 If url's last component does not exist, it will be created. 391 392 Attributes related to the identity of the source branch like 393 branch nickname will be cleaned, a working tree is created 394 whether one existed before or not; and a local branch is always 395 created. 396 397 :param revision_id: if revision_id is not None, then the clone 398 operation may tune itself to download less data. 399 :param accelerator_tree: A tree which can be used for retrieving file 400 contents more quickly than the revision tree, i.e. a workingtree. 401 The revision tree will be used for cases where accelerator_tree's 402 content is different. 403 :param hardlink: If true, hard-link files from accelerator_tree, 404 where possible. 405 :param stacked: If true, create a stacked branch referring to the 406 location of this control directory. 407 :param create_tree_if_local: If true, a working-tree will be created 408 when working locally. 409 """ 410 raise NotImplementedError(self.sprout) 411 412 def push_branch(self, source, revision_id=None, overwrite=False, 413 remember=False, create_prefix=False, lossy=False, 414 tag_selector=None): 415 """Push the source branch into this ControlDir.""" 416 br_to = None 417 # If we can open a branch, use its direct repository, otherwise see 418 # if there is a repository without a branch. 419 try: 420 br_to = self.open_branch() 421 except errors.NotBranchError: 422 # Didn't find a branch, can we find a repository? 423 repository_to = self.find_repository() 424 else: 425 # Found a branch, so we must have found a repository 426 repository_to = br_to.repository 427 428 push_result = PushResult() 429 push_result.source_branch = source 430 if br_to is None: 431 # We have a repository but no branch, copy the revisions, and then 432 # create a branch. 433 if revision_id is None: 434 # No revision supplied by the user, default to the branch 435 # revision 436 revision_id = source.last_revision() 437 repository_to.fetch(source.repository, revision_id=revision_id) 438 br_to = source.sprout( 439 self, revision_id=revision_id, lossy=lossy, 440 tag_selector=tag_selector) 441 if source.get_push_location() is None or remember: 442 # FIXME: Should be done only if we succeed ? -- vila 2012-01-18 443 source.set_push_location(br_to.base) 444 push_result.stacked_on = None 445 push_result.branch_push_result = None 446 push_result.old_revno = None 447 push_result.old_revid = _mod_revision.NULL_REVISION 448 push_result.target_branch = br_to 449 push_result.master_branch = None 450 push_result.workingtree_updated = False 451 else: 452 # We have successfully opened the branch, remember if necessary: 453 if source.get_push_location() is None or remember: 454 # FIXME: Should be done only if we succeed ? -- vila 2012-01-18 455 source.set_push_location(br_to.base) 456 try: 457 tree_to = self.open_workingtree() 458 except errors.NotLocalUrl: 459 push_result.branch_push_result = source.push( 460 br_to, overwrite, stop_revision=revision_id, lossy=lossy, 461 tag_selector=tag_selector) 462 push_result.workingtree_updated = False 463 except errors.NoWorkingTree: 464 push_result.branch_push_result = source.push( 465 br_to, overwrite, stop_revision=revision_id, lossy=lossy, 466 tag_selector=tag_selector) 467 push_result.workingtree_updated = None # Not applicable 468 else: 469 with tree_to.lock_write(): 470 push_result.branch_push_result = source.push( 471 tree_to.branch, overwrite, stop_revision=revision_id, 472 lossy=lossy, tag_selector=tag_selector) 473 tree_to.update() 474 push_result.workingtree_updated = True 475 push_result.old_revno = push_result.branch_push_result.old_revno 476 push_result.old_revid = push_result.branch_push_result.old_revid 477 push_result.target_branch = \ 478 push_result.branch_push_result.target_branch 479 return push_result 480 481 def _get_tree_branch(self, name=None): 482 """Return the branch and tree, if any, for this controldir. 483 484 :param name: Name of colocated branch to open. 485 486 Return None for tree if not present or inaccessible. 487 Raise NotBranchError if no branch is present. 488 :return: (tree, branch) 489 """ 490 try: 491 tree = self.open_workingtree() 492 except (errors.NoWorkingTree, errors.NotLocalUrl): 493 tree = None 494 branch = self.open_branch(name=name) 495 else: 496 if name is not None: 497 branch = self.open_branch(name=name) 498 else: 499 branch = tree.branch 500 return tree, branch 501 502 def get_config(self): 503 """Get configuration for this ControlDir.""" 504 raise NotImplementedError(self.get_config) 505 506 def check_conversion_target(self, target_format): 507 """Check that a controldir as a whole can be converted to a new format.""" 508 raise NotImplementedError(self.check_conversion_target) 509 510 def clone(self, url, revision_id=None, force_new_repo=False, 511 preserve_stacking=False, tag_selector=None): 512 """Clone this controldir and its contents to url verbatim. 513 514 :param url: The url create the clone at. If url's last component does 515 not exist, it will be created. 516 :param revision_id: The tip revision-id to use for any branch or 517 working tree. If not None, then the clone operation may tune 518 itself to download less data. 519 :param force_new_repo: Do not use a shared repository for the target 520 even if one is available. 521 :param preserve_stacking: When cloning a stacked branch, stack the 522 new branch on top of the other branch's stacked-on branch. 523 """ 524 return self.clone_on_transport(_mod_transport.get_transport(url), 525 revision_id=revision_id, 526 force_new_repo=force_new_repo, 527 preserve_stacking=preserve_stacking, 528 tag_selector=tag_selector) 529 530 def clone_on_transport(self, transport, revision_id=None, 531 force_new_repo=False, preserve_stacking=False, stacked_on=None, 532 create_prefix=False, use_existing_dir=True, no_tree=False, 533 tag_selector=None): 534 """Clone this controldir and its contents to transport verbatim. 535 536 :param transport: The transport for the location to produce the clone 537 at. If the target directory does not exist, it will be created. 538 :param revision_id: The tip revision-id to use for any branch or 539 working tree. If not None, then the clone operation may tune 540 itself to download less data. 541 :param force_new_repo: Do not use a shared repository for the target, 542 even if one is available. 543 :param preserve_stacking: When cloning a stacked branch, stack the 544 new branch on top of the other branch's stacked-on branch. 545 :param create_prefix: Create any missing directories leading up to 546 to_transport. 547 :param use_existing_dir: Use an existing directory if one exists. 548 :param no_tree: If set to true prevents creation of a working tree. 549 """ 550 raise NotImplementedError(self.clone_on_transport) 551 552 @classmethod 553 def find_controldirs(klass, transport, evaluate=None, list_current=None): 554 """Find control dirs recursively from current location. 555 556 This is intended primarily as a building block for more sophisticated 557 functionality, like finding trees under a directory, or finding 558 branches that use a given repository. 559 560 :param evaluate: An optional callable that yields recurse, value, 561 where recurse controls whether this controldir is recursed into 562 and value is the value to yield. By default, all bzrdirs 563 are recursed into, and the return value is the controldir. 564 :param list_current: if supplied, use this function to list the current 565 directory, instead of Transport.list_dir 566 :return: a generator of found bzrdirs, or whatever evaluate returns. 567 """ 568 if list_current is None: 569 def list_current(transport): 570 return transport.list_dir('') 571 if evaluate is None: 572 def evaluate(controldir): 573 return True, controldir 574 575 pending = [transport] 576 while len(pending) > 0: 577 current_transport = pending.pop() 578 recurse = True 579 try: 580 controldir = klass.open_from_transport(current_transport) 581 except (errors.NotBranchError, errors.PermissionDenied, 582 errors.UnknownFormatError): 583 pass 584 else: 585 recurse, value = evaluate(controldir) 586 yield value 587 try: 588 subdirs = list_current(current_transport) 589 except (errors.NoSuchFile, errors.PermissionDenied): 590 continue 591 if recurse: 592 for subdir in sorted(subdirs, reverse=True): 593 pending.append(current_transport.clone(subdir)) 594 595 @classmethod 596 def find_branches(klass, transport): 597 """Find all branches under a transport. 598 599 This will find all branches below the transport, including branches 600 inside other branches. Where possible, it will use 601 Repository.find_branches. 602 603 To list all the branches that use a particular Repository, see 604 Repository.find_branches 605 """ 606 def evaluate(controldir): 607 try: 608 repository = controldir.open_repository() 609 except errors.NoRepositoryPresent: 610 pass 611 else: 612 return False, ([], repository) 613 return True, (controldir.list_branches(), None) 614 ret = [] 615 for branches, repo in klass.find_controldirs( 616 transport, evaluate=evaluate): 617 if repo is not None: 618 ret.extend(repo.find_branches()) 619 if branches is not None: 620 ret.extend(branches) 621 return ret 622 623 @classmethod 624 def create_branch_and_repo(klass, base, force_new_repo=False, format=None): 625 """Create a new ControlDir, Branch and Repository at the url 'base'. 626 627 This will use the current default ControlDirFormat unless one is 628 specified, and use whatever 629 repository format that that uses via controldir.create_branch and 630 create_repository. If a shared repository is available that is used 631 preferentially. 632 633 The created Branch object is returned. 634 635 :param base: The URL to create the branch at. 636 :param force_new_repo: If True a new repository is always created. 637 :param format: If supplied, the format of branch to create. If not 638 supplied, the default is used. 639 """ 640 controldir = klass.create(base, format) 641 controldir._find_or_create_repository(force_new_repo) 642 return controldir.create_branch() 643 644 @classmethod 645 def create_branch_convenience(klass, base, force_new_repo=False, 646 force_new_tree=None, format=None, 647 possible_transports=None): 648 """Create a new ControlDir, Branch and Repository at the url 'base'. 649 650 This is a convenience function - it will use an existing repository 651 if possible, can be told explicitly whether to create a working tree or 652 not. 653 654 This will use the current default ControlDirFormat unless one is 655 specified, and use whatever 656 repository format that that uses via ControlDir.create_branch and 657 create_repository. If a shared repository is available that is used 658 preferentially. Whatever repository is used, its tree creation policy 659 is followed. 660 661 The created Branch object is returned. 662 If a working tree cannot be made due to base not being a file:// url, 663 no error is raised unless force_new_tree is True, in which case no 664 data is created on disk and NotLocalUrl is raised. 665 666 :param base: The URL to create the branch at. 667 :param force_new_repo: If True a new repository is always created. 668 :param force_new_tree: If True or False force creation of a tree or 669 prevent such creation respectively. 670 :param format: Override for the controldir format to create. 671 :param possible_transports: An optional reusable transports list. 672 """ 673 if force_new_tree: 674 # check for non local urls 675 t = _mod_transport.get_transport(base, possible_transports) 676 if not isinstance(t, local.LocalTransport): 677 raise errors.NotLocalUrl(base) 678 controldir = klass.create(base, format, possible_transports) 679 repo = controldir._find_or_create_repository(force_new_repo) 680 result = controldir.create_branch() 681 if force_new_tree or (repo.make_working_trees() and 682 force_new_tree is None): 683 try: 684 controldir.create_workingtree() 685 except errors.NotLocalUrl: 686 pass 687 return result 688 689 @classmethod 690 def create_standalone_workingtree(klass, base, format=None): 691 """Create a new ControlDir, WorkingTree, Branch and Repository at 'base'. 692 693 'base' must be a local path or a file:// url. 694 695 This will use the current default ControlDirFormat unless one is 696 specified, and use whatever 697 repository format that that uses for bzrdirformat.create_workingtree, 698 create_branch and create_repository. 699 700 :param format: Override for the controldir format to create. 701 :return: The WorkingTree object. 702 """ 703 t = _mod_transport.get_transport(base) 704 if not isinstance(t, local.LocalTransport): 705 raise errors.NotLocalUrl(base) 706 controldir = klass.create_branch_and_repo(base, 707 force_new_repo=True, 708 format=format).controldir 709 return controldir.create_workingtree() 710 711 @classmethod 712 def open_unsupported(klass, base): 713 """Open a branch which is not supported.""" 714 return klass.open(base, _unsupported=True) 715 716 @classmethod 717 def open(klass, base, possible_transports=None, probers=None, 718 _unsupported=False): 719 """Open an existing controldir, rooted at 'base' (url). 720 721 :param _unsupported: a private parameter to the ControlDir class. 722 """ 723 t = _mod_transport.get_transport(base, possible_transports) 724 return klass.open_from_transport(t, probers=probers, 725 _unsupported=_unsupported) 726 727 @classmethod 728 def open_from_transport(klass, transport, _unsupported=False, 729 probers=None): 730 """Open a controldir within a particular directory. 731 732 :param transport: Transport containing the controldir. 733 :param _unsupported: private. 734 """ 735 for hook in klass.hooks['pre_open']: 736 hook(transport) 737 # Keep initial base since 'transport' may be modified while following 738 # the redirections. 739 base = transport.base 740 741 def find_format(transport): 742 return transport, ControlDirFormat.find_format(transport, 743 probers=probers) 744 745 def redirected(transport, e, redirection_notice): 746 redirected_transport = transport._redirected_to(e.source, e.target) 747 if redirected_transport is None: 748 raise errors.NotBranchError(base) 749 trace.note(gettext('{0} is{1} redirected to {2}').format( 750 transport.base, e.permanently, redirected_transport.base)) 751 return redirected_transport 752 753 try: 754 transport, format = _mod_transport.do_catching_redirections( 755 find_format, transport, redirected) 756 except errors.TooManyRedirections: 757 raise errors.NotBranchError(base) 758 759 format.check_support_status(_unsupported) 760 return format.open(transport, _found=True) 761 762 @classmethod 763 def open_containing(klass, url, possible_transports=None): 764 """Open an existing branch which contains url. 765 766 :param url: url to search from. 767 768 See open_containing_from_transport for more detail. 769 """ 770 transport = _mod_transport.get_transport(url, possible_transports) 771 return klass.open_containing_from_transport(transport) 772 773 @classmethod 774 def open_containing_from_transport(klass, a_transport): 775 """Open an existing branch which contains a_transport.base. 776 777 This probes for a branch at a_transport, and searches upwards from there. 778 779 Basically we keep looking up until we find the control directory or 780 run into the root. If there isn't one, raises NotBranchError. 781 If there is one and it is either an unrecognised format or an unsupported 782 format, UnknownFormatError or UnsupportedFormatError are raised. 783 If there is one, it is returned, along with the unused portion of url. 784 785 :return: The ControlDir that contains the path, and a Unicode path 786 for the rest of the URL. 787 """ 788 # this gets the normalised url back. I.e. '.' -> the full path. 789 url = a_transport.base 790 while True: 791 try: 792 result = klass.open_from_transport(a_transport) 793 return result, urlutils.unescape(a_transport.relpath(url)) 794 except errors.NotBranchError: 795 pass 796 except errors.PermissionDenied: 797 pass 798 try: 799 new_t = a_transport.clone('..') 800 except urlutils.InvalidURLJoin: 801 # reached the root, whatever that may be 802 raise errors.NotBranchError(path=url) 803 if new_t.base == a_transport.base: 804 # reached the root, whatever that may be 805 raise errors.NotBranchError(path=url) 806 a_transport = new_t 807 808 @classmethod 809 def open_tree_or_branch(klass, location, name=None): 810 """Return the branch and working tree at a location. 811 812 If there is no tree at the location, tree will be None. 813 If there is no branch at the location, an exception will be 814 raised 815 :return: (tree, branch) 816 """ 817 controldir = klass.open(location) 818 return controldir._get_tree_branch(name=name) 819 820 @classmethod 821 def open_containing_tree_or_branch(klass, location, 822 possible_transports=None): 823 """Return the branch and working tree contained by a location. 824 825 Returns (tree, branch, relpath). 826 If there is no tree at containing the location, tree will be None. 827 If there is no branch containing the location, an exception will be 828 raised 829 relpath is the portion of the path that is contained by the branch. 830 """ 831 controldir, relpath = klass.open_containing(location, 832 possible_transports=possible_transports) 833 tree, branch = controldir._get_tree_branch() 834 return tree, branch, relpath 835 836 @classmethod 837 def open_containing_tree_branch_or_repository(klass, location): 838 """Return the working tree, branch and repo contained by a location. 839 840 Returns (tree, branch, repository, relpath). 841 If there is no tree containing the location, tree will be None. 842 If there is no branch containing the location, branch will be None. 843 If there is no repository containing the location, repository will be 844 None. 845 relpath is the portion of the path that is contained by the innermost 846 ControlDir. 847 848 If no tree, branch or repository is found, a NotBranchError is raised. 849 """ 850 controldir, relpath = klass.open_containing(location) 851 try: 852 tree, branch = controldir._get_tree_branch() 853 except errors.NotBranchError: 854 try: 855 repo = controldir.find_repository() 856 return None, None, repo, relpath 857 except (errors.NoRepositoryPresent): 858 raise errors.NotBranchError(location) 859 return tree, branch, branch.repository, relpath 860 861 @classmethod 862 def create(klass, base, format=None, possible_transports=None): 863 """Create a new ControlDir at the url 'base'. 864 865 :param format: If supplied, the format of branch to create. If not 866 supplied, the default is used. 867 :param possible_transports: If supplied, a list of transports that 868 can be reused to share a remote connection. 869 """ 870 if klass is not ControlDir: 871 raise AssertionError("ControlDir.create always creates the" 872 "default format, not one of %r" % klass) 873 t = _mod_transport.get_transport(base, possible_transports) 874 t.ensure_base() 875 if format is None: 876 format = ControlDirFormat.get_default_format() 877 return format.initialize_on_transport(t) 878 879 880class ControlDirHooks(hooks.Hooks): 881 """Hooks for ControlDir operations.""" 882 883 def __init__(self): 884 """Create the default hooks.""" 885 hooks.Hooks.__init__(self, "breezy.controldir", "ControlDir.hooks") 886 self.add_hook('pre_open', 887 "Invoked before attempting to open a ControlDir with the transport " 888 "that the open will use.", (1, 14)) 889 self.add_hook('post_repo_init', 890 "Invoked after a repository has been initialized. " 891 "post_repo_init is called with a " 892 "breezy.controldir.RepoInitHookParams.", 893 (2, 2)) 894 895 896# install the default hooks 897ControlDir.hooks = ControlDirHooks() 898 899 900class ControlComponentFormat(object): 901 """A component that can live inside of a control directory.""" 902 903 upgrade_recommended = False 904 905 def get_format_description(self): 906 """Return the short description for this format.""" 907 raise NotImplementedError(self.get_format_description) 908 909 def is_supported(self): 910 """Is this format supported? 911 912 Supported formats must be initializable and openable. 913 Unsupported formats may not support initialization or committing or 914 some other features depending on the reason for not being supported. 915 """ 916 return True 917 918 def check_support_status(self, allow_unsupported, recommend_upgrade=True, 919 basedir=None): 920 """Give an error or warning on old formats. 921 922 :param allow_unsupported: If true, allow opening 923 formats that are strongly deprecated, and which may 924 have limited functionality. 925 926 :param recommend_upgrade: If true (default), warn 927 the user through the ui object that they may wish 928 to upgrade the object. 929 """ 930 if not allow_unsupported and not self.is_supported(): 931 # see open_downlevel to open legacy branches. 932 raise errors.UnsupportedFormatError(format=self) 933 if recommend_upgrade and self.upgrade_recommended: 934 ui.ui_factory.recommend_upgrade( 935 self.get_format_description(), basedir) 936 937 @classmethod 938 def get_format_string(cls): 939 raise NotImplementedError(cls.get_format_string) 940 941 942class ControlComponentFormatRegistry(registry.FormatRegistry): 943 """A registry for control components (branch, workingtree, repository).""" 944 945 def __init__(self, other_registry=None): 946 super(ControlComponentFormatRegistry, self).__init__(other_registry) 947 self._extra_formats = [] 948 949 def register(self, format): 950 """Register a new format.""" 951 super(ControlComponentFormatRegistry, self).register( 952 format.get_format_string(), format) 953 954 def remove(self, format): 955 """Remove a registered format.""" 956 super(ControlComponentFormatRegistry, self).remove( 957 format.get_format_string()) 958 959 def register_extra(self, format): 960 """Register a format that can not be used in a metadir. 961 962 This is mainly useful to allow custom repository formats, such as older 963 Bazaar formats and foreign formats, to be tested. 964 """ 965 self._extra_formats.append(registry._ObjectGetter(format)) 966 967 def remove_extra(self, format): 968 """Remove an extra format. 969 """ 970 self._extra_formats.remove(registry._ObjectGetter(format)) 971 972 def register_extra_lazy(self, module_name, member_name): 973 """Register a format lazily. 974 """ 975 self._extra_formats.append( 976 registry._LazyObjectGetter(module_name, member_name)) 977 978 def _get_extra(self): 979 """Return getters for extra formats, not usable in meta directories.""" 980 return [getter.get_obj for getter in self._extra_formats] 981 982 def _get_all_lazy(self): 983 """Return getters for all formats, even those not usable in metadirs.""" 984 result = [self._dict[name].get_obj for name in self.keys()] 985 result.extend(self._get_extra()) 986 return result 987 988 def _get_all(self): 989 """Return all formats, even those not usable in metadirs.""" 990 result = [] 991 for getter in self._get_all_lazy(): 992 fmt = getter() 993 if callable(fmt): 994 fmt = fmt() 995 result.append(fmt) 996 return result 997 998 def _get_all_modules(self): 999 """Return a set of the modules providing objects.""" 1000 modules = set() 1001 for name in self.keys(): 1002 modules.add(self._get_module(name)) 1003 for getter in self._extra_formats: 1004 modules.add(getter.get_module()) 1005 return modules 1006 1007 1008class Converter(object): 1009 """Converts a disk format object from one format to another.""" 1010 1011 def convert(self, to_convert, pb): 1012 """Perform the conversion of to_convert, giving feedback via pb. 1013 1014 :param to_convert: The disk object to convert. 1015 :param pb: a progress bar to use for progress information. 1016 """ 1017 1018 def step(self, message): 1019 """Update the pb by a step.""" 1020 self.count += 1 1021 self.pb.update(message, self.count, self.total) 1022 1023 1024class ControlDirFormat(object): 1025 """An encapsulation of the initialization and open routines for a format. 1026 1027 Formats provide three things: 1028 * An initialization routine, 1029 * a format string, 1030 * an open routine. 1031 1032 Formats are placed in a dict by their format string for reference 1033 during controldir opening. These should be subclasses of ControlDirFormat 1034 for consistency. 1035 1036 Once a format is deprecated, just deprecate the initialize and open 1037 methods on the format class. Do not deprecate the object, as the 1038 object will be created every system load. 1039 1040 :cvar colocated_branches: Whether this formats supports colocated branches. 1041 :cvar supports_workingtrees: This control directory can co-exist with a 1042 working tree. 1043 """ 1044 1045 _default_format = None 1046 """The default format used for new control directories.""" 1047 1048 _probers = [] 1049 """The registered format probers, e.g. BzrProber. 1050 1051 This is a list of Prober-derived classes. 1052 """ 1053 1054 colocated_branches = False 1055 """Whether co-located branches are supported for this control dir format. 1056 """ 1057 1058 supports_workingtrees = True 1059 """Whether working trees can exist in control directories of this format. 1060 """ 1061 1062 fixed_components = False 1063 """Whether components can not change format independent of the control dir. 1064 """ 1065 1066 upgrade_recommended = False 1067 """Whether an upgrade from this format is recommended.""" 1068 1069 def get_format_description(self): 1070 """Return the short description for this format.""" 1071 raise NotImplementedError(self.get_format_description) 1072 1073 def get_converter(self, format=None): 1074 """Return the converter to use to convert controldirs needing converts. 1075 1076 This returns a breezy.controldir.Converter object. 1077 1078 This should return the best upgrader to step this format towards the 1079 current default format. In the case of plugins we can/should provide 1080 some means for them to extend the range of returnable converters. 1081 1082 :param format: Optional format to override the default format of the 1083 library. 1084 """ 1085 raise NotImplementedError(self.get_converter) 1086 1087 def is_supported(self): 1088 """Is this format supported? 1089 1090 Supported formats must be openable. 1091 Unsupported formats may not support initialization or committing or 1092 some other features depending on the reason for not being supported. 1093 """ 1094 return True 1095 1096 def is_initializable(self): 1097 """Whether new control directories of this format can be initialized. 1098 """ 1099 return self.is_supported() 1100 1101 def check_support_status(self, allow_unsupported, recommend_upgrade=True, 1102 basedir=None): 1103 """Give an error or warning on old formats. 1104 1105 :param allow_unsupported: If true, allow opening 1106 formats that are strongly deprecated, and which may 1107 have limited functionality. 1108 1109 :param recommend_upgrade: If true (default), warn 1110 the user through the ui object that they may wish 1111 to upgrade the object. 1112 """ 1113 if not allow_unsupported and not self.is_supported(): 1114 # see open_downlevel to open legacy branches. 1115 raise errors.UnsupportedFormatError(format=self) 1116 if recommend_upgrade and self.upgrade_recommended: 1117 ui.ui_factory.recommend_upgrade( 1118 self.get_format_description(), basedir) 1119 1120 def same_model(self, target_format): 1121 return (self.repository_format.rich_root_data == 1122 target_format.rich_root_data) 1123 1124 @classmethod 1125 def register_prober(klass, prober): 1126 """Register a prober that can look for a control dir. 1127 1128 """ 1129 klass._probers.append(prober) 1130 1131 @classmethod 1132 def unregister_prober(klass, prober): 1133 """Unregister a prober. 1134 1135 """ 1136 klass._probers.remove(prober) 1137 1138 def __str__(self): 1139 # Trim the newline 1140 return self.get_format_description().rstrip() 1141 1142 @classmethod 1143 def all_probers(klass): 1144 return klass._probers 1145 1146 @classmethod 1147 def known_formats(klass): 1148 """Return all the known formats. 1149 """ 1150 result = [] 1151 for prober_kls in klass.all_probers(): 1152 result.extend(prober_kls.known_formats()) 1153 return result 1154 1155 @classmethod 1156 def find_format(klass, transport, probers=None): 1157 """Return the format present at transport.""" 1158 if probers is None: 1159 probers = sorted( 1160 klass.all_probers(), 1161 key=lambda prober: prober.priority(transport)) 1162 for prober_kls in probers: 1163 prober = prober_kls() 1164 try: 1165 return prober.probe_transport(transport) 1166 except errors.NotBranchError: 1167 # this format does not find a control dir here. 1168 pass 1169 raise errors.NotBranchError(path=transport.base) 1170 1171 def initialize(self, url, possible_transports=None): 1172 """Create a control dir at this url and return an opened copy. 1173 1174 While not deprecated, this method is very specific and its use will 1175 lead to many round trips to setup a working environment. See 1176 initialize_on_transport_ex for a [nearly] all-in-one method. 1177 1178 Subclasses should typically override initialize_on_transport 1179 instead of this method. 1180 """ 1181 return self.initialize_on_transport( 1182 _mod_transport.get_transport(url, possible_transports)) 1183 1184 def initialize_on_transport(self, transport): 1185 """Initialize a new controldir in the base directory of a Transport.""" 1186 raise NotImplementedError(self.initialize_on_transport) 1187 1188 def initialize_on_transport_ex(self, transport, use_existing_dir=False, 1189 create_prefix=False, force_new_repo=False, stacked_on=None, 1190 stack_on_pwd=None, repo_format_name=None, make_working_trees=None, 1191 shared_repo=False, vfs_only=False): 1192 """Create this format on transport. 1193 1194 The directory to initialize will be created. 1195 1196 :param force_new_repo: Do not use a shared repository for the target, 1197 even if one is available. 1198 :param create_prefix: Create any missing directories leading up to 1199 to_transport. 1200 :param use_existing_dir: Use an existing directory if one exists. 1201 :param stacked_on: A url to stack any created branch on, None to follow 1202 any target stacking policy. 1203 :param stack_on_pwd: If stack_on is relative, the location it is 1204 relative to. 1205 :param repo_format_name: If non-None, a repository will be 1206 made-or-found. Should none be found, or if force_new_repo is True 1207 the repo_format_name is used to select the format of repository to 1208 create. 1209 :param make_working_trees: Control the setting of make_working_trees 1210 for a new shared repository when one is made. None to use whatever 1211 default the format has. 1212 :param shared_repo: Control whether made repositories are shared or 1213 not. 1214 :param vfs_only: If True do not attempt to use a smart server 1215 :return: repo, controldir, require_stacking, repository_policy. repo is 1216 None if none was created or found, controldir is always valid. 1217 require_stacking is the result of examining the stacked_on 1218 parameter and any stacking policy found for the target. 1219 """ 1220 raise NotImplementedError(self.initialize_on_transport_ex) 1221 1222 def network_name(self): 1223 """A simple byte string uniquely identifying this format for RPC calls. 1224 1225 Bzr control formats use this disk format string to identify the format 1226 over the wire. Its possible that other control formats have more 1227 complex detection requirements, so we permit them to use any unique and 1228 immutable string they desire. 1229 """ 1230 raise NotImplementedError(self.network_name) 1231 1232 def open(self, transport, _found=False): 1233 """Return an instance of this format for the dir transport points at. 1234 """ 1235 raise NotImplementedError(self.open) 1236 1237 @classmethod 1238 def _set_default_format(klass, format): 1239 """Set default format (for testing behavior of defaults only)""" 1240 klass._default_format = format 1241 1242 @classmethod 1243 def get_default_format(klass): 1244 """Return the current default format.""" 1245 return klass._default_format 1246 1247 def supports_transport(self, transport): 1248 """Check if this format can be opened over a particular transport. 1249 """ 1250 raise NotImplementedError(self.supports_transport) 1251 1252 @classmethod 1253 def is_control_filename(klass, filename): 1254 """True if filename is the name of a path which is reserved for 1255 controldirs. 1256 1257 :param filename: A filename within the root transport of this 1258 controldir. 1259 1260 This is true IF and ONLY IF the filename is part of the namespace reserved 1261 for bzr control dirs. Currently this is the '.bzr' directory in the root 1262 of the root_transport. it is expected that plugins will need to extend 1263 this in the future - for instance to make bzr talk with svn working 1264 trees. 1265 """ 1266 raise NotImplementedError(self.is_control_filename) 1267 1268 1269class Prober(object): 1270 """Abstract class that can be used to detect a particular kind of 1271 control directory. 1272 1273 At the moment this just contains a single method to probe a particular 1274 transport, but it may be extended in the future to e.g. avoid 1275 multiple levels of probing for Subversion repositories. 1276 1277 See BzrProber and RemoteBzrProber in breezy.bzrdir for the 1278 probers that detect .bzr/ directories and Bazaar smart servers, 1279 respectively. 1280 1281 Probers should be registered using the register_prober methods on 1282 ControlDirFormat. 1283 """ 1284 1285 def probe_transport(self, transport): 1286 """Return the controldir style format present in a directory. 1287 1288 :raise UnknownFormatError: If a control dir was found but is 1289 in an unknown format. 1290 :raise NotBranchError: If no control directory was found. 1291 :return: A ControlDirFormat instance. 1292 """ 1293 raise NotImplementedError(self.probe_transport) 1294 1295 @classmethod 1296 def known_formats(klass): 1297 """Return the control dir formats known by this prober. 1298 1299 Multiple probers can return the same formats, so this should 1300 return a set. 1301 1302 :return: A set of known formats. 1303 """ 1304 raise NotImplementedError(klass.known_formats) 1305 1306 @classmethod 1307 def priority(klass, transport): 1308 """Priority of this prober. 1309 1310 A lower value means the prober gets checked first. 1311 1312 Other conventions: 1313 1314 -10: This is a "server" prober 1315 0: No priority set 1316 10: This is a regular file-based prober 1317 100: This is a prober for an unsupported format 1318 """ 1319 return 0 1320 1321 1322class ControlDirFormatInfo(object): 1323 1324 def __init__(self, native, deprecated, hidden, experimental): 1325 self.deprecated = deprecated 1326 self.native = native 1327 self.hidden = hidden 1328 self.experimental = experimental 1329 1330 1331class ControlDirFormatRegistry(registry.Registry): 1332 """Registry of user-selectable ControlDir subformats. 1333 1334 Differs from ControlDirFormat._formats in that it provides sub-formats, 1335 e.g. BzrDirMeta1 with weave repository. Also, it's more user-oriented. 1336 """ 1337 1338 def __init__(self): 1339 """Create a ControlDirFormatRegistry.""" 1340 self._registration_order = list() 1341 super(ControlDirFormatRegistry, self).__init__() 1342 1343 def register(self, key, factory, help, native=True, deprecated=False, 1344 hidden=False, experimental=False): 1345 """Register a ControlDirFormat factory. 1346 1347 The factory must be a callable that takes one parameter: the key. 1348 It must produce an instance of the ControlDirFormat when called. 1349 1350 This function mainly exists to prevent the info object from being 1351 supplied directly. 1352 """ 1353 registry.Registry.register(self, key, factory, help, 1354 ControlDirFormatInfo(native, deprecated, hidden, experimental)) 1355 self._registration_order.append(key) 1356 1357 def register_alias(self, key, target, hidden=False): 1358 """Register a format alias. 1359 1360 :param key: Alias name 1361 :param target: Target format 1362 :param hidden: Whether the alias is hidden 1363 """ 1364 info = self.get_info(target) 1365 registry.Registry.register_alias(self, key, target, 1366 ControlDirFormatInfo( 1367 native=info.native, deprecated=info.deprecated, 1368 hidden=hidden, experimental=info.experimental)) 1369 1370 def register_lazy(self, key, module_name, member_name, help, native=True, 1371 deprecated=False, hidden=False, experimental=False): 1372 registry.Registry.register_lazy(self, key, module_name, member_name, 1373 help, ControlDirFormatInfo(native, deprecated, hidden, experimental)) 1374 self._registration_order.append(key) 1375 1376 def set_default(self, key): 1377 """Set the 'default' key to be a clone of the supplied key. 1378 1379 This method must be called once and only once. 1380 """ 1381 self.register_alias('default', key) 1382 1383 def set_default_repository(self, key): 1384 """Set the FormatRegistry default and Repository default. 1385 1386 This is a transitional method while Repository.set_default_format 1387 is deprecated. 1388 """ 1389 if 'default' in self: 1390 self.remove('default') 1391 self.set_default(key) 1392 format = self.get('default')() 1393 1394 def make_controldir(self, key): 1395 return self.get(key)() 1396 1397 def help_topic(self, topic): 1398 output = "" 1399 default_realkey = None 1400 default_help = self.get_help('default') 1401 help_pairs = [] 1402 for key in self._registration_order: 1403 if key == 'default': 1404 continue 1405 help = self.get_help(key) 1406 if help == default_help: 1407 default_realkey = key 1408 else: 1409 help_pairs.append((key, help)) 1410 1411 def wrapped(key, help, info): 1412 if info.native: 1413 help = '(native) ' + help 1414 return ':%s:\n%s\n\n' % (key, 1415 textwrap.fill(help, initial_indent=' ', 1416 subsequent_indent=' ', 1417 break_long_words=False)) 1418 if default_realkey is not None: 1419 output += wrapped(default_realkey, '(default) %s' % default_help, 1420 self.get_info('default')) 1421 deprecated_pairs = [] 1422 experimental_pairs = [] 1423 for key, help in help_pairs: 1424 info = self.get_info(key) 1425 if info.hidden: 1426 continue 1427 elif info.deprecated: 1428 deprecated_pairs.append((key, help)) 1429 elif info.experimental: 1430 experimental_pairs.append((key, help)) 1431 else: 1432 output += wrapped(key, help, info) 1433 output += "\nSee :doc:`formats-help` for more about storage formats." 1434 other_output = "" 1435 if len(experimental_pairs) > 0: 1436 other_output += "Experimental formats are shown below.\n\n" 1437 for key, help in experimental_pairs: 1438 info = self.get_info(key) 1439 other_output += wrapped(key, help, info) 1440 else: 1441 other_output += \ 1442 "No experimental formats are available.\n\n" 1443 if len(deprecated_pairs) > 0: 1444 other_output += "\nDeprecated formats are shown below.\n\n" 1445 for key, help in deprecated_pairs: 1446 info = self.get_info(key) 1447 other_output += wrapped(key, help, info) 1448 else: 1449 other_output += \ 1450 "\nNo deprecated formats are available.\n\n" 1451 other_output += \ 1452 "\nSee :doc:`formats-help` for more about storage formats." 1453 1454 if topic == 'other-formats': 1455 return other_output 1456 else: 1457 return output 1458 1459 1460class RepoInitHookParams(object): 1461 """Object holding parameters passed to `*_repo_init` hooks. 1462 1463 There are 4 fields that hooks may wish to access: 1464 1465 :ivar repository: Repository created 1466 :ivar format: Repository format 1467 :ivar bzrdir: The controldir for the repository 1468 :ivar shared: The repository is shared 1469 """ 1470 1471 def __init__(self, repository, format, controldir, shared): 1472 """Create a group of RepoInitHook parameters. 1473 1474 :param repository: Repository created 1475 :param format: Repository format 1476 :param controldir: The controldir for the repository 1477 :param shared: The repository is shared 1478 """ 1479 self.repository = repository 1480 self.format = format 1481 self.controldir = controldir 1482 self.shared = shared 1483 1484 def __eq__(self, other): 1485 return self.__dict__ == other.__dict__ 1486 1487 def __repr__(self): 1488 if self.repository: 1489 return "<%s for %s>" % (self.__class__.__name__, 1490 self.repository) 1491 else: 1492 return "<%s for %s>" % (self.__class__.__name__, 1493 self.controldir) 1494 1495 1496def is_control_filename(filename): 1497 """Check if filename is used for control directories.""" 1498 # TODO(jelmer): Instead, have a function that returns all control 1499 # filenames. 1500 for key, format in format_registry.items(): 1501 if format().is_control_filename(filename): 1502 return True 1503 else: 1504 return False 1505 1506 1507class RepositoryAcquisitionPolicy(object): 1508 """Abstract base class for repository acquisition policies. 1509 1510 A repository acquisition policy decides how a ControlDir acquires a repository 1511 for a branch that is being created. The most basic policy decision is 1512 whether to create a new repository or use an existing one. 1513 """ 1514 1515 def __init__(self, stack_on, stack_on_pwd, require_stacking): 1516 """Constructor. 1517 1518 :param stack_on: A location to stack on 1519 :param stack_on_pwd: If stack_on is relative, the location it is 1520 relative to. 1521 :param require_stacking: If True, it is a failure to not stack. 1522 """ 1523 self._stack_on = stack_on 1524 self._stack_on_pwd = stack_on_pwd 1525 self._require_stacking = require_stacking 1526 1527 def configure_branch(self, branch): 1528 """Apply any configuration data from this policy to the branch. 1529 1530 Default implementation sets repository stacking. 1531 """ 1532 if self._stack_on is None: 1533 return 1534 if self._stack_on_pwd is None: 1535 stack_on = self._stack_on 1536 else: 1537 try: 1538 stack_on = urlutils.rebase_url(self._stack_on, 1539 self._stack_on_pwd, 1540 branch.user_url) 1541 except urlutils.InvalidRebaseURLs: 1542 stack_on = self._get_full_stack_on() 1543 try: 1544 branch.set_stacked_on_url(stack_on) 1545 except (_mod_branch.UnstackableBranchFormat, 1546 errors.UnstackableRepositoryFormat): 1547 if self._require_stacking: 1548 raise 1549 1550 def requires_stacking(self): 1551 """Return True if this policy requires stacking.""" 1552 return self._stack_on is not None and self._require_stacking 1553 1554 def _get_full_stack_on(self): 1555 """Get a fully-qualified URL for the stack_on location.""" 1556 if self._stack_on is None: 1557 return None 1558 if self._stack_on_pwd is None: 1559 return self._stack_on 1560 else: 1561 return urlutils.join(self._stack_on_pwd, self._stack_on) 1562 1563 def _add_fallback(self, repository, possible_transports=None): 1564 """Add a fallback to the supplied repository, if stacking is set.""" 1565 stack_on = self._get_full_stack_on() 1566 if stack_on is None: 1567 return 1568 try: 1569 stacked_dir = ControlDir.open( 1570 stack_on, possible_transports=possible_transports) 1571 except errors.JailBreak: 1572 # We keep the stacking details, but we are in the server code so 1573 # actually stacking is not needed. 1574 return 1575 try: 1576 stacked_repo = stacked_dir.open_branch().repository 1577 except errors.NotBranchError: 1578 stacked_repo = stacked_dir.open_repository() 1579 try: 1580 repository.add_fallback_repository(stacked_repo) 1581 except errors.UnstackableRepositoryFormat: 1582 if self._require_stacking: 1583 raise 1584 else: 1585 self._require_stacking = True 1586 1587 def acquire_repository(self, make_working_trees=None, shared=False, 1588 possible_transports=None): 1589 """Acquire a repository for this controlrdir. 1590 1591 Implementations may create a new repository or use a pre-exising 1592 repository. 1593 1594 :param make_working_trees: If creating a repository, set 1595 make_working_trees to this value (if non-None) 1596 :param shared: If creating a repository, make it shared if True 1597 :return: A repository, is_new_flag (True if the repository was 1598 created). 1599 """ 1600 raise NotImplementedError( 1601 RepositoryAcquisitionPolicy.acquire_repository) 1602 1603 1604# Please register new formats after old formats so that formats 1605# appear in chronological order and format descriptions can build 1606# on previous ones. 1607format_registry = ControlDirFormatRegistry() 1608 1609network_format_registry = registry.FormatRegistry() 1610"""Registry of formats indexed by their network name. 1611 1612The network name for a ControlDirFormat is an identifier that can be used when 1613referring to formats with smart server operations. See 1614ControlDirFormat.network_name() for more detail. 1615""" 1616