21
21
from warnings import warn
24
from bzrlib import bzrdir, errors, lockdir, osutils, revision, \
36
28
from bzrlib.config import TreeConfig
37
29
from bzrlib.decorators import needs_read_lock, needs_write_lock
38
30
import bzrlib.errors as errors
139
131
return bzrdir.BzrDir.create_standalone_workingtree(base).branch
141
@deprecated_function(zero_eight)
142
133
def setup_caching(self, cache_root):
143
134
"""Subclasses that care about caching should override this, and set
144
135
up cached stores located under cache_root.
146
NOTE: This is unused.
137
# seems to be unused, 2006-01-13 mbp
138
warn('%s is deprecated' % self.setup_caching)
139
self.cache_root = cache_root
150
141
def get_config(self):
151
142
return bzrlib.config.BranchConfig(self)
159
150
nick = property(_get_nick, _set_nick)
161
152
def is_locked(self):
162
raise NotImplementedError(self.is_locked)
153
raise NotImplementedError('is_locked is abstract')
164
155
def lock_write(self):
165
raise NotImplementedError(self.lock_write)
156
raise NotImplementedError('lock_write is abstract')
167
158
def lock_read(self):
168
raise NotImplementedError(self.lock_read)
159
raise NotImplementedError('lock_read is abstract')
170
161
def unlock(self):
171
raise NotImplementedError(self.unlock)
162
raise NotImplementedError('unlock is abstract')
173
164
def peek_lock_mode(self):
174
165
"""Return lock mode for the Branch: 'r', 'w' or None"""
175
166
raise NotImplementedError(self.peek_lock_mode)
177
168
def get_physical_lock_status(self):
178
raise NotImplementedError(self.get_physical_lock_status)
169
raise NotImplementedError('get_physical_lock_status is abstract')
180
171
def abspath(self, name):
181
172
"""Return absolute filename for something in the branch
183
174
XXX: Robert Collins 20051017 what is this used for? why is it a branch
184
175
method and not a tree method.
186
raise NotImplementedError(self.abspath)
177
raise NotImplementedError('abspath is abstract')
188
179
def bind(self, other):
189
180
"""Bind the local branch the other branch.
281
272
def get_root_id(self):
282
273
"""Return the id of this branches root"""
283
raise NotImplementedError(self.get_root_id)
274
raise NotImplementedError('get_root_id is abstract')
285
276
def print_file(self, file, revision_id):
286
277
"""Print `file` to stdout."""
287
raise NotImplementedError(self.print_file)
278
raise NotImplementedError('print_file is abstract')
289
280
def append_revision(self, *revision_ids):
290
raise NotImplementedError(self.append_revision)
281
raise NotImplementedError('append_revision is abstract')
292
283
def set_revision_history(self, rev_history):
293
raise NotImplementedError(self.set_revision_history)
284
raise NotImplementedError('set_revision_history is abstract')
295
286
def revision_history(self):
296
287
"""Return sequence of revision hashes on to this branch."""
297
raise NotImplementedError(self.revision_history)
288
raise NotImplementedError('revision_history is abstract')
300
291
"""Return current revision number for this branch.
309
300
raise errors.UpgradeRequired(self.base)
311
302
def last_revision(self):
312
"""Return last revision id, or None"""
303
"""Return last patch hash, or None if no history."""
313
304
ph = self.revision_history()
346
337
:param stop_revision: Updated until the given revision
349
raise NotImplementedError(self.update_revisions)
340
raise NotImplementedError('update_revisions is abstract')
351
342
def revision_id_to_revno(self, revision_id):
352
343
"""Given a revision id, return its revno"""
365
356
if history is None:
366
357
history = self.revision_history()
367
if revno <= 0 or revno > len(history):
358
elif revno <= 0 or revno > len(history):
368
359
raise bzrlib.errors.NoSuchRevision(self, revno)
369
360
return history[revno - 1]
371
362
def pull(self, source, overwrite=False, stop_revision=None):
372
raise NotImplementedError(self.pull)
363
raise NotImplementedError('pull is abstract')
374
365
def basis_tree(self):
375
366
"""Return `Tree` object for last revision."""
381
372
This can change the directory or the filename or both.
383
raise NotImplementedError(self.rename_one)
374
raise NotImplementedError('rename_one is abstract')
385
376
def move(self, from_paths, to_name):
396
387
This returns a list of (from_path, to_path) pairs for each
397
388
entry that is moved.
399
raise NotImplementedError(self.move)
390
raise NotImplementedError('move is abstract')
401
392
def get_parent(self):
402
393
"""Return the parent location of the branch.
405
396
pattern is that the user can override it by specifying a
408
raise NotImplementedError(self.get_parent)
399
raise NotImplementedError('get_parent is abstract')
410
401
def get_submit_branch(self):
411
402
"""Return the submit location of the branch.
428
419
def get_push_location(self):
429
420
"""Return the None or the location to push this branch to."""
430
raise NotImplementedError(self.get_push_location)
421
raise NotImplementedError('get_push_location is abstract')
432
423
def set_push_location(self, location):
433
424
"""Set a new push location for this branch."""
434
raise NotImplementedError(self.set_push_location)
425
raise NotImplementedError('set_push_location is abstract')
436
427
def set_parent(self, url):
437
raise NotImplementedError(self.set_parent)
428
raise NotImplementedError('set_parent is abstract')
439
430
@needs_write_lock
440
431
def update(self):
543
534
rev = self.repository.get_revision(revision_id)
544
535
new_history = rev.get_history(self.repository)[1:]
545
536
destination.set_revision_history(new_history)
547
parent = self.get_parent()
548
except errors.InaccessibleParent, e:
549
mutter('parent was not accessible to copy: %s', e)
552
destination.set_parent(parent)
537
parent = self.get_parent()
539
destination.set_parent(parent)
581
568
mainline_parent_id = revision_id
582
569
return BranchCheckResult(self)
584
def _get_checkout_format(self):
585
"""Return the most suitable metadir for a checkout of this branch.
586
Weaves are used if this branch's repostory uses weaves.
588
if isinstance(self.bzrdir, bzrdir.BzrDirPreSplitOut):
589
from bzrlib import repository
590
format = bzrdir.BzrDirMetaFormat1()
591
format.repository_format = repository.RepositoryFormat7()
593
format = self.repository.bzrdir.cloning_metadir()
596
def create_checkout(self, to_location, revision_id=None,
598
"""Create a checkout of a branch.
600
:param to_location: The url to produce the checkout at
601
:param revision_id: The revision to check out
602
:param lightweight: If True, produce a lightweight checkout, otherwise,
603
produce a bound branch (heavyweight checkout)
604
:return: The tree of the created checkout
606
t = transport.get_transport(to_location)
609
except errors.FileExists:
612
checkout = bzrdir.BzrDirMetaFormat1().initialize_on_transport(t)
613
BranchReferenceFormat().initialize(checkout, self)
615
format = self._get_checkout_format()
616
checkout_branch = bzrdir.BzrDir.create_branch_convenience(
617
to_location, force_new_tree=False, format=format)
618
checkout = checkout_branch.bzrdir
619
checkout_branch.bind(self)
620
# pull up to the specified revision_id to set the initial
621
# branch tip correctly, and seed it with history.
622
checkout_branch.pull(self, stop_revision=revision_id)
623
return checkout.create_workingtree(revision_id)
626
572
class BranchFormat(object):
627
573
"""An encapsulation of the initialization and open routines for a format.
852
798
raise errors.UninitializableFormat(self)
853
799
mutter('creating branch reference in %s', a_bzrdir.transport.base)
854
800
branch_transport = a_bzrdir.get_branch_transport(self)
855
branch_transport.put_bytes('location',
856
target_branch.bzrdir.root_transport.base)
857
branch_transport.put_bytes('format', self.get_format_string())
801
# FIXME rbc 20060209 one j-a-ms encoding branch lands this str() cast is not needed.
802
branch_transport.put('location', StringIO(str(target_branch.bzrdir.root_transport.base)))
803
branch_transport.put('format', StringIO(self.get_format_string()))
858
804
return self.open(a_bzrdir, _found=True)
860
806
def __init__(self):
972
918
__repr__ = __str__
921
# TODO: It might be best to do this somewhere else,
922
# but it is nice for a Branch object to automatically
923
# cache it's information.
924
# Alternatively, we could have the Transport objects cache requests
925
# See the earlier discussion about how major objects (like Branch)
926
# should never expect their __del__ function to run.
927
# XXX: cache_root seems to be unused, 2006-01-13 mbp
928
if hasattr(self, 'cache_root') and self.cache_root is not None:
930
osutils.rmtree(self.cache_root)
933
self.cache_root = None
974
935
def _get_base(self):
975
936
return self._base
1099
1060
transaction = self.get_transaction()
1100
1061
history = transaction.map.find_revision_history()
1101
1062
if history is not None:
1102
# mutter("cache hit for revision-history in %s", self)
1063
mutter("cache hit for revision-history in %s", self)
1103
1064
return list(history)
1104
decode_utf8 = cache_utf8.decode
1105
history = [decode_utf8(l.rstrip('\r\n')) for l in
1106
self.control_files.get('revision-history').readlines()]
1065
history = [l.rstrip('\r\n') for l in
1066
self.control_files.get_utf8('revision-history').readlines()]
1107
1067
transaction.map.add_revision_history(history)
1108
1068
# this call is disabled because revision_history is
1109
1069
# not really an object yet, and the transaction is for objects.
1210
1170
# turn it into a url
1211
1171
if parent.startswith('/'):
1212
1172
parent = urlutils.local_path_to_url(parent.decode('utf8'))
1214
return urlutils.join(self.base[:-1], parent)
1215
except errors.InvalidURLJoin, e:
1216
raise errors.InaccessibleParent(parent, self.base)
1173
return urlutils.join(self.base[:-1], parent)
1219
1176
def get_push_location(self):
1246
1203
"use bzrlib.urlutils.escape")
1248
1205
url = urlutils.relative_url(self.base, url)
1249
self.control_files.put('parent', StringIO(url + '\n'))
1206
self.control_files.put('parent', url + '\n')
1251
1208
@deprecated_function(zero_nine)
1252
1209
def tree_config(self):
1327
1284
@needs_write_lock
1328
1285
def bind(self, other):
1329
"""Bind this branch to the branch other.
1286
"""Bind the local branch the other branch.
1331
This does not push or pull data between the branches, though it does
1332
check for divergence to raise an error when the branches are not
1333
either the same, or one a prefix of the other. That behaviour may not
1334
be useful, so that check may be removed in future.
1336
1288
:param other: The branch to bind to
1337
1289
:type other: Branch
1343
1295
# but binding itself may not be.
1344
1296
# Since we *have* to check at commit time, we don't
1345
1297
# *need* to check here
1347
# we want to raise diverged if:
1348
# last_rev is not in the other_last_rev history, AND
1349
# other_last_rev is not in our history, and do it without pulling
1351
last_rev = self.last_revision()
1352
if last_rev is not None:
1355
other_last_rev = other.last_revision()
1356
if other_last_rev is not None:
1357
# neither branch is new, we have to do some work to
1358
# ascertain diversion.
1359
remote_graph = other.repository.get_revision_graph(
1361
local_graph = self.repository.get_revision_graph(last_rev)
1362
if (last_rev not in remote_graph and
1363
other_last_rev not in local_graph):
1364
raise errors.DivergedBranches(self, other)
1300
# we are now equal to or a suffix of other.
1302
# Since we have 'pulled' from the remote location,
1303
# now we should try to pull in the opposite direction
1304
# in case the local tree has more revisions than the
1306
# There may be a different check you could do here
1307
# rather than actually trying to install revisions remotely.
1308
# TODO: capture an exception which indicates the remote branch
1310
# If it is up-to-date, this probably should not be a failure
1312
# lock other for write so the revision-history syncing cannot race
1316
# if this does not error, other now has the same last rev we do
1317
# it can only error if the pull from other was concurrent with
1318
# a commit to other from someone else.
1320
# until we ditch revision-history, we need to sync them up:
1321
self.set_revision_history(other.revision_history())
1322
# now other and self are up to date with each other and have the
1323
# same revision-history.
1367
1327
self.set_bound_location(other.base)
1369
1329
@needs_write_lock