~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

  • Committer: John Arbash Meinel
  • Date: 2010-11-05 20:54:32 UTC
  • mfrom: (5526 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5527.
  • Revision ID: john@arbash-meinel.com-20101105205432-rmyozu8sthyhmri8
Merge bzr.dev to resolve bzr-2.3.txt (aka NEWS)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011 Canonical Ltd
 
1
# Copyright (C) 2005-2010 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
25
25
        bzrdir,
26
26
        cache_utf8,
27
27
        config as _mod_config,
 
28
        controldir,
28
29
        debug,
29
30
        errors,
30
 
        fetch,
31
 
        graph as _mod_graph,
32
31
        lockdir,
33
32
        lockable_files,
34
33
        remote,
42
41
        urlutils,
43
42
        )
44
43
from bzrlib.config import BranchConfig, TransportConfig
 
44
from bzrlib.repofmt.pack_repo import RepositoryFormatKnitPack5RichRoot
45
45
from bzrlib.tag import (
46
46
    BasicTags,
47
47
    DisabledTags,
48
48
    )
49
49
""")
50
50
 
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
from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises
 
52
from bzrlib.hooks import HookPoint, Hooks
60
53
from bzrlib.inter import InterObject
61
54
from bzrlib.lock import _RelockDebugMixin, LogicalLockResult
62
55
from bzrlib import registry
78
71
    :ivar base:
79
72
        Base directory/url of the branch; using control_url and
80
73
        control_transport is more standardized.
81
 
    :ivar hooks: An instance of BranchHooks.
82
 
    :ivar _master_branch_cache: cached result of get_master_branch, see
83
 
        _clear_cached_state.
 
74
 
 
75
    hooks: An instance of BranchHooks.
84
76
    """
85
77
    # this is really an instance variable - FIXME move it there
86
78
    # - RBC 20060112
100
92
        self._revision_id_to_revno_cache = None
101
93
        self._partial_revision_id_to_revno_cache = {}
102
94
        self._partial_revision_history_cache = []
103
 
        self._tags_bytes = None
104
95
        self._last_revision_info_cache = None
105
 
        self._master_branch_cache = None
106
96
        self._merge_sorted_revisions_cache = None
107
97
        self._open_hook()
108
98
        hooks = Branch.hooks['open']
114
104
 
115
105
    def _activate_fallback_location(self, url):
116
106
        """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
124
107
        repo = self._get_fallback_repository(url)
125
108
        if repo.has_same_location(self.repository):
126
109
            raise errors.UnstackableLocationError(self.user_url, url)
244
227
            possible_transports=[self.bzrdir.root_transport])
245
228
        return a_branch.repository
246
229
 
247
 
    @needs_read_lock
248
230
    def _get_tags_bytes(self):
249
231
        """Get the bytes of a serialised tags dict.
250
232
 
257
239
        :return: The bytes of the tags file.
258
240
        :seealso: Branch._set_tags_bytes.
259
241
        """
260
 
        if self._tags_bytes is None:
261
 
            self._tags_bytes = self._transport.get_bytes('tags')
262
 
        return self._tags_bytes
 
242
        return self._transport.get_bytes('tags')
263
243
 
264
244
    def _get_nick(self, local=False, possible_transports=None):
265
245
        config = self.get_config()
669
649
        raise errors.UnsupportedOperation(self.get_reference_info, self)
670
650
 
671
651
    @needs_write_lock
672
 
    def fetch(self, from_branch, last_revision=None):
 
652
    def fetch(self, from_branch, last_revision=None, pb=None):
673
653
        """Copy revisions from from_branch into this branch.
674
654
 
675
655
        :param from_branch: Where to copy from.
676
656
        :param last_revision: What revision to stop at (None for at the end
677
657
                              of the branch.
 
658
        :param pb: An optional progress bar to use.
678
659
        :return: None
679
660
        """
680
 
        return InterBranch.get(from_branch, self).fetch(last_revision)
 
661
        if self.base == from_branch.base:
 
662
            return (0, [])
 
663
        if pb is not None:
 
664
            symbol_versioning.warn(
 
665
                symbol_versioning.deprecated_in((1, 14, 0))
 
666
                % "pb parameter to fetch()")
 
667
        from_branch.lock_read()
 
668
        try:
 
669
            if last_revision is None:
 
670
                last_revision = from_branch.last_revision()
 
671
                last_revision = _mod_revision.ensure_null(last_revision)
 
672
            return self.repository.fetch(from_branch.repository,
 
673
                                         revision_id=last_revision,
 
674
                                         pb=pb)
 
675
        finally:
 
676
            from_branch.unlock()
681
677
 
682
678
    def get_bound_location(self):
683
679
        """Return the URL of the branch we are bound to.
694
690
 
695
691
    def get_commit_builder(self, parents, config=None, timestamp=None,
696
692
                           timezone=None, committer=None, revprops=None,
697
 
                           revision_id=None, lossy=False):
 
693
                           revision_id=None):
698
694
        """Obtain a CommitBuilder for this branch.
699
695
 
700
696
        :param parents: Revision ids of the parents of the new revision.
704
700
        :param committer: Optional committer to set for commit.
705
701
        :param revprops: Optional dictionary of revision properties.
706
702
        :param revision_id: Optional revision id.
707
 
        :param lossy: Whether to discard data that can not be natively
708
 
            represented, when pushing to a foreign VCS 
709
703
        """
710
704
 
711
705
        if config is None:
712
706
            config = self.get_config()
713
707
 
714
708
        return self.repository.get_commit_builder(self, parents, config,
715
 
            timestamp, timezone, committer, revprops, revision_id,
716
 
            lossy)
 
709
            timestamp, timezone, committer, revprops, revision_id)
717
710
 
718
711
    def get_master_branch(self, possible_transports=None):
719
712
        """Return the branch we are bound to.
797
790
 
798
791
    def _unstack(self):
799
792
        """Change a branch to be unstacked, copying data as needed.
800
 
 
 
793
        
801
794
        Don't call this directly, use set_stacked_on_url(None).
802
795
        """
803
796
        pb = ui.ui_factory.nested_progress_bar()
812
805
            old_repository = self.repository
813
806
            if len(old_repository._fallback_repositories) != 1:
814
807
                raise AssertionError("can't cope with fallback repositories "
815
 
                    "of %r (fallbacks: %r)" % (old_repository,
816
 
                        old_repository._fallback_repositories))
 
808
                    "of %r" % (self.repository,))
817
809
            # Open the new repository object.
818
810
            # Repositories don't offer an interface to remove fallback
819
811
            # repositories today; take the conceptually simpler option and just
867
859
                # XXX: If you unstack a branch while it has a working tree
868
860
                # with a pending merge, the pending-merged revisions will no
869
861
                # longer be present.  You can (probably) revert and remerge.
870
 
                try:
871
 
                    tags_to_fetch = set(self.tags.get_reverse_tag_dict())
872
 
                except errors.TagsNotSupported:
873
 
                    tags_to_fetch = set()
874
 
                fetch_spec = _mod_graph.NotInOtherForRevs(self.repository,
875
 
                    old_repository, required_ids=[self.last_revision()],
876
 
                    if_present_ids=tags_to_fetch, find_ghosts=True).execute()
877
 
                self.repository.fetch(old_repository, fetch_spec=fetch_spec)
 
862
                #
 
863
                # XXX: This only fetches up to the tip of the repository; it
 
864
                # doesn't bring across any tags.  That's fairly consistent
 
865
                # with how branch works, but perhaps not ideal.
 
866
                self.repository.fetch(old_repository,
 
867
                    revision_id=self.last_revision(),
 
868
                    find_ghosts=True)
878
869
            finally:
879
870
                old_repository.unlock()
880
871
        finally:
885
876
 
886
877
        :seealso: Branch._get_tags_bytes.
887
878
        """
888
 
        return _run_with_write_locked_target(self, self._set_tags_bytes_locked,
889
 
                bytes)
890
 
 
891
 
    def _set_tags_bytes_locked(self, bytes):
892
 
        self._tags_bytes = bytes
893
 
        return self._transport.put_bytes('tags', bytes)
 
879
        return _run_with_write_locked_target(self, self._transport.put_bytes,
 
880
            'tags', bytes)
894
881
 
895
882
    def _cache_revision_history(self, rev_history):
896
883
        """Set the cached revision history to rev_history.
923
910
        self._revision_history_cache = None
924
911
        self._revision_id_to_revno_cache = None
925
912
        self._last_revision_info_cache = None
926
 
        self._master_branch_cache = None
927
913
        self._merge_sorted_revisions_cache = None
928
914
        self._partial_revision_history_cache = []
929
915
        self._partial_revision_id_to_revno_cache = {}
930
 
        self._tags_bytes = None
931
916
 
932
917
    def _gen_revision_history(self):
933
918
        """Return sequence of revision hashes on to this branch.
994
979
        else:
995
980
            return (0, _mod_revision.NULL_REVISION)
996
981
 
997
 
    @deprecated_method(deprecated_in((2, 4, 0)))
 
982
    @deprecated_method(deprecated_in((1, 6, 0)))
 
983
    def missing_revisions(self, other, stop_revision=None):
 
984
        """Return a list of new revisions that would perfectly fit.
 
985
 
 
986
        If self and other have not diverged, return a list of the revisions
 
987
        present in other, but missing from self.
 
988
        """
 
989
        self_history = self.revision_history()
 
990
        self_len = len(self_history)
 
991
        other_history = other.revision_history()
 
992
        other_len = len(other_history)
 
993
        common_index = min(self_len, other_len) -1
 
994
        if common_index >= 0 and \
 
995
            self_history[common_index] != other_history[common_index]:
 
996
            raise errors.DivergedBranches(self, other)
 
997
 
 
998
        if stop_revision is None:
 
999
            stop_revision = other_len
 
1000
        else:
 
1001
            if stop_revision > other_len:
 
1002
                raise errors.NoSuchRevision(self, stop_revision)
 
1003
        return other_history[self_len:stop_revision]
 
1004
 
 
1005
    def update_revisions(self, other, stop_revision=None, overwrite=False,
 
1006
                         graph=None):
 
1007
        """Pull in new perfect-fit revisions.
 
1008
 
 
1009
        :param other: Another Branch to pull from
 
1010
        :param stop_revision: Updated until the given revision
 
1011
        :param overwrite: Always set the branch pointer, rather than checking
 
1012
            to see if it is a proper descendant.
 
1013
        :param graph: A Graph object that can be used to query history
 
1014
            information. This can be None.
 
1015
        :return: None
 
1016
        """
 
1017
        return InterBranch.get(other, self).update_revisions(stop_revision,
 
1018
            overwrite, graph)
 
1019
 
998
1020
    def import_last_revision_info(self, source_repo, revno, revid):
999
1021
        """Set the last revision info, importing from another repo if necessary.
1000
1022
 
 
1023
        This is used by the bound branch code to upload a revision to
 
1024
        the master branch first before updating the tip of the local branch.
 
1025
 
1001
1026
        :param source_repo: Source repository to optionally fetch from
1002
1027
        :param revno: Revision number of the new tip
1003
1028
        :param revid: Revision id of the new tip
1006
1031
            self.repository.fetch(source_repo, revision_id=revid)
1007
1032
        self.set_last_revision_info(revno, revid)
1008
1033
 
1009
 
    def import_last_revision_info_and_tags(self, source, revno, revid,
1010
 
                                           lossy=False):
1011
 
        """Set the last revision info, importing from another repo if necessary.
1012
 
 
1013
 
        This is used by the bound branch code to upload a revision to
1014
 
        the master branch first before updating the tip of the local branch.
1015
 
        Revisions referenced by source's tags are also transferred.
1016
 
 
1017
 
        :param source: Source branch to optionally fetch from
1018
 
        :param revno: Revision number of the new tip
1019
 
        :param revid: Revision id of the new tip
1020
 
        :param lossy: Whether to discard metadata that can not be
1021
 
            natively represented
1022
 
        :return: Tuple with the new revision number and revision id
1023
 
            (should only be different from the arguments when lossy=True)
1024
 
        """
1025
 
        if not self.repository.has_same_location(source.repository):
1026
 
            self.fetch(source, revid)
1027
 
        self.set_last_revision_info(revno, revid)
1028
 
        return (revno, revid)
1029
 
 
1030
1034
    def revision_id_to_revno(self, revision_id):
1031
1035
        """Given a revision id, return its revno"""
1032
1036
        if _mod_revision.is_null(revision_id):
1253
1257
        return result
1254
1258
 
1255
1259
    @needs_read_lock
1256
 
    def sprout(self, to_bzrdir, revision_id=None, repository_policy=None,
1257
 
            repository=None):
 
1260
    def sprout(self, to_bzrdir, revision_id=None, repository_policy=None):
1258
1261
        """Create a new line of development from the branch, into to_bzrdir.
1259
1262
 
1260
1263
        to_bzrdir controls the branch format.
1265
1268
        if (repository_policy is not None and
1266
1269
            repository_policy.requires_stacking()):
1267
1270
            to_bzrdir._format.require_stacking(_skip_repo=True)
1268
 
        result = to_bzrdir.create_branch(repository=repository)
 
1271
        result = to_bzrdir.create_branch()
1269
1272
        result.lock_write()
1270
1273
        try:
1271
1274
            if repository_policy is not None:
1359
1362
        """Return the most suitable metadir for a checkout of this branch.
1360
1363
        Weaves are used if this branch's repository uses weaves.
1361
1364
        """
1362
 
        format = self.repository.bzrdir.checkout_metadir()
1363
 
        format.set_branch_format(self._format)
 
1365
        if isinstance(self.bzrdir, bzrdir.BzrDirPreSplitOut):
 
1366
            from bzrlib.repofmt import weaverepo
 
1367
            format = bzrdir.BzrDirMetaFormat1()
 
1368
            format.repository_format = weaverepo.RepositoryFormat7()
 
1369
        else:
 
1370
            format = self.repository.bzrdir.checkout_metadir()
 
1371
            format.set_branch_format(self._format)
1364
1372
        return format
1365
1373
 
1366
1374
    def create_clone_on_transport(self, to_transport, revision_id=None,
1506
1514
        else:
1507
1515
            raise AssertionError("invalid heads: %r" % (heads,))
1508
1516
 
1509
 
    def heads_to_fetch(self):
1510
 
        """Return the heads that must and that should be fetched to copy this
1511
 
        branch into another repo.
1512
 
 
1513
 
        :returns: a 2-tuple of (must_fetch, if_present_fetch).  must_fetch is a
1514
 
            set of heads that must be fetched.  if_present_fetch is a set of
1515
 
            heads that must be fetched if present, but no error is necessary if
1516
 
            they are not present.
1517
 
        """
1518
 
        # For bzr native formats must_fetch is just the tip, and if_present_fetch
1519
 
        # are the tags.
1520
 
        must_fetch = set([self.last_revision()])
1521
 
        try:
1522
 
            if_present_fetch = set(self.tags.get_reverse_tag_dict())
1523
 
        except errors.TagsNotSupported:
1524
 
            if_present_fetch = set()
1525
 
        must_fetch.discard(_mod_revision.NULL_REVISION)
1526
 
        if_present_fetch.discard(_mod_revision.NULL_REVISION)
1527
 
        return must_fetch, if_present_fetch
1528
 
 
1529
 
 
1530
 
class BranchFormat(controldir.ControlComponentFormat):
 
1517
 
 
1518
class BranchFormat(object):
1531
1519
    """An encapsulation of the initialization and open routines for a format.
1532
1520
 
1533
1521
    Formats provide three things:
1545
1533
    object will be created every time regardless.
1546
1534
    """
1547
1535
 
 
1536
    _default_format = None
 
1537
    """The default format used for new branches."""
 
1538
 
 
1539
    _formats = {}
 
1540
    """The known formats."""
 
1541
 
1548
1542
    can_set_append_revisions_only = True
1549
1543
 
1550
1544
    def __eq__(self, other):
1559
1553
        try:
1560
1554
            transport = a_bzrdir.get_branch_transport(None, name=name)
1561
1555
            format_string = transport.get_bytes("format")
1562
 
            return format_registry.get(format_string)
 
1556
            format = klass._formats[format_string]
 
1557
            if isinstance(format, MetaDirBranchFormatFactory):
 
1558
                return format()
 
1559
            return format
1563
1560
        except errors.NoSuchFile:
1564
1561
            raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)
1565
1562
        except KeyError:
1566
1563
            raise errors.UnknownFormatError(format=format_string, kind='branch')
1567
1564
 
1568
1565
    @classmethod
1569
 
    @deprecated_method(deprecated_in((2, 4, 0)))
1570
1566
    def get_default_format(klass):
1571
1567
        """Return the current default format."""
1572
 
        return format_registry.get_default()
 
1568
        return klass._default_format
1573
1569
 
1574
1570
    @classmethod
1575
 
    @deprecated_method(deprecated_in((2, 4, 0)))
1576
1571
    def get_formats(klass):
1577
1572
        """Get all the known formats.
1578
1573
 
1579
1574
        Warning: This triggers a load of all lazy registered formats: do not
1580
1575
        use except when that is desireed.
1581
1576
        """
1582
 
        return format_registry._get_all()
 
1577
        result = []
 
1578
        for fmt in klass._formats.values():
 
1579
            if isinstance(fmt, MetaDirBranchFormatFactory):
 
1580
                fmt = fmt()
 
1581
            result.append(fmt)
 
1582
        return result
1583
1583
 
1584
1584
    def get_reference(self, a_bzrdir, name=None):
1585
1585
        """Get the target reference of the branch in a_bzrdir.
1624
1624
        for hook in hooks:
1625
1625
            hook(params)
1626
1626
 
1627
 
    def initialize(self, a_bzrdir, name=None, repository=None):
 
1627
    def _initialize_helper(self, a_bzrdir, utf8_files, name=None,
 
1628
                           lock_type='metadir', set_format=True):
 
1629
        """Initialize a branch in a bzrdir, with specified files
 
1630
 
 
1631
        :param a_bzrdir: The bzrdir to initialize the branch in
 
1632
        :param utf8_files: The files to create as a list of
 
1633
            (filename, content) tuples
 
1634
        :param name: Name of colocated branch to create, if any
 
1635
        :param set_format: If True, set the format with
 
1636
            self.get_format_string.  (BzrBranch4 has its format set
 
1637
            elsewhere)
 
1638
        :return: a branch in this format
 
1639
        """
 
1640
        mutter('creating branch %r in %s', self, a_bzrdir.user_url)
 
1641
        branch_transport = a_bzrdir.get_branch_transport(self, name=name)
 
1642
        lock_map = {
 
1643
            'metadir': ('lock', lockdir.LockDir),
 
1644
            'branch4': ('branch-lock', lockable_files.TransportLock),
 
1645
        }
 
1646
        lock_name, lock_class = lock_map[lock_type]
 
1647
        control_files = lockable_files.LockableFiles(branch_transport,
 
1648
            lock_name, lock_class)
 
1649
        control_files.create_lock()
 
1650
        try:
 
1651
            control_files.lock_write()
 
1652
        except errors.LockContention:
 
1653
            if lock_type != 'branch4':
 
1654
                raise
 
1655
            lock_taken = False
 
1656
        else:
 
1657
            lock_taken = True
 
1658
        if set_format:
 
1659
            utf8_files += [('format', self.get_format_string())]
 
1660
        try:
 
1661
            for (filename, content) in utf8_files:
 
1662
                branch_transport.put_bytes(
 
1663
                    filename, content,
 
1664
                    mode=a_bzrdir._get_file_mode())
 
1665
        finally:
 
1666
            if lock_taken:
 
1667
                control_files.unlock()
 
1668
        branch = self.open(a_bzrdir, name, _found=True)
 
1669
        self._run_post_branch_init_hooks(a_bzrdir, name, branch)
 
1670
        return branch
 
1671
 
 
1672
    def initialize(self, a_bzrdir, name=None):
1628
1673
        """Create a branch of this format in a_bzrdir.
1629
1674
        
1630
1675
        :param name: Name of the colocated branch to create.
1664
1709
        """
1665
1710
        raise NotImplementedError(self.network_name)
1666
1711
 
1667
 
    def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False,
1668
 
            found_repository=None):
 
1712
    def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False):
1669
1713
        """Return the branch object for a_bzrdir
1670
1714
 
1671
1715
        :param a_bzrdir: A BzrDir that contains a branch.
1678
1722
        raise NotImplementedError(self.open)
1679
1723
 
1680
1724
    @classmethod
1681
 
    @deprecated_method(deprecated_in((2, 4, 0)))
1682
1725
    def register_format(klass, format):
1683
1726
        """Register a metadir format.
1684
 
 
 
1727
        
1685
1728
        See MetaDirBranchFormatFactory for the ability to register a format
1686
1729
        without loading the code the format needs until it is actually used.
1687
1730
        """
1688
 
        format_registry.register(format)
 
1731
        klass._formats[format.get_format_string()] = format
 
1732
        # Metadir formats have a network name of their format string, and get
 
1733
        # registered as factories.
 
1734
        if isinstance(format, MetaDirBranchFormatFactory):
 
1735
            network_format_registry.register(format.get_format_string(), format)
 
1736
        else:
 
1737
            network_format_registry.register(format.get_format_string(),
 
1738
                format.__class__)
1689
1739
 
1690
1740
    @classmethod
1691
 
    @deprecated_method(deprecated_in((2, 4, 0)))
1692
1741
    def set_default_format(klass, format):
1693
 
        format_registry.set_default(format)
 
1742
        klass._default_format = format
1694
1743
 
1695
1744
    def supports_set_append_revisions_only(self):
1696
1745
        """True if this format supports set_append_revisions_only."""
1700
1749
        """True if this format records a stacked-on branch."""
1701
1750
        return False
1702
1751
 
1703
 
    def supports_leaving_lock(self):
1704
 
        """True if this format supports leaving locks in place."""
1705
 
        return False # by default
1706
 
 
1707
1752
    @classmethod
1708
 
    @deprecated_method(deprecated_in((2, 4, 0)))
1709
1753
    def unregister_format(klass, format):
1710
 
        format_registry.remove(format)
 
1754
        del klass._formats[format.get_format_string()]
1711
1755
 
1712
1756
    def __str__(self):
1713
1757
        return self.get_format_description().rstrip()
1758
1802
        These are all empty initially, because by default nothing should get
1759
1803
        notified.
1760
1804
        """
1761
 
        Hooks.__init__(self, "bzrlib.branch", "Branch.hooks")
1762
 
        self.add_hook('set_rh',
 
1805
        Hooks.__init__(self)
 
1806
        self.create_hook(HookPoint('set_rh',
1763
1807
            "Invoked whenever the revision history has been set via "
1764
1808
            "set_revision_history. The api signature is (branch, "
1765
1809
            "revision_history), and the branch will be write-locked. "
1766
1810
            "The set_rh hook can be expensive for bzr to trigger, a better "
1767
 
            "hook to use is Branch.post_change_branch_tip.", (0, 15))
1768
 
        self.add_hook('open',
 
1811
            "hook to use is Branch.post_change_branch_tip.", (0, 15), None))
 
1812
        self.create_hook(HookPoint('open',
1769
1813
            "Called with the Branch object that has been opened after a "
1770
 
            "branch is opened.", (1, 8))
1771
 
        self.add_hook('post_push',
 
1814
            "branch is opened.", (1, 8), None))
 
1815
        self.create_hook(HookPoint('post_push',
1772
1816
            "Called after a push operation completes. post_push is called "
1773
1817
            "with a bzrlib.branch.BranchPushResult object and only runs in the "
1774
 
            "bzr client.", (0, 15))
1775
 
        self.add_hook('post_pull',
 
1818
            "bzr client.", (0, 15), None))
 
1819
        self.create_hook(HookPoint('post_pull',
1776
1820
            "Called after a pull operation completes. post_pull is called "
1777
1821
            "with a bzrlib.branch.PullResult object and only runs in the "
1778
 
            "bzr client.", (0, 15))
1779
 
        self.add_hook('pre_commit',
 
1822
            "bzr client.", (0, 15), None))
 
1823
        self.create_hook(HookPoint('pre_commit',
1780
1824
            "Called after a commit is calculated but before it is "
1781
1825
            "completed. pre_commit is called with (local, master, old_revno, "
1782
1826
            "old_revid, future_revno, future_revid, tree_delta, future_tree"
1785
1829
            "basis revision. hooks MUST NOT modify this delta. "
1786
1830
            " future_tree is an in-memory tree obtained from "
1787
1831
            "CommitBuilder.revision_tree() and hooks MUST NOT modify this "
1788
 
            "tree.", (0,91))
1789
 
        self.add_hook('post_commit',
 
1832
            "tree.", (0,91), None))
 
1833
        self.create_hook(HookPoint('post_commit',
1790
1834
            "Called in the bzr client after a commit has completed. "
1791
1835
            "post_commit is called with (local, master, old_revno, old_revid, "
1792
1836
            "new_revno, new_revid). old_revid is NULL_REVISION for the first "
1793
 
            "commit to a branch.", (0, 15))
1794
 
        self.add_hook('post_uncommit',
 
1837
            "commit to a branch.", (0, 15), None))
 
1838
        self.create_hook(HookPoint('post_uncommit',
1795
1839
            "Called in the bzr client after an uncommit completes. "
1796
1840
            "post_uncommit is called with (local, master, old_revno, "
1797
1841
            "old_revid, new_revno, new_revid) where local is the local branch "
1798
1842
            "or None, master is the target branch, and an empty branch "
1799
 
            "receives new_revno of 0, new_revid of None.", (0, 15))
1800
 
        self.add_hook('pre_change_branch_tip',
 
1843
            "receives new_revno of 0, new_revid of None.", (0, 15), None))
 
1844
        self.create_hook(HookPoint('pre_change_branch_tip',
1801
1845
            "Called in bzr client and server before a change to the tip of a "
1802
1846
            "branch is made. pre_change_branch_tip is called with a "
1803
1847
            "bzrlib.branch.ChangeBranchTipParams. Note that push, pull, "
1804
 
            "commit, uncommit will all trigger this hook.", (1, 6))
1805
 
        self.add_hook('post_change_branch_tip',
 
1848
            "commit, uncommit will all trigger this hook.", (1, 6), None))
 
1849
        self.create_hook(HookPoint('post_change_branch_tip',
1806
1850
            "Called in bzr client and server after a change to the tip of a "
1807
1851
            "branch is made. post_change_branch_tip is called with a "
1808
1852
            "bzrlib.branch.ChangeBranchTipParams. Note that push, pull, "
1809
 
            "commit, uncommit will all trigger this hook.", (1, 4))
1810
 
        self.add_hook('transform_fallback_location',
 
1853
            "commit, uncommit will all trigger this hook.", (1, 4), None))
 
1854
        self.create_hook(HookPoint('transform_fallback_location',
1811
1855
            "Called when a stacked branch is activating its fallback "
1812
1856
            "locations. transform_fallback_location is called with (branch, "
1813
1857
            "url), and should return a new url. Returning the same url "
1818
1862
            "fallback locations have not been activated. When there are "
1819
1863
            "multiple hooks installed for transform_fallback_location, "
1820
1864
            "all are called with the url returned from the previous hook."
1821
 
            "The order is however undefined.", (1, 9))
1822
 
        self.add_hook('automatic_tag_name',
 
1865
            "The order is however undefined.", (1, 9), None))
 
1866
        self.create_hook(HookPoint('automatic_tag_name',
1823
1867
            "Called to determine an automatic tag name for a revision. "
1824
1868
            "automatic_tag_name is called with (branch, revision_id) and "
1825
1869
            "should return a tag name or None if no tag name could be "
1826
1870
            "determined. The first non-None tag name returned will be used.",
1827
 
            (2, 2))
1828
 
        self.add_hook('post_branch_init',
 
1871
            (2, 2), None))
 
1872
        self.create_hook(HookPoint('post_branch_init',
1829
1873
            "Called after new branch initialization completes. "
1830
1874
            "post_branch_init is called with a "
1831
1875
            "bzrlib.branch.BranchInitHookParams. "
1832
1876
            "Note that init, branch and checkout (both heavyweight and "
1833
 
            "lightweight) will all trigger this hook.", (2, 2))
1834
 
        self.add_hook('post_switch',
 
1877
            "lightweight) will all trigger this hook.", (2, 2), None))
 
1878
        self.create_hook(HookPoint('post_switch',
1835
1879
            "Called after a checkout switches branch. "
1836
1880
            "post_switch is called with a "
1837
 
            "bzrlib.branch.SwitchHookParams.", (2, 2))
 
1881
            "bzrlib.branch.SwitchHookParams.", (2, 2), None))
1838
1882
 
1839
1883
 
1840
1884
 
1953
1997
            self.revision_id)
1954
1998
 
1955
1999
 
 
2000
class BzrBranchFormat4(BranchFormat):
 
2001
    """Bzr branch format 4.
 
2002
 
 
2003
    This format has:
 
2004
     - a revision-history file.
 
2005
     - a branch-lock lock file [ to be shared with the bzrdir ]
 
2006
    """
 
2007
 
 
2008
    def get_format_description(self):
 
2009
        """See BranchFormat.get_format_description()."""
 
2010
        return "Branch format 4"
 
2011
 
 
2012
    def initialize(self, a_bzrdir, name=None):
 
2013
        """Create a branch of this format in a_bzrdir."""
 
2014
        utf8_files = [('revision-history', ''),
 
2015
                      ('branch-name', ''),
 
2016
                      ]
 
2017
        return self._initialize_helper(a_bzrdir, utf8_files, name=name,
 
2018
                                       lock_type='branch4', set_format=False)
 
2019
 
 
2020
    def __init__(self):
 
2021
        super(BzrBranchFormat4, self).__init__()
 
2022
        self._matchingbzrdir = bzrdir.BzrDirFormat6()
 
2023
 
 
2024
    def network_name(self):
 
2025
        """The network name for this format is the control dirs disk label."""
 
2026
        return self._matchingbzrdir.get_format_string()
 
2027
 
 
2028
    def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False):
 
2029
        """See BranchFormat.open()."""
 
2030
        if not _found:
 
2031
            # we are being called directly and must probe.
 
2032
            raise NotImplementedError
 
2033
        return BzrBranch(_format=self,
 
2034
                         _control_files=a_bzrdir._control_files,
 
2035
                         a_bzrdir=a_bzrdir,
 
2036
                         name=name,
 
2037
                         _repository=a_bzrdir.open_repository())
 
2038
 
 
2039
    def __str__(self):
 
2040
        return "Bazaar-NG branch format 4"
 
2041
 
 
2042
 
1956
2043
class BranchFormatMetadir(BranchFormat):
1957
2044
    """Common logic for meta-dir based branch formats."""
1958
2045
 
1960
2047
        """What class to instantiate on open calls."""
1961
2048
        raise NotImplementedError(self._branch_class)
1962
2049
 
1963
 
    def _initialize_helper(self, a_bzrdir, utf8_files, name=None,
1964
 
                           repository=None):
1965
 
        """Initialize a branch in a bzrdir, with specified files
1966
 
 
1967
 
        :param a_bzrdir: The bzrdir to initialize the branch in
1968
 
        :param utf8_files: The files to create as a list of
1969
 
            (filename, content) tuples
1970
 
        :param name: Name of colocated branch to create, if any
1971
 
        :return: a branch in this format
1972
 
        """
1973
 
        mutter('creating branch %r in %s', self, a_bzrdir.user_url)
1974
 
        branch_transport = a_bzrdir.get_branch_transport(self, name=name)
1975
 
        control_files = lockable_files.LockableFiles(branch_transport,
1976
 
            'lock', lockdir.LockDir)
1977
 
        control_files.create_lock()
1978
 
        control_files.lock_write()
1979
 
        try:
1980
 
            utf8_files += [('format', self.get_format_string())]
1981
 
            for (filename, content) in utf8_files:
1982
 
                branch_transport.put_bytes(
1983
 
                    filename, content,
1984
 
                    mode=a_bzrdir._get_file_mode())
1985
 
        finally:
1986
 
            control_files.unlock()
1987
 
        branch = self.open(a_bzrdir, name, _found=True,
1988
 
                found_repository=repository)
1989
 
        self._run_post_branch_init_hooks(a_bzrdir, name, branch)
1990
 
        return branch
1991
 
 
1992
2050
    def network_name(self):
1993
2051
        """A simple byte string uniquely identifying this format for RPC calls.
1994
2052
 
1996
2054
        """
1997
2055
        return self.get_format_string()
1998
2056
 
1999
 
    def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False,
2000
 
            found_repository=None):
 
2057
    def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False):
2001
2058
        """See BranchFormat.open()."""
2002
2059
        if not _found:
2003
2060
            format = BranchFormat.find_format(a_bzrdir, name=name)
2008
2065
        try:
2009
2066
            control_files = lockable_files.LockableFiles(transport, 'lock',
2010
2067
                                                         lockdir.LockDir)
2011
 
            if found_repository is None:
2012
 
                found_repository = a_bzrdir.find_repository()
2013
2068
            return self._branch_class()(_format=self,
2014
2069
                              _control_files=control_files,
2015
2070
                              name=name,
2016
2071
                              a_bzrdir=a_bzrdir,
2017
 
                              _repository=found_repository,
 
2072
                              _repository=a_bzrdir.find_repository(),
2018
2073
                              ignore_fallbacks=ignore_fallbacks)
2019
2074
        except errors.NoSuchFile:
2020
2075
            raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)
2027
2082
    def supports_tags(self):
2028
2083
        return True
2029
2084
 
2030
 
    def supports_leaving_lock(self):
2031
 
        return True
2032
 
 
2033
2085
 
2034
2086
class BzrBranchFormat5(BranchFormatMetadir):
2035
2087
    """Bzr branch format 5.
2055
2107
        """See BranchFormat.get_format_description()."""
2056
2108
        return "Branch format 5"
2057
2109
 
2058
 
    def initialize(self, a_bzrdir, name=None, repository=None):
 
2110
    def initialize(self, a_bzrdir, name=None):
2059
2111
        """Create a branch of this format in a_bzrdir."""
2060
2112
        utf8_files = [('revision-history', ''),
2061
2113
                      ('branch-name', ''),
2062
2114
                      ]
2063
 
        return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
 
2115
        return self._initialize_helper(a_bzrdir, utf8_files, name)
2064
2116
 
2065
2117
    def supports_tags(self):
2066
2118
        return False
2088
2140
        """See BranchFormat.get_format_description()."""
2089
2141
        return "Branch format 6"
2090
2142
 
2091
 
    def initialize(self, a_bzrdir, name=None, repository=None):
 
2143
    def initialize(self, a_bzrdir, name=None):
2092
2144
        """Create a branch of this format in a_bzrdir."""
2093
2145
        utf8_files = [('last-revision', '0 null:\n'),
2094
2146
                      ('branch.conf', ''),
2095
2147
                      ('tags', ''),
2096
2148
                      ]
2097
 
        return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
 
2149
        return self._initialize_helper(a_bzrdir, utf8_files, name)
2098
2150
 
2099
2151
    def make_tags(self, branch):
2100
2152
        """See bzrlib.branch.BranchFormat.make_tags()."""
2118
2170
        """See BranchFormat.get_format_description()."""
2119
2171
        return "Branch format 8"
2120
2172
 
2121
 
    def initialize(self, a_bzrdir, name=None, repository=None):
 
2173
    def initialize(self, a_bzrdir, name=None):
2122
2174
        """Create a branch of this format in a_bzrdir."""
2123
2175
        utf8_files = [('last-revision', '0 null:\n'),
2124
2176
                      ('branch.conf', ''),
2125
2177
                      ('tags', ''),
2126
2178
                      ('references', '')
2127
2179
                      ]
2128
 
        return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
 
2180
        return self._initialize_helper(a_bzrdir, utf8_files, name)
 
2181
 
 
2182
    def __init__(self):
 
2183
        super(BzrBranchFormat8, self).__init__()
 
2184
        self._matchingbzrdir.repository_format = \
 
2185
            RepositoryFormatKnitPack5RichRoot()
2129
2186
 
2130
2187
    def make_tags(self, branch):
2131
2188
        """See bzrlib.branch.BranchFormat.make_tags()."""
2140
2197
    supports_reference_locations = True
2141
2198
 
2142
2199
 
2143
 
class BzrBranchFormat7(BranchFormatMetadir):
 
2200
class BzrBranchFormat7(BzrBranchFormat8):
2144
2201
    """Branch format with last-revision, tags, and a stacked location pointer.
2145
2202
 
2146
2203
    The stacked location pointer is passed down to the repository and requires
2149
2206
    This format was introduced in bzr 1.6.
2150
2207
    """
2151
2208
 
2152
 
    def initialize(self, a_bzrdir, name=None, repository=None):
 
2209
    def initialize(self, a_bzrdir, name=None):
2153
2210
        """Create a branch of this format in a_bzrdir."""
2154
2211
        utf8_files = [('last-revision', '0 null:\n'),
2155
2212
                      ('branch.conf', ''),
2156
2213
                      ('tags', ''),
2157
2214
                      ]
2158
 
        return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
 
2215
        return self._initialize_helper(a_bzrdir, utf8_files, name)
2159
2216
 
2160
2217
    def _branch_class(self):
2161
2218
        return BzrBranch7
2171
2228
    def supports_set_append_revisions_only(self):
2172
2229
        return True
2173
2230
 
2174
 
    def supports_stacking(self):
2175
 
        return True
2176
 
 
2177
 
    def make_tags(self, branch):
2178
 
        """See bzrlib.branch.BranchFormat.make_tags()."""
2179
 
        return BasicTags(branch)
2180
 
 
2181
2231
    supports_reference_locations = False
2182
2232
 
2183
2233
 
2210
2260
        transport = a_bzrdir.get_branch_transport(None, name=name)
2211
2261
        location = transport.put_bytes('location', to_branch.base)
2212
2262
 
2213
 
    def initialize(self, a_bzrdir, name=None, target_branch=None,
2214
 
            repository=None):
 
2263
    def initialize(self, a_bzrdir, name=None, target_branch=None):
2215
2264
        """Create a branch of this format in a_bzrdir."""
2216
2265
        if target_branch is None:
2217
2266
            # this format does not implement branch itself, thus the implicit
2245
2294
        return clone
2246
2295
 
2247
2296
    def open(self, a_bzrdir, name=None, _found=False, location=None,
2248
 
             possible_transports=None, ignore_fallbacks=False,
2249
 
             found_repository=None):
 
2297
             possible_transports=None, ignore_fallbacks=False):
2250
2298
        """Return the branch that the branch reference in a_bzrdir points at.
2251
2299
 
2252
2300
        :param a_bzrdir: A BzrDir that contains a branch.
2283
2331
        return result
2284
2332
 
2285
2333
 
2286
 
class BranchFormatRegistry(controldir.ControlComponentFormatRegistry):
2287
 
    """Branch format registry."""
2288
 
 
2289
 
    def __init__(self, other_registry=None):
2290
 
        super(BranchFormatRegistry, self).__init__(other_registry)
2291
 
        self._default_format = None
2292
 
 
2293
 
    def set_default(self, format):
2294
 
        self._default_format = format
2295
 
 
2296
 
    def get_default(self):
2297
 
        return self._default_format
2298
 
 
2299
 
 
2300
2334
network_format_registry = registry.FormatRegistry()
2301
2335
"""Registry of formats indexed by their network name.
2302
2336
 
2305
2339
BranchFormat.network_name() for more detail.
2306
2340
"""
2307
2341
 
2308
 
format_registry = BranchFormatRegistry(network_format_registry)
2309
 
 
2310
2342
 
2311
2343
# formats which have no format string are not discoverable
2312
2344
# and not independently creatable, so are not registered.
2314
2346
__format6 = BzrBranchFormat6()
2315
2347
__format7 = BzrBranchFormat7()
2316
2348
__format8 = BzrBranchFormat8()
2317
 
format_registry.register(__format5)
2318
 
format_registry.register(BranchReferenceFormat())
2319
 
format_registry.register(__format6)
2320
 
format_registry.register(__format7)
2321
 
format_registry.register(__format8)
2322
 
format_registry.set_default(__format7)
 
2349
BranchFormat.register_format(__format5)
 
2350
BranchFormat.register_format(BranchReferenceFormat())
 
2351
BranchFormat.register_format(__format6)
 
2352
BranchFormat.register_format(__format7)
 
2353
BranchFormat.register_format(__format8)
 
2354
BranchFormat.set_default_format(__format7)
 
2355
_legacy_formats = [BzrBranchFormat4(),
 
2356
    ]
 
2357
network_format_registry.register(
 
2358
    _legacy_formats[0].network_name(), _legacy_formats[0].__class__)
2323
2359
 
2324
2360
 
2325
2361
class BranchWriteLockResult(LogicalLockResult):
2482
2518
            'revision-history', '\n'.join(history),
2483
2519
            mode=self.bzrdir._get_file_mode())
2484
2520
 
2485
 
    @deprecated_method(deprecated_in((2, 4, 0)))
 
2521
    @needs_write_lock
2486
2522
    def set_revision_history(self, rev_history):
2487
2523
        """See Branch.set_revision_history."""
2488
 
        self._set_revision_history(rev_history)
2489
 
 
2490
 
    @needs_write_lock
2491
 
    def _set_revision_history(self, rev_history):
2492
2524
        if 'evil' in debug.debug_flags:
2493
2525
            mutter_callsite(3, "set_revision_history scales with history.")
2494
2526
        check_not_reserved_id = _mod_revision.check_not_reserved_id
2538
2570
            except ValueError:
2539
2571
                rev = self.repository.get_revision(revision_id)
2540
2572
                new_history = rev.get_history(self.repository)[1:]
2541
 
        destination._set_revision_history(new_history)
 
2573
        destination.set_revision_history(new_history)
2542
2574
 
2543
2575
    @needs_write_lock
2544
2576
    def set_last_revision_info(self, revno, revision_id):
2552
2584
        configured to check constraints on history, in which case this may not
2553
2585
        be permitted.
2554
2586
        """
2555
 
        if not revision_id or not isinstance(revision_id, basestring):
2556
 
            raise errors.InvalidRevisionId(revision_id=revision_id, branch=self)
 
2587
        revision_id = _mod_revision.ensure_null(revision_id)
2557
2588
        # this old format stores the full history, but this api doesn't
2558
2589
        # provide it, so we must generate, and might as well check it's
2559
2590
        # correct
2560
2591
        history = self._lefthand_history(revision_id)
2561
2592
        if len(history) != revno:
2562
2593
            raise AssertionError('%d != %d' % (len(history), revno))
2563
 
        self._set_revision_history(history)
 
2594
        self.set_revision_history(history)
2564
2595
 
2565
2596
    def _gen_revision_history(self):
2566
2597
        history = self._transport.get_bytes('revision-history').split('\n')
2580
2611
        :param other_branch: The other branch that DivergedBranches should
2581
2612
            raise with respect to.
2582
2613
        """
2583
 
        self._set_revision_history(self._lefthand_history(revision_id,
 
2614
        self.set_revision_history(self._lefthand_history(revision_id,
2584
2615
            last_rev, other_branch))
2585
2616
 
2586
2617
    def basis_tree(self):
2596
2627
                pass
2597
2628
        return None
2598
2629
 
 
2630
    def _basic_push(self, target, overwrite, stop_revision):
 
2631
        """Basic implementation of push without bound branches or hooks.
 
2632
 
 
2633
        Must be called with source read locked and target write locked.
 
2634
        """
 
2635
        result = BranchPushResult()
 
2636
        result.source_branch = self
 
2637
        result.target_branch = target
 
2638
        result.old_revno, result.old_revid = target.last_revision_info()
 
2639
        self.update_references(target)
 
2640
        if result.old_revid != self.last_revision():
 
2641
            # We assume that during 'push' this repository is closer than
 
2642
            # the target.
 
2643
            graph = self.repository.get_graph(target.repository)
 
2644
            target.update_revisions(self, stop_revision,
 
2645
                overwrite=overwrite, graph=graph)
 
2646
        if self._push_should_merge_tags():
 
2647
            result.tag_conflicts = self.tags.merge_to(target.tags,
 
2648
                overwrite)
 
2649
        result.new_revno, result.new_revid = target.last_revision_info()
 
2650
        return result
 
2651
 
2599
2652
    def get_stacked_on_url(self):
2600
2653
        raise errors.UnstackableBranchFormat(self._format, self.user_url)
2601
2654
 
2630
2683
        """Return the branch we are bound to.
2631
2684
 
2632
2685
        :return: Either a Branch, or None
 
2686
 
 
2687
        This could memoise the branch, but if thats done
 
2688
        it must be revalidated on each new lock.
 
2689
        So for now we just don't memoise it.
 
2690
        # RBC 20060304 review this decision.
2633
2691
        """
2634
 
        if self._master_branch_cache is None:
2635
 
            self._master_branch_cache = self._get_master_branch(
2636
 
                possible_transports)
2637
 
        return self._master_branch_cache
2638
 
 
2639
 
    def _get_master_branch(self, possible_transports):
2640
2692
        bound_loc = self.get_bound_location()
2641
2693
        if not bound_loc:
2642
2694
            return None
2653
2705
 
2654
2706
        :param location: URL to the target branch
2655
2707
        """
2656
 
        self._master_branch_cache = None
2657
2708
        if location:
2658
2709
            self._transport.put_bytes('bound', location+'\n',
2659
2710
                mode=self.bzrdir._get_file_mode())
2768
2819
 
2769
2820
    @needs_write_lock
2770
2821
    def set_last_revision_info(self, revno, revision_id):
2771
 
        if not revision_id or not isinstance(revision_id, basestring):
2772
 
            raise errors.InvalidRevisionId(revision_id=revision_id, branch=self)
 
2822
        revision_id = _mod_revision.ensure_null(revision_id)
2773
2823
        old_revno, old_revid = self.last_revision_info()
2774
2824
        if self._get_append_revisions_only():
2775
2825
            self._check_history_violation(revision_id)
2912
2962
 
2913
2963
    def set_bound_location(self, location):
2914
2964
        """See Branch.set_push_location."""
2915
 
        self._master_branch_cache = None
2916
2965
        result = None
2917
2966
        config = self.get_config()
2918
2967
        if location is None:
2995
3044
        try:
2996
3045
            index = self._partial_revision_history_cache.index(revision_id)
2997
3046
        except ValueError:
2998
 
            try:
2999
 
                self._extend_partial_history(stop_revision=revision_id)
3000
 
            except errors.RevisionNotPresent, e:
3001
 
                raise errors.GhostRevisionsHaveNoRevno(revision_id, e.revision_id)
 
3047
            self._extend_partial_history(stop_revision=revision_id)
3002
3048
            index = len(self._partial_revision_history_cache) - 1
3003
3049
            if self._partial_revision_history_cache[index] != revision_id:
3004
3050
                raise errors.NoSuchRevision(self, revision_id)
3251
3297
        raise NotImplementedError(self.pull)
3252
3298
 
3253
3299
    @needs_write_lock
 
3300
    def update_revisions(self, stop_revision=None, overwrite=False,
 
3301
                         graph=None):
 
3302
        """Pull in new perfect-fit revisions.
 
3303
 
 
3304
        :param stop_revision: Updated until the given revision
 
3305
        :param overwrite: Always set the branch pointer, rather than checking
 
3306
            to see if it is a proper descendant.
 
3307
        :param graph: A Graph object that can be used to query history
 
3308
            information. This can be None.
 
3309
        :return: None
 
3310
        """
 
3311
        raise NotImplementedError(self.update_revisions)
 
3312
 
 
3313
    @needs_write_lock
3254
3314
    def push(self, overwrite=False, stop_revision=None,
3255
3315
             _override_hook_source_branch=None):
3256
3316
        """Mirror the source branch into the target branch.
3268
3328
        """
3269
3329
        raise NotImplementedError(self.copy_content_into)
3270
3330
 
3271
 
    @needs_write_lock
3272
 
    def fetch(self, stop_revision=None):
3273
 
        """Fetch revisions.
3274
 
 
3275
 
        :param stop_revision: Last revision to fetch
3276
 
        """
3277
 
        raise NotImplementedError(self.fetch)
3278
 
 
3279
3331
 
3280
3332
class GenericInterBranch(InterBranch):
3281
3333
    """InterBranch implementation that uses public Branch functions."""
3287
3339
 
3288
3340
    @classmethod
3289
3341
    def _get_branch_formats_to_test(klass):
3290
 
        return [(format_registry.get_default(), format_registry.get_default())]
 
3342
        return [(BranchFormat._default_format, BranchFormat._default_format)]
3291
3343
 
3292
3344
    @classmethod
3293
3345
    def unwrap_format(klass, format):
3294
3346
        if isinstance(format, remote.RemoteBranchFormat):
3295
3347
            format._ensure_real()
3296
3348
            return format._custom_format
3297
 
        return format
 
3349
        return format                                                                                                  
3298
3350
 
3299
3351
    @needs_write_lock
3300
3352
    def copy_content_into(self, revision_id=None):
3316
3368
            self.source.tags.merge_to(self.target.tags)
3317
3369
 
3318
3370
    @needs_write_lock
3319
 
    def fetch(self, stop_revision=None):
3320
 
        if self.target.base == self.source.base:
3321
 
            return (0, [])
3322
 
        self.source.lock_read()
3323
 
        try:
3324
 
            fetch_spec_factory = fetch.FetchSpecFactory()
3325
 
            fetch_spec_factory.source_branch = self.source
3326
 
            fetch_spec_factory.source_branch_stop_revision_id = stop_revision
3327
 
            fetch_spec_factory.source_repo = self.source.repository
3328
 
            fetch_spec_factory.target_repo = self.target.repository
3329
 
            fetch_spec_factory.target_repo_kind = fetch.TargetRepoKinds.PREEXISTING
3330
 
            fetch_spec = fetch_spec_factory.make_fetch_spec()
3331
 
            return self.target.repository.fetch(self.source.repository,
3332
 
                fetch_spec=fetch_spec)
3333
 
        finally:
3334
 
            self.source.unlock()
3335
 
 
3336
 
    @needs_write_lock
3337
 
    def _update_revisions(self, stop_revision=None, overwrite=False,
3338
 
            graph=None):
 
3371
    def update_revisions(self, stop_revision=None, overwrite=False,
 
3372
        graph=None):
 
3373
        """See InterBranch.update_revisions()."""
3339
3374
        other_revno, other_last_revision = self.source.last_revision_info()
3340
3375
        stop_revno = None # unknown
3341
3376
        if stop_revision is None:
3352
3387
        # case of having something to pull, and so that the check for
3353
3388
        # already merged can operate on the just fetched graph, which will
3354
3389
        # be cached in memory.
3355
 
        self.fetch(stop_revision=stop_revision)
 
3390
        self.target.fetch(self.source, stop_revision)
3356
3391
        # Check to see if one is an ancestor of the other
3357
3392
        if not overwrite:
3358
3393
            if graph is None:
3386
3421
        if local and not bound_location:
3387
3422
            raise errors.LocalRequiresBoundBranch()
3388
3423
        master_branch = None
3389
 
        source_is_master = (self.source.user_url == bound_location)
3390
 
        if not local and bound_location and not source_is_master:
 
3424
        if not local and bound_location and self.source.user_url != bound_location:
3391
3425
            # not pulling from master, so we need to update master.
3392
3426
            master_branch = self.target.get_master_branch(possible_transports)
3393
3427
            master_branch.lock_write()
3399
3433
            return self._pull(overwrite,
3400
3434
                stop_revision, _hook_master=master_branch,
3401
3435
                run_hooks=run_hooks,
3402
 
                _override_hook_target=_override_hook_target,
3403
 
                merge_tags_to_master=not source_is_master)
 
3436
                _override_hook_target=_override_hook_target)
3404
3437
        finally:
3405
3438
            if master_branch:
3406
3439
                master_branch.unlock()
3427
3460
        finally:
3428
3461
            self.source.unlock()
3429
3462
 
3430
 
    def _basic_push(self, overwrite, stop_revision):
3431
 
        """Basic implementation of push without bound branches or hooks.
3432
 
 
3433
 
        Must be called with source read locked and target write locked.
3434
 
        """
3435
 
        result = BranchPushResult()
3436
 
        result.source_branch = self.source
3437
 
        result.target_branch = self.target
3438
 
        result.old_revno, result.old_revid = self.target.last_revision_info()
3439
 
        self.source.update_references(self.target)
3440
 
        if result.old_revid != stop_revision:
3441
 
            # We assume that during 'push' this repository is closer than
3442
 
            # the target.
3443
 
            graph = self.source.repository.get_graph(self.target.repository)
3444
 
            self._update_revisions(stop_revision, overwrite=overwrite,
3445
 
                    graph=graph)
3446
 
        if self.source._push_should_merge_tags():
3447
 
            result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
3448
 
                overwrite)
3449
 
        result.new_revno, result.new_revid = self.target.last_revision_info()
3450
 
        return result
3451
 
 
3452
3463
    def _push_with_bound_branches(self, overwrite, stop_revision,
3453
3464
            _override_hook_source_branch=None):
3454
3465
        """Push from source into target, and into target's master if any.
3469
3480
            master_branch.lock_write()
3470
3481
            try:
3471
3482
                # push into the master from the source branch.
3472
 
                master_inter = InterBranch.get(self.source, master_branch)
3473
 
                master_inter._basic_push(overwrite, stop_revision)
3474
 
                # and push into the target branch from the source. Note that
3475
 
                # we push from the source branch again, because it's considered
3476
 
                # the highest bandwidth repository.
3477
 
                result = self._basic_push(overwrite, stop_revision)
 
3483
                self.source._basic_push(master_branch, overwrite, stop_revision)
 
3484
                # and push into the target branch from the source. Note that we
 
3485
                # push from the source branch again, because it's considered the
 
3486
                # highest bandwidth repository.
 
3487
                result = self.source._basic_push(self.target, overwrite,
 
3488
                    stop_revision)
3478
3489
                result.master_branch = master_branch
3479
3490
                result.local_branch = self.target
3480
3491
                _run_hooks()
3483
3494
                master_branch.unlock()
3484
3495
        else:
3485
3496
            # no master branch
3486
 
            result = self._basic_push(overwrite, stop_revision)
 
3497
            result = self.source._basic_push(self.target, overwrite,
 
3498
                stop_revision)
3487
3499
            # TODO: Why set master_branch and local_branch if there's no
3488
3500
            # binding?  Maybe cleaner to just leave them unset? -- mbp
3489
3501
            # 20070504
3494
3506
 
3495
3507
    def _pull(self, overwrite=False, stop_revision=None,
3496
3508
             possible_transports=None, _hook_master=None, run_hooks=True,
3497
 
             _override_hook_target=None, local=False,
3498
 
             merge_tags_to_master=True):
 
3509
             _override_hook_target=None, local=False):
3499
3510
        """See Branch.pull.
3500
3511
 
3501
3512
        This function is the core worker, used by GenericInterBranch.pull to
3506
3517
        :param run_hooks: Private parameter - if false, this branch
3507
3518
            is being called because it's the master of the primary branch,
3508
3519
            so it should not run its hooks.
3509
 
            is being called because it's the master of the primary branch,
3510
 
            so it should not run its hooks.
3511
3520
        :param _override_hook_target: Private parameter - set the branch to be
3512
3521
            supplied as the target_branch to pull hooks.
3513
3522
        :param local: Only update the local branch, and not the bound branch.
3532
3541
            # -- JRV20090506
3533
3542
            result.old_revno, result.old_revid = \
3534
3543
                self.target.last_revision_info()
3535
 
            self._update_revisions(stop_revision, overwrite=overwrite,
3536
 
                graph=graph)
 
3544
            self.target.update_revisions(self.source, stop_revision,
 
3545
                overwrite=overwrite, graph=graph)
3537
3546
            # TODO: The old revid should be specified when merging tags, 
3538
3547
            # so a tags implementation that versions tags can only 
3539
3548
            # pull in the most recent changes. -- JRV20090506
3540
3549
            result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
3541
 
                overwrite, ignore_master=not merge_tags_to_master)
 
3550
                overwrite)
3542
3551
            result.new_revno, result.new_revid = self.target.last_revision_info()
3543
3552
            if _hook_master:
3544
3553
                result.master_branch = _hook_master