/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

  • Committer: mbp at sourcefrog
  • Date: 2011-04-11 01:23:58 UTC
  • mfrom: (5777 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5802.
  • Revision ID: mbp@sourcefrog.net-20110411012358-gl07rdtxydlq7fh1
merge news

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
 
1
# Copyright (C) 2005-2011 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
27
27
        config as _mod_config,
28
28
        debug,
29
29
        errors,
 
30
        fetch,
 
31
        graph as _mod_graph,
30
32
        lockdir,
31
33
        lockable_files,
 
34
        remote,
32
35
        repository,
33
36
        revision as _mod_revision,
34
37
        rio,
39
42
        urlutils,
40
43
        )
41
44
from bzrlib.config import BranchConfig, TransportConfig
42
 
from bzrlib.repofmt.pack_repo import RepositoryFormatKnitPack5RichRoot
43
45
from bzrlib.tag import (
44
46
    BasicTags,
45
47
    DisabledTags,
46
48
    )
47
49
""")
48
50
 
49
 
from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises
50
 
from bzrlib.hooks import HookPoint, Hooks
 
51
from bzrlib import (
 
52
    controldir,
 
53
    )
 
54
from bzrlib.decorators import (
 
55
    needs_read_lock,
 
56
    needs_write_lock,
 
57
    only_raises,
 
58
    )
 
59
from bzrlib.hooks import Hooks
51
60
from bzrlib.inter import InterObject
52
61
from bzrlib.lock import _RelockDebugMixin, LogicalLockResult
53
62
from bzrlib import registry
63
72
BZR_BRANCH_FORMAT_6 = "Bazaar Branch Format 6 (bzr 0.15)\n"
64
73
 
65
74
 
66
 
class Branch(bzrdir.ControlComponent):
 
75
class Branch(controldir.ControlComponent):
67
76
    """Branch holding a history of revisions.
68
77
 
69
78
    :ivar base:
70
79
        Base directory/url of the branch; using control_url and
71
80
        control_transport is more standardized.
72
 
 
73
 
    hooks: An instance of BranchHooks.
 
81
    :ivar hooks: An instance of BranchHooks.
 
82
    :ivar _master_branch_cache: cached result of get_master_branch, see
 
83
        _clear_cached_state.
74
84
    """
75
85
    # this is really an instance variable - FIXME move it there
76
86
    # - RBC 20060112
90
100
        self._revision_id_to_revno_cache = None
91
101
        self._partial_revision_id_to_revno_cache = {}
92
102
        self._partial_revision_history_cache = []
 
103
        self._tags_bytes = None
93
104
        self._last_revision_info_cache = None
 
105
        self._master_branch_cache = None
94
106
        self._merge_sorted_revisions_cache = None
95
107
        self._open_hook()
96
108
        hooks = Branch.hooks['open']
102
114
 
103
115
    def _activate_fallback_location(self, url):
104
116
        """Activate the branch/repository from url as a fallback repository."""
 
117
        for existing_fallback_repo in self.repository._fallback_repositories:
 
118
            if existing_fallback_repo.user_url == url:
 
119
                # This fallback is already configured.  This probably only
 
120
                # happens because BzrDir.sprout is a horrible mess.  To avoid
 
121
                # confusing _unstack we don't add this a second time.
 
122
                mutter('duplicate activation of fallback %r on %r', url, self)
 
123
                return
105
124
        repo = self._get_fallback_repository(url)
106
125
        if repo.has_same_location(self.repository):
107
126
            raise errors.UnstackableLocationError(self.user_url, url)
197
216
        return self.supports_tags() and self.tags.get_tag_dict()
198
217
 
199
218
    def get_config(self):
 
219
        """Get a bzrlib.config.BranchConfig for this Branch.
 
220
 
 
221
        This can then be used to get and set configuration options for the
 
222
        branch.
 
223
 
 
224
        :return: A bzrlib.config.BranchConfig.
 
225
        """
200
226
        return BranchConfig(self)
201
227
 
202
228
    def _get_config(self):
218
244
            possible_transports=[self.bzrdir.root_transport])
219
245
        return a_branch.repository
220
246
 
 
247
    @needs_read_lock
221
248
    def _get_tags_bytes(self):
222
249
        """Get the bytes of a serialised tags dict.
223
250
 
230
257
        :return: The bytes of the tags file.
231
258
        :seealso: Branch._set_tags_bytes.
232
259
        """
233
 
        return self._transport.get_bytes('tags')
 
260
        if self._tags_bytes is None:
 
261
            self._tags_bytes = self._transport.get_bytes('tags')
 
262
        return self._tags_bytes
234
263
 
235
264
    def _get_nick(self, local=False, possible_transports=None):
236
265
        config = self.get_config()
238
267
        if not local and not config.has_explicit_nickname():
239
268
            try:
240
269
                master = self.get_master_branch(possible_transports)
 
270
                if master and self.user_url == master.user_url:
 
271
                    raise errors.RecursiveBind(self.user_url)
241
272
                if master is not None:
242
273
                    # return the master branch value
243
274
                    return master.nick
 
275
            except errors.RecursiveBind, e:
 
276
                raise e
244
277
            except errors.BzrError, e:
245
278
                # Silently fall back to local implicit nick if the master is
246
279
                # unavailable
636
669
        raise errors.UnsupportedOperation(self.get_reference_info, self)
637
670
 
638
671
    @needs_write_lock
639
 
    def fetch(self, from_branch, last_revision=None, pb=None):
 
672
    def fetch(self, from_branch, last_revision=None, fetch_spec=None):
640
673
        """Copy revisions from from_branch into this branch.
641
674
 
642
675
        :param from_branch: Where to copy from.
643
676
        :param last_revision: What revision to stop at (None for at the end
644
677
                              of the branch.
645
 
        :param pb: An optional progress bar to use.
 
678
        :param fetch_spec: If specified, a SearchResult or
 
679
            PendingAncestryResult that describes which revisions to copy.  This
 
680
            allows copying multiple heads at once.  Mutually exclusive with
 
681
            last_revision.
646
682
        :return: None
647
683
        """
648
 
        if self.base == from_branch.base:
649
 
            return (0, [])
650
 
        if pb is not None:
651
 
            symbol_versioning.warn(
652
 
                symbol_versioning.deprecated_in((1, 14, 0))
653
 
                % "pb parameter to fetch()")
654
 
        from_branch.lock_read()
655
 
        try:
656
 
            if last_revision is None:
657
 
                last_revision = from_branch.last_revision()
658
 
                last_revision = _mod_revision.ensure_null(last_revision)
659
 
            return self.repository.fetch(from_branch.repository,
660
 
                                         revision_id=last_revision,
661
 
                                         pb=pb)
662
 
        finally:
663
 
            from_branch.unlock()
 
684
        return InterBranch.get(from_branch, self).fetch(last_revision,
 
685
            fetch_spec)
664
686
 
665
687
    def get_bound_location(self):
666
688
        """Return the URL of the branch we are bound to.
777
799
 
778
800
    def _unstack(self):
779
801
        """Change a branch to be unstacked, copying data as needed.
780
 
        
 
802
 
781
803
        Don't call this directly, use set_stacked_on_url(None).
782
804
        """
783
805
        pb = ui.ui_factory.nested_progress_bar()
792
814
            old_repository = self.repository
793
815
            if len(old_repository._fallback_repositories) != 1:
794
816
                raise AssertionError("can't cope with fallback repositories "
795
 
                    "of %r" % (self.repository,))
796
 
            # unlock it, including unlocking the fallback
 
817
                    "of %r (fallbacks: %r)" % (old_repository,
 
818
                        old_repository._fallback_repositories))
 
819
            # Open the new repository object.
 
820
            # Repositories don't offer an interface to remove fallback
 
821
            # repositories today; take the conceptually simpler option and just
 
822
            # reopen it.  We reopen it starting from the URL so that we
 
823
            # get a separate connection for RemoteRepositories and can
 
824
            # stream from one of them to the other.  This does mean doing
 
825
            # separate SSH connection setup, but unstacking is not a
 
826
            # common operation so it's tolerable.
 
827
            new_bzrdir = bzrdir.BzrDir.open(self.bzrdir.root_transport.base)
 
828
            new_repository = new_bzrdir.find_repository()
 
829
            if new_repository._fallback_repositories:
 
830
                raise AssertionError("didn't expect %r to have "
 
831
                    "fallback_repositories"
 
832
                    % (self.repository,))
 
833
            # Replace self.repository with the new repository.
 
834
            # Do our best to transfer the lock state (i.e. lock-tokens and
 
835
            # lock count) of self.repository to the new repository.
 
836
            lock_token = old_repository.lock_write().repository_token
 
837
            self.repository = new_repository
 
838
            if isinstance(self, remote.RemoteBranch):
 
839
                # Remote branches can have a second reference to the old
 
840
                # repository that need to be replaced.
 
841
                if self._real_branch is not None:
 
842
                    self._real_branch.repository = new_repository
 
843
            self.repository.lock_write(token=lock_token)
 
844
            if lock_token is not None:
 
845
                old_repository.leave_lock_in_place()
797
846
            old_repository.unlock()
 
847
            if lock_token is not None:
 
848
                # XXX: self.repository.leave_lock_in_place() before this
 
849
                # function will not be preserved.  Fortunately that doesn't
 
850
                # affect the current default format (2a), and would be a
 
851
                # corner-case anyway.
 
852
                #  - Andrew Bennetts, 2010/06/30
 
853
                self.repository.dont_leave_lock_in_place()
 
854
            old_lock_count = 0
 
855
            while True:
 
856
                try:
 
857
                    old_repository.unlock()
 
858
                except errors.LockNotHeld:
 
859
                    break
 
860
                old_lock_count += 1
 
861
            if old_lock_count == 0:
 
862
                raise AssertionError(
 
863
                    'old_repository should have been locked at least once.')
 
864
            for i in range(old_lock_count-1):
 
865
                self.repository.lock_write()
 
866
            # Fetch from the old repository into the new.
798
867
            old_repository.lock_read()
799
868
            try:
800
 
                # Repositories don't offer an interface to remove fallback
801
 
                # repositories today; take the conceptually simpler option and just
802
 
                # reopen it.  We reopen it starting from the URL so that we
803
 
                # get a separate connection for RemoteRepositories and can
804
 
                # stream from one of them to the other.  This does mean doing
805
 
                # separate SSH connection setup, but unstacking is not a
806
 
                # common operation so it's tolerable.
807
 
                new_bzrdir = bzrdir.BzrDir.open(self.bzrdir.root_transport.base)
808
 
                new_repository = new_bzrdir.find_repository()
809
 
                self.repository = new_repository
810
 
                if self.repository._fallback_repositories:
811
 
                    raise AssertionError("didn't expect %r to have "
812
 
                        "fallback_repositories"
813
 
                        % (self.repository,))
814
 
                # this is not paired with an unlock because it's just restoring
815
 
                # the previous state; the lock's released when set_stacked_on_url
816
 
                # returns
817
 
                self.repository.lock_write()
818
869
                # XXX: If you unstack a branch while it has a working tree
819
870
                # with a pending merge, the pending-merged revisions will no
820
871
                # longer be present.  You can (probably) revert and remerge.
821
 
                #
822
 
                # XXX: This only fetches up to the tip of the repository; it
823
 
                # doesn't bring across any tags.  That's fairly consistent
824
 
                # with how branch works, but perhaps not ideal.
825
 
                self.repository.fetch(old_repository,
826
 
                    revision_id=self.last_revision(),
827
 
                    find_ghosts=True)
 
872
                try:
 
873
                    tags_to_fetch = set(self.tags.get_reverse_tag_dict())
 
874
                except errors.TagsNotSupported:
 
875
                    tags_to_fetch = set()
 
876
                fetch_spec = _mod_graph.NotInOtherForRevs(self.repository,
 
877
                    old_repository, required_ids=[self.last_revision()],
 
878
                    if_present_ids=tags_to_fetch, find_ghosts=True).execute()
 
879
                self.repository.fetch(old_repository, fetch_spec=fetch_spec)
828
880
            finally:
829
881
                old_repository.unlock()
830
882
        finally:
835
887
 
836
888
        :seealso: Branch._get_tags_bytes.
837
889
        """
838
 
        return _run_with_write_locked_target(self, self._transport.put_bytes,
839
 
            'tags', bytes)
 
890
        return _run_with_write_locked_target(self, self._set_tags_bytes_locked,
 
891
                bytes)
 
892
 
 
893
    def _set_tags_bytes_locked(self, bytes):
 
894
        self._tags_bytes = bytes
 
895
        return self._transport.put_bytes('tags', bytes)
840
896
 
841
897
    def _cache_revision_history(self, rev_history):
842
898
        """Set the cached revision history to rev_history.
869
925
        self._revision_history_cache = None
870
926
        self._revision_id_to_revno_cache = None
871
927
        self._last_revision_info_cache = None
 
928
        self._master_branch_cache = None
872
929
        self._merge_sorted_revisions_cache = None
873
930
        self._partial_revision_history_cache = []
874
931
        self._partial_revision_id_to_revno_cache = {}
 
932
        self._tags_bytes = None
875
933
 
876
934
    def _gen_revision_history(self):
877
935
        """Return sequence of revision hashes on to this branch.
938
996
        else:
939
997
            return (0, _mod_revision.NULL_REVISION)
940
998
 
941
 
    @deprecated_method(deprecated_in((1, 6, 0)))
942
 
    def missing_revisions(self, other, stop_revision=None):
943
 
        """Return a list of new revisions that would perfectly fit.
944
 
 
945
 
        If self and other have not diverged, return a list of the revisions
946
 
        present in other, but missing from self.
947
 
        """
948
 
        self_history = self.revision_history()
949
 
        self_len = len(self_history)
950
 
        other_history = other.revision_history()
951
 
        other_len = len(other_history)
952
 
        common_index = min(self_len, other_len) -1
953
 
        if common_index >= 0 and \
954
 
            self_history[common_index] != other_history[common_index]:
955
 
            raise errors.DivergedBranches(self, other)
956
 
 
957
 
        if stop_revision is None:
958
 
            stop_revision = other_len
959
 
        else:
960
 
            if stop_revision > other_len:
961
 
                raise errors.NoSuchRevision(self, stop_revision)
962
 
        return other_history[self_len:stop_revision]
963
 
 
964
 
    @needs_write_lock
965
999
    def update_revisions(self, other, stop_revision=None, overwrite=False,
966
 
                         graph=None):
 
1000
                         graph=None, fetch_tags=True):
967
1001
        """Pull in new perfect-fit revisions.
968
1002
 
969
1003
        :param other: Another Branch to pull from
972
1006
            to see if it is a proper descendant.
973
1007
        :param graph: A Graph object that can be used to query history
974
1008
            information. This can be None.
 
1009
        :param fetch_tags: Flag that specifies if tags from other should be
 
1010
            fetched too.
975
1011
        :return: None
976
1012
        """
977
1013
        return InterBranch.get(other, self).update_revisions(stop_revision,
978
 
            overwrite, graph)
 
1014
            overwrite, graph, fetch_tags=fetch_tags)
979
1015
 
 
1016
    @deprecated_method(deprecated_in((2, 4, 0)))
980
1017
    def import_last_revision_info(self, source_repo, revno, revid):
981
1018
        """Set the last revision info, importing from another repo if necessary.
982
1019
 
983
 
        This is used by the bound branch code to upload a revision to
984
 
        the master branch first before updating the tip of the local branch.
985
 
 
986
1020
        :param source_repo: Source repository to optionally fetch from
987
1021
        :param revno: Revision number of the new tip
988
1022
        :param revid: Revision id of the new tip
991
1025
            self.repository.fetch(source_repo, revision_id=revid)
992
1026
        self.set_last_revision_info(revno, revid)
993
1027
 
 
1028
    def import_last_revision_info_and_tags(self, source, revno, revid):
 
1029
        """Set the last revision info, importing from another repo if necessary.
 
1030
 
 
1031
        This is used by the bound branch code to upload a revision to
 
1032
        the master branch first before updating the tip of the local branch.
 
1033
        Revisions referenced by source's tags are also transferred.
 
1034
 
 
1035
        :param source: Source branch to optionally fetch from
 
1036
        :param revno: Revision number of the new tip
 
1037
        :param revid: Revision id of the new tip
 
1038
        """
 
1039
        if not self.repository.has_same_location(source.repository):
 
1040
            try:
 
1041
                tags_to_fetch = set(source.tags.get_reverse_tag_dict())
 
1042
            except errors.TagsNotSupported:
 
1043
                tags_to_fetch = set()
 
1044
            fetch_spec = _mod_graph.NotInOtherForRevs(self.repository,
 
1045
                source.repository, [revid],
 
1046
                if_present_ids=tags_to_fetch).execute()
 
1047
            self.repository.fetch(source.repository, fetch_spec=fetch_spec)
 
1048
        self.set_last_revision_info(revno, revid)
 
1049
 
994
1050
    def revision_id_to_revno(self, revision_id):
995
1051
        """Given a revision id, return its revno"""
996
1052
        if _mod_revision.is_null(revision_id):
1016
1072
            self._extend_partial_history(distance_from_last)
1017
1073
        return self._partial_revision_history_cache[distance_from_last]
1018
1074
 
1019
 
    @needs_write_lock
1020
1075
    def pull(self, source, overwrite=False, stop_revision=None,
1021
1076
             possible_transports=None, *args, **kwargs):
1022
1077
        """Mirror source into this branch.
1218
1273
        return result
1219
1274
 
1220
1275
    @needs_read_lock
1221
 
    def sprout(self, to_bzrdir, revision_id=None, repository_policy=None):
 
1276
    def sprout(self, to_bzrdir, revision_id=None, repository_policy=None,
 
1277
            repository=None):
1222
1278
        """Create a new line of development from the branch, into to_bzrdir.
1223
1279
 
1224
1280
        to_bzrdir controls the branch format.
1229
1285
        if (repository_policy is not None and
1230
1286
            repository_policy.requires_stacking()):
1231
1287
            to_bzrdir._format.require_stacking(_skip_repo=True)
1232
 
        result = to_bzrdir.create_branch()
 
1288
        result = to_bzrdir.create_branch(repository=repository)
1233
1289
        result.lock_write()
1234
1290
        try:
1235
1291
            if repository_policy is not None:
1265
1321
                revno = 1
1266
1322
        destination.set_last_revision_info(revno, revision_id)
1267
1323
 
1268
 
    @needs_read_lock
1269
1324
    def copy_content_into(self, destination, revision_id=None):
1270
1325
        """Copy the content of self into destination.
1271
1326
 
1272
1327
        revision_id: if not None, the revision history in the new branch will
1273
1328
                     be truncated to end with revision_id.
1274
1329
        """
1275
 
        self.update_references(destination)
1276
 
        self._synchronize_history(destination, revision_id)
1277
 
        try:
1278
 
            parent = self.get_parent()
1279
 
        except errors.InaccessibleParent, e:
1280
 
            mutter('parent was not accessible to copy: %s', e)
1281
 
        else:
1282
 
            if parent:
1283
 
                destination.set_parent(parent)
1284
 
        if self._push_should_merge_tags():
1285
 
            self.tags.merge_to(destination.tags)
 
1330
        return InterBranch.get(self, destination).copy_content_into(
 
1331
            revision_id=revision_id)
1286
1332
 
1287
1333
    def update_references(self, target):
1288
1334
        if not getattr(self._format, 'supports_reference_locations', False):
1333
1379
        """Return the most suitable metadir for a checkout of this branch.
1334
1380
        Weaves are used if this branch's repository uses weaves.
1335
1381
        """
1336
 
        if isinstance(self.bzrdir, bzrdir.BzrDirPreSplitOut):
1337
 
            from bzrlib.repofmt import weaverepo
1338
 
            format = bzrdir.BzrDirMetaFormat1()
1339
 
            format.repository_format = weaverepo.RepositoryFormat7()
1340
 
        else:
1341
 
            format = self.repository.bzrdir.checkout_metadir()
1342
 
            format.set_branch_format(self._format)
 
1382
        format = self.repository.bzrdir.checkout_metadir()
 
1383
        format.set_branch_format(self._format)
1343
1384
        return format
1344
1385
 
1345
1386
    def create_clone_on_transport(self, to_transport, revision_id=None,
1346
 
        stacked_on=None, create_prefix=False, use_existing_dir=False):
 
1387
        stacked_on=None, create_prefix=False, use_existing_dir=False,
 
1388
        no_tree=None):
1347
1389
        """Create a clone of this branch and its bzrdir.
1348
1390
 
1349
1391
        :param to_transport: The transport to clone onto.
1362
1404
            revision_id = self.last_revision()
1363
1405
        dir_to = self.bzrdir.clone_on_transport(to_transport,
1364
1406
            revision_id=revision_id, stacked_on=stacked_on,
1365
 
            create_prefix=create_prefix, use_existing_dir=use_existing_dir)
 
1407
            create_prefix=create_prefix, use_existing_dir=use_existing_dir,
 
1408
            no_tree=no_tree)
1366
1409
        return dir_to.open_branch()
1367
1410
 
1368
1411
    def create_checkout(self, to_location, revision_id=None,
1483
1526
        else:
1484
1527
            raise AssertionError("invalid heads: %r" % (heads,))
1485
1528
 
1486
 
 
1487
 
class BranchFormat(object):
 
1529
    def heads_to_fetch(self):
 
1530
        """Return the heads that must and that should be fetched to copy this
 
1531
        branch into another repo.
 
1532
 
 
1533
        :returns: a 2-tuple of (must_fetch, if_present_fetch).  must_fetch is a
 
1534
            set of heads that must be fetched.  if_present_fetch is a set of
 
1535
            heads that must be fetched if present, but no error is necessary if
 
1536
            they are not present.
 
1537
        """
 
1538
        # For bzr native formats must_fetch is just the tip, and if_present_fetch
 
1539
        # are the tags.
 
1540
        must_fetch = set([self.last_revision()])
 
1541
        try:
 
1542
            if_present_fetch = set(self.tags.get_reverse_tag_dict())
 
1543
        except errors.TagsNotSupported:
 
1544
            if_present_fetch = set()
 
1545
        must_fetch.discard(_mod_revision.NULL_REVISION)
 
1546
        if_present_fetch.discard(_mod_revision.NULL_REVISION)
 
1547
        return must_fetch, if_present_fetch
 
1548
 
 
1549
 
 
1550
class BranchFormat(controldir.ControlComponentFormat):
1488
1551
    """An encapsulation of the initialization and open routines for a format.
1489
1552
 
1490
1553
    Formats provide three things:
1493
1556
     * an open routine.
1494
1557
 
1495
1558
    Formats are placed in an dict by their format string for reference
1496
 
    during branch opening. Its not required that these be instances, they
 
1559
    during branch opening. It's not required that these be instances, they
1497
1560
    can be classes themselves with class methods - it simply depends on
1498
1561
    whether state is needed for a given format or not.
1499
1562
 
1502
1565
    object will be created every time regardless.
1503
1566
    """
1504
1567
 
1505
 
    _default_format = None
1506
 
    """The default format used for new branches."""
1507
 
 
1508
 
    _formats = {}
1509
 
    """The known formats."""
1510
 
 
1511
1568
    can_set_append_revisions_only = True
1512
1569
 
1513
1570
    def __eq__(self, other):
1522
1579
        try:
1523
1580
            transport = a_bzrdir.get_branch_transport(None, name=name)
1524
1581
            format_string = transport.get_bytes("format")
1525
 
            return klass._formats[format_string]
 
1582
            return format_registry.get(format_string)
1526
1583
        except errors.NoSuchFile:
1527
1584
            raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)
1528
1585
        except KeyError:
1529
1586
            raise errors.UnknownFormatError(format=format_string, kind='branch')
1530
1587
 
1531
1588
    @classmethod
 
1589
    @deprecated_method(deprecated_in((2, 4, 0)))
1532
1590
    def get_default_format(klass):
1533
1591
        """Return the current default format."""
1534
 
        return klass._default_format
 
1592
        return format_registry.get_default()
 
1593
 
 
1594
    @classmethod
 
1595
    @deprecated_method(deprecated_in((2, 4, 0)))
 
1596
    def get_formats(klass):
 
1597
        """Get all the known formats.
 
1598
 
 
1599
        Warning: This triggers a load of all lazy registered formats: do not
 
1600
        use except when that is desireed.
 
1601
        """
 
1602
        return format_registry._get_all()
1535
1603
 
1536
1604
    def get_reference(self, a_bzrdir, name=None):
1537
1605
        """Get the target reference of the branch in a_bzrdir.
1576
1644
        for hook in hooks:
1577
1645
            hook(params)
1578
1646
 
1579
 
    def _initialize_helper(self, a_bzrdir, utf8_files, name=None,
1580
 
                           lock_type='metadir', set_format=True):
1581
 
        """Initialize a branch in a bzrdir, with specified files
1582
 
 
1583
 
        :param a_bzrdir: The bzrdir to initialize the branch in
1584
 
        :param utf8_files: The files to create as a list of
1585
 
            (filename, content) tuples
1586
 
        :param name: Name of colocated branch to create, if any
1587
 
        :param set_format: If True, set the format with
1588
 
            self.get_format_string.  (BzrBranch4 has its format set
1589
 
            elsewhere)
1590
 
        :return: a branch in this format
1591
 
        """
1592
 
        mutter('creating branch %r in %s', self, a_bzrdir.user_url)
1593
 
        branch_transport = a_bzrdir.get_branch_transport(self, name=name)
1594
 
        lock_map = {
1595
 
            'metadir': ('lock', lockdir.LockDir),
1596
 
            'branch4': ('branch-lock', lockable_files.TransportLock),
1597
 
        }
1598
 
        lock_name, lock_class = lock_map[lock_type]
1599
 
        control_files = lockable_files.LockableFiles(branch_transport,
1600
 
            lock_name, lock_class)
1601
 
        control_files.create_lock()
1602
 
        try:
1603
 
            control_files.lock_write()
1604
 
        except errors.LockContention:
1605
 
            if lock_type != 'branch4':
1606
 
                raise
1607
 
            lock_taken = False
1608
 
        else:
1609
 
            lock_taken = True
1610
 
        if set_format:
1611
 
            utf8_files += [('format', self.get_format_string())]
1612
 
        try:
1613
 
            for (filename, content) in utf8_files:
1614
 
                branch_transport.put_bytes(
1615
 
                    filename, content,
1616
 
                    mode=a_bzrdir._get_file_mode())
1617
 
        finally:
1618
 
            if lock_taken:
1619
 
                control_files.unlock()
1620
 
        branch = self.open(a_bzrdir, name, _found=True)
1621
 
        self._run_post_branch_init_hooks(a_bzrdir, name, branch)
1622
 
        return branch
1623
 
 
1624
 
    def initialize(self, a_bzrdir, name=None):
 
1647
    def initialize(self, a_bzrdir, name=None, repository=None):
1625
1648
        """Create a branch of this format in a_bzrdir.
1626
1649
        
1627
1650
        :param name: Name of the colocated branch to create.
1661
1684
        """
1662
1685
        raise NotImplementedError(self.network_name)
1663
1686
 
1664
 
    def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False):
 
1687
    def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False,
 
1688
            found_repository=None):
1665
1689
        """Return the branch object for a_bzrdir
1666
1690
 
1667
1691
        :param a_bzrdir: A BzrDir that contains a branch.
1674
1698
        raise NotImplementedError(self.open)
1675
1699
 
1676
1700
    @classmethod
 
1701
    @deprecated_method(deprecated_in((2, 4, 0)))
1677
1702
    def register_format(klass, format):
1678
 
        """Register a metadir format."""
1679
 
        klass._formats[format.get_format_string()] = format
1680
 
        # Metadir formats have a network name of their format string, and get
1681
 
        # registered as class factories.
1682
 
        network_format_registry.register(format.get_format_string(), format.__class__)
 
1703
        """Register a metadir format.
 
1704
 
 
1705
        See MetaDirBranchFormatFactory for the ability to register a format
 
1706
        without loading the code the format needs until it is actually used.
 
1707
        """
 
1708
        format_registry.register(format)
1683
1709
 
1684
1710
    @classmethod
 
1711
    @deprecated_method(deprecated_in((2, 4, 0)))
1685
1712
    def set_default_format(klass, format):
1686
 
        klass._default_format = format
 
1713
        format_registry.set_default(format)
1687
1714
 
1688
1715
    def supports_set_append_revisions_only(self):
1689
1716
        """True if this format supports set_append_revisions_only."""
1693
1720
        """True if this format records a stacked-on branch."""
1694
1721
        return False
1695
1722
 
 
1723
    def supports_leaving_lock(self):
 
1724
        """True if this format supports leaving locks in place."""
 
1725
        return False # by default
 
1726
 
1696
1727
    @classmethod
 
1728
    @deprecated_method(deprecated_in((2, 4, 0)))
1697
1729
    def unregister_format(klass, format):
1698
 
        del klass._formats[format.get_format_string()]
 
1730
        format_registry.remove(format)
1699
1731
 
1700
1732
    def __str__(self):
1701
1733
        return self.get_format_description().rstrip()
1705
1737
        return False  # by default
1706
1738
 
1707
1739
 
 
1740
class MetaDirBranchFormatFactory(registry._LazyObjectGetter):
 
1741
    """A factory for a BranchFormat object, permitting simple lazy registration.
 
1742
    
 
1743
    While none of the built in BranchFormats are lazy registered yet,
 
1744
    bzrlib.tests.test_branch.TestMetaDirBranchFormatFactory demonstrates how to
 
1745
    use it, and the bzr-loom plugin uses it as well (see
 
1746
    bzrlib.plugins.loom.formats).
 
1747
    """
 
1748
 
 
1749
    def __init__(self, format_string, module_name, member_name):
 
1750
        """Create a MetaDirBranchFormatFactory.
 
1751
 
 
1752
        :param format_string: The format string the format has.
 
1753
        :param module_name: Module to load the format class from.
 
1754
        :param member_name: Attribute name within the module for the format class.
 
1755
        """
 
1756
        registry._LazyObjectGetter.__init__(self, module_name, member_name)
 
1757
        self._format_string = format_string
 
1758
        
 
1759
    def get_format_string(self):
 
1760
        """See BranchFormat.get_format_string."""
 
1761
        return self._format_string
 
1762
 
 
1763
    def __call__(self):
 
1764
        """Used for network_format_registry support."""
 
1765
        return self.get_obj()()
 
1766
 
 
1767
 
1708
1768
class BranchHooks(Hooks):
1709
1769
    """A dictionary mapping hook name to a list of callables for branch hooks.
1710
1770
 
1718
1778
        These are all empty initially, because by default nothing should get
1719
1779
        notified.
1720
1780
        """
1721
 
        Hooks.__init__(self)
1722
 
        self.create_hook(HookPoint('set_rh',
 
1781
        Hooks.__init__(self, "bzrlib.branch", "Branch.hooks")
 
1782
        self.add_hook('set_rh',
1723
1783
            "Invoked whenever the revision history has been set via "
1724
1784
            "set_revision_history. The api signature is (branch, "
1725
1785
            "revision_history), and the branch will be write-locked. "
1726
1786
            "The set_rh hook can be expensive for bzr to trigger, a better "
1727
 
            "hook to use is Branch.post_change_branch_tip.", (0, 15), None))
1728
 
        self.create_hook(HookPoint('open',
 
1787
            "hook to use is Branch.post_change_branch_tip.", (0, 15))
 
1788
        self.add_hook('open',
1729
1789
            "Called with the Branch object that has been opened after a "
1730
 
            "branch is opened.", (1, 8), None))
1731
 
        self.create_hook(HookPoint('post_push',
 
1790
            "branch is opened.", (1, 8))
 
1791
        self.add_hook('post_push',
1732
1792
            "Called after a push operation completes. post_push is called "
1733
1793
            "with a bzrlib.branch.BranchPushResult object and only runs in the "
1734
 
            "bzr client.", (0, 15), None))
1735
 
        self.create_hook(HookPoint('post_pull',
 
1794
            "bzr client.", (0, 15))
 
1795
        self.add_hook('post_pull',
1736
1796
            "Called after a pull operation completes. post_pull is called "
1737
1797
            "with a bzrlib.branch.PullResult object and only runs in the "
1738
 
            "bzr client.", (0, 15), None))
1739
 
        self.create_hook(HookPoint('pre_commit',
1740
 
            "Called after a commit is calculated but before it is is "
 
1798
            "bzr client.", (0, 15))
 
1799
        self.add_hook('pre_commit',
 
1800
            "Called after a commit is calculated but before it is "
1741
1801
            "completed. pre_commit is called with (local, master, old_revno, "
1742
1802
            "old_revid, future_revno, future_revid, tree_delta, future_tree"
1743
1803
            "). old_revid is NULL_REVISION for the first commit to a branch, "
1745
1805
            "basis revision. hooks MUST NOT modify this delta. "
1746
1806
            " future_tree is an in-memory tree obtained from "
1747
1807
            "CommitBuilder.revision_tree() and hooks MUST NOT modify this "
1748
 
            "tree.", (0,91), None))
1749
 
        self.create_hook(HookPoint('post_commit',
 
1808
            "tree.", (0,91))
 
1809
        self.add_hook('post_commit',
1750
1810
            "Called in the bzr client after a commit has completed. "
1751
1811
            "post_commit is called with (local, master, old_revno, old_revid, "
1752
1812
            "new_revno, new_revid). old_revid is NULL_REVISION for the first "
1753
 
            "commit to a branch.", (0, 15), None))
1754
 
        self.create_hook(HookPoint('post_uncommit',
 
1813
            "commit to a branch.", (0, 15))
 
1814
        self.add_hook('post_uncommit',
1755
1815
            "Called in the bzr client after an uncommit completes. "
1756
1816
            "post_uncommit is called with (local, master, old_revno, "
1757
1817
            "old_revid, new_revno, new_revid) where local is the local branch "
1758
1818
            "or None, master is the target branch, and an empty branch "
1759
 
            "receives new_revno of 0, new_revid of None.", (0, 15), None))
1760
 
        self.create_hook(HookPoint('pre_change_branch_tip',
 
1819
            "receives new_revno of 0, new_revid of None.", (0, 15))
 
1820
        self.add_hook('pre_change_branch_tip',
1761
1821
            "Called in bzr client and server before a change to the tip of a "
1762
1822
            "branch is made. pre_change_branch_tip is called with a "
1763
1823
            "bzrlib.branch.ChangeBranchTipParams. Note that push, pull, "
1764
 
            "commit, uncommit will all trigger this hook.", (1, 6), None))
1765
 
        self.create_hook(HookPoint('post_change_branch_tip',
 
1824
            "commit, uncommit will all trigger this hook.", (1, 6))
 
1825
        self.add_hook('post_change_branch_tip',
1766
1826
            "Called in bzr client and server after a change to the tip of a "
1767
1827
            "branch is made. post_change_branch_tip is called with a "
1768
1828
            "bzrlib.branch.ChangeBranchTipParams. Note that push, pull, "
1769
 
            "commit, uncommit will all trigger this hook.", (1, 4), None))
1770
 
        self.create_hook(HookPoint('transform_fallback_location',
 
1829
            "commit, uncommit will all trigger this hook.", (1, 4))
 
1830
        self.add_hook('transform_fallback_location',
1771
1831
            "Called when a stacked branch is activating its fallback "
1772
1832
            "locations. transform_fallback_location is called with (branch, "
1773
1833
            "url), and should return a new url. Returning the same url "
1778
1838
            "fallback locations have not been activated. When there are "
1779
1839
            "multiple hooks installed for transform_fallback_location, "
1780
1840
            "all are called with the url returned from the previous hook."
1781
 
            "The order is however undefined.", (1, 9), None))
1782
 
        self.create_hook(HookPoint('automatic_tag_name',
1783
 
            "Called to determine an automatic tag name for a revision."
 
1841
            "The order is however undefined.", (1, 9))
 
1842
        self.add_hook('automatic_tag_name',
 
1843
            "Called to determine an automatic tag name for a revision. "
1784
1844
            "automatic_tag_name is called with (branch, revision_id) and "
1785
1845
            "should return a tag name or None if no tag name could be "
1786
1846
            "determined. The first non-None tag name returned will be used.",
1787
 
            (2, 2), None))
1788
 
        self.create_hook(HookPoint('post_branch_init',
 
1847
            (2, 2))
 
1848
        self.add_hook('post_branch_init',
1789
1849
            "Called after new branch initialization completes. "
1790
1850
            "post_branch_init is called with a "
1791
1851
            "bzrlib.branch.BranchInitHookParams. "
1792
1852
            "Note that init, branch and checkout (both heavyweight and "
1793
 
            "lightweight) will all trigger this hook.", (2, 2), None))
1794
 
        self.create_hook(HookPoint('post_switch',
 
1853
            "lightweight) will all trigger this hook.", (2, 2))
 
1854
        self.add_hook('post_switch',
1795
1855
            "Called after a checkout switches branch. "
1796
1856
            "post_switch is called with a "
1797
 
            "bzrlib.branch.SwitchHookParams.", (2, 2), None))
 
1857
            "bzrlib.branch.SwitchHookParams.", (2, 2))
1798
1858
 
1799
1859
 
1800
1860
 
1877
1937
        return self.__dict__ == other.__dict__
1878
1938
 
1879
1939
    def __repr__(self):
1880
 
        if self.branch:
1881
 
            return "<%s of %s>" % (self.__class__.__name__, self.branch)
1882
 
        else:
1883
 
            return "<%s of format:%s bzrdir:%s>" % (
1884
 
                self.__class__.__name__, self.branch,
1885
 
                self.format, self.bzrdir)
 
1940
        return "<%s of %s>" % (self.__class__.__name__, self.branch)
1886
1941
 
1887
1942
 
1888
1943
class SwitchHookParams(object):
1918
1973
            self.revision_id)
1919
1974
 
1920
1975
 
1921
 
class BzrBranchFormat4(BranchFormat):
1922
 
    """Bzr branch format 4.
1923
 
 
1924
 
    This format has:
1925
 
     - a revision-history file.
1926
 
     - a branch-lock lock file [ to be shared with the bzrdir ]
1927
 
    """
1928
 
 
1929
 
    def get_format_description(self):
1930
 
        """See BranchFormat.get_format_description()."""
1931
 
        return "Branch format 4"
1932
 
 
1933
 
    def initialize(self, a_bzrdir, name=None):
1934
 
        """Create a branch of this format in a_bzrdir."""
1935
 
        utf8_files = [('revision-history', ''),
1936
 
                      ('branch-name', ''),
1937
 
                      ]
1938
 
        return self._initialize_helper(a_bzrdir, utf8_files, name=name,
1939
 
                                       lock_type='branch4', set_format=False)
1940
 
 
1941
 
    def __init__(self):
1942
 
        super(BzrBranchFormat4, self).__init__()
1943
 
        self._matchingbzrdir = bzrdir.BzrDirFormat6()
1944
 
 
1945
 
    def network_name(self):
1946
 
        """The network name for this format is the control dirs disk label."""
1947
 
        return self._matchingbzrdir.get_format_string()
1948
 
 
1949
 
    def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False):
1950
 
        """See BranchFormat.open()."""
1951
 
        if not _found:
1952
 
            # we are being called directly and must probe.
1953
 
            raise NotImplementedError
1954
 
        return BzrBranch(_format=self,
1955
 
                         _control_files=a_bzrdir._control_files,
1956
 
                         a_bzrdir=a_bzrdir,
1957
 
                         name=name,
1958
 
                         _repository=a_bzrdir.open_repository())
1959
 
 
1960
 
    def __str__(self):
1961
 
        return "Bazaar-NG branch format 4"
1962
 
 
1963
 
 
1964
1976
class BranchFormatMetadir(BranchFormat):
1965
1977
    """Common logic for meta-dir based branch formats."""
1966
1978
 
1968
1980
        """What class to instantiate on open calls."""
1969
1981
        raise NotImplementedError(self._branch_class)
1970
1982
 
 
1983
    def _initialize_helper(self, a_bzrdir, utf8_files, name=None,
 
1984
                           repository=None):
 
1985
        """Initialize a branch in a bzrdir, with specified files
 
1986
 
 
1987
        :param a_bzrdir: The bzrdir to initialize the branch in
 
1988
        :param utf8_files: The files to create as a list of
 
1989
            (filename, content) tuples
 
1990
        :param name: Name of colocated branch to create, if any
 
1991
        :return: a branch in this format
 
1992
        """
 
1993
        mutter('creating branch %r in %s', self, a_bzrdir.user_url)
 
1994
        branch_transport = a_bzrdir.get_branch_transport(self, name=name)
 
1995
        control_files = lockable_files.LockableFiles(branch_transport,
 
1996
            'lock', lockdir.LockDir)
 
1997
        control_files.create_lock()
 
1998
        control_files.lock_write()
 
1999
        try:
 
2000
            utf8_files += [('format', self.get_format_string())]
 
2001
            for (filename, content) in utf8_files:
 
2002
                branch_transport.put_bytes(
 
2003
                    filename, content,
 
2004
                    mode=a_bzrdir._get_file_mode())
 
2005
        finally:
 
2006
            control_files.unlock()
 
2007
        branch = self.open(a_bzrdir, name, _found=True,
 
2008
                found_repository=repository)
 
2009
        self._run_post_branch_init_hooks(a_bzrdir, name, branch)
 
2010
        return branch
 
2011
 
1971
2012
    def network_name(self):
1972
2013
        """A simple byte string uniquely identifying this format for RPC calls.
1973
2014
 
1975
2016
        """
1976
2017
        return self.get_format_string()
1977
2018
 
1978
 
    def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False):
 
2019
    def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False,
 
2020
            found_repository=None):
1979
2021
        """See BranchFormat.open()."""
1980
2022
        if not _found:
1981
2023
            format = BranchFormat.find_format(a_bzrdir, name=name)
1986
2028
        try:
1987
2029
            control_files = lockable_files.LockableFiles(transport, 'lock',
1988
2030
                                                         lockdir.LockDir)
 
2031
            if found_repository is None:
 
2032
                found_repository = a_bzrdir.find_repository()
1989
2033
            return self._branch_class()(_format=self,
1990
2034
                              _control_files=control_files,
1991
2035
                              name=name,
1992
2036
                              a_bzrdir=a_bzrdir,
1993
 
                              _repository=a_bzrdir.find_repository(),
 
2037
                              _repository=found_repository,
1994
2038
                              ignore_fallbacks=ignore_fallbacks)
1995
2039
        except errors.NoSuchFile:
1996
2040
            raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)
2003
2047
    def supports_tags(self):
2004
2048
        return True
2005
2049
 
 
2050
    def supports_leaving_lock(self):
 
2051
        return True
 
2052
 
2006
2053
 
2007
2054
class BzrBranchFormat5(BranchFormatMetadir):
2008
2055
    """Bzr branch format 5.
2028
2075
        """See BranchFormat.get_format_description()."""
2029
2076
        return "Branch format 5"
2030
2077
 
2031
 
    def initialize(self, a_bzrdir, name=None):
 
2078
    def initialize(self, a_bzrdir, name=None, repository=None):
2032
2079
        """Create a branch of this format in a_bzrdir."""
2033
2080
        utf8_files = [('revision-history', ''),
2034
2081
                      ('branch-name', ''),
2035
2082
                      ]
2036
 
        return self._initialize_helper(a_bzrdir, utf8_files, name)
 
2083
        return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
2037
2084
 
2038
2085
    def supports_tags(self):
2039
2086
        return False
2061
2108
        """See BranchFormat.get_format_description()."""
2062
2109
        return "Branch format 6"
2063
2110
 
2064
 
    def initialize(self, a_bzrdir, name=None):
 
2111
    def initialize(self, a_bzrdir, name=None, repository=None):
2065
2112
        """Create a branch of this format in a_bzrdir."""
2066
2113
        utf8_files = [('last-revision', '0 null:\n'),
2067
2114
                      ('branch.conf', ''),
2068
2115
                      ('tags', ''),
2069
2116
                      ]
2070
 
        return self._initialize_helper(a_bzrdir, utf8_files, name)
 
2117
        return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
2071
2118
 
2072
2119
    def make_tags(self, branch):
2073
2120
        """See bzrlib.branch.BranchFormat.make_tags()."""
2091
2138
        """See BranchFormat.get_format_description()."""
2092
2139
        return "Branch format 8"
2093
2140
 
2094
 
    def initialize(self, a_bzrdir, name=None):
 
2141
    def initialize(self, a_bzrdir, name=None, repository=None):
2095
2142
        """Create a branch of this format in a_bzrdir."""
2096
2143
        utf8_files = [('last-revision', '0 null:\n'),
2097
2144
                      ('branch.conf', ''),
2098
2145
                      ('tags', ''),
2099
2146
                      ('references', '')
2100
2147
                      ]
2101
 
        return self._initialize_helper(a_bzrdir, utf8_files, name)
2102
 
 
2103
 
    def __init__(self):
2104
 
        super(BzrBranchFormat8, self).__init__()
2105
 
        self._matchingbzrdir.repository_format = \
2106
 
            RepositoryFormatKnitPack5RichRoot()
 
2148
        return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
2107
2149
 
2108
2150
    def make_tags(self, branch):
2109
2151
        """See bzrlib.branch.BranchFormat.make_tags()."""
2118
2160
    supports_reference_locations = True
2119
2161
 
2120
2162
 
2121
 
class BzrBranchFormat7(BzrBranchFormat8):
 
2163
class BzrBranchFormat7(BranchFormatMetadir):
2122
2164
    """Branch format with last-revision, tags, and a stacked location pointer.
2123
2165
 
2124
2166
    The stacked location pointer is passed down to the repository and requires
2127
2169
    This format was introduced in bzr 1.6.
2128
2170
    """
2129
2171
 
2130
 
    def initialize(self, a_bzrdir, name=None):
 
2172
    def initialize(self, a_bzrdir, name=None, repository=None):
2131
2173
        """Create a branch of this format in a_bzrdir."""
2132
2174
        utf8_files = [('last-revision', '0 null:\n'),
2133
2175
                      ('branch.conf', ''),
2134
2176
                      ('tags', ''),
2135
2177
                      ]
2136
 
        return self._initialize_helper(a_bzrdir, utf8_files, name)
 
2178
        return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
2137
2179
 
2138
2180
    def _branch_class(self):
2139
2181
        return BzrBranch7
2149
2191
    def supports_set_append_revisions_only(self):
2150
2192
        return True
2151
2193
 
 
2194
    def supports_stacking(self):
 
2195
        return True
 
2196
 
 
2197
    def make_tags(self, branch):
 
2198
        """See bzrlib.branch.BranchFormat.make_tags()."""
 
2199
        return BasicTags(branch)
 
2200
 
2152
2201
    supports_reference_locations = False
2153
2202
 
2154
2203
 
2181
2230
        transport = a_bzrdir.get_branch_transport(None, name=name)
2182
2231
        location = transport.put_bytes('location', to_branch.base)
2183
2232
 
2184
 
    def initialize(self, a_bzrdir, name=None, target_branch=None):
 
2233
    def initialize(self, a_bzrdir, name=None, target_branch=None,
 
2234
            repository=None):
2185
2235
        """Create a branch of this format in a_bzrdir."""
2186
2236
        if target_branch is None:
2187
2237
            # this format does not implement branch itself, thus the implicit
2215
2265
        return clone
2216
2266
 
2217
2267
    def open(self, a_bzrdir, name=None, _found=False, location=None,
2218
 
             possible_transports=None, ignore_fallbacks=False):
 
2268
             possible_transports=None, ignore_fallbacks=False,
 
2269
             found_repository=None):
2219
2270
        """Return the branch that the branch reference in a_bzrdir points at.
2220
2271
 
2221
2272
        :param a_bzrdir: A BzrDir that contains a branch.
2252
2303
        return result
2253
2304
 
2254
2305
 
 
2306
class BranchFormatRegistry(controldir.ControlComponentFormatRegistry):
 
2307
    """Branch format registry."""
 
2308
 
 
2309
    def __init__(self, other_registry=None):
 
2310
        super(BranchFormatRegistry, self).__init__(other_registry)
 
2311
        self._default_format = None
 
2312
 
 
2313
    def set_default(self, format):
 
2314
        self._default_format = format
 
2315
 
 
2316
    def get_default(self):
 
2317
        return self._default_format
 
2318
 
 
2319
 
2255
2320
network_format_registry = registry.FormatRegistry()
2256
2321
"""Registry of formats indexed by their network name.
2257
2322
 
2260
2325
BranchFormat.network_name() for more detail.
2261
2326
"""
2262
2327
 
 
2328
format_registry = BranchFormatRegistry(network_format_registry)
 
2329
 
2263
2330
 
2264
2331
# formats which have no format string are not discoverable
2265
2332
# and not independently creatable, so are not registered.
2267
2334
__format6 = BzrBranchFormat6()
2268
2335
__format7 = BzrBranchFormat7()
2269
2336
__format8 = BzrBranchFormat8()
2270
 
BranchFormat.register_format(__format5)
2271
 
BranchFormat.register_format(BranchReferenceFormat())
2272
 
BranchFormat.register_format(__format6)
2273
 
BranchFormat.register_format(__format7)
2274
 
BranchFormat.register_format(__format8)
2275
 
BranchFormat.set_default_format(__format7)
2276
 
_legacy_formats = [BzrBranchFormat4(),
2277
 
    ]
2278
 
network_format_registry.register(
2279
 
    _legacy_formats[0].network_name(), _legacy_formats[0].__class__)
 
2337
format_registry.register(__format5)
 
2338
format_registry.register(BranchReferenceFormat())
 
2339
format_registry.register(__format6)
 
2340
format_registry.register(__format7)
 
2341
format_registry.register(__format8)
 
2342
format_registry.set_default(__format7)
2280
2343
 
2281
2344
 
2282
2345
class BranchWriteLockResult(LogicalLockResult):
2558
2621
        result.target_branch = target
2559
2622
        result.old_revno, result.old_revid = target.last_revision_info()
2560
2623
        self.update_references(target)
2561
 
        if result.old_revid != self.last_revision():
 
2624
        if result.old_revid != stop_revision:
2562
2625
            # We assume that during 'push' this repository is closer than
2563
2626
            # the target.
2564
2627
            graph = self.repository.get_graph(target.repository)
2565
2628
            target.update_revisions(self, stop_revision,
2566
2629
                overwrite=overwrite, graph=graph)
2567
2630
        if self._push_should_merge_tags():
2568
 
            result.tag_conflicts = self.tags.merge_to(target.tags,
2569
 
                overwrite)
 
2631
            result.tag_conflicts = self.tags.merge_to(target.tags, overwrite)
2570
2632
        result.new_revno, result.new_revid = target.last_revision_info()
2571
2633
        return result
2572
2634
 
2604
2666
        """Return the branch we are bound to.
2605
2667
 
2606
2668
        :return: Either a Branch, or None
2607
 
 
2608
 
        This could memoise the branch, but if thats done
2609
 
        it must be revalidated on each new lock.
2610
 
        So for now we just don't memoise it.
2611
 
        # RBC 20060304 review this decision.
2612
2669
        """
 
2670
        if self._master_branch_cache is None:
 
2671
            self._master_branch_cache = self._get_master_branch(
 
2672
                possible_transports)
 
2673
        return self._master_branch_cache
 
2674
 
 
2675
    def _get_master_branch(self, possible_transports):
2613
2676
        bound_loc = self.get_bound_location()
2614
2677
        if not bound_loc:
2615
2678
            return None
2626
2689
 
2627
2690
        :param location: URL to the target branch
2628
2691
        """
 
2692
        self._master_branch_cache = None
2629
2693
        if location:
2630
2694
            self._transport.put_bytes('bound', location+'\n',
2631
2695
                mode=self.bzrdir._get_file_mode())
2883
2947
 
2884
2948
    def set_bound_location(self, location):
2885
2949
        """See Branch.set_push_location."""
 
2950
        self._master_branch_cache = None
2886
2951
        result = None
2887
2952
        config = self.get_config()
2888
2953
        if location is None:
2965
3030
        try:
2966
3031
            index = self._partial_revision_history_cache.index(revision_id)
2967
3032
        except ValueError:
2968
 
            self._extend_partial_history(stop_revision=revision_id)
 
3033
            try:
 
3034
                self._extend_partial_history(stop_revision=revision_id)
 
3035
            except errors.RevisionNotPresent, e:
 
3036
                raise errors.GhostRevisionsHaveNoRevno(revision_id, e.revision_id)
2969
3037
            index = len(self._partial_revision_history_cache) - 1
2970
3038
            if self._partial_revision_history_cache[index] != revision_id:
2971
3039
                raise errors.NoSuchRevision(self, revision_id)
3026
3094
    :ivar tag_conflicts: A list of tag conflicts, see BasicTags.merge_to
3027
3095
    """
3028
3096
 
 
3097
    @deprecated_method(deprecated_in((2, 3, 0)))
3029
3098
    def __int__(self):
3030
 
        # DEPRECATED: pull used to return the change in revno
 
3099
        """Return the relative change in revno.
 
3100
 
 
3101
        :deprecated: Use `new_revno` and `old_revno` instead.
 
3102
        """
3031
3103
        return self.new_revno - self.old_revno
3032
3104
 
3033
3105
    def report(self, to_file):
3058
3130
        target, otherwise it will be None.
3059
3131
    """
3060
3132
 
 
3133
    @deprecated_method(deprecated_in((2, 3, 0)))
3061
3134
    def __int__(self):
3062
 
        # DEPRECATED: push used to return the change in revno
 
3135
        """Return the relative change in revno.
 
3136
 
 
3137
        :deprecated: Use `new_revno` and `old_revno` instead.
 
3138
        """
3063
3139
        return self.new_revno - self.old_revno
3064
3140
 
3065
3141
    def report(self, to_file):
3188
3264
    _optimisers = []
3189
3265
    """The available optimised InterBranch types."""
3190
3266
 
3191
 
    @staticmethod
3192
 
    def _get_branch_formats_to_test():
3193
 
        """Return a tuple with the Branch formats to use when testing."""
3194
 
        raise NotImplementedError(InterBranch._get_branch_formats_to_test)
 
3267
    @classmethod
 
3268
    def _get_branch_formats_to_test(klass):
 
3269
        """Return an iterable of format tuples for testing.
 
3270
        
 
3271
        :return: An iterable of (from_format, to_format) to use when testing
 
3272
            this InterBranch class. Each InterBranch class should define this
 
3273
            method itself.
 
3274
        """
 
3275
        raise NotImplementedError(klass._get_branch_formats_to_test)
3195
3276
 
 
3277
    @needs_write_lock
3196
3278
    def pull(self, overwrite=False, stop_revision=None,
3197
3279
             possible_transports=None, local=False):
3198
3280
        """Mirror source into target branch.
3203
3285
        """
3204
3286
        raise NotImplementedError(self.pull)
3205
3287
 
 
3288
    @needs_write_lock
3206
3289
    def update_revisions(self, stop_revision=None, overwrite=False,
3207
 
                         graph=None):
 
3290
                         graph=None, fetch_tags=True):
3208
3291
        """Pull in new perfect-fit revisions.
3209
3292
 
3210
3293
        :param stop_revision: Updated until the given revision
3212
3295
            to see if it is a proper descendant.
3213
3296
        :param graph: A Graph object that can be used to query history
3214
3297
            information. This can be None.
 
3298
        :param fetch_tags: Flag that specifies if tags from source should be
 
3299
            fetched too.
3215
3300
        :return: None
3216
3301
        """
3217
3302
        raise NotImplementedError(self.update_revisions)
3218
3303
 
 
3304
    @needs_write_lock
3219
3305
    def push(self, overwrite=False, stop_revision=None,
3220
3306
             _override_hook_source_branch=None):
3221
3307
        """Mirror the source branch into the target branch.
3224
3310
        """
3225
3311
        raise NotImplementedError(self.push)
3226
3312
 
 
3313
    @needs_write_lock
 
3314
    def copy_content_into(self, revision_id=None):
 
3315
        """Copy the content of source into target
 
3316
 
 
3317
        revision_id: if not None, the revision history in the new branch will
 
3318
                     be truncated to end with revision_id.
 
3319
        """
 
3320
        raise NotImplementedError(self.copy_content_into)
 
3321
 
 
3322
    @needs_write_lock
 
3323
    def fetch(self, stop_revision=None, fetch_spec=None):
 
3324
        """Fetch revisions.
 
3325
 
 
3326
        :param stop_revision: Last revision to fetch
 
3327
        :param fetch_spec: Fetch spec.
 
3328
        """
 
3329
        raise NotImplementedError(self.fetch)
 
3330
 
3227
3331
 
3228
3332
class GenericInterBranch(InterBranch):
3229
 
    """InterBranch implementation that uses public Branch functions.
3230
 
    """
3231
 
 
3232
 
    @staticmethod
3233
 
    def _get_branch_formats_to_test():
3234
 
        return BranchFormat._default_format, BranchFormat._default_format
3235
 
 
 
3333
    """InterBranch implementation that uses public Branch functions."""
 
3334
 
 
3335
    @classmethod
 
3336
    def is_compatible(klass, source, target):
 
3337
        # GenericBranch uses the public API, so always compatible
 
3338
        return True
 
3339
 
 
3340
    @classmethod
 
3341
    def _get_branch_formats_to_test(klass):
 
3342
        return [(format_registry.get_default(), format_registry.get_default())]
 
3343
 
 
3344
    @classmethod
 
3345
    def unwrap_format(klass, format):
 
3346
        if isinstance(format, remote.RemoteBranchFormat):
 
3347
            format._ensure_real()
 
3348
            return format._custom_format
 
3349
        return format
 
3350
 
 
3351
    @needs_write_lock
 
3352
    def copy_content_into(self, revision_id=None):
 
3353
        """Copy the content of source into target
 
3354
 
 
3355
        revision_id: if not None, the revision history in the new branch will
 
3356
                     be truncated to end with revision_id.
 
3357
        """
 
3358
        self.source.update_references(self.target)
 
3359
        self.source._synchronize_history(self.target, revision_id)
 
3360
        try:
 
3361
            parent = self.source.get_parent()
 
3362
        except errors.InaccessibleParent, e:
 
3363
            mutter('parent was not accessible to copy: %s', e)
 
3364
        else:
 
3365
            if parent:
 
3366
                self.target.set_parent(parent)
 
3367
        if self.source._push_should_merge_tags():
 
3368
            self.source.tags.merge_to(self.target.tags)
 
3369
 
 
3370
    @needs_write_lock
 
3371
    def fetch(self, stop_revision=None, fetch_spec=None):
 
3372
        if fetch_spec is not None and stop_revision is not None:
 
3373
            raise AssertionError(
 
3374
                "fetch_spec and last_revision are mutually exclusive.")
 
3375
        if self.target.base == self.source.base:
 
3376
            return (0, [])
 
3377
        self.source.lock_read()
 
3378
        try:
 
3379
            if stop_revision is None and fetch_spec is None:
 
3380
                stop_revision = self.source.last_revision()
 
3381
                stop_revision = _mod_revision.ensure_null(stop_revision)
 
3382
            return self.target.repository.fetch(self.source.repository,
 
3383
                revision_id=stop_revision, fetch_spec=fetch_spec)
 
3384
        finally:
 
3385
            self.source.unlock()
 
3386
 
 
3387
    @needs_write_lock
3236
3388
    def update_revisions(self, stop_revision=None, overwrite=False,
3237
 
        graph=None):
 
3389
        graph=None, fetch_tags=True):
3238
3390
        """See InterBranch.update_revisions()."""
3239
 
        self.source.lock_read()
3240
 
        try:
3241
 
            other_revno, other_last_revision = self.source.last_revision_info()
3242
 
            stop_revno = None # unknown
3243
 
            if stop_revision is None:
3244
 
                stop_revision = other_last_revision
3245
 
                if _mod_revision.is_null(stop_revision):
3246
 
                    # if there are no commits, we're done.
3247
 
                    return
3248
 
                stop_revno = other_revno
3249
 
 
3250
 
            # what's the current last revision, before we fetch [and change it
3251
 
            # possibly]
3252
 
            last_rev = _mod_revision.ensure_null(self.target.last_revision())
3253
 
            # we fetch here so that we don't process data twice in the common
3254
 
            # case of having something to pull, and so that the check for
3255
 
            # already merged can operate on the just fetched graph, which will
3256
 
            # be cached in memory.
3257
 
            self.target.fetch(self.source, stop_revision)
3258
 
            # Check to see if one is an ancestor of the other
3259
 
            if not overwrite:
3260
 
                if graph is None:
3261
 
                    graph = self.target.repository.get_graph()
3262
 
                if self.target._check_if_descendant_or_diverged(
3263
 
                        stop_revision, last_rev, graph, self.source):
3264
 
                    # stop_revision is a descendant of last_rev, but we aren't
3265
 
                    # overwriting, so we're done.
3266
 
                    return
3267
 
            if stop_revno is None:
3268
 
                if graph is None:
3269
 
                    graph = self.target.repository.get_graph()
3270
 
                this_revno, this_last_revision = \
3271
 
                        self.target.last_revision_info()
3272
 
                stop_revno = graph.find_distance_to_null(stop_revision,
3273
 
                                [(other_last_revision, other_revno),
3274
 
                                 (this_last_revision, this_revno)])
3275
 
            self.target.set_last_revision_info(stop_revno, stop_revision)
3276
 
        finally:
3277
 
            self.source.unlock()
3278
 
 
 
3391
        other_revno, other_last_revision = self.source.last_revision_info()
 
3392
        stop_revno = None # unknown
 
3393
        if stop_revision is None:
 
3394
            stop_revision = other_last_revision
 
3395
            if _mod_revision.is_null(stop_revision):
 
3396
                # if there are no commits, we're done.
 
3397
                return
 
3398
            stop_revno = other_revno
 
3399
 
 
3400
        # what's the current last revision, before we fetch [and change it
 
3401
        # possibly]
 
3402
        last_rev = _mod_revision.ensure_null(self.target.last_revision())
 
3403
        # we fetch here so that we don't process data twice in the common
 
3404
        # case of having something to pull, and so that the check for
 
3405
        # already merged can operate on the just fetched graph, which will
 
3406
        # be cached in memory.
 
3407
        if fetch_tags:
 
3408
            fetch_spec_factory = fetch.FetchSpecFactory()
 
3409
            fetch_spec_factory.source_branch = self.source
 
3410
            fetch_spec_factory.source_branch_stop_revision_id = stop_revision
 
3411
            fetch_spec_factory.source_repo = self.source.repository
 
3412
            fetch_spec_factory.target_repo = self.target.repository
 
3413
            fetch_spec_factory.target_repo_kind = fetch.TargetRepoKinds.PREEXISTING
 
3414
            fetch_spec = fetch_spec_factory.make_fetch_spec()
 
3415
        else:
 
3416
            fetch_spec = _mod_graph.NotInOtherForRevs(self.target.repository,
 
3417
                self.source.repository, revision_ids=[stop_revision]).execute()
 
3418
        self.target.fetch(self.source, fetch_spec=fetch_spec)
 
3419
        # Check to see if one is an ancestor of the other
 
3420
        if not overwrite:
 
3421
            if graph is None:
 
3422
                graph = self.target.repository.get_graph()
 
3423
            if self.target._check_if_descendant_or_diverged(
 
3424
                    stop_revision, last_rev, graph, self.source):
 
3425
                # stop_revision is a descendant of last_rev, but we aren't
 
3426
                # overwriting, so we're done.
 
3427
                return
 
3428
        if stop_revno is None:
 
3429
            if graph is None:
 
3430
                graph = self.target.repository.get_graph()
 
3431
            this_revno, this_last_revision = \
 
3432
                    self.target.last_revision_info()
 
3433
            stop_revno = graph.find_distance_to_null(stop_revision,
 
3434
                            [(other_last_revision, other_revno),
 
3435
                             (this_last_revision, this_revno)])
 
3436
        self.target.set_last_revision_info(stop_revno, stop_revision)
 
3437
 
 
3438
    @needs_write_lock
3279
3439
    def pull(self, overwrite=False, stop_revision=None,
3280
 
             possible_transports=None, _hook_master=None, run_hooks=True,
 
3440
             possible_transports=None, run_hooks=True,
3281
3441
             _override_hook_target=None, local=False):
3282
 
        """See Branch.pull.
 
3442
        """Pull from source into self, updating my master if any.
3283
3443
 
3284
 
        :param _hook_master: Private parameter - set the branch to
3285
 
            be supplied as the master to pull hooks.
3286
3444
        :param run_hooks: Private parameter - if false, this branch
3287
3445
            is being called because it's the master of the primary branch,
3288
3446
            so it should not run its hooks.
3289
 
        :param _override_hook_target: Private parameter - set the branch to be
3290
 
            supplied as the target_branch to pull hooks.
3291
 
        :param local: Only update the local branch, and not the bound branch.
3292
3447
        """
3293
 
        # This type of branch can't be bound.
3294
 
        if local:
 
3448
        bound_location = self.target.get_bound_location()
 
3449
        if local and not bound_location:
3295
3450
            raise errors.LocalRequiresBoundBranch()
3296
 
        result = PullResult()
3297
 
        result.source_branch = self.source
3298
 
        if _override_hook_target is None:
3299
 
            result.target_branch = self.target
3300
 
        else:
3301
 
            result.target_branch = _override_hook_target
3302
 
        self.source.lock_read()
 
3451
        master_branch = None
 
3452
        source_is_master = (self.source.user_url == bound_location)
 
3453
        if not local and bound_location and not source_is_master:
 
3454
            # not pulling from master, so we need to update master.
 
3455
            master_branch = self.target.get_master_branch(possible_transports)
 
3456
            master_branch.lock_write()
3303
3457
        try:
3304
 
            # We assume that during 'pull' the target repository is closer than
3305
 
            # the source one.
3306
 
            self.source.update_references(self.target)
3307
 
            graph = self.target.repository.get_graph(self.source.repository)
3308
 
            # TODO: Branch formats should have a flag that indicates 
3309
 
            # that revno's are expensive, and pull() should honor that flag.
3310
 
            # -- JRV20090506
3311
 
            result.old_revno, result.old_revid = \
3312
 
                self.target.last_revision_info()
3313
 
            self.target.update_revisions(self.source, stop_revision,
3314
 
                overwrite=overwrite, graph=graph)
3315
 
            # TODO: The old revid should be specified when merging tags, 
3316
 
            # so a tags implementation that versions tags can only 
3317
 
            # pull in the most recent changes. -- JRV20090506
3318
 
            result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
3319
 
                overwrite)
3320
 
            result.new_revno, result.new_revid = self.target.last_revision_info()
3321
 
            if _hook_master:
3322
 
                result.master_branch = _hook_master
3323
 
                result.local_branch = result.target_branch
3324
 
            else:
3325
 
                result.master_branch = result.target_branch
3326
 
                result.local_branch = None
3327
 
            if run_hooks:
3328
 
                for hook in Branch.hooks['post_pull']:
3329
 
                    hook(result)
 
3458
            if master_branch:
 
3459
                # pull from source into master.
 
3460
                master_branch.pull(self.source, overwrite, stop_revision,
 
3461
                    run_hooks=False)
 
3462
            return self._pull(overwrite,
 
3463
                stop_revision, _hook_master=master_branch,
 
3464
                run_hooks=run_hooks,
 
3465
                _override_hook_target=_override_hook_target,
 
3466
                merge_tags_to_master=not source_is_master)
3330
3467
        finally:
3331
 
            self.source.unlock()
3332
 
        return result
 
3468
            if master_branch:
 
3469
                master_branch.unlock()
3333
3470
 
3334
3471
    def push(self, overwrite=False, stop_revision=None,
3335
3472
             _override_hook_source_branch=None):
3375
3512
                # push into the master from the source branch.
3376
3513
                self.source._basic_push(master_branch, overwrite, stop_revision)
3377
3514
                # and push into the target branch from the source. Note that we
3378
 
                # push from the source branch again, because its considered the
 
3515
                # push from the source branch again, because it's considered the
3379
3516
                # highest bandwidth repository.
3380
3517
                result = self.source._basic_push(self.target, overwrite,
3381
3518
                    stop_revision)
3397
3534
            _run_hooks()
3398
3535
            return result
3399
3536
 
3400
 
    @classmethod
3401
 
    def is_compatible(self, source, target):
3402
 
        # GenericBranch uses the public API, so always compatible
3403
 
        return True
3404
 
 
3405
 
 
3406
 
class InterToBranch5(GenericInterBranch):
3407
 
 
3408
 
    @staticmethod
3409
 
    def _get_branch_formats_to_test():
3410
 
        return BranchFormat._default_format, BzrBranchFormat5()
3411
 
 
3412
 
    def pull(self, overwrite=False, stop_revision=None,
3413
 
             possible_transports=None, run_hooks=True,
3414
 
             _override_hook_target=None, local=False):
3415
 
        """Pull from source into self, updating my master if any.
3416
 
 
 
3537
    def _pull(self, overwrite=False, stop_revision=None,
 
3538
             possible_transports=None, _hook_master=None, run_hooks=True,
 
3539
             _override_hook_target=None, local=False,
 
3540
             merge_tags_to_master=True):
 
3541
        """See Branch.pull.
 
3542
 
 
3543
        This function is the core worker, used by GenericInterBranch.pull to
 
3544
        avoid duplication when pulling source->master and source->local.
 
3545
 
 
3546
        :param _hook_master: Private parameter - set the branch to
 
3547
            be supplied as the master to pull hooks.
3417
3548
        :param run_hooks: Private parameter - if false, this branch
3418
3549
            is being called because it's the master of the primary branch,
3419
3550
            so it should not run its hooks.
 
3551
            is being called because it's the master of the primary branch,
 
3552
            so it should not run its hooks.
 
3553
        :param _override_hook_target: Private parameter - set the branch to be
 
3554
            supplied as the target_branch to pull hooks.
 
3555
        :param local: Only update the local branch, and not the bound branch.
3420
3556
        """
3421
 
        bound_location = self.target.get_bound_location()
3422
 
        if local and not bound_location:
 
3557
        # This type of branch can't be bound.
 
3558
        if local:
3423
3559
            raise errors.LocalRequiresBoundBranch()
3424
 
        master_branch = None
3425
 
        if not local and bound_location and self.source.user_url != bound_location:
3426
 
            # not pulling from master, so we need to update master.
3427
 
            master_branch = self.target.get_master_branch(possible_transports)
3428
 
            master_branch.lock_write()
 
3560
        result = PullResult()
 
3561
        result.source_branch = self.source
 
3562
        if _override_hook_target is None:
 
3563
            result.target_branch = self.target
 
3564
        else:
 
3565
            result.target_branch = _override_hook_target
 
3566
        self.source.lock_read()
3429
3567
        try:
3430
 
            if master_branch:
3431
 
                # pull from source into master.
3432
 
                master_branch.pull(self.source, overwrite, stop_revision,
3433
 
                    run_hooks=False)
3434
 
            return super(InterToBranch5, self).pull(overwrite,
3435
 
                stop_revision, _hook_master=master_branch,
3436
 
                run_hooks=run_hooks,
3437
 
                _override_hook_target=_override_hook_target)
 
3568
            # We assume that during 'pull' the target repository is closer than
 
3569
            # the source one.
 
3570
            self.source.update_references(self.target)
 
3571
            graph = self.target.repository.get_graph(self.source.repository)
 
3572
            # TODO: Branch formats should have a flag that indicates 
 
3573
            # that revno's are expensive, and pull() should honor that flag.
 
3574
            # -- JRV20090506
 
3575
            result.old_revno, result.old_revid = \
 
3576
                self.target.last_revision_info()
 
3577
            self.target.update_revisions(self.source, stop_revision,
 
3578
                overwrite=overwrite, graph=graph)
 
3579
            # TODO: The old revid should be specified when merging tags, 
 
3580
            # so a tags implementation that versions tags can only 
 
3581
            # pull in the most recent changes. -- JRV20090506
 
3582
            result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
 
3583
                overwrite, ignore_master=not merge_tags_to_master)
 
3584
            result.new_revno, result.new_revid = self.target.last_revision_info()
 
3585
            if _hook_master:
 
3586
                result.master_branch = _hook_master
 
3587
                result.local_branch = result.target_branch
 
3588
            else:
 
3589
                result.master_branch = result.target_branch
 
3590
                result.local_branch = None
 
3591
            if run_hooks:
 
3592
                for hook in Branch.hooks['post_pull']:
 
3593
                    hook(result)
3438
3594
        finally:
3439
 
            if master_branch:
3440
 
                master_branch.unlock()
 
3595
            self.source.unlock()
 
3596
        return result
3441
3597
 
3442
3598
 
3443
3599
InterBranch.register_optimiser(GenericInterBranch)
3444
 
InterBranch.register_optimiser(InterToBranch5)