~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

  • Committer: Vincent Ladeuil
  • Date: 2010-07-15 13:05:40 UTC
  • mto: This revision was merged to the branch mainline in revision 5347.
  • Revision ID: v.ladeuil+lp@free.fr-20100715130540-nac9q1yu78870v0e
Delete the after_cleanup_size parameter from the LRUCache constructor.

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
27
27
        config as _mod_config,
28
28
        debug,
29
29
        errors,
30
 
        fetch,
31
 
        graph as _mod_graph,
32
30
        lockdir,
33
31
        lockable_files,
34
32
        remote,
42
40
        urlutils,
43
41
        )
44
42
from bzrlib.config import BranchConfig, TransportConfig
 
43
from bzrlib.repofmt.pack_repo import RepositoryFormatKnitPack5RichRoot
45
44
from bzrlib.tag import (
46
45
    BasicTags,
47
46
    DisabledTags,
48
47
    )
49
48
""")
50
49
 
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
 
50
from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises
 
51
from bzrlib.hooks import HookPoint, Hooks
60
52
from bzrlib.inter import InterObject
61
53
from bzrlib.lock import _RelockDebugMixin, LogicalLockResult
62
54
from bzrlib import registry
72
64
BZR_BRANCH_FORMAT_6 = "Bazaar Branch Format 6 (bzr 0.15)\n"
73
65
 
74
66
 
75
 
class Branch(controldir.ControlComponent):
 
67
class Branch(bzrdir.ControlComponent):
76
68
    """Branch holding a history of revisions.
77
69
 
78
70
    :ivar base:
79
71
        Base directory/url of the branch; using control_url and
80
72
        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.
 
73
 
 
74
    hooks: An instance of BranchHooks.
84
75
    """
85
76
    # this is really an instance variable - FIXME move it there
86
77
    # - RBC 20060112
100
91
        self._revision_id_to_revno_cache = None
101
92
        self._partial_revision_id_to_revno_cache = {}
102
93
        self._partial_revision_history_cache = []
103
 
        self._tags_bytes = None
104
94
        self._last_revision_info_cache = None
105
 
        self._master_branch_cache = None
106
95
        self._merge_sorted_revisions_cache = None
107
96
        self._open_hook()
108
97
        hooks = Branch.hooks['open']
114
103
 
115
104
    def _activate_fallback_location(self, url):
116
105
        """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
106
        repo = self._get_fallback_repository(url)
125
107
        if repo.has_same_location(self.repository):
126
108
            raise errors.UnstackableLocationError(self.user_url, url)
244
226
            possible_transports=[self.bzrdir.root_transport])
245
227
        return a_branch.repository
246
228
 
247
 
    @needs_read_lock
248
229
    def _get_tags_bytes(self):
249
230
        """Get the bytes of a serialised tags dict.
250
231
 
257
238
        :return: The bytes of the tags file.
258
239
        :seealso: Branch._set_tags_bytes.
259
240
        """
260
 
        if self._tags_bytes is None:
261
 
            self._tags_bytes = self._transport.get_bytes('tags')
262
 
        return self._tags_bytes
 
241
        return self._transport.get_bytes('tags')
263
242
 
264
243
    def _get_nick(self, local=False, possible_transports=None):
265
244
        config = self.get_config()
267
246
        if not local and not config.has_explicit_nickname():
268
247
            try:
269
248
                master = self.get_master_branch(possible_transports)
270
 
                if master and self.user_url == master.user_url:
271
 
                    raise errors.RecursiveBind(self.user_url)
272
249
                if master is not None:
273
250
                    # return the master branch value
274
251
                    return master.nick
275
 
            except errors.RecursiveBind, e:
276
 
                raise e
277
252
            except errors.BzrError, e:
278
253
                # Silently fall back to local implicit nick if the master is
279
254
                # unavailable
669
644
        raise errors.UnsupportedOperation(self.get_reference_info, self)
670
645
 
671
646
    @needs_write_lock
672
 
    def fetch(self, from_branch, last_revision=None):
 
647
    def fetch(self, from_branch, last_revision=None, pb=None):
673
648
        """Copy revisions from from_branch into this branch.
674
649
 
675
650
        :param from_branch: Where to copy from.
676
651
        :param last_revision: What revision to stop at (None for at the end
677
652
                              of the branch.
 
653
        :param pb: An optional progress bar to use.
678
654
        :return: None
679
655
        """
680
 
        return InterBranch.get(from_branch, self).fetch(last_revision)
 
656
        if self.base == from_branch.base:
 
657
            return (0, [])
 
658
        if pb is not None:
 
659
            symbol_versioning.warn(
 
660
                symbol_versioning.deprecated_in((1, 14, 0))
 
661
                % "pb parameter to fetch()")
 
662
        from_branch.lock_read()
 
663
        try:
 
664
            if last_revision is None:
 
665
                last_revision = from_branch.last_revision()
 
666
                last_revision = _mod_revision.ensure_null(last_revision)
 
667
            return self.repository.fetch(from_branch.repository,
 
668
                                         revision_id=last_revision,
 
669
                                         pb=pb)
 
670
        finally:
 
671
            from_branch.unlock()
681
672
 
682
673
    def get_bound_location(self):
683
674
        """Return the URL of the branch we are bound to.
694
685
 
695
686
    def get_commit_builder(self, parents, config=None, timestamp=None,
696
687
                           timezone=None, committer=None, revprops=None,
697
 
                           revision_id=None, lossy=False):
 
688
                           revision_id=None):
698
689
        """Obtain a CommitBuilder for this branch.
699
690
 
700
691
        :param parents: Revision ids of the parents of the new revision.
704
695
        :param committer: Optional committer to set for commit.
705
696
        :param revprops: Optional dictionary of revision properties.
706
697
        :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
698
        """
710
699
 
711
700
        if config is None:
712
701
            config = self.get_config()
713
702
 
714
703
        return self.repository.get_commit_builder(self, parents, config,
715
 
            timestamp, timezone, committer, revprops, revision_id,
716
 
            lossy)
 
704
            timestamp, timezone, committer, revprops, revision_id)
717
705
 
718
706
    def get_master_branch(self, possible_transports=None):
719
707
        """Return the branch we are bound to.
797
785
 
798
786
    def _unstack(self):
799
787
        """Change a branch to be unstacked, copying data as needed.
800
 
 
 
788
        
801
789
        Don't call this directly, use set_stacked_on_url(None).
802
790
        """
803
791
        pb = ui.ui_factory.nested_progress_bar()
812
800
            old_repository = self.repository
813
801
            if len(old_repository._fallback_repositories) != 1:
814
802
                raise AssertionError("can't cope with fallback repositories "
815
 
                    "of %r (fallbacks: %r)" % (old_repository,
816
 
                        old_repository._fallback_repositories))
 
803
                    "of %r" % (self.repository,))
817
804
            # Open the new repository object.
818
805
            # Repositories don't offer an interface to remove fallback
819
806
            # repositories today; take the conceptually simpler option and just
867
854
                # XXX: If you unstack a branch while it has a working tree
868
855
                # with a pending merge, the pending-merged revisions will no
869
856
                # 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)
 
857
                #
 
858
                # XXX: This only fetches up to the tip of the repository; it
 
859
                # doesn't bring across any tags.  That's fairly consistent
 
860
                # with how branch works, but perhaps not ideal.
 
861
                self.repository.fetch(old_repository,
 
862
                    revision_id=self.last_revision(),
 
863
                    find_ghosts=True)
878
864
            finally:
879
865
                old_repository.unlock()
880
866
        finally:
885
871
 
886
872
        :seealso: Branch._get_tags_bytes.
887
873
        """
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)
 
874
        return _run_with_write_locked_target(self, self._transport.put_bytes,
 
875
            'tags', bytes)
894
876
 
895
877
    def _cache_revision_history(self, rev_history):
896
878
        """Set the cached revision history to rev_history.
923
905
        self._revision_history_cache = None
924
906
        self._revision_id_to_revno_cache = None
925
907
        self._last_revision_info_cache = None
926
 
        self._master_branch_cache = None
927
908
        self._merge_sorted_revisions_cache = None
928
909
        self._partial_revision_history_cache = []
929
910
        self._partial_revision_id_to_revno_cache = {}
930
 
        self._tags_bytes = None
931
911
 
932
912
    def _gen_revision_history(self):
933
913
        """Return sequence of revision hashes on to this branch.
994
974
        else:
995
975
            return (0, _mod_revision.NULL_REVISION)
996
976
 
997
 
    @deprecated_method(deprecated_in((2, 4, 0)))
 
977
    @deprecated_method(deprecated_in((1, 6, 0)))
 
978
    def missing_revisions(self, other, stop_revision=None):
 
979
        """Return a list of new revisions that would perfectly fit.
 
980
 
 
981
        If self and other have not diverged, return a list of the revisions
 
982
        present in other, but missing from self.
 
983
        """
 
984
        self_history = self.revision_history()
 
985
        self_len = len(self_history)
 
986
        other_history = other.revision_history()
 
987
        other_len = len(other_history)
 
988
        common_index = min(self_len, other_len) -1
 
989
        if common_index >= 0 and \
 
990
            self_history[common_index] != other_history[common_index]:
 
991
            raise errors.DivergedBranches(self, other)
 
992
 
 
993
        if stop_revision is None:
 
994
            stop_revision = other_len
 
995
        else:
 
996
            if stop_revision > other_len:
 
997
                raise errors.NoSuchRevision(self, stop_revision)
 
998
        return other_history[self_len:stop_revision]
 
999
 
 
1000
    def update_revisions(self, other, stop_revision=None, overwrite=False,
 
1001
                         graph=None):
 
1002
        """Pull in new perfect-fit revisions.
 
1003
 
 
1004
        :param other: Another Branch to pull from
 
1005
        :param stop_revision: Updated until the given revision
 
1006
        :param overwrite: Always set the branch pointer, rather than checking
 
1007
            to see if it is a proper descendant.
 
1008
        :param graph: A Graph object that can be used to query history
 
1009
            information. This can be None.
 
1010
        :return: None
 
1011
        """
 
1012
        return InterBranch.get(other, self).update_revisions(stop_revision,
 
1013
            overwrite, graph)
 
1014
 
998
1015
    def import_last_revision_info(self, source_repo, revno, revid):
999
1016
        """Set the last revision info, importing from another repo if necessary.
1000
1017
 
 
1018
        This is used by the bound branch code to upload a revision to
 
1019
        the master branch first before updating the tip of the local branch.
 
1020
 
1001
1021
        :param source_repo: Source repository to optionally fetch from
1002
1022
        :param revno: Revision number of the new tip
1003
1023
        :param revid: Revision id of the new tip
1006
1026
            self.repository.fetch(source_repo, revision_id=revid)
1007
1027
        self.set_last_revision_info(revno, revid)
1008
1028
 
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
1029
    def revision_id_to_revno(self, revision_id):
1031
1030
        """Given a revision id, return its revno"""
1032
1031
        if _mod_revision.is_null(revision_id):
1253
1252
        return result
1254
1253
 
1255
1254
    @needs_read_lock
1256
 
    def sprout(self, to_bzrdir, revision_id=None, repository_policy=None,
1257
 
            repository=None):
 
1255
    def sprout(self, to_bzrdir, revision_id=None, repository_policy=None):
1258
1256
        """Create a new line of development from the branch, into to_bzrdir.
1259
1257
 
1260
1258
        to_bzrdir controls the branch format.
1265
1263
        if (repository_policy is not None and
1266
1264
            repository_policy.requires_stacking()):
1267
1265
            to_bzrdir._format.require_stacking(_skip_repo=True)
1268
 
        result = to_bzrdir.create_branch(repository=repository)
 
1266
        result = to_bzrdir.create_branch()
1269
1267
        result.lock_write()
1270
1268
        try:
1271
1269
            if repository_policy is not None:
1359
1357
        """Return the most suitable metadir for a checkout of this branch.
1360
1358
        Weaves are used if this branch's repository uses weaves.
1361
1359
        """
1362
 
        format = self.repository.bzrdir.checkout_metadir()
1363
 
        format.set_branch_format(self._format)
 
1360
        if isinstance(self.bzrdir, bzrdir.BzrDirPreSplitOut):
 
1361
            from bzrlib.repofmt import weaverepo
 
1362
            format = bzrdir.BzrDirMetaFormat1()
 
1363
            format.repository_format = weaverepo.RepositoryFormat7()
 
1364
        else:
 
1365
            format = self.repository.bzrdir.checkout_metadir()
 
1366
            format.set_branch_format(self._format)
1364
1367
        return format
1365
1368
 
1366
1369
    def create_clone_on_transport(self, to_transport, revision_id=None,
1367
 
        stacked_on=None, create_prefix=False, use_existing_dir=False,
1368
 
        no_tree=None):
 
1370
        stacked_on=None, create_prefix=False, use_existing_dir=False):
1369
1371
        """Create a clone of this branch and its bzrdir.
1370
1372
 
1371
1373
        :param to_transport: The transport to clone onto.
1384
1386
            revision_id = self.last_revision()
1385
1387
        dir_to = self.bzrdir.clone_on_transport(to_transport,
1386
1388
            revision_id=revision_id, stacked_on=stacked_on,
1387
 
            create_prefix=create_prefix, use_existing_dir=use_existing_dir,
1388
 
            no_tree=no_tree)
 
1389
            create_prefix=create_prefix, use_existing_dir=use_existing_dir)
1389
1390
        return dir_to.open_branch()
1390
1391
 
1391
1392
    def create_checkout(self, to_location, revision_id=None,
1506
1507
        else:
1507
1508
            raise AssertionError("invalid heads: %r" % (heads,))
1508
1509
 
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):
 
1510
 
 
1511
class BranchFormat(object):
1531
1512
    """An encapsulation of the initialization and open routines for a format.
1532
1513
 
1533
1514
    Formats provide three things:
1536
1517
     * an open routine.
1537
1518
 
1538
1519
    Formats are placed in an dict by their format string for reference
1539
 
    during branch opening. It's not required that these be instances, they
 
1520
    during branch opening. Its not required that these be instances, they
1540
1521
    can be classes themselves with class methods - it simply depends on
1541
1522
    whether state is needed for a given format or not.
1542
1523
 
1545
1526
    object will be created every time regardless.
1546
1527
    """
1547
1528
 
 
1529
    _default_format = None
 
1530
    """The default format used for new branches."""
 
1531
 
 
1532
    _formats = {}
 
1533
    """The known formats."""
 
1534
 
1548
1535
    can_set_append_revisions_only = True
1549
1536
 
1550
1537
    def __eq__(self, other):
1559
1546
        try:
1560
1547
            transport = a_bzrdir.get_branch_transport(None, name=name)
1561
1548
            format_string = transport.get_bytes("format")
1562
 
            return format_registry.get(format_string)
 
1549
            format = klass._formats[format_string]
 
1550
            if isinstance(format, MetaDirBranchFormatFactory):
 
1551
                return format()
 
1552
            return format
1563
1553
        except errors.NoSuchFile:
1564
1554
            raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)
1565
1555
        except KeyError:
1566
1556
            raise errors.UnknownFormatError(format=format_string, kind='branch')
1567
1557
 
1568
1558
    @classmethod
1569
 
    @deprecated_method(deprecated_in((2, 4, 0)))
1570
1559
    def get_default_format(klass):
1571
1560
        """Return the current default format."""
1572
 
        return format_registry.get_default()
 
1561
        return klass._default_format
1573
1562
 
1574
1563
    @classmethod
1575
 
    @deprecated_method(deprecated_in((2, 4, 0)))
1576
1564
    def get_formats(klass):
1577
1565
        """Get all the known formats.
1578
1566
 
1579
1567
        Warning: This triggers a load of all lazy registered formats: do not
1580
1568
        use except when that is desireed.
1581
1569
        """
1582
 
        return format_registry._get_all()
 
1570
        result = []
 
1571
        for fmt in klass._formats.values():
 
1572
            if isinstance(fmt, MetaDirBranchFormatFactory):
 
1573
                fmt = fmt()
 
1574
            result.append(fmt)
 
1575
        return result
1583
1576
 
1584
1577
    def get_reference(self, a_bzrdir, name=None):
1585
1578
        """Get the target reference of the branch in a_bzrdir.
1624
1617
        for hook in hooks:
1625
1618
            hook(params)
1626
1619
 
1627
 
    def initialize(self, a_bzrdir, name=None, repository=None):
 
1620
    def _initialize_helper(self, a_bzrdir, utf8_files, name=None,
 
1621
                           lock_type='metadir', set_format=True):
 
1622
        """Initialize a branch in a bzrdir, with specified files
 
1623
 
 
1624
        :param a_bzrdir: The bzrdir to initialize the branch in
 
1625
        :param utf8_files: The files to create as a list of
 
1626
            (filename, content) tuples
 
1627
        :param name: Name of colocated branch to create, if any
 
1628
        :param set_format: If True, set the format with
 
1629
            self.get_format_string.  (BzrBranch4 has its format set
 
1630
            elsewhere)
 
1631
        :return: a branch in this format
 
1632
        """
 
1633
        mutter('creating branch %r in %s', self, a_bzrdir.user_url)
 
1634
        branch_transport = a_bzrdir.get_branch_transport(self, name=name)
 
1635
        lock_map = {
 
1636
            'metadir': ('lock', lockdir.LockDir),
 
1637
            'branch4': ('branch-lock', lockable_files.TransportLock),
 
1638
        }
 
1639
        lock_name, lock_class = lock_map[lock_type]
 
1640
        control_files = lockable_files.LockableFiles(branch_transport,
 
1641
            lock_name, lock_class)
 
1642
        control_files.create_lock()
 
1643
        try:
 
1644
            control_files.lock_write()
 
1645
        except errors.LockContention:
 
1646
            if lock_type != 'branch4':
 
1647
                raise
 
1648
            lock_taken = False
 
1649
        else:
 
1650
            lock_taken = True
 
1651
        if set_format:
 
1652
            utf8_files += [('format', self.get_format_string())]
 
1653
        try:
 
1654
            for (filename, content) in utf8_files:
 
1655
                branch_transport.put_bytes(
 
1656
                    filename, content,
 
1657
                    mode=a_bzrdir._get_file_mode())
 
1658
        finally:
 
1659
            if lock_taken:
 
1660
                control_files.unlock()
 
1661
        branch = self.open(a_bzrdir, name, _found=True)
 
1662
        self._run_post_branch_init_hooks(a_bzrdir, name, branch)
 
1663
        return branch
 
1664
 
 
1665
    def initialize(self, a_bzrdir, name=None):
1628
1666
        """Create a branch of this format in a_bzrdir.
1629
1667
        
1630
1668
        :param name: Name of the colocated branch to create.
1664
1702
        """
1665
1703
        raise NotImplementedError(self.network_name)
1666
1704
 
1667
 
    def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False,
1668
 
            found_repository=None):
 
1705
    def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False):
1669
1706
        """Return the branch object for a_bzrdir
1670
1707
 
1671
1708
        :param a_bzrdir: A BzrDir that contains a branch.
1678
1715
        raise NotImplementedError(self.open)
1679
1716
 
1680
1717
    @classmethod
1681
 
    @deprecated_method(deprecated_in((2, 4, 0)))
1682
1718
    def register_format(klass, format):
1683
1719
        """Register a metadir format.
1684
 
 
 
1720
        
1685
1721
        See MetaDirBranchFormatFactory for the ability to register a format
1686
1722
        without loading the code the format needs until it is actually used.
1687
1723
        """
1688
 
        format_registry.register(format)
 
1724
        klass._formats[format.get_format_string()] = format
 
1725
        # Metadir formats have a network name of their format string, and get
 
1726
        # registered as factories.
 
1727
        if isinstance(format, MetaDirBranchFormatFactory):
 
1728
            network_format_registry.register(format.get_format_string(), format)
 
1729
        else:
 
1730
            network_format_registry.register(format.get_format_string(),
 
1731
                format.__class__)
1689
1732
 
1690
1733
    @classmethod
1691
 
    @deprecated_method(deprecated_in((2, 4, 0)))
1692
1734
    def set_default_format(klass, format):
1693
 
        format_registry.set_default(format)
 
1735
        klass._default_format = format
1694
1736
 
1695
1737
    def supports_set_append_revisions_only(self):
1696
1738
        """True if this format supports set_append_revisions_only."""
1700
1742
        """True if this format records a stacked-on branch."""
1701
1743
        return False
1702
1744
 
1703
 
    def supports_leaving_lock(self):
1704
 
        """True if this format supports leaving locks in place."""
1705
 
        return False # by default
1706
 
 
1707
1745
    @classmethod
1708
 
    @deprecated_method(deprecated_in((2, 4, 0)))
1709
1746
    def unregister_format(klass, format):
1710
 
        format_registry.remove(format)
 
1747
        del klass._formats[format.get_format_string()]
1711
1748
 
1712
1749
    def __str__(self):
1713
1750
        return self.get_format_description().rstrip()
1758
1795
        These are all empty initially, because by default nothing should get
1759
1796
        notified.
1760
1797
        """
1761
 
        Hooks.__init__(self, "bzrlib.branch", "Branch.hooks")
1762
 
        self.add_hook('set_rh',
 
1798
        Hooks.__init__(self)
 
1799
        self.create_hook(HookPoint('set_rh',
1763
1800
            "Invoked whenever the revision history has been set via "
1764
1801
            "set_revision_history. The api signature is (branch, "
1765
1802
            "revision_history), and the branch will be write-locked. "
1766
1803
            "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',
 
1804
            "hook to use is Branch.post_change_branch_tip.", (0, 15), None))
 
1805
        self.create_hook(HookPoint('open',
1769
1806
            "Called with the Branch object that has been opened after a "
1770
 
            "branch is opened.", (1, 8))
1771
 
        self.add_hook('post_push',
 
1807
            "branch is opened.", (1, 8), None))
 
1808
        self.create_hook(HookPoint('post_push',
1772
1809
            "Called after a push operation completes. post_push is called "
1773
1810
            "with a bzrlib.branch.BranchPushResult object and only runs in the "
1774
 
            "bzr client.", (0, 15))
1775
 
        self.add_hook('post_pull',
 
1811
            "bzr client.", (0, 15), None))
 
1812
        self.create_hook(HookPoint('post_pull',
1776
1813
            "Called after a pull operation completes. post_pull is called "
1777
1814
            "with a bzrlib.branch.PullResult object and only runs in the "
1778
 
            "bzr client.", (0, 15))
1779
 
        self.add_hook('pre_commit',
1780
 
            "Called after a commit is calculated but before it is "
 
1815
            "bzr client.", (0, 15), None))
 
1816
        self.create_hook(HookPoint('pre_commit',
 
1817
            "Called after a commit is calculated but before it is is "
1781
1818
            "completed. pre_commit is called with (local, master, old_revno, "
1782
1819
            "old_revid, future_revno, future_revid, tree_delta, future_tree"
1783
1820
            "). old_revid is NULL_REVISION for the first commit to a branch, "
1785
1822
            "basis revision. hooks MUST NOT modify this delta. "
1786
1823
            " future_tree is an in-memory tree obtained from "
1787
1824
            "CommitBuilder.revision_tree() and hooks MUST NOT modify this "
1788
 
            "tree.", (0,91))
1789
 
        self.add_hook('post_commit',
 
1825
            "tree.", (0,91), None))
 
1826
        self.create_hook(HookPoint('post_commit',
1790
1827
            "Called in the bzr client after a commit has completed. "
1791
1828
            "post_commit is called with (local, master, old_revno, old_revid, "
1792
1829
            "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',
 
1830
            "commit to a branch.", (0, 15), None))
 
1831
        self.create_hook(HookPoint('post_uncommit',
1795
1832
            "Called in the bzr client after an uncommit completes. "
1796
1833
            "post_uncommit is called with (local, master, old_revno, "
1797
1834
            "old_revid, new_revno, new_revid) where local is the local branch "
1798
1835
            "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',
 
1836
            "receives new_revno of 0, new_revid of None.", (0, 15), None))
 
1837
        self.create_hook(HookPoint('pre_change_branch_tip',
1801
1838
            "Called in bzr client and server before a change to the tip of a "
1802
1839
            "branch is made. pre_change_branch_tip is called with a "
1803
1840
            "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',
 
1841
            "commit, uncommit will all trigger this hook.", (1, 6), None))
 
1842
        self.create_hook(HookPoint('post_change_branch_tip',
1806
1843
            "Called in bzr client and server after a change to the tip of a "
1807
1844
            "branch is made. post_change_branch_tip is called with a "
1808
1845
            "bzrlib.branch.ChangeBranchTipParams. Note that push, pull, "
1809
 
            "commit, uncommit will all trigger this hook.", (1, 4))
1810
 
        self.add_hook('transform_fallback_location',
 
1846
            "commit, uncommit will all trigger this hook.", (1, 4), None))
 
1847
        self.create_hook(HookPoint('transform_fallback_location',
1811
1848
            "Called when a stacked branch is activating its fallback "
1812
1849
            "locations. transform_fallback_location is called with (branch, "
1813
1850
            "url), and should return a new url. Returning the same url "
1818
1855
            "fallback locations have not been activated. When there are "
1819
1856
            "multiple hooks installed for transform_fallback_location, "
1820
1857
            "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',
1823
 
            "Called to determine an automatic tag name for a revision. "
 
1858
            "The order is however undefined.", (1, 9), None))
 
1859
        self.create_hook(HookPoint('automatic_tag_name',
 
1860
            "Called to determine an automatic tag name for a revision."
1824
1861
            "automatic_tag_name is called with (branch, revision_id) and "
1825
1862
            "should return a tag name or None if no tag name could be "
1826
1863
            "determined. The first non-None tag name returned will be used.",
1827
 
            (2, 2))
1828
 
        self.add_hook('post_branch_init',
 
1864
            (2, 2), None))
 
1865
        self.create_hook(HookPoint('post_branch_init',
1829
1866
            "Called after new branch initialization completes. "
1830
1867
            "post_branch_init is called with a "
1831
1868
            "bzrlib.branch.BranchInitHookParams. "
1832
1869
            "Note that init, branch and checkout (both heavyweight and "
1833
 
            "lightweight) will all trigger this hook.", (2, 2))
1834
 
        self.add_hook('post_switch',
 
1870
            "lightweight) will all trigger this hook.", (2, 2), None))
 
1871
        self.create_hook(HookPoint('post_switch',
1835
1872
            "Called after a checkout switches branch. "
1836
1873
            "post_switch is called with a "
1837
 
            "bzrlib.branch.SwitchHookParams.", (2, 2))
 
1874
            "bzrlib.branch.SwitchHookParams.", (2, 2), None))
1838
1875
 
1839
1876
 
1840
1877
 
1917
1954
        return self.__dict__ == other.__dict__
1918
1955
 
1919
1956
    def __repr__(self):
1920
 
        return "<%s of %s>" % (self.__class__.__name__, self.branch)
 
1957
        if self.branch:
 
1958
            return "<%s of %s>" % (self.__class__.__name__, self.branch)
 
1959
        else:
 
1960
            return "<%s of format:%s bzrdir:%s>" % (
 
1961
                self.__class__.__name__, self.branch,
 
1962
                self.format, self.bzrdir)
1921
1963
 
1922
1964
 
1923
1965
class SwitchHookParams(object):
1953
1995
            self.revision_id)
1954
1996
 
1955
1997
 
 
1998
class BzrBranchFormat4(BranchFormat):
 
1999
    """Bzr branch format 4.
 
2000
 
 
2001
    This format has:
 
2002
     - a revision-history file.
 
2003
     - a branch-lock lock file [ to be shared with the bzrdir ]
 
2004
    """
 
2005
 
 
2006
    def get_format_description(self):
 
2007
        """See BranchFormat.get_format_description()."""
 
2008
        return "Branch format 4"
 
2009
 
 
2010
    def initialize(self, a_bzrdir, name=None):
 
2011
        """Create a branch of this format in a_bzrdir."""
 
2012
        utf8_files = [('revision-history', ''),
 
2013
                      ('branch-name', ''),
 
2014
                      ]
 
2015
        return self._initialize_helper(a_bzrdir, utf8_files, name=name,
 
2016
                                       lock_type='branch4', set_format=False)
 
2017
 
 
2018
    def __init__(self):
 
2019
        super(BzrBranchFormat4, self).__init__()
 
2020
        self._matchingbzrdir = bzrdir.BzrDirFormat6()
 
2021
 
 
2022
    def network_name(self):
 
2023
        """The network name for this format is the control dirs disk label."""
 
2024
        return self._matchingbzrdir.get_format_string()
 
2025
 
 
2026
    def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False):
 
2027
        """See BranchFormat.open()."""
 
2028
        if not _found:
 
2029
            # we are being called directly and must probe.
 
2030
            raise NotImplementedError
 
2031
        return BzrBranch(_format=self,
 
2032
                         _control_files=a_bzrdir._control_files,
 
2033
                         a_bzrdir=a_bzrdir,
 
2034
                         name=name,
 
2035
                         _repository=a_bzrdir.open_repository())
 
2036
 
 
2037
    def __str__(self):
 
2038
        return "Bazaar-NG branch format 4"
 
2039
 
 
2040
 
1956
2041
class BranchFormatMetadir(BranchFormat):
1957
2042
    """Common logic for meta-dir based branch formats."""
1958
2043
 
1960
2045
        """What class to instantiate on open calls."""
1961
2046
        raise NotImplementedError(self._branch_class)
1962
2047
 
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
2048
    def network_name(self):
1993
2049
        """A simple byte string uniquely identifying this format for RPC calls.
1994
2050
 
1996
2052
        """
1997
2053
        return self.get_format_string()
1998
2054
 
1999
 
    def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False,
2000
 
            found_repository=None):
 
2055
    def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False):
2001
2056
        """See BranchFormat.open()."""
2002
2057
        if not _found:
2003
2058
            format = BranchFormat.find_format(a_bzrdir, name=name)
2008
2063
        try:
2009
2064
            control_files = lockable_files.LockableFiles(transport, 'lock',
2010
2065
                                                         lockdir.LockDir)
2011
 
            if found_repository is None:
2012
 
                found_repository = a_bzrdir.find_repository()
2013
2066
            return self._branch_class()(_format=self,
2014
2067
                              _control_files=control_files,
2015
2068
                              name=name,
2016
2069
                              a_bzrdir=a_bzrdir,
2017
 
                              _repository=found_repository,
 
2070
                              _repository=a_bzrdir.find_repository(),
2018
2071
                              ignore_fallbacks=ignore_fallbacks)
2019
2072
        except errors.NoSuchFile:
2020
2073
            raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)
2027
2080
    def supports_tags(self):
2028
2081
        return True
2029
2082
 
2030
 
    def supports_leaving_lock(self):
2031
 
        return True
2032
 
 
2033
2083
 
2034
2084
class BzrBranchFormat5(BranchFormatMetadir):
2035
2085
    """Bzr branch format 5.
2055
2105
        """See BranchFormat.get_format_description()."""
2056
2106
        return "Branch format 5"
2057
2107
 
2058
 
    def initialize(self, a_bzrdir, name=None, repository=None):
 
2108
    def initialize(self, a_bzrdir, name=None):
2059
2109
        """Create a branch of this format in a_bzrdir."""
2060
2110
        utf8_files = [('revision-history', ''),
2061
2111
                      ('branch-name', ''),
2062
2112
                      ]
2063
 
        return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
 
2113
        return self._initialize_helper(a_bzrdir, utf8_files, name)
2064
2114
 
2065
2115
    def supports_tags(self):
2066
2116
        return False
2088
2138
        """See BranchFormat.get_format_description()."""
2089
2139
        return "Branch format 6"
2090
2140
 
2091
 
    def initialize(self, a_bzrdir, name=None, repository=None):
 
2141
    def initialize(self, a_bzrdir, name=None):
2092
2142
        """Create a branch of this format in a_bzrdir."""
2093
2143
        utf8_files = [('last-revision', '0 null:\n'),
2094
2144
                      ('branch.conf', ''),
2095
2145
                      ('tags', ''),
2096
2146
                      ]
2097
 
        return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
 
2147
        return self._initialize_helper(a_bzrdir, utf8_files, name)
2098
2148
 
2099
2149
    def make_tags(self, branch):
2100
2150
        """See bzrlib.branch.BranchFormat.make_tags()."""
2118
2168
        """See BranchFormat.get_format_description()."""
2119
2169
        return "Branch format 8"
2120
2170
 
2121
 
    def initialize(self, a_bzrdir, name=None, repository=None):
 
2171
    def initialize(self, a_bzrdir, name=None):
2122
2172
        """Create a branch of this format in a_bzrdir."""
2123
2173
        utf8_files = [('last-revision', '0 null:\n'),
2124
2174
                      ('branch.conf', ''),
2125
2175
                      ('tags', ''),
2126
2176
                      ('references', '')
2127
2177
                      ]
2128
 
        return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
 
2178
        return self._initialize_helper(a_bzrdir, utf8_files, name)
 
2179
 
 
2180
    def __init__(self):
 
2181
        super(BzrBranchFormat8, self).__init__()
 
2182
        self._matchingbzrdir.repository_format = \
 
2183
            RepositoryFormatKnitPack5RichRoot()
2129
2184
 
2130
2185
    def make_tags(self, branch):
2131
2186
        """See bzrlib.branch.BranchFormat.make_tags()."""
2140
2195
    supports_reference_locations = True
2141
2196
 
2142
2197
 
2143
 
class BzrBranchFormat7(BranchFormatMetadir):
 
2198
class BzrBranchFormat7(BzrBranchFormat8):
2144
2199
    """Branch format with last-revision, tags, and a stacked location pointer.
2145
2200
 
2146
2201
    The stacked location pointer is passed down to the repository and requires
2149
2204
    This format was introduced in bzr 1.6.
2150
2205
    """
2151
2206
 
2152
 
    def initialize(self, a_bzrdir, name=None, repository=None):
 
2207
    def initialize(self, a_bzrdir, name=None):
2153
2208
        """Create a branch of this format in a_bzrdir."""
2154
2209
        utf8_files = [('last-revision', '0 null:\n'),
2155
2210
                      ('branch.conf', ''),
2156
2211
                      ('tags', ''),
2157
2212
                      ]
2158
 
        return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
 
2213
        return self._initialize_helper(a_bzrdir, utf8_files, name)
2159
2214
 
2160
2215
    def _branch_class(self):
2161
2216
        return BzrBranch7
2171
2226
    def supports_set_append_revisions_only(self):
2172
2227
        return True
2173
2228
 
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
2229
    supports_reference_locations = False
2182
2230
 
2183
2231
 
2210
2258
        transport = a_bzrdir.get_branch_transport(None, name=name)
2211
2259
        location = transport.put_bytes('location', to_branch.base)
2212
2260
 
2213
 
    def initialize(self, a_bzrdir, name=None, target_branch=None,
2214
 
            repository=None):
 
2261
    def initialize(self, a_bzrdir, name=None, target_branch=None):
2215
2262
        """Create a branch of this format in a_bzrdir."""
2216
2263
        if target_branch is None:
2217
2264
            # this format does not implement branch itself, thus the implicit
2245
2292
        return clone
2246
2293
 
2247
2294
    def open(self, a_bzrdir, name=None, _found=False, location=None,
2248
 
             possible_transports=None, ignore_fallbacks=False,
2249
 
             found_repository=None):
 
2295
             possible_transports=None, ignore_fallbacks=False):
2250
2296
        """Return the branch that the branch reference in a_bzrdir points at.
2251
2297
 
2252
2298
        :param a_bzrdir: A BzrDir that contains a branch.
2283
2329
        return result
2284
2330
 
2285
2331
 
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
2332
network_format_registry = registry.FormatRegistry()
2301
2333
"""Registry of formats indexed by their network name.
2302
2334
 
2305
2337
BranchFormat.network_name() for more detail.
2306
2338
"""
2307
2339
 
2308
 
format_registry = BranchFormatRegistry(network_format_registry)
2309
 
 
2310
2340
 
2311
2341
# formats which have no format string are not discoverable
2312
2342
# and not independently creatable, so are not registered.
2314
2344
__format6 = BzrBranchFormat6()
2315
2345
__format7 = BzrBranchFormat7()
2316
2346
__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)
 
2347
BranchFormat.register_format(__format5)
 
2348
BranchFormat.register_format(BranchReferenceFormat())
 
2349
BranchFormat.register_format(__format6)
 
2350
BranchFormat.register_format(__format7)
 
2351
BranchFormat.register_format(__format8)
 
2352
BranchFormat.set_default_format(__format7)
 
2353
_legacy_formats = [BzrBranchFormat4(),
 
2354
    ]
 
2355
network_format_registry.register(
 
2356
    _legacy_formats[0].network_name(), _legacy_formats[0].__class__)
2323
2357
 
2324
2358
 
2325
2359
class BranchWriteLockResult(LogicalLockResult):
2482
2516
            'revision-history', '\n'.join(history),
2483
2517
            mode=self.bzrdir._get_file_mode())
2484
2518
 
2485
 
    @deprecated_method(deprecated_in((2, 4, 0)))
 
2519
    @needs_write_lock
2486
2520
    def set_revision_history(self, rev_history):
2487
2521
        """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
2522
        if 'evil' in debug.debug_flags:
2493
2523
            mutter_callsite(3, "set_revision_history scales with history.")
2494
2524
        check_not_reserved_id = _mod_revision.check_not_reserved_id
2538
2568
            except ValueError:
2539
2569
                rev = self.repository.get_revision(revision_id)
2540
2570
                new_history = rev.get_history(self.repository)[1:]
2541
 
        destination._set_revision_history(new_history)
 
2571
        destination.set_revision_history(new_history)
2542
2572
 
2543
2573
    @needs_write_lock
2544
2574
    def set_last_revision_info(self, revno, revision_id):
2552
2582
        configured to check constraints on history, in which case this may not
2553
2583
        be permitted.
2554
2584
        """
2555
 
        if not revision_id or not isinstance(revision_id, basestring):
2556
 
            raise errors.InvalidRevisionId(revision_id=revision_id, branch=self)
 
2585
        revision_id = _mod_revision.ensure_null(revision_id)
2557
2586
        # this old format stores the full history, but this api doesn't
2558
2587
        # provide it, so we must generate, and might as well check it's
2559
2588
        # correct
2560
2589
        history = self._lefthand_history(revision_id)
2561
2590
        if len(history) != revno:
2562
2591
            raise AssertionError('%d != %d' % (len(history), revno))
2563
 
        self._set_revision_history(history)
 
2592
        self.set_revision_history(history)
2564
2593
 
2565
2594
    def _gen_revision_history(self):
2566
2595
        history = self._transport.get_bytes('revision-history').split('\n')
2580
2609
        :param other_branch: The other branch that DivergedBranches should
2581
2610
            raise with respect to.
2582
2611
        """
2583
 
        self._set_revision_history(self._lefthand_history(revision_id,
 
2612
        self.set_revision_history(self._lefthand_history(revision_id,
2584
2613
            last_rev, other_branch))
2585
2614
 
2586
2615
    def basis_tree(self):
2596
2625
                pass
2597
2626
        return None
2598
2627
 
 
2628
    def _basic_push(self, target, overwrite, stop_revision):
 
2629
        """Basic implementation of push without bound branches or hooks.
 
2630
 
 
2631
        Must be called with source read locked and target write locked.
 
2632
        """
 
2633
        result = BranchPushResult()
 
2634
        result.source_branch = self
 
2635
        result.target_branch = target
 
2636
        result.old_revno, result.old_revid = target.last_revision_info()
 
2637
        self.update_references(target)
 
2638
        if result.old_revid != self.last_revision():
 
2639
            # We assume that during 'push' this repository is closer than
 
2640
            # the target.
 
2641
            graph = self.repository.get_graph(target.repository)
 
2642
            target.update_revisions(self, stop_revision,
 
2643
                overwrite=overwrite, graph=graph)
 
2644
        if self._push_should_merge_tags():
 
2645
            result.tag_conflicts = self.tags.merge_to(target.tags,
 
2646
                overwrite)
 
2647
        result.new_revno, result.new_revid = target.last_revision_info()
 
2648
        return result
 
2649
 
2599
2650
    def get_stacked_on_url(self):
2600
2651
        raise errors.UnstackableBranchFormat(self._format, self.user_url)
2601
2652
 
2630
2681
        """Return the branch we are bound to.
2631
2682
 
2632
2683
        :return: Either a Branch, or None
 
2684
 
 
2685
        This could memoise the branch, but if thats done
 
2686
        it must be revalidated on each new lock.
 
2687
        So for now we just don't memoise it.
 
2688
        # RBC 20060304 review this decision.
2633
2689
        """
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
2690
        bound_loc = self.get_bound_location()
2641
2691
        if not bound_loc:
2642
2692
            return None
2653
2703
 
2654
2704
        :param location: URL to the target branch
2655
2705
        """
2656
 
        self._master_branch_cache = None
2657
2706
        if location:
2658
2707
            self._transport.put_bytes('bound', location+'\n',
2659
2708
                mode=self.bzrdir._get_file_mode())
2768
2817
 
2769
2818
    @needs_write_lock
2770
2819
    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)
 
2820
        revision_id = _mod_revision.ensure_null(revision_id)
2773
2821
        old_revno, old_revid = self.last_revision_info()
2774
2822
        if self._get_append_revisions_only():
2775
2823
            self._check_history_violation(revision_id)
2912
2960
 
2913
2961
    def set_bound_location(self, location):
2914
2962
        """See Branch.set_push_location."""
2915
 
        self._master_branch_cache = None
2916
2963
        result = None
2917
2964
        config = self.get_config()
2918
2965
        if location is None:
2995
3042
        try:
2996
3043
            index = self._partial_revision_history_cache.index(revision_id)
2997
3044
        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)
 
3045
            self._extend_partial_history(stop_revision=revision_id)
3002
3046
            index = len(self._partial_revision_history_cache) - 1
3003
3047
            if self._partial_revision_history_cache[index] != revision_id:
3004
3048
                raise errors.NoSuchRevision(self, revision_id)
3059
3103
    :ivar tag_conflicts: A list of tag conflicts, see BasicTags.merge_to
3060
3104
    """
3061
3105
 
3062
 
    @deprecated_method(deprecated_in((2, 3, 0)))
3063
3106
    def __int__(self):
3064
 
        """Return the relative change in revno.
3065
 
 
3066
 
        :deprecated: Use `new_revno` and `old_revno` instead.
3067
 
        """
 
3107
        # DEPRECATED: pull used to return the change in revno
3068
3108
        return self.new_revno - self.old_revno
3069
3109
 
3070
3110
    def report(self, to_file):
3095
3135
        target, otherwise it will be None.
3096
3136
    """
3097
3137
 
3098
 
    @deprecated_method(deprecated_in((2, 3, 0)))
3099
3138
    def __int__(self):
3100
 
        """Return the relative change in revno.
3101
 
 
3102
 
        :deprecated: Use `new_revno` and `old_revno` instead.
3103
 
        """
 
3139
        # DEPRECATED: push used to return the change in revno
3104
3140
        return self.new_revno - self.old_revno
3105
3141
 
3106
3142
    def report(self, to_file):
3251
3287
        raise NotImplementedError(self.pull)
3252
3288
 
3253
3289
    @needs_write_lock
 
3290
    def update_revisions(self, stop_revision=None, overwrite=False,
 
3291
                         graph=None):
 
3292
        """Pull in new perfect-fit revisions.
 
3293
 
 
3294
        :param stop_revision: Updated until the given revision
 
3295
        :param overwrite: Always set the branch pointer, rather than checking
 
3296
            to see if it is a proper descendant.
 
3297
        :param graph: A Graph object that can be used to query history
 
3298
            information. This can be None.
 
3299
        :return: None
 
3300
        """
 
3301
        raise NotImplementedError(self.update_revisions)
 
3302
 
 
3303
    @needs_write_lock
3254
3304
    def push(self, overwrite=False, stop_revision=None,
3255
3305
             _override_hook_source_branch=None):
3256
3306
        """Mirror the source branch into the target branch.
3259
3309
        """
3260
3310
        raise NotImplementedError(self.push)
3261
3311
 
3262
 
    @needs_write_lock
3263
 
    def copy_content_into(self, revision_id=None):
3264
 
        """Copy the content of source into target
3265
 
 
3266
 
        revision_id: if not None, the revision history in the new branch will
3267
 
                     be truncated to end with revision_id.
3268
 
        """
3269
 
        raise NotImplementedError(self.copy_content_into)
3270
 
 
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
3312
 
3280
3313
class GenericInterBranch(InterBranch):
3281
3314
    """InterBranch implementation that uses public Branch functions."""
3287
3320
 
3288
3321
    @classmethod
3289
3322
    def _get_branch_formats_to_test(klass):
3290
 
        return [(format_registry.get_default(), format_registry.get_default())]
 
3323
        return [(BranchFormat._default_format, BranchFormat._default_format)]
3291
3324
 
3292
3325
    @classmethod
3293
3326
    def unwrap_format(klass, format):
3294
3327
        if isinstance(format, remote.RemoteBranchFormat):
3295
3328
            format._ensure_real()
3296
3329
            return format._custom_format
3297
 
        return format
 
3330
        return format                                                                                                  
3298
3331
 
3299
3332
    @needs_write_lock
3300
3333
    def copy_content_into(self, revision_id=None):
3316
3349
            self.source.tags.merge_to(self.target.tags)
3317
3350
 
3318
3351
    @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):
 
3352
    def update_revisions(self, stop_revision=None, overwrite=False,
 
3353
        graph=None):
 
3354
        """See InterBranch.update_revisions()."""
3339
3355
        other_revno, other_last_revision = self.source.last_revision_info()
3340
3356
        stop_revno = None # unknown
3341
3357
        if stop_revision is None:
3352
3368
        # case of having something to pull, and so that the check for
3353
3369
        # already merged can operate on the just fetched graph, which will
3354
3370
        # be cached in memory.
3355
 
        self.fetch(stop_revision=stop_revision)
 
3371
        self.target.fetch(self.source, stop_revision)
3356
3372
        # Check to see if one is an ancestor of the other
3357
3373
        if not overwrite:
3358
3374
            if graph is None:
3386
3402
        if local and not bound_location:
3387
3403
            raise errors.LocalRequiresBoundBranch()
3388
3404
        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:
 
3405
        if not local and bound_location and self.source.user_url != bound_location:
3391
3406
            # not pulling from master, so we need to update master.
3392
3407
            master_branch = self.target.get_master_branch(possible_transports)
3393
3408
            master_branch.lock_write()
3399
3414
            return self._pull(overwrite,
3400
3415
                stop_revision, _hook_master=master_branch,
3401
3416
                run_hooks=run_hooks,
3402
 
                _override_hook_target=_override_hook_target,
3403
 
                merge_tags_to_master=not source_is_master)
 
3417
                _override_hook_target=_override_hook_target)
3404
3418
        finally:
3405
3419
            if master_branch:
3406
3420
                master_branch.unlock()
3427
3441
        finally:
3428
3442
            self.source.unlock()
3429
3443
 
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
3444
    def _push_with_bound_branches(self, overwrite, stop_revision,
3453
3445
            _override_hook_source_branch=None):
3454
3446
        """Push from source into target, and into target's master if any.
3469
3461
            master_branch.lock_write()
3470
3462
            try:
3471
3463
                # 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)
 
3464
                self.source._basic_push(master_branch, overwrite, stop_revision)
 
3465
                # and push into the target branch from the source. Note that we
 
3466
                # push from the source branch again, because its considered the
 
3467
                # highest bandwidth repository.
 
3468
                result = self.source._basic_push(self.target, overwrite,
 
3469
                    stop_revision)
3478
3470
                result.master_branch = master_branch
3479
3471
                result.local_branch = self.target
3480
3472
                _run_hooks()
3483
3475
                master_branch.unlock()
3484
3476
        else:
3485
3477
            # no master branch
3486
 
            result = self._basic_push(overwrite, stop_revision)
 
3478
            result = self.source._basic_push(self.target, overwrite,
 
3479
                stop_revision)
3487
3480
            # TODO: Why set master_branch and local_branch if there's no
3488
3481
            # binding?  Maybe cleaner to just leave them unset? -- mbp
3489
3482
            # 20070504
3494
3487
 
3495
3488
    def _pull(self, overwrite=False, stop_revision=None,
3496
3489
             possible_transports=None, _hook_master=None, run_hooks=True,
3497
 
             _override_hook_target=None, local=False,
3498
 
             merge_tags_to_master=True):
 
3490
             _override_hook_target=None, local=False):
3499
3491
        """See Branch.pull.
3500
3492
 
3501
3493
        This function is the core worker, used by GenericInterBranch.pull to
3506
3498
        :param run_hooks: Private parameter - if false, this branch
3507
3499
            is being called because it's the master of the primary branch,
3508
3500
            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
3501
        :param _override_hook_target: Private parameter - set the branch to be
3512
3502
            supplied as the target_branch to pull hooks.
3513
3503
        :param local: Only update the local branch, and not the bound branch.
3532
3522
            # -- JRV20090506
3533
3523
            result.old_revno, result.old_revid = \
3534
3524
                self.target.last_revision_info()
3535
 
            self._update_revisions(stop_revision, overwrite=overwrite,
3536
 
                graph=graph)
 
3525
            self.target.update_revisions(self.source, stop_revision,
 
3526
                overwrite=overwrite, graph=graph)
3537
3527
            # TODO: The old revid should be specified when merging tags, 
3538
3528
            # so a tags implementation that versions tags can only 
3539
3529
            # pull in the most recent changes. -- JRV20090506
3540
3530
            result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
3541
 
                overwrite, ignore_master=not merge_tags_to_master)
 
3531
                overwrite)
3542
3532
            result.new_revno, result.new_revid = self.target.last_revision_info()
3543
3533
            if _hook_master:
3544
3534
                result.master_branch = _hook_master