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
18
21
from cStringIO import StringIO
21
23
from bzrlib.lazy_import import lazy_import
22
24
lazy_import(globals(), """
23
from itertools import chain
24
26
from bzrlib import (
28
config as _mod_config,
37
revision as _mod_revision,
43
from bzrlib.config import BranchConfig, TransportConfig
44
from bzrlib.tag import (
31
config as _mod_config,
40
revision as _mod_revision,
48
from bzrlib.i18n import gettext, ngettext
51
# Explicitly import bzrlib.bzrdir so that the BzrProber
52
# is guaranteed to be registered.
50
55
from bzrlib import (
53
59
from bzrlib.decorators import (
66
72
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"
74
75
class Branch(controldir.ControlComponent):
75
76
"""Branch holding a history of revisions.
93
94
def user_transport(self):
94
95
return self.bzrdir.user_transport
96
def __init__(self, *ignored, **ignored_too):
97
def __init__(self, possible_transports=None):
97
98
self.tags = self._format.make_tags(self)
98
99
self._revision_history_cache = None
99
100
self._revision_id_to_revno_cache = None
103
104
self._last_revision_info_cache = None
104
105
self._master_branch_cache = None
105
106
self._merge_sorted_revisions_cache = None
107
self._open_hook(possible_transports)
107
108
hooks = Branch.hooks['open']
108
109
for hook in hooks:
111
def _open_hook(self):
112
def _open_hook(self, possible_transports):
112
113
"""Called by init to allow simpler extension of the base class."""
114
def _activate_fallback_location(self, url):
115
def _activate_fallback_location(self, url, possible_transports):
115
116
"""Activate the branch/repository from url as a fallback repository."""
116
117
for existing_fallback_repo in self.repository._fallback_repositories:
117
118
if existing_fallback_repo.user_url == url:
118
119
# This fallback is already configured. This probably only
119
# happens because BzrDir.sprout is a horrible mess. To avoid
120
# happens because ControlDir.sprout is a horrible mess. To avoid
120
121
# confusing _unstack we don't add this a second time.
121
122
mutter('duplicate activation of fallback %r on %r', url, self)
123
repo = self._get_fallback_repository(url)
124
repo = self._get_fallback_repository(url, possible_transports)
124
125
if repo.has_same_location(self.repository):
125
126
raise errors.UnstackableLocationError(self.user_url, url)
126
127
self.repository.add_fallback_repository(repo)
180
181
For instance, if the branch is at URL/.bzr/branch,
181
182
Branch.open(URL) -> a Branch instance.
183
control = bzrdir.BzrDir.open(base, _unsupported,
184
possible_transports=possible_transports)
185
return control.open_branch(unsupported=_unsupported)
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)
188
def open_from_transport(transport, name=None, _unsupported=False):
190
def open_from_transport(transport, name=None, _unsupported=False,
191
possible_transports=None):
189
192
"""Open the branch rooted at transport"""
190
control = bzrdir.BzrDir.open_from_transport(transport, _unsupported)
191
return control.open_branch(name=name, unsupported=_unsupported)
193
control = controldir.ControlDir.open_from_transport(transport, _unsupported)
194
return control.open_branch(name=name, unsupported=_unsupported,
195
possible_transports=possible_transports)
194
198
def open_containing(url, possible_transports=None):
202
206
format, UnknownFormatError or UnsupportedFormatError are raised.
203
207
If there is one, it is returned, along with the unused portion of url.
205
control, relpath = bzrdir.BzrDir.open_containing(url,
209
control, relpath = controldir.ControlDir.open_containing(url,
206
210
possible_transports)
207
return control.open_branch(), relpath
211
branch = control.open_branch(possible_transports=possible_transports)
212
return (branch, relpath)
209
214
def _push_should_merge_tags(self):
210
215
"""Should _basic_push merge this branch's tags into the target?
223
228
:return: A bzrlib.config.BranchConfig.
225
return BranchConfig(self)
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)
227
242
def _get_config(self):
228
243
"""Get the concrete config for just the config in this branch.
237
252
raise NotImplementedError(self._get_config)
239
def _get_fallback_repository(self, url):
254
def _get_fallback_repository(self, url, possible_transports):
240
255
"""Get the repository we fallback to at url."""
241
256
url = urlutils.join(self.base, url)
242
a_branch = Branch.open(url,
243
possible_transports=[self.bzrdir.root_transport])
257
a_branch = Branch.open(url, possible_transports=possible_transports)
244
258
return a_branch.repository
652
666
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')
654
675
def set_append_revisions_only(self, enabled):
655
676
if not self._format.supports_set_append_revisions_only():
656
677
raise errors.UpgradeRequired(self.user_url)
661
self.get_config().set_user_option('append_revisions_only', value,
678
self.get_config_stack().set('append_revisions_only', enabled)
664
680
def set_reference_info(self, file_id, tree_path, branch_location):
665
681
"""Set the branch location to use for a tree reference."""
695
711
raise errors.UpgradeRequired(self.user_url)
697
def get_commit_builder(self, parents, config=None, timestamp=None,
713
def get_commit_builder(self, parents, config_stack=None, timestamp=None,
698
714
timezone=None, committer=None, revprops=None,
699
715
revision_id=None, lossy=False):
700
716
"""Obtain a CommitBuilder for this branch.
710
726
represented, when pushing to a foreign VCS
714
config = self.get_config()
729
if config_stack is None:
730
config_stack = self.get_config_stack()
716
return self.repository.get_commit_builder(self, parents, config,
732
return self.repository.get_commit_builder(self, parents, config_stack,
717
733
timestamp, timezone, committer, revprops, revision_id,
743
@deprecated_method(deprecated_in((2, 5, 0)))
727
744
def get_revision_delta(self, revno):
728
745
"""Return the delta for one revision.
730
747
The delta is relative to its mainline predecessor, or the
731
748
empty tree for revision 1.
733
rh = self.revision_history()
734
if not (1 <= revno <= len(rh)):
751
revid = self.get_rev_id(revno)
752
except errors.NoSuchRevision:
735
753
raise errors.InvalidRevisionNumber(revno)
736
return self.repository.get_revision_delta(rh[revno-1])
754
return self.repository.get_revision_delta(revid)
738
756
def get_stacked_on_url(self):
739
757
"""Get the URL this branch is stacked against.
785
803
other_branch=None):
786
804
"""See Branch.generate_revision_history"""
787
805
graph = self.repository.get_graph()
806
(last_revno, last_revid) = self.last_revision_info()
788
807
known_revision_ids = [
789
self.last_revision_info(),
808
(last_revid, last_revno),
790
809
(_mod_revision.NULL_REVISION, 0),
792
811
if last_rev is not None:
869
889
# stream from one of them to the other. This does mean doing
870
890
# separate SSH connection setup, but unstacking is not a
871
891
# common operation so it's tolerable.
872
new_bzrdir = bzrdir.BzrDir.open(self.bzrdir.root_transport.base)
892
new_bzrdir = controldir.ControlDir.open(
893
self.bzrdir.root_transport.base)
873
894
new_repository = new_bzrdir.find_repository()
874
895
if new_repository._fallback_repositories:
875
896
raise AssertionError("didn't expect %r to have "
918
939
tags_to_fetch = set(self.tags.get_reverse_tag_dict())
919
940
except errors.TagsNotSupported:
920
941
tags_to_fetch = set()
921
fetch_spec = _mod_graph.NotInOtherForRevs(self.repository,
942
fetch_spec = vf_search.NotInOtherForRevs(self.repository,
922
943
old_repository, required_ids=[self.last_revision()],
923
944
if_present_ids=tags_to_fetch, find_ghosts=True).execute()
924
945
self.repository.fetch(old_repository, fetch_spec=fetch_spec)
1145
1170
def _set_config_location(self, name, url, config=None,
1146
1171
make_relative=False):
1147
1172
if config is None:
1148
config = self.get_config()
1173
config = self.get_config_stack()
1149
1174
if url is None:
1151
1176
elif make_relative:
1152
1177
url = urlutils.relative_url(self.base, url)
1153
config.set_user_option(name, url, warn_masked=True)
1178
config.set(name, url)
1155
1180
def _get_config_location(self, name, config=None):
1156
1181
if config is None:
1157
config = self.get_config()
1158
location = config.get_user_option(name)
1182
config = self.get_config_stack()
1183
location = config.get(name)
1159
1184
if location == '':
1160
1185
location = None
1161
1186
return location
1163
1188
def get_child_submit_format(self):
1164
1189
"""Return the preferred format of submissions to this branch."""
1165
return self.get_config().get_user_option("child_submit_format")
1190
return self.get_config_stack().get('child_submit_format')
1167
1192
def get_submit_branch(self):
1168
1193
"""Return the submit location of the branch.
1200
1224
self._set_config_location('public_branch', location)
1202
1226
def get_push_location(self):
1203
"""Return the None or the location to push this branch to."""
1204
push_loc = self.get_config().get_user_option('push_location')
1227
"""Return None or the location to push this branch to."""
1228
return self.get_config_stack().get('push_location')
1207
1230
def set_push_location(self, location):
1208
1231
"""Set a new push location for this branch."""
1293
1316
if repository_policy is not None:
1294
1317
repository_policy.configure_branch(result)
1295
1318
self.copy_content_into(result, revision_id=revision_id)
1296
master_branch = self.get_master_branch()
1297
if master_branch is None:
1319
master_url = self.get_bound_location()
1320
if master_url is None:
1298
1321
result.set_parent(self.bzrdir.root_transport.base)
1300
result.set_parent(master_branch.bzrdir.root_transport.base)
1323
result.set_parent(master_url)
1302
1325
result.unlock()
1377
1400
# TODO: We should probably also check that self.revision_history
1378
1401
# matches the repository for older branch formats.
1379
1402
# If looking for the code that cross-checks repository parents against
1380
# the iter_reverse_revision_history output, that is now a repository
1403
# the Graph.iter_lefthand_ancestry output, that is now a repository
1381
1404
# specific check.
1384
def _get_checkout_format(self):
1407
def _get_checkout_format(self, lightweight=False):
1385
1408
"""Return the most suitable metadir for a checkout of this branch.
1386
1409
Weaves are used if this branch's repository uses weaves.
1434
1457
t = transport.get_transport(to_location)
1435
1458
t.ensure_base()
1459
format = self._get_checkout_format(lightweight=lightweight)
1461
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
1436
1477
if lightweight:
1437
format = self._get_checkout_format()
1438
checkout = format.initialize_on_transport(t)
1439
from_branch = BranchReferenceFormat().initialize(checkout,
1478
from_branch = checkout.set_branch_reference(target_branch=self)
1442
format = self._get_checkout_format()
1443
checkout_branch = bzrdir.BzrDir.create_branch_convenience(
1444
to_location, force_new_tree=False, format=format)
1445
checkout = checkout_branch.bzrdir
1480
policy = checkout.determine_repository_policy()
1481
repo = policy.acquire_repository()[0]
1482
checkout_branch = checkout.create_branch()
1446
1483
checkout_branch.bind(self)
1447
1484
# pull up to the specified revision_id to set the initial
1448
1485
# branch tip correctly, and seed it with history.
1449
1486
checkout_branch.pull(self, stop_revision=revision_id)
1451
1488
tree = checkout.create_workingtree(revision_id,
1452
1489
from_branch=from_branch,
1453
1490
accelerator_tree=accelerator_tree,
1542
1579
heads that must be fetched if present, but no error is necessary if
1543
1580
they are not present.
1545
# For bzr native formats must_fetch is just the tip, and if_present_fetch
1582
# For bzr native formats must_fetch is just the tip, and
1583
# if_present_fetch are the tags.
1547
1584
must_fetch = set([self.last_revision()])
1549
if_present_fetch = set(self.tags.get_reverse_tag_dict())
1550
except errors.TagsNotSupported:
1551
if_present_fetch = set()
1585
if_present_fetch = set()
1586
if self.get_config_stack().get('branch.fetch_tags'):
1588
if_present_fetch = set(self.tags.get_reverse_tag_dict())
1589
except errors.TagsNotSupported:
1552
1591
must_fetch.discard(_mod_revision.NULL_REVISION)
1553
1592
if_present_fetch.discard(_mod_revision.NULL_REVISION)
1554
1593
return must_fetch, if_present_fetch
1581
1618
return not (self == other)
1584
def find_format(klass, a_bzrdir, name=None):
1585
"""Return the format for the branch object in a_bzrdir."""
1587
transport = a_bzrdir.get_branch_transport(None, name=name)
1588
format_string = transport.get_bytes("format")
1589
return format_registry.get(format_string)
1590
except errors.NoSuchFile:
1591
raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)
1593
raise errors.UnknownFormatError(format=format_string, kind='branch')
1596
1621
@deprecated_method(deprecated_in((2, 4, 0)))
1597
1622
def get_default_format(klass):
1598
1623
"""Return the current default format."""
1609
1634
return format_registry._get_all()
1611
def get_reference(self, a_bzrdir, name=None):
1612
"""Get the target reference of the branch in a_bzrdir.
1636
def get_reference(self, controldir, name=None):
1637
"""Get the target reference of the branch in controldir.
1614
1639
format probing must have been completed before calling
1615
1640
this method - it is assumed that the format of the branch
1616
in a_bzrdir is correct.
1641
in controldir is correct.
1618
:param a_bzrdir: The bzrdir to get the branch data from.
1643
:param controldir: The controldir to get the branch data from.
1619
1644
:param name: Name of the colocated branch to fetch
1620
1645
:return: None if the branch is not a reference branch.
1625
def set_reference(self, a_bzrdir, name, to_branch):
1626
"""Set the target reference of the branch in a_bzrdir.
1650
def set_reference(self, controldir, name, to_branch):
1651
"""Set the target reference of the branch in controldir.
1628
1653
format probing must have been completed before calling
1629
1654
this method - it is assumed that the format of the branch
1630
in a_bzrdir is correct.
1655
in controldir is correct.
1632
:param a_bzrdir: The bzrdir to set the branch reference for.
1657
:param controldir: The controldir to set the branch reference for.
1633
1658
:param name: Name of colocated branch to set, None for default
1634
1659
:param to_branch: branch that the checkout is to reference
1636
1661
raise NotImplementedError(self.set_reference)
1638
def get_format_string(self):
1639
"""Return the ASCII format string that identifies this format."""
1640
raise NotImplementedError(self.get_format_string)
1642
1663
def get_format_description(self):
1643
1664
"""Return the short format description for this format."""
1644
1665
raise NotImplementedError(self.get_format_description)
1646
def _run_post_branch_init_hooks(self, a_bzrdir, name, branch):
1667
def _run_post_branch_init_hooks(self, controldir, name, branch):
1647
1668
hooks = Branch.hooks['post_branch_init']
1650
params = BranchInitHookParams(self, a_bzrdir, name, branch)
1671
params = BranchInitHookParams(self, controldir, name, branch)
1651
1672
for hook in hooks:
1654
def initialize(self, a_bzrdir, name=None, repository=None):
1655
"""Create a branch of this format in a_bzrdir.
1675
def initialize(self, controldir, name=None, repository=None,
1676
append_revisions_only=None):
1677
"""Create a branch of this format in controldir.
1657
1679
:param name: Name of the colocated branch to create.
1659
1681
raise NotImplementedError(self.initialize)
1692
1714
raise NotImplementedError(self.network_name)
1694
def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False,
1695
found_repository=None):
1696
"""Return the branch object for a_bzrdir
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.
1698
:param a_bzrdir: A BzrDir that contains a branch.
1720
:param controldir: A ControlDir that contains a branch.
1699
1721
:param name: Name of colocated branch to open
1700
1722
:param _found: a private parameter, do not use it. It is used to
1701
1723
indicate if format probing has already be done.
1743
1765
"""True if this format supports tags stored in the branch"""
1744
1766
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."""
1747
1777
class MetaDirBranchFormatFactory(registry._LazyObjectGetter):
1748
1778
"""A factory for a BranchFormat object, permitting simple lazy registration.
1922
1952
branch, which refer to the original branch.
1925
def __init__(self, format, a_bzrdir, name, branch):
1955
def __init__(self, format, controldir, name, branch):
1926
1956
"""Create a group of BranchInitHook parameters.
1928
1958
:param format: the branch format
1929
:param a_bzrdir: the BzrDir where the branch will be/has been
1959
:param controldir: the ControlDir where the branch will be/has been
1931
1961
:param name: name of colocated branch, if any (or None)
1932
1962
:param branch: the branch created
1961
1991
def __init__(self, control_dir, to_branch, force, revision_id):
1962
1992
"""Create a group of SwitchHook parameters.
1964
:param control_dir: BzrDir of the checkout to change
1994
:param control_dir: ControlDir of the checkout to change
1965
1995
:param to_branch: branch that the checkout is to reference
1966
1996
:param force: skip the check for local commits in a heavy checkout
1967
1997
:param revision_id: revision ID to switch to (or None)
1980
2010
self.revision_id)
1983
class BranchFormatMetadir(BranchFormat):
1984
"""Common logic for meta-dir based branch formats."""
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)
1986
2034
def _branch_class(self):
1987
2035
"""What class to instantiate on open calls."""
1988
2036
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.
1990
2046
def _initialize_helper(self, a_bzrdir, utf8_files, name=None,
1991
2047
repository=None):
1992
"""Initialize a branch in a bzrdir, with specified files
2048
"""Initialize a branch in a control dir, with specified files
1994
2050
:param a_bzrdir: The bzrdir to initialize the branch in
1995
2051
:param utf8_files: The files to create as a list of
1997
2053
:param name: Name of colocated branch to create, if any
1998
2054
:return: a branch in this format
2057
name = a_bzrdir._get_selected_branch()
2000
2058
mutter('creating branch %r in %s', self, a_bzrdir.user_url)
2001
2059
branch_transport = a_bzrdir.get_branch_transport(self, name=name)
2002
2060
control_files = lockable_files.LockableFiles(branch_transport,
2016
2074
self._run_post_branch_init_hooks(a_bzrdir, name, branch)
2019
def network_name(self):
2020
"""A simple byte string uniquely identifying this format for RPC calls.
2022
Metadir branch formats use their format string.
2024
return self.get_format_string()
2026
2077
def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False,
2027
found_repository=None):
2078
found_repository=None, possible_transports=None):
2028
2079
"""See BranchFormat.open()."""
2081
name = a_bzrdir._get_selected_branch()
2030
format = BranchFormat.find_format(a_bzrdir, name=name)
2083
format = BranchFormatMetadir.find_format(a_bzrdir, name=name)
2031
2084
if format.__class__ != self.__class__:
2032
2085
raise AssertionError("wrong format %r found for %r" %
2033
2086
(format, self))
2043
2096
a_bzrdir=a_bzrdir,
2044
2097
_repository=found_repository,
2045
ignore_fallbacks=ignore_fallbacks)
2098
ignore_fallbacks=ignore_fallbacks,
2099
possible_transports=possible_transports)
2046
2100
except errors.NoSuchFile:
2047
2101
raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)
2050
super(BranchFormatMetadir, self).__init__()
2051
self._matchingbzrdir = bzrdir.BzrDirMetaFormat1()
2052
self._matchingbzrdir.set_branch_format(self)
2104
def _matchingbzrdir(self):
2105
ret = bzrdir.BzrDirMetaFormat1()
2106
ret.set_branch_format(self)
2054
2109
def supports_tags(self):
2057
2112
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)
2061
2124
class BzrBranchFormat5(BranchFormatMetadir):
2062
2125
"""Bzr branch format 5.
2082
2146
"""See BranchFormat.get_format_description()."""
2083
2147
return "Branch format 5"
2085
def initialize(self, a_bzrdir, name=None, repository=None):
2149
def initialize(self, a_bzrdir, name=None, repository=None,
2150
append_revisions_only=None):
2086
2151
"""Create a branch of this format in a_bzrdir."""
2152
if append_revisions_only:
2153
raise errors.UpgradeRequired(a_bzrdir.user_url)
2087
2154
utf8_files = [('revision-history', ''),
2088
2155
('branch-name', ''),
2115
2183
"""See BranchFormat.get_format_description()."""
2116
2184
return "Branch format 6"
2118
def initialize(self, a_bzrdir, name=None, repository=None):
2186
def initialize(self, a_bzrdir, name=None, repository=None,
2187
append_revisions_only=None):
2119
2188
"""Create a branch of this format in a_bzrdir."""
2120
2189
utf8_files = [('last-revision', '0 null:\n'),
2121
('branch.conf', ''),
2191
self._get_initial_config(append_revisions_only)),
2124
2194
return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
2126
2196
def make_tags(self, branch):
2127
2197
"""See bzrlib.branch.BranchFormat.make_tags()."""
2128
return BasicTags(branch)
2198
return _mod_tag.BasicTags(branch)
2130
2200
def supports_set_append_revisions_only(self):
2145
2216
"""See BranchFormat.get_format_description()."""
2146
2217
return "Branch format 8"
2148
def initialize(self, a_bzrdir, name=None, repository=None):
2219
def initialize(self, a_bzrdir, name=None, repository=None,
2220
append_revisions_only=None):
2149
2221
"""Create a branch of this format in a_bzrdir."""
2150
2222
utf8_files = [('last-revision', '0 null:\n'),
2151
('branch.conf', ''),
2224
self._get_initial_config(append_revisions_only)),
2153
2226
('references', '')
2176
2249
This format was introduced in bzr 1.6.
2179
def initialize(self, a_bzrdir, name=None, repository=None):
2252
def initialize(self, a_bzrdir, name=None, repository=None,
2253
append_revisions_only=None):
2180
2254
"""Create a branch of this format in a_bzrdir."""
2181
2255
utf8_files = [('last-revision', '0 null:\n'),
2182
('branch.conf', ''),
2257
self._get_initial_config(append_revisions_only)),
2185
2260
return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
2204
2280
def make_tags(self, branch):
2205
2281
"""See bzrlib.branch.BranchFormat.make_tags()."""
2206
return BasicTags(branch)
2282
return _mod_tag.BasicTags(branch)
2208
2284
supports_reference_locations = False
2211
class BranchReferenceFormat(BranchFormat):
2287
class BranchReferenceFormat(BranchFormatMetadir):
2212
2288
"""Bzr branch reference format.
2214
2290
Branch references are used in implementing checkouts, they
2238
2315
location = transport.put_bytes('location', to_branch.base)
2240
2317
def initialize(self, a_bzrdir, name=None, target_branch=None,
2318
repository=None, append_revisions_only=None):
2242
2319
"""Create a branch of this format in a_bzrdir."""
2243
2320
if target_branch is None:
2244
2321
# this format does not implement branch itself, thus the implicit
2245
2322
# creation contract must see it as uninitializable
2246
2323
raise errors.UninitializableFormat(self)
2247
2324
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()
2248
2329
branch_transport = a_bzrdir.get_branch_transport(self, name=name)
2249
2330
branch_transport.put_bytes('location',
2250
target_branch.bzrdir.user_url)
2251
branch_transport.put_bytes('format', self.get_format_string())
2253
a_bzrdir, name, _found=True,
2331
target_branch.user_url)
2332
branch_transport.put_bytes('format', self.as_string())
2333
branch = self.open(a_bzrdir, name, _found=True,
2254
2334
possible_transports=[target_branch.bzrdir.root_transport])
2255
2335
self._run_post_branch_init_hooks(a_bzrdir, name, branch)
2259
super(BranchReferenceFormat, self).__init__()
2260
self._matchingbzrdir = bzrdir.BzrDirMetaFormat1()
2261
self._matchingbzrdir.set_branch_format(self)
2263
2338
def _make_reference_clone_function(format, a_branch):
2264
2339
"""Create a clone() routine for a branch dynamically."""
2265
2340
def clone(to_bzrdir, revision_id=None,
2288
2363
:param possible_transports: An optional reusable transports list.
2366
name = a_bzrdir._get_selected_branch()
2291
format = BranchFormat.find_format(a_bzrdir, name=name)
2368
format = BranchFormatMetadir.find_format(a_bzrdir, name=name)
2292
2369
if format.__class__ != self.__class__:
2293
2370
raise AssertionError("wrong format %r found for %r" %
2294
2371
(format, self))
2295
2372
if location is None:
2296
2373
location = self.get_reference(a_bzrdir, name)
2297
real_bzrdir = bzrdir.BzrDir.open(
2374
real_bzrdir = controldir.ControlDir.open(
2298
2375
location, possible_transports=possible_transports)
2299
result = real_bzrdir.open_branch(name=name,
2300
ignore_fallbacks=ignore_fallbacks)
2376
result = real_bzrdir.open_branch(ignore_fallbacks=ignore_fallbacks,
2377
possible_transports=possible_transports)
2301
2378
# this changes the behaviour of result.clone to create a new reference
2302
2379
# rather than a copy of the content of the branch.
2303
2380
# I did not use a proxy object because that needs much more extensive
2385
2462
def __init__(self, _format=None,
2386
2463
_control_files=None, a_bzrdir=None, name=None,
2387
_repository=None, ignore_fallbacks=False):
2464
_repository=None, ignore_fallbacks=False,
2465
possible_transports=None):
2388
2466
"""Create new branch object at a particular location."""
2389
2467
if a_bzrdir is None:
2390
2468
raise ValueError('a_bzrdir must be supplied')
2392
self.bzrdir = a_bzrdir
2393
self._base = self.bzrdir.transport.clone('..').base
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
2394
2477
self.name = name
2395
# XXX: We should be able to just do
2396
# self.base = self.bzrdir.root_transport.base
2397
# but this does not quite work yet -- mbp 20080522
2398
2478
self._format = _format
2399
2479
if _control_files is None:
2400
2480
raise ValueError('BzrBranch _control_files is None')
2401
2481
self.control_files = _control_files
2402
2482
self._transport = _control_files._transport
2403
2483
self.repository = _repository
2404
Branch.__init__(self)
2484
self.conf_store = None
2485
Branch.__init__(self, possible_transports)
2406
2487
def __str__(self):
2407
if self.name is None:
2408
return '%s(%s)' % (self.__class__.__name__, self.user_url)
2410
return '%s(%s,%s)' % (self.__class__.__name__, self.user_url,
2488
return '%s(%s)' % (self.__class__.__name__, self.user_url)
2413
2490
__repr__ = __str__
2419
2496
base = property(_get_base, doc="The URL for the root of this branch.")
2499
def user_transport(self):
2500
return self._user_transport
2421
2502
def _get_config(self):
2422
return TransportConfig(self._transport, 'branch.conf')
2503
return _mod_config.TransportConfig(self._transport, 'branch.conf')
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
2424
2510
def is_locked(self):
2425
2511
return self.control_files.is_locked()
2506
2594
raise errors.InvalidRevisionId(revision_id=revision_id, branch=self)
2507
2595
revision_id = _mod_revision.ensure_null(revision_id)
2508
2596
old_revno, old_revid = self.last_revision_info()
2509
if self._get_append_revisions_only():
2597
if self.get_append_revisions_only():
2510
2598
self._check_history_violation(revision_id)
2511
2599
self._run_pre_change_branch_tip_hooks(revno, revision_id)
2512
2600
self._write_last_revision_info(revno, revision_id)
2655
2743
self._transport.put_bytes('last-revision', out_string,
2656
2744
mode=self.bzrdir._get_file_mode())
2747
def update_feature_flags(self, updated_flags):
2748
"""Update the feature flags for this branch.
2750
:param updated_flags: Dictionary mapping feature names to necessities
2751
A necessity can be None to indicate the feature should be removed
2753
self._format._update_feature_flags(updated_flags)
2754
self.control_transport.put_bytes('format', self._format.as_string())
2659
2757
class FullHistoryBzrBranch(BzrBranch):
2660
2758
"""Bzr branch which contains the full revision history."""
2767
2865
class BzrBranch8(BzrBranch):
2768
2866
"""A branch that stores tree-reference locations."""
2770
def _open_hook(self):
2868
def _open_hook(self, possible_transports=None):
2771
2869
if self._ignore_fallbacks:
2871
if possible_transports is None:
2872
possible_transports = [self.bzrdir.root_transport]
2774
2874
url = self.get_stacked_on_url()
2775
2875
except (errors.UnstackableRepositoryFormat, errors.NotStacked,
2783
2883
raise AssertionError(
2784
2884
"'transform_fallback_location' hook %s returned "
2785
2885
"None, not a URL." % hook_name)
2786
self._activate_fallback_location(url)
2886
self._activate_fallback_location(url,
2887
possible_transports=possible_transports)
2788
2889
def __init__(self, *args, **kwargs):
2789
2890
self._ignore_fallbacks = kwargs.get('ignore_fallbacks', False)
2907
3008
"""See Branch.set_push_location."""
2908
3009
self._master_branch_cache = None
2910
config = self.get_config()
3011
conf = self.get_config_stack()
2911
3012
if location is None:
2912
if config.get_user_option('bound') != 'True':
3013
if not conf.get('bound'):
2915
config.set_user_option('bound', 'False', warn_masked=True)
3016
conf.set('bound', 'False')
2918
3019
self._set_config_location('bound_location', location,
2920
config.set_user_option('bound', 'True', warn_masked=True)
3021
conf.set('bound', 'True')
2923
3024
def _get_bound_location(self, bound):
2924
3025
"""Return the bound location in the config file.
2926
3027
Return None if the bound parameter does not match"""
2927
config = self.get_config()
2928
config_bound = (config.get_user_option('bound') == 'True')
2929
if config_bound != bound:
3028
conf = self.get_config_stack()
3029
if conf.get('bound') != bound:
2931
return self._get_config_location('bound_location', config=config)
3031
return self._get_config_location('bound_location', config=conf)
2933
3033
def get_bound_location(self):
2934
"""See Branch.set_push_location."""
3034
"""See Branch.get_bound_location."""
2935
3035
return self._get_bound_location(True)
2937
3037
def get_old_bound_location(self):
2944
3044
## self._check_stackable_repo()
2945
3045
# stacked_on_location is only ever defined in branch.conf, so don't
2946
3046
# waste effort reading the whole stack of config files.
2947
config = self.get_config()._get_branch_data_config()
3047
conf = _mod_config.BranchOnlyStack(self)
2948
3048
stacked_url = self._get_config_location('stacked_on_location',
2950
3050
if stacked_url is None:
2951
3051
raise errors.NotStacked(self)
2954
def _get_append_revisions_only(self):
2955
return self.get_config(
2956
).get_user_option_as_bool('append_revisions_only')
3052
return stacked_url.encode('utf-8')
2958
3054
@needs_read_lock
2959
3055
def get_rev_id(self, revno, history=None):
2989
3085
except errors.RevisionNotPresent, e:
2990
3086
raise errors.GhostRevisionsHaveNoRevno(revision_id, e.revision_id)
2991
3087
index = len(self._partial_revision_history_cache) - 1
3089
raise errors.NoSuchRevision(self, revision_id)
2992
3090
if self._partial_revision_history_cache[index] != revision_id:
2993
3091
raise errors.NoSuchRevision(self, revision_id)
2994
3092
return self.revno() - index
3046
3144
:ivar local_branch: target branch if there is a Master, else None
3047
3145
:ivar target_branch: Target/destination branch object. (write locked)
3048
3146
:ivar tag_conflicts: A list of tag conflicts, see BasicTags.merge_to
3147
:ivar tag_updates: A dict with new tags, see BasicTags.merge_to
3051
@deprecated_method(deprecated_in((2, 3, 0)))
3053
"""Return the relative change in revno.
3055
:deprecated: Use `new_revno` and `old_revno` instead.
3057
return self.new_revno - self.old_revno
3059
3150
def report(self, to_file):
3151
tag_conflicts = getattr(self, "tag_conflicts", None)
3152
tag_updates = getattr(self, "tag_updates", None)
3060
3153
if not is_quiet():
3061
if self.old_revid == self.new_revid:
3062
to_file.write('No revisions to pull.\n')
3154
if self.old_revid != self.new_revid:
3064
3155
to_file.write('Now on revision %d.\n' % self.new_revno)
3157
to_file.write('%d tag(s) updated.\n' % len(tag_updates))
3158
if self.old_revid == self.new_revid and not tag_updates:
3159
if not tag_conflicts:
3160
to_file.write('No revisions or tags to pull.\n')
3162
to_file.write('No revisions to pull.\n')
3065
3163
self._show_tag_conficts(to_file)
3084
3182
target, otherwise it will be None.
3087
@deprecated_method(deprecated_in((2, 3, 0)))
3089
"""Return the relative change in revno.
3091
:deprecated: Use `new_revno` and `old_revno` instead.
3093
return self.new_revno - self.old_revno
3095
3185
def report(self, to_file):
3096
"""Write a human-readable description of the result."""
3097
if self.old_revid == self.new_revid:
3098
note('No new revisions to push.')
3100
note('Pushed up to revision %d.' % self.new_revno)
3186
# TODO: This function gets passed a to_file, but then
3187
# ignores it and calls note() instead. This is also
3188
# inconsistent with PullResult(), which writes to stdout.
3189
# -- JRV20110901, bug #838853
3190
tag_conflicts = getattr(self, "tag_conflicts", None)
3191
tag_updates = getattr(self, "tag_updates", None)
3193
if self.old_revid != self.new_revid:
3194
note(gettext('Pushed up to revision %d.') % self.new_revno)
3196
note(ngettext('%d tag updated.', '%d tags updated.', len(tag_updates)) % len(tag_updates))
3197
if self.old_revid == self.new_revid and not tag_updates:
3198
if not tag_conflicts:
3199
note(gettext('No new revisions or tags to push.'))
3201
note(gettext('No new revisions to push.'))
3101
3202
self._show_tag_conficts(to_file)
3117
3218
:param verbose: Requests more detailed display of what was checked,
3120
note('checked branch %s format %s', self.branch.user_url,
3121
self.branch._format)
3221
note(gettext('checked branch {0} format {1}').format(
3222
self.branch.user_url, self.branch._format))
3122
3223
for error in self.errors:
3123
note('found error:%s', error)
3224
note(gettext('found error:%s'), error)
3126
3227
class Converter5to6(object):
3134
3235
# Copy source data into target
3135
3236
new_branch._write_last_revision_info(*branch.last_revision_info())
3136
new_branch.set_parent(branch.get_parent())
3137
new_branch.set_bound_location(branch.get_bound_location())
3138
new_branch.set_push_location(branch.get_push_location())
3237
new_branch.lock_write()
3239
new_branch.set_parent(branch.get_parent())
3240
new_branch.set_bound_location(branch.get_bound_location())
3241
new_branch.set_push_location(branch.get_push_location())
3140
3245
# New branch has no tags by default
3141
3246
new_branch.tags._set_tag_dict({})
3143
3248
# Copying done; now update target format
3144
3249
new_branch._transport.put_bytes('format',
3145
format.get_format_string(),
3146
3251
mode=new_branch.bzrdir._get_file_mode())
3148
3253
# Clean up old files
3149
3254
new_branch._transport.delete('revision-history')
3151
branch.set_parent(None)
3152
except errors.NoSuchFile:
3154
branch.set_bound_location(None)
3258
branch.set_parent(None)
3259
except errors.NoSuchFile:
3261
branch.set_bound_location(None)
3157
3266
class Converter6to7(object):
3161
3270
format = BzrBranchFormat7()
3162
3271
branch._set_config_location('stacked_on_location', '')
3163
3272
# update target format
3164
branch._transport.put_bytes('format', format.get_format_string())
3273
branch._transport.put_bytes('format', format.as_string())
3167
3276
class Converter7to8(object):
3168
"""Perform an in-place upgrade of format 6 to format 7"""
3277
"""Perform an in-place upgrade of format 7 to format 8"""
3170
3279
def convert(self, branch):
3171
3280
format = BzrBranchFormat8()
3172
3281
branch._transport.put_bytes('references', '')
3173
3282
# update target format
3174
branch._transport.put_bytes('format', format.get_format_string())
3283
branch._transport.put_bytes('format', format.as_string())
3177
3286
class InterBranch(InterObject):
3344
3453
if local and not bound_location:
3345
3454
raise errors.LocalRequiresBoundBranch()
3346
3455
master_branch = None
3347
source_is_master = (self.source.user_url == bound_location)
3456
source_is_master = False
3458
# bound_location comes from a config file, some care has to be
3459
# taken to relate it to source.user_url
3460
normalized = urlutils.normalize_url(bound_location)
3462
relpath = self.source.user_transport.relpath(normalized)
3463
source_is_master = (relpath == '')
3464
except (errors.PathNotChild, errors.InvalidURL):
3465
source_is_master = False
3348
3466
if not local and bound_location and not source_is_master:
3349
3467
# not pulling from master, so we need to update master.
3350
3468
master_branch = self.target.get_master_branch(possible_transports)
3402
3520
self._update_revisions(stop_revision, overwrite=overwrite,
3404
3522
if self.source._push_should_merge_tags():
3405
result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
3523
result.tag_updates, result.tag_conflicts = (
3524
self.source.tags.merge_to(self.target.tags, overwrite))
3407
3525
result.new_revno, result.new_revid = self.target.last_revision_info()
3492
3610
# TODO: The old revid should be specified when merging tags,
3493
3611
# so a tags implementation that versions tags can only
3494
3612
# pull in the most recent changes. -- JRV20090506
3495
result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
3496
overwrite, ignore_master=not merge_tags_to_master)
3613
result.tag_updates, result.tag_conflicts = (
3614
self.source.tags.merge_to(self.target.tags, overwrite,
3615
ignore_master=not merge_tags_to_master))
3497
3616
result.new_revno, result.new_revid = self.target.last_revision_info()
3498
3617
if _hook_master:
3499
3618
result.master_branch = _hook_master