59
from bzrlib.smart.client import _SmartClient
60
60
from bzrlib.store.revision.text import TextRevisionStore
61
61
from bzrlib.store.text import TextStore
62
62
from bzrlib.store.versioned import WeaveStore
63
63
from bzrlib.transactions import WriteTransaction
64
from bzrlib.transport import get_transport
64
from bzrlib.transport import (
65
do_catching_redirections,
65
68
from bzrlib.weave import Weave
68
from bzrlib.trace import mutter, note
71
from bzrlib.trace import (
69
75
from bzrlib.transport.local import LocalTransport
87
93
If there is a tree, the tree is opened and break_lock() called.
88
94
Otherwise, branch is tried, and finally repository.
96
# XXX: This seems more like a UI function than something that really
97
# belongs in this class.
91
99
thing_to_unlock = self.open_workingtree()
92
100
except (errors.NotLocalUrl, errors.NoWorkingTree):
109
117
source_repo_format.check_conversion_target(target_repo_format)
112
def _check_supported(format, allow_unsupported):
113
"""Check whether format is a supported format.
115
If allow_unsupported is True, this is a no-op.
120
def _check_supported(format, allow_unsupported,
121
recommend_upgrade=True,
123
"""Give an error or warning on old formats.
125
:param format: may be any kind of format - workingtree, branch,
128
:param allow_unsupported: If true, allow opening
129
formats that are strongly deprecated, and which may
130
have limited functionality.
132
:param recommend_upgrade: If true (default), warn
133
the user through the ui object that they may wish
134
to upgrade the object.
136
# TODO: perhaps move this into a base Format class; it's not BzrDir
137
# specific. mbp 20070323
117
138
if not allow_unsupported and not format.is_supported():
118
139
# see open_downlevel to open legacy branches.
119
140
raise errors.UnsupportedFormatError(format=format)
141
if recommend_upgrade \
142
and getattr(format, 'upgrade_recommended', False):
143
ui.ui_factory.recommend_upgrade(
144
format.get_format_description(),
121
def clone(self, url, revision_id=None, basis=None, force_new_repo=False):
147
def clone(self, url, revision_id=None, force_new_repo=False):
122
148
"""Clone this bzrdir and its contents to url verbatim.
124
150
If urls last component does not exist, it will be created.
140
165
if force_new_repo:
141
166
result_repo = local_repo.clone(
143
revision_id=revision_id,
168
revision_id=revision_id)
145
169
result_repo.set_make_working_trees(local_repo.make_working_trees())
148
172
result_repo = result.find_repository()
149
173
# fetch content this dir needs.
151
# XXX FIXME RBC 20060214 need tests for this when the basis
153
result_repo.fetch(basis_repo, revision_id=revision_id)
154
174
result_repo.fetch(local_repo, revision_id=revision_id)
155
175
except errors.NoRepositoryPresent:
156
176
# needed to make one anyway.
157
177
result_repo = local_repo.clone(
159
revision_id=revision_id,
179
revision_id=revision_id)
161
180
result_repo.set_make_working_trees(local_repo.make_working_trees())
162
181
# 1 if there is a branch present
163
182
# make sure its content is available in the target repository
167
186
except errors.NotBranchError:
170
self.open_workingtree().clone(result, basis=basis_tree)
189
self.open_workingtree().clone(result)
171
190
except (errors.NoWorkingTree, errors.NotLocalUrl):
175
def _get_basis_components(self, basis):
176
"""Retrieve the basis components that are available at basis."""
178
return None, None, None
180
basis_tree = basis.open_workingtree()
181
basis_branch = basis_tree.branch
182
basis_repo = basis_branch.repository
183
except (errors.NoWorkingTree, errors.NotLocalUrl):
186
basis_branch = basis.open_branch()
187
basis_repo = basis_branch.repository
188
except errors.NotBranchError:
191
basis_repo = basis.open_repository()
192
except errors.NoRepositoryPresent:
194
return basis_repo, basis_branch, basis_tree
196
194
# TODO: This should be given a Transport, and should chdir up; otherwise
197
195
# this will open a new connection.
198
196
def _make_tail(self, url):
419
if ((found_bzrdir.root_transport.base ==
417
if ((found_bzrdir.root_transport.base ==
420
418
self.root_transport.base) or repository.is_shared()):
421
419
return repository
423
421
raise errors.NoRepositoryPresent(self)
424
422
raise errors.NoRepositoryPresent(self)
424
def get_branch_reference(self):
425
"""Return the referenced URL for the branch in this bzrdir.
427
:raises NotBranchError: If there is no Branch.
428
:return: The URL the branch in this bzrdir references if it is a
429
reference branch, or None for regular branches.
426
433
def get_branch_transport(self, branch_format):
427
434
"""Get the transport for use by branch format in this BzrDir.
520
527
return BzrDir.open_from_transport(t, _unsupported=_unsupported)
523
def open_from_transport(transport, _unsupported=False):
530
def open_from_transport(transport, _unsupported=False,
531
_server_formats=True):
524
532
"""Open a bzrdir within a particular directory.
526
534
:param transport: Transport containing the bzrdir.
527
535
:param _unsupported: private.
529
format = BzrDirFormat.find_format(transport)
537
base = transport.base
539
def find_format(transport):
540
return transport, BzrDirFormat.find_format(
541
transport, _server_formats=_server_formats)
543
def redirected(transport, e, redirection_notice):
544
qualified_source = e.get_source_url()
545
relpath = transport.relpath(qualified_source)
546
if not e.target.endswith(relpath):
547
# Not redirected to a branch-format, not a branch
548
raise errors.NotBranchError(path=e.target)
549
target = e.target[:-len(relpath)]
550
note('%s is%s redirected to %s',
551
transport.base, e.permanently, target)
552
# Let's try with a new transport
553
qualified_target = e.get_target_url()[:-len(relpath)]
554
# FIXME: If 'transport' has a qualifier, this should
555
# be applied again to the new transport *iff* the
556
# schemes used are the same. It's a bit tricky to
557
# verify, so I'll punt for now
559
return get_transport(target)
562
transport, format = do_catching_redirections(find_format,
565
except errors.TooManyRedirections:
566
raise errors.NotBranchError(base)
530
568
BzrDir._check_supported(format, _unsupported)
531
569
return format.open(transport, _found=True)
572
610
return result, urlutils.unescape(a_transport.relpath(url))
573
611
except errors.NotBranchError, e:
575
new_t = a_transport.clone('..')
614
new_t = a_transport.clone('..')
615
except errors.InvalidURLJoin:
616
# reached the root, whatever that may be
617
raise errors.NotBranchError(path=url)
576
618
if new_t.base == a_transport.base:
577
619
# reached the root, whatever that may be
578
620
raise errors.NotBranchError(path=url)
611
653
raise NotImplementedError(self.open_repository)
613
def open_workingtree(self, _unsupported=False):
655
def open_workingtree(self, _unsupported=False,
656
recommend_upgrade=True):
614
657
"""Open the workingtree object at this BzrDir if one is present.
616
TODO: static convenience version of this?
659
:param recommend_upgrade: Optional keyword parameter, when True (the
660
default), emit through the ui module a recommendation that the user
661
upgrade the working tree when the workingtree being opened is old
662
(but still fully supported).
618
664
raise NotImplementedError(self.open_workingtree)
641
687
workingtree and discards it, and that's somewhat expensive.)
644
self.open_workingtree()
690
self.open_workingtree(recommend_upgrade=False)
646
692
except errors.NoWorkingTree:
649
def _cloning_metadir(self, basis=None):
650
def related_repository(bzrdir):
695
def _cloning_metadir(self):
696
"""Produce a metadir suitable for cloning with"""
697
result_format = self._format.__class__()
652
branch = bzrdir.open_branch()
653
return branch.repository
700
branch = self.open_branch()
701
source_repository = branch.repository
654
702
except errors.NotBranchError:
655
703
source_branch = None
656
return bzrdir.open_repository()
657
result_format = self._format.__class__()
660
source_repository = related_repository(self)
661
except errors.NoRepositoryPresent:
664
source_repository = related_repository(self)
665
result_format.repository_format = source_repository._format
704
source_repository = self.open_repository()
666
705
except errors.NoRepositoryPresent:
667
706
source_repository = None
708
# XXX TODO: This isinstance is here because we have not implemented
709
# the fix recommended in bug # 103195 - to delegate this choice the
711
repo_format = source_repository._format
712
if not isinstance(repo_format, remote.RemoteRepositoryFormat):
713
result_format.repository_format = repo_format
669
tree = self.open_workingtree()
715
# TODO: Couldn't we just probe for the format in these cases,
716
# rather than opening the whole tree? It would be a little
717
# faster. mbp 20070401
718
tree = self.open_workingtree(recommend_upgrade=False)
670
719
except (errors.NoWorkingTree, errors.NotLocalUrl):
671
720
result_format.workingtree_format = None
673
722
result_format.workingtree_format = tree._format.__class__()
674
723
return result_format, source_repository
676
def cloning_metadir(self, basis=None):
725
def cloning_metadir(self):
677
726
"""Produce a metadir suitable for cloning or sprouting with.
679
728
These operations may produce workingtrees (yes, even though they're
691
740
def checkout_metadir(self):
692
741
return self.cloning_metadir()
694
def sprout(self, url, revision_id=None, basis=None, force_new_repo=False,
743
def sprout(self, url, revision_id=None, force_new_repo=False,
696
745
"""Create a copy of this bzrdir prepared for use as a new line of
707
756
itself to download less data.
709
758
self._make_tail(url)
710
cloning_format = self.cloning_metadir(basis)
759
cloning_format = self.cloning_metadir()
711
760
result = cloning_format.initialize(url)
712
basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
714
762
source_branch = self.open_branch()
715
763
source_repository = source_branch.repository
741
787
result_repo = result.create_repository()
742
788
if result_repo is not None:
743
789
# fetch needed content into target.
745
# XXX FIXME RBC 20060214 need tests for this when the basis
747
result_repo.fetch(basis_repo, revision_id=revision_id)
748
790
if source_repository is not None:
749
791
result_repo.fetch(source_repository, revision_id=revision_id)
750
792
if source_branch is not None:
810
852
"""Pre-splitout bzrdirs do not suffer from stale locks."""
811
853
raise NotImplementedError(self.break_lock)
813
def clone(self, url, revision_id=None, basis=None, force_new_repo=False):
855
def clone(self, url, revision_id=None, force_new_repo=False):
814
856
"""See BzrDir.clone()."""
815
857
from bzrlib.workingtree import WorkingTreeFormat2
816
858
self._make_tail(url)
817
859
result = self._format._initialize_for_clone(url)
818
basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
819
self.open_repository().clone(result, revision_id=revision_id, basis=basis_repo)
860
self.open_repository().clone(result, revision_id=revision_id)
820
861
from_branch = self.open_branch()
821
862
from_branch.clone(result, revision_id=revision_id)
823
self.open_workingtree().clone(result, basis=basis_tree)
864
self.open_workingtree().clone(result)
824
865
except errors.NotLocalUrl:
825
866
# make a new one, this format always has to have one.
844
885
def create_workingtree(self, revision_id=None):
845
886
"""See BzrDir.create_workingtree."""
846
887
# this looks buggy but is not -really-
888
# because this format creates the workingtree when the bzrdir is
847
890
# clone and sprout will have set the revision_id
848
891
# and that will have set it for us, its only
849
892
# specific uses of create_workingtree in isolation
850
893
# that can do wonky stuff here, and that only
851
894
# happens for creating checkouts, which cannot be
852
895
# done on this format anyway. So - acceptable wart.
853
result = self.open_workingtree()
896
result = self.open_workingtree(recommend_upgrade=False)
854
897
if revision_id is not None:
855
898
if revision_id == _mod_revision.NULL_REVISION:
856
899
result.set_parent_ids([])
912
955
self._check_supported(format, unsupported)
913
956
return format.open(self, _found=True)
915
def sprout(self, url, revision_id=None, basis=None, force_new_repo=False):
958
def sprout(self, url, revision_id=None, force_new_repo=False):
916
959
"""See BzrDir.sprout()."""
917
960
from bzrlib.workingtree import WorkingTreeFormat2
918
961
self._make_tail(url)
919
962
result = self._format._initialize_for_clone(url)
920
basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
922
self.open_repository().clone(result, revision_id=revision_id, basis=basis_repo)
964
self.open_repository().clone(result, revision_id=revision_id)
923
965
except errors.NoRepositoryPresent:
962
1004
from bzrlib.repofmt.weaverepo import RepositoryFormat5
963
1005
return RepositoryFormat5().open(self, _found=True)
965
def open_workingtree(self, _unsupported=False):
1007
def open_workingtree(self, _unsupported=False,
1008
recommend_upgrade=True):
966
1009
"""See BzrDir.create_workingtree."""
967
1010
from bzrlib.workingtree import WorkingTreeFormat2
968
return WorkingTreeFormat2().open(self, _found=True)
1011
wt_format = WorkingTreeFormat2()
1012
# we don't warn here about upgrades; that ought to be handled for the
1014
return wt_format.open(self, _found=True)
971
1017
class BzrDir6(BzrDirPreSplitOut):
979
1025
from bzrlib.repofmt.weaverepo import RepositoryFormat6
980
1026
return RepositoryFormat6().open(self, _found=True)
982
def open_workingtree(self, _unsupported=False):
1028
def open_workingtree(self, _unsupported=False,
1029
recommend_upgrade=True):
983
1030
"""See BzrDir.create_workingtree."""
1031
# we don't warn here about upgrades; that ought to be handled for the
984
1033
from bzrlib.workingtree import WorkingTreeFormat2
985
1034
return WorkingTreeFormat2().open(self, _found=True)
1014
1063
def destroy_workingtree(self):
1015
1064
"""See BzrDir.destroy_workingtree."""
1016
wt = self.open_workingtree()
1065
wt = self.open_workingtree(recommend_upgrade=False)
1017
1066
repository = wt.branch.repository
1018
1067
empty = repository.revision_tree(_mod_revision.NULL_REVISION)
1019
1068
wt.revert([], old_tree=empty)
1022
1071
def destroy_workingtree_metadata(self):
1023
1072
self.transport.delete_tree('checkout')
1074
def find_branch_format(self):
1075
"""Find the branch 'format' for this bzrdir.
1077
This might be a synthetic object for e.g. RemoteBranch and SVN.
1079
from bzrlib.branch import BranchFormat
1080
return BranchFormat.find_format(self)
1025
1082
def _get_mkdir_mode(self):
1026
1083
"""Figure out the mode to use when creating a bzrdir subdir."""
1027
1084
temp_control = lockable_files.LockableFiles(self.transport, '',
1028
1085
lockable_files.TransportLock)
1029
1086
return temp_control._dir_mode
1088
def get_branch_reference(self):
1089
"""See BzrDir.get_branch_reference()."""
1090
from bzrlib.branch import BranchFormat
1091
format = BranchFormat.find_format(self)
1092
return format.get_reference(self)
1031
1094
def get_branch_transport(self, branch_format):
1032
1095
"""See BzrDir.get_branch_transport()."""
1033
1096
if branch_format is None:
1093
1156
except errors.NotBranchError:
1096
if not isinstance(self.open_workingtree()._format,
1159
my_wt = self.open_workingtree(recommend_upgrade=False)
1160
if not isinstance(my_wt._format,
1097
1161
format.workingtree_format.__class__):
1098
1162
# the workingtree needs an upgrade.
1104
1168
def open_branch(self, unsupported=False):
1105
1169
"""See BzrDir.open_branch."""
1106
from bzrlib.branch import BranchFormat
1107
format = BranchFormat.find_format(self)
1170
format = self.find_branch_format()
1108
1171
self._check_supported(format, unsupported)
1109
1172
return format.open(self, _found=True)
1115
1178
self._check_supported(format, unsupported)
1116
1179
return format.open(self, _found=True)
1118
def open_workingtree(self, unsupported=False):
1181
def open_workingtree(self, unsupported=False,
1182
recommend_upgrade=True):
1119
1183
"""See BzrDir.open_workingtree."""
1120
1184
from bzrlib.workingtree import WorkingTreeFormat
1121
1185
format = WorkingTreeFormat.find_format(self)
1122
self._check_supported(format, unsupported)
1186
self._check_supported(format, unsupported,
1188
basedir=self.root_transport.base)
1123
1189
return format.open(self, _found=True)
1152
1218
This is a list of BzrDirFormat objects.
1221
_control_server_formats = []
1222
"""The registered control server formats, e.g. RemoteBzrDirs.
1224
This is a list of BzrDirFormat objects.
1155
1227
_lock_file_name = 'branch-lock'
1157
1229
# _lock_class must be set in subclasses to the lock type, typ.
1158
1230
# TransportLock or LockDir
1161
def find_format(klass, transport):
1233
def find_format(klass, transport, _server_formats=True):
1162
1234
"""Return the format present at transport."""
1163
for format in klass._control_formats:
1236
formats = klass._control_server_formats + klass._control_formats
1238
formats = klass._control_formats
1239
for format in formats:
1165
1241
return format.probe_transport(transport)
1166
1242
except errors.NotBranchError:
1172
1248
def probe_transport(klass, transport):
1173
"""Return the .bzrdir style transport present at URL."""
1249
"""Return the .bzrdir style format present in a directory."""
1175
1251
format_string = transport.get(".bzr/branch-format").read()
1176
1252
except errors.NoSuchFile:
1308
1384
def register_control_format(klass, format):
1309
"""Register a format that does not use '.bzrdir' for its control dir.
1385
"""Register a format that does not use '.bzr' for its control dir.
1311
1387
TODO: This should be pulled up into a 'ControlDirFormat' base class
1312
1388
which BzrDirFormat can inherit from, and renamed to register_format
1316
1392
klass._control_formats.append(format)
1395
def register_control_server_format(klass, format):
1396
"""Register a control format for client-server environments.
1398
These formats will be tried before ones registered with
1399
register_control_format. This gives implementations that decide to the
1400
chance to grab it before anything looks at the contents of the format
1403
klass._control_server_formats.append(format)
1319
1406
@symbol_versioning.deprecated_method(symbol_versioning.zero_fourteen)
1320
1407
def set_default_format(klass, format):
1321
1408
klass._set_default_format(format)
1598
1681
__set_workingtree_format)
1684
# Register bzr control format
1685
BzrDirFormat.register_control_format(BzrDirFormat)
1687
# Register bzr formats
1601
1688
BzrDirFormat.register_format(BzrDirFormat4())
1602
1689
BzrDirFormat.register_format(BzrDirFormat5())
1603
1690
BzrDirFormat.register_format(BzrDirFormat6())
1615
1702
easy to identify.
1618
def __init__(self, transport_server, transport_readonly_server, formats):
1705
def __init__(self, vfs_factory, transport_server, transport_readonly_server,
1707
"""Create an object to adapt tests.
1709
:param vfs_server: A factory to create a Transport Server which has
1710
all the VFS methods working, and is writable.
1712
self._vfs_factory = vfs_factory
1619
1713
self._transport_server = transport_server
1620
1714
self._transport_readonly_server = transport_readonly_server
1621
1715
self._formats = formats
1624
1718
result = unittest.TestSuite()
1625
1719
for format in self._formats:
1626
1720
new_test = deepcopy(test)
1721
new_test.vfs_transport_factory = self._vfs_factory
1627
1722
new_test.transport_server = self._transport_server
1628
1723
new_test.transport_readonly_server = self._transport_readonly_server
1629
1724
new_test.bzrdir_format = format
2109
2204
branch_converter = _mod_branch.Converter5to6()
2110
2205
branch_converter.convert(branch)
2112
tree = self.bzrdir.open_workingtree()
2207
tree = self.bzrdir.open_workingtree(recommend_upgrade=False)
2113
2208
except (errors.NoWorkingTree, errors.NotLocalUrl):
2123
2218
return to_convert
2221
# This is not in remote.py because it's small, and needs to be registered.
2222
# Putting it in remote.py creates a circular import problem.
2223
# we can make it a lazy object if the control formats is turned into something
2225
class RemoteBzrDirFormat(BzrDirMetaFormat1):
2226
"""Format representing bzrdirs accessed via a smart server"""
2228
def get_format_description(self):
2229
return 'bzr remote bzrdir'
2232
def probe_transport(klass, transport):
2233
"""Return a RemoteBzrDirFormat object if it looks possible."""
2235
transport.get_smart_client()
2236
except (NotImplementedError, AttributeError,
2237
errors.TransportNotPossible):
2238
# no smart server, so not a branch for this format type.
2239
raise errors.NotBranchError(path=transport.base)
2243
def initialize_on_transport(self, transport):
2245
# hand off the request to the smart server
2246
medium = transport.get_smart_medium()
2247
except errors.NoSmartMedium:
2248
# TODO: lookup the local format from a server hint.
2249
local_dir_format = BzrDirMetaFormat1()
2250
return local_dir_format.initialize_on_transport(transport)
2251
client = _SmartClient(medium)
2252
path = client.remote_path_from_transport(transport)
2253
response = _SmartClient(medium).call('BzrDirFormat.initialize', path)
2254
assert response[0] in ('ok', ), 'unexpected response code %s' % (response,)
2255
return remote.RemoteBzrDir(transport)
2257
def _open(self, transport):
2258
return remote.RemoteBzrDir(transport)
2260
def __eq__(self, other):
2261
if not isinstance(other, RemoteBzrDirFormat):
2263
return self.get_format_description() == other.get_format_description()
2266
BzrDirFormat.register_control_server_format(RemoteBzrDirFormat)
2126
2269
class BzrDirFormatInfo(object):
2128
def __init__(self, native, deprecated):
2271
def __init__(self, native, deprecated, hidden):
2129
2272
self.deprecated = deprecated
2130
2273
self.native = native
2274
self.hidden = hidden
2133
2277
class BzrDirFormatRegistry(registry.Registry):
2140
2284
def register_metadir(self, key,
2141
2285
repository_format, help, native=True, deprecated=False,
2142
2286
branch_format=None,
2144
2289
"""Register a metadir subformat.
2146
2291
These all use a BzrDirMetaFormat1 bzrdir, but can be parameterized
2178
2323
if repository_format is not None:
2179
2324
bd.repository_format = _load(repository_format)
2181
self.register(key, helper, help, native, deprecated)
2326
self.register(key, helper, help, native, deprecated, hidden)
2183
def register(self, key, factory, help, native=True, deprecated=False):
2328
def register(self, key, factory, help, native=True, deprecated=False,
2184
2330
"""Register a BzrDirFormat factory.
2186
2332
The factory must be a callable that takes one parameter: the key.
2190
2336
supplied directly.
2192
2338
registry.Registry.register(self, key, factory, help,
2193
BzrDirFormatInfo(native, deprecated))
2339
BzrDirFormatInfo(native, deprecated, hidden))
2195
2341
def register_lazy(self, key, module_name, member_name, help, native=True,
2342
deprecated=False, hidden=False):
2197
2343
registry.Registry.register_lazy(self, key, module_name, member_name,
2198
help, BzrDirFormatInfo(native, deprecated))
2344
help, BzrDirFormatInfo(native, deprecated, hidden))
2200
2346
def set_default(self, key):
2201
2347
"""Set the 'default' key to be a clone of the supplied key.
2251
2397
deprecated_pairs = []
2252
2398
for key, help in help_pairs:
2253
2399
info = self.get_info(key)
2402
elif info.deprecated:
2255
2403
deprecated_pairs.append((key, help))
2257
2405
output += wrapped(key, help, info)
2289
2437
# directly from workingtree_4 triggers a circular import.
2290
2438
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2440
format_registry.register_metadir('dirstate-tags',
2441
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2442
help='New in 0.15: Fast local operations and improved scaling for '
2443
'network operations. Additionally adds support for tags.'
2444
' Incompatible with bzr < 0.15.',
2445
branch_format='bzrlib.branch.BzrBranchFormat6',
2446
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2292
2448
format_registry.register_metadir('dirstate-with-subtree',
2293
2449
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
2294
2450
help='New in 0.15: Fast local operations and improved scaling for '