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: The Format probe_transport seems a bit redundant with just trying to
26
# open the bzrdir. -- mbp
28
# TODO: Can we move specific formats into separate modules to make this file
31
from cStringIO import StringIO
35
from bzrlib.lazy_import import lazy_import
36
lazy_import(globals(), """
37
from copy import deepcopy
38
from stat import S_ISDIR
47
revision as _mod_revision,
56
from bzrlib.osutils import (
61
from bzrlib.store.revision.text import TextRevisionStore
62
from bzrlib.store.text import TextStore
63
from bzrlib.store.versioned import WeaveStore
64
from bzrlib.transactions import WriteTransaction
65
from bzrlib.transport import (
66
do_catching_redirections,
69
from bzrlib.weave import Weave
72
from bzrlib.trace import (
76
from bzrlib.transport.local import LocalTransport
80
"""A .bzr control diretory.
82
BzrDir instances let you create or open any of the things that can be
83
found within .bzr - checkouts, branches and repositories.
86
the transport which this bzr dir is rooted at (i.e. file:///.../.bzr/)
88
a transport connected to the directory this bzr was opened from.
92
"""Invoke break_lock on the first object in the bzrdir.
94
If there is a tree, the tree is opened and break_lock() called.
95
Otherwise, branch is tried, and finally repository.
98
thing_to_unlock = self.open_workingtree()
99
except (errors.NotLocalUrl, errors.NoWorkingTree):
101
thing_to_unlock = self.open_branch()
102
except errors.NotBranchError:
104
thing_to_unlock = self.open_repository()
105
except errors.NoRepositoryPresent:
107
thing_to_unlock.break_lock()
109
def can_convert_format(self):
110
"""Return true if this bzrdir is one whose format we can convert from."""
113
def check_conversion_target(self, target_format):
114
target_repo_format = target_format.repository_format
115
source_repo_format = self._format.repository_format
116
source_repo_format.check_conversion_target(target_repo_format)
119
def _check_supported(format, allow_unsupported,
120
recommend_upgrade=True,
122
"""Give an error or warning on old formats.
124
:param format: may be any kind of format - workingtree, branch,
127
:param allow_unsupported: If true, allow opening
128
formats that are strongly deprecated, and which may
129
have limited functionality.
131
:param recommend_upgrade: If true (default), warn
132
the user through the ui object that they may wish
133
to upgrade the object.
135
# TODO: perhaps move this into the format itself.
137
if not allow_unsupported and not format.is_supported():
138
# see open_downlevel to open legacy branches.
139
raise errors.UnsupportedFormatError(format=format)
140
if recommend_upgrade \
141
and getattr(format, 'upgrade_recommended', False):
142
ui.ui_factory.recommend_upgrade(
143
format.get_format_description(),
146
def clone(self, url, revision_id=None, basis=None, force_new_repo=False):
147
"""Clone this bzrdir and its contents to url verbatim.
149
If urls last component does not exist, it will be created.
151
if revision_id is not None, then the clone operation may tune
152
itself to download less data.
153
:param force_new_repo: Do not use a shared repository for the target
154
even if one is available.
157
basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
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,
170
result_repo.set_make_working_trees(local_repo.make_working_trees())
173
result_repo = result.find_repository()
174
# fetch content this dir needs.
176
# XXX FIXME RBC 20060214 need tests for this when the basis
178
result_repo.fetch(basis_repo, revision_id=revision_id)
179
result_repo.fetch(local_repo, revision_id=revision_id)
180
except errors.NoRepositoryPresent:
181
# needed to make one anyway.
182
result_repo = local_repo.clone(
184
revision_id=revision_id,
186
result_repo.set_make_working_trees(local_repo.make_working_trees())
187
# 1 if there is a branch present
188
# make sure its content is available in the target repository
191
self.open_branch().clone(result, revision_id=revision_id)
192
except errors.NotBranchError:
195
self.open_workingtree().clone(result, basis=basis_tree)
196
except (errors.NoWorkingTree, errors.NotLocalUrl):
200
def _get_basis_components(self, basis):
201
"""Retrieve the basis components that are available at basis."""
203
return None, None, None
205
basis_tree = basis.open_workingtree()
206
basis_branch = basis_tree.branch
207
basis_repo = basis_branch.repository
208
except (errors.NoWorkingTree, errors.NotLocalUrl):
211
basis_branch = basis.open_branch()
212
basis_repo = basis_branch.repository
213
except errors.NotBranchError:
216
basis_repo = basis.open_repository()
217
except errors.NoRepositoryPresent:
219
return basis_repo, basis_branch, basis_tree
221
# TODO: This should be given a Transport, and should chdir up; otherwise
222
# this will open a new connection.
223
def _make_tail(self, url):
224
head, tail = urlutils.split(url)
225
if tail and tail != '.':
226
t = get_transport(head)
229
except errors.FileExists:
232
# TODO: Should take a Transport
234
def create(cls, base, format=None):
235
"""Create a new BzrDir at the url 'base'.
237
This will call the current default formats initialize with base
238
as the only parameter.
240
:param format: If supplied, the format of branch to create. If not
241
supplied, the default is used.
243
if cls is not BzrDir:
244
raise AssertionError("BzrDir.create always creates the default"
245
" format, not one of %r" % cls)
246
head, tail = urlutils.split(base)
247
if tail and tail != '.':
248
t = get_transport(head)
251
except errors.FileExists:
254
format = BzrDirFormat.get_default_format()
255
return format.initialize(safe_unicode(base))
257
def create_branch(self):
258
"""Create a branch in this BzrDir.
260
The bzrdirs format will control what branch format is created.
261
For more control see BranchFormatXX.create(a_bzrdir).
263
raise NotImplementedError(self.create_branch)
266
def create_branch_and_repo(base, force_new_repo=False, format=None):
267
"""Create a new BzrDir, Branch and Repository at the url 'base'.
269
This will use the current default BzrDirFormat, and use whatever
270
repository format that that uses via bzrdir.create_branch and
271
create_repository. If a shared repository is available that is used
274
The created Branch object is returned.
276
:param base: The URL to create the branch at.
277
:param force_new_repo: If True a new repository is always created.
279
bzrdir = BzrDir.create(base, format)
280
bzrdir._find_or_create_repository(force_new_repo)
281
return bzrdir.create_branch()
283
def _find_or_create_repository(self, force_new_repo):
284
"""Create a new repository if needed, returning the repository."""
286
return self.create_repository()
288
return self.find_repository()
289
except errors.NoRepositoryPresent:
290
return self.create_repository()
293
def create_branch_convenience(base, force_new_repo=False,
294
force_new_tree=None, format=None):
295
"""Create a new BzrDir, Branch and Repository at the url 'base'.
297
This is a convenience function - it will use an existing repository
298
if possible, can be told explicitly whether to create a working tree or
301
This will use the current default BzrDirFormat, and use whatever
302
repository format that that uses via bzrdir.create_branch and
303
create_repository. If a shared repository is available that is used
304
preferentially. Whatever repository is used, its tree creation policy
307
The created Branch object is returned.
308
If a working tree cannot be made due to base not being a file:// url,
309
no error is raised unless force_new_tree is True, in which case no
310
data is created on disk and NotLocalUrl is raised.
312
:param base: The URL to create the branch at.
313
:param force_new_repo: If True a new repository is always created.
314
:param force_new_tree: If True or False force creation of a tree or
315
prevent such creation respectively.
316
:param format: Override for the for the bzrdir format to create
319
# check for non local urls
320
t = get_transport(safe_unicode(base))
321
if not isinstance(t, LocalTransport):
322
raise errors.NotLocalUrl(base)
323
bzrdir = BzrDir.create(base, format)
324
repo = bzrdir._find_or_create_repository(force_new_repo)
325
result = bzrdir.create_branch()
326
if force_new_tree or (repo.make_working_trees() and
327
force_new_tree is None):
329
bzrdir.create_workingtree()
330
except errors.NotLocalUrl:
335
def create_repository(base, shared=False, format=None):
336
"""Create a new BzrDir and Repository at the url 'base'.
338
If no format is supplied, this will default to the current default
339
BzrDirFormat by default, and use whatever repository format that that
340
uses for bzrdirformat.create_repository.
342
:param shared: Create a shared repository rather than a standalone
344
The Repository object is returned.
346
This must be overridden as an instance method in child classes, where
347
it should take no parameters and construct whatever repository format
348
that child class desires.
350
bzrdir = BzrDir.create(base, format)
351
return bzrdir.create_repository(shared)
354
def create_standalone_workingtree(base, format=None):
355
"""Create a new BzrDir, WorkingTree, Branch and Repository at 'base'.
357
'base' must be a local path or a file:// url.
359
This will use the current default BzrDirFormat, and use whatever
360
repository format that that uses for bzrdirformat.create_workingtree,
361
create_branch and create_repository.
363
:return: The WorkingTree object.
365
t = get_transport(safe_unicode(base))
366
if not isinstance(t, LocalTransport):
367
raise errors.NotLocalUrl(base)
368
bzrdir = BzrDir.create_branch_and_repo(safe_unicode(base),
370
format=format).bzrdir
371
return bzrdir.create_workingtree()
373
def create_workingtree(self, revision_id=None):
374
"""Create a working tree at this BzrDir.
376
revision_id: create it as of this revision id.
378
raise NotImplementedError(self.create_workingtree)
380
def retire_bzrdir(self):
381
"""Permanently disable the bzrdir.
383
This is done by renaming it to give the user some ability to recover
384
if there was a problem.
386
This will have horrible consequences if anyone has anything locked or
389
for i in xrange(10000):
391
to_path = '.bzr.retired.%d' % i
392
self.root_transport.rename('.bzr', to_path)
393
note("renamed %s to %s"
394
% (self.root_transport.abspath('.bzr'), to_path))
396
except (errors.TransportError, IOError, errors.PathError):
399
def destroy_workingtree(self):
400
"""Destroy the working tree at this BzrDir.
402
Formats that do not support this may raise UnsupportedOperation.
404
raise NotImplementedError(self.destroy_workingtree)
406
def destroy_workingtree_metadata(self):
407
"""Destroy the control files for the working tree at this BzrDir.
409
The contents of working tree files are not affected.
410
Formats that do not support this may raise UnsupportedOperation.
412
raise NotImplementedError(self.destroy_workingtree_metadata)
414
def find_repository(self):
415
"""Find the repository that should be used for a_bzrdir.
417
This does not require a branch as we use it to find the repo for
418
new branches as well as to hook existing branches up to their
422
return self.open_repository()
423
except errors.NoRepositoryPresent:
425
next_transport = self.root_transport.clone('..')
427
# find the next containing bzrdir
429
found_bzrdir = BzrDir.open_containing_from_transport(
431
except errors.NotBranchError:
433
raise errors.NoRepositoryPresent(self)
434
# does it have a repository ?
436
repository = found_bzrdir.open_repository()
437
except errors.NoRepositoryPresent:
438
next_transport = found_bzrdir.root_transport.clone('..')
439
if (found_bzrdir.root_transport.base == next_transport.base):
440
# top of the file system
444
if ((found_bzrdir.root_transport.base ==
445
self.root_transport.base) or repository.is_shared()):
448
raise errors.NoRepositoryPresent(self)
449
raise errors.NoRepositoryPresent(self)
451
def get_branch_transport(self, branch_format):
452
"""Get the transport for use by branch format in this BzrDir.
454
Note that bzr dirs that do not support format strings will raise
455
IncompatibleFormat if the branch format they are given has
456
a format string, and vice versa.
458
If branch_format is None, the transport is returned with no
459
checking. if it is not None, then the returned transport is
460
guaranteed to point to an existing directory ready for use.
462
raise NotImplementedError(self.get_branch_transport)
464
def get_repository_transport(self, repository_format):
465
"""Get the transport for use by repository format in this BzrDir.
467
Note that bzr dirs that do not support format strings will raise
468
IncompatibleFormat if the repository format they are given has
469
a format string, and vice versa.
471
If repository_format is None, the transport is returned with no
472
checking. if it is not None, then the returned transport is
473
guaranteed to point to an existing directory ready for use.
475
raise NotImplementedError(self.get_repository_transport)
477
def get_workingtree_transport(self, tree_format):
478
"""Get the transport for use by workingtree format in this BzrDir.
480
Note that bzr dirs that do not support format strings will raise
481
IncompatibleFormat if the workingtree format they are given has a
482
format string, and vice versa.
484
If workingtree_format is None, the transport is returned with no
485
checking. if it is not None, then the returned transport is
486
guaranteed to point to an existing directory ready for use.
488
raise NotImplementedError(self.get_workingtree_transport)
490
def __init__(self, _transport, _format):
491
"""Initialize a Bzr control dir object.
493
Only really common logic should reside here, concrete classes should be
494
made with varying behaviours.
496
:param _format: the format that is creating this BzrDir instance.
497
:param _transport: the transport this dir is based at.
499
self._format = _format
500
self.transport = _transport.clone('.bzr')
501
self.root_transport = _transport
503
def is_control_filename(self, filename):
504
"""True if filename is the name of a path which is reserved for bzrdir's.
506
:param filename: A filename within the root transport of this bzrdir.
508
This is true IF and ONLY IF the filename is part of the namespace reserved
509
for bzr control dirs. Currently this is the '.bzr' directory in the root
510
of the root_transport. it is expected that plugins will need to extend
511
this in the future - for instance to make bzr talk with svn working
514
# this might be better on the BzrDirFormat class because it refers to
515
# all the possible bzrdir disk formats.
516
# This method is tested via the workingtree is_control_filename tests-
517
# it was extracted from WorkingTree.is_control_filename. If the methods
518
# contract is extended beyond the current trivial implementation please
519
# add new tests for it to the appropriate place.
520
return filename == '.bzr' or filename.startswith('.bzr/')
522
def needs_format_conversion(self, format=None):
523
"""Return true if this bzrdir needs convert_format run on it.
525
For instance, if the repository format is out of date but the
526
branch and working tree are not, this should return True.
528
:param format: Optional parameter indicating a specific desired
529
format we plan to arrive at.
531
raise NotImplementedError(self.needs_format_conversion)
534
def open_unsupported(base):
535
"""Open a branch which is not supported."""
536
return BzrDir.open(base, _unsupported=True)
539
def open(base, _unsupported=False):
540
"""Open an existing bzrdir, rooted at 'base' (url)
542
_unsupported is a private parameter to the BzrDir class.
544
t = get_transport(base)
545
return BzrDir.open_from_transport(t, _unsupported=_unsupported)
548
def open_from_transport(transport, _unsupported=False):
549
"""Open a bzrdir within a particular directory.
551
:param transport: Transport containing the bzrdir.
552
:param _unsupported: private.
554
base = transport.base
556
def find_format(transport):
557
return transport, BzrDirFormat.find_format(transport)
559
def redirected(transport, e, redirection_notice):
560
qualified_source = e.get_source_url()
561
relpath = transport.relpath(qualified_source)
562
if not e.target.endswith(relpath):
563
# Not redirected to a branch-format, not a branch
564
raise errors.NotBranchError(path=e.target)
565
target = e.target[:-len(relpath)]
566
note('%s is%s redirected to %s',
567
transport.base, e.permanently, target)
568
# Let's try with a new transport
569
qualified_target = e.get_target_url()[:-len(relpath)]
570
# FIXME: If 'transport' has a qualifier, this should
571
# be applied again to the new transport *iff* the
572
# schemes used are the same. It's a bit tricky to
573
# verify, so I'll punt for now
575
return get_transport(target)
578
transport, format = do_catching_redirections(find_format,
581
except errors.TooManyRedirections:
582
raise errors.NotBranchError(base)
584
BzrDir._check_supported(format, _unsupported)
585
return format.open(transport, _found=True)
587
def open_branch(self, unsupported=False):
588
"""Open the branch object at this BzrDir if one is present.
590
If unsupported is True, then no longer supported branch formats can
593
TODO: static convenience version of this?
595
raise NotImplementedError(self.open_branch)
598
def open_containing(url):
599
"""Open an existing branch which contains url.
601
:param url: url to search from.
602
See open_containing_from_transport for more detail.
604
return BzrDir.open_containing_from_transport(get_transport(url))
607
def open_containing_from_transport(a_transport):
608
"""Open an existing branch which contains a_transport.base
610
This probes for a branch at a_transport, and searches upwards from there.
612
Basically we keep looking up until we find the control directory or
613
run into the root. If there isn't one, raises NotBranchError.
614
If there is one and it is either an unrecognised format or an unsupported
615
format, UnknownFormatError or UnsupportedFormatError are raised.
616
If there is one, it is returned, along with the unused portion of url.
618
:return: The BzrDir that contains the path, and a Unicode path
619
for the rest of the URL.
621
# this gets the normalised url back. I.e. '.' -> the full path.
622
url = a_transport.base
625
result = BzrDir.open_from_transport(a_transport)
626
return result, urlutils.unescape(a_transport.relpath(url))
627
except errors.NotBranchError, e:
629
new_t = a_transport.clone('..')
630
if new_t.base == a_transport.base:
631
# reached the root, whatever that may be
632
raise errors.NotBranchError(path=url)
636
def open_containing_tree_or_branch(klass, location):
637
"""Return the branch and working tree contained by a location.
639
Returns (tree, branch, relpath).
640
If there is no tree at containing the location, tree will be None.
641
If there is no branch containing the location, an exception will be
643
relpath is the portion of the path that is contained by the branch.
645
bzrdir, relpath = klass.open_containing(location)
647
tree = bzrdir.open_workingtree()
648
except (errors.NoWorkingTree, errors.NotLocalUrl):
650
branch = bzrdir.open_branch()
653
return tree, branch, relpath
655
def open_repository(self, _unsupported=False):
656
"""Open the repository object at this BzrDir if one is present.
658
This will not follow the Branch object pointer - its strictly a direct
659
open facility. Most client code should use open_branch().repository to
662
_unsupported is a private parameter, not part of the api.
663
TODO: static convenience version of this?
665
raise NotImplementedError(self.open_repository)
667
def open_workingtree(self, _unsupported=False):
668
"""Open the workingtree object at this BzrDir if one is present.
670
TODO: static convenience version of this?
672
raise NotImplementedError(self.open_workingtree)
674
def has_branch(self):
675
"""Tell if this bzrdir contains a branch.
677
Note: if you're going to open the branch, you should just go ahead
678
and try, and not ask permission first. (This method just opens the
679
branch and discards it, and that's somewhat expensive.)
684
except errors.NotBranchError:
687
def has_workingtree(self):
688
"""Tell if this bzrdir contains a working tree.
690
This will still raise an exception if the bzrdir has a workingtree that
691
is remote & inaccessible.
693
Note: if you're going to open the working tree, you should just go ahead
694
and try, and not ask permission first. (This method just opens the
695
workingtree and discards it, and that's somewhat expensive.)
698
self.open_workingtree(recommend_upgrade=False)
700
except errors.NoWorkingTree:
703
def _cloning_metadir(self, basis=None):
704
def related_repository(bzrdir):
706
branch = bzrdir.open_branch()
707
return branch.repository
708
except errors.NotBranchError:
710
return bzrdir.open_repository()
711
result_format = self._format.__class__()
714
source_repository = related_repository(self)
715
except errors.NoRepositoryPresent:
718
source_repository = related_repository(self)
719
result_format.repository_format = source_repository._format
720
except errors.NoRepositoryPresent:
721
source_repository = None
723
tree = self.open_workingtree()
724
except (errors.NoWorkingTree, errors.NotLocalUrl):
725
result_format.workingtree_format = None
727
result_format.workingtree_format = tree._format.__class__()
728
return result_format, source_repository
730
def cloning_metadir(self, basis=None):
731
"""Produce a metadir suitable for cloning or sprouting with.
733
These operations may produce workingtrees (yes, even though they're
734
"cloning" something that doesn't have a tree, so a viable workingtree
735
format must be selected.
737
format, repository = self._cloning_metadir()
738
if format._workingtree_format is None:
739
if repository is None:
741
tree_format = repository._format._matchingbzrdir.workingtree_format
742
format.workingtree_format = tree_format.__class__()
745
def checkout_metadir(self):
746
return self.cloning_metadir()
748
def sprout(self, url, revision_id=None, basis=None, force_new_repo=False,
750
"""Create a copy of this bzrdir prepared for use as a new line of
753
If urls last component does not exist, it will be created.
755
Attributes related to the identity of the source branch like
756
branch nickname will be cleaned, a working tree is created
757
whether one existed before or not; and a local branch is always
760
if revision_id is not None, then the clone operation may tune
761
itself to download less data.
764
cloning_format = self.cloning_metadir(basis)
765
result = cloning_format.initialize(url)
766
basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
768
source_branch = self.open_branch()
769
source_repository = source_branch.repository
770
except errors.NotBranchError:
773
source_repository = self.open_repository()
774
except errors.NoRepositoryPresent:
775
# copy the entire basis one if there is one
776
# but there is no repository.
777
source_repository = basis_repo
782
result_repo = result.find_repository()
783
except errors.NoRepositoryPresent:
785
if source_repository is None and result_repo is not None:
787
elif source_repository is None and result_repo is None:
788
# no repo available, make a new one
789
result.create_repository()
790
elif source_repository is not None and result_repo is None:
791
# have source, and want to make a new target repo
792
# we don't clone the repo because that preserves attributes
793
# like is_shared(), and we have not yet implemented a
794
# repository sprout().
795
result_repo = result.create_repository()
796
if result_repo is not None:
797
# fetch needed content into target.
799
# XXX FIXME RBC 20060214 need tests for this when the basis
801
result_repo.fetch(basis_repo, revision_id=revision_id)
802
if source_repository is not None:
803
result_repo.fetch(source_repository, revision_id=revision_id)
804
if source_branch is not None:
805
source_branch.sprout(result, revision_id=revision_id)
807
result.create_branch()
808
# TODO: jam 20060426 we probably need a test in here in the
809
# case that the newly sprouted branch is a remote one
810
if result_repo is None or result_repo.make_working_trees():
811
wt = result.create_workingtree()
814
if wt.path2id('') is None:
816
wt.set_root_id(self.open_workingtree.get_root_id())
817
except errors.NoWorkingTree:
823
if recurse == 'down':
825
basis = wt.basis_tree()
827
subtrees = basis.iter_references()
828
recurse_branch = wt.branch
829
elif source_branch is not None:
830
basis = source_branch.basis_tree()
832
subtrees = basis.iter_references()
833
recurse_branch = source_branch
838
for path, file_id in subtrees:
839
target = urlutils.join(url, urlutils.escape(path))
840
sublocation = source_branch.reference_parent(file_id, path)
841
sublocation.bzrdir.sprout(target,
842
basis.get_reference_revision(file_id, path),
843
force_new_repo=force_new_repo, recurse=recurse)
845
if basis is not None:
850
class BzrDirPreSplitOut(BzrDir):
851
"""A common class for the all-in-one formats."""
853
def __init__(self, _transport, _format):
854
"""See BzrDir.__init__."""
855
super(BzrDirPreSplitOut, self).__init__(_transport, _format)
856
assert self._format._lock_class == lockable_files.TransportLock
857
assert self._format._lock_file_name == 'branch-lock'
858
self._control_files = lockable_files.LockableFiles(
859
self.get_branch_transport(None),
860
self._format._lock_file_name,
861
self._format._lock_class)
863
def break_lock(self):
864
"""Pre-splitout bzrdirs do not suffer from stale locks."""
865
raise NotImplementedError(self.break_lock)
867
def clone(self, url, revision_id=None, basis=None, force_new_repo=False):
868
"""See BzrDir.clone()."""
869
from bzrlib.workingtree import WorkingTreeFormat2
871
result = self._format._initialize_for_clone(url)
872
basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
873
self.open_repository().clone(result, revision_id=revision_id, basis=basis_repo)
874
from_branch = self.open_branch()
875
from_branch.clone(result, revision_id=revision_id)
877
self.open_workingtree().clone(result, basis=basis_tree)
878
except errors.NotLocalUrl:
879
# make a new one, this format always has to have one.
881
WorkingTreeFormat2().initialize(result)
882
except errors.NotLocalUrl:
883
# but we cannot do it for remote trees.
884
to_branch = result.open_branch()
885
WorkingTreeFormat2().stub_initialize_remote(to_branch.control_files)
888
def create_branch(self):
889
"""See BzrDir.create_branch."""
890
return self.open_branch()
892
def create_repository(self, shared=False):
893
"""See BzrDir.create_repository."""
895
raise errors.IncompatibleFormat('shared repository', self._format)
896
return self.open_repository()
898
def create_workingtree(self, revision_id=None):
899
"""See BzrDir.create_workingtree."""
900
# this looks buggy but is not -really-
901
# because this format creates the workingtree when the bzrdir is
903
# clone and sprout will have set the revision_id
904
# and that will have set it for us, its only
905
# specific uses of create_workingtree in isolation
906
# that can do wonky stuff here, and that only
907
# happens for creating checkouts, which cannot be
908
# done on this format anyway. So - acceptable wart.
909
result = self.open_workingtree(recommend_upgrade=False)
910
if revision_id is not None:
911
if revision_id == _mod_revision.NULL_REVISION:
912
result.set_parent_ids([])
914
result.set_parent_ids([revision_id])
917
def destroy_workingtree(self):
918
"""See BzrDir.destroy_workingtree."""
919
raise errors.UnsupportedOperation(self.destroy_workingtree, self)
921
def destroy_workingtree_metadata(self):
922
"""See BzrDir.destroy_workingtree_metadata."""
923
raise errors.UnsupportedOperation(self.destroy_workingtree_metadata,
926
def get_branch_transport(self, branch_format):
927
"""See BzrDir.get_branch_transport()."""
928
if branch_format is None:
929
return self.transport
931
branch_format.get_format_string()
932
except NotImplementedError:
933
return self.transport
934
raise errors.IncompatibleFormat(branch_format, self._format)
936
def get_repository_transport(self, repository_format):
937
"""See BzrDir.get_repository_transport()."""
938
if repository_format is None:
939
return self.transport
941
repository_format.get_format_string()
942
except NotImplementedError:
943
return self.transport
944
raise errors.IncompatibleFormat(repository_format, self._format)
946
def get_workingtree_transport(self, workingtree_format):
947
"""See BzrDir.get_workingtree_transport()."""
948
if workingtree_format is None:
949
return self.transport
951
workingtree_format.get_format_string()
952
except NotImplementedError:
953
return self.transport
954
raise errors.IncompatibleFormat(workingtree_format, self._format)
956
def needs_format_conversion(self, format=None):
957
"""See BzrDir.needs_format_conversion()."""
958
# if the format is not the same as the system default,
959
# an upgrade is needed.
961
format = BzrDirFormat.get_default_format()
962
return not isinstance(self._format, format.__class__)
964
def open_branch(self, unsupported=False):
965
"""See BzrDir.open_branch."""
966
from bzrlib.branch import BzrBranchFormat4
967
format = BzrBranchFormat4()
968
self._check_supported(format, unsupported)
969
return format.open(self, _found=True)
971
def sprout(self, url, revision_id=None, basis=None, force_new_repo=False):
972
"""See BzrDir.sprout()."""
973
from bzrlib.workingtree import WorkingTreeFormat2
975
result = self._format._initialize_for_clone(url)
976
basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
978
self.open_repository().clone(result, revision_id=revision_id, basis=basis_repo)
979
except errors.NoRepositoryPresent:
982
self.open_branch().sprout(result, revision_id=revision_id)
983
except errors.NotBranchError:
985
# we always want a working tree
986
WorkingTreeFormat2().initialize(result)
990
class BzrDir4(BzrDirPreSplitOut):
991
"""A .bzr version 4 control object.
993
This is a deprecated format and may be removed after sept 2006.
996
def create_repository(self, shared=False):
997
"""See BzrDir.create_repository."""
998
return self._format.repository_format.initialize(self, shared)
1000
def needs_format_conversion(self, format=None):
1001
"""Format 4 dirs are always in need of conversion."""
1004
def open_repository(self):
1005
"""See BzrDir.open_repository."""
1006
from bzrlib.repofmt.weaverepo import RepositoryFormat4
1007
return RepositoryFormat4().open(self, _found=True)
1010
class BzrDir5(BzrDirPreSplitOut):
1011
"""A .bzr version 5 control object.
1013
This is a deprecated format and may be removed after sept 2006.
1016
def open_repository(self):
1017
"""See BzrDir.open_repository."""
1018
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1019
return RepositoryFormat5().open(self, _found=True)
1021
def open_workingtree(self, _unsupported=False,
1022
recommend_upgrade=True):
1023
"""See BzrDir.create_workingtree."""
1024
from bzrlib.workingtree import WorkingTreeFormat2
1025
wt_format = WorkingTreeFormat2()
1026
# we don't warn here about upgrades; that ought to be handled for the
1028
return wt_format.open(self, _found=True)
1031
class BzrDir6(BzrDirPreSplitOut):
1032
"""A .bzr version 6 control object.
1034
This is a deprecated format and may be removed after sept 2006.
1037
def open_repository(self):
1038
"""See BzrDir.open_repository."""
1039
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1040
return RepositoryFormat6().open(self, _found=True)
1042
def open_workingtree(self, _unsupported=False,
1043
recommend_upgrade=True):
1044
"""See BzrDir.create_workingtree."""
1045
# we don't warn here about upgrades; that ought to be handled for the
1047
from bzrlib.workingtree import WorkingTreeFormat2
1048
return WorkingTreeFormat2().open(self, _found=True)
1051
class BzrDirMeta1(BzrDir):
1052
"""A .bzr meta version 1 control object.
1054
This is the first control object where the
1055
individual aspects are really split out: there are separate repository,
1056
workingtree and branch subdirectories and any subset of the three can be
1057
present within a BzrDir.
1060
def can_convert_format(self):
1061
"""See BzrDir.can_convert_format()."""
1064
def create_branch(self):
1065
"""See BzrDir.create_branch."""
1066
return self._format.get_branch_format().initialize(self)
1068
def create_repository(self, shared=False):
1069
"""See BzrDir.create_repository."""
1070
return self._format.repository_format.initialize(self, shared)
1072
def create_workingtree(self, revision_id=None):
1073
"""See BzrDir.create_workingtree."""
1074
from bzrlib.workingtree import WorkingTreeFormat
1075
return self._format.workingtree_format.initialize(self, revision_id)
1077
def destroy_workingtree(self):
1078
"""See BzrDir.destroy_workingtree."""
1079
wt = self.open_workingtree(recommend_upgrade=False)
1080
repository = wt.branch.repository
1081
empty = repository.revision_tree(_mod_revision.NULL_REVISION)
1082
wt.revert([], old_tree=empty)
1083
self.destroy_workingtree_metadata()
1085
def destroy_workingtree_metadata(self):
1086
self.transport.delete_tree('checkout')
1088
def _get_mkdir_mode(self):
1089
"""Figure out the mode to use when creating a bzrdir subdir."""
1090
temp_control = lockable_files.LockableFiles(self.transport, '',
1091
lockable_files.TransportLock)
1092
return temp_control._dir_mode
1094
def get_branch_transport(self, branch_format):
1095
"""See BzrDir.get_branch_transport()."""
1096
if branch_format is None:
1097
return self.transport.clone('branch')
1099
branch_format.get_format_string()
1100
except NotImplementedError:
1101
raise errors.IncompatibleFormat(branch_format, self._format)
1103
self.transport.mkdir('branch', mode=self._get_mkdir_mode())
1104
except errors.FileExists:
1106
return self.transport.clone('branch')
1108
def get_repository_transport(self, repository_format):
1109
"""See BzrDir.get_repository_transport()."""
1110
if repository_format is None:
1111
return self.transport.clone('repository')
1113
repository_format.get_format_string()
1114
except NotImplementedError:
1115
raise errors.IncompatibleFormat(repository_format, self._format)
1117
self.transport.mkdir('repository', mode=self._get_mkdir_mode())
1118
except errors.FileExists:
1120
return self.transport.clone('repository')
1122
def get_workingtree_transport(self, workingtree_format):
1123
"""See BzrDir.get_workingtree_transport()."""
1124
if workingtree_format is None:
1125
return self.transport.clone('checkout')
1127
workingtree_format.get_format_string()
1128
except NotImplementedError:
1129
raise errors.IncompatibleFormat(workingtree_format, self._format)
1131
self.transport.mkdir('checkout', mode=self._get_mkdir_mode())
1132
except errors.FileExists:
1134
return self.transport.clone('checkout')
1136
def needs_format_conversion(self, format=None):
1137
"""See BzrDir.needs_format_conversion()."""
1139
format = BzrDirFormat.get_default_format()
1140
if not isinstance(self._format, format.__class__):
1141
# it is not a meta dir format, conversion is needed.
1143
# we might want to push this down to the repository?
1145
if not isinstance(self.open_repository()._format,
1146
format.repository_format.__class__):
1147
# the repository needs an upgrade.
1149
except errors.NoRepositoryPresent:
1152
if not isinstance(self.open_branch()._format,
1153
format.get_branch_format().__class__):
1154
# the branch needs an upgrade.
1156
except errors.NotBranchError:
1159
my_wt = self.open_workingtree(recommend_upgrade=False)
1160
if not isinstance(my_wt._format,
1161
format.workingtree_format.__class__):
1162
# the workingtree needs an upgrade.
1164
except (errors.NoWorkingTree, errors.NotLocalUrl):
1168
def open_branch(self, unsupported=False):
1169
"""See BzrDir.open_branch."""
1170
from bzrlib.branch import BranchFormat
1171
format = BranchFormat.find_format(self)
1172
self._check_supported(format, unsupported)
1173
return format.open(self, _found=True)
1175
def open_repository(self, unsupported=False):
1176
"""See BzrDir.open_repository."""
1177
from bzrlib.repository import RepositoryFormat
1178
format = RepositoryFormat.find_format(self)
1179
self._check_supported(format, unsupported)
1180
return format.open(self, _found=True)
1182
def open_workingtree(self, unsupported=False,
1183
recommend_upgrade=True):
1184
"""See BzrDir.open_workingtree."""
1185
from bzrlib.workingtree import WorkingTreeFormat
1186
format = WorkingTreeFormat.find_format(self)
1187
self._check_supported(format, unsupported,
1189
basedir=self.root_transport.base)
1190
return format.open(self, _found=True)
1193
class BzrDirFormat(object):
1194
"""An encapsulation of the initialization and open routines for a format.
1196
Formats provide three things:
1197
* An initialization routine,
1201
Formats are placed in an dict by their format string for reference
1202
during bzrdir opening. These should be subclasses of BzrDirFormat
1205
Once a format is deprecated, just deprecate the initialize and open
1206
methods on the format class. Do not deprecate the object, as the
1207
object will be created every system load.
1210
_default_format = None
1211
"""The default format used for new .bzr dirs."""
1214
"""The known formats."""
1216
_control_formats = []
1217
"""The registered control formats - .bzr, ....
1219
This is a list of BzrDirFormat objects.
1222
_lock_file_name = 'branch-lock'
1224
# _lock_class must be set in subclasses to the lock type, typ.
1225
# TransportLock or LockDir
1228
def find_format(klass, transport):
1229
"""Return the format present at transport."""
1230
for format in klass._control_formats:
1232
return format.probe_transport(transport)
1233
except errors.NotBranchError:
1234
# this format does not find a control dir here.
1236
raise errors.NotBranchError(path=transport.base)
1239
def probe_transport(klass, transport):
1240
"""Return the .bzrdir style transport present at URL."""
1242
format_string = transport.get(".bzr/branch-format").read()
1243
except errors.NoSuchFile:
1244
raise errors.NotBranchError(path=transport.base)
1247
return klass._formats[format_string]
1249
raise errors.UnknownFormatError(format=format_string)
1252
def get_default_format(klass):
1253
"""Return the current default format."""
1254
return klass._default_format
1256
def get_format_string(self):
1257
"""Return the ASCII format string that identifies this format."""
1258
raise NotImplementedError(self.get_format_string)
1260
def get_format_description(self):
1261
"""Return the short description for this format."""
1262
raise NotImplementedError(self.get_format_description)
1264
def get_converter(self, format=None):
1265
"""Return the converter to use to convert bzrdirs needing converts.
1267
This returns a bzrlib.bzrdir.Converter object.
1269
This should return the best upgrader to step this format towards the
1270
current default format. In the case of plugins we can/should provide
1271
some means for them to extend the range of returnable converters.
1273
:param format: Optional format to override the default format of the
1276
raise NotImplementedError(self.get_converter)
1278
def initialize(self, url):
1279
"""Create a bzr control dir at this url and return an opened copy.
1281
Subclasses should typically override initialize_on_transport
1282
instead of this method.
1284
return self.initialize_on_transport(get_transport(url))
1286
def initialize_on_transport(self, transport):
1287
"""Initialize a new bzrdir in the base directory of a Transport."""
1288
# Since we don't have a .bzr directory, inherit the
1289
# mode from the root directory
1290
temp_control = lockable_files.LockableFiles(transport,
1291
'', lockable_files.TransportLock)
1292
temp_control._transport.mkdir('.bzr',
1293
# FIXME: RBC 20060121 don't peek under
1295
mode=temp_control._dir_mode)
1296
file_mode = temp_control._file_mode
1298
mutter('created control directory in ' + transport.base)
1299
control = transport.clone('.bzr')
1300
utf8_files = [('README',
1301
"This is a Bazaar-NG control directory.\n"
1302
"Do not change any files in this directory.\n"),
1303
('branch-format', self.get_format_string()),
1305
# NB: no need to escape relative paths that are url safe.
1306
control_files = lockable_files.LockableFiles(control,
1307
self._lock_file_name, self._lock_class)
1308
control_files.create_lock()
1309
control_files.lock_write()
1311
for file, content in utf8_files:
1312
control_files.put_utf8(file, content)
1314
control_files.unlock()
1315
return self.open(transport, _found=True)
1317
def is_supported(self):
1318
"""Is this format supported?
1320
Supported formats must be initializable and openable.
1321
Unsupported formats may not support initialization or committing or
1322
some other features depending on the reason for not being supported.
1326
def same_model(self, target_format):
1327
return (self.repository_format.rich_root_data ==
1328
target_format.rich_root_data)
1331
def known_formats(klass):
1332
"""Return all the known formats.
1334
Concrete formats should override _known_formats.
1336
# There is double indirection here to make sure that control
1337
# formats used by more than one dir format will only be probed
1338
# once. This can otherwise be quite expensive for remote connections.
1340
for format in klass._control_formats:
1341
result.update(format._known_formats())
1345
def _known_formats(klass):
1346
"""Return the known format instances for this control format."""
1347
return set(klass._formats.values())
1349
def open(self, transport, _found=False):
1350
"""Return an instance of this format for the dir transport points at.
1352
_found is a private parameter, do not use it.
1355
found_format = BzrDirFormat.find_format(transport)
1356
if not isinstance(found_format, self.__class__):
1357
raise AssertionError("%s was asked to open %s, but it seems to need "
1359
% (self, transport, found_format))
1360
return self._open(transport)
1362
def _open(self, transport):
1363
"""Template method helper for opening BzrDirectories.
1365
This performs the actual open and any additional logic or parameter
1368
raise NotImplementedError(self._open)
1371
def register_format(klass, format):
1372
klass._formats[format.get_format_string()] = format
1375
def register_control_format(klass, format):
1376
"""Register a format that does not use '.bzr' for its control dir.
1378
TODO: This should be pulled up into a 'ControlDirFormat' base class
1379
which BzrDirFormat can inherit from, and renamed to register_format
1380
there. It has been done without that for now for simplicity of
1383
klass._control_formats.append(format)
1386
@symbol_versioning.deprecated_method(symbol_versioning.zero_fourteen)
1387
def set_default_format(klass, format):
1388
klass._set_default_format(format)
1391
def _set_default_format(klass, format):
1392
"""Set default format (for testing behavior of defaults only)"""
1393
klass._default_format = format
1396
return self.get_format_string()[:-1]
1399
def unregister_format(klass, format):
1400
assert klass._formats[format.get_format_string()] is format
1401
del klass._formats[format.get_format_string()]
1404
def unregister_control_format(klass, format):
1405
klass._control_formats.remove(format)
1408
class BzrDirFormat4(BzrDirFormat):
1409
"""Bzr dir format 4.
1411
This format is a combined format for working tree, branch and repository.
1413
- Format 1 working trees [always]
1414
- Format 4 branches [always]
1415
- Format 4 repositories [always]
1417
This format is deprecated: it indexes texts using a text it which is
1418
removed in format 5; write support for this format has been removed.
1421
_lock_class = lockable_files.TransportLock
1423
def get_format_string(self):
1424
"""See BzrDirFormat.get_format_string()."""
1425
return "Bazaar-NG branch, format 0.0.4\n"
1427
def get_format_description(self):
1428
"""See BzrDirFormat.get_format_description()."""
1429
return "All-in-one format 4"
1431
def get_converter(self, format=None):
1432
"""See BzrDirFormat.get_converter()."""
1433
# there is one and only one upgrade path here.
1434
return ConvertBzrDir4To5()
1436
def initialize_on_transport(self, transport):
1437
"""Format 4 branches cannot be created."""
1438
raise errors.UninitializableFormat(self)
1440
def is_supported(self):
1441
"""Format 4 is not supported.
1443
It is not supported because the model changed from 4 to 5 and the
1444
conversion logic is expensive - so doing it on the fly was not
1449
def _open(self, transport):
1450
"""See BzrDirFormat._open."""
1451
return BzrDir4(transport, self)
1453
def __return_repository_format(self):
1454
"""Circular import protection."""
1455
from bzrlib.repofmt.weaverepo import RepositoryFormat4
1456
return RepositoryFormat4()
1457
repository_format = property(__return_repository_format)
1460
class BzrDirFormat5(BzrDirFormat):
1461
"""Bzr control format 5.
1463
This format is a combined format for working tree, branch and repository.
1465
- Format 2 working trees [always]
1466
- Format 4 branches [always]
1467
- Format 5 repositories [always]
1468
Unhashed stores in the repository.
1471
_lock_class = lockable_files.TransportLock
1473
def get_format_string(self):
1474
"""See BzrDirFormat.get_format_string()."""
1475
return "Bazaar-NG branch, format 5\n"
1477
def get_format_description(self):
1478
"""See BzrDirFormat.get_format_description()."""
1479
return "All-in-one format 5"
1481
def get_converter(self, format=None):
1482
"""See BzrDirFormat.get_converter()."""
1483
# there is one and only one upgrade path here.
1484
return ConvertBzrDir5To6()
1486
def _initialize_for_clone(self, url):
1487
return self.initialize_on_transport(get_transport(url), _cloning=True)
1489
def initialize_on_transport(self, transport, _cloning=False):
1490
"""Format 5 dirs always have working tree, branch and repository.
1492
Except when they are being cloned.
1494
from bzrlib.branch import BzrBranchFormat4
1495
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1496
from bzrlib.workingtree import WorkingTreeFormat2
1497
result = (super(BzrDirFormat5, self).initialize_on_transport(transport))
1498
RepositoryFormat5().initialize(result, _internal=True)
1500
branch = BzrBranchFormat4().initialize(result)
1502
WorkingTreeFormat2().initialize(result)
1503
except errors.NotLocalUrl:
1504
# Even though we can't access the working tree, we need to
1505
# create its control files.
1506
WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
1509
def _open(self, transport):
1510
"""See BzrDirFormat._open."""
1511
return BzrDir5(transport, self)
1513
def __return_repository_format(self):
1514
"""Circular import protection."""
1515
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1516
return RepositoryFormat5()
1517
repository_format = property(__return_repository_format)
1520
class BzrDirFormat6(BzrDirFormat):
1521
"""Bzr control format 6.
1523
This format is a combined format for working tree, branch and repository.
1525
- Format 2 working trees [always]
1526
- Format 4 branches [always]
1527
- Format 6 repositories [always]
1530
_lock_class = lockable_files.TransportLock
1532
def get_format_string(self):
1533
"""See BzrDirFormat.get_format_string()."""
1534
return "Bazaar-NG branch, format 6\n"
1536
def get_format_description(self):
1537
"""See BzrDirFormat.get_format_description()."""
1538
return "All-in-one format 6"
1540
def get_converter(self, format=None):
1541
"""See BzrDirFormat.get_converter()."""
1542
# there is one and only one upgrade path here.
1543
return ConvertBzrDir6ToMeta()
1545
def _initialize_for_clone(self, url):
1546
return self.initialize_on_transport(get_transport(url), _cloning=True)
1548
def initialize_on_transport(self, transport, _cloning=False):
1549
"""Format 6 dirs always have working tree, branch and repository.
1551
Except when they are being cloned.
1553
from bzrlib.branch import BzrBranchFormat4
1554
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1555
from bzrlib.workingtree import WorkingTreeFormat2
1556
result = super(BzrDirFormat6, self).initialize_on_transport(transport)
1557
RepositoryFormat6().initialize(result, _internal=True)
1559
branch = BzrBranchFormat4().initialize(result)
1561
WorkingTreeFormat2().initialize(result)
1562
except errors.NotLocalUrl:
1563
# Even though we can't access the working tree, we need to
1564
# create its control files.
1565
WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
1568
def _open(self, transport):
1569
"""See BzrDirFormat._open."""
1570
return BzrDir6(transport, self)
1572
def __return_repository_format(self):
1573
"""Circular import protection."""
1574
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1575
return RepositoryFormat6()
1576
repository_format = property(__return_repository_format)
1579
class BzrDirMetaFormat1(BzrDirFormat):
1580
"""Bzr meta control format 1
1582
This is the first format with split out working tree, branch and repository
1585
- Format 3 working trees [optional]
1586
- Format 5 branches [optional]
1587
- Format 7 repositories [optional]
1590
_lock_class = lockdir.LockDir
1593
self._workingtree_format = None
1594
self._branch_format = None
1596
def __eq__(self, other):
1597
if other.__class__ is not self.__class__:
1599
if other.repository_format != self.repository_format:
1601
if other.workingtree_format != self.workingtree_format:
1605
def __ne__(self, other):
1606
return not self == other
1608
def get_branch_format(self):
1609
if self._branch_format is None:
1610
from bzrlib.branch import BranchFormat
1611
self._branch_format = BranchFormat.get_default_format()
1612
return self._branch_format
1614
def set_branch_format(self, format):
1615
self._branch_format = format
1617
def get_converter(self, format=None):
1618
"""See BzrDirFormat.get_converter()."""
1620
format = BzrDirFormat.get_default_format()
1621
if not isinstance(self, format.__class__):
1622
# converting away from metadir is not implemented
1623
raise NotImplementedError(self.get_converter)
1624
return ConvertMetaToMeta(format)
1626
def get_format_string(self):
1627
"""See BzrDirFormat.get_format_string()."""
1628
return "Bazaar-NG meta directory, format 1\n"
1630
def get_format_description(self):
1631
"""See BzrDirFormat.get_format_description()."""
1632
return "Meta directory format 1"
1634
def _open(self, transport):
1635
"""See BzrDirFormat._open."""
1636
return BzrDirMeta1(transport, self)
1638
def __return_repository_format(self):
1639
"""Circular import protection."""
1640
if getattr(self, '_repository_format', None):
1641
return self._repository_format
1642
from bzrlib.repository import RepositoryFormat
1643
return RepositoryFormat.get_default_format()
1645
def __set_repository_format(self, value):
1646
"""Allow changint the repository format for metadir formats."""
1647
self._repository_format = value
1649
repository_format = property(__return_repository_format, __set_repository_format)
1651
def __get_workingtree_format(self):
1652
if self._workingtree_format is None:
1653
from bzrlib.workingtree import WorkingTreeFormat
1654
self._workingtree_format = WorkingTreeFormat.get_default_format()
1655
return self._workingtree_format
1657
def __set_workingtree_format(self, wt_format):
1658
self._workingtree_format = wt_format
1660
workingtree_format = property(__get_workingtree_format,
1661
__set_workingtree_format)
1664
# Register bzr control format
1665
BzrDirFormat.register_control_format(BzrDirFormat)
1667
# Register bzr formats
1668
BzrDirFormat.register_format(BzrDirFormat4())
1669
BzrDirFormat.register_format(BzrDirFormat5())
1670
BzrDirFormat.register_format(BzrDirFormat6())
1671
__default_format = BzrDirMetaFormat1()
1672
BzrDirFormat.register_format(__default_format)
1673
BzrDirFormat._default_format = __default_format
1676
class BzrDirTestProviderAdapter(object):
1677
"""A tool to generate a suite testing multiple bzrdir formats at once.
1679
This is done by copying the test once for each transport and injecting
1680
the transport_server, transport_readonly_server, and bzrdir_format
1681
classes into each copy. Each copy is also given a new id() to make it
1685
def __init__(self, transport_server, transport_readonly_server, formats):
1686
self._transport_server = transport_server
1687
self._transport_readonly_server = transport_readonly_server
1688
self._formats = formats
1690
def adapt(self, test):
1691
result = unittest.TestSuite()
1692
for format in self._formats:
1693
new_test = deepcopy(test)
1694
new_test.transport_server = self._transport_server
1695
new_test.transport_readonly_server = self._transport_readonly_server
1696
new_test.bzrdir_format = format
1697
def make_new_test_id():
1698
new_id = "%s(%s)" % (new_test.id(), format.__class__.__name__)
1699
return lambda: new_id
1700
new_test.id = make_new_test_id()
1701
result.addTest(new_test)
1705
class Converter(object):
1706
"""Converts a disk format object from one format to another."""
1708
def convert(self, to_convert, pb):
1709
"""Perform the conversion of to_convert, giving feedback via pb.
1711
:param to_convert: The disk object to convert.
1712
:param pb: a progress bar to use for progress information.
1715
def step(self, message):
1716
"""Update the pb by a step."""
1718
self.pb.update(message, self.count, self.total)
1721
class ConvertBzrDir4To5(Converter):
1722
"""Converts format 4 bzr dirs to format 5."""
1725
super(ConvertBzrDir4To5, self).__init__()
1726
self.converted_revs = set()
1727
self.absent_revisions = set()
1731
def convert(self, to_convert, pb):
1732
"""See Converter.convert()."""
1733
self.bzrdir = to_convert
1735
self.pb.note('starting upgrade from format 4 to 5')
1736
if isinstance(self.bzrdir.transport, LocalTransport):
1737
self.bzrdir.get_workingtree_transport(None).delete('stat-cache')
1738
self._convert_to_weaves()
1739
return BzrDir.open(self.bzrdir.root_transport.base)
1741
def _convert_to_weaves(self):
1742
self.pb.note('note: upgrade may be faster if all store files are ungzipped first')
1745
stat = self.bzrdir.transport.stat('weaves')
1746
if not S_ISDIR(stat.st_mode):
1747
self.bzrdir.transport.delete('weaves')
1748
self.bzrdir.transport.mkdir('weaves')
1749
except errors.NoSuchFile:
1750
self.bzrdir.transport.mkdir('weaves')
1751
# deliberately not a WeaveFile as we want to build it up slowly.
1752
self.inv_weave = Weave('inventory')
1753
# holds in-memory weaves for all files
1754
self.text_weaves = {}
1755
self.bzrdir.transport.delete('branch-format')
1756
self.branch = self.bzrdir.open_branch()
1757
self._convert_working_inv()
1758
rev_history = self.branch.revision_history()
1759
# to_read is a stack holding the revisions we still need to process;
1760
# appending to it adds new highest-priority revisions
1761
self.known_revisions = set(rev_history)
1762
self.to_read = rev_history[-1:]
1764
rev_id = self.to_read.pop()
1765
if (rev_id not in self.revisions
1766
and rev_id not in self.absent_revisions):
1767
self._load_one_rev(rev_id)
1769
to_import = self._make_order()
1770
for i, rev_id in enumerate(to_import):
1771
self.pb.update('converting revision', i, len(to_import))
1772
self._convert_one_rev(rev_id)
1774
self._write_all_weaves()
1775
self._write_all_revs()
1776
self.pb.note('upgraded to weaves:')
1777
self.pb.note(' %6d revisions and inventories', len(self.revisions))
1778
self.pb.note(' %6d revisions not present', len(self.absent_revisions))
1779
self.pb.note(' %6d texts', self.text_count)
1780
self._cleanup_spare_files_after_format4()
1781
self.branch.control_files.put_utf8('branch-format', BzrDirFormat5().get_format_string())
1783
def _cleanup_spare_files_after_format4(self):
1784
# FIXME working tree upgrade foo.
1785
for n in 'merged-patches', 'pending-merged-patches':
1787
## assert os.path.getsize(p) == 0
1788
self.bzrdir.transport.delete(n)
1789
except errors.NoSuchFile:
1791
self.bzrdir.transport.delete_tree('inventory-store')
1792
self.bzrdir.transport.delete_tree('text-store')
1794
def _convert_working_inv(self):
1795
inv = xml4.serializer_v4.read_inventory(
1796
self.branch.control_files.get('inventory'))
1797
new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
1798
# FIXME inventory is a working tree change.
1799
self.branch.control_files.put('inventory', StringIO(new_inv_xml))
1801
def _write_all_weaves(self):
1802
controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)
1803
weave_transport = self.bzrdir.transport.clone('weaves')
1804
weaves = WeaveStore(weave_transport, prefixed=False)
1805
transaction = WriteTransaction()
1809
for file_id, file_weave in self.text_weaves.items():
1810
self.pb.update('writing weave', i, len(self.text_weaves))
1811
weaves._put_weave(file_id, file_weave, transaction)
1813
self.pb.update('inventory', 0, 1)
1814
controlweaves._put_weave('inventory', self.inv_weave, transaction)
1815
self.pb.update('inventory', 1, 1)
1819
def _write_all_revs(self):
1820
"""Write all revisions out in new form."""
1821
self.bzrdir.transport.delete_tree('revision-store')
1822
self.bzrdir.transport.mkdir('revision-store')
1823
revision_transport = self.bzrdir.transport.clone('revision-store')
1825
_revision_store = TextRevisionStore(TextStore(revision_transport,
1829
transaction = WriteTransaction()
1830
for i, rev_id in enumerate(self.converted_revs):
1831
self.pb.update('write revision', i, len(self.converted_revs))
1832
_revision_store.add_revision(self.revisions[rev_id], transaction)
1836
def _load_one_rev(self, rev_id):
1837
"""Load a revision object into memory.
1839
Any parents not either loaded or abandoned get queued to be
1841
self.pb.update('loading revision',
1842
len(self.revisions),
1843
len(self.known_revisions))
1844
if not self.branch.repository.has_revision(rev_id):
1846
self.pb.note('revision {%s} not present in branch; '
1847
'will be converted as a ghost',
1849
self.absent_revisions.add(rev_id)
1851
rev = self.branch.repository._revision_store.get_revision(rev_id,
1852
self.branch.repository.get_transaction())
1853
for parent_id in rev.parent_ids:
1854
self.known_revisions.add(parent_id)
1855
self.to_read.append(parent_id)
1856
self.revisions[rev_id] = rev
1858
def _load_old_inventory(self, rev_id):
1859
assert rev_id not in self.converted_revs
1860
old_inv_xml = self.branch.repository.inventory_store.get(rev_id).read()
1861
inv = xml4.serializer_v4.read_inventory_from_string(old_inv_xml)
1862
inv.revision_id = rev_id
1863
rev = self.revisions[rev_id]
1864
if rev.inventory_sha1:
1865
assert rev.inventory_sha1 == sha_string(old_inv_xml), \
1866
'inventory sha mismatch for {%s}' % rev_id
1869
def _load_updated_inventory(self, rev_id):
1870
assert rev_id in self.converted_revs
1871
inv_xml = self.inv_weave.get_text(rev_id)
1872
inv = xml5.serializer_v5.read_inventory_from_string(inv_xml)
1875
def _convert_one_rev(self, rev_id):
1876
"""Convert revision and all referenced objects to new format."""
1877
rev = self.revisions[rev_id]
1878
inv = self._load_old_inventory(rev_id)
1879
present_parents = [p for p in rev.parent_ids
1880
if p not in self.absent_revisions]
1881
self._convert_revision_contents(rev, inv, present_parents)
1882
self._store_new_weave(rev, inv, present_parents)
1883
self.converted_revs.add(rev_id)
1885
def _store_new_weave(self, rev, inv, present_parents):
1886
# the XML is now updated with text versions
1888
entries = inv.iter_entries()
1890
for path, ie in entries:
1891
assert getattr(ie, 'revision', None) is not None, \
1892
'no revision on {%s} in {%s}' % \
1893
(file_id, rev.revision_id)
1894
new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
1895
new_inv_sha1 = sha_string(new_inv_xml)
1896
self.inv_weave.add_lines(rev.revision_id,
1898
new_inv_xml.splitlines(True))
1899
rev.inventory_sha1 = new_inv_sha1
1901
def _convert_revision_contents(self, rev, inv, present_parents):
1902
"""Convert all the files within a revision.
1904
Also upgrade the inventory to refer to the text revision ids."""
1905
rev_id = rev.revision_id
1906
mutter('converting texts of revision {%s}',
1908
parent_invs = map(self._load_updated_inventory, present_parents)
1909
entries = inv.iter_entries()
1911
for path, ie in entries:
1912
self._convert_file_version(rev, ie, parent_invs)
1914
def _convert_file_version(self, rev, ie, parent_invs):
1915
"""Convert one version of one file.
1917
The file needs to be added into the weave if it is a merge
1918
of >=2 parents or if it's changed from its parent.
1920
file_id = ie.file_id
1921
rev_id = rev.revision_id
1922
w = self.text_weaves.get(file_id)
1925
self.text_weaves[file_id] = w
1926
text_changed = False
1927
previous_entries = ie.find_previous_heads(parent_invs,
1931
for old_revision in previous_entries:
1932
# if this fails, its a ghost ?
1933
assert old_revision in self.converted_revs, \
1934
"Revision {%s} not in converted_revs" % old_revision
1935
self.snapshot_ie(previous_entries, ie, w, rev_id)
1937
assert getattr(ie, 'revision', None) is not None
1939
def snapshot_ie(self, previous_revisions, ie, w, rev_id):
1940
# TODO: convert this logic, which is ~= snapshot to
1941
# a call to:. This needs the path figured out. rather than a work_tree
1942
# a v4 revision_tree can be given, or something that looks enough like
1943
# one to give the file content to the entry if it needs it.
1944
# and we need something that looks like a weave store for snapshot to
1946
#ie.snapshot(rev, PATH, previous_revisions, REVISION_TREE, InMemoryWeaveStore(self.text_weaves))
1947
if len(previous_revisions) == 1:
1948
previous_ie = previous_revisions.values()[0]
1949
if ie._unchanged(previous_ie):
1950
ie.revision = previous_ie.revision
1953
text = self.branch.repository.text_store.get(ie.text_id)
1954
file_lines = text.readlines()
1955
assert sha_strings(file_lines) == ie.text_sha1
1956
assert sum(map(len, file_lines)) == ie.text_size
1957
w.add_lines(rev_id, previous_revisions, file_lines)
1958
self.text_count += 1
1960
w.add_lines(rev_id, previous_revisions, [])
1961
ie.revision = rev_id
1963
def _make_order(self):
1964
"""Return a suitable order for importing revisions.
1966
The order must be such that an revision is imported after all
1967
its (present) parents.
1969
todo = set(self.revisions.keys())
1970
done = self.absent_revisions.copy()
1973
# scan through looking for a revision whose parents
1975
for rev_id in sorted(list(todo)):
1976
rev = self.revisions[rev_id]
1977
parent_ids = set(rev.parent_ids)
1978
if parent_ids.issubset(done):
1979
# can take this one now
1980
order.append(rev_id)
1986
class ConvertBzrDir5To6(Converter):
1987
"""Converts format 5 bzr dirs to format 6."""
1989
def convert(self, to_convert, pb):
1990
"""See Converter.convert()."""
1991
self.bzrdir = to_convert
1993
self.pb.note('starting upgrade from format 5 to 6')
1994
self._convert_to_prefixed()
1995
return BzrDir.open(self.bzrdir.root_transport.base)
1997
def _convert_to_prefixed(self):
1998
from bzrlib.store import TransportStore
1999
self.bzrdir.transport.delete('branch-format')
2000
for store_name in ["weaves", "revision-store"]:
2001
self.pb.note("adding prefixes to %s" % store_name)
2002
store_transport = self.bzrdir.transport.clone(store_name)
2003
store = TransportStore(store_transport, prefixed=True)
2004
for urlfilename in store_transport.list_dir('.'):
2005
filename = urlutils.unescape(urlfilename)
2006
if (filename.endswith(".weave") or
2007
filename.endswith(".gz") or
2008
filename.endswith(".sig")):
2009
file_id = os.path.splitext(filename)[0]
2012
prefix_dir = store.hash_prefix(file_id)
2013
# FIXME keep track of the dirs made RBC 20060121
2015
store_transport.move(filename, prefix_dir + '/' + filename)
2016
except errors.NoSuchFile: # catches missing dirs strangely enough
2017
store_transport.mkdir(prefix_dir)
2018
store_transport.move(filename, prefix_dir + '/' + filename)
2019
self.bzrdir._control_files.put_utf8('branch-format', BzrDirFormat6().get_format_string())
2022
class ConvertBzrDir6ToMeta(Converter):
2023
"""Converts format 6 bzr dirs to metadirs."""
2025
def convert(self, to_convert, pb):
2026
"""See Converter.convert()."""
2027
from bzrlib.repofmt.weaverepo import RepositoryFormat7
2028
from bzrlib.branch import BzrBranchFormat5
2029
self.bzrdir = to_convert
2032
self.total = 20 # the steps we know about
2033
self.garbage_inventories = []
2035
self.pb.note('starting upgrade from format 6 to metadir')
2036
self.bzrdir._control_files.put_utf8('branch-format', "Converting to format 6")
2037
# its faster to move specific files around than to open and use the apis...
2038
# first off, nuke ancestry.weave, it was never used.
2040
self.step('Removing ancestry.weave')
2041
self.bzrdir.transport.delete('ancestry.weave')
2042
except errors.NoSuchFile:
2044
# find out whats there
2045
self.step('Finding branch files')
2046
last_revision = self.bzrdir.open_branch().last_revision()
2047
bzrcontents = self.bzrdir.transport.list_dir('.')
2048
for name in bzrcontents:
2049
if name.startswith('basis-inventory.'):
2050
self.garbage_inventories.append(name)
2051
# create new directories for repository, working tree and branch
2052
self.dir_mode = self.bzrdir._control_files._dir_mode
2053
self.file_mode = self.bzrdir._control_files._file_mode
2054
repository_names = [('inventory.weave', True),
2055
('revision-store', True),
2057
self.step('Upgrading repository ')
2058
self.bzrdir.transport.mkdir('repository', mode=self.dir_mode)
2059
self.make_lock('repository')
2060
# we hard code the formats here because we are converting into
2061
# the meta format. The meta format upgrader can take this to a
2062
# future format within each component.
2063
self.put_format('repository', RepositoryFormat7())
2064
for entry in repository_names:
2065
self.move_entry('repository', entry)
2067
self.step('Upgrading branch ')
2068
self.bzrdir.transport.mkdir('branch', mode=self.dir_mode)
2069
self.make_lock('branch')
2070
self.put_format('branch', BzrBranchFormat5())
2071
branch_files = [('revision-history', True),
2072
('branch-name', True),
2074
for entry in branch_files:
2075
self.move_entry('branch', entry)
2077
checkout_files = [('pending-merges', True),
2078
('inventory', True),
2079
('stat-cache', False)]
2080
# If a mandatory checkout file is not present, the branch does not have
2081
# a functional checkout. Do not create a checkout in the converted
2083
for name, mandatory in checkout_files:
2084
if mandatory and name not in bzrcontents:
2085
has_checkout = False
2089
if not has_checkout:
2090
self.pb.note('No working tree.')
2091
# If some checkout files are there, we may as well get rid of them.
2092
for name, mandatory in checkout_files:
2093
if name in bzrcontents:
2094
self.bzrdir.transport.delete(name)
2096
from bzrlib.workingtree import WorkingTreeFormat3
2097
self.step('Upgrading working tree')
2098
self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
2099
self.make_lock('checkout')
2101
'checkout', WorkingTreeFormat3())
2102
self.bzrdir.transport.delete_multi(
2103
self.garbage_inventories, self.pb)
2104
for entry in checkout_files:
2105
self.move_entry('checkout', entry)
2106
if last_revision is not None:
2107
self.bzrdir._control_files.put_utf8(
2108
'checkout/last-revision', last_revision)
2109
self.bzrdir._control_files.put_utf8(
2110
'branch-format', BzrDirMetaFormat1().get_format_string())
2111
return BzrDir.open(self.bzrdir.root_transport.base)
2113
def make_lock(self, name):
2114
"""Make a lock for the new control dir name."""
2115
self.step('Make %s lock' % name)
2116
ld = lockdir.LockDir(self.bzrdir.transport,
2118
file_modebits=self.file_mode,
2119
dir_modebits=self.dir_mode)
2122
def move_entry(self, new_dir, entry):
2123
"""Move then entry name into new_dir."""
2125
mandatory = entry[1]
2126
self.step('Moving %s' % name)
2128
self.bzrdir.transport.move(name, '%s/%s' % (new_dir, name))
2129
except errors.NoSuchFile:
2133
def put_format(self, dirname, format):
2134
self.bzrdir._control_files.put_utf8('%s/format' % dirname, format.get_format_string())
2137
class ConvertMetaToMeta(Converter):
2138
"""Converts the components of metadirs."""
2140
def __init__(self, target_format):
2141
"""Create a metadir to metadir converter.
2143
:param target_format: The final metadir format that is desired.
2145
self.target_format = target_format
2147
def convert(self, to_convert, pb):
2148
"""See Converter.convert()."""
2149
self.bzrdir = to_convert
2153
self.step('checking repository format')
2155
repo = self.bzrdir.open_repository()
2156
except errors.NoRepositoryPresent:
2159
if not isinstance(repo._format, self.target_format.repository_format.__class__):
2160
from bzrlib.repository import CopyConverter
2161
self.pb.note('starting repository conversion')
2162
converter = CopyConverter(self.target_format.repository_format)
2163
converter.convert(repo, pb)
2165
branch = self.bzrdir.open_branch()
2166
except errors.NotBranchError:
2169
# TODO: conversions of Branch and Tree should be done by
2170
# InterXFormat lookups
2171
# Avoid circular imports
2172
from bzrlib import branch as _mod_branch
2173
if (branch._format.__class__ is _mod_branch.BzrBranchFormat5 and
2174
self.target_format.get_branch_format().__class__ is
2175
_mod_branch.BzrBranchFormat6):
2176
branch_converter = _mod_branch.Converter5to6()
2177
branch_converter.convert(branch)
2179
tree = self.bzrdir.open_workingtree(recommend_upgrade=False)
2180
except (errors.NoWorkingTree, errors.NotLocalUrl):
2183
# TODO: conversions of Branch and Tree should be done by
2184
# InterXFormat lookups
2185
if (isinstance(tree, workingtree.WorkingTree3) and
2186
not isinstance(tree, workingtree_4.WorkingTree4) and
2187
isinstance(self.target_format.workingtree_format,
2188
workingtree_4.WorkingTreeFormat4)):
2189
workingtree_4.Converter3to4().convert(tree)
2193
class BzrDirFormatInfo(object):
2195
def __init__(self, native, deprecated, hidden):
2196
self.deprecated = deprecated
2197
self.native = native
2198
self.hidden = hidden
2201
class BzrDirFormatRegistry(registry.Registry):
2202
"""Registry of user-selectable BzrDir subformats.
2204
Differs from BzrDirFormat._control_formats in that it provides sub-formats,
2205
e.g. BzrDirMeta1 with weave repository. Also, it's more user-oriented.
2208
def register_metadir(self, key,
2209
repository_format, help, native=True, deprecated=False,
2213
"""Register a metadir subformat.
2215
These all use a BzrDirMetaFormat1 bzrdir, but can be parameterized
2216
by the Repository format.
2218
:param repository_format: The fully-qualified repository format class
2220
:param branch_format: Fully-qualified branch format class name as
2222
:param tree_format: Fully-qualified tree format class name as
2225
# This should be expanded to support setting WorkingTree and Branch
2226
# formats, once BzrDirMetaFormat1 supports that.
2227
def _load(full_name):
2228
mod_name, factory_name = full_name.rsplit('.', 1)
2230
mod = __import__(mod_name, globals(), locals(),
2232
except ImportError, e:
2233
raise ImportError('failed to load %s: %s' % (full_name, e))
2235
factory = getattr(mod, factory_name)
2236
except AttributeError:
2237
raise AttributeError('no factory %s in module %r'
2242
bd = BzrDirMetaFormat1()
2243
if branch_format is not None:
2244
bd.set_branch_format(_load(branch_format))
2245
if tree_format is not None:
2246
bd.workingtree_format = _load(tree_format)
2247
if repository_format is not None:
2248
bd.repository_format = _load(repository_format)
2250
self.register(key, helper, help, native, deprecated, hidden)
2252
def register(self, key, factory, help, native=True, deprecated=False,
2254
"""Register a BzrDirFormat factory.
2256
The factory must be a callable that takes one parameter: the key.
2257
It must produce an instance of the BzrDirFormat when called.
2259
This function mainly exists to prevent the info object from being
2262
registry.Registry.register(self, key, factory, help,
2263
BzrDirFormatInfo(native, deprecated, hidden))
2265
def register_lazy(self, key, module_name, member_name, help, native=True,
2266
deprecated=False, hidden=False):
2267
registry.Registry.register_lazy(self, key, module_name, member_name,
2268
help, BzrDirFormatInfo(native, deprecated, hidden))
2270
def set_default(self, key):
2271
"""Set the 'default' key to be a clone of the supplied key.
2273
This method must be called once and only once.
2275
registry.Registry.register(self, 'default', self.get(key),
2276
self.get_help(key), info=self.get_info(key))
2278
def set_default_repository(self, key):
2279
"""Set the FormatRegistry default and Repository default.
2281
This is a transitional method while Repository.set_default_format
2284
if 'default' in self:
2285
self.remove('default')
2286
self.set_default(key)
2287
format = self.get('default')()
2288
assert isinstance(format, BzrDirMetaFormat1)
2290
def make_bzrdir(self, key):
2291
return self.get(key)()
2293
def help_topic(self, topic):
2294
output = textwrap.dedent("""\
2295
Bazaar directory formats
2296
------------------------
2298
These formats can be used for creating branches, working trees, and
2302
default_help = self.get_help('default')
2304
for key in self.keys():
2305
if key == 'default':
2307
help = self.get_help(key)
2308
if help == default_help:
2309
default_realkey = key
2311
help_pairs.append((key, help))
2313
def wrapped(key, help, info):
2315
help = '(native) ' + help
2316
return ' %s:\n%s\n\n' % (key,
2317
textwrap.fill(help, initial_indent=' ',
2318
subsequent_indent=' '))
2319
output += wrapped('%s/default' % default_realkey, default_help,
2320
self.get_info('default'))
2321
deprecated_pairs = []
2322
for key, help in help_pairs:
2323
info = self.get_info(key)
2326
elif info.deprecated:
2327
deprecated_pairs.append((key, help))
2329
output += wrapped(key, help, info)
2330
if len(deprecated_pairs) > 0:
2331
output += "Deprecated formats\n------------------\n\n"
2332
for key, help in deprecated_pairs:
2333
info = self.get_info(key)
2334
output += wrapped(key, help, info)
2339
format_registry = BzrDirFormatRegistry()
2340
format_registry.register('weave', BzrDirFormat6,
2341
'Pre-0.8 format. Slower than knit and does not'
2342
' support checkouts or shared repositories.',
2344
format_registry.register_metadir('knit',
2345
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2346
'Format using knits. Recommended for interoperation with bzr <= 0.14.',
2347
branch_format='bzrlib.branch.BzrBranchFormat5',
2348
tree_format='bzrlib.workingtree.WorkingTreeFormat3')
2349
format_registry.register_metadir('metaweave',
2350
'bzrlib.repofmt.weaverepo.RepositoryFormat7',
2351
'Transitional format in 0.8. Slower than knit.',
2352
branch_format='bzrlib.branch.BzrBranchFormat5',
2353
tree_format='bzrlib.workingtree.WorkingTreeFormat3',
2355
format_registry.register_metadir('dirstate',
2356
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2357
help='New in 0.15: Fast local operations. Compatible with bzr 0.8 and '
2358
'above when accessed over the network.',
2359
branch_format='bzrlib.branch.BzrBranchFormat5',
2360
# this uses bzrlib.workingtree.WorkingTreeFormat4 because importing
2361
# directly from workingtree_4 triggers a circular import.
2362
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2364
format_registry.register_metadir('dirstate-tags',
2365
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2366
help='New in 0.15: Fast local operations and improved scaling for '
2367
'network operations. Additionally adds support for tags.'
2368
' Incompatible with bzr < 0.15.',
2369
branch_format='bzrlib.branch.BzrBranchFormat6',
2370
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2372
format_registry.register_metadir('dirstate-with-subtree',
2373
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
2374
help='New in 0.15: Fast local operations and improved scaling for '
2375
'network operations. Additionally adds support for versioning nested '
2376
'bzr branches. Incompatible with bzr < 0.15.',
2377
branch_format='bzrlib.branch.BzrBranchFormat6',
2378
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2381
format_registry.set_default('dirstate')