15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
20
from bzrlib.lazy_import import lazy_import
19
21
lazy_import(globals(), """
22
from itertools import chain
20
23
from bzrlib import (
85
89
self.tags = self._make_tags()
86
90
self._revision_history_cache = None
87
91
self._revision_id_to_revno_cache = None
92
self._last_revision_info_cache = None
94
hooks = Branch.hooks['open']
99
"""Called by init to allow simpler extension of the base class."""
89
101
def break_lock(self):
90
102
"""Break a lock if one is present from another instance.
223
235
self.control_files.dont_leave_in_place()
225
@deprecated_method(deprecated_in((0, 16, 0)))
226
def abspath(self, name):
227
"""Return absolute filename for something in the branch
229
XXX: Robert Collins 20051017 what is this used for? why is it a branch
230
method and not a tree method.
232
raise NotImplementedError(self.abspath)
234
237
def bind(self, other):
235
238
"""Bind the local branch the other branch.
324
327
raise errors.InvalidRevisionNumber(revno)
325
328
return self.repository.get_revision_delta(rh[revno-1])
330
def get_stacked_on_url(self):
331
"""Get the URL this branch is stacked against.
333
:raises NotStacked: If the branch is not stacked.
334
:raises UnstackableBranchFormat: If the branch does not support
337
raise NotImplementedError(self.get_stacked_on_url)
327
339
def print_file(self, file, revision_id):
328
340
"""Print `file` to stdout."""
329
341
raise NotImplementedError(self.print_file)
331
343
def set_revision_history(self, rev_history):
332
344
raise NotImplementedError(self.set_revision_history)
346
def set_stacked_on_url(self, url):
347
"""Set the URL this branch is stacked against.
349
:raises UnstackableBranchFormat: If the branch does not support
351
:raises UnstackableRepositoryFormat: If the repository does not support
354
raise NotImplementedError(self.set_stacked_on_url)
334
356
def _cache_revision_history(self, rev_history):
335
357
"""Set the cached revision history to rev_history.
413
436
"""Return last revision id, or NULL_REVISION."""
414
437
return self.last_revision_info()[1]
416
440
def last_revision_info(self):
417
441
"""Return information about the last revision.
419
:return: A tuple (revno, last_revision_id).
443
:return: A tuple (revno, revision_id).
445
if self._last_revision_info_cache is None:
446
self._last_revision_info_cache = self._last_revision_info()
447
return self._last_revision_info_cache
449
def _last_revision_info(self):
421
450
rh = self.revision_history()
484
513
if not overwrite:
485
514
if graph is None:
486
515
graph = self.repository.get_graph()
487
heads = graph.heads([stop_revision, last_rev])
488
if heads == set([last_rev]):
489
# The current revision is a decendent of the target,
516
if self._check_if_descendant_or_diverged(
517
stop_revision, last_rev, graph, other):
518
# stop_revision is a descendant of last_rev, but we aren't
519
# overwriting, so we're done.
492
elif heads == set([stop_revision, last_rev]):
493
# These branches have diverged
494
raise errors.DivergedBranches(self, other)
495
elif heads != set([stop_revision]):
496
raise AssertionError("invalid heads: %r" % heads)
497
521
if stop_revno is None:
498
522
if graph is None:
499
523
graph = self.repository.get_graph()
528
550
return history[revno - 1]
530
552
def pull(self, source, overwrite=False, stop_revision=None,
531
possible_transports=None):
553
possible_transports=None, _override_hook_target=None):
532
554
"""Mirror source into this branch.
534
556
This branch is considered to be 'local', having low latency.
548
570
"""Return `Tree` object for last revision."""
549
571
return self.repository.revision_tree(self.last_revision())
551
def rename_one(self, from_rel, to_rel):
554
This can change the directory or the filename or both.
556
raise NotImplementedError(self.rename_one)
558
def move(self, from_paths, to_name):
561
to_name must exist as a versioned directory.
563
If to_name exists and is a directory, the files are moved into
564
it, keeping their old names. If it is a directory,
566
Note that to_name is only the last component of the new name;
567
this doesn't change the directory.
569
This returns a list of (from_path, to_path) pairs for each
572
raise NotImplementedError(self.move)
574
573
def get_parent(self):
575
574
"""Return the parent location of the branch.
676
675
revision_id: if not None, the revision history in the new branch will
677
676
be truncated to end with revision_id.
679
result = self._format.initialize(to_bzrdir)
678
result = to_bzrdir.create_branch()
680
679
self.copy_content_into(result, revision_id=revision_id)
684
683
def sprout(self, to_bzrdir, revision_id=None):
685
684
"""Create a new line of development from the branch, into to_bzrdir.
686
to_bzrdir controls the branch format.
687
688
revision_id: if not None, the revision history in the new branch will
688
689
be truncated to end with revision_id.
690
result = self._format.initialize(to_bzrdir)
691
result = to_bzrdir.create_branch()
691
692
self.copy_content_into(result, revision_id=revision_id)
692
693
result.set_parent(self.bzrdir.root_transport.base)
854
856
def supports_tags(self):
855
857
return self._format.supports_tags()
859
def _check_if_descendant_or_diverged(self, revision_a, revision_b, graph,
861
"""Ensure that revision_b is a descendant of revision_a.
863
This is a helper function for update_revisions.
865
:raises: DivergedBranches if revision_b has diverged from revision_a.
866
:returns: True if revision_b is a descendant of revision_a.
868
relation = self._revision_relations(revision_a, revision_b, graph)
869
if relation == 'b_descends_from_a':
871
elif relation == 'diverged':
872
raise errors.DivergedBranches(self, other_branch)
873
elif relation == 'a_descends_from_b':
876
raise AssertionError("invalid relation: %r" % (relation,))
878
def _revision_relations(self, revision_a, revision_b, graph):
879
"""Determine the relationship between two revisions.
881
:returns: One of: 'a_descends_from_b', 'b_descends_from_a', 'diverged'
883
heads = graph.heads([revision_a, revision_b])
884
if heads == set([revision_b]):
885
return 'b_descends_from_a'
886
elif heads == set([revision_a, revision_b]):
887
# These branches have diverged
889
elif heads == set([revision_a]):
890
return 'a_descends_from_b'
892
raise AssertionError("invalid heads: %r" % (heads,))
858
895
class BranchFormat(object):
859
896
"""An encapsulation of the initialization and open routines for a format.
998
1035
def set_default_format(klass, format):
999
1036
klass._default_format = format
1038
def supports_stacking(self):
1039
"""True if this format records a stacked-on branch."""
1002
1043
def unregister_format(klass, format):
1003
1044
del klass._formats[format.get_format_string()]
1071
1114
# local is the local branch or None, master is the target branch,
1072
1115
# and an empty branch recieves new_revno of 0, new_revid of None.
1073
1116
self['post_uncommit'] = []
1118
# Invoked before the tip of a branch changes.
1119
# the api signature is
1120
# (params) where params is a ChangeBranchTipParams with the members
1121
# (branch, old_revno, new_revno, old_revid, new_revid)
1122
self['pre_change_branch_tip'] = []
1074
1123
# Introduced in 1.4
1075
1124
# Invoked after the tip of a branch changes.
1076
1125
# the api signature is
1077
1126
# (params) where params is a ChangeBranchTipParams with the members
1078
1127
# (branch, old_revno, new_revno, old_revid, new_revid)
1079
1128
self['post_change_branch_tip'] = []
1130
# Invoked when a stacked branch activates its fallback locations and
1131
# allows the transformation of the url of said location.
1132
# the api signature is
1133
# (branch, url) where branch is the branch having its fallback
1134
# location activated and url is the url for the fallback location.
1135
# The hook should return a url.
1136
self['transform_fallback_location'] = []
1082
1139
# install the default hooks into the Branch class.
1112
1169
self.old_revid = old_revid
1113
1170
self.new_revid = new_revid
1172
def __eq__(self, other):
1173
return self.__dict__ == other.__dict__
1176
return "<%s of %s from (%s, %s) to (%s, %s)>" % (
1177
self.__class__.__name__, self.branch,
1178
self.old_revno, self.old_revid, self.new_revno, self.new_revid)
1116
1181
class BzrBranchFormat4(BranchFormat):
1117
1182
"""Bzr branch format 4.
1155
1220
return "Bazaar-NG branch format 4"
1158
class BzrBranchFormat5(BranchFormat):
1223
class BranchFormatMetadir(BranchFormat):
1224
"""Common logic for meta-dir based branch formats."""
1226
def _branch_class(self):
1227
"""What class to instantiate on open calls."""
1228
raise NotImplementedError(self._branch_class)
1230
def open(self, a_bzrdir, _found=False):
1231
"""Return the branch object for a_bzrdir.
1233
_found is a private parameter, do not use it. It is used to indicate
1234
if format probing has already be done.
1237
format = BranchFormat.find_format(a_bzrdir)
1238
if format.__class__ != self.__class__:
1239
raise AssertionError("wrong format %r found for %r" %
1242
transport = a_bzrdir.get_branch_transport(None)
1243
control_files = lockable_files.LockableFiles(transport, 'lock',
1245
return self._branch_class()(_format=self,
1246
_control_files=control_files,
1248
_repository=a_bzrdir.find_repository())
1249
except errors.NoSuchFile:
1250
raise errors.NotBranchError(path=transport.base)
1253
super(BranchFormatMetadir, self).__init__()
1254
self._matchingbzrdir = bzrdir.BzrDirMetaFormat1()
1256
def supports_tags(self):
1260
class BzrBranchFormat5(BranchFormatMetadir):
1159
1261
"""Bzr branch format 5.
1161
1263
This format has:
1184
1289
return self._initialize_helper(a_bzrdir, utf8_files)
1187
super(BzrBranchFormat5, self).__init__()
1188
self._matchingbzrdir = bzrdir.BzrDirMetaFormat1()
1190
def open(self, a_bzrdir, _found=False):
1191
"""Return the branch object for a_bzrdir
1193
_found is a private parameter, do not use it. It is used to indicate
1194
if format probing has already be done.
1197
format = BranchFormat.find_format(a_bzrdir)
1198
if format.__class__ != self.__class__:
1199
raise AssertionError("wrong format %r found for %r" %
1202
transport = a_bzrdir.get_branch_transport(None)
1203
control_files = lockable_files.LockableFiles(transport, 'lock',
1205
return BzrBranch5(_format=self,
1206
_control_files=control_files,
1208
_repository=a_bzrdir.find_repository())
1209
except errors.NoSuchFile:
1210
raise errors.NotBranchError(path=transport.base)
1213
class BzrBranchFormat6(BzrBranchFormat5):
1291
def supports_tags(self):
1295
class BzrBranchFormat6(BranchFormatMetadir):
1214
1296
"""Branch format with last-revision and tags.
1216
1298
Unlike previous formats, this has no explicit revision history. Instead,
1238
1323
return self._initialize_helper(a_bzrdir, utf8_files)
1240
def open(self, a_bzrdir, _found=False):
1241
"""Return the branch object for a_bzrdir
1243
_found is a private parameter, do not use it. It is used to indicate
1244
if format probing has already be done.
1247
format = BranchFormat.find_format(a_bzrdir)
1248
if format.__class__ != self.__class__:
1249
raise AssertionError("wrong format %r found for %r" %
1251
transport = a_bzrdir.get_branch_transport(None)
1252
control_files = lockable_files.LockableFiles(transport, 'lock',
1254
return BzrBranch6(_format=self,
1255
_control_files=control_files,
1257
_repository=a_bzrdir.find_repository())
1259
def supports_tags(self):
1326
class BzrBranchFormat7(BranchFormatMetadir):
1327
"""Branch format with last-revision, tags, and a stacked location pointer.
1329
The stacked location pointer is passed down to the repository and requires
1330
a repository format with supports_external_lookups = True.
1332
This format was introduced in bzr 1.6.
1335
def _branch_class(self):
1338
def get_format_string(self):
1339
"""See BranchFormat.get_format_string()."""
1340
return "Bazaar Branch Format 7 (needs bzr 1.6)\n"
1342
def get_format_description(self):
1343
"""See BranchFormat.get_format_description()."""
1344
return "Branch format 7"
1346
def initialize(self, a_bzrdir):
1347
"""Create a branch of this format in a_bzrdir."""
1348
utf8_files = [('last-revision', '0 null:\n'),
1349
('branch.conf', ''),
1352
return self._initialize_helper(a_bzrdir, utf8_files)
1355
super(BzrBranchFormat7, self).__init__()
1356
self._matchingbzrdir.repository_format = \
1357
RepositoryFormatKnitPack5RichRoot()
1359
def supports_stacking(self):
1351
1451
# and not independently creatable, so are not registered.
1352
1452
__format5 = BzrBranchFormat5()
1353
1453
__format6 = BzrBranchFormat6()
1454
__format7 = BzrBranchFormat7()
1354
1455
BranchFormat.register_format(__format5)
1355
1456
BranchFormat.register_format(BranchReferenceFormat())
1356
1457
BranchFormat.register_format(__format6)
1458
BranchFormat.register_format(__format7)
1357
1459
BranchFormat.set_default_format(__format6)
1358
1460
_legacy_formats = [BzrBranchFormat4(),
1465
1562
"""See Branch.set_revision_history."""
1466
1563
if 'evil' in debug.debug_flags:
1467
1564
mutter_callsite(3, "set_revision_history scales with history.")
1565
check_not_reserved_id = _mod_revision.check_not_reserved_id
1566
for rev_id in rev_history:
1567
check_not_reserved_id(rev_id)
1568
if Branch.hooks['post_change_branch_tip']:
1569
# Don't calculate the last_revision_info() if there are no hooks
1571
old_revno, old_revid = self.last_revision_info()
1572
if len(rev_history) == 0:
1573
revid = _mod_revision.NULL_REVISION
1575
revid = rev_history[-1]
1576
self._run_pre_change_branch_tip_hooks(len(rev_history), revid)
1468
1577
self._write_revision_history(rev_history)
1469
1578
self._clear_cached_state()
1470
1579
self._cache_revision_history(rev_history)
1471
1580
for hook in Branch.hooks['set_rh']:
1472
1581
hook(self, rev_history)
1582
if Branch.hooks['post_change_branch_tip']:
1583
self._run_post_change_branch_tip_hooks(old_revno, old_revid)
1585
def _run_pre_change_branch_tip_hooks(self, new_revno, new_revid):
1586
"""Run the pre_change_branch_tip hooks."""
1587
hooks = Branch.hooks['pre_change_branch_tip']
1590
old_revno, old_revid = self.last_revision_info()
1591
params = ChangeBranchTipParams(
1592
self, old_revno, new_revno, old_revid, new_revid)
1596
except errors.TipChangeRejected:
1599
exc_info = sys.exc_info()
1600
hook_name = Branch.hooks.get_hook_name(hook)
1601
raise errors.HookFailed(
1602
'pre_change_branch_tip', hook_name, exc_info)
1474
1604
def _run_post_change_branch_tip_hooks(self, old_revno, old_revid):
1475
1605
"""Run the post_change_branch_tip hooks."""
1476
1606
hooks = Branch.hooks['post_change_branch_tip']
1503
1632
if len(history) != revno:
1504
1633
raise AssertionError('%d != %d' % (len(history), revno))
1505
1634
self.set_revision_history(history)
1506
self._run_post_change_branch_tip_hooks(old_revno, old_revid)
1508
1636
def _gen_revision_history(self):
1509
1637
history = self._transport.get_bytes('revision-history').split('\n')
1528
1656
raise errors.NoSuchRevision(self, revision_id)
1529
1657
current_rev_id = revision_id
1530
1658
new_history = []
1659
check_not_reserved_id = _mod_revision.check_not_reserved_id
1531
1660
# Do not include ghosts or graph origin in revision_history
1532
1661
while (current_rev_id in parents_map and
1533
1662
len(parents_map[current_rev_id]) > 0):
1663
check_not_reserved_id(current_rev_id)
1534
1664
new_history.append(current_rev_id)
1535
1665
current_rev_id = parents_map[current_rev_id][0]
1536
1666
parents_map = graph.get_parent_map([current_rev_id])
1558
1688
@needs_write_lock
1559
1689
def pull(self, source, overwrite=False, stop_revision=None,
1560
_hook_master=None, run_hooks=True, possible_transports=None):
1690
_hook_master=None, run_hooks=True, possible_transports=None,
1691
_override_hook_target=None):
1561
1692
"""See Branch.pull.
1563
1694
:param _hook_master: Private parameter - set the branch to
1564
be supplied as the master to push hooks.
1695
be supplied as the master to pull hooks.
1565
1696
:param run_hooks: Private parameter - if false, this branch
1566
1697
is being called because it's the master of the primary branch,
1567
1698
so it should not run its hooks.
1699
:param _override_hook_target: Private parameter - set the branch to be
1700
supplied as the target_branch to pull hooks.
1569
1702
result = PullResult()
1570
1703
result.source_branch = source
1571
result.target_branch = self
1704
if _override_hook_target is None:
1705
result.target_branch = self
1707
result.target_branch = _override_hook_target
1572
1708
source.lock_read()
1574
1710
# We assume that during 'pull' the local repository is closer than
1581
1717
result.new_revno, result.new_revid = self.last_revision_info()
1582
1718
if _hook_master:
1583
1719
result.master_branch = _hook_master
1584
result.local_branch = self
1720
result.local_branch = result.target_branch
1586
result.master_branch = self
1722
result.master_branch = result.target_branch
1587
1723
result.local_branch = None
1589
1725
for hook in Branch.hooks['post_pull']:
1616
1752
# TODO: Public option to disable running hooks - should be trivial but
1620
result = self._push_with_bound_branches(target, overwrite,
1622
_override_hook_source_branch=_override_hook_source_branch)
1754
return _run_with_write_locked_target(
1755
target, self._push_with_bound_branches, target, overwrite,
1757
_override_hook_source_branch=_override_hook_source_branch)
1627
1759
def _push_with_bound_branches(self, target, overwrite,
1679
1811
result.source_branch = self
1680
1812
result.target_branch = target
1681
1813
result.old_revno, result.old_revid = target.last_revision_info()
1683
# We assume that during 'push' this repository is closer than
1685
graph = self.repository.get_graph(target.repository)
1686
target.update_revisions(self, stop_revision, overwrite=overwrite,
1688
result.tag_conflicts = self.tags.merge_to(target.tags, overwrite)
1814
if result.old_revid != self.last_revision():
1815
# We assume that during 'push' this repository is closer than
1817
graph = self.repository.get_graph(target.repository)
1818
target.update_revisions(self, stop_revision, overwrite=overwrite,
1820
if self._push_should_merge_tags():
1821
result.tag_conflicts = self.tags.merge_to(target.tags, overwrite)
1689
1822
result.new_revno, result.new_revid = target.last_revision_info()
1825
def _push_should_merge_tags(self):
1826
"""Should _basic_push merge this branch's tags into the target?
1828
The default implementation returns False if this branch has no tags,
1829
and True the rest of the time. Subclasses may override this.
1831
return self.tags.supports_tags() and self.tags.get_tag_dict()
1692
1833
def get_parent(self):
1693
1834
"""See Branch.get_parent."""
1694
1835
parent = self._get_parent_location()
1703
1844
except errors.InvalidURLJoin, e:
1704
1845
raise errors.InaccessibleParent(parent, self.base)
1847
def get_stacked_on_url(self):
1848
raise errors.UnstackableBranchFormat(self._format, self.base)
1706
1850
def set_push_location(self, location):
1707
1851
"""See Branch.set_push_location."""
1708
1852
self.get_config().set_user_option(
1734
1878
self._transport.put_bytes('parent', url + '\n',
1735
1879
mode=self.bzrdir._get_file_mode())
1881
def set_stacked_on_url(self, url):
1882
raise errors.UnstackableBranchFormat(self._format, self.base)
1738
1885
class BzrBranch5(BzrBranch):
1739
1886
"""A format 5 branch. This supports new features over plain branches.
1741
1888
It has support for a master_branch which is the data for bound branches.
1749
super(BzrBranch5, self).__init__(_format=_format,
1750
_control_files=_control_files,
1752
_repository=_repository)
1754
1891
@needs_write_lock
1755
1892
def pull(self, source, overwrite=False, stop_revision=None,
1756
run_hooks=True, possible_transports=None):
1893
run_hooks=True, possible_transports=None,
1894
_override_hook_target=None):
1757
1895
"""Pull from source into self, updating my master if any.
1759
1897
:param run_hooks: Private parameter - if false, this branch
1873
class BzrBranch6(BzrBranch5):
2012
class BzrBranch7(BzrBranch5):
2013
"""A branch with support for a fallback repository."""
2015
def _get_fallback_repository(self, url):
2016
"""Get the repository we fallback to at url."""
2017
url = urlutils.join(self.base, url)
2018
return bzrdir.BzrDir.open(url).open_branch().repository
2020
def _activate_fallback_location(self, url):
2021
"""Activate the branch/repository from url as a fallback repository."""
2022
self.repository.add_fallback_repository(
2023
self._get_fallback_repository(url))
2025
def _open_hook(self):
2027
url = self.get_stacked_on_url()
2028
except (errors.UnstackableRepositoryFormat, errors.NotStacked,
2029
errors.UnstackableBranchFormat):
2032
for hook in Branch.hooks['transform_fallback_location']:
2033
url = hook(self, url)
2035
hook_name = Branch.hooks.get_hook_name(hook)
2036
raise AssertionError(
2037
"'transform_fallback_location' hook %s returned "
2038
"None, not a URL." % hook_name)
2039
self._activate_fallback_location(url)
2041
def _check_stackable_repo(self):
2042
if not self.repository._format.supports_external_lookups:
2043
raise errors.UnstackableRepositoryFormat(self.repository._format,
2044
self.repository.base)
1875
2046
def __init__(self, *args, **kwargs):
1876
super(BzrBranch6, self).__init__(*args, **kwargs)
2047
super(BzrBranch7, self).__init__(*args, **kwargs)
1877
2048
self._last_revision_info_cache = None
1878
2049
self._partial_revision_history_cache = []
1880
2051
def _clear_cached_state(self):
1881
super(BzrBranch6, self)._clear_cached_state()
2052
super(BzrBranch7, self)._clear_cached_state()
1882
2053
self._last_revision_info_cache = None
1883
2054
self._partial_revision_history_cache = []
1886
def last_revision_info(self):
1887
"""Return information about the last revision.
1889
:return: A tuple (revno, revision_id).
1891
if self._last_revision_info_cache is None:
1892
self._last_revision_info_cache = self._last_revision_info()
1893
return self._last_revision_info_cache
1895
2056
def _last_revision_info(self):
1896
2057
revision_string = self._transport.get_bytes('last-revision')
1897
2058
revno, revision_id = revision_string.rstrip('\n').split(' ', 1)
1919
2080
old_revno, old_revid = self.last_revision_info()
1920
2081
if self._get_append_revisions_only():
1921
2082
self._check_history_violation(revision_id)
2083
self._run_pre_change_branch_tip_hooks(revno, revision_id)
1922
2084
self._write_last_revision_info(revno, revision_id)
1923
2085
self._clear_cached_state()
1924
2086
self._last_revision_info_cache = revno, revision_id
1934
2096
def _gen_revision_history(self):
1935
2097
"""Generate the revision history from last revision
1937
self._extend_partial_history()
2099
last_revno, last_revision = self.last_revision_info()
2100
self._extend_partial_history(stop_index=last_revno-1)
1938
2101
return list(reversed(self._partial_revision_history_cache))
1940
2103
def _extend_partial_history(self, stop_index=None, stop_revision=None):
2030
2193
"""See Branch.get_old_bound_location"""
2031
2194
return self._get_bound_location(False)
2196
def get_stacked_on_url(self):
2197
# you can always ask for the URL; but you might not be able to use it
2198
# if the repo can't support stacking.
2199
## self._check_stackable_repo()
2200
stacked_url = self._get_config_location('stacked_on_location')
2201
if stacked_url is None:
2202
raise errors.NotStacked(self)
2033
2205
def set_append_revisions_only(self, enabled):
2038
2210
self.get_config().set_user_option('append_revisions_only', value,
2039
2211
warn_masked=True)
2213
def set_stacked_on_url(self, url):
2214
self._check_stackable_repo()
2217
old_url = self.get_stacked_on_url()
2218
except (errors.NotStacked, errors.UnstackableBranchFormat,
2219
errors.UnstackableRepositoryFormat):
2222
# repositories don't offer an interface to remove fallback
2223
# repositories today; take the conceptually simpler option and just
2225
self.repository = self.bzrdir.find_repository()
2226
# for every revision reference the branch has, ensure it is pulled
2228
source_repository = self._get_fallback_repository(old_url)
2229
for revision_id in chain([self.last_revision()],
2230
self.tags.get_reverse_tag_dict()):
2231
self.repository.fetch(source_repository, revision_id,
2234
self._activate_fallback_location(url)
2235
# write this out after the repository is stacked to avoid setting a
2236
# stacked config that doesn't work.
2237
self._set_config_location('stacked_on_location', url)
2041
2239
def _get_append_revisions_only(self):
2042
2240
value = self.get_config().get_user_option('append_revisions_only')
2043
2241
return value == 'True'
2118
2316
return self.revno() - index
2319
class BzrBranch6(BzrBranch7):
2320
"""See BzrBranchFormat6 for the capabilities of this branch.
2322
This subclass of BzrBranch7 disables the new features BzrBranch7 added,
2326
def get_stacked_on_url(self):
2327
raise errors.UnstackableBranchFormat(self._format, self.base)
2329
def set_stacked_on_url(self, url):
2330
raise errors.UnstackableBranchFormat(self._format, self.base)
2121
2333
######################################################################
2122
2334
# results of operations
2140
2352
:ivar old_revid: Tip revision id before pull.
2141
2353
:ivar new_revid: Tip revision id after pull.
2142
2354
:ivar source_branch: Source (local) branch object.
2143
:ivar master_branch: Master branch of the target, or None.
2355
:ivar master_branch: Master branch of the target, or the target if no
2357
:ivar local_branch: target branch if there is a Master, else None
2144
2358
:ivar target_branch: Target/destination branch object.
2359
:ivar tag_conflicts: A list of tag conflicts, see BasicTags.merge_to
2147
2362
def __int__(self):
2231
2446
except errors.NoSuchFile:
2233
2448
branch.set_bound_location(None)
2451
class Converter6to7(object):
2452
"""Perform an in-place upgrade of format 6 to format 7"""
2454
def convert(self, branch):
2455
format = BzrBranchFormat7()
2456
branch._set_config_location('stacked_on_location', '')
2457
# update target format
2458
branch._transport.put_bytes('format', format.get_format_string())
2462
def _run_with_write_locked_target(target, callable, *args, **kwargs):
2463
"""Run ``callable(*args, **kwargs)``, write-locking target for the
2466
_run_with_write_locked_target will attempt to release the lock it acquires.
2468
If an exception is raised by callable, then that exception *will* be
2469
propagated, even if the unlock attempt raises its own error. Thus
2470
_run_with_write_locked_target should be preferred to simply doing::
2474
return callable(*args, **kwargs)
2479
# This is very similar to bzrlib.decorators.needs_write_lock. Perhaps they
2480
# should share code?
2483
result = callable(*args, **kwargs)
2485
exc_info = sys.exc_info()
2489
raise exc_info[0], exc_info[1], exc_info[2]