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
513
527
rev_iter = iter(merge_sorted_revisions)
514
528
if start_revision_id is not None:
515
529
for node in rev_iter:
516
rev_id = node.key[-1]
517
531
if rev_id != start_revision_id:
520
534
# The decision to include the start or not
521
535
# depends on the stop_rule if a stop is provided
522
536
# so pop this node back into the iterator
523
rev_iter = chain(iter([node]), rev_iter)
537
rev_iter = itertools.chain(iter([node]), rev_iter)
525
539
if stop_revision_id is None:
526
540
# Yield everything
527
541
for node in rev_iter:
528
rev_id = node.key[-1]
529
543
yield (rev_id, node.merge_depth, node.revno,
530
544
node.end_of_merge)
531
545
elif stop_rule == 'exclude':
532
546
for node in rev_iter:
533
rev_id = node.key[-1]
534
548
if rev_id == stop_revision_id:
536
550
yield (rev_id, node.merge_depth, node.revno,
537
551
node.end_of_merge)
538
552
elif stop_rule == 'include':
539
553
for node in rev_iter:
540
rev_id = node.key[-1]
541
555
yield (rev_id, node.merge_depth, node.revno,
542
556
node.end_of_merge)
543
557
if rev_id == stop_revision_id:
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)
1436
1460
if lightweight:
1437
format = self._get_checkout_format()
1438
1461
checkout = format.initialize_on_transport(t)
1439
1462
from_branch = BranchReferenceFormat().initialize(checkout,
1440
1463
target_branch=self)
1442
format = self._get_checkout_format()
1443
checkout_branch = bzrdir.BzrDir.create_branch_convenience(
1465
checkout_branch = controldir.ControlDir.create_branch_convenience(
1444
1466
to_location, force_new_tree=False, format=format)
1445
1467
checkout = checkout_branch.bzrdir
1446
1468
checkout_branch.bind(self)
1542
1564
heads that must be fetched if present, but no error is necessary if
1543
1565
they are not present.
1545
# For bzr native formats must_fetch is just the tip, and if_present_fetch
1567
# For bzr native formats must_fetch is just the tip, and
1568
# if_present_fetch are the tags.
1547
1569
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()
1570
if_present_fetch = set()
1571
if self.get_config_stack().get('branch.fetch_tags'):
1573
if_present_fetch = set(self.tags.get_reverse_tag_dict())
1574
except errors.TagsNotSupported:
1552
1576
must_fetch.discard(_mod_revision.NULL_REVISION)
1553
1577
if_present_fetch.discard(_mod_revision.NULL_REVISION)
1554
1578
return must_fetch, if_present_fetch
1581
1603
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
1606
@deprecated_method(deprecated_in((2, 4, 0)))
1597
1607
def get_default_format(klass):
1598
1608
"""Return the current default format."""
1609
1619
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.
1621
def get_reference(self, controldir, name=None):
1622
"""Get the target reference of the branch in controldir.
1614
1624
format probing must have been completed before calling
1615
1625
this method - it is assumed that the format of the branch
1616
in a_bzrdir is correct.
1626
in controldir is correct.
1618
:param a_bzrdir: The bzrdir to get the branch data from.
1628
:param controldir: The controldir to get the branch data from.
1619
1629
:param name: Name of the colocated branch to fetch
1620
1630
: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.
1635
def set_reference(self, controldir, name, to_branch):
1636
"""Set the target reference of the branch in controldir.
1628
1638
format probing must have been completed before calling
1629
1639
this method - it is assumed that the format of the branch
1630
in a_bzrdir is correct.
1640
in controldir is correct.
1632
:param a_bzrdir: The bzrdir to set the branch reference for.
1642
:param controldir: The controldir to set the branch reference for.
1633
1643
:param name: Name of colocated branch to set, None for default
1634
1644
:param to_branch: branch that the checkout is to reference
1636
1646
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
1648
def get_format_description(self):
1643
1649
"""Return the short format description for this format."""
1644
1650
raise NotImplementedError(self.get_format_description)
1646
def _run_post_branch_init_hooks(self, a_bzrdir, name, branch):
1652
def _run_post_branch_init_hooks(self, controldir, name, branch):
1647
1653
hooks = Branch.hooks['post_branch_init']
1650
params = BranchInitHookParams(self, a_bzrdir, name, branch)
1656
params = BranchInitHookParams(self, controldir, name, branch)
1651
1657
for hook in hooks:
1654
def initialize(self, a_bzrdir, name=None, repository=None):
1655
"""Create a branch of this format in a_bzrdir.
1660
def initialize(self, controldir, name=None, repository=None,
1661
append_revisions_only=None):
1662
"""Create a branch of this format in controldir.
1657
1664
:param name: Name of the colocated branch to create.
1659
1666
raise NotImplementedError(self.initialize)
1692
1699
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
1701
def open(self, controldir, name=None, _found=False, ignore_fallbacks=False,
1702
found_repository=None, possible_transports=None):
1703
"""Return the branch object for controldir.
1698
:param a_bzrdir: A BzrDir that contains a branch.
1705
:param controldir: A ControlDir that contains a branch.
1699
1706
:param name: Name of colocated branch to open
1700
1707
:param _found: a private parameter, do not use it. It is used to
1701
1708
indicate if format probing has already be done.
1743
1750
"""True if this format supports tags stored in the branch"""
1744
1751
return False # by default
1753
def tags_are_versioned(self):
1754
"""Whether the tag container for this branch versions tags."""
1757
def supports_tags_referencing_ghosts(self):
1758
"""True if tags can reference ghost revisions."""
1747
1762
class MetaDirBranchFormatFactory(registry._LazyObjectGetter):
1748
1763
"""A factory for a BranchFormat object, permitting simple lazy registration.
1922
1937
branch, which refer to the original branch.
1925
def __init__(self, format, a_bzrdir, name, branch):
1940
def __init__(self, format, controldir, name, branch):
1926
1941
"""Create a group of BranchInitHook parameters.
1928
1943
:param format: the branch format
1929
:param a_bzrdir: the BzrDir where the branch will be/has been
1944
:param controldir: the ControlDir where the branch will be/has been
1931
1946
:param name: name of colocated branch, if any (or None)
1932
1947
:param branch: the branch created
1961
1976
def __init__(self, control_dir, to_branch, force, revision_id):
1962
1977
"""Create a group of SwitchHook parameters.
1964
:param control_dir: BzrDir of the checkout to change
1979
:param control_dir: ControlDir of the checkout to change
1965
1980
:param to_branch: branch that the checkout is to reference
1966
1981
:param force: skip the check for local commits in a heavy checkout
1967
1982
:param revision_id: revision ID to switch to (or None)
1980
1995
self.revision_id)
1983
class BranchFormatMetadir(BranchFormat):
1984
"""Common logic for meta-dir based branch formats."""
1998
class BranchFormatMetadir(bzrdir.BzrFormat, BranchFormat):
1999
"""Base class for branch formats that live in meta directories.
2003
BranchFormat.__init__(self)
2004
bzrdir.BzrFormat.__init__(self)
2007
def find_format(klass, controldir, name=None):
2008
"""Return the format for the branch object in controldir."""
2010
transport = controldir.get_branch_transport(None, name=name)
2011
except errors.NoSuchFile:
2012
raise errors.NotBranchError(path=name, bzrdir=controldir)
2014
format_string = transport.get_bytes("format")
2015
except errors.NoSuchFile:
2016
raise errors.NotBranchError(path=transport.base, bzrdir=controldir)
2017
return klass._find_format(format_registry, 'branch', format_string)
1986
2019
def _branch_class(self):
1987
2020
"""What class to instantiate on open calls."""
1988
2021
raise NotImplementedError(self._branch_class)
2023
def _get_initial_config(self, append_revisions_only=None):
2024
if append_revisions_only:
2025
return "append_revisions_only = True\n"
2027
# Avoid writing anything if append_revisions_only is disabled,
2028
# as that is the default.
1990
2031
def _initialize_helper(self, a_bzrdir, utf8_files, name=None,
1991
2032
repository=None):
1992
2033
"""Initialize a branch in a bzrdir, with specified files
2016
2057
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
2060
def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False,
2027
found_repository=None):
2061
found_repository=None, possible_transports=None):
2028
2062
"""See BranchFormat.open()."""
2030
format = BranchFormat.find_format(a_bzrdir, name=name)
2064
format = BranchFormatMetadir.find_format(a_bzrdir, name=name)
2031
2065
if format.__class__ != self.__class__:
2032
2066
raise AssertionError("wrong format %r found for %r" %
2033
2067
(format, self))
2043
2077
a_bzrdir=a_bzrdir,
2044
2078
_repository=found_repository,
2045
ignore_fallbacks=ignore_fallbacks)
2079
ignore_fallbacks=ignore_fallbacks,
2080
possible_transports=possible_transports)
2046
2081
except errors.NoSuchFile:
2047
2082
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)
2085
def _matchingbzrdir(self):
2086
ret = bzrdir.BzrDirMetaFormat1()
2087
ret.set_branch_format(self)
2054
2090
def supports_tags(self):
2057
2093
def supports_leaving_lock(self):
2096
def check_support_status(self, allow_unsupported, recommend_upgrade=True,
2098
BranchFormat.check_support_status(self,
2099
allow_unsupported=allow_unsupported, recommend_upgrade=recommend_upgrade,
2101
bzrdir.BzrFormat.check_support_status(self, allow_unsupported=allow_unsupported,
2102
recommend_upgrade=recommend_upgrade, basedir=basedir)
2061
2105
class BzrBranchFormat5(BranchFormatMetadir):
2062
2106
"""Bzr branch format 5.
2082
2127
"""See BranchFormat.get_format_description()."""
2083
2128
return "Branch format 5"
2085
def initialize(self, a_bzrdir, name=None, repository=None):
2130
def initialize(self, a_bzrdir, name=None, repository=None,
2131
append_revisions_only=None):
2086
2132
"""Create a branch of this format in a_bzrdir."""
2133
if append_revisions_only:
2134
raise errors.UpgradeRequired(a_bzrdir.user_url)
2087
2135
utf8_files = [('revision-history', ''),
2088
2136
('branch-name', ''),
2115
2164
"""See BranchFormat.get_format_description()."""
2116
2165
return "Branch format 6"
2118
def initialize(self, a_bzrdir, name=None, repository=None):
2167
def initialize(self, a_bzrdir, name=None, repository=None,
2168
append_revisions_only=None):
2119
2169
"""Create a branch of this format in a_bzrdir."""
2120
2170
utf8_files = [('last-revision', '0 null:\n'),
2121
('branch.conf', ''),
2172
self._get_initial_config(append_revisions_only)),
2124
2175
return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
2126
2177
def make_tags(self, branch):
2127
2178
"""See bzrlib.branch.BranchFormat.make_tags()."""
2128
return BasicTags(branch)
2179
return _mod_tag.BasicTags(branch)
2130
2181
def supports_set_append_revisions_only(self):
2145
2197
"""See BranchFormat.get_format_description()."""
2146
2198
return "Branch format 8"
2148
def initialize(self, a_bzrdir, name=None, repository=None):
2200
def initialize(self, a_bzrdir, name=None, repository=None,
2201
append_revisions_only=None):
2149
2202
"""Create a branch of this format in a_bzrdir."""
2150
2203
utf8_files = [('last-revision', '0 null:\n'),
2151
('branch.conf', ''),
2205
self._get_initial_config(append_revisions_only)),
2153
2207
('references', '')
2176
2230
This format was introduced in bzr 1.6.
2179
def initialize(self, a_bzrdir, name=None, repository=None):
2233
def initialize(self, a_bzrdir, name=None, repository=None,
2234
append_revisions_only=None):
2180
2235
"""Create a branch of this format in a_bzrdir."""
2181
2236
utf8_files = [('last-revision', '0 null:\n'),
2182
('branch.conf', ''),
2238
self._get_initial_config(append_revisions_only)),
2185
2241
return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
2204
2261
def make_tags(self, branch):
2205
2262
"""See bzrlib.branch.BranchFormat.make_tags()."""
2206
return BasicTags(branch)
2263
return _mod_tag.BasicTags(branch)
2208
2265
supports_reference_locations = False
2211
class BranchReferenceFormat(BranchFormat):
2268
class BranchReferenceFormat(BranchFormatMetadir):
2212
2269
"""Bzr branch reference format.
2214
2271
Branch references are used in implementing checkouts, they
2238
2296
location = transport.put_bytes('location', to_branch.base)
2240
2298
def initialize(self, a_bzrdir, name=None, target_branch=None,
2299
repository=None, append_revisions_only=None):
2242
2300
"""Create a branch of this format in a_bzrdir."""
2243
2301
if target_branch is None:
2244
2302
# this format does not implement branch itself, thus the implicit
2245
2303
# creation contract must see it as uninitializable
2246
2304
raise errors.UninitializableFormat(self)
2247
2305
mutter('creating branch reference in %s', a_bzrdir.user_url)
2306
if a_bzrdir._format.fixed_components:
2307
raise errors.IncompatibleFormat(self, a_bzrdir._format)
2248
2308
branch_transport = a_bzrdir.get_branch_transport(self, name=name)
2249
2309
branch_transport.put_bytes('location',
2250
target_branch.bzrdir.user_url)
2251
branch_transport.put_bytes('format', self.get_format_string())
2310
target_branch.user_url)
2311
branch_transport.put_bytes('format', self.as_string())
2252
2312
branch = self.open(
2253
2313
a_bzrdir, name, _found=True,
2254
2314
possible_transports=[target_branch.bzrdir.root_transport])
2255
2315
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
2318
def _make_reference_clone_function(format, a_branch):
2264
2319
"""Create a clone() routine for a branch dynamically."""
2265
2320
def clone(to_bzrdir, revision_id=None,
2288
2343
:param possible_transports: An optional reusable transports list.
2291
format = BranchFormat.find_format(a_bzrdir, name=name)
2346
format = BranchFormatMetadir.find_format(a_bzrdir, name=name)
2292
2347
if format.__class__ != self.__class__:
2293
2348
raise AssertionError("wrong format %r found for %r" %
2294
2349
(format, self))
2295
2350
if location is None:
2296
2351
location = self.get_reference(a_bzrdir, name)
2297
real_bzrdir = bzrdir.BzrDir.open(
2352
real_bzrdir = controldir.ControlDir.open(
2298
2353
location, possible_transports=possible_transports)
2299
2354
result = real_bzrdir.open_branch(name=name,
2300
ignore_fallbacks=ignore_fallbacks)
2355
ignore_fallbacks=ignore_fallbacks,
2356
possible_transports=possible_transports)
2301
2357
# this changes the behaviour of result.clone to create a new reference
2302
2358
# rather than a copy of the content of the branch.
2303
2359
# I did not use a proxy object because that needs much more extensive
2385
2441
def __init__(self, _format=None,
2386
2442
_control_files=None, a_bzrdir=None, name=None,
2387
_repository=None, ignore_fallbacks=False):
2443
_repository=None, ignore_fallbacks=False,
2444
possible_transports=None):
2388
2445
"""Create new branch object at a particular location."""
2389
2446
if a_bzrdir is None:
2390
2447
raise ValueError('a_bzrdir must be supplied')
2392
2449
self.bzrdir = a_bzrdir
2393
self._base = self.bzrdir.transport.clone('..').base
2450
self._user_transport = self.bzrdir.transport.clone('..')
2451
if name is not None:
2452
self._user_transport.set_segment_parameter(
2453
"branch", urlutils.escape(name))
2454
self._base = self._user_transport.base
2394
2455
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
2456
self._format = _format
2399
2457
if _control_files is None:
2400
2458
raise ValueError('BzrBranch _control_files is None')
2401
2459
self.control_files = _control_files
2402
2460
self._transport = _control_files._transport
2403
2461
self.repository = _repository
2404
Branch.__init__(self)
2462
Branch.__init__(self, possible_transports)
2406
2464
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,
2465
return '%s(%s)' % (self.__class__.__name__, self.user_url)
2413
2467
__repr__ = __str__
2419
2473
base = property(_get_base, doc="The URL for the root of this branch.")
2476
def user_transport(self):
2477
return self._user_transport
2421
2479
def _get_config(self):
2422
return TransportConfig(self._transport, 'branch.conf')
2480
return _mod_config.TransportConfig(self._transport, 'branch.conf')
2482
def _get_config_store(self):
2483
return _mod_config.BranchStore(self)
2424
2485
def is_locked(self):
2425
2486
return self.control_files.is_locked()
2506
2567
raise errors.InvalidRevisionId(revision_id=revision_id, branch=self)
2507
2568
revision_id = _mod_revision.ensure_null(revision_id)
2508
2569
old_revno, old_revid = self.last_revision_info()
2509
if self._get_append_revisions_only():
2570
if self.get_append_revisions_only():
2510
2571
self._check_history_violation(revision_id)
2511
2572
self._run_pre_change_branch_tip_hooks(revno, revision_id)
2512
2573
self._write_last_revision_info(revno, revision_id)
2655
2716
self._transport.put_bytes('last-revision', out_string,
2656
2717
mode=self.bzrdir._get_file_mode())
2720
def update_feature_flags(self, updated_flags):
2721
"""Update the feature flags for this branch.
2723
:param updated_flags: Dictionary mapping feature names to necessities
2724
A necessity can be None to indicate the feature should be removed
2726
self._format._update_feature_flags(updated_flags)
2727
self.control_transport.put_bytes('format', self._format.as_string())
2659
2730
class FullHistoryBzrBranch(BzrBranch):
2660
2731
"""Bzr branch which contains the full revision history."""
2767
2838
class BzrBranch8(BzrBranch):
2768
2839
"""A branch that stores tree-reference locations."""
2770
def _open_hook(self):
2841
def _open_hook(self, possible_transports=None):
2771
2842
if self._ignore_fallbacks:
2844
if possible_transports is None:
2845
possible_transports = [self.bzrdir.root_transport]
2774
2847
url = self.get_stacked_on_url()
2775
2848
except (errors.UnstackableRepositoryFormat, errors.NotStacked,
2783
2856
raise AssertionError(
2784
2857
"'transform_fallback_location' hook %s returned "
2785
2858
"None, not a URL." % hook_name)
2786
self._activate_fallback_location(url)
2859
self._activate_fallback_location(url,
2860
possible_transports=possible_transports)
2788
2862
def __init__(self, *args, **kwargs):
2789
2863
self._ignore_fallbacks = kwargs.get('ignore_fallbacks', False)
2907
2981
"""See Branch.set_push_location."""
2908
2982
self._master_branch_cache = None
2910
config = self.get_config()
2984
conf = self.get_config_stack()
2911
2985
if location is None:
2912
if config.get_user_option('bound') != 'True':
2986
if not conf.get('bound'):
2915
config.set_user_option('bound', 'False', warn_masked=True)
2989
conf.set('bound', 'False')
2918
2992
self._set_config_location('bound_location', location,
2920
config.set_user_option('bound', 'True', warn_masked=True)
2994
conf.set('bound', 'True')
2923
2997
def _get_bound_location(self, bound):
2924
2998
"""Return the bound location in the config file.
2926
3000
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:
3001
conf = self.get_config_stack()
3002
if conf.get('bound') != bound:
2931
return self._get_config_location('bound_location', config=config)
3004
return self._get_config_location('bound_location', config=conf)
2933
3006
def get_bound_location(self):
2934
"""See Branch.set_push_location."""
3007
"""See Branch.get_bound_location."""
2935
3008
return self._get_bound_location(True)
2937
3010
def get_old_bound_location(self):
2942
3015
# you can always ask for the URL; but you might not be able to use it
2943
3016
# if the repo can't support stacking.
2944
3017
## self._check_stackable_repo()
2945
stacked_url = self._get_config_location('stacked_on_location')
3018
# stacked_on_location is only ever defined in branch.conf, so don't
3019
# waste effort reading the whole stack of config files.
3020
conf = _mod_config.BranchOnlyStack(self)
3021
stacked_url = self._get_config_location('stacked_on_location',
2946
3023
if stacked_url is None:
2947
3024
raise errors.NotStacked(self)
2950
def _get_append_revisions_only(self):
2951
return self.get_config(
2952
).get_user_option_as_bool('append_revisions_only')
3025
return stacked_url.encode('utf-8')
2954
3027
@needs_read_lock
2955
3028
def get_rev_id(self, revno, history=None):
2985
3058
except errors.RevisionNotPresent, e:
2986
3059
raise errors.GhostRevisionsHaveNoRevno(revision_id, e.revision_id)
2987
3060
index = len(self._partial_revision_history_cache) - 1
3062
raise errors.NoSuchRevision(self, revision_id)
2988
3063
if self._partial_revision_history_cache[index] != revision_id:
2989
3064
raise errors.NoSuchRevision(self, revision_id)
2990
3065
return self.revno() - index
3053
3129
return self.new_revno - self.old_revno
3055
3131
def report(self, to_file):
3132
tag_conflicts = getattr(self, "tag_conflicts", None)
3133
tag_updates = getattr(self, "tag_updates", None)
3056
3134
if not is_quiet():
3057
if self.old_revid == self.new_revid:
3058
to_file.write('No revisions to pull.\n')
3135
if self.old_revid != self.new_revid:
3060
3136
to_file.write('Now on revision %d.\n' % self.new_revno)
3138
to_file.write('%d tag(s) updated.\n' % len(tag_updates))
3139
if self.old_revid == self.new_revid and not tag_updates:
3140
if not tag_conflicts:
3141
to_file.write('No revisions or tags to pull.\n')
3143
to_file.write('No revisions to pull.\n')
3061
3144
self._show_tag_conficts(to_file)
3089
3172
return self.new_revno - self.old_revno
3091
3174
def report(self, to_file):
3092
"""Write a human-readable description of the result."""
3093
if self.old_revid == self.new_revid:
3094
note('No new revisions to push.')
3096
note('Pushed up to revision %d.' % self.new_revno)
3175
# TODO: This function gets passed a to_file, but then
3176
# ignores it and calls note() instead. This is also
3177
# inconsistent with PullResult(), which writes to stdout.
3178
# -- JRV20110901, bug #838853
3179
tag_conflicts = getattr(self, "tag_conflicts", None)
3180
tag_updates = getattr(self, "tag_updates", None)
3182
if self.old_revid != self.new_revid:
3183
note(gettext('Pushed up to revision %d.') % self.new_revno)
3185
note(ngettext('%d tag updated.', '%d tags updated.', len(tag_updates)) % len(tag_updates))
3186
if self.old_revid == self.new_revid and not tag_updates:
3187
if not tag_conflicts:
3188
note(gettext('No new revisions or tags to push.'))
3190
note(gettext('No new revisions to push.'))
3097
3191
self._show_tag_conficts(to_file)
3113
3207
:param verbose: Requests more detailed display of what was checked,
3116
note('checked branch %s format %s', self.branch.user_url,
3117
self.branch._format)
3210
note(gettext('checked branch {0} format {1}').format(
3211
self.branch.user_url, self.branch._format))
3118
3212
for error in self.errors:
3119
note('found error:%s', error)
3213
note(gettext('found error:%s'), error)
3122
3216
class Converter5to6(object):
3157
3251
format = BzrBranchFormat7()
3158
3252
branch._set_config_location('stacked_on_location', '')
3159
3253
# update target format
3160
branch._transport.put_bytes('format', format.get_format_string())
3254
branch._transport.put_bytes('format', format.as_string())
3163
3257
class Converter7to8(object):
3164
"""Perform an in-place upgrade of format 6 to format 7"""
3258
"""Perform an in-place upgrade of format 7 to format 8"""
3166
3260
def convert(self, branch):
3167
3261
format = BzrBranchFormat8()
3168
3262
branch._transport.put_bytes('references', '')
3169
3263
# update target format
3170
branch._transport.put_bytes('format', format.get_format_string())
3264
branch._transport.put_bytes('format', format.as_string())
3173
3267
class InterBranch(InterObject):
3340
3434
if local and not bound_location:
3341
3435
raise errors.LocalRequiresBoundBranch()
3342
3436
master_branch = None
3343
source_is_master = (self.source.user_url == bound_location)
3437
source_is_master = False
3439
# bound_location comes from a config file, some care has to be
3440
# taken to relate it to source.user_url
3441
normalized = urlutils.normalize_url(bound_location)
3443
relpath = self.source.user_transport.relpath(normalized)
3444
source_is_master = (relpath == '')
3445
except (errors.PathNotChild, errors.InvalidURL):
3446
source_is_master = False
3344
3447
if not local and bound_location and not source_is_master:
3345
3448
# not pulling from master, so we need to update master.
3346
3449
master_branch = self.target.get_master_branch(possible_transports)
3398
3501
self._update_revisions(stop_revision, overwrite=overwrite,
3400
3503
if self.source._push_should_merge_tags():
3401
result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
3504
result.tag_updates, result.tag_conflicts = (
3505
self.source.tags.merge_to(self.target.tags, overwrite))
3403
3506
result.new_revno, result.new_revid = self.target.last_revision_info()
3488
3591
# TODO: The old revid should be specified when merging tags,
3489
3592
# so a tags implementation that versions tags can only
3490
3593
# pull in the most recent changes. -- JRV20090506
3491
result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
3492
overwrite, ignore_master=not merge_tags_to_master)
3594
result.tag_updates, result.tag_conflicts = (
3595
self.source.tags.merge_to(self.target.tags, overwrite,
3596
ignore_master=not merge_tags_to_master))
3493
3597
result.new_revno, result.new_revid = self.target.last_revision_info()
3494
3598
if _hook_master:
3495
3599
result.master_branch = _hook_master