~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

  • Committer: Vincent Ladeuil
  • Date: 2011-09-29 15:50:58 UTC
  • mfrom: (6177 +trunk)
  • mto: This revision was merged to the branch mainline in revision 6178.
  • Revision ID: v.ladeuil+lp@free.fr-20110929155058-zgbecmx1huzktegm
Merge trunk and resolve conflicts

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2012 Canonical Ltd
 
1
# Copyright (C) 2005-2011 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
 
from __future__ import absolute_import
18
 
 
19
 
import bzrlib.bzrdir
20
17
 
21
18
from cStringIO import StringIO
22
19
 
24
21
lazy_import(globals(), """
25
22
import itertools
26
23
from bzrlib import (
27
 
    bzrdir,
28
 
    controldir,
29
 
    cache_utf8,
30
 
    cleanup,
31
 
    config as _mod_config,
32
 
    debug,
33
 
    errors,
34
 
    fetch,
35
 
    graph as _mod_graph,
36
 
    lockdir,
37
 
    lockable_files,
38
 
    remote,
39
 
    repository,
40
 
    revision as _mod_revision,
41
 
    rio,
42
 
    tag as _mod_tag,
43
 
    transport,
44
 
    ui,
45
 
    urlutils,
46
 
    vf_search,
47
 
    )
 
24
        bzrdir,
 
25
        cache_utf8,
 
26
        cleanup,
 
27
        config as _mod_config,
 
28
        debug,
 
29
        errors,
 
30
        fetch,
 
31
        graph as _mod_graph,
 
32
        lockdir,
 
33
        lockable_files,
 
34
        remote,
 
35
        repository,
 
36
        revision as _mod_revision,
 
37
        rio,
 
38
        tag as _mod_tag,
 
39
        transport,
 
40
        ui,
 
41
        urlutils,
 
42
        )
48
43
from bzrlib.i18n import gettext, ngettext
49
44
""")
50
45
 
51
 
# Explicitly import bzrlib.bzrdir so that the BzrProber
52
 
# is guaranteed to be registered.
53
 
import bzrlib.bzrdir
54
 
 
55
46
from bzrlib import (
56
 
    bzrdir,
57
47
    controldir,
58
48
    )
59
49
from bzrlib.decorators import (
94
84
    def user_transport(self):
95
85
        return self.bzrdir.user_transport
96
86
 
97
 
    def __init__(self, possible_transports=None):
 
87
    def __init__(self, *ignored, **ignored_too):
98
88
        self.tags = self._format.make_tags(self)
99
89
        self._revision_history_cache = None
100
90
        self._revision_id_to_revno_cache = None
104
94
        self._last_revision_info_cache = None
105
95
        self._master_branch_cache = None
106
96
        self._merge_sorted_revisions_cache = None
107
 
        self._open_hook(possible_transports)
 
97
        self._open_hook()
108
98
        hooks = Branch.hooks['open']
109
99
        for hook in hooks:
110
100
            hook(self)
111
101
 
112
 
    def _open_hook(self, possible_transports):
 
102
    def _open_hook(self):
113
103
        """Called by init to allow simpler extension of the base class."""
114
104
 
115
 
    def _activate_fallback_location(self, url, possible_transports):
 
105
    def _activate_fallback_location(self, url):
116
106
        """Activate the branch/repository from url as a fallback repository."""
117
107
        for existing_fallback_repo in self.repository._fallback_repositories:
118
108
            if existing_fallback_repo.user_url == url:
119
109
                # This fallback is already configured.  This probably only
120
 
                # happens because ControlDir.sprout is a horrible mess.  To avoid
 
110
                # happens because BzrDir.sprout is a horrible mess.  To avoid
121
111
                # confusing _unstack we don't add this a second time.
122
112
                mutter('duplicate activation of fallback %r on %r', url, self)
123
113
                return
124
 
        repo = self._get_fallback_repository(url, possible_transports)
 
114
        repo = self._get_fallback_repository(url)
125
115
        if repo.has_same_location(self.repository):
126
116
            raise errors.UnstackableLocationError(self.user_url, url)
127
117
        self.repository.add_fallback_repository(repo)
181
171
        For instance, if the branch is at URL/.bzr/branch,
182
172
        Branch.open(URL) -> a Branch instance.
183
173
        """
184
 
        control = controldir.ControlDir.open(base,
185
 
            possible_transports=possible_transports, _unsupported=_unsupported)
186
 
        return control.open_branch(unsupported=_unsupported,
187
 
            possible_transports=possible_transports)
 
174
        control = bzrdir.BzrDir.open(base, _unsupported,
 
175
                                     possible_transports=possible_transports)
 
176
        return control.open_branch(unsupported=_unsupported)
188
177
 
189
178
    @staticmethod
190
 
    def open_from_transport(transport, name=None, _unsupported=False,
191
 
            possible_transports=None):
 
179
    def open_from_transport(transport, name=None, _unsupported=False):
192
180
        """Open the branch rooted at transport"""
193
 
        control = controldir.ControlDir.open_from_transport(transport, _unsupported)
194
 
        return control.open_branch(name=name, unsupported=_unsupported,
195
 
            possible_transports=possible_transports)
 
181
        control = bzrdir.BzrDir.open_from_transport(transport, _unsupported)
 
182
        return control.open_branch(name=name, unsupported=_unsupported)
196
183
 
197
184
    @staticmethod
198
185
    def open_containing(url, possible_transports=None):
206
193
        format, UnknownFormatError or UnsupportedFormatError are raised.
207
194
        If there is one, it is returned, along with the unused portion of url.
208
195
        """
209
 
        control, relpath = controldir.ControlDir.open_containing(url,
 
196
        control, relpath = bzrdir.BzrDir.open_containing(url,
210
197
                                                         possible_transports)
211
 
        branch = control.open_branch(possible_transports=possible_transports)
212
 
        return (branch, relpath)
 
198
        return control.open_branch(), relpath
213
199
 
214
200
    def _push_should_merge_tags(self):
215
201
        """Should _basic_push merge this branch's tags into the target?
251
237
        """
252
238
        raise NotImplementedError(self._get_config)
253
239
 
254
 
    def _get_fallback_repository(self, url, possible_transports):
 
240
    def _get_fallback_repository(self, url):
255
241
        """Get the repository we fallback to at url."""
256
242
        url = urlutils.join(self.base, url)
257
 
        a_branch = Branch.open(url, possible_transports=possible_transports)
 
243
        a_branch = Branch.open(url,
 
244
            possible_transports=[self.bzrdir.root_transport])
258
245
        return a_branch.repository
259
246
 
260
247
    @needs_read_lock
670
657
        """
671
658
        if not self._format.supports_set_append_revisions_only():
672
659
            return False
673
 
        return self.get_config_stack().get('append_revisions_only')
 
660
        return self.get_config(
 
661
            ).get_user_option_as_bool('append_revisions_only')
674
662
 
675
663
    def set_append_revisions_only(self, enabled):
676
664
        if not self._format.supports_set_append_revisions_only():
677
665
            raise errors.UpgradeRequired(self.user_url)
678
 
        self.get_config_stack().set('append_revisions_only', enabled)
 
666
        if enabled:
 
667
            value = 'True'
 
668
        else:
 
669
            value = 'False'
 
670
        self.get_config().set_user_option('append_revisions_only', value,
 
671
            warn_masked=True)
679
672
 
680
673
    def set_reference_info(self, file_id, tree_path, branch_location):
681
674
        """Set the branch location to use for a tree reference."""
710
703
        """
711
704
        raise errors.UpgradeRequired(self.user_url)
712
705
 
713
 
    def get_commit_builder(self, parents, config_stack=None, timestamp=None,
 
706
    def get_commit_builder(self, parents, config=None, timestamp=None,
714
707
                           timezone=None, committer=None, revprops=None,
715
708
                           revision_id=None, lossy=False):
716
709
        """Obtain a CommitBuilder for this branch.
726
719
            represented, when pushing to a foreign VCS 
727
720
        """
728
721
 
729
 
        if config_stack is None:
730
 
            config_stack = self.get_config_stack()
 
722
        if config is None:
 
723
            config = self.get_config()
731
724
 
732
 
        return self.repository.get_commit_builder(self, parents, config_stack,
 
725
        return self.repository.get_commit_builder(self, parents, config,
733
726
            timestamp, timezone, committer, revprops, revision_id,
734
727
            lossy)
735
728
 
856
849
                return
857
850
            self._unstack()
858
851
        else:
859
 
            self._activate_fallback_location(url,
860
 
                possible_transports=[self.bzrdir.root_transport])
 
852
            self._activate_fallback_location(url)
861
853
        # write this out after the repository is stacked to avoid setting a
862
854
        # stacked config that doesn't work.
863
855
        self._set_config_location('stacked_on_location', url)
889
881
            # stream from one of them to the other.  This does mean doing
890
882
            # separate SSH connection setup, but unstacking is not a
891
883
            # common operation so it's tolerable.
892
 
            new_bzrdir = controldir.ControlDir.open(
893
 
                self.bzrdir.root_transport.base)
 
884
            new_bzrdir = bzrdir.BzrDir.open(self.bzrdir.root_transport.base)
894
885
            new_repository = new_bzrdir.find_repository()
895
886
            if new_repository._fallback_repositories:
896
887
                raise AssertionError("didn't expect %r to have "
939
930
                    tags_to_fetch = set(self.tags.get_reverse_tag_dict())
940
931
                except errors.TagsNotSupported:
941
932
                    tags_to_fetch = set()
942
 
                fetch_spec = vf_search.NotInOtherForRevs(self.repository,
 
933
                fetch_spec = _mod_graph.NotInOtherForRevs(self.repository,
943
934
                    old_repository, required_ids=[self.last_revision()],
944
935
                    if_present_ids=tags_to_fetch, find_ghosts=True).execute()
945
936
                self.repository.fetch(old_repository, fetch_spec=fetch_spec)
1013
1004
        """
1014
1005
        raise NotImplementedError(self._gen_revision_history)
1015
1006
 
1016
 
    @deprecated_method(deprecated_in((2, 5, 0)))
1017
1007
    @needs_read_lock
1018
1008
    def revision_history(self):
1019
1009
        """Return sequence of revision ids on this branch.
1021
1011
        This method will cache the revision history for as long as it is safe to
1022
1012
        do so.
1023
1013
        """
1024
 
        return self._revision_history()
1025
 
 
1026
 
    def _revision_history(self):
1027
1014
        if 'evil' in debug.debug_flags:
1028
1015
            mutter_callsite(3, "revision_history scales with history.")
1029
1016
        if self._revision_history_cache is not None:
1099
1086
        """Given a revision id, return its revno"""
1100
1087
        if _mod_revision.is_null(revision_id):
1101
1088
            return 0
1102
 
        history = self._revision_history()
 
1089
        history = self.revision_history()
1103
1090
        try:
1104
1091
            return history.index(revision_id) + 1
1105
1092
        except ValueError:
1170
1157
    def _set_config_location(self, name, url, config=None,
1171
1158
                             make_relative=False):
1172
1159
        if config is None:
1173
 
            config = self.get_config_stack()
 
1160
            config = self.get_config()
1174
1161
        if url is None:
1175
1162
            url = ''
1176
1163
        elif make_relative:
1177
1164
            url = urlutils.relative_url(self.base, url)
1178
 
        config.set(name, url)
 
1165
        config.set_user_option(name, url, warn_masked=True)
1179
1166
 
1180
1167
    def _get_config_location(self, name, config=None):
1181
1168
        if config is None:
1182
 
            config = self.get_config_stack()
1183
 
        location = config.get(name)
 
1169
            config = self.get_config()
 
1170
        location = config.get_user_option(name)
1184
1171
        if location == '':
1185
1172
            location = None
1186
1173
        return location
1187
1174
 
1188
1175
    def get_child_submit_format(self):
1189
1176
        """Return the preferred format of submissions to this branch."""
1190
 
        return self.get_config_stack().get('child_submit_format')
 
1177
        return self.get_config().get_user_option("child_submit_format")
1191
1178
 
1192
1179
    def get_submit_branch(self):
1193
1180
        """Return the submit location of the branch.
1196
1183
        pattern is that the user can override it by specifying a
1197
1184
        location.
1198
1185
        """
1199
 
        return self.get_config_stack().get('submit_branch')
 
1186
        return self.get_config().get_user_option('submit_branch')
1200
1187
 
1201
1188
    def set_submit_branch(self, location):
1202
1189
        """Return the submit location of the branch.
1205
1192
        pattern is that the user can override it by specifying a
1206
1193
        location.
1207
1194
        """
1208
 
        self.get_config_stack().set('submit_branch', location)
 
1195
        self.get_config().set_user_option('submit_branch', location,
 
1196
            warn_masked=True)
1209
1197
 
1210
1198
    def get_public_branch(self):
1211
1199
        """Return the public location of the branch.
1224
1212
        self._set_config_location('public_branch', location)
1225
1213
 
1226
1214
    def get_push_location(self):
1227
 
        """Return None or the location to push this branch to."""
1228
 
        return self.get_config_stack().get('push_location')
 
1215
        """Return the None or the location to push this branch to."""
 
1216
        push_loc = self.get_config().get_user_option('push_location')
 
1217
        return push_loc
1229
1218
 
1230
1219
    def set_push_location(self, location):
1231
1220
        """Set a new push location for this branch."""
1400
1389
        # TODO: We should probably also check that self.revision_history
1401
1390
        # matches the repository for older branch formats.
1402
1391
        # If looking for the code that cross-checks repository parents against
1403
 
        # the Graph.iter_lefthand_ancestry output, that is now a repository
 
1392
        # the iter_reverse_revision_history output, that is now a repository
1404
1393
        # specific check.
1405
1394
        return result
1406
1395
 
1457
1446
        t = transport.get_transport(to_location)
1458
1447
        t.ensure_base()
1459
1448
        format = self._get_checkout_format(lightweight=lightweight)
1460
 
        try:
 
1449
        if lightweight:
1461
1450
            checkout = format.initialize_on_transport(t)
1462
 
        except errors.AlreadyControlDirError:
1463
 
            # It's fine if the control directory already exists,
1464
 
            # as long as there is no existing branch and working tree.
1465
 
            checkout = controldir.ControlDir.open_from_transport(t)
1466
 
            try:
1467
 
                checkout.open_branch()
1468
 
            except errors.NotBranchError:
1469
 
                pass
1470
 
            else:
1471
 
                raise errors.AlreadyControlDirError(t.base)
1472
 
            if checkout.control_transport.base == self.bzrdir.control_transport.base:
1473
 
                # When checking out to the same control directory,
1474
 
                # always create a lightweight checkout
1475
 
                lightweight = True
1476
 
 
1477
 
        if lightweight:
1478
 
            from_branch = checkout.set_branch_reference(target_branch=self)
 
1451
            from_branch = BranchReferenceFormat().initialize(checkout, 
 
1452
                target_branch=self)
1479
1453
        else:
1480
 
            policy = checkout.determine_repository_policy()
1481
 
            repo = policy.acquire_repository()[0]
1482
 
            checkout_branch = checkout.create_branch()
 
1454
            checkout_branch = bzrdir.BzrDir.create_branch_convenience(
 
1455
                to_location, force_new_tree=False, format=format)
 
1456
            checkout = checkout_branch.bzrdir
1483
1457
            checkout_branch.bind(self)
1484
1458
            # pull up to the specified revision_id to set the initial
1485
1459
            # branch tip correctly, and seed it with history.
1486
1460
            checkout_branch.pull(self, stop_revision=revision_id)
1487
 
            from_branch = None
 
1461
            from_branch=None
1488
1462
        tree = checkout.create_workingtree(revision_id,
1489
1463
                                           from_branch=from_branch,
1490
1464
                                           accelerator_tree=accelerator_tree,
1579
1553
            heads that must be fetched if present, but no error is necessary if
1580
1554
            they are not present.
1581
1555
        """
1582
 
        # For bzr native formats must_fetch is just the tip, and
1583
 
        # if_present_fetch are the tags.
 
1556
        # For bzr native formats must_fetch is just the tip, and if_present_fetch
 
1557
        # are the tags.
1584
1558
        must_fetch = set([self.last_revision()])
1585
1559
        if_present_fetch = set()
1586
 
        if self.get_config_stack().get('branch.fetch_tags'):
 
1560
        c = self.get_config()
 
1561
        include_tags = c.get_user_option_as_bool('branch.fetch_tags',
 
1562
                                                 default=False)
 
1563
        if include_tags:
1587
1564
            try:
1588
1565
                if_present_fetch = set(self.tags.get_reverse_tag_dict())
1589
1566
            except errors.TagsNotSupported:
1598
1575
 
1599
1576
    Formats provide three things:
1600
1577
     * An initialization routine,
1601
 
     * a format description
 
1578
     * a format string,
1602
1579
     * an open routine.
1603
1580
 
1604
1581
    Formats are placed in an dict by their format string for reference
1618
1595
        return not (self == other)
1619
1596
 
1620
1597
    @classmethod
 
1598
    def find_format(klass, a_bzrdir, name=None):
 
1599
        """Return the format for the branch object in a_bzrdir."""
 
1600
        try:
 
1601
            transport = a_bzrdir.get_branch_transport(None, name=name)
 
1602
            format_string = transport.get_bytes("format")
 
1603
            return format_registry.get(format_string)
 
1604
        except errors.NoSuchFile:
 
1605
            raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)
 
1606
        except KeyError:
 
1607
            raise errors.UnknownFormatError(format=format_string, kind='branch')
 
1608
 
 
1609
    @classmethod
1621
1610
    @deprecated_method(deprecated_in((2, 4, 0)))
1622
1611
    def get_default_format(klass):
1623
1612
        """Return the current default format."""
1633
1622
        """
1634
1623
        return format_registry._get_all()
1635
1624
 
1636
 
    def get_reference(self, controldir, name=None):
1637
 
        """Get the target reference of the branch in controldir.
 
1625
    def get_reference(self, a_bzrdir, name=None):
 
1626
        """Get the target reference of the branch in a_bzrdir.
1638
1627
 
1639
1628
        format probing must have been completed before calling
1640
1629
        this method - it is assumed that the format of the branch
1641
 
        in controldir is correct.
 
1630
        in a_bzrdir is correct.
1642
1631
 
1643
 
        :param controldir: The controldir to get the branch data from.
 
1632
        :param a_bzrdir: The bzrdir to get the branch data from.
1644
1633
        :param name: Name of the colocated branch to fetch
1645
1634
        :return: None if the branch is not a reference branch.
1646
1635
        """
1647
1636
        return None
1648
1637
 
1649
1638
    @classmethod
1650
 
    def set_reference(self, controldir, name, to_branch):
1651
 
        """Set the target reference of the branch in controldir.
 
1639
    def set_reference(self, a_bzrdir, name, to_branch):
 
1640
        """Set the target reference of the branch in a_bzrdir.
1652
1641
 
1653
1642
        format probing must have been completed before calling
1654
1643
        this method - it is assumed that the format of the branch
1655
 
        in controldir is correct.
 
1644
        in a_bzrdir is correct.
1656
1645
 
1657
 
        :param controldir: The controldir to set the branch reference for.
 
1646
        :param a_bzrdir: The bzrdir to set the branch reference for.
1658
1647
        :param name: Name of colocated branch to set, None for default
1659
1648
        :param to_branch: branch that the checkout is to reference
1660
1649
        """
1661
1650
        raise NotImplementedError(self.set_reference)
1662
1651
 
 
1652
    def get_format_string(self):
 
1653
        """Return the ASCII format string that identifies this format."""
 
1654
        raise NotImplementedError(self.get_format_string)
 
1655
 
1663
1656
    def get_format_description(self):
1664
1657
        """Return the short format description for this format."""
1665
1658
        raise NotImplementedError(self.get_format_description)
1666
1659
 
1667
 
    def _run_post_branch_init_hooks(self, controldir, name, branch):
 
1660
    def _run_post_branch_init_hooks(self, a_bzrdir, name, branch):
1668
1661
        hooks = Branch.hooks['post_branch_init']
1669
1662
        if not hooks:
1670
1663
            return
1671
 
        params = BranchInitHookParams(self, controldir, name, branch)
 
1664
        params = BranchInitHookParams(self, a_bzrdir, name, branch)
1672
1665
        for hook in hooks:
1673
1666
            hook(params)
1674
1667
 
1675
 
    def initialize(self, controldir, name=None, repository=None,
 
1668
    def initialize(self, a_bzrdir, name=None, repository=None,
1676
1669
                   append_revisions_only=None):
1677
 
        """Create a branch of this format in controldir.
1678
 
 
 
1670
        """Create a branch of this format in a_bzrdir.
 
1671
        
1679
1672
        :param name: Name of the colocated branch to create.
1680
1673
        """
1681
1674
        raise NotImplementedError(self.initialize)
1713
1706
        """
1714
1707
        raise NotImplementedError(self.network_name)
1715
1708
 
1716
 
    def open(self, controldir, name=None, _found=False, ignore_fallbacks=False,
1717
 
            found_repository=None, possible_transports=None):
1718
 
        """Return the branch object for controldir.
 
1709
    def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False,
 
1710
            found_repository=None):
 
1711
        """Return the branch object for a_bzrdir
1719
1712
 
1720
 
        :param controldir: A ControlDir that contains a branch.
 
1713
        :param a_bzrdir: A BzrDir that contains a branch.
1721
1714
        :param name: Name of colocated branch to open
1722
1715
        :param _found: a private parameter, do not use it. It is used to
1723
1716
            indicate if format probing has already be done.
1792
1785
        """
1793
1786
        registry._LazyObjectGetter.__init__(self, module_name, member_name)
1794
1787
        self._format_string = format_string
1795
 
 
 
1788
        
1796
1789
    def get_format_string(self):
1797
1790
        """See BranchFormat.get_format_string."""
1798
1791
        return self._format_string
1943
1936
    There are 4 fields that hooks may wish to access:
1944
1937
 
1945
1938
    :ivar format: the branch format
1946
 
    :ivar bzrdir: the ControlDir where the branch will be/has been initialized
 
1939
    :ivar bzrdir: the BzrDir where the branch will be/has been initialized
1947
1940
    :ivar name: name of colocated branch, if any (or None)
1948
1941
    :ivar branch: the branch created
1949
1942
 
1952
1945
    branch, which refer to the original branch.
1953
1946
    """
1954
1947
 
1955
 
    def __init__(self, format, controldir, name, branch):
 
1948
    def __init__(self, format, a_bzrdir, name, branch):
1956
1949
        """Create a group of BranchInitHook parameters.
1957
1950
 
1958
1951
        :param format: the branch format
1959
 
        :param controldir: the ControlDir where the branch will be/has been
 
1952
        :param a_bzrdir: the BzrDir where the branch will be/has been
1960
1953
            initialized
1961
1954
        :param name: name of colocated branch, if any (or None)
1962
1955
        :param branch: the branch created
1966
1959
        in branch, which refer to the original branch.
1967
1960
        """
1968
1961
        self.format = format
1969
 
        self.bzrdir = controldir
 
1962
        self.bzrdir = a_bzrdir
1970
1963
        self.name = name
1971
1964
        self.branch = branch
1972
1965
 
1982
1975
 
1983
1976
    There are 4 fields that hooks may wish to access:
1984
1977
 
1985
 
    :ivar control_dir: ControlDir of the checkout to change
 
1978
    :ivar control_dir: BzrDir of the checkout to change
1986
1979
    :ivar to_branch: branch that the checkout is to reference
1987
1980
    :ivar force: skip the check for local commits in a heavy checkout
1988
1981
    :ivar revision_id: revision ID to switch to (or None)
1991
1984
    def __init__(self, control_dir, to_branch, force, revision_id):
1992
1985
        """Create a group of SwitchHook parameters.
1993
1986
 
1994
 
        :param control_dir: ControlDir of the checkout to change
 
1987
        :param control_dir: BzrDir of the checkout to change
1995
1988
        :param to_branch: branch that the checkout is to reference
1996
1989
        :param force: skip the check for local commits in a heavy checkout
1997
1990
        :param revision_id: revision ID to switch to (or None)
2010
2003
            self.revision_id)
2011
2004
 
2012
2005
 
2013
 
class BranchFormatMetadir(bzrdir.BzrFormat, BranchFormat):
2014
 
    """Base class for branch formats that live in meta directories.
2015
 
    """
2016
 
 
2017
 
    def __init__(self):
2018
 
        BranchFormat.__init__(self)
2019
 
        bzrdir.BzrFormat.__init__(self)
2020
 
 
2021
 
    @classmethod
2022
 
    def find_format(klass, controldir, name=None):
2023
 
        """Return the format for the branch object in controldir."""
2024
 
        try:
2025
 
            transport = controldir.get_branch_transport(None, name=name)
2026
 
        except errors.NoSuchFile:
2027
 
            raise errors.NotBranchError(path=name, bzrdir=controldir)
2028
 
        try:
2029
 
            format_string = transport.get_bytes("format")
2030
 
        except errors.NoSuchFile:
2031
 
            raise errors.NotBranchError(path=transport.base, bzrdir=controldir)
2032
 
        return klass._find_format(format_registry, 'branch', format_string)
 
2006
class BranchFormatMetadir(BranchFormat):
 
2007
    """Common logic for meta-dir based branch formats."""
2033
2008
 
2034
2009
    def _branch_class(self):
2035
2010
        """What class to instantiate on open calls."""
2053
2028
        :param name: Name of colocated branch to create, if any
2054
2029
        :return: a branch in this format
2055
2030
        """
2056
 
        if name is None:
2057
 
            name = a_bzrdir._get_selected_branch()
2058
2031
        mutter('creating branch %r in %s', self, a_bzrdir.user_url)
2059
2032
        branch_transport = a_bzrdir.get_branch_transport(self, name=name)
2060
2033
        control_files = lockable_files.LockableFiles(branch_transport,
2062
2035
        control_files.create_lock()
2063
2036
        control_files.lock_write()
2064
2037
        try:
2065
 
            utf8_files += [('format', self.as_string())]
 
2038
            utf8_files += [('format', self.get_format_string())]
2066
2039
            for (filename, content) in utf8_files:
2067
2040
                branch_transport.put_bytes(
2068
2041
                    filename, content,
2074
2047
        self._run_post_branch_init_hooks(a_bzrdir, name, branch)
2075
2048
        return branch
2076
2049
 
 
2050
    def network_name(self):
 
2051
        """A simple byte string uniquely identifying this format for RPC calls.
 
2052
 
 
2053
        Metadir branch formats use their format string.
 
2054
        """
 
2055
        return self.get_format_string()
 
2056
 
2077
2057
    def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False,
2078
 
            found_repository=None, possible_transports=None):
 
2058
            found_repository=None):
2079
2059
        """See BranchFormat.open()."""
2080
 
        if name is None:
2081
 
            name = a_bzrdir._get_selected_branch()
2082
2060
        if not _found:
2083
 
            format = BranchFormatMetadir.find_format(a_bzrdir, name=name)
 
2061
            format = BranchFormat.find_format(a_bzrdir, name=name)
2084
2062
            if format.__class__ != self.__class__:
2085
2063
                raise AssertionError("wrong format %r found for %r" %
2086
2064
                    (format, self))
2095
2073
                              name=name,
2096
2074
                              a_bzrdir=a_bzrdir,
2097
2075
                              _repository=found_repository,
2098
 
                              ignore_fallbacks=ignore_fallbacks,
2099
 
                              possible_transports=possible_transports)
 
2076
                              ignore_fallbacks=ignore_fallbacks)
2100
2077
        except errors.NoSuchFile:
2101
2078
            raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)
2102
2079
 
2103
 
    @property
2104
 
    def _matchingbzrdir(self):
2105
 
        ret = bzrdir.BzrDirMetaFormat1()
2106
 
        ret.set_branch_format(self)
2107
 
        return ret
 
2080
    def __init__(self):
 
2081
        super(BranchFormatMetadir, self).__init__()
 
2082
        self._matchingbzrdir = bzrdir.BzrDirMetaFormat1()
 
2083
        self._matchingbzrdir.set_branch_format(self)
2108
2084
 
2109
2085
    def supports_tags(self):
2110
2086
        return True
2112
2088
    def supports_leaving_lock(self):
2113
2089
        return True
2114
2090
 
2115
 
    def check_support_status(self, allow_unsupported, recommend_upgrade=True,
2116
 
            basedir=None):
2117
 
        BranchFormat.check_support_status(self,
2118
 
            allow_unsupported=allow_unsupported, recommend_upgrade=recommend_upgrade,
2119
 
            basedir=basedir)
2120
 
        bzrdir.BzrFormat.check_support_status(self, allow_unsupported=allow_unsupported,
2121
 
            recommend_upgrade=recommend_upgrade, basedir=basedir)
2122
 
 
2123
2091
 
2124
2092
class BzrBranchFormat5(BranchFormatMetadir):
2125
2093
    """Bzr branch format 5.
2137
2105
    def _branch_class(self):
2138
2106
        return BzrBranch5
2139
2107
 
2140
 
    @classmethod
2141
 
    def get_format_string(cls):
 
2108
    def get_format_string(self):
2142
2109
        """See BranchFormat.get_format_string()."""
2143
2110
        return "Bazaar-NG branch format 5\n"
2144
2111
 
2174
2141
    def _branch_class(self):
2175
2142
        return BzrBranch6
2176
2143
 
2177
 
    @classmethod
2178
 
    def get_format_string(cls):
 
2144
    def get_format_string(self):
2179
2145
        """See BranchFormat.get_format_string()."""
2180
2146
        return "Bazaar Branch Format 6 (bzr 0.15)\n"
2181
2147
 
2207
2173
    def _branch_class(self):
2208
2174
        return BzrBranch8
2209
2175
 
2210
 
    @classmethod
2211
 
    def get_format_string(cls):
 
2176
    def get_format_string(self):
2212
2177
        """See BranchFormat.get_format_string()."""
2213
2178
        return "Bazaar Branch Format 8 (needs bzr 1.15)\n"
2214
2179
 
2262
2227
    def _branch_class(self):
2263
2228
        return BzrBranch7
2264
2229
 
2265
 
    @classmethod
2266
 
    def get_format_string(cls):
 
2230
    def get_format_string(self):
2267
2231
        """See BranchFormat.get_format_string()."""
2268
2232
        return "Bazaar Branch Format 7 (needs bzr 1.6)\n"
2269
2233
 
2284
2248
    supports_reference_locations = False
2285
2249
 
2286
2250
 
2287
 
class BranchReferenceFormat(BranchFormatMetadir):
 
2251
class BranchReferenceFormat(BranchFormat):
2288
2252
    """Bzr branch reference format.
2289
2253
 
2290
2254
    Branch references are used in implementing checkouts, they
2295
2259
     - a format string
2296
2260
    """
2297
2261
 
2298
 
    @classmethod
2299
 
    def get_format_string(cls):
 
2262
    def get_format_string(self):
2300
2263
        """See BranchFormat.get_format_string()."""
2301
2264
        return "Bazaar-NG Branch Reference Format 1\n"
2302
2265
 
2324
2287
        mutter('creating branch reference in %s', a_bzrdir.user_url)
2325
2288
        if a_bzrdir._format.fixed_components:
2326
2289
            raise errors.IncompatibleFormat(self, a_bzrdir._format)
2327
 
        if name is None:
2328
 
            name = a_bzrdir._get_selected_branch()
2329
2290
        branch_transport = a_bzrdir.get_branch_transport(self, name=name)
2330
2291
        branch_transport.put_bytes('location',
2331
 
            target_branch.user_url)
2332
 
        branch_transport.put_bytes('format', self.as_string())
2333
 
        branch = self.open(a_bzrdir, name, _found=True,
 
2292
            target_branch.bzrdir.user_url)
 
2293
        branch_transport.put_bytes('format', self.get_format_string())
 
2294
        branch = self.open(
 
2295
            a_bzrdir, name, _found=True,
2334
2296
            possible_transports=[target_branch.bzrdir.root_transport])
2335
2297
        self._run_post_branch_init_hooks(a_bzrdir, name, branch)
2336
2298
        return branch
2337
2299
 
 
2300
    def __init__(self):
 
2301
        super(BranchReferenceFormat, self).__init__()
 
2302
        self._matchingbzrdir = bzrdir.BzrDirMetaFormat1()
 
2303
        self._matchingbzrdir.set_branch_format(self)
 
2304
 
2338
2305
    def _make_reference_clone_function(format, a_branch):
2339
2306
        """Create a clone() routine for a branch dynamically."""
2340
2307
        def clone(to_bzrdir, revision_id=None,
2362
2329
            a_bzrdir.
2363
2330
        :param possible_transports: An optional reusable transports list.
2364
2331
        """
2365
 
        if name is None:
2366
 
            name = a_bzrdir._get_selected_branch()
2367
2332
        if not _found:
2368
 
            format = BranchFormatMetadir.find_format(a_bzrdir, name=name)
 
2333
            format = BranchFormat.find_format(a_bzrdir, name=name)
2369
2334
            if format.__class__ != self.__class__:
2370
2335
                raise AssertionError("wrong format %r found for %r" %
2371
2336
                    (format, self))
2372
2337
        if location is None:
2373
2338
            location = self.get_reference(a_bzrdir, name)
2374
 
        real_bzrdir = controldir.ControlDir.open(
 
2339
        real_bzrdir = bzrdir.BzrDir.open(
2375
2340
            location, possible_transports=possible_transports)
2376
 
        result = real_bzrdir.open_branch(ignore_fallbacks=ignore_fallbacks,
2377
 
            possible_transports=possible_transports)
 
2341
        result = real_bzrdir.open_branch(name=name, 
 
2342
            ignore_fallbacks=ignore_fallbacks)
2378
2343
        # this changes the behaviour of result.clone to create a new reference
2379
2344
        # rather than a copy of the content of the branch.
2380
2345
        # I did not use a proxy object because that needs much more extensive
2461
2426
 
2462
2427
    def __init__(self, _format=None,
2463
2428
                 _control_files=None, a_bzrdir=None, name=None,
2464
 
                 _repository=None, ignore_fallbacks=False,
2465
 
                 possible_transports=None):
 
2429
                 _repository=None, ignore_fallbacks=False):
2466
2430
        """Create new branch object at a particular location."""
2467
2431
        if a_bzrdir is None:
2468
2432
            raise ValueError('a_bzrdir must be supplied')
2469
 
        if name is None:
2470
 
            raise ValueError('name must be supplied')
2471
 
        self.bzrdir = a_bzrdir
2472
 
        self._user_transport = self.bzrdir.transport.clone('..')
2473
 
        if name != "":
2474
 
            self._user_transport.set_segment_parameter(
2475
 
                "branch", urlutils.escape(name))
2476
 
        self._base = self._user_transport.base
 
2433
        else:
 
2434
            self.bzrdir = a_bzrdir
 
2435
        self._base = self.bzrdir.transport.clone('..').base
2477
2436
        self.name = name
 
2437
        # XXX: We should be able to just do
 
2438
        #   self.base = self.bzrdir.root_transport.base
 
2439
        # but this does not quite work yet -- mbp 20080522
2478
2440
        self._format = _format
2479
2441
        if _control_files is None:
2480
2442
            raise ValueError('BzrBranch _control_files is None')
2481
2443
        self.control_files = _control_files
2482
2444
        self._transport = _control_files._transport
2483
2445
        self.repository = _repository
2484
 
        self.conf_store = None
2485
 
        Branch.__init__(self, possible_transports)
 
2446
        Branch.__init__(self)
2486
2447
 
2487
2448
    def __str__(self):
2488
 
        return '%s(%s)' % (self.__class__.__name__, self.user_url)
 
2449
        if self.name is None:
 
2450
            return '%s(%s)' % (self.__class__.__name__, self.user_url)
 
2451
        else:
 
2452
            return '%s(%s,%s)' % (self.__class__.__name__, self.user_url,
 
2453
                self.name)
2489
2454
 
2490
2455
    __repr__ = __str__
2491
2456
 
2495
2460
 
2496
2461
    base = property(_get_base, doc="The URL for the root of this branch.")
2497
2462
 
2498
 
    @property
2499
 
    def user_transport(self):
2500
 
        return self._user_transport
2501
 
 
2502
2463
    def _get_config(self):
2503
2464
        return _mod_config.TransportConfig(self._transport, 'branch.conf')
2504
2465
 
2505
 
    def _get_config_store(self):
2506
 
        if self.conf_store is None:
2507
 
            self.conf_store =  _mod_config.BranchStore(self)
2508
 
        return self.conf_store
2509
 
 
2510
2466
    def is_locked(self):
2511
2467
        return self.control_files.is_locked()
2512
2468
 
2560
2516
 
2561
2517
    @only_raises(errors.LockNotHeld, errors.LockBroken)
2562
2518
    def unlock(self):
2563
 
        if self.conf_store is not None:
2564
 
            self.conf_store.save_changes()
2565
2519
        try:
2566
2520
            self.control_files.unlock()
2567
2521
        finally:
2743
2697
        self._transport.put_bytes('last-revision', out_string,
2744
2698
            mode=self.bzrdir._get_file_mode())
2745
2699
 
2746
 
    @needs_write_lock
2747
 
    def update_feature_flags(self, updated_flags):
2748
 
        """Update the feature flags for this branch.
2749
 
 
2750
 
        :param updated_flags: Dictionary mapping feature names to necessities
2751
 
            A necessity can be None to indicate the feature should be removed
2752
 
        """
2753
 
        self._format._update_feature_flags(updated_flags)
2754
 
        self.control_transport.put_bytes('format', self._format.as_string())
2755
 
 
2756
2700
 
2757
2701
class FullHistoryBzrBranch(BzrBranch):
2758
2702
    """Bzr branch which contains the full revision history."""
2771
2715
        self._set_revision_history(history)
2772
2716
 
2773
2717
    def _read_last_revision_info(self):
2774
 
        rh = self._revision_history()
 
2718
        rh = self.revision_history()
2775
2719
        revno = len(rh)
2776
2720
        if revno:
2777
2721
            return (revno, rh[-1])
2831
2775
        if revision_id == _mod_revision.NULL_REVISION:
2832
2776
            new_history = []
2833
2777
        else:
2834
 
            new_history = self._revision_history()
 
2778
            new_history = self.revision_history()
2835
2779
        if revision_id is not None and new_history != []:
2836
2780
            try:
2837
2781
                new_history = new_history[:new_history.index(revision_id) + 1]
2865
2809
class BzrBranch8(BzrBranch):
2866
2810
    """A branch that stores tree-reference locations."""
2867
2811
 
2868
 
    def _open_hook(self, possible_transports=None):
 
2812
    def _open_hook(self):
2869
2813
        if self._ignore_fallbacks:
2870
2814
            return
2871
 
        if possible_transports is None:
2872
 
            possible_transports = [self.bzrdir.root_transport]
2873
2815
        try:
2874
2816
            url = self.get_stacked_on_url()
2875
2817
        except (errors.UnstackableRepositoryFormat, errors.NotStacked,
2883
2825
                    raise AssertionError(
2884
2826
                        "'transform_fallback_location' hook %s returned "
2885
2827
                        "None, not a URL." % hook_name)
2886
 
            self._activate_fallback_location(url,
2887
 
                possible_transports=possible_transports)
 
2828
            self._activate_fallback_location(url)
2888
2829
 
2889
2830
    def __init__(self, *args, **kwargs):
2890
2831
        self._ignore_fallbacks = kwargs.get('ignore_fallbacks', False)
3008
2949
        """See Branch.set_push_location."""
3009
2950
        self._master_branch_cache = None
3010
2951
        result = None
3011
 
        conf = self.get_config_stack()
 
2952
        config = self.get_config()
3012
2953
        if location is None:
3013
 
            if not conf.get('bound'):
 
2954
            if config.get_user_option('bound') != 'True':
3014
2955
                return False
3015
2956
            else:
3016
 
                conf.set('bound', 'False')
 
2957
                config.set_user_option('bound', 'False', warn_masked=True)
3017
2958
                return True
3018
2959
        else:
3019
2960
            self._set_config_location('bound_location', location,
3020
 
                                      config=conf)
3021
 
            conf.set('bound', 'True')
 
2961
                                      config=config)
 
2962
            config.set_user_option('bound', 'True', warn_masked=True)
3022
2963
        return True
3023
2964
 
3024
2965
    def _get_bound_location(self, bound):
3025
2966
        """Return the bound location in the config file.
3026
2967
 
3027
2968
        Return None if the bound parameter does not match"""
3028
 
        conf = self.get_config_stack()
3029
 
        if conf.get('bound') != bound:
 
2969
        config = self.get_config()
 
2970
        config_bound = (config.get_user_option('bound') == 'True')
 
2971
        if config_bound != bound:
3030
2972
            return None
3031
 
        return self._get_config_location('bound_location', config=conf)
 
2973
        return self._get_config_location('bound_location', config=config)
3032
2974
 
3033
2975
    def get_bound_location(self):
3034
 
        """See Branch.get_bound_location."""
 
2976
        """See Branch.set_push_location."""
3035
2977
        return self._get_bound_location(True)
3036
2978
 
3037
2979
    def get_old_bound_location(self):
3044
2986
        ## self._check_stackable_repo()
3045
2987
        # stacked_on_location is only ever defined in branch.conf, so don't
3046
2988
        # waste effort reading the whole stack of config files.
3047
 
        conf = _mod_config.BranchOnlyStack(self)
 
2989
        config = self.get_config()._get_branch_data_config()
3048
2990
        stacked_url = self._get_config_location('stacked_on_location',
3049
 
                                                config=conf)
 
2991
            config=config)
3050
2992
        if stacked_url is None:
3051
2993
            raise errors.NotStacked(self)
3052
 
        return stacked_url.encode('utf-8')
 
2994
        return stacked_url
3053
2995
 
3054
2996
    @needs_read_lock
3055
2997
    def get_rev_id(self, revno, history=None):
3085
3027
            except errors.RevisionNotPresent, e:
3086
3028
                raise errors.GhostRevisionsHaveNoRevno(revision_id, e.revision_id)
3087
3029
            index = len(self._partial_revision_history_cache) - 1
3088
 
            if index < 0:
3089
 
                raise errors.NoSuchRevision(self, revision_id)
3090
3030
            if self._partial_revision_history_cache[index] != revision_id:
3091
3031
                raise errors.NoSuchRevision(self, revision_id)
3092
3032
        return self.revno() - index
3250
3190
 
3251
3191
        # Copy source data into target
3252
3192
        new_branch._write_last_revision_info(*branch.last_revision_info())
3253
 
        new_branch.lock_write()
3254
 
        try:
3255
 
            new_branch.set_parent(branch.get_parent())
3256
 
            new_branch.set_bound_location(branch.get_bound_location())
3257
 
            new_branch.set_push_location(branch.get_push_location())
3258
 
        finally:
3259
 
            new_branch.unlock()
 
3193
        new_branch.set_parent(branch.get_parent())
 
3194
        new_branch.set_bound_location(branch.get_bound_location())
 
3195
        new_branch.set_push_location(branch.get_push_location())
3260
3196
 
3261
3197
        # New branch has no tags by default
3262
3198
        new_branch.tags._set_tag_dict({})
3263
3199
 
3264
3200
        # Copying done; now update target format
3265
3201
        new_branch._transport.put_bytes('format',
3266
 
            format.as_string(),
 
3202
            format.get_format_string(),
3267
3203
            mode=new_branch.bzrdir._get_file_mode())
3268
3204
 
3269
3205
        # Clean up old files
3270
3206
        new_branch._transport.delete('revision-history')
3271
 
        branch.lock_write()
3272
3207
        try:
3273
 
            try:
3274
 
                branch.set_parent(None)
3275
 
            except errors.NoSuchFile:
3276
 
                pass
3277
 
            branch.set_bound_location(None)
3278
 
        finally:
3279
 
            branch.unlock()
 
3208
            branch.set_parent(None)
 
3209
        except errors.NoSuchFile:
 
3210
            pass
 
3211
        branch.set_bound_location(None)
3280
3212
 
3281
3213
 
3282
3214
class Converter6to7(object):
3286
3218
        format = BzrBranchFormat7()
3287
3219
        branch._set_config_location('stacked_on_location', '')
3288
3220
        # update target format
3289
 
        branch._transport.put_bytes('format', format.as_string())
 
3221
        branch._transport.put_bytes('format', format.get_format_string())
3290
3222
 
3291
3223
 
3292
3224
class Converter7to8(object):
3296
3228
        format = BzrBranchFormat8()
3297
3229
        branch._transport.put_bytes('references', '')
3298
3230
        # update target format
3299
 
        branch._transport.put_bytes('format', format.as_string())
 
3231
        branch._transport.put_bytes('format', format.get_format_string())
3300
3232
 
3301
3233
 
3302
3234
class InterBranch(InterObject):