99
101
def _open_hook(self):
100
102
"""Called by init to allow simpler extension of the base class."""
102
def _activate_fallback_location(self, url):
104
def _activate_fallback_location(self, url, lock_style):
103
105
"""Activate the branch/repository from url as a fallback repository."""
104
self.repository.add_fallback_repository(
105
self._get_fallback_repository(url))
106
repo = self._get_fallback_repository(url)
107
if lock_style == 'write':
109
elif lock_style == 'read':
111
self.repository.add_fallback_repository(repo)
107
113
def break_lock(self):
108
114
"""Break a lock if one is present from another instance.
497
503
raise errors.UpgradeRequired(self.base)
505
def set_reference_info(self, file_id, tree_path, branch_location):
506
"""Set the branch location to use for a tree reference."""
507
raise errors.UnsupportedOperation(self.set_reference_info, self)
509
def get_reference_info(self, file_id):
510
"""Get the tree_path and branch_location for a tree reference."""
511
raise errors.UnsupportedOperation(self.get_reference_info, self)
499
513
@needs_write_lock
500
514
def fetch(self, from_branch, last_revision=None, pb=None):
501
515
"""Copy revisions from from_branch into this branch.
590
604
def set_revision_history(self, rev_history):
591
605
raise NotImplementedError(self.set_revision_history)
608
def set_parent(self, url):
609
"""See Branch.set_parent."""
610
# TODO: Maybe delete old location files?
611
# URLs should never be unicode, even on the local fs,
612
# FIXUP this and get_parent in a future branch format bump:
613
# read and rewrite the file. RBC 20060125
615
if isinstance(url, unicode):
617
url = url.encode('ascii')
618
except UnicodeEncodeError:
619
raise errors.InvalidURL(url,
620
"Urls must be 7-bit ascii, "
621
"use bzrlib.urlutils.escape")
622
url = urlutils.relative_url(self.base, url)
623
self._set_parent_location(url)
593
626
def set_stacked_on_url(self, url):
594
627
"""Set the URL this branch is stacked against.
982
1015
be truncated to end with revision_id.
984
1017
result = to_bzrdir.create_branch()
985
if repository_policy is not None:
986
repository_policy.configure_branch(result)
987
self.copy_content_into(result, revision_id=revision_id)
1020
if repository_policy is not None:
1021
repository_policy.configure_branch(result)
1022
self.copy_content_into(result, revision_id=revision_id)
990
1027
@needs_read_lock
991
1028
def sprout(self, to_bzrdir, revision_id=None, repository_policy=None):
997
1034
be truncated to end with revision_id.
999
1036
result = to_bzrdir.create_branch()
1000
if repository_policy is not None:
1001
repository_policy.configure_branch(result)
1002
self.copy_content_into(result, revision_id=revision_id)
1003
result.set_parent(self.bzrdir.root_transport.base)
1039
if repository_policy is not None:
1040
repository_policy.configure_branch(result)
1041
self.copy_content_into(result, revision_id=revision_id)
1042
result.set_parent(self.bzrdir.root_transport.base)
1006
1047
def _synchronize_history(self, destination, revision_id):
1050
1092
if self._push_should_merge_tags():
1051
1093
self.tags.merge_to(destination.tags)
1095
def update_references(self, target):
1096
if not getattr(self._format, 'supports_reference_locations', False):
1098
reference_dict = self._get_all_reference_info()
1099
if len(reference_dict) == 0:
1101
old_base = self.base
1102
new_base = target.base
1103
target_reference_dict = target._get_all_reference_info()
1104
for file_id, (tree_path, branch_location) in (
1105
reference_dict.items()):
1106
branch_location = urlutils.rebase_url(branch_location,
1108
target_reference_dict.setdefault(
1109
file_id, (tree_path, branch_location))
1110
target._set_all_reference_info(target_reference_dict)
1053
1112
@needs_read_lock
1054
1113
def check(self):
1055
1114
"""Check consistency of the branch.
1105
1164
def create_clone_on_transport(self, to_transport, revision_id=None,
1165
stacked_on=None, create_prefix=False, use_existing_dir=False):
1107
1166
"""Create a clone of this branch and its bzrdir.
1109
1168
:param to_transport: The transport to clone onto.
1110
1169
:param revision_id: The revision id to use as tip in the new branch.
1111
1170
If None the tip is obtained from this branch.
1112
1171
:param stacked_on: An optional URL to stack the clone on.
1172
:param create_prefix: Create any missing directories leading up to
1174
:param use_existing_dir: Use an existing directory if one exists.
1114
1176
# XXX: Fix the bzrdir API to allow getting the branch back from the
1115
1177
# clone call. Or something. 20090224 RBC/spiv.
1116
dir_to = self.bzrdir.clone_on_transport(to_transport,
1117
revision_id=revision_id, stacked_on=stacked_on)
1178
if revision_id is None:
1179
revision_id = self.last_revision()
1181
dir_to = self.bzrdir.clone_on_transport(to_transport,
1182
revision_id=revision_id, stacked_on=stacked_on,
1183
create_prefix=create_prefix, use_existing_dir=use_existing_dir)
1184
except errors.FileExists:
1185
if not use_existing_dir:
1187
except errors.NoSuchFile:
1188
if not create_prefix:
1118
1190
return dir_to.open_branch()
1120
1192
def create_checkout(self, to_location, revision_id=None,
1174
1246
reconciler.reconcile()
1175
1247
return reconciler
1177
def reference_parent(self, file_id, path):
1249
def reference_parent(self, file_id, path, possible_transports=None):
1178
1250
"""Return the parent branch for a tree-reference file_id
1179
1251
:param file_id: The file_id of the tree reference
1180
1252
:param path: The path of the file_id in the tree
1181
1253
:return: A branch associated with the file_id
1183
1255
# FIXME should provide multiple branches, based on config
1184
return Branch.open(self.bzrdir.root_transport.clone(path).base)
1256
return Branch.open(self.bzrdir.root_transport.clone(path).base,
1257
possible_transports=possible_transports)
1186
1259
def supports_tags(self):
1187
1260
return self._format.supports_tags()
1688
class BzrBranchFormat7(BranchFormatMetadir):
1769
class BzrBranchFormat8(BranchFormatMetadir):
1770
"""Metadir format supporting storing locations of subtree branches."""
1772
def _branch_class(self):
1775
def get_format_string(self):
1776
"""See BranchFormat.get_format_string()."""
1777
return "Bazaar Branch Format 8 (needs bzr 1.15)\n"
1779
def get_format_description(self):
1780
"""See BranchFormat.get_format_description()."""
1781
return "Branch format 8"
1783
def initialize(self, a_bzrdir):
1784
"""Create a branch of this format in a_bzrdir."""
1785
utf8_files = [('last-revision', '0 null:\n'),
1786
('branch.conf', ''),
1790
return self._initialize_helper(a_bzrdir, utf8_files)
1793
super(BzrBranchFormat8, self).__init__()
1794
self._matchingbzrdir.repository_format = \
1795
RepositoryFormatKnitPack5RichRoot()
1797
def make_tags(self, branch):
1798
"""See bzrlib.branch.BranchFormat.make_tags()."""
1799
return BasicTags(branch)
1801
def supports_stacking(self):
1804
supports_reference_locations = True
1807
class BzrBranchFormat7(BzrBranchFormat8):
1689
1808
"""Branch format with last-revision, tags, and a stacked location pointer.
1691
1810
The stacked location pointer is passed down to the repository and requires
1705
1832
"""See BranchFormat.get_format_description()."""
1706
1833
return "Branch format 7"
1708
def initialize(self, a_bzrdir):
1709
"""Create a branch of this format in a_bzrdir."""
1710
utf8_files = [('last-revision', '0 null:\n'),
1711
('branch.conf', ''),
1714
return self._initialize_helper(a_bzrdir, utf8_files)
1717
super(BzrBranchFormat7, self).__init__()
1718
self._matchingbzrdir.repository_format = \
1719
RepositoryFormatKnitPack5RichRoot()
1721
def make_tags(self, branch):
1722
"""See bzrlib.branch.BranchFormat.make_tags()."""
1723
return BasicTags(branch)
1725
def supports_stacking(self):
1835
supports_reference_locations = False
1729
1838
class BranchReferenceFormat(BranchFormat):
1836
1945
__format5 = BzrBranchFormat5()
1837
1946
__format6 = BzrBranchFormat6()
1838
1947
__format7 = BzrBranchFormat7()
1948
__format8 = BzrBranchFormat8()
1839
1949
BranchFormat.register_format(__format5)
1840
1950
BranchFormat.register_format(BranchReferenceFormat())
1841
1951
BranchFormat.register_format(__format6)
1842
1952
BranchFormat.register_format(__format7)
1953
BranchFormat.register_format(__format8)
1843
1954
BranchFormat.set_default_format(__format6)
1844
1955
_legacy_formats = [BzrBranchFormat4(),
1899
2010
return self.control_files.is_locked()
1901
2012
def lock_write(self, token=None):
1902
repo_token = self.repository.lock_write()
2013
# All-in-one needs to always unlock/lock.
2014
repo_control = getattr(self.repository, 'control_files', None)
2015
if self.control_files == repo_control or not self.is_locked():
2016
self.repository.lock_write()
1904
token = self.control_files.lock_write(token=token)
2021
return self.control_files.lock_write(token=token)
1906
self.repository.unlock()
2024
self.repository.unlock()
1910
2027
def lock_read(self):
1911
self.repository.lock_read()
2028
# All-in-one needs to always unlock/lock.
2029
repo_control = getattr(self.repository, 'control_files', None)
2030
if self.control_files == repo_control or not self.is_locked():
2031
self.repository.lock_read()
1913
2036
self.control_files.lock_read()
1915
self.repository.unlock()
2039
self.repository.unlock()
1918
2042
def unlock(self):
1919
# TODO: test for failed two phase locks. This is known broken.
1921
2044
self.control_files.unlock()
1923
self.repository.unlock()
1924
if not self.control_files.is_locked():
1925
# we just released the lock
1926
self._clear_cached_state()
2046
# All-in-one needs to always unlock/lock.
2047
repo_control = getattr(self.repository, 'control_files', None)
2048
if (self.control_files == repo_control or
2049
not self.control_files.is_locked()):
2050
self.repository.unlock()
2051
if not self.control_files.is_locked():
2052
# we just released the lock
2053
self._clear_cached_state()
1928
2055
def peek_lock_mode(self):
1929
2056
if self.control_files._lock_count == 0:
2194
2323
'push_location', location,
2195
2324
store=_mod_config.STORE_LOCATION_NORECURSE)
2198
def set_parent(self, url):
2199
"""See Branch.set_parent."""
2200
# TODO: Maybe delete old location files?
2201
# URLs should never be unicode, even on the local fs,
2202
# FIXUP this and get_parent in a future branch format bump:
2203
# read and rewrite the file. RBC 20060125
2205
if isinstance(url, unicode):
2207
url = url.encode('ascii')
2208
except UnicodeEncodeError:
2209
raise errors.InvalidURL(url,
2210
"Urls must be 7-bit ascii, "
2211
"use bzrlib.urlutils.escape")
2212
url = urlutils.relative_url(self.base, url)
2213
self._set_parent_location(url)
2215
2326
def _set_parent_location(self, url):
2216
2327
if url is None:
2217
2328
self._transport.delete('parent')
2366
2477
raise AssertionError(
2367
2478
"'transform_fallback_location' hook %s returned "
2368
2479
"None, not a URL." % hook_name)
2369
self._activate_fallback_location(url)
2480
self._activate_fallback_location(url, None)
2371
2482
def __init__(self, *args, **kwargs):
2372
2483
self._ignore_fallbacks = kwargs.get('ignore_fallbacks', False)
2373
super(BzrBranch7, self).__init__(*args, **kwargs)
2484
super(BzrBranch8, self).__init__(*args, **kwargs)
2374
2485
self._last_revision_info_cache = None
2375
2486
self._partial_revision_history_cache = []
2487
self._reference_info = None
2377
2489
def _clear_cached_state(self):
2378
super(BzrBranch7, self)._clear_cached_state()
2490
super(BzrBranch8, self)._clear_cached_state()
2379
2491
self._last_revision_info_cache = None
2380
2492
self._partial_revision_history_cache = []
2493
self._reference_info = None
2382
2495
def _last_revision_info(self):
2383
2496
revision_string = self._transport.get_bytes('last-revision')
2493
2606
"""Set the parent branch"""
2494
2607
return self._get_config_location('parent_location')
2610
def _set_all_reference_info(self, info_dict):
2611
"""Replace all reference info stored in a branch.
2613
:param info_dict: A dict of {file_id: (tree_path, branch_location)}
2616
writer = rio.RioWriter(s)
2617
for key, (tree_path, branch_location) in info_dict.iteritems():
2618
stanza = rio.Stanza(file_id=key, tree_path=tree_path,
2619
branch_location=branch_location)
2620
writer.write_stanza(stanza)
2621
self._transport.put_bytes('references', s.getvalue())
2622
self._reference_info = info_dict
2625
def _get_all_reference_info(self):
2626
"""Return all the reference info stored in a branch.
2628
:return: A dict of {file_id: (tree_path, branch_location)}
2630
if self._reference_info is not None:
2631
return self._reference_info
2632
rio_file = self._transport.get('references')
2634
stanzas = rio.read_stanzas(rio_file)
2635
info_dict = dict((s['file_id'], (s['tree_path'],
2636
s['branch_location'])) for s in stanzas)
2639
self._reference_info = info_dict
2642
def set_reference_info(self, file_id, tree_path, branch_location):
2643
"""Set the branch location to use for a tree reference.
2645
:param file_id: The file-id of the tree reference.
2646
:param tree_path: The path of the tree reference in the tree.
2647
:param branch_location: The location of the branch to retrieve tree
2650
info_dict = self._get_all_reference_info()
2651
info_dict[file_id] = (tree_path, branch_location)
2652
if None in (tree_path, branch_location):
2653
if tree_path is not None:
2654
raise ValueError('tree_path must be None when branch_location'
2656
if branch_location is not None:
2657
raise ValueError('branch_location must be None when tree_path'
2659
del info_dict[file_id]
2660
self._set_all_reference_info(info_dict)
2662
def get_reference_info(self, file_id):
2663
"""Get the tree_path and branch_location for a tree reference.
2665
:return: a tuple of (tree_path, branch_location)
2667
return self._get_all_reference_info().get(file_id, (None, None))
2669
def reference_parent(self, file_id, path, possible_transports=None):
2670
"""Return the parent branch for a tree-reference file_id.
2672
:param file_id: The file_id of the tree reference
2673
:param path: The path of the file_id in the tree
2674
:return: A branch associated with the file_id
2676
branch_location = self.get_reference_info(file_id)[1]
2677
if branch_location is None:
2678
return Branch.reference_parent(self, file_id, path,
2679
possible_transports)
2680
branch_location = urlutils.join(self.base, branch_location)
2681
return Branch.open(branch_location,
2682
possible_transports=possible_transports)
2496
2684
def set_push_location(self, location):
2497
2685
"""See Branch.set_push_location."""
2498
2686
self._set_config_location('push_location', location)
2596
2784
return self.revno() - index
2787
class BzrBranch7(BzrBranch8):
2788
"""A branch with support for a fallback repository."""
2790
def set_reference_info(self, file_id, tree_path, branch_location):
2791
Branch.set_reference_info(self, file_id, tree_path, branch_location)
2793
def get_reference_info(self, file_id):
2794
Branch.get_reference_info(self, file_id)
2796
def reference_parent(self, file_id, path, possible_transports=None):
2797
return Branch.reference_parent(self, file_id, path,
2798
possible_transports)
2599
2801
class BzrBranch6(BzrBranch7):
2600
2802
"""See BzrBranchFormat6 for the capabilities of this branch.
2742
2944
branch._transport.put_bytes('format', format.get_format_string())
2947
class Converter7to8(object):
2948
"""Perform an in-place upgrade of format 6 to format 7"""
2950
def convert(self, branch):
2951
format = BzrBranchFormat8()
2952
branch._transport.put_bytes('references', '')
2953
# update target format
2954
branch._transport.put_bytes('format', format.get_format_string())
2746
2957
def _run_with_write_locked_target(target, callable, *args, **kwargs):
2747
2958
"""Run ``callable(*args, **kwargs)``, write-locking target for the