744
787
really matter if it's on an nfs/smb/afs/coda/... share, as long as
745
788
it's writable, and can be accessed via the normal filesystem API.
747
# We actually expect this class to be somewhat short-lived; part of its
748
# purpose is to try to isolate what bits of the branch logic are tied to
749
# filesystem access, so that in a later step, we can extricate them to
750
# a separarte ("storage") class.
751
_inventory_weave = None
753
# Map some sort of prefix into a namespace
754
# stuff like "revno:10", "revid:", etc.
755
# This should match a prefix with a function which accepts
756
REVISION_NAMESPACES = {}
758
791
def __init__(self, transport=DEPRECATED_PARAMETER, init=DEPRECATED_PARAMETER,
759
792
relax_version_check=DEPRECATED_PARAMETER, _format=None,
760
793
_control_files=None, a_bzrdir=None, _repository=None):
1063
1095
def tree_config(self):
1064
1096
return TreeConfig(self)
1066
def _get_truncated_history(self, revision_id):
1067
history = self.revision_history()
1068
if revision_id is None:
1099
class BzrBranch5(BzrBranch):
1100
"""A format 5 branch. This supports new features over plan branches.
1102
It has support for a master_branch which is the data for bound branches.
1110
super(BzrBranch5, self).__init__(_format=_format,
1111
_control_files=_control_files,
1113
_repository=_repository)
1116
def pull(self, source, overwrite=False, stop_revision=None):
1117
"""Updates branch.pull to be bound branch aware."""
1118
bound_location = self.get_bound_location()
1119
if source.base != bound_location:
1120
# not pulling from master, so we need to update master.
1121
master_branch = self.get_master_branch()
1123
master_branch.pull(source)
1124
source = master_branch
1125
return super(BzrBranch5, self).pull(source, overwrite, stop_revision)
1127
def get_bound_location(self):
1071
idx = history.index(revision_id)
1073
raise InvalidRevisionId(revision_id=revision, branch=self)
1074
return history[:idx+1]
1129
return self.control_files.get_utf8('bound').read()[:-1]
1130
except errors.NoSuchFile:
1076
1133
@needs_read_lock
1077
def _clone_weave(self, to_location, revision=None, basis_branch=None):
1079
from bzrlib.workingtree import WorkingTree
1080
assert isinstance(to_location, basestring)
1081
if basis_branch is not None:
1082
note("basis_branch is not supported for fast weave copy yet.")
1084
history = self._get_truncated_history(revision)
1085
if not bzrlib.osutils.lexists(to_location):
1086
os.mkdir(to_location)
1087
bzrdir_to = self.bzrdir._format.initialize(to_location)
1088
self.repository.clone(bzrdir_to)
1089
branch_to = bzrdir_to.create_branch()
1090
mutter("copy branch from %s to %s", self, branch_to)
1092
# FIXME duplicate code with base .clone().
1093
# .. would template method be useful here? RBC 20051207
1094
branch_to.set_parent(self.base)
1095
branch_to.append_revision(*history)
1096
WorkingTree.create(branch_to, branch_to.base)
1134
def get_master_branch(self):
1135
"""Return the branch we are bound to.
1137
:return: Either a Branch, or None
1139
This could memoise the branch, but if thats done
1140
it must be revalidated on each new lock.
1141
So for now we just dont memoise it.
1142
# RBC 20060304 review this decision.
1144
bound_loc = self.get_bound_location()
1148
return Branch.open(bound_loc)
1149
except (errors.NotBranchError, errors.ConnectionError), e:
1150
raise errors.BoundBranchConnectionFailure(
1154
def set_bound_location(self, location):
1155
"""Set the target where this branch is bound to.
1157
:param location: URL to the target branch
1160
self.control_files.put_utf8('bound', location+'\n')
1163
self.control_files._transport.delete('bound')
1169
def bind(self, other):
1170
"""Bind the local branch the other branch.
1172
:param other: The branch to bind to
1175
# TODO: jam 20051230 Consider checking if the target is bound
1176
# It is debatable whether you should be able to bind to
1177
# a branch which is itself bound.
1178
# Committing is obviously forbidden,
1179
# but binding itself may not be.
1180
# Since we *have* to check at commit time, we don't
1181
# *need* to check here
1184
# we are now equal to or a suffix of other.
1186
# Since we have 'pulled' from the remote location,
1187
# now we should try to pull in the opposite direction
1188
# in case the local tree has more revisions than the
1190
# There may be a different check you could do here
1191
# rather than actually trying to install revisions remotely.
1192
# TODO: capture an exception which indicates the remote branch
1194
# If it is up-to-date, this probably should not be a failure
1196
# lock other for write so the revision-history syncing cannot race
1200
# if this does not error, other now has the same last rev we do
1201
# it can only error if the pull from other was concurrent with
1202
# a commit to other from someone else.
1204
# until we ditch revision-history, we need to sync them up:
1205
self.set_revision_history(other.revision_history())
1206
# now other and self are up to date with each other and have the
1207
# same revision-history.
1211
self.set_bound_location(other.base)
1215
"""If bound, unbind"""
1216
return self.set_bound_location(None)
1220
"""Synchronise this branch with the master branch if any.
1222
:return: None or the last_revision that was pivoted out during the
1225
master = self.get_master_branch()
1226
if master is not None:
1227
old_tip = self.last_revision()
1228
self.pull(master, overwrite=True)
1229
if old_tip in self.repository.get_ancestry(self.last_revision()):
1101
1235
class BranchTestProviderAdapter(object):