~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/controldir.py

  • Committer: Martin Packman
  • Date: 2012-01-05 09:50:04 UTC
  • mfrom: (6424 +trunk)
  • mto: This revision was merged to the branch mainline in revision 6426.
  • Revision ID: martin.packman@canonical.com-20120105095004-mia9xb7y0efmto0v
Merge bzr.dev to resolve conflicts in bzrlib.builtins

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
 
23
23
"""
24
24
 
 
25
from __future__ import absolute_import
 
26
 
25
27
from bzrlib.lazy_import import lazy_import
26
28
lazy_import(globals(), """
27
29
import textwrap
28
30
 
29
31
from bzrlib import (
30
32
    errors,
 
33
    hooks,
31
34
    revision as _mod_revision,
32
35
    transport as _mod_transport,
 
36
    trace,
33
37
    ui,
34
38
    urlutils,
35
39
    )
 
40
from bzrlib.transport import local
36
41
from bzrlib.push import (
37
42
    PushResult,
38
43
    )
39
44
 
 
45
from bzrlib.i18n import gettext
40
46
""")
41
47
 
42
48
from bzrlib import registry
75
81
        return self.user_transport.base
76
82
 
77
83
 
78
 
 
79
84
class ControlDir(ControlComponent):
80
85
    """A control directory.
81
86
 
103
108
        """Return a sequence of all branches local to this control directory.
104
109
 
105
110
        """
 
111
        return self.get_branches().values()
 
112
 
 
113
    def get_branches(self):
 
114
        """Get all branches in this control directory, as a dictionary.
 
115
        
 
116
        :return: Dictionary mapping branch names to instances.
 
117
        """
106
118
        try:
107
 
            return [self.open_branch()]
 
119
           return { None: self.open_branch() }
108
120
        except (errors.NotBranchError, errors.NoRepositoryPresent):
109
 
            return []
 
121
           return {}
110
122
 
111
123
    def is_control_filename(self, filename):
112
124
        """True if filename is the name of a path which is reserved for
146
158
        """Destroy the repository in this ControlDir."""
147
159
        raise NotImplementedError(self.destroy_repository)
148
160
 
149
 
    def create_branch(self, name=None, repository=None):
 
161
    def create_branch(self, name=None, repository=None,
 
162
                      append_revisions_only=None):
150
163
        """Create a branch in this ControlDir.
151
164
 
152
165
        :param name: Name of the colocated branch to create, None for
153
166
            the default branch.
 
167
        :param append_revisions_only: Whether this branch should only allow
 
168
            appending new revisions to its history.
154
169
 
155
170
        The controldirs format will control what branch format is created.
156
171
        For more control see BranchFormatXX.create(a_controldir).
195
210
        raise NotImplementedError(self.destroy_workingtree_metadata)
196
211
 
197
212
    def find_branch_format(self, name=None):
198
 
        """Find the branch 'format' for this bzrdir.
 
213
        """Find the branch 'format' for this controldir.
199
214
 
200
215
        This might be a synthetic object for e.g. RemoteBranch and SVN.
201
216
        """
216
231
        return None
217
232
 
218
233
    def open_branch(self, name=None, unsupported=False,
219
 
                    ignore_fallbacks=False):
 
234
                    ignore_fallbacks=False, possible_transports=None):
220
235
        """Open the branch object at this ControlDir if one is present.
221
236
 
222
 
        If unsupported is True, then no longer supported branch formats can
223
 
        still be opened.
224
 
 
225
 
        TODO: static convenience version of this?
 
237
        :param unsupported: if True, then no longer supported branch formats can
 
238
            still be opened.
 
239
        :param ignore_fallbacks: Whether to open fallback repositories
 
240
        :param possible_transports: Transports to use for opening e.g.
 
241
            fallback repositories.
226
242
        """
227
243
        raise NotImplementedError(self.open_branch)
228
244
 
234
250
        get at a repository.
235
251
 
236
252
        :param _unsupported: a private parameter, not part of the api.
237
 
 
238
 
        TODO: static convenience version of this?
239
253
        """
240
254
        raise NotImplementedError(self.open_repository)
241
255
 
248
262
        """
249
263
        raise NotImplementedError(self.find_repository)
250
264
 
251
 
    def open_workingtree(self, _unsupported=False,
 
265
    def open_workingtree(self, unsupported=False,
252
266
                         recommend_upgrade=True, from_branch=None):
253
267
        """Open the workingtree object at this ControlDir if one is present.
254
268
 
269
283
        branch and discards it, and that's somewhat expensive.)
270
284
        """
271
285
        try:
272
 
            self.open_branch(name)
 
286
            self.open_branch(name, ignore_fallbacks=True)
273
287
            return True
274
288
        except errors.NotBranchError:
275
289
            return False
316
330
        raise NotImplementedError(self.cloning_metadir)
317
331
 
318
332
    def checkout_metadir(self):
319
 
        """Produce a metadir suitable for checkouts of this controldir."""
 
333
        """Produce a metadir suitable for checkouts of this controldir.
 
334
 
 
335
        :returns: A ControlDirFormat with all component formats
 
336
            either set appropriately or set to None if that component
 
337
            should not be created.
 
338
        """
320
339
        return self.cloning_metadir()
321
340
 
322
341
    def sprout(self, url, revision_id=None, force_new_repo=False,
413
432
        return push_result
414
433
 
415
434
    def _get_tree_branch(self, name=None):
416
 
        """Return the branch and tree, if any, for this bzrdir.
 
435
        """Return the branch and tree, if any, for this controldir.
417
436
 
418
437
        :param name: Name of colocated branch to open.
419
438
 
438
457
        raise NotImplementedError(self.get_config)
439
458
 
440
459
    def check_conversion_target(self, target_format):
441
 
        """Check that a bzrdir as a whole can be converted to a new format."""
 
460
        """Check that a controldir as a whole can be converted to a new format."""
442
461
        raise NotImplementedError(self.check_conversion_target)
443
462
 
444
463
    def clone(self, url, revision_id=None, force_new_repo=False,
445
464
              preserve_stacking=False):
446
 
        """Clone this bzrdir and its contents to url verbatim.
 
465
        """Clone this controldir and its contents to url verbatim.
447
466
 
448
467
        :param url: The url create the clone at.  If url's last component does
449
468
            not exist, it will be created.
463
482
    def clone_on_transport(self, transport, revision_id=None,
464
483
        force_new_repo=False, preserve_stacking=False, stacked_on=None,
465
484
        create_prefix=False, use_existing_dir=True, no_tree=False):
466
 
        """Clone this bzrdir and its contents to transport verbatim.
 
485
        """Clone this controldir and its contents to transport verbatim.
467
486
 
468
487
        :param transport: The transport for the location to produce the clone
469
488
            at.  If the target directory does not exist, it will be created.
481
500
        """
482
501
        raise NotImplementedError(self.clone_on_transport)
483
502
 
 
503
    @classmethod
 
504
    def find_bzrdirs(klass, transport, evaluate=None, list_current=None):
 
505
        """Find control dirs recursively from current location.
 
506
 
 
507
        This is intended primarily as a building block for more sophisticated
 
508
        functionality, like finding trees under a directory, or finding
 
509
        branches that use a given repository.
 
510
 
 
511
        :param evaluate: An optional callable that yields recurse, value,
 
512
            where recurse controls whether this controldir is recursed into
 
513
            and value is the value to yield.  By default, all bzrdirs
 
514
            are recursed into, and the return value is the controldir.
 
515
        :param list_current: if supplied, use this function to list the current
 
516
            directory, instead of Transport.list_dir
 
517
        :return: a generator of found bzrdirs, or whatever evaluate returns.
 
518
        """
 
519
        if list_current is None:
 
520
            def list_current(transport):
 
521
                return transport.list_dir('')
 
522
        if evaluate is None:
 
523
            def evaluate(controldir):
 
524
                return True, controldir
 
525
 
 
526
        pending = [transport]
 
527
        while len(pending) > 0:
 
528
            current_transport = pending.pop()
 
529
            recurse = True
 
530
            try:
 
531
                controldir = klass.open_from_transport(current_transport)
 
532
            except (errors.NotBranchError, errors.PermissionDenied):
 
533
                pass
 
534
            else:
 
535
                recurse, value = evaluate(controldir)
 
536
                yield value
 
537
            try:
 
538
                subdirs = list_current(current_transport)
 
539
            except (errors.NoSuchFile, errors.PermissionDenied):
 
540
                continue
 
541
            if recurse:
 
542
                for subdir in sorted(subdirs, reverse=True):
 
543
                    pending.append(current_transport.clone(subdir))
 
544
 
 
545
    @classmethod
 
546
    def find_branches(klass, transport):
 
547
        """Find all branches under a transport.
 
548
 
 
549
        This will find all branches below the transport, including branches
 
550
        inside other branches.  Where possible, it will use
 
551
        Repository.find_branches.
 
552
 
 
553
        To list all the branches that use a particular Repository, see
 
554
        Repository.find_branches
 
555
        """
 
556
        def evaluate(controldir):
 
557
            try:
 
558
                repository = controldir.open_repository()
 
559
            except errors.NoRepositoryPresent:
 
560
                pass
 
561
            else:
 
562
                return False, ([], repository)
 
563
            return True, (controldir.list_branches(), None)
 
564
        ret = []
 
565
        for branches, repo in klass.find_bzrdirs(
 
566
                transport, evaluate=evaluate):
 
567
            if repo is not None:
 
568
                ret.extend(repo.find_branches())
 
569
            if branches is not None:
 
570
                ret.extend(branches)
 
571
        return ret
 
572
 
 
573
    @classmethod
 
574
    def create_branch_and_repo(klass, base, force_new_repo=False, format=None):
 
575
        """Create a new ControlDir, Branch and Repository at the url 'base'.
 
576
 
 
577
        This will use the current default ControlDirFormat unless one is
 
578
        specified, and use whatever
 
579
        repository format that that uses via controldir.create_branch and
 
580
        create_repository. If a shared repository is available that is used
 
581
        preferentially.
 
582
 
 
583
        The created Branch object is returned.
 
584
 
 
585
        :param base: The URL to create the branch at.
 
586
        :param force_new_repo: If True a new repository is always created.
 
587
        :param format: If supplied, the format of branch to create.  If not
 
588
            supplied, the default is used.
 
589
        """
 
590
        controldir = klass.create(base, format)
 
591
        controldir._find_or_create_repository(force_new_repo)
 
592
        return controldir.create_branch()
 
593
 
 
594
    @classmethod
 
595
    def create_branch_convenience(klass, base, force_new_repo=False,
 
596
                                  force_new_tree=None, format=None,
 
597
                                  possible_transports=None):
 
598
        """Create a new ControlDir, Branch and Repository at the url 'base'.
 
599
 
 
600
        This is a convenience function - it will use an existing repository
 
601
        if possible, can be told explicitly whether to create a working tree or
 
602
        not.
 
603
 
 
604
        This will use the current default ControlDirFormat unless one is
 
605
        specified, and use whatever
 
606
        repository format that that uses via ControlDir.create_branch and
 
607
        create_repository. If a shared repository is available that is used
 
608
        preferentially. Whatever repository is used, its tree creation policy
 
609
        is followed.
 
610
 
 
611
        The created Branch object is returned.
 
612
        If a working tree cannot be made due to base not being a file:// url,
 
613
        no error is raised unless force_new_tree is True, in which case no
 
614
        data is created on disk and NotLocalUrl is raised.
 
615
 
 
616
        :param base: The URL to create the branch at.
 
617
        :param force_new_repo: If True a new repository is always created.
 
618
        :param force_new_tree: If True or False force creation of a tree or
 
619
                               prevent such creation respectively.
 
620
        :param format: Override for the controldir format to create.
 
621
        :param possible_transports: An optional reusable transports list.
 
622
        """
 
623
        if force_new_tree:
 
624
            # check for non local urls
 
625
            t = _mod_transport.get_transport(base, possible_transports)
 
626
            if not isinstance(t, local.LocalTransport):
 
627
                raise errors.NotLocalUrl(base)
 
628
        controldir = klass.create(base, format, possible_transports)
 
629
        repo = controldir._find_or_create_repository(force_new_repo)
 
630
        result = controldir.create_branch()
 
631
        if force_new_tree or (repo.make_working_trees() and
 
632
                              force_new_tree is None):
 
633
            try:
 
634
                controldir.create_workingtree()
 
635
            except errors.NotLocalUrl:
 
636
                pass
 
637
        return result
 
638
 
 
639
    @classmethod
 
640
    def create_standalone_workingtree(klass, base, format=None):
 
641
        """Create a new ControlDir, WorkingTree, Branch and Repository at 'base'.
 
642
 
 
643
        'base' must be a local path or a file:// url.
 
644
 
 
645
        This will use the current default ControlDirFormat unless one is
 
646
        specified, and use whatever
 
647
        repository format that that uses for bzrdirformat.create_workingtree,
 
648
        create_branch and create_repository.
 
649
 
 
650
        :param format: Override for the controldir format to create.
 
651
        :return: The WorkingTree object.
 
652
        """
 
653
        t = _mod_transport.get_transport(base)
 
654
        if not isinstance(t, local.LocalTransport):
 
655
            raise errors.NotLocalUrl(base)
 
656
        controldir = klass.create_branch_and_repo(base,
 
657
                                               force_new_repo=True,
 
658
                                               format=format).bzrdir
 
659
        return controldir.create_workingtree()
 
660
 
 
661
    @classmethod
 
662
    def open_unsupported(klass, base):
 
663
        """Open a branch which is not supported."""
 
664
        return klass.open(base, _unsupported=True)
 
665
 
 
666
    @classmethod
 
667
    def open(klass, base, possible_transports=None, probers=None,
 
668
             _unsupported=False):
 
669
        """Open an existing controldir, rooted at 'base' (url).
 
670
 
 
671
        :param _unsupported: a private parameter to the ControlDir class.
 
672
        """
 
673
        t = _mod_transport.get_transport(base, possible_transports)
 
674
        return klass.open_from_transport(t, probers=probers,
 
675
                _unsupported=_unsupported)
 
676
 
 
677
    @classmethod
 
678
    def open_from_transport(klass, transport, _unsupported=False,
 
679
                            probers=None):
 
680
        """Open a controldir within a particular directory.
 
681
 
 
682
        :param transport: Transport containing the controldir.
 
683
        :param _unsupported: private.
 
684
        """
 
685
        for hook in klass.hooks['pre_open']:
 
686
            hook(transport)
 
687
        # Keep initial base since 'transport' may be modified while following
 
688
        # the redirections.
 
689
        base = transport.base
 
690
        def find_format(transport):
 
691
            return transport, ControlDirFormat.find_format(transport,
 
692
                probers=probers)
 
693
 
 
694
        def redirected(transport, e, redirection_notice):
 
695
            redirected_transport = transport._redirected_to(e.source, e.target)
 
696
            if redirected_transport is None:
 
697
                raise errors.NotBranchError(base)
 
698
            trace.note(gettext('{0} is{1} redirected to {2}').format(
 
699
                 transport.base, e.permanently, redirected_transport.base))
 
700
            return redirected_transport
 
701
 
 
702
        try:
 
703
            transport, format = _mod_transport.do_catching_redirections(
 
704
                find_format, transport, redirected)
 
705
        except errors.TooManyRedirections:
 
706
            raise errors.NotBranchError(base)
 
707
 
 
708
        format.check_support_status(_unsupported)
 
709
        return format.open(transport, _found=True)
 
710
 
 
711
    @classmethod
 
712
    def open_containing(klass, url, possible_transports=None):
 
713
        """Open an existing branch which contains url.
 
714
 
 
715
        :param url: url to search from.
 
716
 
 
717
        See open_containing_from_transport for more detail.
 
718
        """
 
719
        transport = _mod_transport.get_transport(url, possible_transports)
 
720
        return klass.open_containing_from_transport(transport)
 
721
 
 
722
    @classmethod
 
723
    def open_containing_from_transport(klass, a_transport):
 
724
        """Open an existing branch which contains a_transport.base.
 
725
 
 
726
        This probes for a branch at a_transport, and searches upwards from there.
 
727
 
 
728
        Basically we keep looking up until we find the control directory or
 
729
        run into the root.  If there isn't one, raises NotBranchError.
 
730
        If there is one and it is either an unrecognised format or an unsupported
 
731
        format, UnknownFormatError or UnsupportedFormatError are raised.
 
732
        If there is one, it is returned, along with the unused portion of url.
 
733
 
 
734
        :return: The ControlDir that contains the path, and a Unicode path
 
735
                for the rest of the URL.
 
736
        """
 
737
        # this gets the normalised url back. I.e. '.' -> the full path.
 
738
        url = a_transport.base
 
739
        while True:
 
740
            try:
 
741
                result = klass.open_from_transport(a_transport)
 
742
                return result, urlutils.unescape(a_transport.relpath(url))
 
743
            except errors.NotBranchError, e:
 
744
                pass
 
745
            except errors.PermissionDenied:
 
746
                pass
 
747
            try:
 
748
                new_t = a_transport.clone('..')
 
749
            except errors.InvalidURLJoin:
 
750
                # reached the root, whatever that may be
 
751
                raise errors.NotBranchError(path=url)
 
752
            if new_t.base == a_transport.base:
 
753
                # reached the root, whatever that may be
 
754
                raise errors.NotBranchError(path=url)
 
755
            a_transport = new_t
 
756
 
 
757
    @classmethod
 
758
    def open_tree_or_branch(klass, location):
 
759
        """Return the branch and working tree at a location.
 
760
 
 
761
        If there is no tree at the location, tree will be None.
 
762
        If there is no branch at the location, an exception will be
 
763
        raised
 
764
        :return: (tree, branch)
 
765
        """
 
766
        controldir = klass.open(location)
 
767
        return controldir._get_tree_branch()
 
768
 
 
769
    @classmethod
 
770
    def open_containing_tree_or_branch(klass, location):
 
771
        """Return the branch and working tree contained by a location.
 
772
 
 
773
        Returns (tree, branch, relpath).
 
774
        If there is no tree at containing the location, tree will be None.
 
775
        If there is no branch containing the location, an exception will be
 
776
        raised
 
777
        relpath is the portion of the path that is contained by the branch.
 
778
        """
 
779
        controldir, relpath = klass.open_containing(location)
 
780
        tree, branch = controldir._get_tree_branch()
 
781
        return tree, branch, relpath
 
782
 
 
783
    @classmethod
 
784
    def open_containing_tree_branch_or_repository(klass, location):
 
785
        """Return the working tree, branch and repo contained by a location.
 
786
 
 
787
        Returns (tree, branch, repository, relpath).
 
788
        If there is no tree containing the location, tree will be None.
 
789
        If there is no branch containing the location, branch will be None.
 
790
        If there is no repository containing the location, repository will be
 
791
        None.
 
792
        relpath is the portion of the path that is contained by the innermost
 
793
        ControlDir.
 
794
 
 
795
        If no tree, branch or repository is found, a NotBranchError is raised.
 
796
        """
 
797
        controldir, relpath = klass.open_containing(location)
 
798
        try:
 
799
            tree, branch = controldir._get_tree_branch()
 
800
        except errors.NotBranchError:
 
801
            try:
 
802
                repo = controldir.find_repository()
 
803
                return None, None, repo, relpath
 
804
            except (errors.NoRepositoryPresent):
 
805
                raise errors.NotBranchError(location)
 
806
        return tree, branch, branch.repository, relpath
 
807
 
 
808
    @classmethod
 
809
    def create(klass, base, format=None, possible_transports=None):
 
810
        """Create a new ControlDir at the url 'base'.
 
811
 
 
812
        :param format: If supplied, the format of branch to create.  If not
 
813
            supplied, the default is used.
 
814
        :param possible_transports: If supplied, a list of transports that
 
815
            can be reused to share a remote connection.
 
816
        """
 
817
        if klass is not ControlDir:
 
818
            raise AssertionError("ControlDir.create always creates the"
 
819
                "default format, not one of %r" % klass)
 
820
        t = _mod_transport.get_transport(base, possible_transports)
 
821
        t.ensure_base()
 
822
        if format is None:
 
823
            format = ControlDirFormat.get_default_format()
 
824
        return format.initialize_on_transport(t)
 
825
 
 
826
 
 
827
class ControlDirHooks(hooks.Hooks):
 
828
    """Hooks for ControlDir operations."""
 
829
 
 
830
    def __init__(self):
 
831
        """Create the default hooks."""
 
832
        hooks.Hooks.__init__(self, "bzrlib.controldir", "ControlDir.hooks")
 
833
        self.add_hook('pre_open',
 
834
            "Invoked before attempting to open a ControlDir with the transport "
 
835
            "that the open will use.", (1, 14))
 
836
        self.add_hook('post_repo_init',
 
837
            "Invoked after a repository has been initialized. "
 
838
            "post_repo_init is called with a "
 
839
            "bzrlib.controldir.RepoInitHookParams.",
 
840
            (2, 2))
 
841
 
 
842
# install the default hooks
 
843
ControlDir.hooks = ControlDirHooks()
 
844
 
484
845
 
485
846
class ControlComponentFormat(object):
486
 
    """A component that can live inside of a .bzr meta directory."""
 
847
    """A component that can live inside of a control directory."""
487
848
 
488
849
    upgrade_recommended = False
489
850
 
490
 
    def get_format_string(self):
491
 
        """Return the format of this format, if usable in meta directories."""
492
 
        raise NotImplementedError(self.get_format_string)
493
 
 
494
851
    def get_format_description(self):
495
852
        """Return the short description for this format."""
496
853
        raise NotImplementedError(self.get_format_description)
523
880
            ui.ui_factory.recommend_upgrade(
524
881
                self.get_format_description(), basedir)
525
882
 
 
883
    @classmethod
 
884
    def get_format_string(cls):
 
885
        raise NotImplementedError(cls.get_format_string)
 
886
 
526
887
 
527
888
class ControlComponentFormatRegistry(registry.FormatRegistry):
528
889
    """A registry for control components (branch, workingtree, repository)."""
679
1040
    def is_supported(self):
680
1041
        """Is this format supported?
681
1042
 
682
 
        Supported formats must be initializable and openable.
 
1043
        Supported formats must be openable.
683
1044
        Unsupported formats may not support initialization or committing or
684
1045
        some other features depending on the reason for not being supported.
685
1046
        """
686
1047
        return True
687
1048
 
 
1049
    def is_initializable(self):
 
1050
        """Whether new control directories of this format can be initialized.
 
1051
        """
 
1052
        return self.is_supported()
 
1053
 
688
1054
    def check_support_status(self, allow_unsupported, recommend_upgrade=True,
689
1055
        basedir=None):
690
1056
        """Give an error or warning on old formats.
746
1112
        return self.get_format_description().rstrip()
747
1113
 
748
1114
    @classmethod
 
1115
    def all_probers(klass):
 
1116
        return klass._server_probers + klass._probers
 
1117
 
 
1118
    @classmethod
749
1119
    def known_formats(klass):
750
1120
        """Return all the known formats.
751
1121
        """
752
1122
        result = set()
753
 
        for prober_kls in klass._probers + klass._server_probers:
 
1123
        for prober_kls in klass.all_probers():
754
1124
            result.update(prober_kls.known_formats())
755
1125
        return result
756
1126
 
757
1127
    @classmethod
758
 
    def find_format(klass, transport, _server_formats=True):
 
1128
    def find_format(klass, transport, probers=None):
759
1129
        """Return the format present at transport."""
760
 
        if _server_formats:
761
 
            _probers = klass._server_probers + klass._probers
762
 
        else:
763
 
            _probers = klass._probers
764
 
        for prober_kls in _probers:
 
1130
        if probers is None:
 
1131
            probers = klass.all_probers()
 
1132
        for prober_kls in probers:
765
1133
            prober = prober_kls()
766
1134
            try:
767
1135
                return prober.probe_transport(transport)
846
1214
        """Return the current default format."""
847
1215
        return klass._default_format
848
1216
 
 
1217
    def supports_transport(self, transport):
 
1218
        """Check if this format can be opened over a particular transport.
 
1219
        """
 
1220
        raise NotImplementedError(self.supports_transport)
 
1221
 
849
1222
 
850
1223
class Prober(object):
851
1224
    """Abstract class that can be used to detect a particular kind of
874
1247
        raise NotImplementedError(self.probe_transport)
875
1248
 
876
1249
    @classmethod
877
 
    def known_formats(cls):
 
1250
    def known_formats(klass):
878
1251
        """Return the control dir formats known by this prober.
879
1252
 
880
1253
        Multiple probers can return the same formats, so this should
882
1255
 
883
1256
        :return: A set of known formats.
884
1257
        """
885
 
        raise NotImplementedError(cls.known_formats)
 
1258
        raise NotImplementedError(klass.known_formats)
886
1259
 
887
1260
 
888
1261
class ControlDirFormatInfo(object):
1021
1394
            return output
1022
1395
 
1023
1396
 
 
1397
class RepoInitHookParams(object):
 
1398
    """Object holding parameters passed to `*_repo_init` hooks.
 
1399
 
 
1400
    There are 4 fields that hooks may wish to access:
 
1401
 
 
1402
    :ivar repository: Repository created
 
1403
    :ivar format: Repository format
 
1404
    :ivar bzrdir: The controldir for the repository
 
1405
    :ivar shared: The repository is shared
 
1406
    """
 
1407
 
 
1408
    def __init__(self, repository, format, controldir, shared):
 
1409
        """Create a group of RepoInitHook parameters.
 
1410
 
 
1411
        :param repository: Repository created
 
1412
        :param format: Repository format
 
1413
        :param controldir: The controldir for the repository
 
1414
        :param shared: The repository is shared
 
1415
        """
 
1416
        self.repository = repository
 
1417
        self.format = format
 
1418
        self.bzrdir = controldir
 
1419
        self.shared = shared
 
1420
 
 
1421
    def __eq__(self, other):
 
1422
        return self.__dict__ == other.__dict__
 
1423
 
 
1424
    def __repr__(self):
 
1425
        if self.repository:
 
1426
            return "<%s for %s>" % (self.__class__.__name__,
 
1427
                self.repository)
 
1428
        else:
 
1429
            return "<%s for %s>" % (self.__class__.__name__,
 
1430
                self.bzrdir)
 
1431
 
 
1432
 
1024
1433
# Please register new formats after old formats so that formats
1025
1434
# appear in chronological order and format descriptions can build
1026
1435
# on previous ones.