744
776
really matter if it's on an nfs/smb/afs/coda/... share, as long as
745
777
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
780
def __init__(self, transport=DEPRECATED_PARAMETER, init=DEPRECATED_PARAMETER,
759
781
relax_version_check=DEPRECATED_PARAMETER, _format=None,
760
782
_control_files=None, a_bzrdir=None, _repository=None):
1063
1084
def tree_config(self):
1064
1085
return TreeConfig(self)
1066
def _get_truncated_history(self, revision_id):
1067
history = self.revision_history()
1068
if revision_id is None:
1088
class BzrBranch5(BzrBranch):
1089
"""A format 5 branch. This supports new features over plan branches.
1091
It has support for a master_branch which is the data for bound branches.
1099
super(BzrBranch5, self).__init__(_format=_format,
1100
_control_files=_control_files,
1102
_repository=_repository)
1105
def pull(self, source, overwrite=False, stop_revision=None):
1106
"""Updates branch.pull to be bound branch aware."""
1107
# TODO: jam 20051230 This does work, in that 'bzr pull'
1108
# will update the master branch before updating the
1109
# local branch. However, 'source' can also already
1110
# be the master branch. Which means that we are
1111
# asking it to update from itself, before we continue.
1112
# This probably causes double downloads, etc.
1113
# So we probably want to put in an explicit check
1114
# of whether source is already the master branch.
1115
bound_location = self.get_bound_location()
1116
if source.base != bound_location:
1117
# not pulling from master, so we need to update master.
1118
master_branch = self.get_master_branch()
1120
master_branch.pull(source)
1121
source = master_branch
1122
return super(BzrBranch5, self).pull(source, overwrite, stop_revision)
1124
def get_bound_location(self):
1071
idx = history.index(revision_id)
1073
raise InvalidRevisionId(revision_id=revision, branch=self)
1074
return history[:idx+1]
1126
return self.control_files.get_utf8('bound').read()[:-1]
1127
except errors.NoSuchFile:
1076
1130
@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)
1131
def get_master_branch(self):
1132
"""Return the branch we are bound to.
1134
:return: Either a Branch, or None
1136
This could memoise the branch, but if thats done
1137
it must be revalidated on each new lock.
1138
So for now we just dont memoise it.
1139
# RBC 20060304 review this decision.
1141
bound_loc = self.get_bound_location()
1145
return Branch.open(bound_loc)
1146
except (errors.NotBranchError, errors.ConnectionError), e:
1147
raise errors.BoundBranchConnectionFailure(
1151
def set_bound_location(self, location):
1152
"""Set the target where this branch is bound to.
1154
:param location: URL to the target branch
1157
self.control_files.put_utf8('bound', location+'\n')
1160
self.control_files._transport.delete('bound')
1166
def bind(self, other):
1167
"""Bind the local branch the other branch.
1169
:param other: The branch to bind to
1172
# TODO: jam 20051230 Consider checking if the target is bound
1173
# It is debatable whether you should be able to bind to
1174
# a branch which is itself bound.
1175
# Committing is obviously forbidden,
1176
# but binding itself may not be.
1177
# Since we *have* to check at commit time, we don't
1178
# *need* to check here
1181
# we are now equal to or a suffix of other.
1183
# Since we have 'pulled' from the remote location,
1184
# now we should try to pull in the opposite direction
1185
# in case the local tree has more revisions than the
1187
# There may be a different check you could do here
1188
# rather than actually trying to install revisions remotely.
1189
# TODO: capture an exception which indicates the remote branch
1191
# If it is up-to-date, this probably should not be a failure
1193
# lock other for write so the revision-history syncing cannot race
1197
# if this does not error, other now has the same last rev we do
1198
# it can only error if the pull from other was concurrent with
1199
# a commit to other from someone else.
1201
# until we ditch revision-history, we need to sync them up:
1202
self.set_revision_history(other.revision_history())
1203
# now other and self are up to date with each other and have the
1204
# same revision-history.
1208
self.set_bound_location(other.base)
1212
"""If bound, unbind"""
1213
return self.set_bound_location(None)
1101
1216
class BranchTestProviderAdapter(object):