~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

  • Committer: Martin Packman
  • Date: 2011-11-23 18:59:43 UTC
  • mto: This revision was merged to the branch mainline in revision 6304.
  • Revision ID: martin.packman@canonical.com-20111123185943-1s2ltxqt5ugohh0w
Add full stops to various registry help strings

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
17
import bzrlib.bzrdir
20
18
 
21
19
from cStringIO import StringIO
43
41
    transport,
44
42
    ui,
45
43
    urlutils,
46
 
    vf_search,
47
44
    )
48
45
from bzrlib.i18n import gettext, ngettext
49
46
""")
50
47
 
51
 
# Explicitly import bzrlib.bzrdir so that the BzrProber
52
 
# is guaranteed to be registered.
53
 
import bzrlib.bzrdir
54
 
 
55
48
from bzrlib import (
56
 
    bzrdir,
57
49
    controldir,
58
50
    )
59
51
from bzrlib.decorators import (
94
86
    def user_transport(self):
95
87
        return self.bzrdir.user_transport
96
88
 
97
 
    def __init__(self, possible_transports=None):
 
89
    def __init__(self, *ignored, **ignored_too):
98
90
        self.tags = self._format.make_tags(self)
99
91
        self._revision_history_cache = None
100
92
        self._revision_id_to_revno_cache = None
104
96
        self._last_revision_info_cache = None
105
97
        self._master_branch_cache = None
106
98
        self._merge_sorted_revisions_cache = None
107
 
        self._open_hook(possible_transports)
 
99
        self._open_hook()
108
100
        hooks = Branch.hooks['open']
109
101
        for hook in hooks:
110
102
            hook(self)
111
103
 
112
 
    def _open_hook(self, possible_transports):
 
104
    def _open_hook(self):
113
105
        """Called by init to allow simpler extension of the base class."""
114
106
 
115
 
    def _activate_fallback_location(self, url, possible_transports):
 
107
    def _activate_fallback_location(self, url):
116
108
        """Activate the branch/repository from url as a fallback repository."""
117
109
        for existing_fallback_repo in self.repository._fallback_repositories:
118
110
            if existing_fallback_repo.user_url == url:
121
113
                # confusing _unstack we don't add this a second time.
122
114
                mutter('duplicate activation of fallback %r on %r', url, self)
123
115
                return
124
 
        repo = self._get_fallback_repository(url, possible_transports)
 
116
        repo = self._get_fallback_repository(url)
125
117
        if repo.has_same_location(self.repository):
126
118
            raise errors.UnstackableLocationError(self.user_url, url)
127
119
        self.repository.add_fallback_repository(repo)
181
173
        For instance, if the branch is at URL/.bzr/branch,
182
174
        Branch.open(URL) -> a Branch instance.
183
175
        """
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)
 
176
        control = controldir.ControlDir.open(base, _unsupported,
 
177
                                     possible_transports=possible_transports)
 
178
        return control.open_branch(unsupported=_unsupported)
188
179
 
189
180
    @staticmethod
190
 
    def open_from_transport(transport, name=None, _unsupported=False,
191
 
            possible_transports=None):
 
181
    def open_from_transport(transport, name=None, _unsupported=False):
192
182
        """Open the branch rooted at transport"""
193
183
        control = controldir.ControlDir.open_from_transport(transport, _unsupported)
194
 
        return control.open_branch(name=name, unsupported=_unsupported,
195
 
            possible_transports=possible_transports)
 
184
        return control.open_branch(name=name, unsupported=_unsupported)
196
185
 
197
186
    @staticmethod
198
187
    def open_containing(url, possible_transports=None):
208
197
        """
209
198
        control, relpath = controldir.ControlDir.open_containing(url,
210
199
                                                         possible_transports)
211
 
        branch = control.open_branch(possible_transports=possible_transports)
212
 
        return (branch, relpath)
 
200
        return control.open_branch(), relpath
213
201
 
214
202
    def _push_should_merge_tags(self):
215
203
        """Should _basic_push merge this branch's tags into the target?
251
239
        """
252
240
        raise NotImplementedError(self._get_config)
253
241
 
254
 
    def _get_fallback_repository(self, url, possible_transports):
 
242
    def _get_fallback_repository(self, url):
255
243
        """Get the repository we fallback to at url."""
256
244
        url = urlutils.join(self.base, url)
257
 
        a_branch = Branch.open(url, possible_transports=possible_transports)
 
245
        a_branch = Branch.open(url,
 
246
            possible_transports=[self.bzrdir.root_transport])
258
247
        return a_branch.repository
259
248
 
260
249
    @needs_read_lock
670
659
        """
671
660
        if not self._format.supports_set_append_revisions_only():
672
661
            return False
673
 
        return self.get_config_stack().get('append_revisions_only')
 
662
        return self.get_config(
 
663
            ).get_user_option_as_bool('append_revisions_only')
674
664
 
675
665
    def set_append_revisions_only(self, enabled):
676
666
        if not self._format.supports_set_append_revisions_only():
677
667
            raise errors.UpgradeRequired(self.user_url)
678
 
        self.get_config_stack().set('append_revisions_only', enabled)
 
668
        if enabled:
 
669
            value = 'True'
 
670
        else:
 
671
            value = 'False'
 
672
        self.get_config().set_user_option('append_revisions_only', value,
 
673
            warn_masked=True)
679
674
 
680
675
    def set_reference_info(self, file_id, tree_path, branch_location):
681
676
        """Set the branch location to use for a tree reference."""
710
705
        """
711
706
        raise errors.UpgradeRequired(self.user_url)
712
707
 
713
 
    def get_commit_builder(self, parents, config_stack=None, timestamp=None,
 
708
    def get_commit_builder(self, parents, config=None, timestamp=None,
714
709
                           timezone=None, committer=None, revprops=None,
715
710
                           revision_id=None, lossy=False):
716
711
        """Obtain a CommitBuilder for this branch.
726
721
            represented, when pushing to a foreign VCS 
727
722
        """
728
723
 
729
 
        if config_stack is None:
730
 
            config_stack = self.get_config_stack()
 
724
        if config is None:
 
725
            config = self.get_config()
731
726
 
732
 
        return self.repository.get_commit_builder(self, parents, config_stack,
 
727
        return self.repository.get_commit_builder(self, parents, config,
733
728
            timestamp, timezone, committer, revprops, revision_id,
734
729
            lossy)
735
730
 
856
851
                return
857
852
            self._unstack()
858
853
        else:
859
 
            self._activate_fallback_location(url,
860
 
                possible_transports=[self.bzrdir.root_transport])
 
854
            self._activate_fallback_location(url)
861
855
        # write this out after the repository is stacked to avoid setting a
862
856
        # stacked config that doesn't work.
863
857
        self._set_config_location('stacked_on_location', url)
939
933
                    tags_to_fetch = set(self.tags.get_reverse_tag_dict())
940
934
                except errors.TagsNotSupported:
941
935
                    tags_to_fetch = set()
942
 
                fetch_spec = vf_search.NotInOtherForRevs(self.repository,
 
936
                fetch_spec = _mod_graph.NotInOtherForRevs(self.repository,
943
937
                    old_repository, required_ids=[self.last_revision()],
944
938
                    if_present_ids=tags_to_fetch, find_ghosts=True).execute()
945
939
                self.repository.fetch(old_repository, fetch_spec=fetch_spec)
1170
1164
    def _set_config_location(self, name, url, config=None,
1171
1165
                             make_relative=False):
1172
1166
        if config is None:
1173
 
            config = self.get_config_stack()
 
1167
            config = self.get_config()
1174
1168
        if url is None:
1175
1169
            url = ''
1176
1170
        elif make_relative:
1177
1171
            url = urlutils.relative_url(self.base, url)
1178
 
        config.set(name, url)
 
1172
        config.set_user_option(name, url, warn_masked=True)
1179
1173
 
1180
1174
    def _get_config_location(self, name, config=None):
1181
1175
        if config is None:
1182
 
            config = self.get_config_stack()
1183
 
        location = config.get(name)
 
1176
            config = self.get_config()
 
1177
        location = config.get_user_option(name)
1184
1178
        if location == '':
1185
1179
            location = None
1186
1180
        return location
1187
1181
 
1188
1182
    def get_child_submit_format(self):
1189
1183
        """Return the preferred format of submissions to this branch."""
1190
 
        return self.get_config_stack().get('child_submit_format')
 
1184
        return self.get_config().get_user_option("child_submit_format")
1191
1185
 
1192
1186
    def get_submit_branch(self):
1193
1187
        """Return the submit location of the branch.
1196
1190
        pattern is that the user can override it by specifying a
1197
1191
        location.
1198
1192
        """
1199
 
        return self.get_config_stack().get('submit_branch')
 
1193
        return self.get_config().get_user_option('submit_branch')
1200
1194
 
1201
1195
    def set_submit_branch(self, location):
1202
1196
        """Return the submit location of the branch.
1205
1199
        pattern is that the user can override it by specifying a
1206
1200
        location.
1207
1201
        """
1208
 
        self.get_config_stack().set('submit_branch', location)
 
1202
        self.get_config().set_user_option('submit_branch', location,
 
1203
            warn_masked=True)
1209
1204
 
1210
1205
    def get_public_branch(self):
1211
1206
        """Return the public location of the branch.
1224
1219
        self._set_config_location('public_branch', location)
1225
1220
 
1226
1221
    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')
 
1222
        """Return the None or the location to push this branch to."""
 
1223
        push_loc = self.get_config().get_user_option('push_location')
 
1224
        return push_loc
1229
1225
 
1230
1226
    def set_push_location(self, location):
1231
1227
        """Set a new push location for this branch."""
1457
1453
        t = transport.get_transport(to_location)
1458
1454
        t.ensure_base()
1459
1455
        format = self._get_checkout_format(lightweight=lightweight)
1460
 
        try:
 
1456
        if lightweight:
1461
1457
            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)
 
1458
            from_branch = BranchReferenceFormat().initialize(checkout, 
 
1459
                target_branch=self)
1479
1460
        else:
1480
 
            policy = checkout.determine_repository_policy()
1481
 
            repo = policy.acquire_repository()[0]
1482
 
            checkout_branch = checkout.create_branch()
 
1461
            checkout_branch = controldir.ControlDir.create_branch_convenience(
 
1462
                to_location, force_new_tree=False, format=format)
 
1463
            checkout = checkout_branch.bzrdir
1483
1464
            checkout_branch.bind(self)
1484
1465
            # pull up to the specified revision_id to set the initial
1485
1466
            # branch tip correctly, and seed it with history.
1486
1467
            checkout_branch.pull(self, stop_revision=revision_id)
1487
 
            from_branch = None
 
1468
            from_branch=None
1488
1469
        tree = checkout.create_workingtree(revision_id,
1489
1470
                                           from_branch=from_branch,
1490
1471
                                           accelerator_tree=accelerator_tree,
1579
1560
            heads that must be fetched if present, but no error is necessary if
1580
1561
            they are not present.
1581
1562
        """
1582
 
        # For bzr native formats must_fetch is just the tip, and
1583
 
        # if_present_fetch are the tags.
 
1563
        # For bzr native formats must_fetch is just the tip, and if_present_fetch
 
1564
        # are the tags.
1584
1565
        must_fetch = set([self.last_revision()])
1585
1566
        if_present_fetch = set()
1586
 
        if self.get_config_stack().get('branch.fetch_tags'):
 
1567
        c = self.get_config()
 
1568
        include_tags = c.get_user_option_as_bool('branch.fetch_tags',
 
1569
                                                 default=False)
 
1570
        if include_tags:
1587
1571
            try:
1588
1572
                if_present_fetch = set(self.tags.get_reverse_tag_dict())
1589
1573
            except errors.TagsNotSupported:
1598
1582
 
1599
1583
    Formats provide three things:
1600
1584
     * An initialization routine,
1601
 
     * a format description
 
1585
     * a format string,
1602
1586
     * an open routine.
1603
1587
 
1604
1588
    Formats are placed in an dict by their format string for reference
1618
1602
        return not (self == other)
1619
1603
 
1620
1604
    @classmethod
 
1605
    def find_format(klass, controldir, name=None):
 
1606
        """Return the format for the branch object in controldir."""
 
1607
        try:
 
1608
            transport = controldir.get_branch_transport(None, name=name)
 
1609
            format_string = transport.get_bytes("format")
 
1610
            return format_registry.get(format_string)
 
1611
        except errors.NoSuchFile:
 
1612
            raise errors.NotBranchError(path=transport.base, bzrdir=controldir)
 
1613
        except KeyError:
 
1614
            raise errors.UnknownFormatError(format=format_string, kind='branch')
 
1615
 
 
1616
    @classmethod
1621
1617
    @deprecated_method(deprecated_in((2, 4, 0)))
1622
1618
    def get_default_format(klass):
1623
1619
        """Return the current default format."""
1660
1656
        """
1661
1657
        raise NotImplementedError(self.set_reference)
1662
1658
 
 
1659
    def get_format_string(self):
 
1660
        """Return the ASCII format string that identifies this format."""
 
1661
        raise NotImplementedError(self.get_format_string)
 
1662
 
1663
1663
    def get_format_description(self):
1664
1664
        """Return the short format description for this format."""
1665
1665
        raise NotImplementedError(self.get_format_description)
1714
1714
        raise NotImplementedError(self.network_name)
1715
1715
 
1716
1716
    def open(self, controldir, name=None, _found=False, ignore_fallbacks=False,
1717
 
            found_repository=None, possible_transports=None):
 
1717
            found_repository=None):
1718
1718
        """Return the branch object for controldir.
1719
1719
 
1720
1720
        :param controldir: A ControlDir that contains a branch.
1792
1792
        """
1793
1793
        registry._LazyObjectGetter.__init__(self, module_name, member_name)
1794
1794
        self._format_string = format_string
1795
 
 
 
1795
        
1796
1796
    def get_format_string(self):
1797
1797
        """See BranchFormat.get_format_string."""
1798
1798
        return self._format_string
2010
2010
            self.revision_id)
2011
2011
 
2012
2012
 
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)
 
2013
class BranchFormatMetadir(BranchFormat):
 
2014
    """Common logic for meta-dir based branch formats."""
2033
2015
 
2034
2016
    def _branch_class(self):
2035
2017
        """What class to instantiate on open calls."""
2053
2035
        :param name: Name of colocated branch to create, if any
2054
2036
        :return: a branch in this format
2055
2037
        """
2056
 
        if name is None:
2057
 
            name = a_bzrdir._get_selected_branch()
2058
2038
        mutter('creating branch %r in %s', self, a_bzrdir.user_url)
2059
2039
        branch_transport = a_bzrdir.get_branch_transport(self, name=name)
2060
2040
        control_files = lockable_files.LockableFiles(branch_transport,
2062
2042
        control_files.create_lock()
2063
2043
        control_files.lock_write()
2064
2044
        try:
2065
 
            utf8_files += [('format', self.as_string())]
 
2045
            utf8_files += [('format', self.get_format_string())]
2066
2046
            for (filename, content) in utf8_files:
2067
2047
                branch_transport.put_bytes(
2068
2048
                    filename, content,
2074
2054
        self._run_post_branch_init_hooks(a_bzrdir, name, branch)
2075
2055
        return branch
2076
2056
 
 
2057
    def network_name(self):
 
2058
        """A simple byte string uniquely identifying this format for RPC calls.
 
2059
 
 
2060
        Metadir branch formats use their format string.
 
2061
        """
 
2062
        return self.get_format_string()
 
2063
 
2077
2064
    def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False,
2078
 
            found_repository=None, possible_transports=None):
 
2065
            found_repository=None):
2079
2066
        """See BranchFormat.open()."""
2080
 
        if name is None:
2081
 
            name = a_bzrdir._get_selected_branch()
2082
2067
        if not _found:
2083
 
            format = BranchFormatMetadir.find_format(a_bzrdir, name=name)
 
2068
            format = BranchFormat.find_format(a_bzrdir, name=name)
2084
2069
            if format.__class__ != self.__class__:
2085
2070
                raise AssertionError("wrong format %r found for %r" %
2086
2071
                    (format, self))
2095
2080
                              name=name,
2096
2081
                              a_bzrdir=a_bzrdir,
2097
2082
                              _repository=found_repository,
2098
 
                              ignore_fallbacks=ignore_fallbacks,
2099
 
                              possible_transports=possible_transports)
 
2083
                              ignore_fallbacks=ignore_fallbacks)
2100
2084
        except errors.NoSuchFile:
2101
2085
            raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)
2102
2086
 
2112
2096
    def supports_leaving_lock(self):
2113
2097
        return True
2114
2098
 
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
2099
 
2124
2100
class BzrBranchFormat5(BranchFormatMetadir):
2125
2101
    """Bzr branch format 5.
2137
2113
    def _branch_class(self):
2138
2114
        return BzrBranch5
2139
2115
 
2140
 
    @classmethod
2141
 
    def get_format_string(cls):
 
2116
    def get_format_string(self):
2142
2117
        """See BranchFormat.get_format_string()."""
2143
2118
        return "Bazaar-NG branch format 5\n"
2144
2119
 
2174
2149
    def _branch_class(self):
2175
2150
        return BzrBranch6
2176
2151
 
2177
 
    @classmethod
2178
 
    def get_format_string(cls):
 
2152
    def get_format_string(self):
2179
2153
        """See BranchFormat.get_format_string()."""
2180
2154
        return "Bazaar Branch Format 6 (bzr 0.15)\n"
2181
2155
 
2207
2181
    def _branch_class(self):
2208
2182
        return BzrBranch8
2209
2183
 
2210
 
    @classmethod
2211
 
    def get_format_string(cls):
 
2184
    def get_format_string(self):
2212
2185
        """See BranchFormat.get_format_string()."""
2213
2186
        return "Bazaar Branch Format 8 (needs bzr 1.15)\n"
2214
2187
 
2262
2235
    def _branch_class(self):
2263
2236
        return BzrBranch7
2264
2237
 
2265
 
    @classmethod
2266
 
    def get_format_string(cls):
 
2238
    def get_format_string(self):
2267
2239
        """See BranchFormat.get_format_string()."""
2268
2240
        return "Bazaar Branch Format 7 (needs bzr 1.6)\n"
2269
2241
 
2295
2267
     - a format string
2296
2268
    """
2297
2269
 
2298
 
    @classmethod
2299
 
    def get_format_string(cls):
 
2270
    def get_format_string(self):
2300
2271
        """See BranchFormat.get_format_string()."""
2301
2272
        return "Bazaar-NG Branch Reference Format 1\n"
2302
2273
 
2324
2295
        mutter('creating branch reference in %s', a_bzrdir.user_url)
2325
2296
        if a_bzrdir._format.fixed_components:
2326
2297
            raise errors.IncompatibleFormat(self, a_bzrdir._format)
2327
 
        if name is None:
2328
 
            name = a_bzrdir._get_selected_branch()
2329
2298
        branch_transport = a_bzrdir.get_branch_transport(self, name=name)
2330
2299
        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,
 
2300
            target_branch.bzrdir.user_url)
 
2301
        branch_transport.put_bytes('format', self.get_format_string())
 
2302
        branch = self.open(
 
2303
            a_bzrdir, name, _found=True,
2334
2304
            possible_transports=[target_branch.bzrdir.root_transport])
2335
2305
        self._run_post_branch_init_hooks(a_bzrdir, name, branch)
2336
2306
        return branch
2362
2332
            a_bzrdir.
2363
2333
        :param possible_transports: An optional reusable transports list.
2364
2334
        """
2365
 
        if name is None:
2366
 
            name = a_bzrdir._get_selected_branch()
2367
2335
        if not _found:
2368
 
            format = BranchFormatMetadir.find_format(a_bzrdir, name=name)
 
2336
            format = BranchFormat.find_format(a_bzrdir, name=name)
2369
2337
            if format.__class__ != self.__class__:
2370
2338
                raise AssertionError("wrong format %r found for %r" %
2371
2339
                    (format, self))
2373
2341
            location = self.get_reference(a_bzrdir, name)
2374
2342
        real_bzrdir = controldir.ControlDir.open(
2375
2343
            location, possible_transports=possible_transports)
2376
 
        result = real_bzrdir.open_branch(ignore_fallbacks=ignore_fallbacks,
2377
 
            possible_transports=possible_transports)
 
2344
        result = real_bzrdir.open_branch(name=name, 
 
2345
            ignore_fallbacks=ignore_fallbacks)
2378
2346
        # this changes the behaviour of result.clone to create a new reference
2379
2347
        # rather than a copy of the content of the branch.
2380
2348
        # I did not use a proxy object because that needs much more extensive
2461
2429
 
2462
2430
    def __init__(self, _format=None,
2463
2431
                 _control_files=None, a_bzrdir=None, name=None,
2464
 
                 _repository=None, ignore_fallbacks=False,
2465
 
                 possible_transports=None):
 
2432
                 _repository=None, ignore_fallbacks=False):
2466
2433
        """Create new branch object at a particular location."""
2467
2434
        if a_bzrdir is None:
2468
2435
            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
 
2436
        else:
 
2437
            self.bzrdir = a_bzrdir
 
2438
        self._base = self.bzrdir.transport.clone('..').base
2477
2439
        self.name = name
 
2440
        # XXX: We should be able to just do
 
2441
        #   self.base = self.bzrdir.root_transport.base
 
2442
        # but this does not quite work yet -- mbp 20080522
2478
2443
        self._format = _format
2479
2444
        if _control_files is None:
2480
2445
            raise ValueError('BzrBranch _control_files is None')
2481
2446
        self.control_files = _control_files
2482
2447
        self._transport = _control_files._transport
2483
2448
        self.repository = _repository
2484
 
        self.conf_store = None
2485
 
        Branch.__init__(self, possible_transports)
 
2449
        Branch.__init__(self)
2486
2450
 
2487
2451
    def __str__(self):
2488
 
        return '%s(%s)' % (self.__class__.__name__, self.user_url)
 
2452
        if self.name is None:
 
2453
            return '%s(%s)' % (self.__class__.__name__, self.user_url)
 
2454
        else:
 
2455
            return '%s(%s,%s)' % (self.__class__.__name__, self.user_url,
 
2456
                self.name)
2489
2457
 
2490
2458
    __repr__ = __str__
2491
2459
 
2495
2463
 
2496
2464
    base = property(_get_base, doc="The URL for the root of this branch.")
2497
2465
 
2498
 
    @property
2499
 
    def user_transport(self):
2500
 
        return self._user_transport
2501
 
 
2502
2466
    def _get_config(self):
2503
2467
        return _mod_config.TransportConfig(self._transport, 'branch.conf')
2504
2468
 
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
2469
    def is_locked(self):
2511
2470
        return self.control_files.is_locked()
2512
2471
 
2560
2519
 
2561
2520
    @only_raises(errors.LockNotHeld, errors.LockBroken)
2562
2521
    def unlock(self):
2563
 
        if self.conf_store is not None:
2564
 
            self.conf_store.save_changes()
2565
2522
        try:
2566
2523
            self.control_files.unlock()
2567
2524
        finally:
2743
2700
        self._transport.put_bytes('last-revision', out_string,
2744
2701
            mode=self.bzrdir._get_file_mode())
2745
2702
 
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
2703
 
2757
2704
class FullHistoryBzrBranch(BzrBranch):
2758
2705
    """Bzr branch which contains the full revision history."""
2865
2812
class BzrBranch8(BzrBranch):
2866
2813
    """A branch that stores tree-reference locations."""
2867
2814
 
2868
 
    def _open_hook(self, possible_transports=None):
 
2815
    def _open_hook(self):
2869
2816
        if self._ignore_fallbacks:
2870
2817
            return
2871
 
        if possible_transports is None:
2872
 
            possible_transports = [self.bzrdir.root_transport]
2873
2818
        try:
2874
2819
            url = self.get_stacked_on_url()
2875
2820
        except (errors.UnstackableRepositoryFormat, errors.NotStacked,
2883
2828
                    raise AssertionError(
2884
2829
                        "'transform_fallback_location' hook %s returned "
2885
2830
                        "None, not a URL." % hook_name)
2886
 
            self._activate_fallback_location(url,
2887
 
                possible_transports=possible_transports)
 
2831
            self._activate_fallback_location(url)
2888
2832
 
2889
2833
    def __init__(self, *args, **kwargs):
2890
2834
        self._ignore_fallbacks = kwargs.get('ignore_fallbacks', False)
3008
2952
        """See Branch.set_push_location."""
3009
2953
        self._master_branch_cache = None
3010
2954
        result = None
3011
 
        conf = self.get_config_stack()
 
2955
        config = self.get_config()
3012
2956
        if location is None:
3013
 
            if not conf.get('bound'):
 
2957
            if config.get_user_option('bound') != 'True':
3014
2958
                return False
3015
2959
            else:
3016
 
                conf.set('bound', 'False')
 
2960
                config.set_user_option('bound', 'False', warn_masked=True)
3017
2961
                return True
3018
2962
        else:
3019
2963
            self._set_config_location('bound_location', location,
3020
 
                                      config=conf)
3021
 
            conf.set('bound', 'True')
 
2964
                                      config=config)
 
2965
            config.set_user_option('bound', 'True', warn_masked=True)
3022
2966
        return True
3023
2967
 
3024
2968
    def _get_bound_location(self, bound):
3025
2969
        """Return the bound location in the config file.
3026
2970
 
3027
2971
        Return None if the bound parameter does not match"""
3028
 
        conf = self.get_config_stack()
3029
 
        if conf.get('bound') != bound:
 
2972
        config = self.get_config()
 
2973
        config_bound = (config.get_user_option('bound') == 'True')
 
2974
        if config_bound != bound:
3030
2975
            return None
3031
 
        return self._get_config_location('bound_location', config=conf)
 
2976
        return self._get_config_location('bound_location', config=config)
3032
2977
 
3033
2978
    def get_bound_location(self):
3034
 
        """See Branch.get_bound_location."""
 
2979
        """See Branch.set_push_location."""
3035
2980
        return self._get_bound_location(True)
3036
2981
 
3037
2982
    def get_old_bound_location(self):
3044
2989
        ## self._check_stackable_repo()
3045
2990
        # stacked_on_location is only ever defined in branch.conf, so don't
3046
2991
        # waste effort reading the whole stack of config files.
3047
 
        conf = _mod_config.BranchOnlyStack(self)
 
2992
        config = self.get_config()._get_branch_data_config()
3048
2993
        stacked_url = self._get_config_location('stacked_on_location',
3049
 
                                                config=conf)
 
2994
            config=config)
3050
2995
        if stacked_url is None:
3051
2996
            raise errors.NotStacked(self)
3052
 
        return stacked_url.encode('utf-8')
 
2997
        return stacked_url
3053
2998
 
3054
2999
    @needs_read_lock
3055
3000
    def get_rev_id(self, revno, history=None):
3250
3195
 
3251
3196
        # Copy source data into target
3252
3197
        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()
 
3198
        new_branch.set_parent(branch.get_parent())
 
3199
        new_branch.set_bound_location(branch.get_bound_location())
 
3200
        new_branch.set_push_location(branch.get_push_location())
3260
3201
 
3261
3202
        # New branch has no tags by default
3262
3203
        new_branch.tags._set_tag_dict({})
3263
3204
 
3264
3205
        # Copying done; now update target format
3265
3206
        new_branch._transport.put_bytes('format',
3266
 
            format.as_string(),
 
3207
            format.get_format_string(),
3267
3208
            mode=new_branch.bzrdir._get_file_mode())
3268
3209
 
3269
3210
        # Clean up old files
3270
3211
        new_branch._transport.delete('revision-history')
3271
 
        branch.lock_write()
3272
3212
        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()
 
3213
            branch.set_parent(None)
 
3214
        except errors.NoSuchFile:
 
3215
            pass
 
3216
        branch.set_bound_location(None)
3280
3217
 
3281
3218
 
3282
3219
class Converter6to7(object):
3286
3223
        format = BzrBranchFormat7()
3287
3224
        branch._set_config_location('stacked_on_location', '')
3288
3225
        # update target format
3289
 
        branch._transport.put_bytes('format', format.as_string())
 
3226
        branch._transport.put_bytes('format', format.get_format_string())
3290
3227
 
3291
3228
 
3292
3229
class Converter7to8(object):
3296
3233
        format = BzrBranchFormat8()
3297
3234
        branch._transport.put_bytes('references', '')
3298
3235
        # update target format
3299
 
        branch._transport.put_bytes('format', format.as_string())
 
3236
        branch._transport.put_bytes('format', format.get_format_string())
3300
3237
 
3301
3238
 
3302
3239
class InterBranch(InterObject):