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,
53
from bzrlib.osutils import (
58
from bzrlib.smart.client import SmartClient
59
from bzrlib.store.revision.text import TextRevisionStore
60
from bzrlib.store.text import TextStore
61
from bzrlib.store.versioned import WeaveStore
62
from bzrlib.transactions import WriteTransaction
63
from bzrlib.transport import get_transport
64
from bzrlib.weave import Weave
67
from bzrlib.trace import mutter, note
68
from bzrlib.transport.local import LocalTransport
72
"""A .bzr control diretory.
74
BzrDir instances let you create or open any of the things that can be
75
found within .bzr - checkouts, branches and repositories.
78
the transport which this bzr dir is rooted at (i.e. file:///.../.bzr/)
80
a transport connected to the directory this bzr was opened from.
84
"""Invoke break_lock on the first object in the bzrdir.
86
If there is a tree, the tree is opened and break_lock() called.
87
Otherwise, branch is tried, and finally repository.
89
# XXX: This seems more like a UI function than something that really
90
# belongs in this class.
92
thing_to_unlock = self.open_workingtree()
93
except (errors.NotLocalUrl, errors.NoWorkingTree):
95
thing_to_unlock = self.open_branch()
96
except errors.NotBranchError:
98
thing_to_unlock = self.open_repository()
99
except errors.NoRepositoryPresent:
101
thing_to_unlock.break_lock()
103
def can_convert_format(self):
104
"""Return true if this bzrdir is one whose format we can convert from."""
107
def check_conversion_target(self, target_format):
108
target_repo_format = target_format.repository_format
109
source_repo_format = self._format.repository_format
110
source_repo_format.check_conversion_target(target_repo_format)
113
def _check_supported(format, allow_unsupported):
114
"""Check whether format is a supported format.
116
If allow_unsupported is True, this is a no-op.
118
if not allow_unsupported and not format.is_supported():
119
# see open_downlevel to open legacy branches.
120
raise errors.UnsupportedFormatError(format=format)
122
def clone(self, url, revision_id=None, basis=None, force_new_repo=False):
123
"""Clone this bzrdir and its contents to url verbatim.
125
If urls last component does not exist, it will be created.
127
if revision_id is not None, then the clone operation may tune
128
itself to download less data.
129
:param force_new_repo: Do not use a shared repository for the target
130
even if one is available.
133
basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
134
result = self._format.initialize(url)
136
local_repo = self.find_repository()
137
except errors.NoRepositoryPresent:
140
# may need to copy content in
142
result_repo = local_repo.clone(
144
revision_id=revision_id,
146
result_repo.set_make_working_trees(local_repo.make_working_trees())
149
result_repo = result.find_repository()
150
# fetch content this dir needs.
152
# XXX FIXME RBC 20060214 need tests for this when the basis
154
result_repo.fetch(basis_repo, revision_id=revision_id)
155
result_repo.fetch(local_repo, revision_id=revision_id)
156
except errors.NoRepositoryPresent:
157
# needed to make one anyway.
158
result_repo = local_repo.clone(
160
revision_id=revision_id,
162
result_repo.set_make_working_trees(local_repo.make_working_trees())
163
# 1 if there is a branch present
164
# make sure its content is available in the target repository
167
self.open_branch().clone(result, revision_id=revision_id)
168
except errors.NotBranchError:
171
self.open_workingtree().clone(result, basis=basis_tree)
172
except (errors.NoWorkingTree, errors.NotLocalUrl):
176
def _get_basis_components(self, basis):
177
"""Retrieve the basis components that are available at basis."""
179
return None, None, None
181
basis_tree = basis.open_workingtree()
182
basis_branch = basis_tree.branch
183
basis_repo = basis_branch.repository
184
except (errors.NoWorkingTree, errors.NotLocalUrl):
187
basis_branch = basis.open_branch()
188
basis_repo = basis_branch.repository
189
except errors.NotBranchError:
192
basis_repo = basis.open_repository()
193
except errors.NoRepositoryPresent:
195
return basis_repo, basis_branch, basis_tree
197
# TODO: This should be given a Transport, and should chdir up; otherwise
198
# this will open a new connection.
199
def _make_tail(self, url):
200
head, tail = urlutils.split(url)
201
if tail and tail != '.':
202
t = get_transport(head)
205
except errors.FileExists:
208
# TODO: Should take a Transport
210
def create(cls, base, format=None):
211
"""Create a new BzrDir at the url 'base'.
213
This will call the current default formats initialize with base
214
as the only parameter.
216
:param format: If supplied, the format of branch to create. If not
217
supplied, the default is used.
219
if cls is not BzrDir:
220
raise AssertionError("BzrDir.create always creates the default"
221
" format, not one of %r" % cls)
222
head, tail = urlutils.split(base)
223
if tail and tail != '.':
224
t = get_transport(head)
227
except errors.FileExists:
230
format = BzrDirFormat.get_default_format()
231
return format.initialize(safe_unicode(base))
233
def create_branch(self):
234
"""Create a branch in this BzrDir.
236
The bzrdirs format will control what branch format is created.
237
For more control see BranchFormatXX.create(a_bzrdir).
239
raise NotImplementedError(self.create_branch)
242
def create_branch_and_repo(base, force_new_repo=False, format=None):
243
"""Create a new BzrDir, Branch and Repository at the url 'base'.
245
This will use the current default BzrDirFormat, and use whatever
246
repository format that that uses via bzrdir.create_branch and
247
create_repository. If a shared repository is available that is used
250
The created Branch object is returned.
252
:param base: The URL to create the branch at.
253
:param force_new_repo: If True a new repository is always created.
255
bzrdir = BzrDir.create(base, format)
256
bzrdir._find_or_create_repository(force_new_repo)
257
return bzrdir.create_branch()
259
def _find_or_create_repository(self, force_new_repo):
260
"""Create a new repository if needed, returning the repository."""
262
return self.create_repository()
264
return self.find_repository()
265
except errors.NoRepositoryPresent:
266
return self.create_repository()
269
def create_branch_convenience(base, force_new_repo=False,
270
force_new_tree=None, format=None):
271
"""Create a new BzrDir, Branch and Repository at the url 'base'.
273
This is a convenience function - it will use an existing repository
274
if possible, can be told explicitly whether to create a working tree or
277
This will use the current default BzrDirFormat, and use whatever
278
repository format that that uses via bzrdir.create_branch and
279
create_repository. If a shared repository is available that is used
280
preferentially. Whatever repository is used, its tree creation policy
283
The created Branch object is returned.
284
If a working tree cannot be made due to base not being a file:// url,
285
no error is raised unless force_new_tree is True, in which case no
286
data is created on disk and NotLocalUrl is raised.
288
:param base: The URL to create the branch at.
289
:param force_new_repo: If True a new repository is always created.
290
:param force_new_tree: If True or False force creation of a tree or
291
prevent such creation respectively.
292
:param format: Override for the for the bzrdir format to create
295
# check for non local urls
296
t = get_transport(safe_unicode(base))
297
if not isinstance(t, LocalTransport):
298
raise errors.NotLocalUrl(base)
299
bzrdir = BzrDir.create(base, format)
300
repo = bzrdir._find_or_create_repository(force_new_repo)
301
result = bzrdir.create_branch()
302
if force_new_tree or (repo.make_working_trees() and
303
force_new_tree is None):
305
bzrdir.create_workingtree()
306
except errors.NotLocalUrl:
311
def create_repository(base, shared=False, format=None):
312
"""Create a new BzrDir and Repository at the url 'base'.
314
If no format is supplied, this will default to the current default
315
BzrDirFormat by default, and use whatever repository format that that
316
uses for bzrdirformat.create_repository.
318
:param shared: Create a shared repository rather than a standalone
320
The Repository object is returned.
322
This must be overridden as an instance method in child classes, where
323
it should take no parameters and construct whatever repository format
324
that child class desires.
326
bzrdir = BzrDir.create(base, format)
327
return bzrdir.create_repository(shared)
330
def create_standalone_workingtree(base, format=None):
331
"""Create a new BzrDir, WorkingTree, Branch and Repository at 'base'.
333
'base' must be a local path or a file:// url.
335
This will use the current default BzrDirFormat, and use whatever
336
repository format that that uses for bzrdirformat.create_workingtree,
337
create_branch and create_repository.
339
:return: The WorkingTree object.
341
t = get_transport(safe_unicode(base))
342
if not isinstance(t, LocalTransport):
343
raise errors.NotLocalUrl(base)
344
bzrdir = BzrDir.create_branch_and_repo(safe_unicode(base),
346
format=format).bzrdir
347
return bzrdir.create_workingtree()
349
def create_workingtree(self, revision_id=None):
350
"""Create a working tree at this BzrDir.
352
revision_id: create it as of this revision id.
354
raise NotImplementedError(self.create_workingtree)
356
def retire_bzrdir(self):
357
"""Permanently disable the bzrdir.
359
This is done by renaming it to give the user some ability to recover
360
if there was a problem.
362
This will have horrible consequences if anyone has anything locked or
365
for i in xrange(10000):
367
to_path = '.bzr.retired.%d' % i
368
self.root_transport.rename('.bzr', to_path)
369
note("renamed %s to %s"
370
% (self.root_transport.abspath('.bzr'), to_path))
372
except (errors.TransportError, IOError, errors.PathError):
375
def destroy_workingtree(self):
376
"""Destroy the working tree at this BzrDir.
378
Formats that do not support this may raise UnsupportedOperation.
380
raise NotImplementedError(self.destroy_workingtree)
382
def destroy_workingtree_metadata(self):
383
"""Destroy the control files for the working tree at this BzrDir.
385
The contents of working tree files are not affected.
386
Formats that do not support this may raise UnsupportedOperation.
388
raise NotImplementedError(self.destroy_workingtree_metadata)
390
def find_repository(self):
391
"""Find the repository that should be used for a_bzrdir.
393
This does not require a branch as we use it to find the repo for
394
new branches as well as to hook existing branches up to their
398
return self.open_repository()
399
except errors.NoRepositoryPresent:
401
next_transport = self.root_transport.clone('..')
403
# find the next containing bzrdir
405
found_bzrdir = BzrDir.open_containing_from_transport(
407
except errors.NotBranchError:
409
raise errors.NoRepositoryPresent(self)
410
# does it have a repository ?
412
repository = found_bzrdir.open_repository()
413
except errors.NoRepositoryPresent:
414
next_transport = found_bzrdir.root_transport.clone('..')
415
if (found_bzrdir.root_transport.base == next_transport.base):
416
# top of the file system
420
if ((found_bzrdir.root_transport.base ==
421
self.root_transport.base) or repository.is_shared()):
424
raise errors.NoRepositoryPresent(self)
425
raise errors.NoRepositoryPresent(self)
427
def get_branch_reference(self):
428
"""Return the referenced URL for the branch in this bzrdir.
430
:raises NotBranchError: If there is no Branch.
431
:return: The URL the branch in this bzrdir references if it is a
432
reference branch, or None for regular branches.
436
def get_branch_transport(self, branch_format):
437
"""Get the transport for use by branch format in this BzrDir.
439
Note that bzr dirs that do not support format strings will raise
440
IncompatibleFormat if the branch format they are given has
441
a format string, and vice versa.
443
If branch_format is None, the transport is returned with no
444
checking. if it is not None, then the returned transport is
445
guaranteed to point to an existing directory ready for use.
447
raise NotImplementedError(self.get_branch_transport)
449
def get_repository_transport(self, repository_format):
450
"""Get the transport for use by repository format in this BzrDir.
452
Note that bzr dirs that do not support format strings will raise
453
IncompatibleFormat if the repository format they are given has
454
a format string, and vice versa.
456
If repository_format is None, the transport is returned with no
457
checking. if it is not None, then the returned transport is
458
guaranteed to point to an existing directory ready for use.
460
raise NotImplementedError(self.get_repository_transport)
462
def get_workingtree_transport(self, tree_format):
463
"""Get the transport for use by workingtree format in this BzrDir.
465
Note that bzr dirs that do not support format strings will raise
466
IncompatibleFormat if the workingtree format they are given has a
467
format string, and vice versa.
469
If workingtree_format is None, the transport is returned with no
470
checking. if it is not None, then the returned transport is
471
guaranteed to point to an existing directory ready for use.
473
raise NotImplementedError(self.get_workingtree_transport)
475
def __init__(self, _transport, _format):
476
"""Initialize a Bzr control dir object.
478
Only really common logic should reside here, concrete classes should be
479
made with varying behaviours.
481
:param _format: the format that is creating this BzrDir instance.
482
:param _transport: the transport this dir is based at.
484
self._format = _format
485
self.transport = _transport.clone('.bzr')
486
self.root_transport = _transport
488
def is_control_filename(self, filename):
489
"""True if filename is the name of a path which is reserved for bzrdir's.
491
:param filename: A filename within the root transport of this bzrdir.
493
This is true IF and ONLY IF the filename is part of the namespace reserved
494
for bzr control dirs. Currently this is the '.bzr' directory in the root
495
of the root_transport. it is expected that plugins will need to extend
496
this in the future - for instance to make bzr talk with svn working
499
# this might be better on the BzrDirFormat class because it refers to
500
# all the possible bzrdir disk formats.
501
# This method is tested via the workingtree is_control_filename tests-
502
# it was extracted from WorkingTree.is_control_filename. If the methods
503
# contract is extended beyond the current trivial implementation please
504
# add new tests for it to the appropriate place.
505
return filename == '.bzr' or filename.startswith('.bzr/')
507
def needs_format_conversion(self, format=None):
508
"""Return true if this bzrdir needs convert_format run on it.
510
For instance, if the repository format is out of date but the
511
branch and working tree are not, this should return True.
513
:param format: Optional parameter indicating a specific desired
514
format we plan to arrive at.
516
raise NotImplementedError(self.needs_format_conversion)
519
def open_unsupported(base):
520
"""Open a branch which is not supported."""
521
return BzrDir.open(base, _unsupported=True)
524
def open(base, _unsupported=False):
525
"""Open an existing bzrdir, rooted at 'base' (url)
527
_unsupported is a private parameter to the BzrDir class.
529
t = get_transport(base)
530
return BzrDir.open_from_transport(t, _unsupported=_unsupported)
533
def open_from_transport(transport, _unsupported=False):
534
"""Open a bzrdir within a particular directory.
536
:param transport: Transport containing the bzrdir.
537
:param _unsupported: private.
539
format = BzrDirFormat.find_format(transport)
540
BzrDir._check_supported(format, _unsupported)
541
return format.open(transport, _found=True)
543
def open_branch(self, unsupported=False):
544
"""Open the branch object at this BzrDir if one is present.
546
If unsupported is True, then no longer supported branch formats can
549
TODO: static convenience version of this?
551
raise NotImplementedError(self.open_branch)
554
def open_containing(url):
555
"""Open an existing branch which contains url.
557
:param url: url to search from.
558
See open_containing_from_transport for more detail.
560
return BzrDir.open_containing_from_transport(get_transport(url))
563
def open_containing_from_transport(a_transport):
564
"""Open an existing branch which contains a_transport.base
566
This probes for a branch at a_transport, and searches upwards from there.
568
Basically we keep looking up until we find the control directory or
569
run into the root. If there isn't one, raises NotBranchError.
570
If there is one and it is either an unrecognised format or an unsupported
571
format, UnknownFormatError or UnsupportedFormatError are raised.
572
If there is one, it is returned, along with the unused portion of url.
574
:return: The BzrDir that contains the path, and a Unicode path
575
for the rest of the URL.
577
# this gets the normalised url back. I.e. '.' -> the full path.
578
url = a_transport.base
581
result = BzrDir.open_from_transport(a_transport)
582
return result, urlutils.unescape(a_transport.relpath(url))
583
except errors.NotBranchError, e:
586
new_t = a_transport.clone('..')
587
except errors.InvalidURLJoin:
588
# reached the root, whatever that may be
589
raise errors.NotBranchError(path=url)
590
if new_t.base == a_transport.base:
591
# reached the root, whatever that may be
592
raise errors.NotBranchError(path=url)
596
def open_containing_tree_or_branch(klass, location):
597
"""Return the branch and working tree contained by a location.
599
Returns (tree, branch, relpath).
600
If there is no tree at containing the location, tree will be None.
601
If there is no branch containing the location, an exception will be
603
relpath is the portion of the path that is contained by the branch.
605
bzrdir, relpath = klass.open_containing(location)
607
tree = bzrdir.open_workingtree()
608
except (errors.NoWorkingTree, errors.NotLocalUrl):
610
branch = bzrdir.open_branch()
613
return tree, branch, relpath
615
def open_repository(self, _unsupported=False):
616
"""Open the repository object at this BzrDir if one is present.
618
This will not follow the Branch object pointer - its strictly a direct
619
open facility. Most client code should use open_branch().repository to
622
_unsupported is a private parameter, not part of the api.
623
TODO: static convenience version of this?
625
raise NotImplementedError(self.open_repository)
627
def open_workingtree(self, _unsupported=False):
628
"""Open the workingtree object at this BzrDir if one is present.
630
TODO: static convenience version of this?
632
raise NotImplementedError(self.open_workingtree)
634
def has_branch(self):
635
"""Tell if this bzrdir contains a branch.
637
Note: if you're going to open the branch, you should just go ahead
638
and try, and not ask permission first. (This method just opens the
639
branch and discards it, and that's somewhat expensive.)
644
except errors.NotBranchError:
647
def has_workingtree(self):
648
"""Tell if this bzrdir contains a working tree.
650
This will still raise an exception if the bzrdir has a workingtree that
651
is remote & inaccessible.
653
Note: if you're going to open the working tree, you should just go ahead
654
and try, and not ask permission first. (This method just opens the
655
workingtree and discards it, and that's somewhat expensive.)
658
self.open_workingtree()
660
except errors.NoWorkingTree:
663
def _cloning_metadir(self):
664
"""Produce a metadir suitable for cloning with"""
665
def related_repository(bzrdir):
667
branch = bzrdir.open_branch()
668
return branch.repository
669
except errors.NotBranchError:
671
return bzrdir.open_repository()
672
result_format = self._format.__class__()
674
source_repository = related_repository(self)
675
except errors.NoRepositoryPresent:
676
source_repository = None
678
repo_format = source_repository._format
679
if not isinstance(repo_format, remote.RemoteRepositoryFormat):
680
result_format.repository_format = repo_format
682
tree = self.open_workingtree()
683
except (errors.NoWorkingTree, errors.NotLocalUrl):
684
result_format.workingtree_format = None
686
result_format.workingtree_format = tree._format.__class__()
687
return result_format, source_repository
689
def cloning_metadir(self):
690
"""Produce a metadir suitable for cloning or sprouting with.
692
These operations may produce workingtrees (yes, even though they're
693
"cloning" something that doesn't have a tree, so a viable workingtree
694
format must be selected.
696
format, repository = self._cloning_metadir()
697
if format._workingtree_format is None:
698
if repository is None:
700
tree_format = repository._format._matchingbzrdir.workingtree_format
701
format.workingtree_format = tree_format.__class__()
704
def checkout_metadir(self):
705
return self.cloning_metadir()
707
def sprout(self, url, revision_id=None, basis=None, force_new_repo=False,
709
"""Create a copy of this bzrdir prepared for use as a new line of
712
If urls last component does not exist, it will be created.
714
Attributes related to the identity of the source branch like
715
branch nickname will be cleaned, a working tree is created
716
whether one existed before or not; and a local branch is always
719
if revision_id is not None, then the clone operation may tune
720
itself to download less data.
723
cloning_format = self.cloning_metadir()
724
result = cloning_format.initialize(url)
725
basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
727
source_branch = self.open_branch()
728
source_repository = source_branch.repository
729
except errors.NotBranchError:
732
source_repository = self.open_repository()
733
except errors.NoRepositoryPresent:
734
# copy the entire basis one if there is one
735
# but there is no repository.
736
source_repository = basis_repo
741
result_repo = result.find_repository()
742
except errors.NoRepositoryPresent:
744
if source_repository is None and result_repo is not None:
746
elif source_repository is None and result_repo is None:
747
# no repo available, make a new one
748
result.create_repository()
749
elif source_repository is not None and result_repo is None:
750
# have source, and want to make a new target repo
751
# we don't clone the repo because that preserves attributes
752
# like is_shared(), and we have not yet implemented a
753
# repository sprout().
754
result_repo = result.create_repository()
755
if result_repo is not None:
756
# fetch needed content into target.
758
# XXX FIXME RBC 20060214 need tests for this when the basis
760
result_repo.fetch(basis_repo, revision_id=revision_id)
761
if source_repository is not None:
762
result_repo.fetch(source_repository, revision_id=revision_id)
763
if source_branch is not None:
764
source_branch.sprout(result, revision_id=revision_id)
766
result.create_branch()
767
# TODO: jam 20060426 we probably need a test in here in the
768
# case that the newly sprouted branch is a remote one
769
if result_repo is None or result_repo.make_working_trees():
770
wt = result.create_workingtree()
773
if wt.path2id('') is None:
775
wt.set_root_id(self.open_workingtree.get_root_id())
776
except errors.NoWorkingTree:
782
if recurse == 'down':
784
basis = wt.basis_tree()
786
subtrees = basis.iter_references()
787
recurse_branch = wt.branch
788
elif source_branch is not None:
789
basis = source_branch.basis_tree()
791
subtrees = basis.iter_references()
792
recurse_branch = source_branch
797
for path, file_id in subtrees:
798
target = urlutils.join(url, urlutils.escape(path))
799
sublocation = source_branch.reference_parent(file_id, path)
800
sublocation.bzrdir.sprout(target,
801
basis.get_reference_revision(file_id, path),
802
force_new_repo=force_new_repo, recurse=recurse)
804
if basis is not None:
809
class BzrDirPreSplitOut(BzrDir):
810
"""A common class for the all-in-one formats."""
812
def __init__(self, _transport, _format):
813
"""See BzrDir.__init__."""
814
super(BzrDirPreSplitOut, self).__init__(_transport, _format)
815
assert self._format._lock_class == lockable_files.TransportLock
816
assert self._format._lock_file_name == 'branch-lock'
817
self._control_files = lockable_files.LockableFiles(
818
self.get_branch_transport(None),
819
self._format._lock_file_name,
820
self._format._lock_class)
822
def break_lock(self):
823
"""Pre-splitout bzrdirs do not suffer from stale locks."""
824
raise NotImplementedError(self.break_lock)
826
def clone(self, url, revision_id=None, basis=None, force_new_repo=False):
827
"""See BzrDir.clone()."""
828
from bzrlib.workingtree import WorkingTreeFormat2
830
result = self._format._initialize_for_clone(url)
831
basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
832
self.open_repository().clone(result, revision_id=revision_id, basis=basis_repo)
833
from_branch = self.open_branch()
834
from_branch.clone(result, revision_id=revision_id)
836
self.open_workingtree().clone(result, basis=basis_tree)
837
except errors.NotLocalUrl:
838
# make a new one, this format always has to have one.
840
WorkingTreeFormat2().initialize(result)
841
except errors.NotLocalUrl:
842
# but we cannot do it for remote trees.
843
to_branch = result.open_branch()
844
WorkingTreeFormat2().stub_initialize_remote(to_branch.control_files)
847
def create_branch(self):
848
"""See BzrDir.create_branch."""
849
return self.open_branch()
851
def create_repository(self, shared=False):
852
"""See BzrDir.create_repository."""
854
raise errors.IncompatibleFormat('shared repository', self._format)
855
return self.open_repository()
857
def create_workingtree(self, revision_id=None):
858
"""See BzrDir.create_workingtree."""
859
# this looks buggy but is not -really-
860
# clone and sprout will have set the revision_id
861
# and that will have set it for us, its only
862
# specific uses of create_workingtree in isolation
863
# that can do wonky stuff here, and that only
864
# happens for creating checkouts, which cannot be
865
# done on this format anyway. So - acceptable wart.
866
result = self.open_workingtree()
867
if revision_id is not None:
868
if revision_id == _mod_revision.NULL_REVISION:
869
result.set_parent_ids([])
871
result.set_parent_ids([revision_id])
874
def destroy_workingtree(self):
875
"""See BzrDir.destroy_workingtree."""
876
raise errors.UnsupportedOperation(self.destroy_workingtree, self)
878
def destroy_workingtree_metadata(self):
879
"""See BzrDir.destroy_workingtree_metadata."""
880
raise errors.UnsupportedOperation(self.destroy_workingtree_metadata,
883
def get_branch_transport(self, branch_format):
884
"""See BzrDir.get_branch_transport()."""
885
if branch_format is None:
886
return self.transport
888
branch_format.get_format_string()
889
except NotImplementedError:
890
return self.transport
891
raise errors.IncompatibleFormat(branch_format, self._format)
893
def get_repository_transport(self, repository_format):
894
"""See BzrDir.get_repository_transport()."""
895
if repository_format is None:
896
return self.transport
898
repository_format.get_format_string()
899
except NotImplementedError:
900
return self.transport
901
raise errors.IncompatibleFormat(repository_format, self._format)
903
def get_workingtree_transport(self, workingtree_format):
904
"""See BzrDir.get_workingtree_transport()."""
905
if workingtree_format is None:
906
return self.transport
908
workingtree_format.get_format_string()
909
except NotImplementedError:
910
return self.transport
911
raise errors.IncompatibleFormat(workingtree_format, self._format)
913
def needs_format_conversion(self, format=None):
914
"""See BzrDir.needs_format_conversion()."""
915
# if the format is not the same as the system default,
916
# an upgrade is needed.
918
format = BzrDirFormat.get_default_format()
919
return not isinstance(self._format, format.__class__)
921
def open_branch(self, unsupported=False):
922
"""See BzrDir.open_branch."""
923
from bzrlib.branch import BzrBranchFormat4
924
format = BzrBranchFormat4()
925
self._check_supported(format, unsupported)
926
return format.open(self, _found=True)
928
def sprout(self, url, revision_id=None, basis=None, force_new_repo=False):
929
"""See BzrDir.sprout()."""
930
from bzrlib.workingtree import WorkingTreeFormat2
932
result = self._format._initialize_for_clone(url)
933
basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
935
self.open_repository().clone(result, revision_id=revision_id, basis=basis_repo)
936
except errors.NoRepositoryPresent:
939
self.open_branch().sprout(result, revision_id=revision_id)
940
except errors.NotBranchError:
942
# we always want a working tree
943
WorkingTreeFormat2().initialize(result)
947
class BzrDir4(BzrDirPreSplitOut):
948
"""A .bzr version 4 control object.
950
This is a deprecated format and may be removed after sept 2006.
953
def create_repository(self, shared=False):
954
"""See BzrDir.create_repository."""
955
return self._format.repository_format.initialize(self, shared)
957
def needs_format_conversion(self, format=None):
958
"""Format 4 dirs are always in need of conversion."""
961
def open_repository(self):
962
"""See BzrDir.open_repository."""
963
from bzrlib.repofmt.weaverepo import RepositoryFormat4
964
return RepositoryFormat4().open(self, _found=True)
967
class BzrDir5(BzrDirPreSplitOut):
968
"""A .bzr version 5 control object.
970
This is a deprecated format and may be removed after sept 2006.
973
def open_repository(self):
974
"""See BzrDir.open_repository."""
975
from bzrlib.repofmt.weaverepo import RepositoryFormat5
976
return RepositoryFormat5().open(self, _found=True)
978
def open_workingtree(self, _unsupported=False):
979
"""See BzrDir.create_workingtree."""
980
from bzrlib.workingtree import WorkingTreeFormat2
981
return WorkingTreeFormat2().open(self, _found=True)
984
class BzrDir6(BzrDirPreSplitOut):
985
"""A .bzr version 6 control object.
987
This is a deprecated format and may be removed after sept 2006.
990
def open_repository(self):
991
"""See BzrDir.open_repository."""
992
from bzrlib.repofmt.weaverepo import RepositoryFormat6
993
return RepositoryFormat6().open(self, _found=True)
995
def open_workingtree(self, _unsupported=False):
996
"""See BzrDir.create_workingtree."""
997
from bzrlib.workingtree import WorkingTreeFormat2
998
return WorkingTreeFormat2().open(self, _found=True)
1001
class BzrDirMeta1(BzrDir):
1002
"""A .bzr meta version 1 control object.
1004
This is the first control object where the
1005
individual aspects are really split out: there are separate repository,
1006
workingtree and branch subdirectories and any subset of the three can be
1007
present within a BzrDir.
1010
def can_convert_format(self):
1011
"""See BzrDir.can_convert_format()."""
1014
def create_branch(self):
1015
"""See BzrDir.create_branch."""
1016
return self._format.get_branch_format().initialize(self)
1018
def create_repository(self, shared=False):
1019
"""See BzrDir.create_repository."""
1020
return self._format.repository_format.initialize(self, shared)
1022
def create_workingtree(self, revision_id=None):
1023
"""See BzrDir.create_workingtree."""
1024
from bzrlib.workingtree import WorkingTreeFormat
1025
return self._format.workingtree_format.initialize(self, revision_id)
1027
def destroy_workingtree(self):
1028
"""See BzrDir.destroy_workingtree."""
1029
wt = self.open_workingtree()
1030
repository = wt.branch.repository
1031
empty = repository.revision_tree(_mod_revision.NULL_REVISION)
1032
wt.revert([], old_tree=empty)
1033
self.destroy_workingtree_metadata()
1035
def destroy_workingtree_metadata(self):
1036
self.transport.delete_tree('checkout')
1038
def _get_mkdir_mode(self):
1039
"""Figure out the mode to use when creating a bzrdir subdir."""
1040
temp_control = lockable_files.LockableFiles(self.transport, '',
1041
lockable_files.TransportLock)
1042
return temp_control._dir_mode
1044
def get_branch_reference(self):
1045
"""See BzrDir.get_branch_reference()."""
1046
from bzrlib.branch import BranchFormat
1047
format = BranchFormat.find_format(self)
1048
return format.get_reference(self)
1050
def get_branch_transport(self, branch_format):
1051
"""See BzrDir.get_branch_transport()."""
1052
if branch_format is None:
1053
return self.transport.clone('branch')
1055
branch_format.get_format_string()
1056
except NotImplementedError:
1057
raise errors.IncompatibleFormat(branch_format, self._format)
1059
self.transport.mkdir('branch', mode=self._get_mkdir_mode())
1060
except errors.FileExists:
1062
return self.transport.clone('branch')
1064
def get_repository_transport(self, repository_format):
1065
"""See BzrDir.get_repository_transport()."""
1066
if repository_format is None:
1067
return self.transport.clone('repository')
1069
repository_format.get_format_string()
1070
except NotImplementedError:
1071
raise errors.IncompatibleFormat(repository_format, self._format)
1073
self.transport.mkdir('repository', mode=self._get_mkdir_mode())
1074
except errors.FileExists:
1076
return self.transport.clone('repository')
1078
def get_workingtree_transport(self, workingtree_format):
1079
"""See BzrDir.get_workingtree_transport()."""
1080
if workingtree_format is None:
1081
return self.transport.clone('checkout')
1083
workingtree_format.get_format_string()
1084
except NotImplementedError:
1085
raise errors.IncompatibleFormat(workingtree_format, self._format)
1087
self.transport.mkdir('checkout', mode=self._get_mkdir_mode())
1088
except errors.FileExists:
1090
return self.transport.clone('checkout')
1092
def needs_format_conversion(self, format=None):
1093
"""See BzrDir.needs_format_conversion()."""
1095
format = BzrDirFormat.get_default_format()
1096
if not isinstance(self._format, format.__class__):
1097
# it is not a meta dir format, conversion is needed.
1099
# we might want to push this down to the repository?
1101
if not isinstance(self.open_repository()._format,
1102
format.repository_format.__class__):
1103
# the repository needs an upgrade.
1105
except errors.NoRepositoryPresent:
1108
if not isinstance(self.open_branch()._format,
1109
format.get_branch_format().__class__):
1110
# the branch needs an upgrade.
1112
except errors.NotBranchError:
1115
if not isinstance(self.open_workingtree()._format,
1116
format.workingtree_format.__class__):
1117
# the workingtree needs an upgrade.
1119
except (errors.NoWorkingTree, errors.NotLocalUrl):
1123
def open_branch(self, unsupported=False):
1124
"""See BzrDir.open_branch."""
1125
from bzrlib.branch import BranchFormat
1126
format = BranchFormat.find_format(self)
1127
self._check_supported(format, unsupported)
1128
return format.open(self, _found=True)
1130
def open_repository(self, unsupported=False):
1131
"""See BzrDir.open_repository."""
1132
from bzrlib.repository import RepositoryFormat
1133
format = RepositoryFormat.find_format(self)
1134
self._check_supported(format, unsupported)
1135
return format.open(self, _found=True)
1137
def open_workingtree(self, unsupported=False):
1138
"""See BzrDir.open_workingtree."""
1139
from bzrlib.workingtree import WorkingTreeFormat
1140
format = WorkingTreeFormat.find_format(self)
1141
self._check_supported(format, unsupported)
1142
return format.open(self, _found=True)
1145
class BzrDirFormat(object):
1146
"""An encapsulation of the initialization and open routines for a format.
1148
Formats provide three things:
1149
* An initialization routine,
1153
Formats are placed in an dict by their format string for reference
1154
during bzrdir opening. These should be subclasses of BzrDirFormat
1157
Once a format is deprecated, just deprecate the initialize and open
1158
methods on the format class. Do not deprecate the object, as the
1159
object will be created every system load.
1162
_default_format = None
1163
"""The default format used for new .bzr dirs."""
1166
"""The known formats."""
1168
_control_formats = []
1169
"""The registered control formats - .bzr, ....
1171
This is a list of BzrDirFormat objects.
1174
_lock_file_name = 'branch-lock'
1176
# _lock_class must be set in subclasses to the lock type, typ.
1177
# TransportLock or LockDir
1180
def find_format(klass, transport):
1181
"""Return the format present at transport."""
1182
for format in klass._control_formats:
1184
return format.probe_transport(transport)
1185
except errors.NotBranchError:
1186
# this format does not find a control dir here.
1188
raise errors.NotBranchError(path=transport.base)
1191
def probe_transport(klass, transport):
1192
"""Return the .bzrdir style format present in a directory."""
1194
format_string = transport.get(".bzr/branch-format").read()
1195
except errors.NoSuchFile:
1196
raise errors.NotBranchError(path=transport.base)
1199
return klass._formats[format_string]
1201
raise errors.UnknownFormatError(format=format_string)
1204
def get_default_format(klass):
1205
"""Return the current default format."""
1206
return klass._default_format
1208
def get_format_string(self):
1209
"""Return the ASCII format string that identifies this format."""
1210
raise NotImplementedError(self.get_format_string)
1212
def get_format_description(self):
1213
"""Return the short description for this format."""
1214
raise NotImplementedError(self.get_format_description)
1216
def get_converter(self, format=None):
1217
"""Return the converter to use to convert bzrdirs needing converts.
1219
This returns a bzrlib.bzrdir.Converter object.
1221
This should return the best upgrader to step this format towards the
1222
current default format. In the case of plugins we can/should provide
1223
some means for them to extend the range of returnable converters.
1225
:param format: Optional format to override the default format of the
1228
raise NotImplementedError(self.get_converter)
1230
def initialize(self, url):
1231
"""Create a bzr control dir at this url and return an opened copy.
1233
Subclasses should typically override initialize_on_transport
1234
instead of this method.
1236
return self.initialize_on_transport(get_transport(url))
1238
def initialize_on_transport(self, transport):
1239
"""Initialize a new bzrdir in the base directory of a Transport."""
1240
# Since we don't have a .bzr directory, inherit the
1241
# mode from the root directory
1242
temp_control = lockable_files.LockableFiles(transport,
1243
'', lockable_files.TransportLock)
1244
temp_control._transport.mkdir('.bzr',
1245
# FIXME: RBC 20060121 don't peek under
1247
mode=temp_control._dir_mode)
1248
file_mode = temp_control._file_mode
1250
mutter('created control directory in ' + transport.base)
1251
control = transport.clone('.bzr')
1252
utf8_files = [('README',
1253
"This is a Bazaar-NG control directory.\n"
1254
"Do not change any files in this directory.\n"),
1255
('branch-format', self.get_format_string()),
1257
# NB: no need to escape relative paths that are url safe.
1258
control_files = lockable_files.LockableFiles(control,
1259
self._lock_file_name, self._lock_class)
1260
control_files.create_lock()
1261
control_files.lock_write()
1263
for file, content in utf8_files:
1264
control_files.put_utf8(file, content)
1266
control_files.unlock()
1267
return self.open(transport, _found=True)
1269
def is_supported(self):
1270
"""Is this format supported?
1272
Supported formats must be initializable and openable.
1273
Unsupported formats may not support initialization or committing or
1274
some other features depending on the reason for not being supported.
1278
def same_model(self, target_format):
1279
return (self.repository_format.rich_root_data ==
1280
target_format.rich_root_data)
1283
def known_formats(klass):
1284
"""Return all the known formats.
1286
Concrete formats should override _known_formats.
1288
# There is double indirection here to make sure that control
1289
# formats used by more than one dir format will only be probed
1290
# once. This can otherwise be quite expensive for remote connections.
1292
for format in klass._control_formats:
1293
result.update(format._known_formats())
1297
def _known_formats(klass):
1298
"""Return the known format instances for this control format."""
1299
return set(klass._formats.values())
1301
def open(self, transport, _found=False):
1302
"""Return an instance of this format for the dir transport points at.
1304
_found is a private parameter, do not use it.
1307
found_format = BzrDirFormat.find_format(transport)
1308
if not isinstance(found_format, self.__class__):
1309
raise AssertionError("%s was asked to open %s, but it seems to need "
1311
% (self, transport, found_format))
1312
return self._open(transport)
1314
def _open(self, transport):
1315
"""Template method helper for opening BzrDirectories.
1317
This performs the actual open and any additional logic or parameter
1320
raise NotImplementedError(self._open)
1323
def register_format(klass, format):
1324
klass._formats[format.get_format_string()] = format
1327
def register_control_format(klass, format):
1328
"""Register a format that does not use '.bzrdir' for its control dir.
1330
TODO: This should be pulled up into a 'ControlDirFormat' base class
1331
which BzrDirFormat can inherit from, and renamed to register_format
1332
there. It has been done without that for now for simplicity of
1335
klass._control_formats.append(format)
1338
@symbol_versioning.deprecated_method(symbol_versioning.zero_fourteen)
1339
def set_default_format(klass, format):
1340
klass._set_default_format(format)
1343
def _set_default_format(klass, format):
1344
"""Set default format (for testing behavior of defaults only)"""
1345
klass._default_format = format
1348
return self.get_format_string()[:-1]
1351
def unregister_format(klass, format):
1352
assert klass._formats[format.get_format_string()] is format
1353
del klass._formats[format.get_format_string()]
1356
def unregister_control_format(klass, format):
1357
klass._control_formats.remove(format)
1360
# register BzrDirFormat as a control format
1361
BzrDirFormat.register_control_format(BzrDirFormat)
1364
class BzrDirFormat4(BzrDirFormat):
1365
"""Bzr dir format 4.
1367
This format is a combined format for working tree, branch and repository.
1369
- Format 1 working trees [always]
1370
- Format 4 branches [always]
1371
- Format 4 repositories [always]
1373
This format is deprecated: it indexes texts using a text it which is
1374
removed in format 5; write support for this format has been removed.
1377
_lock_class = lockable_files.TransportLock
1379
def get_format_string(self):
1380
"""See BzrDirFormat.get_format_string()."""
1381
return "Bazaar-NG branch, format 0.0.4\n"
1383
def get_format_description(self):
1384
"""See BzrDirFormat.get_format_description()."""
1385
return "All-in-one format 4"
1387
def get_converter(self, format=None):
1388
"""See BzrDirFormat.get_converter()."""
1389
# there is one and only one upgrade path here.
1390
return ConvertBzrDir4To5()
1392
def initialize_on_transport(self, transport):
1393
"""Format 4 branches cannot be created."""
1394
raise errors.UninitializableFormat(self)
1396
def is_supported(self):
1397
"""Format 4 is not supported.
1399
It is not supported because the model changed from 4 to 5 and the
1400
conversion logic is expensive - so doing it on the fly was not
1405
def _open(self, transport):
1406
"""See BzrDirFormat._open."""
1407
return BzrDir4(transport, self)
1409
def __return_repository_format(self):
1410
"""Circular import protection."""
1411
from bzrlib.repofmt.weaverepo import RepositoryFormat4
1412
return RepositoryFormat4()
1413
repository_format = property(__return_repository_format)
1416
class BzrDirFormat5(BzrDirFormat):
1417
"""Bzr control format 5.
1419
This format is a combined format for working tree, branch and repository.
1421
- Format 2 working trees [always]
1422
- Format 4 branches [always]
1423
- Format 5 repositories [always]
1424
Unhashed stores in the repository.
1427
_lock_class = lockable_files.TransportLock
1429
def get_format_string(self):
1430
"""See BzrDirFormat.get_format_string()."""
1431
return "Bazaar-NG branch, format 5\n"
1433
def get_format_description(self):
1434
"""See BzrDirFormat.get_format_description()."""
1435
return "All-in-one format 5"
1437
def get_converter(self, format=None):
1438
"""See BzrDirFormat.get_converter()."""
1439
# there is one and only one upgrade path here.
1440
return ConvertBzrDir5To6()
1442
def _initialize_for_clone(self, url):
1443
return self.initialize_on_transport(get_transport(url), _cloning=True)
1445
def initialize_on_transport(self, transport, _cloning=False):
1446
"""Format 5 dirs always have working tree, branch and repository.
1448
Except when they are being cloned.
1450
from bzrlib.branch import BzrBranchFormat4
1451
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1452
from bzrlib.workingtree import WorkingTreeFormat2
1453
result = (super(BzrDirFormat5, self).initialize_on_transport(transport))
1454
RepositoryFormat5().initialize(result, _internal=True)
1456
branch = BzrBranchFormat4().initialize(result)
1458
WorkingTreeFormat2().initialize(result)
1459
except errors.NotLocalUrl:
1460
# Even though we can't access the working tree, we need to
1461
# create its control files.
1462
WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
1465
def _open(self, transport):
1466
"""See BzrDirFormat._open."""
1467
return BzrDir5(transport, self)
1469
def __return_repository_format(self):
1470
"""Circular import protection."""
1471
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1472
return RepositoryFormat5()
1473
repository_format = property(__return_repository_format)
1476
class BzrDirFormat6(BzrDirFormat):
1477
"""Bzr control format 6.
1479
This format is a combined format for working tree, branch and repository.
1481
- Format 2 working trees [always]
1482
- Format 4 branches [always]
1483
- Format 6 repositories [always]
1486
_lock_class = lockable_files.TransportLock
1488
def get_format_string(self):
1489
"""See BzrDirFormat.get_format_string()."""
1490
return "Bazaar-NG branch, format 6\n"
1492
def get_format_description(self):
1493
"""See BzrDirFormat.get_format_description()."""
1494
return "All-in-one format 6"
1496
def get_converter(self, format=None):
1497
"""See BzrDirFormat.get_converter()."""
1498
# there is one and only one upgrade path here.
1499
return ConvertBzrDir6ToMeta()
1501
def _initialize_for_clone(self, url):
1502
return self.initialize_on_transport(get_transport(url), _cloning=True)
1504
def initialize_on_transport(self, transport, _cloning=False):
1505
"""Format 6 dirs always have working tree, branch and repository.
1507
Except when they are being cloned.
1509
from bzrlib.branch import BzrBranchFormat4
1510
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1511
from bzrlib.workingtree import WorkingTreeFormat2
1512
result = super(BzrDirFormat6, self).initialize_on_transport(transport)
1513
RepositoryFormat6().initialize(result, _internal=True)
1515
branch = BzrBranchFormat4().initialize(result)
1517
WorkingTreeFormat2().initialize(result)
1518
except errors.NotLocalUrl:
1519
# Even though we can't access the working tree, we need to
1520
# create its control files.
1521
WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
1524
def _open(self, transport):
1525
"""See BzrDirFormat._open."""
1526
return BzrDir6(transport, self)
1528
def __return_repository_format(self):
1529
"""Circular import protection."""
1530
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1531
return RepositoryFormat6()
1532
repository_format = property(__return_repository_format)
1535
class BzrDirMetaFormat1(BzrDirFormat):
1536
"""Bzr meta control format 1
1538
This is the first format with split out working tree, branch and repository
1541
- Format 3 working trees [optional]
1542
- Format 5 branches [optional]
1543
- Format 7 repositories [optional]
1546
_lock_class = lockdir.LockDir
1549
self._workingtree_format = None
1550
self._branch_format = None
1552
def __eq__(self, other):
1553
if other.__class__ is not self.__class__:
1555
if other.repository_format != self.repository_format:
1557
if other.workingtree_format != self.workingtree_format:
1561
def __ne__(self, other):
1562
return not self == other
1564
def get_branch_format(self):
1565
if self._branch_format is None:
1566
from bzrlib.branch import BranchFormat
1567
self._branch_format = BranchFormat.get_default_format()
1568
return self._branch_format
1570
def set_branch_format(self, format):
1571
self._branch_format = format
1573
def get_converter(self, format=None):
1574
"""See BzrDirFormat.get_converter()."""
1576
format = BzrDirFormat.get_default_format()
1577
if not isinstance(self, format.__class__):
1578
# converting away from metadir is not implemented
1579
raise NotImplementedError(self.get_converter)
1580
return ConvertMetaToMeta(format)
1582
def get_format_string(self):
1583
"""See BzrDirFormat.get_format_string()."""
1584
return "Bazaar-NG meta directory, format 1\n"
1586
def get_format_description(self):
1587
"""See BzrDirFormat.get_format_description()."""
1588
return "Meta directory format 1"
1590
def _open(self, transport):
1591
"""See BzrDirFormat._open."""
1592
return BzrDirMeta1(transport, self)
1594
def __return_repository_format(self):
1595
"""Circular import protection."""
1596
if getattr(self, '_repository_format', None):
1597
return self._repository_format
1598
from bzrlib.repository import RepositoryFormat
1599
return RepositoryFormat.get_default_format()
1601
def __set_repository_format(self, value):
1602
"""Allow changint the repository format for metadir formats."""
1603
self._repository_format = value
1605
repository_format = property(__return_repository_format, __set_repository_format)
1607
def __get_workingtree_format(self):
1608
if self._workingtree_format is None:
1609
from bzrlib.workingtree import WorkingTreeFormat
1610
self._workingtree_format = WorkingTreeFormat.get_default_format()
1611
return self._workingtree_format
1613
def __set_workingtree_format(self, wt_format):
1614
self._workingtree_format = wt_format
1616
workingtree_format = property(__get_workingtree_format,
1617
__set_workingtree_format)
1620
BzrDirFormat.register_format(BzrDirFormat4())
1621
BzrDirFormat.register_format(BzrDirFormat5())
1622
BzrDirFormat.register_format(BzrDirFormat6())
1623
__default_format = BzrDirMetaFormat1()
1624
BzrDirFormat.register_format(__default_format)
1625
BzrDirFormat._default_format = __default_format
1628
class BzrDirTestProviderAdapter(object):
1629
"""A tool to generate a suite testing multiple bzrdir formats at once.
1631
This is done by copying the test once for each transport and injecting
1632
the transport_server, transport_readonly_server, and bzrdir_format
1633
classes into each copy. Each copy is also given a new id() to make it
1637
def __init__(self, vfs_factory, transport_server, transport_readonly_server,
1639
"""Create an object to adapt tests.
1641
:param vfs_server: A factory to create a Transport Server which has
1642
all the VFS methods working, and is writable.
1644
self._vfs_factory = vfs_factory
1645
self._transport_server = transport_server
1646
self._transport_readonly_server = transport_readonly_server
1647
self._formats = formats
1649
def adapt(self, test):
1650
result = unittest.TestSuite()
1651
for format in self._formats:
1652
new_test = deepcopy(test)
1653
new_test.vfs_transport_factory = self._vfs_factory
1654
new_test.transport_server = self._transport_server
1655
new_test.transport_readonly_server = self._transport_readonly_server
1656
new_test.bzrdir_format = format
1657
def make_new_test_id():
1658
new_id = "%s(%s)" % (new_test.id(), format.__class__.__name__)
1659
return lambda: new_id
1660
new_test.id = make_new_test_id()
1661
result.addTest(new_test)
1665
class Converter(object):
1666
"""Converts a disk format object from one format to another."""
1668
def convert(self, to_convert, pb):
1669
"""Perform the conversion of to_convert, giving feedback via pb.
1671
:param to_convert: The disk object to convert.
1672
:param pb: a progress bar to use for progress information.
1675
def step(self, message):
1676
"""Update the pb by a step."""
1678
self.pb.update(message, self.count, self.total)
1681
class ConvertBzrDir4To5(Converter):
1682
"""Converts format 4 bzr dirs to format 5."""
1685
super(ConvertBzrDir4To5, self).__init__()
1686
self.converted_revs = set()
1687
self.absent_revisions = set()
1691
def convert(self, to_convert, pb):
1692
"""See Converter.convert()."""
1693
self.bzrdir = to_convert
1695
self.pb.note('starting upgrade from format 4 to 5')
1696
if isinstance(self.bzrdir.transport, LocalTransport):
1697
self.bzrdir.get_workingtree_transport(None).delete('stat-cache')
1698
self._convert_to_weaves()
1699
return BzrDir.open(self.bzrdir.root_transport.base)
1701
def _convert_to_weaves(self):
1702
self.pb.note('note: upgrade may be faster if all store files are ungzipped first')
1705
stat = self.bzrdir.transport.stat('weaves')
1706
if not S_ISDIR(stat.st_mode):
1707
self.bzrdir.transport.delete('weaves')
1708
self.bzrdir.transport.mkdir('weaves')
1709
except errors.NoSuchFile:
1710
self.bzrdir.transport.mkdir('weaves')
1711
# deliberately not a WeaveFile as we want to build it up slowly.
1712
self.inv_weave = Weave('inventory')
1713
# holds in-memory weaves for all files
1714
self.text_weaves = {}
1715
self.bzrdir.transport.delete('branch-format')
1716
self.branch = self.bzrdir.open_branch()
1717
self._convert_working_inv()
1718
rev_history = self.branch.revision_history()
1719
# to_read is a stack holding the revisions we still need to process;
1720
# appending to it adds new highest-priority revisions
1721
self.known_revisions = set(rev_history)
1722
self.to_read = rev_history[-1:]
1724
rev_id = self.to_read.pop()
1725
if (rev_id not in self.revisions
1726
and rev_id not in self.absent_revisions):
1727
self._load_one_rev(rev_id)
1729
to_import = self._make_order()
1730
for i, rev_id in enumerate(to_import):
1731
self.pb.update('converting revision', i, len(to_import))
1732
self._convert_one_rev(rev_id)
1734
self._write_all_weaves()
1735
self._write_all_revs()
1736
self.pb.note('upgraded to weaves:')
1737
self.pb.note(' %6d revisions and inventories', len(self.revisions))
1738
self.pb.note(' %6d revisions not present', len(self.absent_revisions))
1739
self.pb.note(' %6d texts', self.text_count)
1740
self._cleanup_spare_files_after_format4()
1741
self.branch.control_files.put_utf8('branch-format', BzrDirFormat5().get_format_string())
1743
def _cleanup_spare_files_after_format4(self):
1744
# FIXME working tree upgrade foo.
1745
for n in 'merged-patches', 'pending-merged-patches':
1747
## assert os.path.getsize(p) == 0
1748
self.bzrdir.transport.delete(n)
1749
except errors.NoSuchFile:
1751
self.bzrdir.transport.delete_tree('inventory-store')
1752
self.bzrdir.transport.delete_tree('text-store')
1754
def _convert_working_inv(self):
1755
inv = xml4.serializer_v4.read_inventory(
1756
self.branch.control_files.get('inventory'))
1757
new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
1758
# FIXME inventory is a working tree change.
1759
self.branch.control_files.put('inventory', StringIO(new_inv_xml))
1761
def _write_all_weaves(self):
1762
controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)
1763
weave_transport = self.bzrdir.transport.clone('weaves')
1764
weaves = WeaveStore(weave_transport, prefixed=False)
1765
transaction = WriteTransaction()
1769
for file_id, file_weave in self.text_weaves.items():
1770
self.pb.update('writing weave', i, len(self.text_weaves))
1771
weaves._put_weave(file_id, file_weave, transaction)
1773
self.pb.update('inventory', 0, 1)
1774
controlweaves._put_weave('inventory', self.inv_weave, transaction)
1775
self.pb.update('inventory', 1, 1)
1779
def _write_all_revs(self):
1780
"""Write all revisions out in new form."""
1781
self.bzrdir.transport.delete_tree('revision-store')
1782
self.bzrdir.transport.mkdir('revision-store')
1783
revision_transport = self.bzrdir.transport.clone('revision-store')
1785
_revision_store = TextRevisionStore(TextStore(revision_transport,
1789
transaction = WriteTransaction()
1790
for i, rev_id in enumerate(self.converted_revs):
1791
self.pb.update('write revision', i, len(self.converted_revs))
1792
_revision_store.add_revision(self.revisions[rev_id], transaction)
1796
def _load_one_rev(self, rev_id):
1797
"""Load a revision object into memory.
1799
Any parents not either loaded or abandoned get queued to be
1801
self.pb.update('loading revision',
1802
len(self.revisions),
1803
len(self.known_revisions))
1804
if not self.branch.repository.has_revision(rev_id):
1806
self.pb.note('revision {%s} not present in branch; '
1807
'will be converted as a ghost',
1809
self.absent_revisions.add(rev_id)
1811
rev = self.branch.repository._revision_store.get_revision(rev_id,
1812
self.branch.repository.get_transaction())
1813
for parent_id in rev.parent_ids:
1814
self.known_revisions.add(parent_id)
1815
self.to_read.append(parent_id)
1816
self.revisions[rev_id] = rev
1818
def _load_old_inventory(self, rev_id):
1819
assert rev_id not in self.converted_revs
1820
old_inv_xml = self.branch.repository.inventory_store.get(rev_id).read()
1821
inv = xml4.serializer_v4.read_inventory_from_string(old_inv_xml)
1822
inv.revision_id = rev_id
1823
rev = self.revisions[rev_id]
1824
if rev.inventory_sha1:
1825
assert rev.inventory_sha1 == sha_string(old_inv_xml), \
1826
'inventory sha mismatch for {%s}' % rev_id
1829
def _load_updated_inventory(self, rev_id):
1830
assert rev_id in self.converted_revs
1831
inv_xml = self.inv_weave.get_text(rev_id)
1832
inv = xml5.serializer_v5.read_inventory_from_string(inv_xml)
1835
def _convert_one_rev(self, rev_id):
1836
"""Convert revision and all referenced objects to new format."""
1837
rev = self.revisions[rev_id]
1838
inv = self._load_old_inventory(rev_id)
1839
present_parents = [p for p in rev.parent_ids
1840
if p not in self.absent_revisions]
1841
self._convert_revision_contents(rev, inv, present_parents)
1842
self._store_new_weave(rev, inv, present_parents)
1843
self.converted_revs.add(rev_id)
1845
def _store_new_weave(self, rev, inv, present_parents):
1846
# the XML is now updated with text versions
1848
entries = inv.iter_entries()
1850
for path, ie in entries:
1851
assert getattr(ie, 'revision', None) is not None, \
1852
'no revision on {%s} in {%s}' % \
1853
(file_id, rev.revision_id)
1854
new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
1855
new_inv_sha1 = sha_string(new_inv_xml)
1856
self.inv_weave.add_lines(rev.revision_id,
1858
new_inv_xml.splitlines(True))
1859
rev.inventory_sha1 = new_inv_sha1
1861
def _convert_revision_contents(self, rev, inv, present_parents):
1862
"""Convert all the files within a revision.
1864
Also upgrade the inventory to refer to the text revision ids."""
1865
rev_id = rev.revision_id
1866
mutter('converting texts of revision {%s}',
1868
parent_invs = map(self._load_updated_inventory, present_parents)
1869
entries = inv.iter_entries()
1871
for path, ie in entries:
1872
self._convert_file_version(rev, ie, parent_invs)
1874
def _convert_file_version(self, rev, ie, parent_invs):
1875
"""Convert one version of one file.
1877
The file needs to be added into the weave if it is a merge
1878
of >=2 parents or if it's changed from its parent.
1880
file_id = ie.file_id
1881
rev_id = rev.revision_id
1882
w = self.text_weaves.get(file_id)
1885
self.text_weaves[file_id] = w
1886
text_changed = False
1887
previous_entries = ie.find_previous_heads(parent_invs,
1891
for old_revision in previous_entries:
1892
# if this fails, its a ghost ?
1893
assert old_revision in self.converted_revs, \
1894
"Revision {%s} not in converted_revs" % old_revision
1895
self.snapshot_ie(previous_entries, ie, w, rev_id)
1897
assert getattr(ie, 'revision', None) is not None
1899
def snapshot_ie(self, previous_revisions, ie, w, rev_id):
1900
# TODO: convert this logic, which is ~= snapshot to
1901
# a call to:. This needs the path figured out. rather than a work_tree
1902
# a v4 revision_tree can be given, or something that looks enough like
1903
# one to give the file content to the entry if it needs it.
1904
# and we need something that looks like a weave store for snapshot to
1906
#ie.snapshot(rev, PATH, previous_revisions, REVISION_TREE, InMemoryWeaveStore(self.text_weaves))
1907
if len(previous_revisions) == 1:
1908
previous_ie = previous_revisions.values()[0]
1909
if ie._unchanged(previous_ie):
1910
ie.revision = previous_ie.revision
1913
text = self.branch.repository.text_store.get(ie.text_id)
1914
file_lines = text.readlines()
1915
assert sha_strings(file_lines) == ie.text_sha1
1916
assert sum(map(len, file_lines)) == ie.text_size
1917
w.add_lines(rev_id, previous_revisions, file_lines)
1918
self.text_count += 1
1920
w.add_lines(rev_id, previous_revisions, [])
1921
ie.revision = rev_id
1923
def _make_order(self):
1924
"""Return a suitable order for importing revisions.
1926
The order must be such that an revision is imported after all
1927
its (present) parents.
1929
todo = set(self.revisions.keys())
1930
done = self.absent_revisions.copy()
1933
# scan through looking for a revision whose parents
1935
for rev_id in sorted(list(todo)):
1936
rev = self.revisions[rev_id]
1937
parent_ids = set(rev.parent_ids)
1938
if parent_ids.issubset(done):
1939
# can take this one now
1940
order.append(rev_id)
1946
class ConvertBzrDir5To6(Converter):
1947
"""Converts format 5 bzr dirs to format 6."""
1949
def convert(self, to_convert, pb):
1950
"""See Converter.convert()."""
1951
self.bzrdir = to_convert
1953
self.pb.note('starting upgrade from format 5 to 6')
1954
self._convert_to_prefixed()
1955
return BzrDir.open(self.bzrdir.root_transport.base)
1957
def _convert_to_prefixed(self):
1958
from bzrlib.store import TransportStore
1959
self.bzrdir.transport.delete('branch-format')
1960
for store_name in ["weaves", "revision-store"]:
1961
self.pb.note("adding prefixes to %s" % store_name)
1962
store_transport = self.bzrdir.transport.clone(store_name)
1963
store = TransportStore(store_transport, prefixed=True)
1964
for urlfilename in store_transport.list_dir('.'):
1965
filename = urlutils.unescape(urlfilename)
1966
if (filename.endswith(".weave") or
1967
filename.endswith(".gz") or
1968
filename.endswith(".sig")):
1969
file_id = os.path.splitext(filename)[0]
1972
prefix_dir = store.hash_prefix(file_id)
1973
# FIXME keep track of the dirs made RBC 20060121
1975
store_transport.move(filename, prefix_dir + '/' + filename)
1976
except errors.NoSuchFile: # catches missing dirs strangely enough
1977
store_transport.mkdir(prefix_dir)
1978
store_transport.move(filename, prefix_dir + '/' + filename)
1979
self.bzrdir._control_files.put_utf8('branch-format', BzrDirFormat6().get_format_string())
1982
class ConvertBzrDir6ToMeta(Converter):
1983
"""Converts format 6 bzr dirs to metadirs."""
1985
def convert(self, to_convert, pb):
1986
"""See Converter.convert()."""
1987
from bzrlib.repofmt.weaverepo import RepositoryFormat7
1988
from bzrlib.branch import BzrBranchFormat5
1989
self.bzrdir = to_convert
1992
self.total = 20 # the steps we know about
1993
self.garbage_inventories = []
1995
self.pb.note('starting upgrade from format 6 to metadir')
1996
self.bzrdir._control_files.put_utf8('branch-format', "Converting to format 6")
1997
# its faster to move specific files around than to open and use the apis...
1998
# first off, nuke ancestry.weave, it was never used.
2000
self.step('Removing ancestry.weave')
2001
self.bzrdir.transport.delete('ancestry.weave')
2002
except errors.NoSuchFile:
2004
# find out whats there
2005
self.step('Finding branch files')
2006
last_revision = self.bzrdir.open_branch().last_revision()
2007
bzrcontents = self.bzrdir.transport.list_dir('.')
2008
for name in bzrcontents:
2009
if name.startswith('basis-inventory.'):
2010
self.garbage_inventories.append(name)
2011
# create new directories for repository, working tree and branch
2012
self.dir_mode = self.bzrdir._control_files._dir_mode
2013
self.file_mode = self.bzrdir._control_files._file_mode
2014
repository_names = [('inventory.weave', True),
2015
('revision-store', True),
2017
self.step('Upgrading repository ')
2018
self.bzrdir.transport.mkdir('repository', mode=self.dir_mode)
2019
self.make_lock('repository')
2020
# we hard code the formats here because we are converting into
2021
# the meta format. The meta format upgrader can take this to a
2022
# future format within each component.
2023
self.put_format('repository', RepositoryFormat7())
2024
for entry in repository_names:
2025
self.move_entry('repository', entry)
2027
self.step('Upgrading branch ')
2028
self.bzrdir.transport.mkdir('branch', mode=self.dir_mode)
2029
self.make_lock('branch')
2030
self.put_format('branch', BzrBranchFormat5())
2031
branch_files = [('revision-history', True),
2032
('branch-name', True),
2034
for entry in branch_files:
2035
self.move_entry('branch', entry)
2037
checkout_files = [('pending-merges', True),
2038
('inventory', True),
2039
('stat-cache', False)]
2040
# If a mandatory checkout file is not present, the branch does not have
2041
# a functional checkout. Do not create a checkout in the converted
2043
for name, mandatory in checkout_files:
2044
if mandatory and name not in bzrcontents:
2045
has_checkout = False
2049
if not has_checkout:
2050
self.pb.note('No working tree.')
2051
# If some checkout files are there, we may as well get rid of them.
2052
for name, mandatory in checkout_files:
2053
if name in bzrcontents:
2054
self.bzrdir.transport.delete(name)
2056
from bzrlib.workingtree import WorkingTreeFormat3
2057
self.step('Upgrading working tree')
2058
self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
2059
self.make_lock('checkout')
2061
'checkout', WorkingTreeFormat3())
2062
self.bzrdir.transport.delete_multi(
2063
self.garbage_inventories, self.pb)
2064
for entry in checkout_files:
2065
self.move_entry('checkout', entry)
2066
if last_revision is not None:
2067
self.bzrdir._control_files.put_utf8(
2068
'checkout/last-revision', last_revision)
2069
self.bzrdir._control_files.put_utf8(
2070
'branch-format', BzrDirMetaFormat1().get_format_string())
2071
return BzrDir.open(self.bzrdir.root_transport.base)
2073
def make_lock(self, name):
2074
"""Make a lock for the new control dir name."""
2075
self.step('Make %s lock' % name)
2076
ld = lockdir.LockDir(self.bzrdir.transport,
2078
file_modebits=self.file_mode,
2079
dir_modebits=self.dir_mode)
2082
def move_entry(self, new_dir, entry):
2083
"""Move then entry name into new_dir."""
2085
mandatory = entry[1]
2086
self.step('Moving %s' % name)
2088
self.bzrdir.transport.move(name, '%s/%s' % (new_dir, name))
2089
except errors.NoSuchFile:
2093
def put_format(self, dirname, format):
2094
self.bzrdir._control_files.put_utf8('%s/format' % dirname, format.get_format_string())
2097
class ConvertMetaToMeta(Converter):
2098
"""Converts the components of metadirs."""
2100
def __init__(self, target_format):
2101
"""Create a metadir to metadir converter.
2103
:param target_format: The final metadir format that is desired.
2105
self.target_format = target_format
2107
def convert(self, to_convert, pb):
2108
"""See Converter.convert()."""
2109
self.bzrdir = to_convert
2113
self.step('checking repository format')
2115
repo = self.bzrdir.open_repository()
2116
except errors.NoRepositoryPresent:
2119
if not isinstance(repo._format, self.target_format.repository_format.__class__):
2120
from bzrlib.repository import CopyConverter
2121
self.pb.note('starting repository conversion')
2122
converter = CopyConverter(self.target_format.repository_format)
2123
converter.convert(repo, pb)
2125
branch = self.bzrdir.open_branch()
2126
except errors.NotBranchError:
2129
# TODO: conversions of Branch and Tree should be done by
2130
# InterXFormat lookups
2131
# Avoid circular imports
2132
from bzrlib import branch as _mod_branch
2133
if (branch._format.__class__ is _mod_branch.BzrBranchFormat5 and
2134
self.target_format.get_branch_format().__class__ is
2135
_mod_branch.BzrBranchFormat6):
2136
branch_converter = _mod_branch.Converter5to6()
2137
branch_converter.convert(branch)
2139
tree = self.bzrdir.open_workingtree()
2140
except (errors.NoWorkingTree, errors.NotLocalUrl):
2143
# TODO: conversions of Branch and Tree should be done by
2144
# InterXFormat lookups
2145
if (isinstance(tree, workingtree.WorkingTree3) and
2146
not isinstance(tree, workingtree_4.WorkingTree4) and
2147
isinstance(self.target_format.workingtree_format,
2148
workingtree_4.WorkingTreeFormat4)):
2149
workingtree_4.Converter3to4().convert(tree)
2153
# This is not in remote.py because it's small, and needs to be registered.
2154
# Putting it in remote.py creates a circular import problem.
2155
# we can make it a lazy object if the control formats is turned into something
2157
class RemoteBzrDirFormat(BzrDirMetaFormat1):
2158
"""Format representing bzrdirs accessed via a smart server"""
2160
def get_format_description(self):
2161
return 'bzr remote bzrdir'
2164
def probe_transport(klass, transport):
2165
"""Return a RemoteBzrDirFormat object if it looks possible."""
2167
transport.get_smart_client()
2168
except (NotImplementedError, AttributeError,
2169
errors.TransportNotPossible):
2170
# no smart server, so not a branch for this format type.
2171
raise errors.NotBranchError(path=transport.base)
2175
def initialize_on_transport(self, transport):
2176
# hand off the request to the smart server
2177
medium = transport.get_smart_medium()
2178
client = SmartClient(medium)
2179
path = client.remote_path_from_transport(transport)
2180
response = SmartClient(medium).call('BzrDirFormat.initialize', path)
2181
assert response[0] in ('ok', ), 'unexpected response code %s' % (response,)
2182
return remote.RemoteBzrDir(transport)
2184
def _open(self, transport):
2185
return remote.RemoteBzrDir(transport)
2187
def __eq__(self, other):
2188
if not isinstance(other, RemoteBzrDirFormat):
2190
return self.get_format_description() == other.get_format_description()
2193
# We can't use register_control_format because it adds it at a lower priority
2194
# than the existing branches, whereas this should take priority.
2195
BzrDirFormat._control_formats.insert(0, RemoteBzrDirFormat)
2198
class BzrDirFormatInfo(object):
2200
def __init__(self, native, deprecated, hidden):
2201
self.deprecated = deprecated
2202
self.native = native
2203
self.hidden = hidden
2206
class BzrDirFormatRegistry(registry.Registry):
2207
"""Registry of user-selectable BzrDir subformats.
2209
Differs from BzrDirFormat._control_formats in that it provides sub-formats,
2210
e.g. BzrDirMeta1 with weave repository. Also, it's more user-oriented.
2213
def register_metadir(self, key,
2214
repository_format, help, native=True, deprecated=False,
2218
"""Register a metadir subformat.
2220
These all use a BzrDirMetaFormat1 bzrdir, but can be parameterized
2221
by the Repository format.
2223
:param repository_format: The fully-qualified repository format class
2225
:param branch_format: Fully-qualified branch format class name as
2227
:param tree_format: Fully-qualified tree format class name as
2230
# This should be expanded to support setting WorkingTree and Branch
2231
# formats, once BzrDirMetaFormat1 supports that.
2232
def _load(full_name):
2233
mod_name, factory_name = full_name.rsplit('.', 1)
2235
mod = __import__(mod_name, globals(), locals(),
2237
except ImportError, e:
2238
raise ImportError('failed to load %s: %s' % (full_name, e))
2240
factory = getattr(mod, factory_name)
2241
except AttributeError:
2242
raise AttributeError('no factory %s in module %r'
2247
bd = BzrDirMetaFormat1()
2248
if branch_format is not None:
2249
bd.set_branch_format(_load(branch_format))
2250
if tree_format is not None:
2251
bd.workingtree_format = _load(tree_format)
2252
if repository_format is not None:
2253
bd.repository_format = _load(repository_format)
2255
self.register(key, helper, help, native, deprecated, hidden)
2257
def register(self, key, factory, help, native=True, deprecated=False,
2259
"""Register a BzrDirFormat factory.
2261
The factory must be a callable that takes one parameter: the key.
2262
It must produce an instance of the BzrDirFormat when called.
2264
This function mainly exists to prevent the info object from being
2267
registry.Registry.register(self, key, factory, help,
2268
BzrDirFormatInfo(native, deprecated, hidden))
2270
def register_lazy(self, key, module_name, member_name, help, native=True,
2271
deprecated=False, hidden=False):
2272
registry.Registry.register_lazy(self, key, module_name, member_name,
2273
help, BzrDirFormatInfo(native, deprecated, hidden))
2275
def set_default(self, key):
2276
"""Set the 'default' key to be a clone of the supplied key.
2278
This method must be called once and only once.
2280
registry.Registry.register(self, 'default', self.get(key),
2281
self.get_help(key), info=self.get_info(key))
2283
def set_default_repository(self, key):
2284
"""Set the FormatRegistry default and Repository default.
2286
This is a transitional method while Repository.set_default_format
2289
if 'default' in self:
2290
self.remove('default')
2291
self.set_default(key)
2292
format = self.get('default')()
2293
assert isinstance(format, BzrDirMetaFormat1)
2295
def make_bzrdir(self, key):
2296
return self.get(key)()
2298
def help_topic(self, topic):
2299
output = textwrap.dedent("""\
2300
Bazaar directory formats
2301
------------------------
2303
These formats can be used for creating branches, working trees, and
2307
default_help = self.get_help('default')
2309
for key in self.keys():
2310
if key == 'default':
2312
help = self.get_help(key)
2313
if help == default_help:
2314
default_realkey = key
2316
help_pairs.append((key, help))
2318
def wrapped(key, help, info):
2320
help = '(native) ' + help
2321
return ' %s:\n%s\n\n' % (key,
2322
textwrap.fill(help, initial_indent=' ',
2323
subsequent_indent=' '))
2324
output += wrapped('%s/default' % default_realkey, default_help,
2325
self.get_info('default'))
2326
deprecated_pairs = []
2327
for key, help in help_pairs:
2328
info = self.get_info(key)
2331
elif info.deprecated:
2332
deprecated_pairs.append((key, help))
2334
output += wrapped(key, help, info)
2335
if len(deprecated_pairs) > 0:
2336
output += "Deprecated formats\n------------------\n\n"
2337
for key, help in deprecated_pairs:
2338
info = self.get_info(key)
2339
output += wrapped(key, help, info)
2344
format_registry = BzrDirFormatRegistry()
2345
format_registry.register('weave', BzrDirFormat6,
2346
'Pre-0.8 format. Slower than knit and does not'
2347
' support checkouts or shared repositories.',
2349
format_registry.register_metadir('knit',
2350
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2351
'Format using knits. Recommended for interoperation with bzr <= 0.14.',
2352
branch_format='bzrlib.branch.BzrBranchFormat5',
2353
tree_format='bzrlib.workingtree.WorkingTreeFormat3')
2354
format_registry.register_metadir('metaweave',
2355
'bzrlib.repofmt.weaverepo.RepositoryFormat7',
2356
'Transitional format in 0.8. Slower than knit.',
2357
branch_format='bzrlib.branch.BzrBranchFormat5',
2358
tree_format='bzrlib.workingtree.WorkingTreeFormat3',
2360
format_registry.register_metadir('dirstate',
2361
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2362
help='New in 0.15: Fast local operations. Compatible with bzr 0.8 and '
2363
'above when accessed over the network.',
2364
branch_format='bzrlib.branch.BzrBranchFormat5',
2365
# this uses bzrlib.workingtree.WorkingTreeFormat4 because importing
2366
# directly from workingtree_4 triggers a circular import.
2367
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2369
format_registry.register_metadir('dirstate-tags',
2370
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2371
help='New in 0.15: Fast local operations and improved scaling for '
2372
'network operations. Additionally adds support for tags.'
2373
' Incompatible with bzr < 0.15.',
2374
branch_format='bzrlib.branch.BzrBranchFormat6',
2375
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2377
format_registry.register_metadir('dirstate-with-subtree',
2378
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
2379
help='New in 0.15: Fast local operations and improved scaling for '
2380
'network operations. Additionally adds support for versioning nested '
2381
'bzr branches. Incompatible with bzr < 0.15.',
2382
branch_format='bzrlib.branch.BzrBranchFormat6',
2383
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2386
format_registry.set_default('dirstate')