~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/bzrdir.py

  • Committer: Patch Queue Manager
  • Date: 2011-10-14 11:14:25 UTC
  • mfrom: (6207.3.11 use-controldir)
  • Revision ID: pqm@pqm.ubuntu.com-20111014111425-c7nzqujggvlsd9zz
(jelmer) Move static/class methods from BzrDir to ControlDir. (Jelmer
 Vernooij)

Show diffs side-by-side

added added

removed removed

Lines of Context:
66
66
from bzrlib import (
67
67
    config,
68
68
    controldir,
69
 
    hooks,
70
69
    registry,
71
70
    )
72
71
from bzrlib.symbol_versioning import (
233
232
        t = _mod_transport.get_transport(url)
234
233
        t.ensure_base()
235
234
 
236
 
    @staticmethod
237
 
    def find_bzrdirs(transport, evaluate=None, list_current=None):
238
 
        """Find bzrdirs recursively from current location.
239
 
 
240
 
        This is intended primarily as a building block for more sophisticated
241
 
        functionality, like finding trees under a directory, or finding
242
 
        branches that use a given repository.
243
 
 
244
 
        :param evaluate: An optional callable that yields recurse, value,
245
 
            where recurse controls whether this bzrdir is recursed into
246
 
            and value is the value to yield.  By default, all bzrdirs
247
 
            are recursed into, and the return value is the bzrdir.
248
 
        :param list_current: if supplied, use this function to list the current
249
 
            directory, instead of Transport.list_dir
250
 
        :return: a generator of found bzrdirs, or whatever evaluate returns.
251
 
        """
252
 
        if list_current is None:
253
 
            def list_current(transport):
254
 
                return transport.list_dir('')
255
 
        if evaluate is None:
256
 
            def evaluate(bzrdir):
257
 
                return True, bzrdir
258
 
 
259
 
        pending = [transport]
260
 
        while len(pending) > 0:
261
 
            current_transport = pending.pop()
262
 
            recurse = True
263
 
            try:
264
 
                bzrdir = BzrDir.open_from_transport(current_transport)
265
 
            except (errors.NotBranchError, errors.PermissionDenied):
266
 
                pass
267
 
            else:
268
 
                recurse, value = evaluate(bzrdir)
269
 
                yield value
270
 
            try:
271
 
                subdirs = list_current(current_transport)
272
 
            except (errors.NoSuchFile, errors.PermissionDenied):
273
 
                continue
274
 
            if recurse:
275
 
                for subdir in sorted(subdirs, reverse=True):
276
 
                    pending.append(current_transport.clone(subdir))
277
 
 
278
 
    @staticmethod
279
 
    def find_branches(transport):
280
 
        """Find all branches under a transport.
281
 
 
282
 
        This will find all branches below the transport, including branches
283
 
        inside other branches.  Where possible, it will use
284
 
        Repository.find_branches.
285
 
 
286
 
        To list all the branches that use a particular Repository, see
287
 
        Repository.find_branches
288
 
        """
289
 
        def evaluate(bzrdir):
290
 
            try:
291
 
                repository = bzrdir.open_repository()
292
 
            except errors.NoRepositoryPresent:
293
 
                pass
294
 
            else:
295
 
                return False, ([], repository)
296
 
            return True, (bzrdir.list_branches(), None)
297
 
        ret = []
298
 
        for branches, repo in BzrDir.find_bzrdirs(transport,
299
 
                                                  evaluate=evaluate):
300
 
            if repo is not None:
301
 
                ret.extend(repo.find_branches())
302
 
            if branches is not None:
303
 
                ret.extend(branches)
304
 
        return ret
305
 
 
306
 
    @staticmethod
307
 
    def create_branch_and_repo(base, force_new_repo=False, format=None):
308
 
        """Create a new BzrDir, Branch and Repository at the url 'base'.
309
 
 
310
 
        This will use the current default BzrDirFormat unless one is
311
 
        specified, and use whatever
312
 
        repository format that that uses via bzrdir.create_branch and
313
 
        create_repository. If a shared repository is available that is used
314
 
        preferentially.
315
 
 
316
 
        The created Branch object is returned.
317
 
 
318
 
        :param base: The URL to create the branch at.
319
 
        :param force_new_repo: If True a new repository is always created.
320
 
        :param format: If supplied, the format of branch to create.  If not
321
 
            supplied, the default is used.
322
 
        """
323
 
        bzrdir = BzrDir.create(base, format)
324
 
        bzrdir._find_or_create_repository(force_new_repo)
325
 
        return bzrdir.create_branch()
326
 
 
327
235
    def determine_repository_policy(self, force_new_repo=False, stack_on=None,
328
236
                                    stack_on_pwd=None, require_stacking=False):
329
237
        """Return an object representing a policy to use.
544
452
                    stacked=stacked)
545
453
        return result
546
454
 
547
 
    @staticmethod
548
 
    def create_branch_convenience(base, force_new_repo=False,
549
 
                                  force_new_tree=None, format=None,
550
 
                                  possible_transports=None):
551
 
        """Create a new BzrDir, Branch and Repository at the url 'base'.
552
 
 
553
 
        This is a convenience function - it will use an existing repository
554
 
        if possible, can be told explicitly whether to create a working tree or
555
 
        not.
556
 
 
557
 
        This will use the current default BzrDirFormat unless one is
558
 
        specified, and use whatever
559
 
        repository format that that uses via bzrdir.create_branch and
560
 
        create_repository. If a shared repository is available that is used
561
 
        preferentially. Whatever repository is used, its tree creation policy
562
 
        is followed.
563
 
 
564
 
        The created Branch object is returned.
565
 
        If a working tree cannot be made due to base not being a file:// url,
566
 
        no error is raised unless force_new_tree is True, in which case no
567
 
        data is created on disk and NotLocalUrl is raised.
568
 
 
569
 
        :param base: The URL to create the branch at.
570
 
        :param force_new_repo: If True a new repository is always created.
571
 
        :param force_new_tree: If True or False force creation of a tree or
572
 
                               prevent such creation respectively.
573
 
        :param format: Override for the bzrdir format to create.
574
 
        :param possible_transports: An optional reusable transports list.
575
 
        """
576
 
        if force_new_tree:
577
 
            # check for non local urls
578
 
            t = _mod_transport.get_transport(base, possible_transports)
579
 
            if not isinstance(t, local.LocalTransport):
580
 
                raise errors.NotLocalUrl(base)
581
 
        bzrdir = BzrDir.create(base, format, possible_transports)
582
 
        repo = bzrdir._find_or_create_repository(force_new_repo)
583
 
        result = bzrdir.create_branch()
584
 
        if force_new_tree or (repo.make_working_trees() and
585
 
                              force_new_tree is None):
586
 
            try:
587
 
                bzrdir.create_workingtree()
588
 
            except errors.NotLocalUrl:
589
 
                pass
590
 
        return result
591
 
 
592
 
    @staticmethod
593
 
    def create_standalone_workingtree(base, format=None):
594
 
        """Create a new BzrDir, WorkingTree, Branch and Repository at 'base'.
595
 
 
596
 
        'base' must be a local path or a file:// url.
597
 
 
598
 
        This will use the current default BzrDirFormat unless one is
599
 
        specified, and use whatever
600
 
        repository format that that uses for bzrdirformat.create_workingtree,
601
 
        create_branch and create_repository.
602
 
 
603
 
        :param format: Override for the bzrdir format to create.
604
 
        :return: The WorkingTree object.
605
 
        """
606
 
        t = _mod_transport.get_transport(base)
607
 
        if not isinstance(t, local.LocalTransport):
608
 
            raise errors.NotLocalUrl(base)
609
 
        bzrdir = BzrDir.create_branch_and_repo(base,
610
 
                                               force_new_repo=True,
611
 
                                               format=format).bzrdir
612
 
        return bzrdir.create_workingtree()
613
 
 
614
455
    @deprecated_method(deprecated_in((2, 3, 0)))
615
456
    def generate_backup_name(self, base):
616
457
        return self._available_backup_name(base)
690
531
                return None
691
532
            # find the next containing bzrdir
692
533
            try:
693
 
                found_bzrdir = BzrDir.open_containing_from_transport(
 
534
                found_bzrdir = self.open_containing_from_transport(
694
535
                    next_transport)[0]
695
536
            except errors.NotBranchError:
696
537
                return None
813
654
        # add new tests for it to the appropriate place.
814
655
        return filename == '.bzr' or filename.startswith('.bzr/')
815
656
 
816
 
    @staticmethod
817
 
    def open_unsupported(base):
818
 
        """Open a branch which is not supported."""
819
 
        return BzrDir.open(base, _unsupported=True)
820
 
 
821
 
    @staticmethod
822
 
    def open(base, _unsupported=False, possible_transports=None):
823
 
        """Open an existing bzrdir, rooted at 'base' (url).
824
 
 
825
 
        :param _unsupported: a private parameter to the BzrDir class.
826
 
        """
827
 
        t = _mod_transport.get_transport(base, possible_transports)
828
 
        return BzrDir.open_from_transport(t, _unsupported=_unsupported)
829
 
 
830
 
    @staticmethod
831
 
    def open_from_transport(transport, _unsupported=False,
832
 
                            _server_formats=True):
833
 
        """Open a bzrdir within a particular directory.
834
 
 
835
 
        :param transport: Transport containing the bzrdir.
836
 
        :param _unsupported: private.
837
 
        """
838
 
        for hook in BzrDir.hooks['pre_open']:
839
 
            hook(transport)
840
 
        # Keep initial base since 'transport' may be modified while following
841
 
        # the redirections.
842
 
        base = transport.base
843
 
        def find_format(transport):
844
 
            return transport, controldir.ControlDirFormat.find_format(
845
 
                transport, _server_formats=_server_formats)
846
 
 
847
 
        def redirected(transport, e, redirection_notice):
848
 
            redirected_transport = transport._redirected_to(e.source, e.target)
849
 
            if redirected_transport is None:
850
 
                raise errors.NotBranchError(base)
851
 
            note(gettext('{0} is{1} redirected to {2}').format(
852
 
                 transport.base, e.permanently, redirected_transport.base))
853
 
            return redirected_transport
854
 
 
855
 
        try:
856
 
            transport, format = do_catching_redirections(find_format,
857
 
                                                         transport,
858
 
                                                         redirected)
859
 
        except errors.TooManyRedirections:
860
 
            raise errors.NotBranchError(base)
861
 
 
862
 
        format.check_support_status(_unsupported)
863
 
        return format.open(transport, _found=True)
864
 
 
865
 
    @staticmethod
866
 
    def open_containing(url, possible_transports=None):
867
 
        """Open an existing branch which contains url.
868
 
 
869
 
        :param url: url to search from.
870
 
 
871
 
        See open_containing_from_transport for more detail.
872
 
        """
873
 
        transport = _mod_transport.get_transport(url, possible_transports)
874
 
        return BzrDir.open_containing_from_transport(transport)
875
 
 
876
 
    @staticmethod
877
 
    def open_containing_from_transport(a_transport):
878
 
        """Open an existing branch which contains a_transport.base.
879
 
 
880
 
        This probes for a branch at a_transport, and searches upwards from there.
881
 
 
882
 
        Basically we keep looking up until we find the control directory or
883
 
        run into the root.  If there isn't one, raises NotBranchError.
884
 
        If there is one and it is either an unrecognised format or an unsupported
885
 
        format, UnknownFormatError or UnsupportedFormatError are raised.
886
 
        If there is one, it is returned, along with the unused portion of url.
887
 
 
888
 
        :return: The BzrDir that contains the path, and a Unicode path
889
 
                for the rest of the URL.
890
 
        """
891
 
        # this gets the normalised url back. I.e. '.' -> the full path.
892
 
        url = a_transport.base
893
 
        while True:
894
 
            try:
895
 
                result = BzrDir.open_from_transport(a_transport)
896
 
                return result, urlutils.unescape(a_transport.relpath(url))
897
 
            except errors.NotBranchError, e:
898
 
                pass
899
 
            try:
900
 
                new_t = a_transport.clone('..')
901
 
            except errors.InvalidURLJoin:
902
 
                # reached the root, whatever that may be
903
 
                raise errors.NotBranchError(path=url)
904
 
            if new_t.base == a_transport.base:
905
 
                # reached the root, whatever that may be
906
 
                raise errors.NotBranchError(path=url)
907
 
            a_transport = new_t
908
 
 
909
 
    @classmethod
910
 
    def open_tree_or_branch(klass, location):
911
 
        """Return the branch and working tree at a location.
912
 
 
913
 
        If there is no tree at the location, tree will be None.
914
 
        If there is no branch at the location, an exception will be
915
 
        raised
916
 
        :return: (tree, branch)
917
 
        """
918
 
        bzrdir = klass.open(location)
919
 
        return bzrdir._get_tree_branch()
920
 
 
921
 
    @classmethod
922
 
    def open_containing_tree_or_branch(klass, location):
923
 
        """Return the branch and working tree contained by a location.
924
 
 
925
 
        Returns (tree, branch, relpath).
926
 
        If there is no tree at containing the location, tree will be None.
927
 
        If there is no branch containing the location, an exception will be
928
 
        raised
929
 
        relpath is the portion of the path that is contained by the branch.
930
 
        """
931
 
        bzrdir, relpath = klass.open_containing(location)
932
 
        tree, branch = bzrdir._get_tree_branch()
933
 
        return tree, branch, relpath
934
 
 
935
 
    @classmethod
936
 
    def open_containing_tree_branch_or_repository(klass, location):
937
 
        """Return the working tree, branch and repo contained by a location.
938
 
 
939
 
        Returns (tree, branch, repository, relpath).
940
 
        If there is no tree containing the location, tree will be None.
941
 
        If there is no branch containing the location, branch will be None.
942
 
        If there is no repository containing the location, repository will be
943
 
        None.
944
 
        relpath is the portion of the path that is contained by the innermost
945
 
        BzrDir.
946
 
 
947
 
        If no tree, branch or repository is found, a NotBranchError is raised.
948
 
        """
949
 
        bzrdir, relpath = klass.open_containing(location)
950
 
        try:
951
 
            tree, branch = bzrdir._get_tree_branch()
952
 
        except errors.NotBranchError:
953
 
            try:
954
 
                repo = bzrdir.find_repository()
955
 
                return None, None, repo, relpath
956
 
            except (errors.NoRepositoryPresent):
957
 
                raise errors.NotBranchError(location)
958
 
        return tree, branch, branch.repository, relpath
959
 
 
960
657
    def _cloning_metadir(self):
961
658
        """Produce a metadir suitable for cloning with.
962
659
 
1002
699
 
1003
700
        :require_stacking: If True, non-stackable formats will be upgraded
1004
701
            to similar stackable formats.
1005
 
        :returns: a BzrDirFormat with all component formats either set
 
702
        :returns: a ControlDirFormat with all component formats either set
1006
703
            appropriately or set to None if that component should not be
1007
704
            created.
1008
705
        """
1020
717
            format.require_stacking()
1021
718
        return format
1022
719
 
1023
 
    @classmethod
1024
 
    def create(cls, base, format=None, possible_transports=None):
1025
 
        """Create a new BzrDir at the url 'base'.
1026
 
 
1027
 
        :param format: If supplied, the format of branch to create.  If not
1028
 
            supplied, the default is used.
1029
 
        :param possible_transports: If supplied, a list of transports that
1030
 
            can be reused to share a remote connection.
1031
 
        """
1032
 
        if cls is not BzrDir:
1033
 
            raise AssertionError("BzrDir.create always creates the"
1034
 
                "default format, not one of %r" % cls)
1035
 
        t = _mod_transport.get_transport(base, possible_transports)
1036
 
        t.ensure_base()
1037
 
        if format is None:
1038
 
            format = controldir.ControlDirFormat.get_default_format()
1039
 
        return format.initialize_on_transport(t)
1040
 
 
1041
720
    def get_branch_transport(self, branch_format, name=None):
1042
721
        """Get the transport for use by branch format in this BzrDir.
1043
722
 
1077
756
        """
1078
757
        raise NotImplementedError(self.get_workingtree_transport)
1079
758
 
1080
 
 
1081
 
class BzrDirHooks(hooks.Hooks):
1082
 
    """Hooks for BzrDir operations."""
1083
 
 
1084
 
    def __init__(self):
1085
 
        """Create the default hooks."""
1086
 
        hooks.Hooks.__init__(self, "bzrlib.bzrdir", "BzrDir.hooks")
1087
 
        self.add_hook('pre_open',
1088
 
            "Invoked before attempting to open a BzrDir with the transport "
1089
 
            "that the open will use.", (1, 14))
1090
 
        self.add_hook('post_repo_init',
1091
 
            "Invoked after a repository has been initialized. "
1092
 
            "post_repo_init is called with a "
1093
 
            "bzrlib.bzrdir.RepoInitHookParams.",
1094
 
            (2, 2))
1095
 
 
1096
 
# install the default hooks
1097
 
BzrDir.hooks = BzrDirHooks()
1098
 
 
1099
 
 
1100
 
class RepoInitHookParams(object):
1101
 
    """Object holding parameters passed to `*_repo_init` hooks.
1102
 
 
1103
 
    There are 4 fields that hooks may wish to access:
1104
 
 
1105
 
    :ivar repository: Repository created
1106
 
    :ivar format: Repository format
1107
 
    :ivar bzrdir: The bzrdir for the repository
1108
 
    :ivar shared: The repository is shared
1109
 
    """
1110
 
 
1111
 
    def __init__(self, repository, format, a_bzrdir, shared):
1112
 
        """Create a group of RepoInitHook parameters.
1113
 
 
1114
 
        :param repository: Repository created
1115
 
        :param format: Repository format
1116
 
        :param bzrdir: The bzrdir for the repository
1117
 
        :param shared: The repository is shared
 
759
    @classmethod
 
760
    def create(cls, base, format=None, possible_transports=None):
 
761
        """Create a new BzrDir at the url 'base'.
 
762
 
 
763
        :param format: If supplied, the format of branch to create.  If not
 
764
            supplied, the default is used.
 
765
        :param possible_transports: If supplied, a list of transports that
 
766
            can be reused to share a remote connection.
1118
767
        """
1119
 
        self.repository = repository
1120
 
        self.format = format
1121
 
        self.bzrdir = a_bzrdir
1122
 
        self.shared = shared
1123
 
 
1124
 
    def __eq__(self, other):
1125
 
        return self.__dict__ == other.__dict__
1126
 
 
1127
 
    def __repr__(self):
1128
 
        if self.repository:
1129
 
            return "<%s for %s>" % (self.__class__.__name__,
1130
 
                self.repository)
1131
 
        else:
1132
 
            return "<%s for %s>" % (self.__class__.__name__,
1133
 
                self.bzrdir)
 
768
        if cls is not BzrDir:
 
769
            raise AssertionError("BzrDir.create always creates the "
 
770
                "default format, not one of %r" % cls)
 
771
        return controldir.ControlDir.create(base, format=format,
 
772
                possible_transports=possible_transports)
1134
773
 
1135
774
 
1136
775
class BzrDirMeta1(BzrDir):