84
121
"""Return true if this bzrdir is one whose format we can convert from."""
124
def check_conversion_target(self, target_format):
125
target_repo_format = target_format.repository_format
126
source_repo_format = self._format.repository_format
127
source_repo_format.check_conversion_target(target_repo_format)
88
def _check_supported(format, allow_unsupported):
89
"""Check whether format is a supported format.
91
If allow_unsupported is True, this is a no-op.
130
def _check_supported(format, allow_unsupported,
131
recommend_upgrade=True,
133
"""Give an error or warning on old formats.
135
:param format: may be any kind of format - workingtree, branch,
138
:param allow_unsupported: If true, allow opening
139
formats that are strongly deprecated, and which may
140
have limited functionality.
142
:param recommend_upgrade: If true (default), warn
143
the user through the ui object that they may wish
144
to upgrade the object.
146
# TODO: perhaps move this into a base Format class; it's not BzrDir
147
# specific. mbp 20070323
93
148
if not allow_unsupported and not format.is_supported():
94
149
# see open_downlevel to open legacy branches.
95
raise errors.UnsupportedFormatError(
96
'sorry, format %s not supported' % format,
97
['use a different bzr version',
98
'or remove the .bzr directory'
99
' and "bzr init" again'])
150
raise errors.UnsupportedFormatError(format=format)
151
if recommend_upgrade \
152
and getattr(format, 'upgrade_recommended', False):
153
ui.ui_factory.recommend_upgrade(
154
format.get_format_description(),
101
def clone(self, url, revision_id=None, basis=None, force_new_repo=False):
157
def clone(self, url, revision_id=None, force_new_repo=False):
102
158
"""Clone this bzrdir and its contents to url verbatim.
104
If urls last component does not exist, it will be created.
106
if revision_id is not None, then the clone operation may tune
107
itself to download less data.
108
:param force_new_repo: Do not use a shared repository for the target
109
even if one is available.
112
basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
113
result = self._format.initialize(url)
160
If url's last component does not exist, it will be created.
162
if revision_id is not None, then the clone operation may tune
163
itself to download less data.
164
:param force_new_repo: Do not use a shared repository for the target
165
even if one is available.
167
return self.clone_on_transport(get_transport(url),
168
revision_id=revision_id,
169
force_new_repo=force_new_repo)
171
def clone_on_transport(self, transport, revision_id=None,
172
force_new_repo=False):
173
"""Clone this bzrdir and its contents to transport verbatim.
175
If the target directory does not exist, it will be created.
177
if revision_id is not None, then the clone operation may tune
178
itself to download less data.
179
:param force_new_repo: Do not use a shared repository for the target
180
even if one is available.
182
transport.ensure_base()
183
result = self._format.initialize_on_transport(transport)
115
185
local_repo = self.find_repository()
116
186
except errors.NoRepositoryPresent:
147
211
except errors.NotBranchError:
150
self.open_workingtree().clone(result, basis=basis_tree)
151
except (errors.NoWorkingTree, errors.NotLocalUrl):
214
result_repo = result.find_repository()
215
except errors.NoRepositoryPresent:
217
if result_repo is None or result_repo.make_working_trees():
219
self.open_workingtree().clone(result)
220
except (errors.NoWorkingTree, errors.NotLocalUrl):
155
def _get_basis_components(self, basis):
156
"""Retrieve the basis components that are available at basis."""
158
return None, None, None
160
basis_tree = basis.open_workingtree()
161
basis_branch = basis_tree.branch
162
basis_repo = basis_branch.repository
163
except (errors.NoWorkingTree, errors.NotLocalUrl):
166
basis_branch = basis.open_branch()
167
basis_repo = basis_branch.repository
168
except errors.NotBranchError:
171
basis_repo = basis.open_repository()
172
except errors.NoRepositoryPresent:
174
return basis_repo, basis_branch, basis_tree
224
# TODO: This should be given a Transport, and should chdir up; otherwise
225
# this will open a new connection.
176
226
def _make_tail(self, url):
177
segments = url.split('/')
178
if segments and segments[-1] not in ('', '.'):
179
parent = '/'.join(segments[:-1])
180
t = bzrlib.transport.get_transport(parent)
182
t.mkdir(segments[-1])
183
except errors.FileExists:
227
t = get_transport(url)
187
def create(cls, base):
231
def create(cls, base, format=None, possible_transports=None):
188
232
"""Create a new BzrDir at the url 'base'.
190
This will call the current default formats initialize with base
191
as the only parameter.
193
If you need a specific format, consider creating an instance
194
of that and calling initialize().
234
:param format: If supplied, the format of branch to create. If not
235
supplied, the default is used.
236
:param possible_transports: If supplied, a list of transports that
237
can be reused to share a remote connection.
196
239
if cls is not BzrDir:
197
raise AssertionError("BzrDir.create always creates the default format, "
198
"not one of %r" % cls)
199
segments = base.split('/')
200
if segments and segments[-1] not in ('', '.'):
201
parent = '/'.join(segments[:-1])
202
t = bzrlib.transport.get_transport(parent)
204
t.mkdir(segments[-1])
205
except errors.FileExists:
207
return BzrDirFormat.get_default_format().initialize(safe_unicode(base))
240
raise AssertionError("BzrDir.create always creates the default"
241
" format, not one of %r" % cls)
242
t = get_transport(base, possible_transports)
245
format = BzrDirFormat.get_default_format()
246
return format.initialize_on_transport(t)
249
def find_bzrdirs(transport, evaluate=None, list_current=None):
250
"""Find bzrdirs recursively from current location.
252
This is intended primarily as a building block for more sophisticated
253
functionality, like finding trees under a directory, or finding
254
branches that use a given repository.
255
:param evaluate: An optional callable that yields recurse, value,
256
where recurse controls whether this bzrdir is recursed into
257
and value is the value to yield. By default, all bzrdirs
258
are recursed into, and the return value is the bzrdir.
259
:param list_current: if supplied, use this function to list the current
260
directory, instead of Transport.list_dir
261
:return: a generator of found bzrdirs, or whatever evaluate returns.
263
if list_current is None:
264
def list_current(transport):
265
return transport.list_dir('')
267
def evaluate(bzrdir):
270
pending = [transport]
271
while len(pending) > 0:
272
current_transport = pending.pop()
275
bzrdir = BzrDir.open_from_transport(current_transport)
276
except errors.NotBranchError:
279
recurse, value = evaluate(bzrdir)
282
subdirs = list_current(current_transport)
283
except errors.NoSuchFile:
286
for subdir in sorted(subdirs, reverse=True):
287
pending.append(current_transport.clone(subdir))
290
def find_branches(transport):
291
"""Find all branches under a transport.
293
This will find all branches below the transport, including branches
294
inside other branches. Where possible, it will use
295
Repository.find_branches.
297
To list all the branches that use a particular Repository, see
298
Repository.find_branches
300
def evaluate(bzrdir):
302
repository = bzrdir.open_repository()
303
except errors.NoRepositoryPresent:
306
return False, (None, repository)
308
branch = bzrdir.open_branch()
309
except errors.NotBranchError:
310
return True, (None, None)
312
return True, (branch, None)
314
for branch, repo in BzrDir.find_bzrdirs(transport, evaluate=evaluate):
316
branches.extend(repo.find_branches())
317
if branch is not None:
318
branches.append(branch)
322
def destroy_repository(self):
323
"""Destroy the repository in this BzrDir"""
324
raise NotImplementedError(self.destroy_repository)
209
326
def create_branch(self):
210
327
"""Create a branch in this BzrDir.
212
The bzrdirs format will control what branch format is created.
329
The bzrdir's format will control what branch format is created.
213
330
For more control see BranchFormatXX.create(a_bzrdir).
215
332
raise NotImplementedError(self.create_branch)
334
def destroy_branch(self):
335
"""Destroy the branch in this BzrDir"""
336
raise NotImplementedError(self.destroy_branch)
218
def create_branch_and_repo(base, force_new_repo=False):
339
def create_branch_and_repo(base, force_new_repo=False, format=None):
219
340
"""Create a new BzrDir, Branch and Repository at the url 'base'.
221
This will use the current default BzrDirFormat, and use whatever
342
This will use the current default BzrDirFormat unless one is
343
specified, and use whatever
222
344
repository format that that uses via bzrdir.create_branch and
223
345
create_repository. If a shared repository is available that is used
265
391
:param force_new_repo: If True a new repository is always created.
266
392
:param force_new_tree: If True or False force creation of a tree or
267
393
prevent such creation respectively.
268
:param format: Override for the for the bzrdir format to create
394
:param format: Override for the bzrdir format to create.
395
:param possible_transports: An optional reusable transports list.
270
397
if force_new_tree:
271
398
# check for non local urls
272
t = get_transport(safe_unicode(base))
399
t = get_transport(base, possible_transports)
273
400
if not isinstance(t, LocalTransport):
274
401
raise errors.NotLocalUrl(base)
276
bzrdir = BzrDir.create(base)
278
bzrdir = format.initialize(base)
402
bzrdir = BzrDir.create(base, format, possible_transports)
279
403
repo = bzrdir._find_or_create_repository(force_new_repo)
280
404
result = bzrdir.create_branch()
281
if force_new_tree or (repo.make_working_trees() and
405
if force_new_tree or (repo.make_working_trees() and
282
406
force_new_tree is None):
284
408
bzrdir.create_workingtree()
285
409
except errors.NotLocalUrl:
290
def create_repository(base, shared=False):
414
@deprecated_function(zero_ninetyone)
415
def create_repository(base, shared=False, format=None):
291
416
"""Create a new BzrDir and Repository at the url 'base'.
293
This will use the current default BzrDirFormat, and use whatever
294
repository format that that uses for bzrdirformat.create_repository.
418
If no format is supplied, this will default to the current default
419
BzrDirFormat by default, and use whatever repository format that that
420
uses for bzrdirformat.create_repository.
296
;param shared: Create a shared repository rather than a standalone
422
:param shared: Create a shared repository rather than a standalone
298
424
The Repository object is returned.
300
426
This must be overridden as an instance method in child classes, where
301
427
it should take no parameters and construct whatever repository format
302
428
that child class desires.
430
This method is deprecated, please call create_repository on a bzrdir
304
bzrdir = BzrDir.create(base)
305
return bzrdir.create_repository()
433
bzrdir = BzrDir.create(base, format)
434
return bzrdir.create_repository(shared)
308
def create_standalone_workingtree(base):
437
def create_standalone_workingtree(base, format=None):
309
438
"""Create a new BzrDir, WorkingTree, Branch and Repository at 'base'.
311
440
'base' must be a local path or a file:// url.
313
This will use the current default BzrDirFormat, and use whatever
442
This will use the current default BzrDirFormat unless one is
443
specified, and use whatever
314
444
repository format that that uses for bzrdirformat.create_workingtree,
315
445
create_branch and create_repository.
317
The WorkingTree object is returned.
447
:param format: Override for the bzrdir format to create.
448
:return: The WorkingTree object.
319
t = get_transport(safe_unicode(base))
450
t = get_transport(base)
320
451
if not isinstance(t, LocalTransport):
321
452
raise errors.NotLocalUrl(base)
322
bzrdir = BzrDir.create_branch_and_repo(safe_unicode(base),
323
force_new_repo=True).bzrdir
453
bzrdir = BzrDir.create_branch_and_repo(base,
455
format=format).bzrdir
324
456
return bzrdir.create_workingtree()
326
def create_workingtree(self, revision_id=None):
458
def create_workingtree(self, revision_id=None, from_branch=None,
459
accelerator_tree=None):
327
460
"""Create a working tree at this BzrDir.
329
revision_id: create it as of this revision id.
462
:param revision_id: create it as of this revision id.
463
:param from_branch: override bzrdir branch (for lightweight checkouts)
464
:param accelerator_tree: A tree which can be used for retrieving file
465
contents more quickly than the revision tree, i.e. a workingtree.
466
The revision tree will be used for cases where accelerator_tree's
467
content is different.
331
469
raise NotImplementedError(self.create_workingtree)
471
def retire_bzrdir(self, limit=10000):
472
"""Permanently disable the bzrdir.
474
This is done by renaming it to give the user some ability to recover
475
if there was a problem.
477
This will have horrible consequences if anyone has anything locked or
479
:param limit: number of times to retry
484
to_path = '.bzr.retired.%d' % i
485
self.root_transport.rename('.bzr', to_path)
486
note("renamed %s to %s"
487
% (self.root_transport.abspath('.bzr'), to_path))
489
except (errors.TransportError, IOError, errors.PathError):
496
def destroy_workingtree(self):
497
"""Destroy the working tree at this BzrDir.
499
Formats that do not support this may raise UnsupportedOperation.
501
raise NotImplementedError(self.destroy_workingtree)
503
def destroy_workingtree_metadata(self):
504
"""Destroy the control files for the working tree at this BzrDir.
506
The contents of working tree files are not affected.
507
Formats that do not support this may raise UnsupportedOperation.
509
raise NotImplementedError(self.destroy_workingtree_metadata)
333
511
def find_repository(self):
334
"""Find the repository that should be used for a_bzrdir.
512
"""Find the repository that should be used.
336
514
This does not require a branch as we use it to find the repo for
337
515
new branches as well as to hook existing branches up to their
448
642
return BzrDir.open(base, _unsupported=True)
451
def open(base, _unsupported=False):
452
"""Open an existing bzrdir, rooted at 'base' (url)
645
def open(base, _unsupported=False, possible_transports=None):
646
"""Open an existing bzrdir, rooted at 'base' (url).
454
_unsupported is a private parameter to the BzrDir class.
456
t = get_transport(base)
457
mutter("trying to open %r with transport %r", base, t)
458
format = BzrDirFormat.find_format(t)
648
:param _unsupported: a private parameter to the BzrDir class.
650
t = get_transport(base, possible_transports=possible_transports)
651
return BzrDir.open_from_transport(t, _unsupported=_unsupported)
654
def open_from_transport(transport, _unsupported=False,
655
_server_formats=True):
656
"""Open a bzrdir within a particular directory.
658
:param transport: Transport containing the bzrdir.
659
:param _unsupported: private.
661
base = transport.base
663
def find_format(transport):
664
return transport, BzrDirFormat.find_format(
665
transport, _server_formats=_server_formats)
667
def redirected(transport, e, redirection_notice):
668
qualified_source = e.get_source_url()
669
relpath = transport.relpath(qualified_source)
670
if not e.target.endswith(relpath):
671
# Not redirected to a branch-format, not a branch
672
raise errors.NotBranchError(path=e.target)
673
target = e.target[:-len(relpath)]
674
note('%s is%s redirected to %s',
675
transport.base, e.permanently, target)
676
# Let's try with a new transport
677
# FIXME: If 'transport' has a qualifier, this should
678
# be applied again to the new transport *iff* the
679
# schemes used are the same. Uncomment this code
680
# once the function (and tests) exist.
682
#target = urlutils.copy_url_qualifiers(original, target)
683
return get_transport(target)
686
transport, format = do_catching_redirections(find_format,
689
except errors.TooManyRedirections:
690
raise errors.NotBranchError(base)
459
692
BzrDir._check_supported(format, _unsupported)
460
return format.open(t, _found=True)
693
return format.open(transport, _found=True)
462
695
def open_branch(self, unsupported=False):
463
696
"""Open the branch object at this BzrDir if one is present.
489
723
If there is one and it is either an unrecognised format or an unsupported
490
724
format, UnknownFormatError or UnsupportedFormatError are raised.
491
725
If there is one, it is returned, along with the unused portion of url.
727
:return: The BzrDir that contains the path, and a Unicode path
728
for the rest of the URL.
493
730
# this gets the normalised url back. I.e. '.' -> the full path.
494
731
url = a_transport.base
497
format = BzrDirFormat.find_format(a_transport)
498
BzrDir._check_supported(format, False)
499
return format.open(a_transport), a_transport.relpath(url)
734
result = BzrDir.open_from_transport(a_transport)
735
return result, urlutils.unescape(a_transport.relpath(url))
500
736
except errors.NotBranchError, e:
501
mutter('not a branch in: %r %s', a_transport.base, e)
502
new_t = a_transport.clone('..')
739
new_t = a_transport.clone('..')
740
except errors.InvalidURLJoin:
741
# reached the root, whatever that may be
742
raise errors.NotBranchError(path=url)
503
743
if new_t.base == a_transport.base:
504
744
# reached the root, whatever that may be
505
745
raise errors.NotBranchError(path=url)
506
746
a_transport = new_t
748
def _get_tree_branch(self):
749
"""Return the branch and tree, if any, for this bzrdir.
751
Return None for tree if not present.
752
Raise NotBranchError if no branch is present.
753
:return: (tree, branch)
756
tree = self.open_workingtree()
757
except (errors.NoWorkingTree, errors.NotLocalUrl):
759
branch = self.open_branch()
765
def open_tree_or_branch(klass, location):
766
"""Return the branch and working tree at a location.
768
If there is no tree at the location, tree will be None.
769
If there is no branch at the location, an exception will be
771
:return: (tree, branch)
773
bzrdir = klass.open(location)
774
return bzrdir._get_tree_branch()
777
def open_containing_tree_or_branch(klass, location):
778
"""Return the branch and working tree contained by a location.
780
Returns (tree, branch, relpath).
781
If there is no tree at containing the location, tree will be None.
782
If there is no branch containing the location, an exception will be
784
relpath is the portion of the path that is contained by the branch.
786
bzrdir, relpath = klass.open_containing(location)
787
tree, branch = bzrdir._get_tree_branch()
788
return tree, branch, relpath
508
790
def open_repository(self, _unsupported=False):
509
791
"""Open the repository object at this BzrDir if one is present.
511
This will not follow the Branch object pointer - its strictly a direct
793
This will not follow the Branch object pointer - it's strictly a direct
512
794
open facility. Most client code should use open_branch().repository to
513
795
get at a repository.
515
_unsupported is a private parameter, not part of the api.
797
:param _unsupported: a private parameter, not part of the api.
516
798
TODO: static convenience version of this?
518
800
raise NotImplementedError(self.open_repository)
520
def open_workingtree(self, _unsupported=False):
802
def open_workingtree(self, _unsupported=False,
803
recommend_upgrade=True, from_branch=None):
521
804
"""Open the workingtree object at this BzrDir if one is present.
523
TODO: static convenience version of this?
806
:param recommend_upgrade: Optional keyword parameter, when True (the
807
default), emit through the ui module a recommendation that the user
808
upgrade the working tree when the workingtree being opened is old
809
(but still fully supported).
810
:param from_branch: override bzrdir branch (for lightweight checkouts)
525
812
raise NotImplementedError(self.open_workingtree)
810
1216
def create_branch(self):
811
1217
"""See BzrDir.create_branch."""
812
from bzrlib.branch import BranchFormat
813
return BranchFormat.get_default_format().initialize(self)
1218
return self._format.get_branch_format().initialize(self)
1220
def destroy_branch(self):
1221
"""See BzrDir.create_branch."""
1222
self.transport.delete_tree('branch')
815
1224
def create_repository(self, shared=False):
816
1225
"""See BzrDir.create_repository."""
817
1226
return self._format.repository_format.initialize(self, shared)
819
def create_workingtree(self, revision_id=None):
1228
def destroy_repository(self):
1229
"""See BzrDir.destroy_repository."""
1230
self.transport.delete_tree('repository')
1232
def create_workingtree(self, revision_id=None, from_branch=None,
1233
accelerator_tree=None):
820
1234
"""See BzrDir.create_workingtree."""
821
from bzrlib.workingtree import WorkingTreeFormat
822
return WorkingTreeFormat.get_default_format().initialize(self, revision_id)
1235
return self._format.workingtree_format.initialize(
1236
self, revision_id, from_branch=from_branch,
1237
accelerator_tree=accelerator_tree)
1239
def destroy_workingtree(self):
1240
"""See BzrDir.destroy_workingtree."""
1241
wt = self.open_workingtree(recommend_upgrade=False)
1242
repository = wt.branch.repository
1243
empty = repository.revision_tree(_mod_revision.NULL_REVISION)
1244
wt.revert(old_tree=empty)
1245
self.destroy_workingtree_metadata()
1247
def destroy_workingtree_metadata(self):
1248
self.transport.delete_tree('checkout')
1250
def find_branch_format(self):
1251
"""Find the branch 'format' for this bzrdir.
1253
This might be a synthetic object for e.g. RemoteBranch and SVN.
1255
from bzrlib.branch import BranchFormat
1256
return BranchFormat.find_format(self)
824
1258
def _get_mkdir_mode(self):
825
1259
"""Figure out the mode to use when creating a bzrdir subdir."""
826
temp_control = LockableFiles(self.transport, '', TransportLock)
1260
temp_control = lockable_files.LockableFiles(self.transport, '',
1261
lockable_files.TransportLock)
827
1262
return temp_control._dir_mode
1264
def get_branch_reference(self):
1265
"""See BzrDir.get_branch_reference()."""
1266
from bzrlib.branch import BranchFormat
1267
format = BranchFormat.find_format(self)
1268
return format.get_reference(self)
829
1270
def get_branch_transport(self, branch_format):
830
1271
"""See BzrDir.get_branch_transport()."""
831
1272
if branch_format is None:
1264
1843
return RepositoryFormat.get_default_format()
1266
1845
def __set_repository_format(self, value):
1267
"""Allow changint the repository format for metadir formats."""
1846
"""Allow changing the repository format for metadir formats."""
1268
1847
self._repository_format = value
1270
1849
repository_format = property(__return_repository_format, __set_repository_format)
1851
def __get_workingtree_format(self):
1852
if self._workingtree_format is None:
1853
from bzrlib.workingtree import WorkingTreeFormat
1854
self._workingtree_format = WorkingTreeFormat.get_default_format()
1855
return self._workingtree_format
1857
def __set_workingtree_format(self, wt_format):
1858
self._workingtree_format = wt_format
1860
workingtree_format = property(__get_workingtree_format,
1861
__set_workingtree_format)
1864
# Register bzr control format
1865
BzrDirFormat.register_control_format(BzrDirFormat)
1867
# Register bzr formats
1273
1868
BzrDirFormat.register_format(BzrDirFormat4())
1274
1869
BzrDirFormat.register_format(BzrDirFormat5())
1275
1870
BzrDirFormat.register_format(BzrDirFormat6())
1276
1871
__default_format = BzrDirMetaFormat1()
1277
1872
BzrDirFormat.register_format(__default_format)
1278
BzrDirFormat.set_default_format(__default_format)
1281
class BzrDirTestProviderAdapter(object):
1282
"""A tool to generate a suite testing multiple bzrdir formats at once.
1284
This is done by copying the test once for each transport and injecting
1285
the transport_server, transport_readonly_server, and bzrdir_format
1286
classes into each copy. Each copy is also given a new id() to make it
1290
def __init__(self, transport_server, transport_readonly_server, formats):
1291
self._transport_server = transport_server
1292
self._transport_readonly_server = transport_readonly_server
1293
self._formats = formats
1295
def adapt(self, test):
1296
result = TestSuite()
1297
for format in self._formats:
1298
new_test = deepcopy(test)
1299
new_test.transport_server = self._transport_server
1300
new_test.transport_readonly_server = self._transport_readonly_server
1301
new_test.bzrdir_format = format
1302
def make_new_test_id():
1303
new_id = "%s(%s)" % (new_test.id(), format.__class__.__name__)
1304
return lambda: new_id
1305
new_test.id = make_new_test_id()
1306
result.addTest(new_test)
1310
class ScratchDir(BzrDir6):
1311
"""Special test class: a bzrdir that cleans up itself..
1313
>>> d = ScratchDir()
1314
>>> base = d.transport.base
1317
>>> b.transport.__del__()
1322
def __init__(self, files=[], dirs=[], transport=None):
1323
"""Make a test branch.
1325
This creates a temporary directory and runs init-tree in it.
1327
If any files are listed, they are created in the working copy.
1329
if transport is None:
1330
transport = bzrlib.transport.local.ScratchTransport()
1331
# local import for scope restriction
1332
BzrDirFormat6().initialize(transport.base)
1333
super(ScratchDir, self).__init__(transport, BzrDirFormat6())
1334
self.create_repository()
1335
self.create_branch()
1336
self.create_workingtree()
1338
super(ScratchDir, self).__init__(transport, BzrDirFormat6())
1340
# BzrBranch creates a clone to .bzr and then forgets about the
1341
# original transport. A ScratchTransport() deletes itself and
1342
# everything underneath it when it goes away, so we need to
1343
# grab a local copy to prevent that from happening
1344
self._transport = transport
1347
self._transport.mkdir(d)
1350
self._transport.put(f, 'content of %s' % f)
1354
>>> orig = ScratchDir(files=["file1", "file2"])
1355
>>> os.listdir(orig.base)
1356
[u'.bzr', u'file1', u'file2']
1357
>>> clone = orig.clone()
1358
>>> if os.name != 'nt':
1359
... os.path.samefile(orig.base, clone.base)
1361
... orig.base == clone.base
1364
>>> os.listdir(clone.base)
1365
[u'.bzr', u'file1', u'file2']
1367
from shutil import copytree
1368
from bzrlib.osutils import mkdtemp
1371
copytree(self.base, base, symlinks=True)
1373
transport=bzrlib.transport.local.ScratchTransport(base))
1873
BzrDirFormat._default_format = __default_format
1376
1876
class Converter(object):
1728
2244
# we hard code the formats here because we are converting into
1729
2245
# the meta format. The meta format upgrader can take this to a
1730
2246
# future format within each component.
1731
self.put_format('repository', bzrlib.repository.RepositoryFormat7())
2247
self.put_format('repository', RepositoryFormat7())
1732
2248
for entry in repository_names:
1733
2249
self.move_entry('repository', entry)
1735
2251
self.step('Upgrading branch ')
1736
2252
self.bzrdir.transport.mkdir('branch', mode=self.dir_mode)
1737
2253
self.make_lock('branch')
1738
self.put_format('branch', bzrlib.branch.BzrBranchFormat5())
2254
self.put_format('branch', BzrBranchFormat5())
1739
2255
branch_files = [('revision-history', True),
1740
2256
('branch-name', True),
1741
2257
('parent', False)]
1742
2258
for entry in branch_files:
1743
2259
self.move_entry('branch', entry)
1745
self.step('Upgrading working tree')
1746
self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
1747
self.make_lock('checkout')
1748
self.put_format('checkout', bzrlib.workingtree.WorkingTreeFormat3())
1749
self.bzrdir.transport.delete_multi(self.garbage_inventories, self.pb)
1750
2261
checkout_files = [('pending-merges', True),
1751
2262
('inventory', True),
1752
2263
('stat-cache', False)]
1753
for entry in checkout_files:
1754
self.move_entry('checkout', entry)
1755
if last_revision is not None:
1756
self.bzrdir._control_files.put_utf8('checkout/last-revision',
1758
self.bzrdir._control_files.put_utf8('branch-format', BzrDirMetaFormat1().get_format_string())
2264
# If a mandatory checkout file is not present, the branch does not have
2265
# a functional checkout. Do not create a checkout in the converted
2267
for name, mandatory in checkout_files:
2268
if mandatory and name not in bzrcontents:
2269
has_checkout = False
2273
if not has_checkout:
2274
self.pb.note('No working tree.')
2275
# If some checkout files are there, we may as well get rid of them.
2276
for name, mandatory in checkout_files:
2277
if name in bzrcontents:
2278
self.bzrdir.transport.delete(name)
2280
from bzrlib.workingtree import WorkingTreeFormat3
2281
self.step('Upgrading working tree')
2282
self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
2283
self.make_lock('checkout')
2285
'checkout', WorkingTreeFormat3())
2286
self.bzrdir.transport.delete_multi(
2287
self.garbage_inventories, self.pb)
2288
for entry in checkout_files:
2289
self.move_entry('checkout', entry)
2290
if last_revision is not None:
2291
self.bzrdir._control_files.put_utf8(
2292
'checkout/last-revision', last_revision)
2293
self.bzrdir._control_files.put_utf8(
2294
'branch-format', BzrDirMetaFormat1().get_format_string())
1759
2295
return BzrDir.open(self.bzrdir.root_transport.base)
1761
2297
def make_lock(self, name):
1762
2298
"""Make a lock for the new control dir name."""
1763
2299
self.step('Make %s lock' % name)
1764
ld = LockDir(self.bzrdir.transport,
1766
file_modebits=self.file_mode,
1767
dir_modebits=self.dir_mode)
2300
ld = lockdir.LockDir(self.bzrdir.transport,
2302
file_modebits=self.file_mode,
2303
dir_modebits=self.dir_mode)
1770
2306
def move_entry(self, new_dir, entry):
1809
2345
self.pb.note('starting repository conversion')
1810
2346
converter = CopyConverter(self.target_format.repository_format)
1811
2347
converter.convert(repo, pb)
2349
branch = self.bzrdir.open_branch()
2350
except errors.NotBranchError:
2353
# TODO: conversions of Branch and Tree should be done by
2354
# InterXFormat lookups
2355
# Avoid circular imports
2356
from bzrlib import branch as _mod_branch
2357
if (branch._format.__class__ is _mod_branch.BzrBranchFormat5 and
2358
self.target_format.get_branch_format().__class__ is
2359
_mod_branch.BzrBranchFormat6):
2360
branch_converter = _mod_branch.Converter5to6()
2361
branch_converter.convert(branch)
2363
tree = self.bzrdir.open_workingtree(recommend_upgrade=False)
2364
except (errors.NoWorkingTree, errors.NotLocalUrl):
2367
# TODO: conversions of Branch and Tree should be done by
2368
# InterXFormat lookups
2369
if (isinstance(tree, workingtree.WorkingTree3) and
2370
not isinstance(tree, workingtree_4.WorkingTree4) and
2371
isinstance(self.target_format.workingtree_format,
2372
workingtree_4.WorkingTreeFormat4)):
2373
workingtree_4.Converter3to4().convert(tree)
1812
2374
return to_convert
2377
# This is not in remote.py because it's small, and needs to be registered.
2378
# Putting it in remote.py creates a circular import problem.
2379
# we can make it a lazy object if the control formats is turned into something
2381
class RemoteBzrDirFormat(BzrDirMetaFormat1):
2382
"""Format representing bzrdirs accessed via a smart server"""
2384
def get_format_description(self):
2385
return 'bzr remote bzrdir'
2388
def probe_transport(klass, transport):
2389
"""Return a RemoteBzrDirFormat object if it looks possible."""
2391
client = transport.get_smart_client()
2392
except (NotImplementedError, AttributeError,
2393
errors.TransportNotPossible):
2394
# no smart server, so not a branch for this format type.
2395
raise errors.NotBranchError(path=transport.base)
2397
# Send a 'hello' request in protocol version one, and decline to
2398
# open it if the server doesn't support our required version (2) so
2399
# that the VFS-based transport will do it.
2400
request = client.get_request()
2401
smart_protocol = protocol.SmartClientRequestProtocolOne(request)
2402
server_version = smart_protocol.query_version()
2403
if server_version != 2:
2404
raise errors.NotBranchError(path=transport.base)
2407
def initialize_on_transport(self, transport):
2409
# hand off the request to the smart server
2410
shared_medium = transport.get_shared_medium()
2411
except errors.NoSmartMedium:
2412
# TODO: lookup the local format from a server hint.
2413
local_dir_format = BzrDirMetaFormat1()
2414
return local_dir_format.initialize_on_transport(transport)
2415
client = _SmartClient(shared_medium)
2416
path = client.remote_path_from_transport(transport)
2417
response = _SmartClient(shared_medium).call('BzrDirFormat.initialize',
2419
assert response[0] in ('ok', ), 'unexpected response code %s' % (response,)
2420
return remote.RemoteBzrDir(transport)
2422
def _open(self, transport):
2423
return remote.RemoteBzrDir(transport)
2425
def __eq__(self, other):
2426
if not isinstance(other, RemoteBzrDirFormat):
2428
return self.get_format_description() == other.get_format_description()
2431
BzrDirFormat.register_control_server_format(RemoteBzrDirFormat)
2434
class BzrDirFormatInfo(object):
2436
def __init__(self, native, deprecated, hidden, experimental):
2437
self.deprecated = deprecated
2438
self.native = native
2439
self.hidden = hidden
2440
self.experimental = experimental
2443
class BzrDirFormatRegistry(registry.Registry):
2444
"""Registry of user-selectable BzrDir subformats.
2446
Differs from BzrDirFormat._control_formats in that it provides sub-formats,
2447
e.g. BzrDirMeta1 with weave repository. Also, it's more user-oriented.
2450
def register_metadir(self, key,
2451
repository_format, help, native=True, deprecated=False,
2455
experimental=False):
2456
"""Register a metadir subformat.
2458
These all use a BzrDirMetaFormat1 bzrdir, but can be parameterized
2459
by the Repository format.
2461
:param repository_format: The fully-qualified repository format class
2463
:param branch_format: Fully-qualified branch format class name as
2465
:param tree_format: Fully-qualified tree format class name as
2468
# This should be expanded to support setting WorkingTree and Branch
2469
# formats, once BzrDirMetaFormat1 supports that.
2470
def _load(full_name):
2471
mod_name, factory_name = full_name.rsplit('.', 1)
2473
mod = __import__(mod_name, globals(), locals(),
2475
except ImportError, e:
2476
raise ImportError('failed to load %s: %s' % (full_name, e))
2478
factory = getattr(mod, factory_name)
2479
except AttributeError:
2480
raise AttributeError('no factory %s in module %r'
2485
bd = BzrDirMetaFormat1()
2486
if branch_format is not None:
2487
bd.set_branch_format(_load(branch_format))
2488
if tree_format is not None:
2489
bd.workingtree_format = _load(tree_format)
2490
if repository_format is not None:
2491
bd.repository_format = _load(repository_format)
2493
self.register(key, helper, help, native, deprecated, hidden,
2496
def register(self, key, factory, help, native=True, deprecated=False,
2497
hidden=False, experimental=False):
2498
"""Register a BzrDirFormat factory.
2500
The factory must be a callable that takes one parameter: the key.
2501
It must produce an instance of the BzrDirFormat when called.
2503
This function mainly exists to prevent the info object from being
2506
registry.Registry.register(self, key, factory, help,
2507
BzrDirFormatInfo(native, deprecated, hidden, experimental))
2509
def register_lazy(self, key, module_name, member_name, help, native=True,
2510
deprecated=False, hidden=False, experimental=False):
2511
registry.Registry.register_lazy(self, key, module_name, member_name,
2512
help, BzrDirFormatInfo(native, deprecated, hidden, experimental))
2514
def set_default(self, key):
2515
"""Set the 'default' key to be a clone of the supplied key.
2517
This method must be called once and only once.
2519
registry.Registry.register(self, 'default', self.get(key),
2520
self.get_help(key), info=self.get_info(key))
2522
def set_default_repository(self, key):
2523
"""Set the FormatRegistry default and Repository default.
2525
This is a transitional method while Repository.set_default_format
2528
if 'default' in self:
2529
self.remove('default')
2530
self.set_default(key)
2531
format = self.get('default')()
2532
assert isinstance(format, BzrDirMetaFormat1)
2534
def make_bzrdir(self, key):
2535
return self.get(key)()
2537
def help_topic(self, topic):
2538
output = textwrap.dedent("""\
2539
These formats can be used for creating branches, working trees, and
2543
default_realkey = None
2544
default_help = self.get_help('default')
2546
for key in self.keys():
2547
if key == 'default':
2549
help = self.get_help(key)
2550
if help == default_help:
2551
default_realkey = key
2553
help_pairs.append((key, help))
2555
def wrapped(key, help, info):
2557
help = '(native) ' + help
2558
return ':%s:\n%s\n\n' % (key,
2559
textwrap.fill(help, initial_indent=' ',
2560
subsequent_indent=' '))
2561
if default_realkey is not None:
2562
output += wrapped(default_realkey, '(default) %s' % default_help,
2563
self.get_info('default'))
2564
deprecated_pairs = []
2565
experimental_pairs = []
2566
for key, help in help_pairs:
2567
info = self.get_info(key)
2570
elif info.deprecated:
2571
deprecated_pairs.append((key, help))
2572
elif info.experimental:
2573
experimental_pairs.append((key, help))
2575
output += wrapped(key, help, info)
2576
if len(experimental_pairs) > 0:
2577
output += "Experimental formats are shown below.\n\n"
2578
for key, help in experimental_pairs:
2579
info = self.get_info(key)
2580
output += wrapped(key, help, info)
2581
if len(deprecated_pairs) > 0:
2582
output += "Deprecated formats are shown below.\n\n"
2583
for key, help in deprecated_pairs:
2584
info = self.get_info(key)
2585
output += wrapped(key, help, info)
2590
format_registry = BzrDirFormatRegistry()
2591
format_registry.register('weave', BzrDirFormat6,
2592
'Pre-0.8 format. Slower than knit and does not'
2593
' support checkouts or shared repositories.',
2595
format_registry.register_metadir('knit',
2596
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2597
'Format using knits. Recommended for interoperation with bzr <= 0.14.',
2598
branch_format='bzrlib.branch.BzrBranchFormat5',
2599
tree_format='bzrlib.workingtree.WorkingTreeFormat3')
2600
format_registry.register_metadir('metaweave',
2601
'bzrlib.repofmt.weaverepo.RepositoryFormat7',
2602
'Transitional format in 0.8. Slower than knit.',
2603
branch_format='bzrlib.branch.BzrBranchFormat5',
2604
tree_format='bzrlib.workingtree.WorkingTreeFormat3',
2606
format_registry.register_metadir('dirstate',
2607
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2608
help='New in 0.15: Fast local operations. Compatible with bzr 0.8 and '
2609
'above when accessed over the network.',
2610
branch_format='bzrlib.branch.BzrBranchFormat5',
2611
# this uses bzrlib.workingtree.WorkingTreeFormat4 because importing
2612
# directly from workingtree_4 triggers a circular import.
2613
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2615
format_registry.register_metadir('dirstate-tags',
2616
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2617
help='New in 0.15: Fast local operations and improved scaling for '
2618
'network operations. Additionally adds support for tags.'
2619
' Incompatible with bzr < 0.15.',
2620
branch_format='bzrlib.branch.BzrBranchFormat6',
2621
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2623
format_registry.register_metadir('rich-root',
2624
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit4',
2625
help='New in 1.0. Better handling of tree roots. Incompatible with'
2627
branch_format='bzrlib.branch.BzrBranchFormat6',
2628
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2630
format_registry.register_metadir('dirstate-with-subtree',
2631
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
2632
help='New in 0.15: Fast local operations and improved scaling for '
2633
'network operations. Additionally adds support for versioning nested '
2634
'bzr branches. Incompatible with bzr < 0.15.',
2635
branch_format='bzrlib.branch.BzrBranchFormat6',
2636
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2640
format_registry.register_metadir('pack-0.92',
2641
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack1',
2642
help='New in 0.92: Pack-based format with data compatible with '
2643
'dirstate-tags format repositories. Interoperates with '
2644
'bzr repositories before 0.92 but cannot be read by bzr < 0.92. '
2645
'Previously called knitpack-experimental. '
2646
'For more information, see '
2647
'http://doc.bazaar-vcs.org/latest/developers/packrepo.html.',
2648
branch_format='bzrlib.branch.BzrBranchFormat6',
2649
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2651
format_registry.register_metadir('pack-0.92-subtree',
2652
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack3',
2653
help='New in 0.92: Pack-based format with data compatible with '
2654
'dirstate-with-subtree format repositories. Interoperates with '
2655
'bzr repositories before 0.92 but cannot be read by bzr < 0.92. '
2656
'Previously called knitpack-experimental. '
2657
'For more information, see '
2658
'http://doc.bazaar-vcs.org/latest/developers/packrepo.html.',
2659
branch_format='bzrlib.branch.BzrBranchFormat6',
2660
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2664
format_registry.register_metadir('rich-root-pack',
2665
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack4',
2666
help='New in 1.0: Pack-based format with data compatible with '
2667
'rich-root format repositories. Incompatible with'
2669
branch_format='bzrlib.branch.BzrBranchFormat6',
2670
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2672
format_registry.set_default('pack-0.92')