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):
1761
class BzrBranchFormat8(BranchFormatMetadir):
1762
"""Metadir format supporting storing locations of subtree branches."""
1764
def _branch_class(self):
1767
def get_format_string(self):
1768
"""See BranchFormat.get_format_string()."""
1769
return "Bazaar Branch Format 8 (needs bzr 1.15)\n"
1771
def get_format_description(self):
1772
"""See BranchFormat.get_format_description()."""
1773
return "Branch format 8"
1775
def initialize(self, a_bzrdir):
1776
"""Create a branch of this format in a_bzrdir."""
1777
utf8_files = [('last-revision', '0 null:\n'),
1778
('branch.conf', ''),
1782
return self._initialize_helper(a_bzrdir, utf8_files)
1785
super(BzrBranchFormat8, self).__init__()
1786
self._matchingbzrdir.repository_format = \
1787
RepositoryFormatKnitPack5RichRoot()
1789
def make_tags(self, branch):
1790
"""See bzrlib.branch.BranchFormat.make_tags()."""
1791
return BasicTags(branch)
1793
def supports_stacking(self):
1796
supports_reference_locations = True
1799
class BzrBranchFormat7(BzrBranchFormat8):
1689
1800
"""Branch format with last-revision, tags, and a stacked location pointer.
1691
1802
The stacked location pointer is passed down to the repository and requires
1705
1824
"""See BranchFormat.get_format_description()."""
1706
1825
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):
1827
supports_reference_locations = False
1729
1830
class BranchReferenceFormat(BranchFormat):
1836
1937
__format5 = BzrBranchFormat5()
1837
1938
__format6 = BzrBranchFormat6()
1838
1939
__format7 = BzrBranchFormat7()
1940
__format8 = BzrBranchFormat8()
1839
1941
BranchFormat.register_format(__format5)
1840
1942
BranchFormat.register_format(BranchReferenceFormat())
1841
1943
BranchFormat.register_format(__format6)
1842
1944
BranchFormat.register_format(__format7)
1945
BranchFormat.register_format(__format8)
1843
1946
BranchFormat.set_default_format(__format6)
1844
1947
_legacy_formats = [BzrBranchFormat4(),
1899
2002
return self.control_files.is_locked()
1901
2004
def lock_write(self, token=None):
1902
repo_token = self.repository.lock_write()
2005
# All-in-one needs to always unlock/lock.
2006
repo_control = getattr(self.repository, 'control_files', None)
2007
if self.control_files == repo_control or not self.is_locked():
2008
self.repository.lock_write()
1904
token = self.control_files.lock_write(token=token)
2013
return self.control_files.lock_write(token=token)
1906
self.repository.unlock()
2016
self.repository.unlock()
1910
2019
def lock_read(self):
1911
self.repository.lock_read()
2020
# All-in-one needs to always unlock/lock.
2021
repo_control = getattr(self.repository, 'control_files', None)
2022
if self.control_files == repo_control or not self.is_locked():
2023
self.repository.lock_read()
1913
2028
self.control_files.lock_read()
1915
self.repository.unlock()
2031
self.repository.unlock()
1918
2034
def unlock(self):
1919
# TODO: test for failed two phase locks. This is known broken.
1921
2036
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()
2038
# All-in-one needs to always unlock/lock.
2039
repo_control = getattr(self.repository, 'control_files', None)
2040
if (self.control_files == repo_control or
2041
not self.control_files.is_locked()):
2042
self.repository.unlock()
2043
if not self.control_files.is_locked():
2044
# we just released the lock
2045
self._clear_cached_state()
1928
2047
def peek_lock_mode(self):
1929
2048
if self.control_files._lock_count == 0:
2194
2315
'push_location', location,
2195
2316
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
2318
def _set_parent_location(self, url):
2216
2319
if url is None:
2217
2320
self._transport.delete('parent')
2366
2469
raise AssertionError(
2367
2470
"'transform_fallback_location' hook %s returned "
2368
2471
"None, not a URL." % hook_name)
2369
self._activate_fallback_location(url)
2472
self._activate_fallback_location(url, None)
2371
2474
def __init__(self, *args, **kwargs):
2372
2475
self._ignore_fallbacks = kwargs.get('ignore_fallbacks', False)
2373
super(BzrBranch7, self).__init__(*args, **kwargs)
2476
super(BzrBranch8, self).__init__(*args, **kwargs)
2374
2477
self._last_revision_info_cache = None
2375
2478
self._partial_revision_history_cache = []
2479
self._reference_info = None
2377
2481
def _clear_cached_state(self):
2378
super(BzrBranch7, self)._clear_cached_state()
2482
super(BzrBranch8, self)._clear_cached_state()
2379
2483
self._last_revision_info_cache = None
2380
2484
self._partial_revision_history_cache = []
2485
self._reference_info = None
2382
2487
def _last_revision_info(self):
2383
2488
revision_string = self._transport.get_bytes('last-revision')
2493
2598
"""Set the parent branch"""
2494
2599
return self._get_config_location('parent_location')
2602
def _set_all_reference_info(self, info_dict):
2603
"""Replace all reference info stored in a branch.
2605
:param info_dict: A dict of {file_id: (tree_path, branch_location)}
2608
writer = rio.RioWriter(s)
2609
for key, (tree_path, branch_location) in info_dict.iteritems():
2610
stanza = rio.Stanza(file_id=key, tree_path=tree_path,
2611
branch_location=branch_location)
2612
writer.write_stanza(stanza)
2613
self._transport.put_bytes('references', s.getvalue())
2614
self._reference_info = info_dict
2617
def _get_all_reference_info(self):
2618
"""Return all the reference info stored in a branch.
2620
:return: A dict of {file_id: (tree_path, branch_location)}
2622
if self._reference_info is not None:
2623
return self._reference_info
2624
rio_file = self._transport.get('references')
2626
stanzas = rio.read_stanzas(rio_file)
2627
info_dict = dict((s['file_id'], (s['tree_path'],
2628
s['branch_location'])) for s in stanzas)
2631
self._reference_info = info_dict
2634
def set_reference_info(self, file_id, tree_path, branch_location):
2635
"""Set the branch location to use for a tree reference.
2637
:param file_id: The file-id of the tree reference.
2638
:param tree_path: The path of the tree reference in the tree.
2639
:param branch_location: The location of the branch to retrieve tree
2642
info_dict = self._get_all_reference_info()
2643
info_dict[file_id] = (tree_path, branch_location)
2644
if None in (tree_path, branch_location):
2645
if tree_path is not None:
2646
raise ValueError('tree_path must be None when branch_location'
2648
if branch_location is not None:
2649
raise ValueError('branch_location must be None when tree_path'
2651
del info_dict[file_id]
2652
self._set_all_reference_info(info_dict)
2654
def get_reference_info(self, file_id):
2655
"""Get the tree_path and branch_location for a tree reference.
2657
:return: a tuple of (tree_path, branch_location)
2659
return self._get_all_reference_info().get(file_id, (None, None))
2661
def reference_parent(self, file_id, path, possible_transports=None):
2662
"""Return the parent branch for a tree-reference file_id.
2664
:param file_id: The file_id of the tree reference
2665
:param path: The path of the file_id in the tree
2666
:return: A branch associated with the file_id
2668
branch_location = self.get_reference_info(file_id)[1]
2669
if branch_location is None:
2670
return Branch.reference_parent(self, file_id, path,
2671
possible_transports)
2672
branch_location = urlutils.join(self.base, branch_location)
2673
return Branch.open(branch_location,
2674
possible_transports=possible_transports)
2496
2676
def set_push_location(self, location):
2497
2677
"""See Branch.set_push_location."""
2498
2678
self._set_config_location('push_location', location)
2596
2776
return self.revno() - index
2779
class BzrBranch7(BzrBranch8):
2780
"""A branch with support for a fallback repository."""
2782
def set_reference_info(self, file_id, tree_path, branch_location):
2783
Branch.set_reference_info(self, file_id, tree_path, branch_location)
2785
def get_reference_info(self, file_id):
2786
Branch.get_reference_info(self, file_id)
2788
def reference_parent(self, file_id, path, possible_transports=None):
2789
return Branch.reference_parent(self, file_id, path,
2790
possible_transports)
2599
2793
class BzrBranch6(BzrBranch7):
2600
2794
"""See BzrBranchFormat6 for the capabilities of this branch.
2742
2936
branch._transport.put_bytes('format', format.get_format_string())
2939
class Converter7to8(object):
2940
"""Perform an in-place upgrade of format 6 to format 7"""
2942
def convert(self, branch):
2943
format = BzrBranchFormat8()
2944
branch._transport.put_bytes('references', '')
2945
# update target format
2946
branch._transport.put_bytes('format', format.get_format_string())
2746
2949
def _run_with_write_locked_target(target, callable, *args, **kwargs):
2747
2950
"""Run ``callable(*args, **kwargs)``, write-locking target for the