124
116
if master is not None:
125
117
master.break_lock()
127
def _check_stackable_repo(self):
128
if not self.repository._format.supports_external_lookups:
129
raise errors.UnstackableRepositoryFormat(self.repository._format,
130
self.repository.base)
132
def _extend_partial_history(self, stop_index=None, stop_revision=None):
133
"""Extend the partial history to include a given index
135
If a stop_index is supplied, stop when that index has been reached.
136
If a stop_revision is supplied, stop when that revision is
137
encountered. Otherwise, stop when the beginning of history is
140
:param stop_index: The index which should be present. When it is
141
present, history extension will stop.
142
:param stop_revision: The revision id which should be present. When
143
it is encountered, history extension will stop.
145
if len(self._partial_revision_history_cache) == 0:
146
self._partial_revision_history_cache = [self.last_revision()]
147
repository._iter_for_revno(
148
self.repository, self._partial_revision_history_cache,
149
stop_index=stop_index, stop_revision=stop_revision)
150
if self._partial_revision_history_cache[-1] == _mod_revision.NULL_REVISION:
151
self._partial_revision_history_cache.pop()
153
def _get_check_refs(self):
154
"""Get the references needed for check().
158
revid = self.last_revision()
159
return [('revision-existence', revid), ('lefthand-distance', revid)]
162
120
def open(base, _unsupported=False, possible_transports=None):
163
121
"""Open the branch rooted at base.
197
155
The default implementation returns False if this branch has no tags,
198
156
and True the rest of the time. Subclasses may override this.
200
return self.supports_tags() and self.tags.get_tag_dict()
158
return self.tags.supports_tags() and self.tags.get_tag_dict()
202
160
def get_config(self):
203
161
return BranchConfig(self)
205
def _get_config(self):
206
"""Get the concrete config for just the config in this branch.
208
This is not intended for client use; see Branch.get_config for the
213
:return: An object supporting get_option and set_option.
215
raise NotImplementedError(self._get_config)
217
def _get_fallback_repository(self, url):
218
"""Get the repository we fallback to at url."""
219
url = urlutils.join(self.base, url)
220
a_bzrdir = bzrdir.BzrDir.open(url,
221
possible_transports=[self.bzrdir.root_transport])
222
return a_bzrdir.open_branch().repository
224
def _get_tags_bytes(self):
225
"""Get the bytes of a serialised tags dict.
227
Note that not all branches support tags, nor do all use the same tags
228
logic: this method is specific to BasicTags. Other tag implementations
229
may use the same method name and behave differently, safely, because
230
of the double-dispatch via
231
format.make_tags->tags_instance->get_tags_dict.
233
:return: The bytes of the tags file.
234
:seealso: Branch._set_tags_bytes.
236
return self._transport.get_bytes('tags')
238
163
def _get_nick(self, local=False, possible_transports=None):
239
164
config = self.get_config()
240
165
# explicit overrides master, but don't look for master if local is True
467
396
"""Iterate over an inclusive range of sorted revisions."""
468
397
rev_iter = iter(merge_sorted_revisions)
469
398
if start_revision_id is not None:
470
for node in rev_iter:
471
rev_id = node.key[-1]
399
for rev_id, depth, revno, end_of_merge in rev_iter:
472
400
if rev_id != start_revision_id:
475
403
# The decision to include the start or not
476
404
# depends on the stop_rule if a stop is provided
477
# so pop this node back into the iterator
478
rev_iter = chain(iter([node]), rev_iter)
406
iter([(rev_id, depth, revno, end_of_merge)]),
480
409
if stop_revision_id is None:
482
for node in rev_iter:
483
rev_id = node.key[-1]
484
yield (rev_id, node.merge_depth, node.revno,
410
for rev_id, depth, revno, end_of_merge in rev_iter:
411
yield rev_id, depth, revno, end_of_merge
486
412
elif stop_rule == 'exclude':
487
for node in rev_iter:
488
rev_id = node.key[-1]
413
for rev_id, depth, revno, end_of_merge in rev_iter:
489
414
if rev_id == stop_revision_id:
491
yield (rev_id, node.merge_depth, node.revno,
416
yield rev_id, depth, revno, end_of_merge
493
417
elif stop_rule == 'include':
494
for node in rev_iter:
495
rev_id = node.key[-1]
496
yield (rev_id, node.merge_depth, node.revno,
418
for rev_id, depth, revno, end_of_merge in rev_iter:
419
yield rev_id, depth, revno, end_of_merge
498
420
if rev_id == stop_revision_id:
500
422
elif stop_rule == 'with-merges':
688
563
:raises UnstackableRepositoryFormat: If the repository does not support
691
if not self._format.supports_stacking():
692
raise errors.UnstackableBranchFormat(self._format, self.base)
693
# XXX: Changing from one fallback repository to another does not check
694
# that all the data you need is present in the new fallback.
695
# Possibly it should.
696
self._check_stackable_repo()
699
old_url = self.get_stacked_on_url()
700
except (errors.NotStacked, errors.UnstackableBranchFormat,
701
errors.UnstackableRepositoryFormat):
705
self._activate_fallback_location(url)
706
# write this out after the repository is stacked to avoid setting a
707
# stacked config that doesn't work.
708
self._set_config_location('stacked_on_location', url)
711
"""Change a branch to be unstacked, copying data as needed.
713
Don't call this directly, use set_stacked_on_url(None).
715
pb = ui.ui_factory.nested_progress_bar()
717
pb.update("Unstacking")
718
# The basic approach here is to fetch the tip of the branch,
719
# including all available ghosts, from the existing stacked
720
# repository into a new repository object without the fallbacks.
722
# XXX: See <https://launchpad.net/bugs/397286> - this may not be
723
# correct for CHKMap repostiories
724
old_repository = self.repository
725
if len(old_repository._fallback_repositories) != 1:
726
raise AssertionError("can't cope with fallback repositories "
727
"of %r" % (self.repository,))
728
# unlock it, including unlocking the fallback
729
old_repository.unlock()
730
old_repository.lock_read()
732
# Repositories don't offer an interface to remove fallback
733
# repositories today; take the conceptually simpler option and just
734
# reopen it. We reopen it starting from the URL so that we
735
# get a separate connection for RemoteRepositories and can
736
# stream from one of them to the other. This does mean doing
737
# separate SSH connection setup, but unstacking is not a
738
# common operation so it's tolerable.
739
new_bzrdir = bzrdir.BzrDir.open(self.bzrdir.root_transport.base)
740
new_repository = new_bzrdir.find_repository()
741
self.repository = new_repository
742
if self.repository._fallback_repositories:
743
raise AssertionError("didn't expect %r to have "
744
"fallback_repositories"
745
% (self.repository,))
746
# this is not paired with an unlock because it's just restoring
747
# the previous state; the lock's released when set_stacked_on_url
749
self.repository.lock_write()
750
# XXX: If you unstack a branch while it has a working tree
751
# with a pending merge, the pending-merged revisions will no
752
# longer be present. You can (probably) revert and remerge.
754
# XXX: This only fetches up to the tip of the repository; it
755
# doesn't bring across any tags. That's fairly consistent
756
# with how branch works, but perhaps not ideal.
757
self.repository.fetch(old_repository,
758
revision_id=self.last_revision(),
761
old_repository.unlock()
765
def _set_tags_bytes(self, bytes):
766
"""Mirror method for _get_tags_bytes.
768
:seealso: Branch._get_tags_bytes.
770
return _run_with_write_locked_target(self, self._transport.put_bytes,
566
raise NotImplementedError(self.set_stacked_on_url)
773
568
def _cache_revision_history(self, rev_history):
774
569
"""Set the cached revision history to rev_history.
933
730
except ValueError:
934
731
raise errors.NoSuchRevision(self, revision_id)
937
733
def get_rev_id(self, revno, history=None):
938
734
"""Find the revision id of the specified revno."""
940
736
return _mod_revision.NULL_REVISION
941
last_revno, last_revid = self.last_revision_info()
942
if revno == last_revno:
944
if revno <= 0 or revno > last_revno:
738
history = self.revision_history()
739
if revno <= 0 or revno > len(history):
945
740
raise errors.NoSuchRevision(self, revno)
946
distance_from_last = last_revno - revno
947
if len(self._partial_revision_history_cache) <= distance_from_last:
948
self._extend_partial_history(distance_from_last)
949
return self._partial_revision_history_cache[distance_from_last]
741
return history[revno - 1]
952
743
def pull(self, source, overwrite=False, stop_revision=None,
953
possible_transports=None, *args, **kwargs):
744
possible_transports=None, _override_hook_target=None):
954
745
"""Mirror source into this branch.
956
747
This branch is considered to be 'local', having low latency.
958
749
:returns: PullResult instance
960
return InterBranch.get(source, self).pull(overwrite=overwrite,
961
stop_revision=stop_revision,
962
possible_transports=possible_transports, *args, **kwargs)
751
raise NotImplementedError(self.pull)
964
def push(self, target, overwrite=False, stop_revision=None, *args,
753
def push(self, target, overwrite=False, stop_revision=None):
966
754
"""Mirror this branch into target.
968
756
This branch is considered to be 'local', having low latency.
970
return InterBranch.get(self, target).push(overwrite, stop_revision,
973
def lossy_push(self, target, stop_revision=None):
974
"""Push deltas into another branch.
976
:note: This does not, like push, retain the revision ids from
977
the source branch and will, rather than adding bzr-specific
978
metadata, push only those semantics of the revision that can be
979
natively represented by this branch' VCS.
981
:param target: Target branch
982
:param stop_revision: Revision to push, defaults to last revision.
983
:return: BranchPushResult with an extra member revidmap:
984
A dictionary mapping revision ids from the target branch
985
to new revision ids in the target branch, for each
986
revision that was pushed.
988
inter = InterBranch.get(self, target)
989
lossy_push = getattr(inter, "lossy_push", None)
990
if lossy_push is None:
991
raise errors.LossyPushToSameVCS(self, target)
992
return lossy_push(stop_revision)
758
raise NotImplementedError(self.push)
994
760
def basis_tree(self):
995
761
"""Return `Tree` object for last revision."""
1244
992
Callers will typically also want to check the repository.
1246
:param refs: Calculated refs for this branch as specified by
1247
branch._get_check_refs()
1248
994
:return: A BranchCheckResult.
1250
result = BranchCheckResult(self)
996
mainline_parent_id = None
1251
997
last_revno, last_revision_id = self.last_revision_info()
1252
actual_revno = refs[('lefthand-distance', last_revision_id)]
1253
if actual_revno != last_revno:
1254
result.errors.append(errors.BzrCheckError(
1255
'revno does not match len(mainline) %s != %s' % (
1256
last_revno, actual_revno)))
1257
# TODO: We should probably also check that self.revision_history
1258
# matches the repository for older branch formats.
1259
# If looking for the code that cross-checks repository parents against
1260
# the iter_reverse_revision_history output, that is now a repository
998
real_rev_history = list(self.repository.iter_reverse_revision_history(
1000
real_rev_history.reverse()
1001
if len(real_rev_history) != last_revno:
1002
raise errors.BzrCheckError('revno does not match len(mainline)'
1003
' %s != %s' % (last_revno, len(real_rev_history)))
1004
# TODO: We should probably also check that real_rev_history actually
1005
# matches self.revision_history()
1006
for revision_id in real_rev_history:
1008
revision = self.repository.get_revision(revision_id)
1009
except errors.NoSuchRevision, e:
1010
raise errors.BzrCheckError("mainline revision {%s} not in repository"
1012
# In general the first entry on the revision history has no parents.
1013
# But it's not illegal for it to have parents listed; this can happen
1014
# in imports from Arch when the parents weren't reachable.
1015
if mainline_parent_id is not None:
1016
if mainline_parent_id not in revision.parent_ids:
1017
raise errors.BzrCheckError("previous revision {%s} not listed among "
1019
% (mainline_parent_id, revision_id))
1020
mainline_parent_id = revision_id
1021
return BranchCheckResult(self)
1264
1023
def _get_checkout_format(self):
1265
1024
"""Return the most suitable metadir for a checkout of this branch.
1621
1342
Hooks.__init__(self)
1622
self.create_hook(HookPoint('set_rh',
1623
"Invoked whenever the revision history has been set via "
1624
"set_revision_history. The api signature is (branch, "
1625
"revision_history), and the branch will be write-locked. "
1626
"The set_rh hook can be expensive for bzr to trigger, a better "
1627
"hook to use is Branch.post_change_branch_tip.", (0, 15), None))
1628
self.create_hook(HookPoint('open',
1629
"Called with the Branch object that has been opened after a "
1630
"branch is opened.", (1, 8), None))
1631
self.create_hook(HookPoint('post_push',
1632
"Called after a push operation completes. post_push is called "
1633
"with a bzrlib.branch.BranchPushResult object and only runs in the "
1634
"bzr client.", (0, 15), None))
1635
self.create_hook(HookPoint('post_pull',
1636
"Called after a pull operation completes. post_pull is called "
1637
"with a bzrlib.branch.PullResult object and only runs in the "
1638
"bzr client.", (0, 15), None))
1639
self.create_hook(HookPoint('pre_commit',
1640
"Called after a commit is calculated but before it is is "
1641
"completed. pre_commit is called with (local, master, old_revno, "
1642
"old_revid, future_revno, future_revid, tree_delta, future_tree"
1643
"). old_revid is NULL_REVISION for the first commit to a branch, "
1644
"tree_delta is a TreeDelta object describing changes from the "
1645
"basis revision. hooks MUST NOT modify this delta. "
1646
" future_tree is an in-memory tree obtained from "
1647
"CommitBuilder.revision_tree() and hooks MUST NOT modify this "
1648
"tree.", (0,91), None))
1649
self.create_hook(HookPoint('post_commit',
1650
"Called in the bzr client after a commit has completed. "
1651
"post_commit is called with (local, master, old_revno, old_revid, "
1652
"new_revno, new_revid). old_revid is NULL_REVISION for the first "
1653
"commit to a branch.", (0, 15), None))
1654
self.create_hook(HookPoint('post_uncommit',
1655
"Called in the bzr client after an uncommit completes. "
1656
"post_uncommit is called with (local, master, old_revno, "
1657
"old_revid, new_revno, new_revid) where local is the local branch "
1658
"or None, master is the target branch, and an empty branch "
1659
"receives new_revno of 0, new_revid of None.", (0, 15), None))
1660
self.create_hook(HookPoint('pre_change_branch_tip',
1661
"Called in bzr client and server before a change to the tip of a "
1662
"branch is made. pre_change_branch_tip is called with a "
1663
"bzrlib.branch.ChangeBranchTipParams. Note that push, pull, "
1664
"commit, uncommit will all trigger this hook.", (1, 6), None))
1665
self.create_hook(HookPoint('post_change_branch_tip',
1666
"Called in bzr client and server after a change to the tip of a "
1667
"branch is made. post_change_branch_tip is called with a "
1668
"bzrlib.branch.ChangeBranchTipParams. Note that push, pull, "
1669
"commit, uncommit will all trigger this hook.", (1, 4), None))
1670
self.create_hook(HookPoint('transform_fallback_location',
1671
"Called when a stacked branch is activating its fallback "
1672
"locations. transform_fallback_location is called with (branch, "
1673
"url), and should return a new url. Returning the same url "
1674
"allows it to be used as-is, returning a different one can be "
1675
"used to cause the branch to stack on a closer copy of that "
1676
"fallback_location. Note that the branch cannot have history "
1677
"accessing methods called on it during this hook because the "
1678
"fallback locations have not been activated. When there are "
1679
"multiple hooks installed for transform_fallback_location, "
1680
"all are called with the url returned from the previous hook."
1681
"The order is however undefined.", (1, 9), None))
1343
# Introduced in 0.15:
1344
# invoked whenever the revision history has been set
1345
# with set_revision_history. The api signature is
1346
# (branch, revision_history), and the branch will
1349
# Invoked after a branch is opened. The api signature is (branch).
1351
# invoked after a push operation completes.
1352
# the api signature is
1354
# containing the members
1355
# (source, local, master, old_revno, old_revid, new_revno, new_revid)
1356
# where local is the local target branch or None, master is the target
1357
# master branch, and the rest should be self explanatory. The source
1358
# is read locked and the target branches write locked. Source will
1359
# be the local low-latency branch.
1360
self['post_push'] = []
1361
# invoked after a pull operation completes.
1362
# the api signature is
1364
# containing the members
1365
# (source, local, master, old_revno, old_revid, new_revno, new_revid)
1366
# where local is the local branch or None, master is the target
1367
# master branch, and the rest should be self explanatory. The source
1368
# is read locked and the target branches write locked. The local
1369
# branch is the low-latency branch.
1370
self['post_pull'] = []
1371
# invoked before a commit operation takes place.
1372
# the api signature is
1373
# (local, master, old_revno, old_revid, future_revno, future_revid,
1374
# tree_delta, future_tree).
1375
# old_revid is NULL_REVISION for the first commit to a branch
1376
# tree_delta is a TreeDelta object describing changes from the basis
1377
# revision, hooks MUST NOT modify this delta
1378
# future_tree is an in-memory tree obtained from
1379
# CommitBuilder.revision_tree() and hooks MUST NOT modify this tree
1380
self['pre_commit'] = []
1381
# invoked after a commit operation completes.
1382
# the api signature is
1383
# (local, master, old_revno, old_revid, new_revno, new_revid)
1384
# old_revid is NULL_REVISION for the first commit to a branch.
1385
self['post_commit'] = []
1386
# invoked after a uncommit operation completes.
1387
# the api signature is
1388
# (local, master, old_revno, old_revid, new_revno, new_revid) where
1389
# local is the local branch or None, master is the target branch,
1390
# and an empty branch recieves new_revno of 0, new_revid of None.
1391
self['post_uncommit'] = []
1393
# Invoked before the tip of a branch changes.
1394
# the api signature is
1395
# (params) where params is a ChangeBranchTipParams with the members
1396
# (branch, old_revno, new_revno, old_revid, new_revid)
1397
self['pre_change_branch_tip'] = []
1399
# Invoked after the tip of a branch changes.
1400
# the api signature is
1401
# (params) where params is a ChangeBranchTipParams with the members
1402
# (branch, old_revno, new_revno, old_revid, new_revid)
1403
self['post_change_branch_tip'] = []
1405
# Invoked when a stacked branch activates its fallback locations and
1406
# allows the transformation of the url of said location.
1407
# the api signature is
1408
# (branch, url) where branch is the branch having its fallback
1409
# location activated and url is the url for the fallback location.
1410
# The hook should return a url.
1411
self['transform_fallback_location'] = []
1684
1414
# install the default hooks into the Branch class.
1873
1610
return self._initialize_helper(a_bzrdir, utf8_files)
1875
def make_tags(self, branch):
1876
"""See bzrlib.branch.BranchFormat.make_tags()."""
1877
return BasicTags(branch)
1879
def supports_set_append_revisions_only(self):
1883
class BzrBranchFormat8(BranchFormatMetadir):
1884
"""Metadir format supporting storing locations of subtree branches."""
1886
def _branch_class(self):
1889
def get_format_string(self):
1890
"""See BranchFormat.get_format_string()."""
1891
return "Bazaar Branch Format 8 (needs bzr 1.15)\n"
1893
def get_format_description(self):
1894
"""See BranchFormat.get_format_description()."""
1895
return "Branch format 8"
1897
def initialize(self, a_bzrdir):
1898
"""Create a branch of this format in a_bzrdir."""
1899
utf8_files = [('last-revision', '0 null:\n'),
1900
('branch.conf', ''),
1904
return self._initialize_helper(a_bzrdir, utf8_files)
1907
super(BzrBranchFormat8, self).__init__()
1908
self._matchingbzrdir.repository_format = \
1909
RepositoryFormatKnitPack5RichRoot()
1911
def make_tags(self, branch):
1912
"""See bzrlib.branch.BranchFormat.make_tags()."""
1913
return BasicTags(branch)
1915
def supports_set_append_revisions_only(self):
1918
def supports_stacking(self):
1921
supports_reference_locations = True
1924
class BzrBranchFormat7(BzrBranchFormat8):
1613
class BzrBranchFormat7(BranchFormatMetadir):
1925
1614
"""Branch format with last-revision, tags, and a stacked location pointer.
1927
1616
The stacked location pointer is passed down to the repository and requires
2124
1806
base = property(_get_base, doc="The URL for the root of this branch.")
2126
def _get_config(self):
2127
return TransportConfig(self._transport, 'branch.conf')
2129
1808
def is_locked(self):
2130
1809
return self.control_files.is_locked()
2132
1811
def lock_write(self, token=None):
2133
if not self.is_locked():
2134
self._note_lock('w')
2135
# All-in-one needs to always unlock/lock.
2136
repo_control = getattr(self.repository, 'control_files', None)
2137
if self.control_files == repo_control or not self.is_locked():
2138
self.repository._warn_if_deprecated(self)
2139
self.repository.lock_write()
1812
repo_token = self.repository.lock_write()
2144
return self.control_files.lock_write(token=token)
1814
token = self.control_files.lock_write(token=token)
2147
self.repository.unlock()
1816
self.repository.unlock()
2150
1820
def lock_read(self):
2151
if not self.is_locked():
2152
self._note_lock('r')
2153
# All-in-one needs to always unlock/lock.
2154
repo_control = getattr(self.repository, 'control_files', None)
2155
if self.control_files == repo_control or not self.is_locked():
2156
self.repository._warn_if_deprecated(self)
2157
self.repository.lock_read()
1821
self.repository.lock_read()
2162
1823
self.control_files.lock_read()
2165
self.repository.unlock()
1825
self.repository.unlock()
2168
@only_raises(errors.LockNotHeld, errors.LockBroken)
2169
1828
def unlock(self):
1829
# TODO: test for failed two phase locks. This is known broken.
2171
1831
self.control_files.unlock()
2173
# All-in-one needs to always unlock/lock.
2174
repo_control = getattr(self.repository, 'control_files', None)
2175
if (self.control_files == repo_control or
2176
not self.control_files.is_locked()):
2177
self.repository.unlock()
2178
if not self.control_files.is_locked():
2179
# we just released the lock
2180
self._clear_cached_state()
1833
self.repository.unlock()
1834
if not self.control_files.is_locked():
1835
# we just released the lock
1836
self._clear_cached_state()
2182
1838
def peek_lock_mode(self):
2183
1839
if self.control_files._lock_count == 0:
2302
1958
"""See Branch.basis_tree."""
2303
1959
return self.repository.revision_tree(self.last_revision())
1962
def pull(self, source, overwrite=False, stop_revision=None,
1963
_hook_master=None, run_hooks=True, possible_transports=None,
1964
_override_hook_target=None):
1967
:param _hook_master: Private parameter - set the branch to
1968
be supplied as the master to pull hooks.
1969
:param run_hooks: Private parameter - if false, this branch
1970
is being called because it's the master of the primary branch,
1971
so it should not run its hooks.
1972
:param _override_hook_target: Private parameter - set the branch to be
1973
supplied as the target_branch to pull hooks.
1975
result = PullResult()
1976
result.source_branch = source
1977
if _override_hook_target is None:
1978
result.target_branch = self
1980
result.target_branch = _override_hook_target
1983
# We assume that during 'pull' the local repository is closer than
1985
graph = self.repository.get_graph(source.repository)
1986
result.old_revno, result.old_revid = self.last_revision_info()
1987
self.update_revisions(source, stop_revision, overwrite=overwrite,
1989
result.tag_conflicts = source.tags.merge_to(self.tags, overwrite)
1990
result.new_revno, result.new_revid = self.last_revision_info()
1992
result.master_branch = _hook_master
1993
result.local_branch = result.target_branch
1995
result.master_branch = result.target_branch
1996
result.local_branch = None
1998
for hook in Branch.hooks['post_pull']:
2305
2004
def _get_parent_location(self):
2306
2005
_locs = ['parent', 'pull', 'x-pull']
2307
2006
for l in _locs:
2014
def push(self, target, overwrite=False, stop_revision=None,
2015
_override_hook_source_branch=None):
2018
This is the basic concrete implementation of push()
2020
:param _override_hook_source_branch: If specified, run
2021
the hooks passing this Branch as the source, rather than self.
2022
This is for use of RemoteBranch, where push is delegated to the
2023
underlying vfs-based Branch.
2025
# TODO: Public option to disable running hooks - should be trivial but
2027
return _run_with_write_locked_target(
2028
target, self._push_with_bound_branches, target, overwrite,
2030
_override_hook_source_branch=_override_hook_source_branch)
2032
def _push_with_bound_branches(self, target, overwrite,
2034
_override_hook_source_branch=None):
2035
"""Push from self into target, and into target's master if any.
2037
This is on the base BzrBranch class even though it doesn't support
2038
bound branches because the *target* might be bound.
2041
if _override_hook_source_branch:
2042
result.source_branch = _override_hook_source_branch
2043
for hook in Branch.hooks['post_push']:
2046
bound_location = target.get_bound_location()
2047
if bound_location and target.base != bound_location:
2048
# there is a master branch.
2050
# XXX: Why the second check? Is it even supported for a branch to
2051
# be bound to itself? -- mbp 20070507
2052
master_branch = target.get_master_branch()
2053
master_branch.lock_write()
2055
# push into the master from this branch.
2056
self._basic_push(master_branch, overwrite, stop_revision)
2057
# and push into the target branch from this. Note that we push from
2058
# this branch again, because its considered the highest bandwidth
2060
result = self._basic_push(target, overwrite, stop_revision)
2061
result.master_branch = master_branch
2062
result.local_branch = target
2066
master_branch.unlock()
2069
result = self._basic_push(target, overwrite, stop_revision)
2070
# TODO: Why set master_branch and local_branch if there's no
2071
# binding? Maybe cleaner to just leave them unset? -- mbp
2073
result.master_branch = target
2074
result.local_branch = None
2314
2078
def _basic_push(self, target, overwrite, stop_revision):
2315
2079
"""Basic implementation of push without bound branches or hooks.
2317
Must be called with source read locked and target write locked.
2081
Must be called with self read locked and target write locked.
2319
result = BranchPushResult()
2083
result = PushResult()
2320
2084
result.source_branch = self
2321
2085
result.target_branch = target
2322
2086
result.old_revno, result.old_revid = target.last_revision_info()
2323
self.update_references(target)
2324
2087
if result.old_revid != self.last_revision():
2325
2088
# We assume that during 'push' this repository is closer than
2327
2090
graph = self.repository.get_graph(target.repository)
2328
target.update_revisions(self, stop_revision,
2329
overwrite=overwrite, graph=graph)
2091
target.update_revisions(self, stop_revision, overwrite=overwrite,
2330
2093
if self._push_should_merge_tags():
2331
result.tag_conflicts = self.tags.merge_to(target.tags,
2094
result.tag_conflicts = self.tags.merge_to(target.tags, overwrite)
2333
2095
result.new_revno, result.new_revid = target.last_revision_info()
2565
2420
"""Set the parent branch"""
2566
2421
return self._get_config_location('parent_location')
2569
def _set_all_reference_info(self, info_dict):
2570
"""Replace all reference info stored in a branch.
2572
:param info_dict: A dict of {file_id: (tree_path, branch_location)}
2575
writer = rio.RioWriter(s)
2576
for key, (tree_path, branch_location) in info_dict.iteritems():
2577
stanza = rio.Stanza(file_id=key, tree_path=tree_path,
2578
branch_location=branch_location)
2579
writer.write_stanza(stanza)
2580
self._transport.put_bytes('references', s.getvalue())
2581
self._reference_info = info_dict
2584
def _get_all_reference_info(self):
2585
"""Return all the reference info stored in a branch.
2587
:return: A dict of {file_id: (tree_path, branch_location)}
2589
if self._reference_info is not None:
2590
return self._reference_info
2591
rio_file = self._transport.get('references')
2593
stanzas = rio.read_stanzas(rio_file)
2594
info_dict = dict((s['file_id'], (s['tree_path'],
2595
s['branch_location'])) for s in stanzas)
2598
self._reference_info = info_dict
2601
def set_reference_info(self, file_id, tree_path, branch_location):
2602
"""Set the branch location to use for a tree reference.
2604
:param file_id: The file-id of the tree reference.
2605
:param tree_path: The path of the tree reference in the tree.
2606
:param branch_location: The location of the branch to retrieve tree
2609
info_dict = self._get_all_reference_info()
2610
info_dict[file_id] = (tree_path, branch_location)
2611
if None in (tree_path, branch_location):
2612
if tree_path is not None:
2613
raise ValueError('tree_path must be None when branch_location'
2615
if branch_location is not None:
2616
raise ValueError('branch_location must be None when tree_path'
2618
del info_dict[file_id]
2619
self._set_all_reference_info(info_dict)
2621
def get_reference_info(self, file_id):
2622
"""Get the tree_path and branch_location for a tree reference.
2624
:return: a tuple of (tree_path, branch_location)
2626
return self._get_all_reference_info().get(file_id, (None, None))
2628
def reference_parent(self, file_id, path, possible_transports=None):
2629
"""Return the parent branch for a tree-reference file_id.
2631
:param file_id: The file_id of the tree reference
2632
:param path: The path of the file_id in the tree
2633
:return: A branch associated with the file_id
2635
branch_location = self.get_reference_info(file_id)[1]
2636
if branch_location is None:
2637
return Branch.reference_parent(self, file_id, path,
2638
possible_transports)
2639
branch_location = urlutils.join(self.base, branch_location)
2640
return Branch.open(branch_location,
2641
possible_transports=possible_transports)
2643
2423
def set_push_location(self, location):
2644
2424
"""See Branch.set_push_location."""
2645
2425
self._set_config_location('push_location', location)
2687
2467
raise errors.NotStacked(self)
2688
2468
return stacked_url
2470
def set_append_revisions_only(self, enabled):
2475
self.get_config().set_user_option('append_revisions_only', value,
2478
def set_stacked_on_url(self, url):
2479
self._check_stackable_repo()
2482
old_url = self.get_stacked_on_url()
2483
except (errors.NotStacked, errors.UnstackableBranchFormat,
2484
errors.UnstackableRepositoryFormat):
2487
# repositories don't offer an interface to remove fallback
2488
# repositories today; take the conceptually simpler option and just
2490
self.repository = self.bzrdir.find_repository()
2491
# for every revision reference the branch has, ensure it is pulled
2493
source_repository = self._get_fallback_repository(old_url)
2494
for revision_id in chain([self.last_revision()],
2495
self.tags.get_reverse_tag_dict()):
2496
self.repository.fetch(source_repository, revision_id,
2499
self._activate_fallback_location(url)
2500
# write this out after the repository is stacked to avoid setting a
2501
# stacked config that doesn't work.
2502
self._set_config_location('stacked_on_location', url)
2690
2504
def _get_append_revisions_only(self):
2691
2505
value = self.get_config().get_user_option('append_revisions_only')
2692
2506
return value == 'True'
2508
def _make_tags(self):
2509
return BasicTags(self)
2694
2511
@needs_write_lock
2695
2512
def generate_revision_history(self, revision_id, last_rev=None,
2696
2513
other_branch=None):
3040
2810
self.source.unlock()
3042
def pull(self, overwrite=False, stop_revision=None,
3043
possible_transports=None, _hook_master=None, run_hooks=True,
3044
_override_hook_target=None, local=False):
3047
:param _hook_master: Private parameter - set the branch to
3048
be supplied as the master to pull hooks.
3049
:param run_hooks: Private parameter - if false, this branch
3050
is being called because it's the master of the primary branch,
3051
so it should not run its hooks.
3052
:param _override_hook_target: Private parameter - set the branch to be
3053
supplied as the target_branch to pull hooks.
3054
:param local: Only update the local branch, and not the bound branch.
3056
# This type of branch can't be bound.
3058
raise errors.LocalRequiresBoundBranch()
3059
result = PullResult()
3060
result.source_branch = self.source
3061
if _override_hook_target is None:
3062
result.target_branch = self.target
3064
result.target_branch = _override_hook_target
3065
self.source.lock_read()
3067
# We assume that during 'pull' the target repository is closer than
3069
self.source.update_references(self.target)
3070
graph = self.target.repository.get_graph(self.source.repository)
3071
# TODO: Branch formats should have a flag that indicates
3072
# that revno's are expensive, and pull() should honor that flag.
3074
result.old_revno, result.old_revid = \
3075
self.target.last_revision_info()
3076
self.target.update_revisions(self.source, stop_revision,
3077
overwrite=overwrite, graph=graph)
3078
# TODO: The old revid should be specified when merging tags,
3079
# so a tags implementation that versions tags can only
3080
# pull in the most recent changes. -- JRV20090506
3081
result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
3083
result.new_revno, result.new_revid = self.target.last_revision_info()
3085
result.master_branch = _hook_master
3086
result.local_branch = result.target_branch
3088
result.master_branch = result.target_branch
3089
result.local_branch = None
3091
for hook in Branch.hooks['post_pull']:
3094
self.source.unlock()
3097
def push(self, overwrite=False, stop_revision=None,
3098
_override_hook_source_branch=None):
3099
"""See InterBranch.push.
3101
This is the basic concrete implementation of push()
3103
:param _override_hook_source_branch: If specified, run
3104
the hooks passing this Branch as the source, rather than self.
3105
This is for use of RemoteBranch, where push is delegated to the
3106
underlying vfs-based Branch.
3108
# TODO: Public option to disable running hooks - should be trivial but
3110
self.source.lock_read()
3112
return _run_with_write_locked_target(
3113
self.target, self._push_with_bound_branches, overwrite,
3115
_override_hook_source_branch=_override_hook_source_branch)
3117
self.source.unlock()
3119
def _push_with_bound_branches(self, overwrite, stop_revision,
3120
_override_hook_source_branch=None):
3121
"""Push from source into target, and into target's master if any.
3124
if _override_hook_source_branch:
3125
result.source_branch = _override_hook_source_branch
3126
for hook in Branch.hooks['post_push']:
3129
bound_location = self.target.get_bound_location()
3130
if bound_location and self.target.base != bound_location:
3131
# there is a master branch.
3133
# XXX: Why the second check? Is it even supported for a branch to
3134
# be bound to itself? -- mbp 20070507
3135
master_branch = self.target.get_master_branch()
3136
master_branch.lock_write()
3138
# push into the master from the source branch.
3139
self.source._basic_push(master_branch, overwrite, stop_revision)
3140
# and push into the target branch from the source. Note that we
3141
# push from the source branch again, because its considered the
3142
# highest bandwidth repository.
3143
result = self.source._basic_push(self.target, overwrite,
3145
result.master_branch = master_branch
3146
result.local_branch = self.target
3150
master_branch.unlock()
3153
result = self.source._basic_push(self.target, overwrite,
3155
# TODO: Why set master_branch and local_branch if there's no
3156
# binding? Maybe cleaner to just leave them unset? -- mbp
3158
result.master_branch = self.target
3159
result.local_branch = None
3164
2813
def is_compatible(self, source, target):
3165
2814
# GenericBranch uses the public API, so always compatible
3169
class InterToBranch5(GenericInterBranch):
3172
def _get_branch_formats_to_test():
3173
return BranchFormat._default_format, BzrBranchFormat5()
3175
def pull(self, overwrite=False, stop_revision=None,
3176
possible_transports=None, run_hooks=True,
3177
_override_hook_target=None, local=False):
3178
"""Pull from source into self, updating my master if any.
3180
:param run_hooks: Private parameter - if false, this branch
3181
is being called because it's the master of the primary branch,
3182
so it should not run its hooks.
3184
bound_location = self.target.get_bound_location()
3185
if local and not bound_location:
3186
raise errors.LocalRequiresBoundBranch()
3187
master_branch = None
3188
if not local and bound_location and self.source.base != bound_location:
3189
# not pulling from master, so we need to update master.
3190
master_branch = self.target.get_master_branch(possible_transports)
3191
master_branch.lock_write()
3194
# pull from source into master.
3195
master_branch.pull(self.source, overwrite, stop_revision,
3197
return super(InterToBranch5, self).pull(overwrite,
3198
stop_revision, _hook_master=master_branch,
3199
run_hooks=run_hooks,
3200
_override_hook_target=_override_hook_target)
3203
master_branch.unlock()
3206
2818
InterBranch.register_optimiser(GenericInterBranch)
3207
InterBranch.register_optimiser(InterToBranch5)