15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
from cStringIO import StringIO
20
from bzrlib.lazy_import import lazy_import
21
lazy_import(globals(), """
18
22
from copy import deepcopy
19
from cStringIO import StringIO
20
23
from unittest import TestSuite
21
24
from warnings import warn
24
27
from bzrlib import (
30
config as _mod_config,
35
revision as _mod_revision,
36
from bzrlib.config import TreeConfig
41
from bzrlib.config import BranchConfig, TreeConfig
42
from bzrlib.lockable_files import LockableFiles, TransportLock
37
45
from bzrlib.decorators import needs_read_lock, needs_write_lock
38
import bzrlib.errors as errors
39
from bzrlib.errors import (BzrError, BzrCheckError, DivergedBranches,
40
HistoryMissing, InvalidRevisionId,
41
InvalidRevisionNumber, LockError, NoSuchFile,
46
from bzrlib.errors import (BzrError, BzrCheckError, DivergedBranches,
47
HistoryMissing, InvalidRevisionId,
48
InvalidRevisionNumber, LockError, NoSuchFile,
42
49
NoSuchRevision, NoWorkingTree, NotVersionedError,
43
NotBranchError, UninitializableFormat,
44
UnlistableStore, UnlistableBranch,
50
NotBranchError, UninitializableFormat,
51
UnlistableStore, UnlistableBranch,
46
from bzrlib.lockable_files import LockableFiles, TransportLock
47
53
from bzrlib.symbol_versioning import (deprecated_function,
49
55
DEPRECATED_PARAMETER,
218
226
if last_revision is None:
219
227
pb.update('get source history')
220
from_history = from_branch.revision_history()
222
last_revision = from_history[-1]
224
# no history in the source branch
225
last_revision = revision.NULL_REVISION
228
last_revision = from_branch.last_revision_info()[1]
226
229
return self.repository.fetch(from_branch.repository,
227
230
revision_id=last_revision,
322
def last_revision_info(self):
323
"""Return information about the last revision.
325
:return: A tuple (revno, last_revision_id).
327
rh = self.revision_history()
330
return (revno, rh[-1])
332
return (0, _mod_revision.NULL_REVISION)
319
334
def missing_revisions(self, other, stop_revision=None):
320
335
"""Return a list of new revisions that would perfectly fit.
369
384
return history[revno - 1]
371
386
def pull(self, source, overwrite=False, stop_revision=None):
387
"""Mirror source into this branch.
389
This branch is considered to be 'local', having low latency.
372
391
raise NotImplementedError(self.pull)
393
def push(self, target, overwrite=False, stop_revision=None):
394
"""Mirror this branch into target.
396
This branch is considered to be 'local', having low latency.
398
raise NotImplementedError(self.push)
374
400
def basis_tree(self):
375
401
"""Return `Tree` object for last revision."""
376
402
return self.repository.revision_tree(self.last_revision())
593
619
format = self.repository.bzrdir.cloning_metadir()
596
def create_checkout(self, to_location, revision_id=None,
622
def create_checkout(self, to_location, revision_id=None,
597
623
lightweight=False):
598
624
"""Create a checkout of a branch.
671
697
def get_format_description(self):
672
698
"""Return the short format description for this format."""
673
raise NotImplementedError(self.get_format_string)
699
raise NotImplementedError(self.get_format_description)
675
701
def initialize(self, a_bzrdir):
676
702
"""Create a branch of this format in a_bzrdir."""
710
736
return self.get_format_string().rstrip()
739
class BranchHooks(dict):
740
"""A dictionary mapping hook name to a list of callables for branch hooks.
742
e.g. ['set_rh'] Is the list of items to be called when the
743
set_revision_history function is invoked.
747
"""Create the default hooks.
749
These are all empty initially, because by default nothing should get
753
# invoked whenever the revision history has been set
754
# with set_revision_history. The api signature is
755
# (branch, revision_history), and the branch will
756
# be write-locked. Introduced in 0.15.
759
def install_hook(self, hook_name, a_callable):
760
"""Install a_callable in to the hook hook_name.
762
:param hook_name: A hook name. See the __init__ method of BranchHooks
763
for the complete list of hooks.
764
:param a_callable: The callable to be invoked when the hook triggers.
765
The exact signature will depend on the hook - see the __init__
766
method of BranchHooks for details on each hook.
769
self[hook_name].append(a_callable)
771
raise errors.UnknownHook('branch', hook_name)
774
# install the default hooks into the Branch class.
775
Branch.hooks = BranchHooks()
713
778
class BzrBranchFormat4(BranchFormat):
714
779
"""Bzr branch format 4.
729
794
utf8_files = [('revision-history', ''),
730
795
('branch-name', ''),
732
control_files = LockableFiles(branch_transport, 'branch-lock',
797
control_files = lockable_files.LockableFiles(branch_transport,
798
'branch-lock', lockable_files.TransportLock)
734
799
control_files.create_lock()
735
800
control_files.lock_write()
790
855
utf8_files = [('revision-history', ''),
791
856
('branch-name', ''),
793
control_files = LockableFiles(branch_transport, 'lock', lockdir.LockDir)
858
control_files = lockable_files.LockableFiles(branch_transport, 'lock',
794
860
control_files.create_lock()
795
861
control_files.lock_write()
796
862
control_files.put_utf8('format', self.get_format_string())
815
881
format = BranchFormat.find_format(a_bzrdir)
816
882
assert format.__class__ == self.__class__
817
883
transport = a_bzrdir.get_branch_transport(None)
818
control_files = LockableFiles(transport, 'lock', lockdir.LockDir)
884
control_files = lockable_files.LockableFiles(transport, 'lock',
819
886
return BzrBranch5(_format=self,
820
887
_control_files=control_files,
821
888
a_bzrdir=a_bzrdir,
1069
1136
def append_revision(self, *revision_ids):
1070
1137
"""See Branch.append_revision."""
1071
1138
for revision_id in revision_ids:
1139
_mod_revision.check_not_reserved_id(revision_id)
1072
1140
mutter("add {%s} to revision-history" % revision_id)
1073
1141
rev_history = self.revision_history()
1074
1142
rev_history.extend(revision_ids)
1092
1160
# this call is disabled because revision_history is
1093
1161
# not really an object yet, and the transaction is for objects.
1094
1162
# transaction.register_clean(history)
1163
for hook in Branch.hooks['set_rh']:
1164
hook(self, rev_history)
1096
1166
@needs_read_lock
1097
1167
def revision_history(self):
1129
1199
# make a new revision history from the graph
1130
1200
current_rev_id = revision_id
1131
1201
new_history = []
1132
while current_rev_id not in (None, revision.NULL_REVISION):
1202
while current_rev_id not in (None, _mod_revision.NULL_REVISION):
1133
1203
new_history.append(current_rev_id)
1134
1204
current_rev_id_parents = stop_graph[current_rev_id]
1193
1263
self.set_revision_history(source.revision_history())
1194
new_count = len(self.revision_history())
1264
new_count = self.last_revision_info()[0]
1195
1265
return new_count - old_count
1197
1267
source.unlock()
1270
def push(self, target, overwrite=False, stop_revision=None):
1271
"""See Branch.push."""
1274
old_count = len(target.revision_history())
1276
target.update_revisions(self, stop_revision)
1277
except DivergedBranches:
1281
target.set_revision_history(self.revision_history())
1282
new_count = len(target.revision_history())
1283
return new_count - old_count
1199
1287
def get_parent(self):
1200
1288
"""See Branch.get_parent."""
1224
1312
def set_push_location(self, location):
1225
1313
"""See Branch.set_push_location."""
1226
self.get_config().set_user_option('push_location', location,
1314
self.get_config().set_user_option(
1315
'push_location', location,
1316
store=_mod_config.STORE_LOCATION_NORECURSE)
1229
1318
@needs_write_lock
1230
1319
def set_parent(self, url):
1274
1363
@needs_write_lock
1275
1364
def pull(self, source, overwrite=False, stop_revision=None):
1276
"""Updates branch.pull to be bound branch aware."""
1365
"""Extends branch.pull to be bound branch aware."""
1277
1366
bound_location = self.get_bound_location()
1278
1367
if source.base != bound_location:
1279
1368
# not pulling from master, so we need to update master.
1283
1372
source = master_branch
1284
1373
return super(BzrBranch5, self).pull(source, overwrite, stop_revision)
1376
def push(self, target, overwrite=False, stop_revision=None):
1377
"""Updates branch.push to be bound branch aware."""
1378
bound_location = target.get_bound_location()
1379
if target.base != bound_location:
1380
# not pushing to master, so we need to update master.
1381
master_branch = target.get_master_branch()
1383
# push into the master from this branch.
1384
super(BzrBranch5, self).push(master_branch, overwrite,
1386
# and push into the target branch from this. Note that we push from
1387
# this branch again, because its considered the highest bandwidth
1389
return super(BzrBranch5, self).push(target, overwrite, stop_revision)
1286
1391
def get_bound_location(self):
1288
1393
return self.control_files.get_utf8('bound').read()[:-1]
1445
1550
@deprecated_function(zero_eight)
1446
1551
def is_control_file(*args, **kwargs):
1447
1552
"""See bzrlib.workingtree.is_control_file."""
1448
return bzrlib.workingtree.is_control_file(*args, **kwargs)
1553
from bzrlib import workingtree
1554
return workingtree.is_control_file(*args, **kwargs)