1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
"""BzrDir logic. The BzrDir is the basic control directory used by bzr.
19
At format 7 this was split out into Branch, Repository and Checkout control
23
# TODO: remove unittest dependency; put that stuff inside the test suite
25
# TODO: Can we move specific formats into separate modules to make this file
28
from cStringIO import StringIO
32
from bzrlib.lazy_import import lazy_import
33
lazy_import(globals(), """
34
from copy import deepcopy
35
from stat import S_ISDIR
45
revision as _mod_revision,
54
from bzrlib.osutils import (
59
from bzrlib.smart.client import _SmartClient
60
from bzrlib.store.revision.text import TextRevisionStore
61
from bzrlib.store.text import TextStore
62
from bzrlib.store.versioned import WeaveStore
63
from bzrlib.transactions import WriteTransaction
64
from bzrlib.transport import (
65
do_catching_redirections,
68
from bzrlib.weave import Weave
71
from bzrlib.trace import (
75
from bzrlib.transport.local import LocalTransport
79
"""A .bzr control diretory.
81
BzrDir instances let you create or open any of the things that can be
82
found within .bzr - checkouts, branches and repositories.
85
the transport which this bzr dir is rooted at (i.e. file:///.../.bzr/)
87
a transport connected to the directory this bzr was opened from.
91
"""Invoke break_lock on the first object in the bzrdir.
93
If there is a tree, the tree is opened and break_lock() called.
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.
99
thing_to_unlock = self.open_workingtree()
100
except (errors.NotLocalUrl, errors.NoWorkingTree):
102
thing_to_unlock = self.open_branch()
103
except errors.NotBranchError:
105
thing_to_unlock = self.open_repository()
106
except errors.NoRepositoryPresent:
108
thing_to_unlock.break_lock()
110
def can_convert_format(self):
111
"""Return true if this bzrdir is one whose format we can convert from."""
114
def check_conversion_target(self, target_format):
115
target_repo_format = target_format.repository_format
116
source_repo_format = self._format.repository_format
117
source_repo_format.check_conversion_target(target_repo_format)
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
138
if not allow_unsupported and not format.is_supported():
139
# see open_downlevel to open legacy branches.
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(),
147
def clone(self, url, revision_id=None, force_new_repo=False):
148
"""Clone this bzrdir and its contents to url verbatim.
150
If urls last component does not exist, it will be created.
152
if revision_id is not None, then the clone operation may tune
153
itself to download less data.
154
:param force_new_repo: Do not use a shared repository for the target
155
even if one is available.
158
result = self._format.initialize(url)
160
local_repo = self.find_repository()
161
except errors.NoRepositoryPresent:
164
# may need to copy content in
166
result_repo = local_repo.clone(
168
revision_id=revision_id)
169
result_repo.set_make_working_trees(local_repo.make_working_trees())
172
result_repo = result.find_repository()
173
# fetch content this dir needs.
174
result_repo.fetch(local_repo, revision_id=revision_id)
175
except errors.NoRepositoryPresent:
176
# needed to make one anyway.
177
result_repo = local_repo.clone(
179
revision_id=revision_id)
180
result_repo.set_make_working_trees(local_repo.make_working_trees())
181
# 1 if there is a branch present
182
# make sure its content is available in the target repository
185
self.open_branch().clone(result, revision_id=revision_id)
186
except errors.NotBranchError:
189
self.open_workingtree().clone(result)
190
except (errors.NoWorkingTree, errors.NotLocalUrl):
194
# TODO: This should be given a Transport, and should chdir up; otherwise
195
# this will open a new connection.
196
def _make_tail(self, url):
197
head, tail = urlutils.split(url)
198
if tail and tail != '.':
199
t = get_transport(head)
202
except errors.FileExists:
205
# TODO: Should take a Transport
207
def create(cls, base, format=None):
208
"""Create a new BzrDir at the url 'base'.
210
This will call the current default formats initialize with base
211
as the only parameter.
213
:param format: If supplied, the format of branch to create. If not
214
supplied, the default is used.
216
if cls is not BzrDir:
217
raise AssertionError("BzrDir.create always creates the default"
218
" format, not one of %r" % cls)
219
head, tail = urlutils.split(base)
220
if tail and tail != '.':
221
t = get_transport(head)
224
except errors.FileExists:
227
format = BzrDirFormat.get_default_format()
228
return format.initialize(safe_unicode(base))
230
def create_branch(self):
231
"""Create a branch in this BzrDir.
233
The bzrdirs format will control what branch format is created.
234
For more control see BranchFormatXX.create(a_bzrdir).
236
raise NotImplementedError(self.create_branch)
239
def create_branch_and_repo(base, force_new_repo=False, format=None):
240
"""Create a new BzrDir, Branch and Repository at the url 'base'.
242
This will use the current default BzrDirFormat, and use whatever
243
repository format that that uses via bzrdir.create_branch and
244
create_repository. If a shared repository is available that is used
247
The created Branch object is returned.
249
:param base: The URL to create the branch at.
250
:param force_new_repo: If True a new repository is always created.
252
bzrdir = BzrDir.create(base, format)
253
bzrdir._find_or_create_repository(force_new_repo)
254
return bzrdir.create_branch()
256
def _find_or_create_repository(self, force_new_repo):
257
"""Create a new repository if needed, returning the repository."""
259
return self.create_repository()
261
return self.find_repository()
262
except errors.NoRepositoryPresent:
263
return self.create_repository()
266
def create_branch_convenience(base, force_new_repo=False,
267
force_new_tree=None, format=None):
268
"""Create a new BzrDir, Branch and Repository at the url 'base'.
270
This is a convenience function - it will use an existing repository
271
if possible, can be told explicitly whether to create a working tree or
274
This will use the current default BzrDirFormat, and use whatever
275
repository format that that uses via bzrdir.create_branch and
276
create_repository. If a shared repository is available that is used
277
preferentially. Whatever repository is used, its tree creation policy
280
The created Branch object is returned.
281
If a working tree cannot be made due to base not being a file:// url,
282
no error is raised unless force_new_tree is True, in which case no
283
data is created on disk and NotLocalUrl is raised.
285
:param base: The URL to create the branch at.
286
:param force_new_repo: If True a new repository is always created.
287
:param force_new_tree: If True or False force creation of a tree or
288
prevent such creation respectively.
289
:param format: Override for the for the bzrdir format to create
292
# check for non local urls
293
t = get_transport(safe_unicode(base))
294
if not isinstance(t, LocalTransport):
295
raise errors.NotLocalUrl(base)
296
bzrdir = BzrDir.create(base, format)
297
repo = bzrdir._find_or_create_repository(force_new_repo)
298
result = bzrdir.create_branch()
299
if force_new_tree or (repo.make_working_trees() and
300
force_new_tree is None):
302
bzrdir.create_workingtree()
303
except errors.NotLocalUrl:
308
def create_repository(base, shared=False, format=None):
309
"""Create a new BzrDir and Repository at the url 'base'.
311
If no format is supplied, this will default to the current default
312
BzrDirFormat by default, and use whatever repository format that that
313
uses for bzrdirformat.create_repository.
315
:param shared: Create a shared repository rather than a standalone
317
The Repository object is returned.
319
This must be overridden as an instance method in child classes, where
320
it should take no parameters and construct whatever repository format
321
that child class desires.
323
bzrdir = BzrDir.create(base, format)
324
return bzrdir.create_repository(shared)
327
def create_standalone_workingtree(base, format=None):
328
"""Create a new BzrDir, WorkingTree, Branch and Repository at 'base'.
330
'base' must be a local path or a file:// url.
332
This will use the current default BzrDirFormat, and use whatever
333
repository format that that uses for bzrdirformat.create_workingtree,
334
create_branch and create_repository.
336
:return: The WorkingTree object.
338
t = get_transport(safe_unicode(base))
339
if not isinstance(t, LocalTransport):
340
raise errors.NotLocalUrl(base)
341
bzrdir = BzrDir.create_branch_and_repo(safe_unicode(base),
343
format=format).bzrdir
344
return bzrdir.create_workingtree()
346
def create_workingtree(self, revision_id=None):
347
"""Create a working tree at this BzrDir.
349
revision_id: create it as of this revision id.
351
raise NotImplementedError(self.create_workingtree)
353
def retire_bzrdir(self):
354
"""Permanently disable the bzrdir.
356
This is done by renaming it to give the user some ability to recover
357
if there was a problem.
359
This will have horrible consequences if anyone has anything locked or
362
for i in xrange(10000):
364
to_path = '.bzr.retired.%d' % i
365
self.root_transport.rename('.bzr', to_path)
366
note("renamed %s to %s"
367
% (self.root_transport.abspath('.bzr'), to_path))
369
except (errors.TransportError, IOError, errors.PathError):
372
def destroy_workingtree(self):
373
"""Destroy the working tree at this BzrDir.
375
Formats that do not support this may raise UnsupportedOperation.
377
raise NotImplementedError(self.destroy_workingtree)
379
def destroy_workingtree_metadata(self):
380
"""Destroy the control files for the working tree at this BzrDir.
382
The contents of working tree files are not affected.
383
Formats that do not support this may raise UnsupportedOperation.
385
raise NotImplementedError(self.destroy_workingtree_metadata)
387
def find_repository(self):
388
"""Find the repository that should be used for a_bzrdir.
390
This does not require a branch as we use it to find the repo for
391
new branches as well as to hook existing branches up to their
395
return self.open_repository()
396
except errors.NoRepositoryPresent:
398
next_transport = self.root_transport.clone('..')
400
# find the next containing bzrdir
402
found_bzrdir = BzrDir.open_containing_from_transport(
404
except errors.NotBranchError:
406
raise errors.NoRepositoryPresent(self)
407
# does it have a repository ?
409
repository = found_bzrdir.open_repository()
410
except errors.NoRepositoryPresent:
411
next_transport = found_bzrdir.root_transport.clone('..')
412
if (found_bzrdir.root_transport.base == next_transport.base):
413
# top of the file system
417
if ((found_bzrdir.root_transport.base ==
418
self.root_transport.base) or repository.is_shared()):
421
raise errors.NoRepositoryPresent(self)
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.
433
def get_branch_transport(self, branch_format):
434
"""Get the transport for use by branch format in this BzrDir.
436
Note that bzr dirs that do not support format strings will raise
437
IncompatibleFormat if the branch format they are given has
438
a format string, and vice versa.
440
If branch_format is None, the transport is returned with no
441
checking. if it is not None, then the returned transport is
442
guaranteed to point to an existing directory ready for use.
444
raise NotImplementedError(self.get_branch_transport)
446
def get_repository_transport(self, repository_format):
447
"""Get the transport for use by repository format in this BzrDir.
449
Note that bzr dirs that do not support format strings will raise
450
IncompatibleFormat if the repository format they are given has
451
a format string, and vice versa.
453
If repository_format is None, the transport is returned with no
454
checking. if it is not None, then the returned transport is
455
guaranteed to point to an existing directory ready for use.
457
raise NotImplementedError(self.get_repository_transport)
459
def get_workingtree_transport(self, tree_format):
460
"""Get the transport for use by workingtree format in this BzrDir.
462
Note that bzr dirs that do not support format strings will raise
463
IncompatibleFormat if the workingtree format they are given has a
464
format string, and vice versa.
466
If workingtree_format is None, the transport is returned with no
467
checking. if it is not None, then the returned transport is
468
guaranteed to point to an existing directory ready for use.
470
raise NotImplementedError(self.get_workingtree_transport)
472
def __init__(self, _transport, _format):
473
"""Initialize a Bzr control dir object.
475
Only really common logic should reside here, concrete classes should be
476
made with varying behaviours.
478
:param _format: the format that is creating this BzrDir instance.
479
:param _transport: the transport this dir is based at.
481
self._format = _format
482
self.transport = _transport.clone('.bzr')
483
self.root_transport = _transport
485
def is_control_filename(self, filename):
486
"""True if filename is the name of a path which is reserved for bzrdir's.
488
:param filename: A filename within the root transport of this bzrdir.
490
This is true IF and ONLY IF the filename is part of the namespace reserved
491
for bzr control dirs. Currently this is the '.bzr' directory in the root
492
of the root_transport. it is expected that plugins will need to extend
493
this in the future - for instance to make bzr talk with svn working
496
# this might be better on the BzrDirFormat class because it refers to
497
# all the possible bzrdir disk formats.
498
# This method is tested via the workingtree is_control_filename tests-
499
# it was extracted from WorkingTree.is_control_filename. If the methods
500
# contract is extended beyond the current trivial implementation please
501
# add new tests for it to the appropriate place.
502
return filename == '.bzr' or filename.startswith('.bzr/')
504
def needs_format_conversion(self, format=None):
505
"""Return true if this bzrdir needs convert_format run on it.
507
For instance, if the repository format is out of date but the
508
branch and working tree are not, this should return True.
510
:param format: Optional parameter indicating a specific desired
511
format we plan to arrive at.
513
raise NotImplementedError(self.needs_format_conversion)
516
def open_unsupported(base):
517
"""Open a branch which is not supported."""
518
return BzrDir.open(base, _unsupported=True)
521
def open(base, _unsupported=False):
522
"""Open an existing bzrdir, rooted at 'base' (url)
524
_unsupported is a private parameter to the BzrDir class.
526
t = get_transport(base)
527
return BzrDir.open_from_transport(t, _unsupported=_unsupported)
530
def open_from_transport(transport, _unsupported=False,
531
_server_formats=True):
532
"""Open a bzrdir within a particular directory.
534
:param transport: Transport containing the bzrdir.
535
:param _unsupported: private.
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)
568
BzrDir._check_supported(format, _unsupported)
569
return format.open(transport, _found=True)
571
def open_branch(self, unsupported=False):
572
"""Open the branch object at this BzrDir if one is present.
574
If unsupported is True, then no longer supported branch formats can
577
TODO: static convenience version of this?
579
raise NotImplementedError(self.open_branch)
582
def open_containing(url):
583
"""Open an existing branch which contains url.
585
:param url: url to search from.
586
See open_containing_from_transport for more detail.
588
return BzrDir.open_containing_from_transport(get_transport(url))
591
def open_containing_from_transport(a_transport):
592
"""Open an existing branch which contains a_transport.base
594
This probes for a branch at a_transport, and searches upwards from there.
596
Basically we keep looking up until we find the control directory or
597
run into the root. If there isn't one, raises NotBranchError.
598
If there is one and it is either an unrecognised format or an unsupported
599
format, UnknownFormatError or UnsupportedFormatError are raised.
600
If there is one, it is returned, along with the unused portion of url.
602
:return: The BzrDir that contains the path, and a Unicode path
603
for the rest of the URL.
605
# this gets the normalised url back. I.e. '.' -> the full path.
606
url = a_transport.base
609
result = BzrDir.open_from_transport(a_transport)
610
return result, urlutils.unescape(a_transport.relpath(url))
611
except errors.NotBranchError, e:
614
new_t = a_transport.clone('..')
615
except errors.InvalidURLJoin:
616
# reached the root, whatever that may be
617
raise errors.NotBranchError(path=url)
618
if new_t.base == a_transport.base:
619
# reached the root, whatever that may be
620
raise errors.NotBranchError(path=url)
624
def open_containing_tree_or_branch(klass, location):
625
"""Return the branch and working tree contained by a location.
627
Returns (tree, branch, relpath).
628
If there is no tree at containing the location, tree will be None.
629
If there is no branch containing the location, an exception will be
631
relpath is the portion of the path that is contained by the branch.
633
bzrdir, relpath = klass.open_containing(location)
635
tree = bzrdir.open_workingtree()
636
except (errors.NoWorkingTree, errors.NotLocalUrl):
638
branch = bzrdir.open_branch()
641
return tree, branch, relpath
643
def open_repository(self, _unsupported=False):
644
"""Open the repository object at this BzrDir if one is present.
646
This will not follow the Branch object pointer - its strictly a direct
647
open facility. Most client code should use open_branch().repository to
650
_unsupported is a private parameter, not part of the api.
651
TODO: static convenience version of this?
653
raise NotImplementedError(self.open_repository)
655
def open_workingtree(self, _unsupported=False,
656
recommend_upgrade=True):
657
"""Open the workingtree object at this BzrDir if one is present.
659
TODO: static convenience version of this?
661
raise NotImplementedError(self.open_workingtree)
663
def has_branch(self):
664
"""Tell if this bzrdir contains a branch.
666
Note: if you're going to open the branch, you should just go ahead
667
and try, and not ask permission first. (This method just opens the
668
branch and discards it, and that's somewhat expensive.)
673
except errors.NotBranchError:
676
def has_workingtree(self):
677
"""Tell if this bzrdir contains a working tree.
679
This will still raise an exception if the bzrdir has a workingtree that
680
is remote & inaccessible.
682
Note: if you're going to open the working tree, you should just go ahead
683
and try, and not ask permission first. (This method just opens the
684
workingtree and discards it, and that's somewhat expensive.)
687
self.open_workingtree(recommend_upgrade=False)
689
except errors.NoWorkingTree:
692
def _cloning_metadir(self):
693
"""Produce a metadir suitable for cloning with"""
694
result_format = self._format.__class__()
697
branch = self.open_branch()
698
source_repository = branch.repository
699
except errors.NotBranchError:
701
source_repository = self.open_repository()
702
except errors.NoRepositoryPresent:
703
source_repository = None
705
# XXX TODO: This isinstance is here because we have not implemented
706
# the fix recommended in bug # 103195 - to delegate this choice the
708
repo_format = source_repository._format
709
if not isinstance(repo_format, remote.RemoteRepositoryFormat):
710
result_format.repository_format = repo_format
712
# TODO: Couldn't we just probe for the format in these cases,
713
# rather than opening the whole tree? It would be a little
714
# faster. mbp 20070401
715
tree = self.open_workingtree(recommend_upgrade=False)
716
except (errors.NoWorkingTree, errors.NotLocalUrl):
717
result_format.workingtree_format = None
719
result_format.workingtree_format = tree._format.__class__()
720
return result_format, source_repository
722
def cloning_metadir(self):
723
"""Produce a metadir suitable for cloning or sprouting with.
725
These operations may produce workingtrees (yes, even though they're
726
"cloning" something that doesn't have a tree, so a viable workingtree
727
format must be selected.
729
format, repository = self._cloning_metadir()
730
if format._workingtree_format is None:
731
if repository is None:
733
tree_format = repository._format._matchingbzrdir.workingtree_format
734
format.workingtree_format = tree_format.__class__()
737
def checkout_metadir(self):
738
return self.cloning_metadir()
740
def sprout(self, url, revision_id=None, force_new_repo=False,
742
"""Create a copy of this bzrdir prepared for use as a new line of
745
If urls last component does not exist, it will be created.
747
Attributes related to the identity of the source branch like
748
branch nickname will be cleaned, a working tree is created
749
whether one existed before or not; and a local branch is always
752
if revision_id is not None, then the clone operation may tune
753
itself to download less data.
756
cloning_format = self.cloning_metadir()
757
result = cloning_format.initialize(url)
759
source_branch = self.open_branch()
760
source_repository = source_branch.repository
761
except errors.NotBranchError:
764
source_repository = self.open_repository()
765
except errors.NoRepositoryPresent:
766
source_repository = None
771
result_repo = result.find_repository()
772
except errors.NoRepositoryPresent:
774
if source_repository is None and result_repo is not None:
776
elif source_repository is None and result_repo is None:
777
# no repo available, make a new one
778
result.create_repository()
779
elif source_repository is not None and result_repo is None:
780
# have source, and want to make a new target repo
781
# we don't clone the repo because that preserves attributes
782
# like is_shared(), and we have not yet implemented a
783
# repository sprout().
784
result_repo = result.create_repository()
785
if result_repo is not None:
786
# fetch needed content into target.
787
if source_repository is not None:
788
result_repo.fetch(source_repository, revision_id=revision_id)
789
if source_branch is not None:
790
source_branch.sprout(result, revision_id=revision_id)
792
result.create_branch()
793
# TODO: jam 20060426 we probably need a test in here in the
794
# case that the newly sprouted branch is a remote one
795
if result_repo is None or result_repo.make_working_trees():
796
wt = result.create_workingtree()
799
if wt.path2id('') is None:
801
wt.set_root_id(self.open_workingtree.get_root_id())
802
except errors.NoWorkingTree:
808
if recurse == 'down':
810
basis = wt.basis_tree()
812
subtrees = basis.iter_references()
813
recurse_branch = wt.branch
814
elif source_branch is not None:
815
basis = source_branch.basis_tree()
817
subtrees = basis.iter_references()
818
recurse_branch = source_branch
823
for path, file_id in subtrees:
824
target = urlutils.join(url, urlutils.escape(path))
825
sublocation = source_branch.reference_parent(file_id, path)
826
sublocation.bzrdir.sprout(target,
827
basis.get_reference_revision(file_id, path),
828
force_new_repo=force_new_repo, recurse=recurse)
830
if basis is not None:
835
class BzrDirPreSplitOut(BzrDir):
836
"""A common class for the all-in-one formats."""
838
def __init__(self, _transport, _format):
839
"""See BzrDir.__init__."""
840
super(BzrDirPreSplitOut, self).__init__(_transport, _format)
841
assert self._format._lock_class == lockable_files.TransportLock
842
assert self._format._lock_file_name == 'branch-lock'
843
self._control_files = lockable_files.LockableFiles(
844
self.get_branch_transport(None),
845
self._format._lock_file_name,
846
self._format._lock_class)
848
def break_lock(self):
849
"""Pre-splitout bzrdirs do not suffer from stale locks."""
850
raise NotImplementedError(self.break_lock)
852
def clone(self, url, revision_id=None, force_new_repo=False):
853
"""See BzrDir.clone()."""
854
from bzrlib.workingtree import WorkingTreeFormat2
856
result = self._format._initialize_for_clone(url)
857
self.open_repository().clone(result, revision_id=revision_id)
858
from_branch = self.open_branch()
859
from_branch.clone(result, revision_id=revision_id)
861
self.open_workingtree().clone(result)
862
except errors.NotLocalUrl:
863
# make a new one, this format always has to have one.
865
WorkingTreeFormat2().initialize(result)
866
except errors.NotLocalUrl:
867
# but we cannot do it for remote trees.
868
to_branch = result.open_branch()
869
WorkingTreeFormat2().stub_initialize_remote(to_branch.control_files)
872
def create_branch(self):
873
"""See BzrDir.create_branch."""
874
return self.open_branch()
876
def create_repository(self, shared=False):
877
"""See BzrDir.create_repository."""
879
raise errors.IncompatibleFormat('shared repository', self._format)
880
return self.open_repository()
882
def create_workingtree(self, revision_id=None):
883
"""See BzrDir.create_workingtree."""
884
# this looks buggy but is not -really-
885
# because this format creates the workingtree when the bzrdir is
887
# clone and sprout will have set the revision_id
888
# and that will have set it for us, its only
889
# specific uses of create_workingtree in isolation
890
# that can do wonky stuff here, and that only
891
# happens for creating checkouts, which cannot be
892
# done on this format anyway. So - acceptable wart.
893
result = self.open_workingtree(recommend_upgrade=False)
894
if revision_id is not None:
895
if revision_id == _mod_revision.NULL_REVISION:
896
result.set_parent_ids([])
898
result.set_parent_ids([revision_id])
901
def destroy_workingtree(self):
902
"""See BzrDir.destroy_workingtree."""
903
raise errors.UnsupportedOperation(self.destroy_workingtree, self)
905
def destroy_workingtree_metadata(self):
906
"""See BzrDir.destroy_workingtree_metadata."""
907
raise errors.UnsupportedOperation(self.destroy_workingtree_metadata,
910
def get_branch_transport(self, branch_format):
911
"""See BzrDir.get_branch_transport()."""
912
if branch_format is None:
913
return self.transport
915
branch_format.get_format_string()
916
except NotImplementedError:
917
return self.transport
918
raise errors.IncompatibleFormat(branch_format, self._format)
920
def get_repository_transport(self, repository_format):
921
"""See BzrDir.get_repository_transport()."""
922
if repository_format is None:
923
return self.transport
925
repository_format.get_format_string()
926
except NotImplementedError:
927
return self.transport
928
raise errors.IncompatibleFormat(repository_format, self._format)
930
def get_workingtree_transport(self, workingtree_format):
931
"""See BzrDir.get_workingtree_transport()."""
932
if workingtree_format is None:
933
return self.transport
935
workingtree_format.get_format_string()
936
except NotImplementedError:
937
return self.transport
938
raise errors.IncompatibleFormat(workingtree_format, self._format)
940
def needs_format_conversion(self, format=None):
941
"""See BzrDir.needs_format_conversion()."""
942
# if the format is not the same as the system default,
943
# an upgrade is needed.
945
format = BzrDirFormat.get_default_format()
946
return not isinstance(self._format, format.__class__)
948
def open_branch(self, unsupported=False):
949
"""See BzrDir.open_branch."""
950
from bzrlib.branch import BzrBranchFormat4
951
format = BzrBranchFormat4()
952
self._check_supported(format, unsupported)
953
return format.open(self, _found=True)
955
def sprout(self, url, revision_id=None, force_new_repo=False):
956
"""See BzrDir.sprout()."""
957
from bzrlib.workingtree import WorkingTreeFormat2
959
result = self._format._initialize_for_clone(url)
961
self.open_repository().clone(result, revision_id=revision_id)
962
except errors.NoRepositoryPresent:
965
self.open_branch().sprout(result, revision_id=revision_id)
966
except errors.NotBranchError:
968
# we always want a working tree
969
WorkingTreeFormat2().initialize(result)
973
class BzrDir4(BzrDirPreSplitOut):
974
"""A .bzr version 4 control object.
976
This is a deprecated format and may be removed after sept 2006.
979
def create_repository(self, shared=False):
980
"""See BzrDir.create_repository."""
981
return self._format.repository_format.initialize(self, shared)
983
def needs_format_conversion(self, format=None):
984
"""Format 4 dirs are always in need of conversion."""
987
def open_repository(self):
988
"""See BzrDir.open_repository."""
989
from bzrlib.repofmt.weaverepo import RepositoryFormat4
990
return RepositoryFormat4().open(self, _found=True)
993
class BzrDir5(BzrDirPreSplitOut):
994
"""A .bzr version 5 control object.
996
This is a deprecated format and may be removed after sept 2006.
999
def open_repository(self):
1000
"""See BzrDir.open_repository."""
1001
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1002
return RepositoryFormat5().open(self, _found=True)
1004
def open_workingtree(self, _unsupported=False,
1005
recommend_upgrade=True):
1006
"""See BzrDir.create_workingtree."""
1007
from bzrlib.workingtree import WorkingTreeFormat2
1008
wt_format = WorkingTreeFormat2()
1009
# we don't warn here about upgrades; that ought to be handled for the
1011
return wt_format.open(self, _found=True)
1014
class BzrDir6(BzrDirPreSplitOut):
1015
"""A .bzr version 6 control object.
1017
This is a deprecated format and may be removed after sept 2006.
1020
def open_repository(self):
1021
"""See BzrDir.open_repository."""
1022
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1023
return RepositoryFormat6().open(self, _found=True)
1025
def open_workingtree(self, _unsupported=False,
1026
recommend_upgrade=True):
1027
"""See BzrDir.create_workingtree."""
1028
# we don't warn here about upgrades; that ought to be handled for the
1030
from bzrlib.workingtree import WorkingTreeFormat2
1031
return WorkingTreeFormat2().open(self, _found=True)
1034
class BzrDirMeta1(BzrDir):
1035
"""A .bzr meta version 1 control object.
1037
This is the first control object where the
1038
individual aspects are really split out: there are separate repository,
1039
workingtree and branch subdirectories and any subset of the three can be
1040
present within a BzrDir.
1043
def can_convert_format(self):
1044
"""See BzrDir.can_convert_format()."""
1047
def create_branch(self):
1048
"""See BzrDir.create_branch."""
1049
return self._format.get_branch_format().initialize(self)
1051
def create_repository(self, shared=False):
1052
"""See BzrDir.create_repository."""
1053
return self._format.repository_format.initialize(self, shared)
1055
def create_workingtree(self, revision_id=None):
1056
"""See BzrDir.create_workingtree."""
1057
from bzrlib.workingtree import WorkingTreeFormat
1058
return self._format.workingtree_format.initialize(self, revision_id)
1060
def destroy_workingtree(self):
1061
"""See BzrDir.destroy_workingtree."""
1062
wt = self.open_workingtree(recommend_upgrade=False)
1063
repository = wt.branch.repository
1064
empty = repository.revision_tree(_mod_revision.NULL_REVISION)
1065
wt.revert([], old_tree=empty)
1066
self.destroy_workingtree_metadata()
1068
def destroy_workingtree_metadata(self):
1069
self.transport.delete_tree('checkout')
1071
def find_branch_format(self):
1072
"""Find the branch 'format' for this bzrdir.
1074
This might be a synthetic object for e.g. RemoteBranch and SVN.
1076
from bzrlib.branch import BranchFormat
1077
return BranchFormat.find_format(self)
1079
def _get_mkdir_mode(self):
1080
"""Figure out the mode to use when creating a bzrdir subdir."""
1081
temp_control = lockable_files.LockableFiles(self.transport, '',
1082
lockable_files.TransportLock)
1083
return temp_control._dir_mode
1085
def get_branch_reference(self):
1086
"""See BzrDir.get_branch_reference()."""
1087
from bzrlib.branch import BranchFormat
1088
format = BranchFormat.find_format(self)
1089
return format.get_reference(self)
1091
def get_branch_transport(self, branch_format):
1092
"""See BzrDir.get_branch_transport()."""
1093
if branch_format is None:
1094
return self.transport.clone('branch')
1096
branch_format.get_format_string()
1097
except NotImplementedError:
1098
raise errors.IncompatibleFormat(branch_format, self._format)
1100
self.transport.mkdir('branch', mode=self._get_mkdir_mode())
1101
except errors.FileExists:
1103
return self.transport.clone('branch')
1105
def get_repository_transport(self, repository_format):
1106
"""See BzrDir.get_repository_transport()."""
1107
if repository_format is None:
1108
return self.transport.clone('repository')
1110
repository_format.get_format_string()
1111
except NotImplementedError:
1112
raise errors.IncompatibleFormat(repository_format, self._format)
1114
self.transport.mkdir('repository', mode=self._get_mkdir_mode())
1115
except errors.FileExists:
1117
return self.transport.clone('repository')
1119
def get_workingtree_transport(self, workingtree_format):
1120
"""See BzrDir.get_workingtree_transport()."""
1121
if workingtree_format is None:
1122
return self.transport.clone('checkout')
1124
workingtree_format.get_format_string()
1125
except NotImplementedError:
1126
raise errors.IncompatibleFormat(workingtree_format, self._format)
1128
self.transport.mkdir('checkout', mode=self._get_mkdir_mode())
1129
except errors.FileExists:
1131
return self.transport.clone('checkout')
1133
def needs_format_conversion(self, format=None):
1134
"""See BzrDir.needs_format_conversion()."""
1136
format = BzrDirFormat.get_default_format()
1137
if not isinstance(self._format, format.__class__):
1138
# it is not a meta dir format, conversion is needed.
1140
# we might want to push this down to the repository?
1142
if not isinstance(self.open_repository()._format,
1143
format.repository_format.__class__):
1144
# the repository needs an upgrade.
1146
except errors.NoRepositoryPresent:
1149
if not isinstance(self.open_branch()._format,
1150
format.get_branch_format().__class__):
1151
# the branch needs an upgrade.
1153
except errors.NotBranchError:
1156
my_wt = self.open_workingtree(recommend_upgrade=False)
1157
if not isinstance(my_wt._format,
1158
format.workingtree_format.__class__):
1159
# the workingtree needs an upgrade.
1161
except (errors.NoWorkingTree, errors.NotLocalUrl):
1165
def open_branch(self, unsupported=False):
1166
"""See BzrDir.open_branch."""
1167
format = self.find_branch_format()
1168
self._check_supported(format, unsupported)
1169
return format.open(self, _found=True)
1171
def open_repository(self, unsupported=False):
1172
"""See BzrDir.open_repository."""
1173
from bzrlib.repository import RepositoryFormat
1174
format = RepositoryFormat.find_format(self)
1175
self._check_supported(format, unsupported)
1176
return format.open(self, _found=True)
1178
def open_workingtree(self, unsupported=False,
1179
recommend_upgrade=True):
1180
"""See BzrDir.open_workingtree."""
1181
from bzrlib.workingtree import WorkingTreeFormat
1182
format = WorkingTreeFormat.find_format(self)
1183
self._check_supported(format, unsupported,
1185
basedir=self.root_transport.base)
1186
return format.open(self, _found=True)
1189
class BzrDirFormat(object):
1190
"""An encapsulation of the initialization and open routines for a format.
1192
Formats provide three things:
1193
* An initialization routine,
1197
Formats are placed in an dict by their format string for reference
1198
during bzrdir opening. These should be subclasses of BzrDirFormat
1201
Once a format is deprecated, just deprecate the initialize and open
1202
methods on the format class. Do not deprecate the object, as the
1203
object will be created every system load.
1206
_default_format = None
1207
"""The default format used for new .bzr dirs."""
1210
"""The known formats."""
1212
_control_formats = []
1213
"""The registered control formats - .bzr, ....
1215
This is a list of BzrDirFormat objects.
1218
_control_server_formats = []
1219
"""The registered control server formats, e.g. RemoteBzrDirs.
1221
This is a list of BzrDirFormat objects.
1224
_lock_file_name = 'branch-lock'
1226
# _lock_class must be set in subclasses to the lock type, typ.
1227
# TransportLock or LockDir
1230
def find_format(klass, transport, _server_formats=True):
1231
"""Return the format present at transport."""
1233
formats = klass._control_server_formats + klass._control_formats
1235
formats = klass._control_formats
1236
for format in formats:
1238
return format.probe_transport(transport)
1239
except errors.NotBranchError:
1240
# this format does not find a control dir here.
1242
raise errors.NotBranchError(path=transport.base)
1245
def probe_transport(klass, transport):
1246
"""Return the .bzrdir style format present in a directory."""
1248
format_string = transport.get(".bzr/branch-format").read()
1249
except errors.NoSuchFile:
1250
raise errors.NotBranchError(path=transport.base)
1253
return klass._formats[format_string]
1255
raise errors.UnknownFormatError(format=format_string)
1258
def get_default_format(klass):
1259
"""Return the current default format."""
1260
return klass._default_format
1262
def get_format_string(self):
1263
"""Return the ASCII format string that identifies this format."""
1264
raise NotImplementedError(self.get_format_string)
1266
def get_format_description(self):
1267
"""Return the short description for this format."""
1268
raise NotImplementedError(self.get_format_description)
1270
def get_converter(self, format=None):
1271
"""Return the converter to use to convert bzrdirs needing converts.
1273
This returns a bzrlib.bzrdir.Converter object.
1275
This should return the best upgrader to step this format towards the
1276
current default format. In the case of plugins we can/should provide
1277
some means for them to extend the range of returnable converters.
1279
:param format: Optional format to override the default format of the
1282
raise NotImplementedError(self.get_converter)
1284
def initialize(self, url):
1285
"""Create a bzr control dir at this url and return an opened copy.
1287
Subclasses should typically override initialize_on_transport
1288
instead of this method.
1290
return self.initialize_on_transport(get_transport(url))
1292
def initialize_on_transport(self, transport):
1293
"""Initialize a new bzrdir in the base directory of a Transport."""
1294
# Since we don't have a .bzr directory, inherit the
1295
# mode from the root directory
1296
temp_control = lockable_files.LockableFiles(transport,
1297
'', lockable_files.TransportLock)
1298
temp_control._transport.mkdir('.bzr',
1299
# FIXME: RBC 20060121 don't peek under
1301
mode=temp_control._dir_mode)
1302
file_mode = temp_control._file_mode
1304
mutter('created control directory in ' + transport.base)
1305
control = transport.clone('.bzr')
1306
utf8_files = [('README',
1307
"This is a Bazaar-NG control directory.\n"
1308
"Do not change any files in this directory.\n"),
1309
('branch-format', self.get_format_string()),
1311
# NB: no need to escape relative paths that are url safe.
1312
control_files = lockable_files.LockableFiles(control,
1313
self._lock_file_name, self._lock_class)
1314
control_files.create_lock()
1315
control_files.lock_write()
1317
for file, content in utf8_files:
1318
control_files.put_utf8(file, content)
1320
control_files.unlock()
1321
return self.open(transport, _found=True)
1323
def is_supported(self):
1324
"""Is this format supported?
1326
Supported formats must be initializable and openable.
1327
Unsupported formats may not support initialization or committing or
1328
some other features depending on the reason for not being supported.
1332
def same_model(self, target_format):
1333
return (self.repository_format.rich_root_data ==
1334
target_format.rich_root_data)
1337
def known_formats(klass):
1338
"""Return all the known formats.
1340
Concrete formats should override _known_formats.
1342
# There is double indirection here to make sure that control
1343
# formats used by more than one dir format will only be probed
1344
# once. This can otherwise be quite expensive for remote connections.
1346
for format in klass._control_formats:
1347
result.update(format._known_formats())
1351
def _known_formats(klass):
1352
"""Return the known format instances for this control format."""
1353
return set(klass._formats.values())
1355
def open(self, transport, _found=False):
1356
"""Return an instance of this format for the dir transport points at.
1358
_found is a private parameter, do not use it.
1361
found_format = BzrDirFormat.find_format(transport)
1362
if not isinstance(found_format, self.__class__):
1363
raise AssertionError("%s was asked to open %s, but it seems to need "
1365
% (self, transport, found_format))
1366
return self._open(transport)
1368
def _open(self, transport):
1369
"""Template method helper for opening BzrDirectories.
1371
This performs the actual open and any additional logic or parameter
1374
raise NotImplementedError(self._open)
1377
def register_format(klass, format):
1378
klass._formats[format.get_format_string()] = format
1381
def register_control_format(klass, format):
1382
"""Register a format that does not use '.bzr' for its control dir.
1384
TODO: This should be pulled up into a 'ControlDirFormat' base class
1385
which BzrDirFormat can inherit from, and renamed to register_format
1386
there. It has been done without that for now for simplicity of
1389
klass._control_formats.append(format)
1392
def register_control_server_format(klass, format):
1393
"""Register a control format for client-server environments.
1395
These formats will be tried before ones registered with
1396
register_control_format. This gives implementations that decide to the
1397
chance to grab it before anything looks at the contents of the format
1400
klass._control_server_formats.append(format)
1403
@symbol_versioning.deprecated_method(symbol_versioning.zero_fourteen)
1404
def set_default_format(klass, format):
1405
klass._set_default_format(format)
1408
def _set_default_format(klass, format):
1409
"""Set default format (for testing behavior of defaults only)"""
1410
klass._default_format = format
1413
return self.get_format_string()[:-1]
1416
def unregister_format(klass, format):
1417
assert klass._formats[format.get_format_string()] is format
1418
del klass._formats[format.get_format_string()]
1421
def unregister_control_format(klass, format):
1422
klass._control_formats.remove(format)
1425
class BzrDirFormat4(BzrDirFormat):
1426
"""Bzr dir format 4.
1428
This format is a combined format for working tree, branch and repository.
1430
- Format 1 working trees [always]
1431
- Format 4 branches [always]
1432
- Format 4 repositories [always]
1434
This format is deprecated: it indexes texts using a text it which is
1435
removed in format 5; write support for this format has been removed.
1438
_lock_class = lockable_files.TransportLock
1440
def get_format_string(self):
1441
"""See BzrDirFormat.get_format_string()."""
1442
return "Bazaar-NG branch, format 0.0.4\n"
1444
def get_format_description(self):
1445
"""See BzrDirFormat.get_format_description()."""
1446
return "All-in-one format 4"
1448
def get_converter(self, format=None):
1449
"""See BzrDirFormat.get_converter()."""
1450
# there is one and only one upgrade path here.
1451
return ConvertBzrDir4To5()
1453
def initialize_on_transport(self, transport):
1454
"""Format 4 branches cannot be created."""
1455
raise errors.UninitializableFormat(self)
1457
def is_supported(self):
1458
"""Format 4 is not supported.
1460
It is not supported because the model changed from 4 to 5 and the
1461
conversion logic is expensive - so doing it on the fly was not
1466
def _open(self, transport):
1467
"""See BzrDirFormat._open."""
1468
return BzrDir4(transport, self)
1470
def __return_repository_format(self):
1471
"""Circular import protection."""
1472
from bzrlib.repofmt.weaverepo import RepositoryFormat4
1473
return RepositoryFormat4()
1474
repository_format = property(__return_repository_format)
1477
class BzrDirFormat5(BzrDirFormat):
1478
"""Bzr control format 5.
1480
This format is a combined format for working tree, branch and repository.
1482
- Format 2 working trees [always]
1483
- Format 4 branches [always]
1484
- Format 5 repositories [always]
1485
Unhashed stores in the repository.
1488
_lock_class = lockable_files.TransportLock
1490
def get_format_string(self):
1491
"""See BzrDirFormat.get_format_string()."""
1492
return "Bazaar-NG branch, format 5\n"
1494
def get_format_description(self):
1495
"""See BzrDirFormat.get_format_description()."""
1496
return "All-in-one format 5"
1498
def get_converter(self, format=None):
1499
"""See BzrDirFormat.get_converter()."""
1500
# there is one and only one upgrade path here.
1501
return ConvertBzrDir5To6()
1503
def _initialize_for_clone(self, url):
1504
return self.initialize_on_transport(get_transport(url), _cloning=True)
1506
def initialize_on_transport(self, transport, _cloning=False):
1507
"""Format 5 dirs always have working tree, branch and repository.
1509
Except when they are being cloned.
1511
from bzrlib.branch import BzrBranchFormat4
1512
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1513
from bzrlib.workingtree import WorkingTreeFormat2
1514
result = (super(BzrDirFormat5, self).initialize_on_transport(transport))
1515
RepositoryFormat5().initialize(result, _internal=True)
1517
branch = BzrBranchFormat4().initialize(result)
1519
WorkingTreeFormat2().initialize(result)
1520
except errors.NotLocalUrl:
1521
# Even though we can't access the working tree, we need to
1522
# create its control files.
1523
WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
1526
def _open(self, transport):
1527
"""See BzrDirFormat._open."""
1528
return BzrDir5(transport, self)
1530
def __return_repository_format(self):
1531
"""Circular import protection."""
1532
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1533
return RepositoryFormat5()
1534
repository_format = property(__return_repository_format)
1537
class BzrDirFormat6(BzrDirFormat):
1538
"""Bzr control format 6.
1540
This format is a combined format for working tree, branch and repository.
1542
- Format 2 working trees [always]
1543
- Format 4 branches [always]
1544
- Format 6 repositories [always]
1547
_lock_class = lockable_files.TransportLock
1549
def get_format_string(self):
1550
"""See BzrDirFormat.get_format_string()."""
1551
return "Bazaar-NG branch, format 6\n"
1553
def get_format_description(self):
1554
"""See BzrDirFormat.get_format_description()."""
1555
return "All-in-one format 6"
1557
def get_converter(self, format=None):
1558
"""See BzrDirFormat.get_converter()."""
1559
# there is one and only one upgrade path here.
1560
return ConvertBzrDir6ToMeta()
1562
def _initialize_for_clone(self, url):
1563
return self.initialize_on_transport(get_transport(url), _cloning=True)
1565
def initialize_on_transport(self, transport, _cloning=False):
1566
"""Format 6 dirs always have working tree, branch and repository.
1568
Except when they are being cloned.
1570
from bzrlib.branch import BzrBranchFormat4
1571
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1572
from bzrlib.workingtree import WorkingTreeFormat2
1573
result = super(BzrDirFormat6, self).initialize_on_transport(transport)
1574
RepositoryFormat6().initialize(result, _internal=True)
1576
branch = BzrBranchFormat4().initialize(result)
1578
WorkingTreeFormat2().initialize(result)
1579
except errors.NotLocalUrl:
1580
# Even though we can't access the working tree, we need to
1581
# create its control files.
1582
WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
1585
def _open(self, transport):
1586
"""See BzrDirFormat._open."""
1587
return BzrDir6(transport, self)
1589
def __return_repository_format(self):
1590
"""Circular import protection."""
1591
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1592
return RepositoryFormat6()
1593
repository_format = property(__return_repository_format)
1596
class BzrDirMetaFormat1(BzrDirFormat):
1597
"""Bzr meta control format 1
1599
This is the first format with split out working tree, branch and repository
1602
- Format 3 working trees [optional]
1603
- Format 5 branches [optional]
1604
- Format 7 repositories [optional]
1607
_lock_class = lockdir.LockDir
1610
self._workingtree_format = None
1611
self._branch_format = None
1613
def __eq__(self, other):
1614
if other.__class__ is not self.__class__:
1616
if other.repository_format != self.repository_format:
1618
if other.workingtree_format != self.workingtree_format:
1622
def __ne__(self, other):
1623
return not self == other
1625
def get_branch_format(self):
1626
if self._branch_format is None:
1627
from bzrlib.branch import BranchFormat
1628
self._branch_format = BranchFormat.get_default_format()
1629
return self._branch_format
1631
def set_branch_format(self, format):
1632
self._branch_format = format
1634
def get_converter(self, format=None):
1635
"""See BzrDirFormat.get_converter()."""
1637
format = BzrDirFormat.get_default_format()
1638
if not isinstance(self, format.__class__):
1639
# converting away from metadir is not implemented
1640
raise NotImplementedError(self.get_converter)
1641
return ConvertMetaToMeta(format)
1643
def get_format_string(self):
1644
"""See BzrDirFormat.get_format_string()."""
1645
return "Bazaar-NG meta directory, format 1\n"
1647
def get_format_description(self):
1648
"""See BzrDirFormat.get_format_description()."""
1649
return "Meta directory format 1"
1651
def _open(self, transport):
1652
"""See BzrDirFormat._open."""
1653
return BzrDirMeta1(transport, self)
1655
def __return_repository_format(self):
1656
"""Circular import protection."""
1657
if getattr(self, '_repository_format', None):
1658
return self._repository_format
1659
from bzrlib.repository import RepositoryFormat
1660
return RepositoryFormat.get_default_format()
1662
def __set_repository_format(self, value):
1663
"""Allow changint the repository format for metadir formats."""
1664
self._repository_format = value
1666
repository_format = property(__return_repository_format, __set_repository_format)
1668
def __get_workingtree_format(self):
1669
if self._workingtree_format is None:
1670
from bzrlib.workingtree import WorkingTreeFormat
1671
self._workingtree_format = WorkingTreeFormat.get_default_format()
1672
return self._workingtree_format
1674
def __set_workingtree_format(self, wt_format):
1675
self._workingtree_format = wt_format
1677
workingtree_format = property(__get_workingtree_format,
1678
__set_workingtree_format)
1681
# Register bzr control format
1682
BzrDirFormat.register_control_format(BzrDirFormat)
1684
# Register bzr formats
1685
BzrDirFormat.register_format(BzrDirFormat4())
1686
BzrDirFormat.register_format(BzrDirFormat5())
1687
BzrDirFormat.register_format(BzrDirFormat6())
1688
__default_format = BzrDirMetaFormat1()
1689
BzrDirFormat.register_format(__default_format)
1690
BzrDirFormat._default_format = __default_format
1693
class BzrDirTestProviderAdapter(object):
1694
"""A tool to generate a suite testing multiple bzrdir formats at once.
1696
This is done by copying the test once for each transport and injecting
1697
the transport_server, transport_readonly_server, and bzrdir_format
1698
classes into each copy. Each copy is also given a new id() to make it
1702
def __init__(self, vfs_factory, transport_server, transport_readonly_server,
1704
"""Create an object to adapt tests.
1706
:param vfs_server: A factory to create a Transport Server which has
1707
all the VFS methods working, and is writable.
1709
self._vfs_factory = vfs_factory
1710
self._transport_server = transport_server
1711
self._transport_readonly_server = transport_readonly_server
1712
self._formats = formats
1714
def adapt(self, test):
1715
result = unittest.TestSuite()
1716
for format in self._formats:
1717
new_test = deepcopy(test)
1718
new_test.vfs_transport_factory = self._vfs_factory
1719
new_test.transport_server = self._transport_server
1720
new_test.transport_readonly_server = self._transport_readonly_server
1721
new_test.bzrdir_format = format
1722
def make_new_test_id():
1723
new_id = "%s(%s)" % (new_test.id(), format.__class__.__name__)
1724
return lambda: new_id
1725
new_test.id = make_new_test_id()
1726
result.addTest(new_test)
1730
class Converter(object):
1731
"""Converts a disk format object from one format to another."""
1733
def convert(self, to_convert, pb):
1734
"""Perform the conversion of to_convert, giving feedback via pb.
1736
:param to_convert: The disk object to convert.
1737
:param pb: a progress bar to use for progress information.
1740
def step(self, message):
1741
"""Update the pb by a step."""
1743
self.pb.update(message, self.count, self.total)
1746
class ConvertBzrDir4To5(Converter):
1747
"""Converts format 4 bzr dirs to format 5."""
1750
super(ConvertBzrDir4To5, self).__init__()
1751
self.converted_revs = set()
1752
self.absent_revisions = set()
1756
def convert(self, to_convert, pb):
1757
"""See Converter.convert()."""
1758
self.bzrdir = to_convert
1760
self.pb.note('starting upgrade from format 4 to 5')
1761
if isinstance(self.bzrdir.transport, LocalTransport):
1762
self.bzrdir.get_workingtree_transport(None).delete('stat-cache')
1763
self._convert_to_weaves()
1764
return BzrDir.open(self.bzrdir.root_transport.base)
1766
def _convert_to_weaves(self):
1767
self.pb.note('note: upgrade may be faster if all store files are ungzipped first')
1770
stat = self.bzrdir.transport.stat('weaves')
1771
if not S_ISDIR(stat.st_mode):
1772
self.bzrdir.transport.delete('weaves')
1773
self.bzrdir.transport.mkdir('weaves')
1774
except errors.NoSuchFile:
1775
self.bzrdir.transport.mkdir('weaves')
1776
# deliberately not a WeaveFile as we want to build it up slowly.
1777
self.inv_weave = Weave('inventory')
1778
# holds in-memory weaves for all files
1779
self.text_weaves = {}
1780
self.bzrdir.transport.delete('branch-format')
1781
self.branch = self.bzrdir.open_branch()
1782
self._convert_working_inv()
1783
rev_history = self.branch.revision_history()
1784
# to_read is a stack holding the revisions we still need to process;
1785
# appending to it adds new highest-priority revisions
1786
self.known_revisions = set(rev_history)
1787
self.to_read = rev_history[-1:]
1789
rev_id = self.to_read.pop()
1790
if (rev_id not in self.revisions
1791
and rev_id not in self.absent_revisions):
1792
self._load_one_rev(rev_id)
1794
to_import = self._make_order()
1795
for i, rev_id in enumerate(to_import):
1796
self.pb.update('converting revision', i, len(to_import))
1797
self._convert_one_rev(rev_id)
1799
self._write_all_weaves()
1800
self._write_all_revs()
1801
self.pb.note('upgraded to weaves:')
1802
self.pb.note(' %6d revisions and inventories', len(self.revisions))
1803
self.pb.note(' %6d revisions not present', len(self.absent_revisions))
1804
self.pb.note(' %6d texts', self.text_count)
1805
self._cleanup_spare_files_after_format4()
1806
self.branch.control_files.put_utf8('branch-format', BzrDirFormat5().get_format_string())
1808
def _cleanup_spare_files_after_format4(self):
1809
# FIXME working tree upgrade foo.
1810
for n in 'merged-patches', 'pending-merged-patches':
1812
## assert os.path.getsize(p) == 0
1813
self.bzrdir.transport.delete(n)
1814
except errors.NoSuchFile:
1816
self.bzrdir.transport.delete_tree('inventory-store')
1817
self.bzrdir.transport.delete_tree('text-store')
1819
def _convert_working_inv(self):
1820
inv = xml4.serializer_v4.read_inventory(
1821
self.branch.control_files.get('inventory'))
1822
new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
1823
# FIXME inventory is a working tree change.
1824
self.branch.control_files.put('inventory', StringIO(new_inv_xml))
1826
def _write_all_weaves(self):
1827
controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)
1828
weave_transport = self.bzrdir.transport.clone('weaves')
1829
weaves = WeaveStore(weave_transport, prefixed=False)
1830
transaction = WriteTransaction()
1834
for file_id, file_weave in self.text_weaves.items():
1835
self.pb.update('writing weave', i, len(self.text_weaves))
1836
weaves._put_weave(file_id, file_weave, transaction)
1838
self.pb.update('inventory', 0, 1)
1839
controlweaves._put_weave('inventory', self.inv_weave, transaction)
1840
self.pb.update('inventory', 1, 1)
1844
def _write_all_revs(self):
1845
"""Write all revisions out in new form."""
1846
self.bzrdir.transport.delete_tree('revision-store')
1847
self.bzrdir.transport.mkdir('revision-store')
1848
revision_transport = self.bzrdir.transport.clone('revision-store')
1850
_revision_store = TextRevisionStore(TextStore(revision_transport,
1854
transaction = WriteTransaction()
1855
for i, rev_id in enumerate(self.converted_revs):
1856
self.pb.update('write revision', i, len(self.converted_revs))
1857
_revision_store.add_revision(self.revisions[rev_id], transaction)
1861
def _load_one_rev(self, rev_id):
1862
"""Load a revision object into memory.
1864
Any parents not either loaded or abandoned get queued to be
1866
self.pb.update('loading revision',
1867
len(self.revisions),
1868
len(self.known_revisions))
1869
if not self.branch.repository.has_revision(rev_id):
1871
self.pb.note('revision {%s} not present in branch; '
1872
'will be converted as a ghost',
1874
self.absent_revisions.add(rev_id)
1876
rev = self.branch.repository._revision_store.get_revision(rev_id,
1877
self.branch.repository.get_transaction())
1878
for parent_id in rev.parent_ids:
1879
self.known_revisions.add(parent_id)
1880
self.to_read.append(parent_id)
1881
self.revisions[rev_id] = rev
1883
def _load_old_inventory(self, rev_id):
1884
assert rev_id not in self.converted_revs
1885
old_inv_xml = self.branch.repository.inventory_store.get(rev_id).read()
1886
inv = xml4.serializer_v4.read_inventory_from_string(old_inv_xml)
1887
inv.revision_id = rev_id
1888
rev = self.revisions[rev_id]
1889
if rev.inventory_sha1:
1890
assert rev.inventory_sha1 == sha_string(old_inv_xml), \
1891
'inventory sha mismatch for {%s}' % rev_id
1894
def _load_updated_inventory(self, rev_id):
1895
assert rev_id in self.converted_revs
1896
inv_xml = self.inv_weave.get_text(rev_id)
1897
inv = xml5.serializer_v5.read_inventory_from_string(inv_xml)
1900
def _convert_one_rev(self, rev_id):
1901
"""Convert revision and all referenced objects to new format."""
1902
rev = self.revisions[rev_id]
1903
inv = self._load_old_inventory(rev_id)
1904
present_parents = [p for p in rev.parent_ids
1905
if p not in self.absent_revisions]
1906
self._convert_revision_contents(rev, inv, present_parents)
1907
self._store_new_weave(rev, inv, present_parents)
1908
self.converted_revs.add(rev_id)
1910
def _store_new_weave(self, rev, inv, present_parents):
1911
# the XML is now updated with text versions
1913
entries = inv.iter_entries()
1915
for path, ie in entries:
1916
assert getattr(ie, 'revision', None) is not None, \
1917
'no revision on {%s} in {%s}' % \
1918
(file_id, rev.revision_id)
1919
new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
1920
new_inv_sha1 = sha_string(new_inv_xml)
1921
self.inv_weave.add_lines(rev.revision_id,
1923
new_inv_xml.splitlines(True))
1924
rev.inventory_sha1 = new_inv_sha1
1926
def _convert_revision_contents(self, rev, inv, present_parents):
1927
"""Convert all the files within a revision.
1929
Also upgrade the inventory to refer to the text revision ids."""
1930
rev_id = rev.revision_id
1931
mutter('converting texts of revision {%s}',
1933
parent_invs = map(self._load_updated_inventory, present_parents)
1934
entries = inv.iter_entries()
1936
for path, ie in entries:
1937
self._convert_file_version(rev, ie, parent_invs)
1939
def _convert_file_version(self, rev, ie, parent_invs):
1940
"""Convert one version of one file.
1942
The file needs to be added into the weave if it is a merge
1943
of >=2 parents or if it's changed from its parent.
1945
file_id = ie.file_id
1946
rev_id = rev.revision_id
1947
w = self.text_weaves.get(file_id)
1950
self.text_weaves[file_id] = w
1951
text_changed = False
1952
previous_entries = ie.find_previous_heads(parent_invs,
1956
for old_revision in previous_entries:
1957
# if this fails, its a ghost ?
1958
assert old_revision in self.converted_revs, \
1959
"Revision {%s} not in converted_revs" % old_revision
1960
self.snapshot_ie(previous_entries, ie, w, rev_id)
1962
assert getattr(ie, 'revision', None) is not None
1964
def snapshot_ie(self, previous_revisions, ie, w, rev_id):
1965
# TODO: convert this logic, which is ~= snapshot to
1966
# a call to:. This needs the path figured out. rather than a work_tree
1967
# a v4 revision_tree can be given, or something that looks enough like
1968
# one to give the file content to the entry if it needs it.
1969
# and we need something that looks like a weave store for snapshot to
1971
#ie.snapshot(rev, PATH, previous_revisions, REVISION_TREE, InMemoryWeaveStore(self.text_weaves))
1972
if len(previous_revisions) == 1:
1973
previous_ie = previous_revisions.values()[0]
1974
if ie._unchanged(previous_ie):
1975
ie.revision = previous_ie.revision
1978
text = self.branch.repository.text_store.get(ie.text_id)
1979
file_lines = text.readlines()
1980
assert sha_strings(file_lines) == ie.text_sha1
1981
assert sum(map(len, file_lines)) == ie.text_size
1982
w.add_lines(rev_id, previous_revisions, file_lines)
1983
self.text_count += 1
1985
w.add_lines(rev_id, previous_revisions, [])
1986
ie.revision = rev_id
1988
def _make_order(self):
1989
"""Return a suitable order for importing revisions.
1991
The order must be such that an revision is imported after all
1992
its (present) parents.
1994
todo = set(self.revisions.keys())
1995
done = self.absent_revisions.copy()
1998
# scan through looking for a revision whose parents
2000
for rev_id in sorted(list(todo)):
2001
rev = self.revisions[rev_id]
2002
parent_ids = set(rev.parent_ids)
2003
if parent_ids.issubset(done):
2004
# can take this one now
2005
order.append(rev_id)
2011
class ConvertBzrDir5To6(Converter):
2012
"""Converts format 5 bzr dirs to format 6."""
2014
def convert(self, to_convert, pb):
2015
"""See Converter.convert()."""
2016
self.bzrdir = to_convert
2018
self.pb.note('starting upgrade from format 5 to 6')
2019
self._convert_to_prefixed()
2020
return BzrDir.open(self.bzrdir.root_transport.base)
2022
def _convert_to_prefixed(self):
2023
from bzrlib.store import TransportStore
2024
self.bzrdir.transport.delete('branch-format')
2025
for store_name in ["weaves", "revision-store"]:
2026
self.pb.note("adding prefixes to %s" % store_name)
2027
store_transport = self.bzrdir.transport.clone(store_name)
2028
store = TransportStore(store_transport, prefixed=True)
2029
for urlfilename in store_transport.list_dir('.'):
2030
filename = urlutils.unescape(urlfilename)
2031
if (filename.endswith(".weave") or
2032
filename.endswith(".gz") or
2033
filename.endswith(".sig")):
2034
file_id = os.path.splitext(filename)[0]
2037
prefix_dir = store.hash_prefix(file_id)
2038
# FIXME keep track of the dirs made RBC 20060121
2040
store_transport.move(filename, prefix_dir + '/' + filename)
2041
except errors.NoSuchFile: # catches missing dirs strangely enough
2042
store_transport.mkdir(prefix_dir)
2043
store_transport.move(filename, prefix_dir + '/' + filename)
2044
self.bzrdir._control_files.put_utf8('branch-format', BzrDirFormat6().get_format_string())
2047
class ConvertBzrDir6ToMeta(Converter):
2048
"""Converts format 6 bzr dirs to metadirs."""
2050
def convert(self, to_convert, pb):
2051
"""See Converter.convert()."""
2052
from bzrlib.repofmt.weaverepo import RepositoryFormat7
2053
from bzrlib.branch import BzrBranchFormat5
2054
self.bzrdir = to_convert
2057
self.total = 20 # the steps we know about
2058
self.garbage_inventories = []
2060
self.pb.note('starting upgrade from format 6 to metadir')
2061
self.bzrdir._control_files.put_utf8('branch-format', "Converting to format 6")
2062
# its faster to move specific files around than to open and use the apis...
2063
# first off, nuke ancestry.weave, it was never used.
2065
self.step('Removing ancestry.weave')
2066
self.bzrdir.transport.delete('ancestry.weave')
2067
except errors.NoSuchFile:
2069
# find out whats there
2070
self.step('Finding branch files')
2071
last_revision = self.bzrdir.open_branch().last_revision()
2072
bzrcontents = self.bzrdir.transport.list_dir('.')
2073
for name in bzrcontents:
2074
if name.startswith('basis-inventory.'):
2075
self.garbage_inventories.append(name)
2076
# create new directories for repository, working tree and branch
2077
self.dir_mode = self.bzrdir._control_files._dir_mode
2078
self.file_mode = self.bzrdir._control_files._file_mode
2079
repository_names = [('inventory.weave', True),
2080
('revision-store', True),
2082
self.step('Upgrading repository ')
2083
self.bzrdir.transport.mkdir('repository', mode=self.dir_mode)
2084
self.make_lock('repository')
2085
# we hard code the formats here because we are converting into
2086
# the meta format. The meta format upgrader can take this to a
2087
# future format within each component.
2088
self.put_format('repository', RepositoryFormat7())
2089
for entry in repository_names:
2090
self.move_entry('repository', entry)
2092
self.step('Upgrading branch ')
2093
self.bzrdir.transport.mkdir('branch', mode=self.dir_mode)
2094
self.make_lock('branch')
2095
self.put_format('branch', BzrBranchFormat5())
2096
branch_files = [('revision-history', True),
2097
('branch-name', True),
2099
for entry in branch_files:
2100
self.move_entry('branch', entry)
2102
checkout_files = [('pending-merges', True),
2103
('inventory', True),
2104
('stat-cache', False)]
2105
# If a mandatory checkout file is not present, the branch does not have
2106
# a functional checkout. Do not create a checkout in the converted
2108
for name, mandatory in checkout_files:
2109
if mandatory and name not in bzrcontents:
2110
has_checkout = False
2114
if not has_checkout:
2115
self.pb.note('No working tree.')
2116
# If some checkout files are there, we may as well get rid of them.
2117
for name, mandatory in checkout_files:
2118
if name in bzrcontents:
2119
self.bzrdir.transport.delete(name)
2121
from bzrlib.workingtree import WorkingTreeFormat3
2122
self.step('Upgrading working tree')
2123
self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
2124
self.make_lock('checkout')
2126
'checkout', WorkingTreeFormat3())
2127
self.bzrdir.transport.delete_multi(
2128
self.garbage_inventories, self.pb)
2129
for entry in checkout_files:
2130
self.move_entry('checkout', entry)
2131
if last_revision is not None:
2132
self.bzrdir._control_files.put_utf8(
2133
'checkout/last-revision', last_revision)
2134
self.bzrdir._control_files.put_utf8(
2135
'branch-format', BzrDirMetaFormat1().get_format_string())
2136
return BzrDir.open(self.bzrdir.root_transport.base)
2138
def make_lock(self, name):
2139
"""Make a lock for the new control dir name."""
2140
self.step('Make %s lock' % name)
2141
ld = lockdir.LockDir(self.bzrdir.transport,
2143
file_modebits=self.file_mode,
2144
dir_modebits=self.dir_mode)
2147
def move_entry(self, new_dir, entry):
2148
"""Move then entry name into new_dir."""
2150
mandatory = entry[1]
2151
self.step('Moving %s' % name)
2153
self.bzrdir.transport.move(name, '%s/%s' % (new_dir, name))
2154
except errors.NoSuchFile:
2158
def put_format(self, dirname, format):
2159
self.bzrdir._control_files.put_utf8('%s/format' % dirname, format.get_format_string())
2162
class ConvertMetaToMeta(Converter):
2163
"""Converts the components of metadirs."""
2165
def __init__(self, target_format):
2166
"""Create a metadir to metadir converter.
2168
:param target_format: The final metadir format that is desired.
2170
self.target_format = target_format
2172
def convert(self, to_convert, pb):
2173
"""See Converter.convert()."""
2174
self.bzrdir = to_convert
2178
self.step('checking repository format')
2180
repo = self.bzrdir.open_repository()
2181
except errors.NoRepositoryPresent:
2184
if not isinstance(repo._format, self.target_format.repository_format.__class__):
2185
from bzrlib.repository import CopyConverter
2186
self.pb.note('starting repository conversion')
2187
converter = CopyConverter(self.target_format.repository_format)
2188
converter.convert(repo, pb)
2190
branch = self.bzrdir.open_branch()
2191
except errors.NotBranchError:
2194
# TODO: conversions of Branch and Tree should be done by
2195
# InterXFormat lookups
2196
# Avoid circular imports
2197
from bzrlib import branch as _mod_branch
2198
if (branch._format.__class__ is _mod_branch.BzrBranchFormat5 and
2199
self.target_format.get_branch_format().__class__ is
2200
_mod_branch.BzrBranchFormat6):
2201
branch_converter = _mod_branch.Converter5to6()
2202
branch_converter.convert(branch)
2204
tree = self.bzrdir.open_workingtree(recommend_upgrade=False)
2205
except (errors.NoWorkingTree, errors.NotLocalUrl):
2208
# TODO: conversions of Branch and Tree should be done by
2209
# InterXFormat lookups
2210
if (isinstance(tree, workingtree.WorkingTree3) and
2211
not isinstance(tree, workingtree_4.WorkingTree4) and
2212
isinstance(self.target_format.workingtree_format,
2213
workingtree_4.WorkingTreeFormat4)):
2214
workingtree_4.Converter3to4().convert(tree)
2218
# This is not in remote.py because it's small, and needs to be registered.
2219
# Putting it in remote.py creates a circular import problem.
2220
# we can make it a lazy object if the control formats is turned into something
2222
class RemoteBzrDirFormat(BzrDirMetaFormat1):
2223
"""Format representing bzrdirs accessed via a smart server"""
2225
def get_format_description(self):
2226
return 'bzr remote bzrdir'
2229
def probe_transport(klass, transport):
2230
"""Return a RemoteBzrDirFormat object if it looks possible."""
2232
transport.get_smart_client()
2233
except (NotImplementedError, AttributeError,
2234
errors.TransportNotPossible):
2235
# no smart server, so not a branch for this format type.
2236
raise errors.NotBranchError(path=transport.base)
2240
def initialize_on_transport(self, transport):
2242
# hand off the request to the smart server
2243
medium = transport.get_smart_medium()
2244
except errors.NoSmartMedium:
2245
# TODO: lookup the local format from a server hint.
2246
local_dir_format = BzrDirMetaFormat1()
2247
return local_dir_format.initialize_on_transport(transport)
2248
client = _SmartClient(medium)
2249
path = client.remote_path_from_transport(transport)
2250
response = _SmartClient(medium).call('BzrDirFormat.initialize', path)
2251
assert response[0] in ('ok', ), 'unexpected response code %s' % (response,)
2252
return remote.RemoteBzrDir(transport)
2254
def _open(self, transport):
2255
return remote.RemoteBzrDir(transport)
2257
def __eq__(self, other):
2258
if not isinstance(other, RemoteBzrDirFormat):
2260
return self.get_format_description() == other.get_format_description()
2263
BzrDirFormat.register_control_server_format(RemoteBzrDirFormat)
2266
class BzrDirFormatInfo(object):
2268
def __init__(self, native, deprecated, hidden):
2269
self.deprecated = deprecated
2270
self.native = native
2271
self.hidden = hidden
2274
class BzrDirFormatRegistry(registry.Registry):
2275
"""Registry of user-selectable BzrDir subformats.
2277
Differs from BzrDirFormat._control_formats in that it provides sub-formats,
2278
e.g. BzrDirMeta1 with weave repository. Also, it's more user-oriented.
2281
def register_metadir(self, key,
2282
repository_format, help, native=True, deprecated=False,
2286
"""Register a metadir subformat.
2288
These all use a BzrDirMetaFormat1 bzrdir, but can be parameterized
2289
by the Repository format.
2291
:param repository_format: The fully-qualified repository format class
2293
:param branch_format: Fully-qualified branch format class name as
2295
:param tree_format: Fully-qualified tree format class name as
2298
# This should be expanded to support setting WorkingTree and Branch
2299
# formats, once BzrDirMetaFormat1 supports that.
2300
def _load(full_name):
2301
mod_name, factory_name = full_name.rsplit('.', 1)
2303
mod = __import__(mod_name, globals(), locals(),
2305
except ImportError, e:
2306
raise ImportError('failed to load %s: %s' % (full_name, e))
2308
factory = getattr(mod, factory_name)
2309
except AttributeError:
2310
raise AttributeError('no factory %s in module %r'
2315
bd = BzrDirMetaFormat1()
2316
if branch_format is not None:
2317
bd.set_branch_format(_load(branch_format))
2318
if tree_format is not None:
2319
bd.workingtree_format = _load(tree_format)
2320
if repository_format is not None:
2321
bd.repository_format = _load(repository_format)
2323
self.register(key, helper, help, native, deprecated, hidden)
2325
def register(self, key, factory, help, native=True, deprecated=False,
2327
"""Register a BzrDirFormat factory.
2329
The factory must be a callable that takes one parameter: the key.
2330
It must produce an instance of the BzrDirFormat when called.
2332
This function mainly exists to prevent the info object from being
2335
registry.Registry.register(self, key, factory, help,
2336
BzrDirFormatInfo(native, deprecated, hidden))
2338
def register_lazy(self, key, module_name, member_name, help, native=True,
2339
deprecated=False, hidden=False):
2340
registry.Registry.register_lazy(self, key, module_name, member_name,
2341
help, BzrDirFormatInfo(native, deprecated, hidden))
2343
def set_default(self, key):
2344
"""Set the 'default' key to be a clone of the supplied key.
2346
This method must be called once and only once.
2348
registry.Registry.register(self, 'default', self.get(key),
2349
self.get_help(key), info=self.get_info(key))
2351
def set_default_repository(self, key):
2352
"""Set the FormatRegistry default and Repository default.
2354
This is a transitional method while Repository.set_default_format
2357
if 'default' in self:
2358
self.remove('default')
2359
self.set_default(key)
2360
format = self.get('default')()
2361
assert isinstance(format, BzrDirMetaFormat1)
2363
def make_bzrdir(self, key):
2364
return self.get(key)()
2366
def help_topic(self, topic):
2367
output = textwrap.dedent("""\
2368
Bazaar directory formats
2369
------------------------
2371
These formats can be used for creating branches, working trees, and
2375
default_help = self.get_help('default')
2377
for key in self.keys():
2378
if key == 'default':
2380
help = self.get_help(key)
2381
if help == default_help:
2382
default_realkey = key
2384
help_pairs.append((key, help))
2386
def wrapped(key, help, info):
2388
help = '(native) ' + help
2389
return ' %s:\n%s\n\n' % (key,
2390
textwrap.fill(help, initial_indent=' ',
2391
subsequent_indent=' '))
2392
output += wrapped('%s/default' % default_realkey, default_help,
2393
self.get_info('default'))
2394
deprecated_pairs = []
2395
for key, help in help_pairs:
2396
info = self.get_info(key)
2399
elif info.deprecated:
2400
deprecated_pairs.append((key, help))
2402
output += wrapped(key, help, info)
2403
if len(deprecated_pairs) > 0:
2404
output += "Deprecated formats\n------------------\n\n"
2405
for key, help in deprecated_pairs:
2406
info = self.get_info(key)
2407
output += wrapped(key, help, info)
2412
format_registry = BzrDirFormatRegistry()
2413
format_registry.register('weave', BzrDirFormat6,
2414
'Pre-0.8 format. Slower than knit and does not'
2415
' support checkouts or shared repositories.',
2417
format_registry.register_metadir('knit',
2418
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2419
'Format using knits. Recommended for interoperation with bzr <= 0.14.',
2420
branch_format='bzrlib.branch.BzrBranchFormat5',
2421
tree_format='bzrlib.workingtree.WorkingTreeFormat3')
2422
format_registry.register_metadir('metaweave',
2423
'bzrlib.repofmt.weaverepo.RepositoryFormat7',
2424
'Transitional format in 0.8. Slower than knit.',
2425
branch_format='bzrlib.branch.BzrBranchFormat5',
2426
tree_format='bzrlib.workingtree.WorkingTreeFormat3',
2428
format_registry.register_metadir('dirstate',
2429
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2430
help='New in 0.15: Fast local operations. Compatible with bzr 0.8 and '
2431
'above when accessed over the network.',
2432
branch_format='bzrlib.branch.BzrBranchFormat5',
2433
# this uses bzrlib.workingtree.WorkingTreeFormat4 because importing
2434
# directly from workingtree_4 triggers a circular import.
2435
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2437
format_registry.register_metadir('dirstate-tags',
2438
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2439
help='New in 0.15: Fast local operations and improved scaling for '
2440
'network operations. Additionally adds support for tags.'
2441
' Incompatible with bzr < 0.15.',
2442
branch_format='bzrlib.branch.BzrBranchFormat6',
2443
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2445
format_registry.register_metadir('dirstate-with-subtree',
2446
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
2447
help='New in 0.15: Fast local operations and improved scaling for '
2448
'network operations. Additionally adds support for versioning nested '
2449
'bzr branches. Incompatible with bzr < 0.15.',
2450
branch_format='bzrlib.branch.BzrBranchFormat6',
2451
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2454
format_registry.set_default('dirstate')