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
17
from __future__ import absolute_import
21
18
from cStringIO import StringIO
23
21
from bzrlib.lazy_import import lazy_import
24
22
lazy_import(globals(), """
23
from itertools import chain
26
24
from bzrlib import (
31
config as _mod_config,
40
revision as _mod_revision,
28
config as _mod_config,
37
revision as _mod_revision,
43
from bzrlib.config import BranchConfig, TransportConfig
44
from bzrlib.tag import (
48
from bzrlib.i18n import gettext, ngettext
51
# Explicitly import bzrlib.bzrdir so that the BzrProber
52
# is guaranteed to be registered.
55
50
from bzrlib import (
59
53
from bzrlib.decorators import (
72
66
from bzrlib.trace import mutter, mutter_callsite, note, is_quiet
69
BZR_BRANCH_FORMAT_4 = "Bazaar-NG branch, format 0.0.4\n"
70
BZR_BRANCH_FORMAT_5 = "Bazaar-NG branch, format 5\n"
71
BZR_BRANCH_FORMAT_6 = "Bazaar Branch Format 6 (bzr 0.15)\n"
75
74
class Branch(controldir.ControlComponent):
76
75
"""Branch holding a history of revisions.
94
93
def user_transport(self):
95
94
return self.bzrdir.user_transport
97
def __init__(self, possible_transports=None):
96
def __init__(self, *ignored, **ignored_too):
98
97
self.tags = self._format.make_tags(self)
99
98
self._revision_history_cache = None
100
99
self._revision_id_to_revno_cache = None
104
103
self._last_revision_info_cache = None
105
104
self._master_branch_cache = None
106
105
self._merge_sorted_revisions_cache = None
107
self._open_hook(possible_transports)
108
107
hooks = Branch.hooks['open']
109
108
for hook in hooks:
112
def _open_hook(self, possible_transports):
111
def _open_hook(self):
113
112
"""Called by init to allow simpler extension of the base class."""
115
def _activate_fallback_location(self, url, possible_transports):
114
def _activate_fallback_location(self, url):
116
115
"""Activate the branch/repository from url as a fallback repository."""
117
116
for existing_fallback_repo in self.repository._fallback_repositories:
118
117
if existing_fallback_repo.user_url == url:
119
118
# This fallback is already configured. This probably only
120
# happens because ControlDir.sprout is a horrible mess. To avoid
119
# happens because BzrDir.sprout is a horrible mess. To avoid
121
120
# confusing _unstack we don't add this a second time.
122
121
mutter('duplicate activation of fallback %r on %r', url, self)
124
repo = self._get_fallback_repository(url, possible_transports)
123
repo = self._get_fallback_repository(url)
125
124
if repo.has_same_location(self.repository):
126
125
raise errors.UnstackableLocationError(self.user_url, url)
127
126
self.repository.add_fallback_repository(repo)
181
180
For instance, if the branch is at URL/.bzr/branch,
182
181
Branch.open(URL) -> a Branch instance.
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)
183
control = bzrdir.BzrDir.open(base, _unsupported,
184
possible_transports=possible_transports)
185
return control.open_branch(unsupported=_unsupported)
190
def open_from_transport(transport, name=None, _unsupported=False,
191
possible_transports=None):
188
def open_from_transport(transport, name=None, _unsupported=False):
192
189
"""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)
190
control = bzrdir.BzrDir.open_from_transport(transport, _unsupported)
191
return control.open_branch(name=name, unsupported=_unsupported)
198
194
def open_containing(url, possible_transports=None):
206
202
format, UnknownFormatError or UnsupportedFormatError are raised.
207
203
If there is one, it is returned, along with the unused portion of url.
209
control, relpath = controldir.ControlDir.open_containing(url,
205
control, relpath = bzrdir.BzrDir.open_containing(url,
210
206
possible_transports)
211
branch = control.open_branch(possible_transports=possible_transports)
212
return (branch, relpath)
207
return control.open_branch(), relpath
214
209
def _push_should_merge_tags(self):
215
210
"""Should _basic_push merge this branch's tags into the target?
228
223
:return: A bzrlib.config.BranchConfig.
230
return _mod_config.BranchConfig(self)
232
def get_config_stack(self):
233
"""Get a bzrlib.config.BranchStack for this Branch.
235
This can then be used to get and set configuration options for the
238
:return: A bzrlib.config.BranchStack.
240
return _mod_config.BranchStack(self)
225
return BranchConfig(self)
242
227
def _get_config(self):
243
228
"""Get the concrete config for just the config in this branch.
252
237
raise NotImplementedError(self._get_config)
254
def _get_fallback_repository(self, url, possible_transports):
239
def _get_fallback_repository(self, url):
255
240
"""Get the repository we fallback to at url."""
256
241
url = urlutils.join(self.base, url)
257
a_branch = Branch.open(url, possible_transports=possible_transports)
242
a_branch = Branch.open(url,
243
possible_transports=[self.bzrdir.root_transport])
258
244
return a_branch.repository
666
652
raise errors.UpgradeRequired(self.user_url)
668
def get_append_revisions_only(self):
669
"""Whether it is only possible to append revisions to the history.
671
if not self._format.supports_set_append_revisions_only():
673
return self.get_config_stack().get('append_revisions_only')
675
654
def set_append_revisions_only(self, enabled):
676
655
if not self._format.supports_set_append_revisions_only():
677
656
raise errors.UpgradeRequired(self.user_url)
678
self.get_config_stack().set('append_revisions_only', enabled)
661
self.get_config().set_user_option('append_revisions_only', value,
680
664
def set_reference_info(self, file_id, tree_path, branch_location):
681
665
"""Set the branch location to use for a tree reference."""
711
695
raise errors.UpgradeRequired(self.user_url)
713
def get_commit_builder(self, parents, config_stack=None, timestamp=None,
697
def get_commit_builder(self, parents, config=None, timestamp=None,
714
698
timezone=None, committer=None, revprops=None,
715
699
revision_id=None, lossy=False):
716
700
"""Obtain a CommitBuilder for this branch.
726
710
represented, when pushing to a foreign VCS
729
if config_stack is None:
730
config_stack = self.get_config_stack()
714
config = self.get_config()
732
return self.repository.get_commit_builder(self, parents, config_stack,
716
return self.repository.get_commit_builder(self, parents, config,
733
717
timestamp, timezone, committer, revprops, revision_id,
743
@deprecated_method(deprecated_in((2, 5, 0)))
744
727
def get_revision_delta(self, revno):
745
728
"""Return the delta for one revision.
747
730
The delta is relative to its mainline predecessor, or the
748
731
empty tree for revision 1.
751
revid = self.get_rev_id(revno)
752
except errors.NoSuchRevision:
733
rh = self.revision_history()
734
if not (1 <= revno <= len(rh)):
753
735
raise errors.InvalidRevisionNumber(revno)
754
return self.repository.get_revision_delta(revid)
736
return self.repository.get_revision_delta(rh[revno-1])
756
738
def get_stacked_on_url(self):
757
739
"""Get the URL this branch is stacked against.
889
870
# stream from one of them to the other. This does mean doing
890
871
# separate SSH connection setup, but unstacking is not a
891
872
# common operation so it's tolerable.
892
new_bzrdir = controldir.ControlDir.open(
893
self.bzrdir.root_transport.base)
873
new_bzrdir = bzrdir.BzrDir.open(self.bzrdir.root_transport.base)
894
874
new_repository = new_bzrdir.find_repository()
895
875
if new_repository._fallback_repositories:
896
876
raise AssertionError("didn't expect %r to have "
939
919
tags_to_fetch = set(self.tags.get_reverse_tag_dict())
940
920
except errors.TagsNotSupported:
941
921
tags_to_fetch = set()
942
fetch_spec = vf_search.NotInOtherForRevs(self.repository,
922
fetch_spec = _mod_graph.NotInOtherForRevs(self.repository,
943
923
old_repository, required_ids=[self.last_revision()],
944
924
if_present_ids=tags_to_fetch, find_ghosts=True).execute()
945
925
self.repository.fetch(old_repository, fetch_spec=fetch_spec)
1170
1146
def _set_config_location(self, name, url, config=None,
1171
1147
make_relative=False):
1172
1148
if config is None:
1173
config = self.get_config_stack()
1149
config = self.get_config()
1174
1150
if url is None:
1176
1152
elif make_relative:
1177
1153
url = urlutils.relative_url(self.base, url)
1178
config.set(name, url)
1154
config.set_user_option(name, url, warn_masked=True)
1180
1156
def _get_config_location(self, name, config=None):
1181
1157
if config is None:
1182
config = self.get_config_stack()
1183
location = config.get(name)
1158
config = self.get_config()
1159
location = config.get_user_option(name)
1184
1160
if location == '':
1185
1161
location = None
1186
1162
return location
1188
1164
def get_child_submit_format(self):
1189
1165
"""Return the preferred format of submissions to this branch."""
1190
return self.get_config_stack().get('child_submit_format')
1166
return self.get_config().get_user_option("child_submit_format")
1192
1168
def get_submit_branch(self):
1193
1169
"""Return the submit location of the branch.
1224
1201
self._set_config_location('public_branch', location)
1226
1203
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')
1204
"""Return the None or the location to push this branch to."""
1205
push_loc = self.get_config().get_user_option('push_location')
1230
1208
def set_push_location(self, location):
1231
1209
"""Set a new push location for this branch."""
1400
1378
# TODO: We should probably also check that self.revision_history
1401
1379
# matches the repository for older branch formats.
1402
1380
# If looking for the code that cross-checks repository parents against
1403
# the Graph.iter_lefthand_ancestry output, that is now a repository
1381
# the iter_reverse_revision_history output, that is now a repository
1404
1382
# specific check.
1407
def _get_checkout_format(self, lightweight=False):
1385
def _get_checkout_format(self):
1408
1386
"""Return the most suitable metadir for a checkout of this branch.
1409
1387
Weaves are used if this branch's repository uses weaves.
1457
1435
t = transport.get_transport(to_location)
1458
1436
t.ensure_base()
1459
format = self._get_checkout_format(lightweight=lightweight)
1438
format = self._get_checkout_format()
1461
1439
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)
1467
checkout.open_branch()
1468
except errors.NotBranchError:
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
1478
from_branch = checkout.set_branch_reference(target_branch=self)
1440
from_branch = BranchReferenceFormat().initialize(checkout,
1480
policy = checkout.determine_repository_policy()
1481
repo = policy.acquire_repository()[0]
1482
checkout_branch = checkout.create_branch()
1443
format = self._get_checkout_format()
1444
checkout_branch = bzrdir.BzrDir.create_branch_convenience(
1445
to_location, force_new_tree=False, format=format)
1446
checkout = checkout_branch.bzrdir
1483
1447
checkout_branch.bind(self)
1484
1448
# pull up to the specified revision_id to set the initial
1485
1449
# branch tip correctly, and seed it with history.
1486
1450
checkout_branch.pull(self, stop_revision=revision_id)
1488
1452
tree = checkout.create_workingtree(revision_id,
1489
1453
from_branch=from_branch,
1490
1454
accelerator_tree=accelerator_tree,
1579
1543
heads that must be fetched if present, but no error is necessary if
1580
1544
they are not present.
1582
# For bzr native formats must_fetch is just the tip, and
1583
# if_present_fetch are the tags.
1546
# For bzr native formats must_fetch is just the tip, and if_present_fetch
1584
1548
must_fetch = set([self.last_revision()])
1585
1549
if_present_fetch = set()
1586
if self.get_config_stack().get('branch.fetch_tags'):
1550
c = self.get_config()
1551
include_tags = c.get_user_option_as_bool('branch.fetch_tags',
1588
1555
if_present_fetch = set(self.tags.get_reverse_tag_dict())
1589
1556
except errors.TagsNotSupported:
1618
1587
return not (self == other)
1590
def find_format(klass, a_bzrdir, name=None):
1591
"""Return the format for the branch object in a_bzrdir."""
1593
transport = a_bzrdir.get_branch_transport(None, name=name)
1594
format_string = bzrdir.extract_format_string(
1595
transport.get_bytes("format"))
1596
return format_registry.get(format_string)
1597
except errors.NoSuchFile:
1598
raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)
1600
raise errors.UnknownFormatError(format=format_string, kind='branch')
1621
1603
@deprecated_method(deprecated_in((2, 4, 0)))
1622
1604
def get_default_format(klass):
1623
1605
"""Return the current default format."""
1634
1616
return format_registry._get_all()
1636
def get_reference(self, controldir, name=None):
1637
"""Get the target reference of the branch in controldir.
1618
def get_reference(self, a_bzrdir, name=None):
1619
"""Get the target reference of the branch in a_bzrdir.
1639
1621
format probing must have been completed before calling
1640
1622
this method - it is assumed that the format of the branch
1641
in controldir is correct.
1623
in a_bzrdir is correct.
1643
:param controldir: The controldir to get the branch data from.
1625
:param a_bzrdir: The bzrdir to get the branch data from.
1644
1626
:param name: Name of the colocated branch to fetch
1645
1627
:return: None if the branch is not a reference branch.
1650
def set_reference(self, controldir, name, to_branch):
1651
"""Set the target reference of the branch in controldir.
1632
def set_reference(self, a_bzrdir, name, to_branch):
1633
"""Set the target reference of the branch in a_bzrdir.
1653
1635
format probing must have been completed before calling
1654
1636
this method - it is assumed that the format of the branch
1655
in controldir is correct.
1637
in a_bzrdir is correct.
1657
:param controldir: The controldir to set the branch reference for.
1639
:param a_bzrdir: The bzrdir to set the branch reference for.
1658
1640
:param name: Name of colocated branch to set, None for default
1659
1641
:param to_branch: branch that the checkout is to reference
1661
1643
raise NotImplementedError(self.set_reference)
1645
def get_format_string(self):
1646
"""Return the ASCII format string that identifies this format."""
1647
raise NotImplementedError(self.get_format_string)
1663
1649
def get_format_description(self):
1664
1650
"""Return the short format description for this format."""
1665
1651
raise NotImplementedError(self.get_format_description)
1667
def _run_post_branch_init_hooks(self, controldir, name, branch):
1653
def _run_post_branch_init_hooks(self, a_bzrdir, name, branch):
1668
1654
hooks = Branch.hooks['post_branch_init']
1671
params = BranchInitHookParams(self, controldir, name, branch)
1657
params = BranchInitHookParams(self, a_bzrdir, name, branch)
1672
1658
for hook in hooks:
1675
def initialize(self, controldir, name=None, repository=None,
1676
append_revisions_only=None):
1677
"""Create a branch of this format in controldir.
1661
def initialize(self, a_bzrdir, name=None, repository=None):
1662
"""Create a branch of this format in a_bzrdir.
1679
1664
:param name: Name of the colocated branch to create.
1681
1666
raise NotImplementedError(self.initialize)
1714
1699
raise NotImplementedError(self.network_name)
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.
1701
def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False,
1702
found_repository=None):
1703
"""Return the branch object for a_bzrdir
1720
:param controldir: A ControlDir that contains a branch.
1705
:param a_bzrdir: A BzrDir that contains a branch.
1721
1706
:param name: Name of colocated branch to open
1722
1707
:param _found: a private parameter, do not use it. It is used to
1723
1708
indicate if format probing has already be done.
1765
1750
"""True if this format supports tags stored in the branch"""
1766
1751
return False # by default
1768
def tags_are_versioned(self):
1769
"""Whether the tag container for this branch versions tags."""
1772
def supports_tags_referencing_ghosts(self):
1773
"""True if tags can reference ghost revisions."""
1777
1754
class MetaDirBranchFormatFactory(registry._LazyObjectGetter):
1778
1755
"""A factory for a BranchFormat object, permitting simple lazy registration.
1952
1929
branch, which refer to the original branch.
1955
def __init__(self, format, controldir, name, branch):
1932
def __init__(self, format, a_bzrdir, name, branch):
1956
1933
"""Create a group of BranchInitHook parameters.
1958
1935
:param format: the branch format
1959
:param controldir: the ControlDir where the branch will be/has been
1936
:param a_bzrdir: the BzrDir where the branch will be/has been
1961
1938
:param name: name of colocated branch, if any (or None)
1962
1939
:param branch: the branch created
1991
1968
def __init__(self, control_dir, to_branch, force, revision_id):
1992
1969
"""Create a group of SwitchHook parameters.
1994
:param control_dir: ControlDir of the checkout to change
1971
:param control_dir: BzrDir of the checkout to change
1995
1972
:param to_branch: branch that the checkout is to reference
1996
1973
:param force: skip the check for local commits in a heavy checkout
1997
1974
:param revision_id: revision ID to switch to (or None)
2010
1987
self.revision_id)
2013
class BranchFormatMetadir(bzrdir.BzrFormat, BranchFormat):
2014
"""Base class for branch formats that live in meta directories.
2018
BranchFormat.__init__(self)
2019
bzrdir.BzrFormat.__init__(self)
2022
def find_format(klass, controldir, name=None):
2023
"""Return the format for the branch object in controldir."""
2025
transport = controldir.get_branch_transport(None, name=name)
2026
except errors.NoSuchFile:
2027
raise errors.NotBranchError(path=name, bzrdir=controldir)
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)
1990
class BranchFormatMetadir(BranchFormat):
1991
"""Common logic for meta-dir based branch formats."""
2034
1993
def _branch_class(self):
2035
1994
"""What class to instantiate on open calls."""
2036
1995
raise NotImplementedError(self._branch_class)
2038
def _get_initial_config(self, append_revisions_only=None):
2039
if append_revisions_only:
2040
return "append_revisions_only = True\n"
2042
# Avoid writing anything if append_revisions_only is disabled,
2043
# as that is the default.
2046
1997
def _initialize_helper(self, a_bzrdir, utf8_files, name=None,
2047
1998
repository=None):
2048
1999
"""Initialize a branch in a bzrdir, with specified files
2053
2004
:param name: Name of colocated branch to create, if any
2054
2005
:return: a branch in this format
2057
name = a_bzrdir._get_selected_branch()
2058
2007
mutter('creating branch %r in %s', self, a_bzrdir.user_url)
2059
2008
branch_transport = a_bzrdir.get_branch_transport(self, name=name)
2060
2009
control_files = lockable_files.LockableFiles(branch_transport,
2074
2023
self._run_post_branch_init_hooks(a_bzrdir, name, branch)
2026
def network_name(self):
2027
"""A simple byte string uniquely identifying this format for RPC calls.
2029
Metadir branch formats use their format string.
2031
return self.get_format_string()
2077
2033
def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False,
2078
found_repository=None, possible_transports=None):
2034
found_repository=None):
2079
2035
"""See BranchFormat.open()."""
2081
name = a_bzrdir._get_selected_branch()
2083
format = BranchFormatMetadir.find_format(a_bzrdir, name=name)
2037
format = BranchFormat.find_format(a_bzrdir, name=name)
2084
2038
if format.__class__ != self.__class__:
2085
2039
raise AssertionError("wrong format %r found for %r" %
2086
2040
(format, self))
2096
2050
a_bzrdir=a_bzrdir,
2097
2051
_repository=found_repository,
2098
ignore_fallbacks=ignore_fallbacks,
2099
possible_transports=possible_transports)
2052
ignore_fallbacks=ignore_fallbacks)
2100
2053
except errors.NoSuchFile:
2101
2054
raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)
2104
def _matchingbzrdir(self):
2105
ret = bzrdir.BzrDirMetaFormat1()
2106
ret.set_branch_format(self)
2057
super(BranchFormatMetadir, self).__init__()
2058
self._matchingbzrdir = bzrdir.BzrDirMetaFormat1()
2059
self._matchingbzrdir.set_branch_format(self)
2109
2061
def supports_tags(self):
2112
2064
def supports_leaving_lock(self):
2115
def check_support_status(self, allow_unsupported, recommend_upgrade=True,
2117
BranchFormat.check_support_status(self,
2118
allow_unsupported=allow_unsupported, recommend_upgrade=recommend_upgrade,
2120
bzrdir.BzrFormat.check_support_status(self, allow_unsupported=allow_unsupported,
2121
recommend_upgrade=recommend_upgrade, basedir=basedir)
2124
2068
class BzrBranchFormat5(BranchFormatMetadir):
2125
2069
"""Bzr branch format 5.
2146
2089
"""See BranchFormat.get_format_description()."""
2147
2090
return "Branch format 5"
2149
def initialize(self, a_bzrdir, name=None, repository=None,
2150
append_revisions_only=None):
2092
def initialize(self, a_bzrdir, name=None, repository=None):
2151
2093
"""Create a branch of this format in a_bzrdir."""
2152
if append_revisions_only:
2153
raise errors.UpgradeRequired(a_bzrdir.user_url)
2154
2094
utf8_files = [('revision-history', ''),
2155
2095
('branch-name', ''),
2183
2122
"""See BranchFormat.get_format_description()."""
2184
2123
return "Branch format 6"
2186
def initialize(self, a_bzrdir, name=None, repository=None,
2187
append_revisions_only=None):
2125
def initialize(self, a_bzrdir, name=None, repository=None):
2188
2126
"""Create a branch of this format in a_bzrdir."""
2189
2127
utf8_files = [('last-revision', '0 null:\n'),
2191
self._get_initial_config(append_revisions_only)),
2128
('branch.conf', ''),
2194
2131
return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
2196
2133
def make_tags(self, branch):
2197
2134
"""See bzrlib.branch.BranchFormat.make_tags()."""
2198
return _mod_tag.BasicTags(branch)
2135
return BasicTags(branch)
2200
2137
def supports_set_append_revisions_only(self):
2216
2152
"""See BranchFormat.get_format_description()."""
2217
2153
return "Branch format 8"
2219
def initialize(self, a_bzrdir, name=None, repository=None,
2220
append_revisions_only=None):
2155
def initialize(self, a_bzrdir, name=None, repository=None):
2221
2156
"""Create a branch of this format in a_bzrdir."""
2222
2157
utf8_files = [('last-revision', '0 null:\n'),
2224
self._get_initial_config(append_revisions_only)),
2158
('branch.conf', ''),
2226
2160
('references', '')
2249
2183
This format was introduced in bzr 1.6.
2252
def initialize(self, a_bzrdir, name=None, repository=None,
2253
append_revisions_only=None):
2186
def initialize(self, a_bzrdir, name=None, repository=None):
2254
2187
"""Create a branch of this format in a_bzrdir."""
2255
2188
utf8_files = [('last-revision', '0 null:\n'),
2257
self._get_initial_config(append_revisions_only)),
2189
('branch.conf', ''),
2260
2192
return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
2280
2211
def make_tags(self, branch):
2281
2212
"""See bzrlib.branch.BranchFormat.make_tags()."""
2282
return _mod_tag.BasicTags(branch)
2213
return BasicTags(branch)
2284
2215
supports_reference_locations = False
2287
class BranchReferenceFormat(BranchFormatMetadir):
2218
class BranchReferenceFormat(BranchFormat):
2288
2219
"""Bzr branch reference format.
2290
2221
Branch references are used in implementing checkouts, they
2315
2245
location = transport.put_bytes('location', to_branch.base)
2317
2247
def initialize(self, a_bzrdir, name=None, target_branch=None,
2318
repository=None, append_revisions_only=None):
2319
2249
"""Create a branch of this format in a_bzrdir."""
2320
2250
if target_branch is None:
2321
2251
# this format does not implement branch itself, thus the implicit
2322
2252
# creation contract must see it as uninitializable
2323
2253
raise errors.UninitializableFormat(self)
2324
2254
mutter('creating branch reference in %s', a_bzrdir.user_url)
2325
if a_bzrdir._format.fixed_components:
2326
raise errors.IncompatibleFormat(self, a_bzrdir._format)
2328
name = a_bzrdir._get_selected_branch()
2329
2255
branch_transport = a_bzrdir.get_branch_transport(self, name=name)
2330
2256
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,
2257
target_branch.bzrdir.user_url)
2258
branch_transport.put_bytes('format', self.get_format_string())
2260
a_bzrdir, name, _found=True,
2334
2261
possible_transports=[target_branch.bzrdir.root_transport])
2335
2262
self._run_post_branch_init_hooks(a_bzrdir, name, branch)
2266
super(BranchReferenceFormat, self).__init__()
2267
self._matchingbzrdir = bzrdir.BzrDirMetaFormat1()
2268
self._matchingbzrdir.set_branch_format(self)
2338
2270
def _make_reference_clone_function(format, a_branch):
2339
2271
"""Create a clone() routine for a branch dynamically."""
2340
2272
def clone(to_bzrdir, revision_id=None,
2363
2295
:param possible_transports: An optional reusable transports list.
2366
name = a_bzrdir._get_selected_branch()
2368
format = BranchFormatMetadir.find_format(a_bzrdir, name=name)
2298
format = BranchFormat.find_format(a_bzrdir, name=name)
2369
2299
if format.__class__ != self.__class__:
2370
2300
raise AssertionError("wrong format %r found for %r" %
2371
2301
(format, self))
2372
2302
if location is None:
2373
2303
location = self.get_reference(a_bzrdir, name)
2374
real_bzrdir = controldir.ControlDir.open(
2304
real_bzrdir = bzrdir.BzrDir.open(
2375
2305
location, possible_transports=possible_transports)
2376
result = real_bzrdir.open_branch(ignore_fallbacks=ignore_fallbacks,
2377
possible_transports=possible_transports)
2306
result = real_bzrdir.open_branch(name=name,
2307
ignore_fallbacks=ignore_fallbacks)
2378
2308
# this changes the behaviour of result.clone to create a new reference
2379
2309
# rather than a copy of the content of the branch.
2380
2310
# I did not use a proxy object because that needs much more extensive
2462
2392
def __init__(self, _format=None,
2463
2393
_control_files=None, a_bzrdir=None, name=None,
2464
_repository=None, ignore_fallbacks=False,
2465
possible_transports=None):
2394
_repository=None, ignore_fallbacks=False):
2466
2395
"""Create new branch object at a particular location."""
2467
2396
if a_bzrdir is None:
2468
2397
raise ValueError('a_bzrdir must be supplied')
2470
raise ValueError('name must be supplied')
2471
self.bzrdir = a_bzrdir
2472
self._user_transport = self.bzrdir.transport.clone('..')
2474
self._user_transport.set_segment_parameter(
2475
"branch", urlutils.escape(name))
2476
self._base = self._user_transport.base
2399
self.bzrdir = a_bzrdir
2400
self._base = self.bzrdir.transport.clone('..').base
2477
2401
self.name = name
2402
# XXX: We should be able to just do
2403
# self.base = self.bzrdir.root_transport.base
2404
# but this does not quite work yet -- mbp 20080522
2478
2405
self._format = _format
2479
2406
if _control_files is None:
2480
2407
raise ValueError('BzrBranch _control_files is None')
2481
2408
self.control_files = _control_files
2482
2409
self._transport = _control_files._transport
2483
2410
self.repository = _repository
2484
Branch.__init__(self, possible_transports)
2411
Branch.__init__(self)
2486
2413
def __str__(self):
2487
return '%s(%s)' % (self.__class__.__name__, self.user_url)
2414
if self.name is None:
2415
return '%s(%s)' % (self.__class__.__name__, self.user_url)
2417
return '%s(%s,%s)' % (self.__class__.__name__, self.user_url,
2489
2420
__repr__ = __str__
2495
2426
base = property(_get_base, doc="The URL for the root of this branch.")
2498
def user_transport(self):
2499
return self._user_transport
2501
2428
def _get_config(self):
2502
return _mod_config.TransportConfig(self._transport, 'branch.conf')
2504
def _get_config_store(self):
2505
return _mod_config.BranchStore(self)
2429
return TransportConfig(self._transport, 'branch.conf')
2507
2431
def is_locked(self):
2508
2432
return self.control_files.is_locked()
2589
2513
raise errors.InvalidRevisionId(revision_id=revision_id, branch=self)
2590
2514
revision_id = _mod_revision.ensure_null(revision_id)
2591
2515
old_revno, old_revid = self.last_revision_info()
2592
if self.get_append_revisions_only():
2516
if self._get_append_revisions_only():
2593
2517
self._check_history_violation(revision_id)
2594
2518
self._run_pre_change_branch_tip_hooks(revno, revision_id)
2595
2519
self._write_last_revision_info(revno, revision_id)
2738
2662
self._transport.put_bytes('last-revision', out_string,
2739
2663
mode=self.bzrdir._get_file_mode())
2742
def update_feature_flags(self, updated_flags):
2743
"""Update the feature flags for this branch.
2745
:param updated_flags: Dictionary mapping feature names to necessities
2746
A necessity can be None to indicate the feature should be removed
2748
self._format._update_feature_flags(updated_flags)
2749
self.control_transport.put_bytes('format', self._format.as_string())
2752
2666
class FullHistoryBzrBranch(BzrBranch):
2753
2667
"""Bzr branch which contains the full revision history."""
2860
2774
class BzrBranch8(BzrBranch):
2861
2775
"""A branch that stores tree-reference locations."""
2863
def _open_hook(self, possible_transports=None):
2777
def _open_hook(self):
2864
2778
if self._ignore_fallbacks:
2866
if possible_transports is None:
2867
possible_transports = [self.bzrdir.root_transport]
2869
2781
url = self.get_stacked_on_url()
2870
2782
except (errors.UnstackableRepositoryFormat, errors.NotStacked,
2878
2790
raise AssertionError(
2879
2791
"'transform_fallback_location' hook %s returned "
2880
2792
"None, not a URL." % hook_name)
2881
self._activate_fallback_location(url,
2882
possible_transports=possible_transports)
2793
self._activate_fallback_location(url)
2884
2795
def __init__(self, *args, **kwargs):
2885
2796
self._ignore_fallbacks = kwargs.get('ignore_fallbacks', False)
3003
2914
"""See Branch.set_push_location."""
3004
2915
self._master_branch_cache = None
3006
conf = self.get_config_stack()
2917
config = self.get_config()
3007
2918
if location is None:
3008
if not conf.get('bound'):
2919
if config.get_user_option('bound') != 'True':
3011
conf.set('bound', 'False')
2922
config.set_user_option('bound', 'False', warn_masked=True)
3014
2925
self._set_config_location('bound_location', location,
3016
conf.set('bound', 'True')
2927
config.set_user_option('bound', 'True', warn_masked=True)
3019
2930
def _get_bound_location(self, bound):
3020
2931
"""Return the bound location in the config file.
3022
2933
Return None if the bound parameter does not match"""
3023
conf = self.get_config_stack()
3024
if conf.get('bound') != bound:
2934
config = self.get_config()
2935
config_bound = (config.get_user_option('bound') == 'True')
2936
if config_bound != bound:
3026
return self._get_config_location('bound_location', config=conf)
2938
return self._get_config_location('bound_location', config=config)
3028
2940
def get_bound_location(self):
3029
"""See Branch.get_bound_location."""
2941
"""See Branch.set_push_location."""
3030
2942
return self._get_bound_location(True)
3032
2944
def get_old_bound_location(self):
3039
2951
## self._check_stackable_repo()
3040
2952
# stacked_on_location is only ever defined in branch.conf, so don't
3041
2953
# waste effort reading the whole stack of config files.
3042
conf = _mod_config.BranchOnlyStack(self)
2954
config = self.get_config()._get_branch_data_config()
3043
2955
stacked_url = self._get_config_location('stacked_on_location',
3045
2957
if stacked_url is None:
3046
2958
raise errors.NotStacked(self)
3047
return stacked_url.encode('utf-8')
2961
def _get_append_revisions_only(self):
2962
return self.get_config(
2963
).get_user_option_as_bool('append_revisions_only')
3049
2965
@needs_read_lock
3050
2966
def get_rev_id(self, revno, history=None):
3080
2996
except errors.RevisionNotPresent, e:
3081
2997
raise errors.GhostRevisionsHaveNoRevno(revision_id, e.revision_id)
3082
2998
index = len(self._partial_revision_history_cache) - 1
3084
raise errors.NoSuchRevision(self, revision_id)
3085
2999
if self._partial_revision_history_cache[index] != revision_id:
3086
3000
raise errors.NoSuchRevision(self, revision_id)
3087
3001
return self.revno() - index
3151
3064
return self.new_revno - self.old_revno
3153
3066
def report(self, to_file):
3154
tag_conflicts = getattr(self, "tag_conflicts", None)
3155
tag_updates = getattr(self, "tag_updates", None)
3156
3067
if not is_quiet():
3157
if self.old_revid != self.new_revid:
3068
if self.old_revid == self.new_revid:
3069
to_file.write('No revisions to pull.\n')
3158
3071
to_file.write('Now on revision %d.\n' % self.new_revno)
3160
to_file.write('%d tag(s) updated.\n' % len(tag_updates))
3161
if self.old_revid == self.new_revid and not tag_updates:
3162
if not tag_conflicts:
3163
to_file.write('No revisions or tags to pull.\n')
3165
to_file.write('No revisions to pull.\n')
3166
3072
self._show_tag_conficts(to_file)
3194
3100
return self.new_revno - self.old_revno
3196
3102
def report(self, to_file):
3197
# TODO: This function gets passed a to_file, but then
3198
# ignores it and calls note() instead. This is also
3199
# inconsistent with PullResult(), which writes to stdout.
3200
# -- JRV20110901, bug #838853
3201
tag_conflicts = getattr(self, "tag_conflicts", None)
3202
tag_updates = getattr(self, "tag_updates", None)
3204
if self.old_revid != self.new_revid:
3205
note(gettext('Pushed up to revision %d.') % self.new_revno)
3207
note(ngettext('%d tag updated.', '%d tags updated.', len(tag_updates)) % len(tag_updates))
3208
if self.old_revid == self.new_revid and not tag_updates:
3209
if not tag_conflicts:
3210
note(gettext('No new revisions or tags to push.'))
3212
note(gettext('No new revisions to push.'))
3103
"""Write a human-readable description of the result."""
3104
if self.old_revid == self.new_revid:
3105
note('No new revisions to push.')
3107
note('Pushed up to revision %d.' % self.new_revno)
3213
3108
self._show_tag_conficts(to_file)
3229
3124
:param verbose: Requests more detailed display of what was checked,
3232
note(gettext('checked branch {0} format {1}').format(
3233
self.branch.user_url, self.branch._format))
3127
note('checked branch %s format %s', self.branch.user_url,
3128
self.branch._format)
3234
3129
for error in self.errors:
3235
note(gettext('found error:%s'), error)
3130
note('found error:%s', error)
3238
3133
class Converter5to6(object):
3273
3168
format = BzrBranchFormat7()
3274
3169
branch._set_config_location('stacked_on_location', '')
3275
3170
# update target format
3276
branch._transport.put_bytes('format', format.as_string())
3171
branch._transport.put_bytes('format', format.get_format_string())
3279
3174
class Converter7to8(object):
3280
"""Perform an in-place upgrade of format 7 to format 8"""
3175
"""Perform an in-place upgrade of format 6 to format 7"""
3282
3177
def convert(self, branch):
3283
3178
format = BzrBranchFormat8()
3284
3179
branch._transport.put_bytes('references', '')
3285
3180
# update target format
3286
branch._transport.put_bytes('format', format.as_string())
3181
branch._transport.put_bytes('format', format.get_format_string())
3289
3184
class InterBranch(InterObject):
3523
3418
self._update_revisions(stop_revision, overwrite=overwrite,
3525
3420
if self.source._push_should_merge_tags():
3526
result.tag_updates, result.tag_conflicts = (
3527
self.source.tags.merge_to(self.target.tags, overwrite))
3421
result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
3528
3423
result.new_revno, result.new_revid = self.target.last_revision_info()
3613
3508
# TODO: The old revid should be specified when merging tags,
3614
3509
# so a tags implementation that versions tags can only
3615
3510
# pull in the most recent changes. -- JRV20090506
3616
result.tag_updates, result.tag_conflicts = (
3617
self.source.tags.merge_to(self.target.tags, overwrite,
3618
ignore_master=not merge_tags_to_master))
3511
result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
3512
overwrite, ignore_master=not merge_tags_to_master)
3619
3513
result.new_revno, result.new_revid = self.target.last_revision_info()
3620
3514
if _hook_master:
3621
3515
result.master_branch = _hook_master