446
456
raise NotImplementedError(self.get_parent)
458
def _set_config_location(self, name, url, config=None,
459
make_relative=False):
461
config = self.get_config()
465
url = urlutils.relative_url(self.base, url)
466
config.set_user_option(name, url)
468
def _get_config_location(self, name, config=None):
470
config = self.get_config()
471
location = config.get_user_option(name)
448
476
def get_submit_branch(self):
449
477
"""Return the submit location of the branch.
464
492
self.get_config().set_user_option('submit_branch', location)
494
def get_public_branch(self):
495
"""Return the public location of the branch.
497
This is is used by merge directives.
499
return self._get_config_location('public_branch')
501
def set_public_branch(self, location):
502
"""Return the submit location of the branch.
504
This is the default location for bundle. The usual
505
pattern is that the user can override it by specifying a
508
self._set_config_location('public_branch', location)
466
510
def get_push_location(self):
467
511
"""Return the None or the location to push this branch to."""
468
512
raise NotImplementedError(self.get_push_location)
675
721
# pull up to the specified revision_id to set the initial
676
722
# branch tip correctly, and seed it with history.
677
723
checkout_branch.pull(self, stop_revision=revision_id)
678
return checkout.create_workingtree(revision_id)
724
tree = checkout.create_workingtree(revision_id)
725
basis_tree = tree.basis_tree()
726
basis_tree.lock_read()
728
for path, file_id in basis_tree.iter_references():
729
reference_parent = self.reference_parent(file_id, path)
730
reference_parent.create_checkout(tree.abspath(path),
731
basis_tree.get_reference_revision(file_id, path),
737
def reference_parent(self, file_id, path):
738
"""Return the parent branch for a tree-reference file_id
739
:param file_id: The file_id of the tree reference
740
:param path: The path of the file_id in the tree
741
:return: A branch associated with the file_id
743
# FIXME should provide multiple branches, based on config
744
return Branch.open(self.bzrdir.root_transport.clone(path).base)
746
def supports_tags(self):
747
return self._format.supports_tags()
681
750
class BranchFormat(object):
796
865
def __str__(self):
797
866
return self.get_format_string().rstrip()
868
def supports_tags(self):
869
"""True if this format supports tags stored in the branch"""
870
return False # by default
872
# XXX: Probably doesn't really belong here -- mbp 20070212
873
def _initialize_control_files(self, a_bzrdir, utf8_files, lock_filename,
875
branch_transport = a_bzrdir.get_branch_transport(self)
876
control_files = lockable_files.LockableFiles(branch_transport,
877
lock_filename, lock_class)
878
control_files.create_lock()
879
control_files.lock_write()
881
for filename, content in utf8_files:
882
control_files.put_utf8(filename, content)
884
control_files.unlock()
800
887
class BranchHooks(dict):
801
888
"""A dictionary mapping hook name to a list of callables for branch hooks.
1107
1199
upgrade/recovery type use; it's not guaranteed that
1108
1200
all operations will work on old format branches.
1202
Branch.__init__(self)
1110
1203
if a_bzrdir is None:
1111
1204
self.bzrdir = bzrdir.BzrDir.open(transport.base)
1113
1206
self.bzrdir = a_bzrdir
1114
self._transport = self.bzrdir.transport.clone('..')
1115
self._base = self._transport.base
1207
# self._transport used to point to the directory containing the
1208
# control directory, but was not used - now it's just the transport
1209
# for the branch control files. mbp 20070212
1210
self._base = self.bzrdir.transport.clone('..').base
1116
1211
self._format = _format
1117
1212
if _control_files is None:
1118
1213
raise ValueError('BzrBranch _control_files is None')
1119
1214
self.control_files = _control_files
1215
self._transport = _control_files._transport
1120
1216
if deprecated_passed(init):
1121
1217
warn("BzrBranch.__init__(..., init=XXX): The init parameter is "
1122
1218
"deprecated as of bzr 0.8. Please use Branch.create().",
1398
1496
:param _run_hooks: Private parameter - allow disabling of
1399
1497
hooks, used when pushing to a master branch.
1499
result = PullResult()
1500
result.source_branch = source
1501
result.target_branch = self
1401
1502
source.lock_read()
1403
old_count, old_tip = self.last_revision_info()
1504
result.old_revno, result.old_revid = self.last_revision_info()
1405
1506
self.update_revisions(source, stop_revision)
1406
1507
except DivergedBranches:
1407
1508
if not overwrite:
1410
self.set_revision_history(source.revision_history())
1411
new_count, new_tip = self.last_revision_info()
1511
if stop_revision is None:
1512
stop_revision = source.last_revision()
1513
self.generate_revision_history(stop_revision)
1514
result.tag_conflicts = source.tags.merge_to(self.tags)
1515
result.new_revno, result.new_revid = self.last_revision_info()
1517
result.master_branch = _hook_master
1518
result.local_branch = self
1520
result.master_branch = self
1521
result.local_branch = None
1418
1523
for hook in Branch.hooks['post_pull']:
1419
hook(source, _hook_local, _hook_master, old_count, old_tip,
1421
return new_count - old_count
1423
1526
source.unlock()
1425
1529
def _get_parent_location(self):
1426
1530
_locs = ['parent', 'pull', 'x-pull']
1441
1545
:param _run_hooks: Private parameter - allow disabling of
1442
1546
hooks, used when pushing to a master branch.
1548
result = PushResult()
1549
result.source_branch = self
1550
result.target_branch = target
1444
1551
target.lock_write()
1446
old_count, old_tip = target.last_revision_info()
1553
result.old_revno, result.old_revid = target.last_revision_info()
1448
1555
target.update_revisions(self, stop_revision)
1449
1556
except DivergedBranches:
1453
1560
target.set_revision_history(self.revision_history())
1454
new_count, new_tip = target.last_revision_info()
1561
result.tag_conflicts = self.tags.merge_to(target.tags)
1562
result.new_revno, result.new_revid = target.last_revision_info()
1564
result.master_branch = _hook_master
1565
result.local_branch = target
1567
result.master_branch = target
1568
result.local_branch = None
1457
_hook_local = target
1459
_hook_master = target
1461
1570
for hook in Branch.hooks['post_push']:
1462
hook(self, _hook_local, _hook_master, old_count, old_tip,
1464
return new_count - old_count
1466
1573
target.unlock()
1468
1576
def get_parent(self):
1469
1577
"""See Branch.get_parent."""
1806
class BzrBranchExperimental(BzrBranch5):
1807
"""Bzr experimental branch format
1810
- a revision-history file.
1812
- a lock dir guarding the branch itself
1813
- all of this stored in a branch/ subdirectory
1814
- works with shared repositories.
1815
- a tag dictionary in the branch
1817
This format is new in bzr 0.15, but shouldn't be used for real data,
1820
This class acts as it's own BranchFormat.
1823
_matchingbzrdir = bzrdir.BzrDirMetaFormat1()
1826
def get_format_string(cls):
1827
"""See BranchFormat.get_format_string()."""
1828
return "Bazaar-NG branch format experimental\n"
1831
def get_format_description(cls):
1832
"""See BranchFormat.get_format_description()."""
1833
return "Experimental branch format"
1836
def _initialize_control_files(cls, a_bzrdir, utf8_files, lock_filename,
1838
branch_transport = a_bzrdir.get_branch_transport(cls)
1839
control_files = lockable_files.LockableFiles(branch_transport,
1840
lock_filename, lock_class)
1841
control_files.create_lock()
1842
control_files.lock_write()
1844
for filename, content in utf8_files:
1845
control_files.put_utf8(filename, content)
1847
control_files.unlock()
1850
def initialize(cls, a_bzrdir):
1851
"""Create a branch of this format in a_bzrdir."""
1852
utf8_files = [('format', cls.get_format_string()),
1853
('revision-history', ''),
1854
('branch-name', ''),
1857
cls._initialize_control_files(a_bzrdir, utf8_files,
1858
'lock', lockdir.LockDir)
1859
return cls.open(a_bzrdir, _found=True)
1862
def open(cls, a_bzrdir, _found=False):
1863
"""Return the branch object for a_bzrdir
1865
_found is a private parameter, do not use it. It is used to indicate
1866
if format probing has already be done.
1869
format = BranchFormat.find_format(a_bzrdir)
1870
assert format.__class__ == cls
1871
transport = a_bzrdir.get_branch_transport(None)
1872
control_files = lockable_files.LockableFiles(transport, 'lock',
1874
return cls(_format=cls,
1875
_control_files=control_files,
1877
_repository=a_bzrdir.find_repository())
1880
def is_supported(cls):
1883
def _make_tags(self):
1884
return BasicTags(self)
1887
def supports_tags(cls):
1891
BranchFormat.register_format(BzrBranchExperimental)
1698
1894
class BzrBranch6(BzrBranch5):
1700
1896
@needs_read_lock
1787
1983
self.set_last_revision_info(prev_revno + len(revision_ids),
1788
1984
revision_ids[-1])
1790
def _set_config_location(self, name, url, config=None,
1791
make_relative=False):
1793
config = self.get_config()
1797
url = urlutils.relative_url(self.base, url)
1798
config.set_user_option(name, url)
1801
def _get_config_location(self, name, config=None):
1803
config = self.get_config()
1804
location = config.get_user_option(name)
1809
1986
@needs_write_lock
1810
1987
def _set_parent_location(self, url):
1811
1988
"""Set the parent branch"""
1907
2087
new_test.bzrdir_format = bzrdir_format
1908
2088
new_test.branch_format = branch_format
1909
2089
def make_new_test_id():
1910
new_id = "%s(%s)" % (new_test.id(), branch_format.__class__.__name__)
2090
# the format can be either a class or an instance
2091
name = getattr(branch_format, '__name__',
2092
branch_format.__class__.__name__)
2093
new_id = "%s(%s)" % (new_test.id(), name)
1911
2094
return lambda: new_id
1912
2095
new_test.id = make_new_test_id()
1913
2096
result.addTest(new_test)
2100
######################################################################
2101
# results of operations
2104
class _Result(object):
2106
def _show_tag_conficts(self, to_file):
2107
if not getattr(self, 'tag_conflicts', None):
2109
to_file.write('Conflicting tags:\n')
2110
for name, value1, value2 in self.tag_conflicts:
2111
to_file.write(' %s\n' % (name, ))
2114
class PullResult(_Result):
2115
"""Result of a Branch.pull operation.
2117
:ivar old_revno: Revision number before pull.
2118
:ivar new_revno: Revision number after pull.
2119
:ivar old_revid: Tip revision id before pull.
2120
:ivar new_revid: Tip revision id after pull.
2121
:ivar source_branch: Source (local) branch object.
2122
:ivar master_branch: Master branch of the target, or None.
2123
:ivar target_branch: Target/destination branch object.
2127
# DEPRECATED: pull used to return the change in revno
2128
return self.new_revno - self.old_revno
2130
def report(self, to_file):
2131
if self.old_revid == self.new_revid:
2132
to_file.write('No revisions to pull.\n')
2134
to_file.write('Now on revision %d.\n' % self.new_revno)
2135
self._show_tag_conficts(to_file)
2138
class PushResult(_Result):
2139
"""Result of a Branch.push operation.
2141
:ivar old_revno: Revision number before push.
2142
:ivar new_revno: Revision number after push.
2143
:ivar old_revid: Tip revision id before push.
2144
:ivar new_revid: Tip revision id after push.
2145
:ivar source_branch: Source branch object.
2146
:ivar master_branch: Master branch of the target, or None.
2147
:ivar target_branch: Target/destination branch object.
2151
# DEPRECATED: push used to return the change in revno
2152
return self.new_revno - self.old_revno
2154
def report(self, to_file):
2155
"""Write a human-readable description of the result."""
2156
if self.old_revid == self.new_revid:
2157
to_file.write('No new revisions to push.\n')
2159
to_file.write('Pushed up to revision %d.\n' % self.new_revno)
2160
self._show_tag_conficts(to_file)
1917
2163
class BranchCheckResult(object):
1918
2164
"""Results of checking branch consistency.
1934
2180
self.branch._format)
1937
######################################################################
1941
@deprecated_function(zero_eight)
1942
def is_control_file(*args, **kwargs):
1943
"""See bzrlib.workingtree.is_control_file."""
1944
from bzrlib import workingtree
1945
return workingtree.is_control_file(*args, **kwargs)
1948
2183
class Converter5to6(object):
1949
2184
"""Perform an in-place upgrade of format 5 to format 6"""