1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
"""BzrDir logic. The BzrDir is the basic control directory used by bzr.
19
At format 7 this was split out into Branch, Repository and Checkout control
23
# TODO: remove unittest dependency; put that stuff inside the test suite
25
# TODO: Can we move specific formats into separate modules to make this file
28
from cStringIO import StringIO
32
from bzrlib.lazy_import import lazy_import
33
lazy_import(globals(), """
34
from copy import deepcopy
35
from stat import S_ISDIR
45
revision as _mod_revision,
54
from bzrlib.osutils import (
59
from bzrlib.smart.client import _SmartClient
60
from bzrlib.store.revision.text import TextRevisionStore
61
from bzrlib.store.text import TextStore
62
from bzrlib.store.versioned import WeaveStore
63
from bzrlib.transactions import WriteTransaction
64
from bzrlib.transport import (
65
do_catching_redirections,
68
from bzrlib.weave import Weave
71
from bzrlib.trace import (
75
from bzrlib.transport.local import LocalTransport
79
"""A .bzr control diretory.
81
BzrDir instances let you create or open any of the things that can be
82
found within .bzr - checkouts, branches and repositories.
85
the transport which this bzr dir is rooted at (i.e. file:///.../.bzr/)
87
a transport connected to the directory this bzr was opened from.
91
"""Invoke break_lock on the first object in the bzrdir.
93
If there is a tree, the tree is opened and break_lock() called.
94
Otherwise, branch is tried, and finally repository.
96
# XXX: This seems more like a UI function than something that really
97
# belongs in this class.
99
thing_to_unlock = self.open_workingtree()
100
except (errors.NotLocalUrl, errors.NoWorkingTree):
102
thing_to_unlock = self.open_branch()
103
except errors.NotBranchError:
105
thing_to_unlock = self.open_repository()
106
except errors.NoRepositoryPresent:
108
thing_to_unlock.break_lock()
110
def can_convert_format(self):
111
"""Return true if this bzrdir is one whose format we can convert from."""
114
def check_conversion_target(self, target_format):
115
target_repo_format = target_format.repository_format
116
source_repo_format = self._format.repository_format
117
source_repo_format.check_conversion_target(target_repo_format)
120
def _check_supported(format, allow_unsupported,
121
recommend_upgrade=True,
123
"""Give an error or warning on old formats.
125
:param format: may be any kind of format - workingtree, branch,
128
:param allow_unsupported: If true, allow opening
129
formats that are strongly deprecated, and which may
130
have limited functionality.
132
:param recommend_upgrade: If true (default), warn
133
the user through the ui object that they may wish
134
to upgrade the object.
136
# TODO: perhaps move this into a base Format class; it's not BzrDir
137
# specific. mbp 20070323
138
if not allow_unsupported and not format.is_supported():
139
# see open_downlevel to open legacy branches.
140
raise errors.UnsupportedFormatError(format=format)
141
if recommend_upgrade \
142
and getattr(format, 'upgrade_recommended', False):
143
ui.ui_factory.recommend_upgrade(
144
format.get_format_description(),
147
def clone(self, url, revision_id=None, force_new_repo=False):
148
"""Clone this bzrdir and its contents to url verbatim.
150
If urls last component does not exist, it will be created.
152
if revision_id is not None, then the clone operation may tune
153
itself to download less data.
154
:param force_new_repo: Do not use a shared repository for the target
155
even if one is available.
158
result = self._format.initialize(url)
160
local_repo = self.find_repository()
161
except errors.NoRepositoryPresent:
164
# may need to copy content in
166
result_repo = local_repo.clone(
168
revision_id=revision_id)
169
result_repo.set_make_working_trees(local_repo.make_working_trees())
172
result_repo = result.find_repository()
173
# fetch content this dir needs.
174
result_repo.fetch(local_repo, revision_id=revision_id)
175
except errors.NoRepositoryPresent:
176
# needed to make one anyway.
177
result_repo = local_repo.clone(
179
revision_id=revision_id)
180
result_repo.set_make_working_trees(local_repo.make_working_trees())
181
# 1 if there is a branch present
182
# make sure its content is available in the target repository
185
self.open_branch().clone(result, revision_id=revision_id)
186
except errors.NotBranchError:
189
self.open_workingtree().clone(result)
190
except (errors.NoWorkingTree, errors.NotLocalUrl):
194
# TODO: This should be given a Transport, and should chdir up; otherwise
195
# this will open a new connection.
196
def _make_tail(self, url):
197
head, tail = urlutils.split(url)
198
if tail and tail != '.':
199
t = get_transport(head)
202
except errors.FileExists:
205
# TODO: Should take a Transport
207
def create(cls, base, format=None):
208
"""Create a new BzrDir at the url 'base'.
210
This will call the current default formats initialize with base
211
as the only parameter.
213
:param format: If supplied, the format of branch to create. If not
214
supplied, the default is used.
216
if cls is not BzrDir:
217
raise AssertionError("BzrDir.create always creates the default"
218
" format, not one of %r" % cls)
219
head, tail = urlutils.split(base)
220
if tail and tail != '.':
221
t = get_transport(head)
224
except errors.FileExists:
227
format = BzrDirFormat.get_default_format()
228
return format.initialize(safe_unicode(base))
230
def create_branch(self):
231
"""Create a branch in this BzrDir.
233
The bzrdirs format will control what branch format is created.
234
For more control see BranchFormatXX.create(a_bzrdir).
236
raise NotImplementedError(self.create_branch)
239
def create_branch_and_repo(base, force_new_repo=False, format=None):
240
"""Create a new BzrDir, Branch and Repository at the url 'base'.
242
This will use the current default BzrDirFormat, and use whatever
243
repository format that that uses via bzrdir.create_branch and
244
create_repository. If a shared repository is available that is used
247
The created Branch object is returned.
249
:param base: The URL to create the branch at.
250
:param force_new_repo: If True a new repository is always created.
252
bzrdir = BzrDir.create(base, format)
253
bzrdir._find_or_create_repository(force_new_repo)
254
return bzrdir.create_branch()
256
def _find_or_create_repository(self, force_new_repo):
257
"""Create a new repository if needed, returning the repository."""
259
return self.create_repository()
261
return self.find_repository()
262
except errors.NoRepositoryPresent:
263
return self.create_repository()
266
def create_branch_convenience(base, force_new_repo=False,
267
force_new_tree=None, format=None):
268
"""Create a new BzrDir, Branch and Repository at the url 'base'.
270
This is a convenience function - it will use an existing repository
271
if possible, can be told explicitly whether to create a working tree or
274
This will use the current default BzrDirFormat, and use whatever
275
repository format that that uses via bzrdir.create_branch and
276
create_repository. If a shared repository is available that is used
277
preferentially. Whatever repository is used, its tree creation policy
280
The created Branch object is returned.
281
If a working tree cannot be made due to base not being a file:// url,
282
no error is raised unless force_new_tree is True, in which case no
283
data is created on disk and NotLocalUrl is raised.
285
:param base: The URL to create the branch at.
286
:param force_new_repo: If True a new repository is always created.
287
:param force_new_tree: If True or False force creation of a tree or
288
prevent such creation respectively.
289
:param format: Override for the for the bzrdir format to create
292
# check for non local urls
293
t = get_transport(safe_unicode(base))
294
if not isinstance(t, LocalTransport):
295
raise errors.NotLocalUrl(base)
296
bzrdir = BzrDir.create(base, format)
297
repo = bzrdir._find_or_create_repository(force_new_repo)
298
result = bzrdir.create_branch()
299
if force_new_tree or (repo.make_working_trees() and
300
force_new_tree is None):
302
bzrdir.create_workingtree()
303
except errors.NotLocalUrl:
308
def create_repository(base, shared=False, format=None):
309
"""Create a new BzrDir and Repository at the url 'base'.
311
If no format is supplied, this will default to the current default
312
BzrDirFormat by default, and use whatever repository format that that
313
uses for bzrdirformat.create_repository.
315
:param shared: Create a shared repository rather than a standalone
317
The Repository object is returned.
319
This must be overridden as an instance method in child classes, where
320
it should take no parameters and construct whatever repository format
321
that child class desires.
323
bzrdir = BzrDir.create(base, format)
324
return bzrdir.create_repository(shared)
327
def create_standalone_workingtree(base, format=None):
328
"""Create a new BzrDir, WorkingTree, Branch and Repository at 'base'.
330
'base' must be a local path or a file:// url.
332
This will use the current default BzrDirFormat, and use whatever
333
repository format that that uses for bzrdirformat.create_workingtree,
334
create_branch and create_repository.
336
:return: The WorkingTree object.
338
t = get_transport(safe_unicode(base))
339
if not isinstance(t, LocalTransport):
340
raise errors.NotLocalUrl(base)
341
bzrdir = BzrDir.create_branch_and_repo(safe_unicode(base),
343
format=format).bzrdir
344
return bzrdir.create_workingtree()
346
def create_workingtree(self, revision_id=None):
347
"""Create a working tree at this BzrDir.
349
revision_id: create it as of this revision id.
351
raise NotImplementedError(self.create_workingtree)
353
def retire_bzrdir(self):
354
"""Permanently disable the bzrdir.
356
This is done by renaming it to give the user some ability to recover
357
if there was a problem.
359
This will have horrible consequences if anyone has anything locked or
362
for i in xrange(10000):
364
to_path = '.bzr.retired.%d' % i
365
self.root_transport.rename('.bzr', to_path)
366
note("renamed %s to %s"
367
% (self.root_transport.abspath('.bzr'), to_path))
369
except (errors.TransportError, IOError, errors.PathError):
372
def destroy_workingtree(self):
373
"""Destroy the working tree at this BzrDir.
375
Formats that do not support this may raise UnsupportedOperation.
377
raise NotImplementedError(self.destroy_workingtree)
379
def destroy_workingtree_metadata(self):
380
"""Destroy the control files for the working tree at this BzrDir.
382
The contents of working tree files are not affected.
383
Formats that do not support this may raise UnsupportedOperation.
385
raise NotImplementedError(self.destroy_workingtree_metadata)
387
def find_repository(self):
388
"""Find the repository that should be used for a_bzrdir.
390
This does not require a branch as we use it to find the repo for
391
new branches as well as to hook existing branches up to their
395
return self.open_repository()
396
except errors.NoRepositoryPresent:
398
next_transport = self.root_transport.clone('..')
400
# find the next containing bzrdir
402
found_bzrdir = BzrDir.open_containing_from_transport(
404
except errors.NotBranchError:
406
raise errors.NoRepositoryPresent(self)
407
# does it have a repository ?
409
repository = found_bzrdir.open_repository()
410
except errors.NoRepositoryPresent:
411
next_transport = found_bzrdir.root_transport.clone('..')
412
if (found_bzrdir.root_transport.base == next_transport.base):
413
# top of the file system
417
if ((found_bzrdir.root_transport.base ==
418
self.root_transport.base) or repository.is_shared()):
421
raise errors.NoRepositoryPresent(self)
422
raise errors.NoRepositoryPresent(self)
424
def get_branch_reference(self):
425
"""Return the referenced URL for the branch in this bzrdir.
427
:raises NotBranchError: If there is no Branch.
428
:return: The URL the branch in this bzrdir references if it is a
429
reference branch, or None for regular branches.
433
def get_branch_transport(self, branch_format):
434
"""Get the transport for use by branch format in this BzrDir.
436
Note that bzr dirs that do not support format strings will raise
437
IncompatibleFormat if the branch format they are given has
438
a format string, and vice versa.
440
If branch_format is None, the transport is returned with no
441
checking. if it is not None, then the returned transport is
442
guaranteed to point to an existing directory ready for use.
444
raise NotImplementedError(self.get_branch_transport)
446
def get_repository_transport(self, repository_format):
447
"""Get the transport for use by repository format in this BzrDir.
449
Note that bzr dirs that do not support format strings will raise
450
IncompatibleFormat if the repository format they are given has
451
a format string, and vice versa.
453
If repository_format is None, the transport is returned with no
454
checking. if it is not None, then the returned transport is
455
guaranteed to point to an existing directory ready for use.
457
raise NotImplementedError(self.get_repository_transport)
459
def get_workingtree_transport(self, tree_format):
460
"""Get the transport for use by workingtree format in this BzrDir.
462
Note that bzr dirs that do not support format strings will raise
463
IncompatibleFormat if the workingtree format they are given has a
464
format string, and vice versa.
466
If workingtree_format is None, the transport is returned with no
467
checking. if it is not None, then the returned transport is
468
guaranteed to point to an existing directory ready for use.
470
raise NotImplementedError(self.get_workingtree_transport)
472
def __init__(self, _transport, _format):
473
"""Initialize a Bzr control dir object.
475
Only really common logic should reside here, concrete classes should be
476
made with varying behaviours.
478
:param _format: the format that is creating this BzrDir instance.
479
:param _transport: the transport this dir is based at.
481
self._format = _format
482
self.transport = _transport.clone('.bzr')
483
self.root_transport = _transport
485
def is_control_filename(self, filename):
486
"""True if filename is the name of a path which is reserved for bzrdir's.
488
:param filename: A filename within the root transport of this bzrdir.
490
This is true IF and ONLY IF the filename is part of the namespace reserved
491
for bzr control dirs. Currently this is the '.bzr' directory in the root
492
of the root_transport. it is expected that plugins will need to extend
493
this in the future - for instance to make bzr talk with svn working
496
# this might be better on the BzrDirFormat class because it refers to
497
# all the possible bzrdir disk formats.
498
# This method is tested via the workingtree is_control_filename tests-
499
# it was extracted from WorkingTree.is_control_filename. If the methods
500
# contract is extended beyond the current trivial implementation please
501
# add new tests for it to the appropriate place.
502
return filename == '.bzr' or filename.startswith('.bzr/')
504
def needs_format_conversion(self, format=None):
505
"""Return true if this bzrdir needs convert_format run on it.
507
For instance, if the repository format is out of date but the
508
branch and working tree are not, this should return True.
510
:param format: Optional parameter indicating a specific desired
511
format we plan to arrive at.
513
raise NotImplementedError(self.needs_format_conversion)
516
def open_unsupported(base):
517
"""Open a branch which is not supported."""
518
return BzrDir.open(base, _unsupported=True)
521
def open(base, _unsupported=False):
522
"""Open an existing bzrdir, rooted at 'base' (url)
524
_unsupported is a private parameter to the BzrDir class.
526
t = get_transport(base)
527
return BzrDir.open_from_transport(t, _unsupported=_unsupported)
530
def open_from_transport(transport, _unsupported=False,
531
_server_formats=True):
532
"""Open a bzrdir within a particular directory.
534
:param transport: Transport containing the bzrdir.
535
:param _unsupported: private.
537
base = transport.base
539
def find_format(transport):
540
return transport, BzrDirFormat.find_format(
541
transport, _server_formats=_server_formats)
543
def redirected(transport, e, redirection_notice):
544
qualified_source = e.get_source_url()
545
relpath = transport.relpath(qualified_source)
546
if not e.target.endswith(relpath):
547
# Not redirected to a branch-format, not a branch
548
raise errors.NotBranchError(path=e.target)
549
target = e.target[:-len(relpath)]
550
note('%s is%s redirected to %s',
551
transport.base, e.permanently, target)
552
# Let's try with a new transport
553
qualified_target = e.get_target_url()[:-len(relpath)]
554
# FIXME: If 'transport' has a qualifier, this should
555
# be applied again to the new transport *iff* the
556
# schemes used are the same. It's a bit tricky to
557
# verify, so I'll punt for now
559
return get_transport(target)
562
transport, format = do_catching_redirections(find_format,
565
except errors.TooManyRedirections:
566
raise errors.NotBranchError(base)
568
BzrDir._check_supported(format, _unsupported)
569
return format.open(transport, _found=True)
571
def open_branch(self, unsupported=False):
572
"""Open the branch object at this BzrDir if one is present.
574
If unsupported is True, then no longer supported branch formats can
577
TODO: static convenience version of this?
579
raise NotImplementedError(self.open_branch)
582
def open_containing(url):
583
"""Open an existing branch which contains url.
585
:param url: url to search from.
586
See open_containing_from_transport for more detail.
588
return BzrDir.open_containing_from_transport(get_transport(url))
591
def open_containing_from_transport(a_transport):
592
"""Open an existing branch which contains a_transport.base
594
This probes for a branch at a_transport, and searches upwards from there.
596
Basically we keep looking up until we find the control directory or
597
run into the root. If there isn't one, raises NotBranchError.
598
If there is one and it is either an unrecognised format or an unsupported
599
format, UnknownFormatError or UnsupportedFormatError are raised.
600
If there is one, it is returned, along with the unused portion of url.
602
:return: The BzrDir that contains the path, and a Unicode path
603
for the rest of the URL.
605
# this gets the normalised url back. I.e. '.' -> the full path.
606
url = a_transport.base
609
result = BzrDir.open_from_transport(a_transport)
610
return result, urlutils.unescape(a_transport.relpath(url))
611
except errors.NotBranchError, e:
614
new_t = a_transport.clone('..')
615
except errors.InvalidURLJoin:
616
# reached the root, whatever that may be
617
raise errors.NotBranchError(path=url)
618
if new_t.base == a_transport.base:
619
# reached the root, whatever that may be
620
raise errors.NotBranchError(path=url)
624
def open_containing_tree_or_branch(klass, location):
625
"""Return the branch and working tree contained by a location.
627
Returns (tree, branch, relpath).
628
If there is no tree at containing the location, tree will be None.
629
If there is no branch containing the location, an exception will be
631
relpath is the portion of the path that is contained by the branch.
633
bzrdir, relpath = klass.open_containing(location)
635
tree = bzrdir.open_workingtree()
636
except (errors.NoWorkingTree, errors.NotLocalUrl):
638
branch = bzrdir.open_branch()
641
return tree, branch, relpath
643
def open_repository(self, _unsupported=False):
644
"""Open the repository object at this BzrDir if one is present.
646
This will not follow the Branch object pointer - its strictly a direct
647
open facility. Most client code should use open_branch().repository to
650
_unsupported is a private parameter, not part of the api.
651
TODO: static convenience version of this?
653
raise NotImplementedError(self.open_repository)
655
def open_workingtree(self, _unsupported=False,
656
recommend_upgrade=True):
657
"""Open the workingtree object at this BzrDir if one is present.
659
:param recommend_upgrade: Optional keyword parameter, when True (the
660
default), emit through the ui module a recommendation that the user
661
upgrade the working tree when the workingtree being opened is old
662
(but still fully supported).
664
raise NotImplementedError(self.open_workingtree)
666
def has_branch(self):
667
"""Tell if this bzrdir contains a branch.
669
Note: if you're going to open the branch, you should just go ahead
670
and try, and not ask permission first. (This method just opens the
671
branch and discards it, and that's somewhat expensive.)
676
except errors.NotBranchError:
679
def has_workingtree(self):
680
"""Tell if this bzrdir contains a working tree.
682
This will still raise an exception if the bzrdir has a workingtree that
683
is remote & inaccessible.
685
Note: if you're going to open the working tree, you should just go ahead
686
and try, and not ask permission first. (This method just opens the
687
workingtree and discards it, and that's somewhat expensive.)
690
self.open_workingtree(recommend_upgrade=False)
692
except errors.NoWorkingTree:
695
def _cloning_metadir(self):
696
"""Produce a metadir suitable for cloning with"""
697
result_format = self._format.__class__()
700
branch = self.open_branch()
701
source_repository = branch.repository
702
except errors.NotBranchError:
704
source_repository = self.open_repository()
705
except errors.NoRepositoryPresent:
706
source_repository = None
708
# XXX TODO: This isinstance is here because we have not implemented
709
# the fix recommended in bug # 103195 - to delegate this choice the
711
repo_format = source_repository._format
712
if not isinstance(repo_format, remote.RemoteRepositoryFormat):
713
result_format.repository_format = repo_format
715
# TODO: Couldn't we just probe for the format in these cases,
716
# rather than opening the whole tree? It would be a little
717
# faster. mbp 20070401
718
tree = self.open_workingtree(recommend_upgrade=False)
719
except (errors.NoWorkingTree, errors.NotLocalUrl):
720
result_format.workingtree_format = None
722
result_format.workingtree_format = tree._format.__class__()
723
return result_format, source_repository
725
def cloning_metadir(self):
726
"""Produce a metadir suitable for cloning or sprouting with.
728
These operations may produce workingtrees (yes, even though they're
729
"cloning" something that doesn't have a tree, so a viable workingtree
730
format must be selected.
732
format, repository = self._cloning_metadir()
733
if format._workingtree_format is None:
734
if repository is None:
736
tree_format = repository._format._matchingbzrdir.workingtree_format
737
format.workingtree_format = tree_format.__class__()
740
def checkout_metadir(self):
741
return self.cloning_metadir()
743
def sprout(self, url, revision_id=None, force_new_repo=False,
745
"""Create a copy of this bzrdir prepared for use as a new line of
748
If urls last component does not exist, it will be created.
750
Attributes related to the identity of the source branch like
751
branch nickname will be cleaned, a working tree is created
752
whether one existed before or not; and a local branch is always
755
if revision_id is not None, then the clone operation may tune
756
itself to download less data.
759
cloning_format = self.cloning_metadir()
760
result = cloning_format.initialize(url)
762
source_branch = self.open_branch()
763
source_repository = source_branch.repository
764
except errors.NotBranchError:
767
source_repository = self.open_repository()
768
except errors.NoRepositoryPresent:
769
source_repository = None
774
result_repo = result.find_repository()
775
except errors.NoRepositoryPresent:
777
if source_repository is None and result_repo is not None:
779
elif source_repository is None and result_repo is None:
780
# no repo available, make a new one
781
result.create_repository()
782
elif source_repository is not None and result_repo is None:
783
# have source, and want to make a new target repo
784
# we don't clone the repo because that preserves attributes
785
# like is_shared(), and we have not yet implemented a
786
# repository sprout().
787
result_repo = result.create_repository()
788
if result_repo is not None:
789
# fetch needed content into target.
790
if source_repository is not None:
792
# source_repository.copy_content_into(result_repo, revision_id=revision_id)
793
# so we can override the copy method
794
result_repo.fetch(source_repository, revision_id=revision_id)
795
if source_branch is not None:
796
source_branch.sprout(result, revision_id=revision_id)
798
result.create_branch()
799
# TODO: jam 20060426 we probably need a test in here in the
800
# case that the newly sprouted branch is a remote one
801
if result_repo is None or result_repo.make_working_trees():
802
wt = result.create_workingtree()
805
if wt.path2id('') is None:
807
wt.set_root_id(self.open_workingtree.get_root_id())
808
except errors.NoWorkingTree:
814
if recurse == 'down':
816
basis = wt.basis_tree()
818
subtrees = basis.iter_references()
819
recurse_branch = wt.branch
820
elif source_branch is not None:
821
basis = source_branch.basis_tree()
823
subtrees = basis.iter_references()
824
recurse_branch = source_branch
829
for path, file_id in subtrees:
830
target = urlutils.join(url, urlutils.escape(path))
831
sublocation = source_branch.reference_parent(file_id, path)
832
sublocation.bzrdir.sprout(target,
833
basis.get_reference_revision(file_id, path),
834
force_new_repo=force_new_repo, recurse=recurse)
836
if basis is not None:
841
class BzrDirPreSplitOut(BzrDir):
842
"""A common class for the all-in-one formats."""
844
def __init__(self, _transport, _format):
845
"""See BzrDir.__init__."""
846
super(BzrDirPreSplitOut, self).__init__(_transport, _format)
847
assert self._format._lock_class == lockable_files.TransportLock
848
assert self._format._lock_file_name == 'branch-lock'
849
self._control_files = lockable_files.LockableFiles(
850
self.get_branch_transport(None),
851
self._format._lock_file_name,
852
self._format._lock_class)
854
def break_lock(self):
855
"""Pre-splitout bzrdirs do not suffer from stale locks."""
856
raise NotImplementedError(self.break_lock)
858
def clone(self, url, revision_id=None, force_new_repo=False):
859
"""See BzrDir.clone()."""
860
from bzrlib.workingtree import WorkingTreeFormat2
862
result = self._format._initialize_for_clone(url)
863
self.open_repository().clone(result, revision_id=revision_id)
864
from_branch = self.open_branch()
865
from_branch.clone(result, revision_id=revision_id)
867
self.open_workingtree().clone(result)
868
except errors.NotLocalUrl:
869
# make a new one, this format always has to have one.
871
WorkingTreeFormat2().initialize(result)
872
except errors.NotLocalUrl:
873
# but we cannot do it for remote trees.
874
to_branch = result.open_branch()
875
WorkingTreeFormat2().stub_initialize_remote(to_branch.control_files)
878
def create_branch(self):
879
"""See BzrDir.create_branch."""
880
return self.open_branch()
882
def create_repository(self, shared=False):
883
"""See BzrDir.create_repository."""
885
raise errors.IncompatibleFormat('shared repository', self._format)
886
return self.open_repository()
888
def create_workingtree(self, revision_id=None):
889
"""See BzrDir.create_workingtree."""
890
# this looks buggy but is not -really-
891
# because this format creates the workingtree when the bzrdir is
893
# clone and sprout will have set the revision_id
894
# and that will have set it for us, its only
895
# specific uses of create_workingtree in isolation
896
# that can do wonky stuff here, and that only
897
# happens for creating checkouts, which cannot be
898
# done on this format anyway. So - acceptable wart.
899
result = self.open_workingtree(recommend_upgrade=False)
900
if revision_id is not None:
901
if revision_id == _mod_revision.NULL_REVISION:
902
result.set_parent_ids([])
904
result.set_parent_ids([revision_id])
907
def destroy_workingtree(self):
908
"""See BzrDir.destroy_workingtree."""
909
raise errors.UnsupportedOperation(self.destroy_workingtree, self)
911
def destroy_workingtree_metadata(self):
912
"""See BzrDir.destroy_workingtree_metadata."""
913
raise errors.UnsupportedOperation(self.destroy_workingtree_metadata,
916
def get_branch_transport(self, branch_format):
917
"""See BzrDir.get_branch_transport()."""
918
if branch_format is None:
919
return self.transport
921
branch_format.get_format_string()
922
except NotImplementedError:
923
return self.transport
924
raise errors.IncompatibleFormat(branch_format, self._format)
926
def get_repository_transport(self, repository_format):
927
"""See BzrDir.get_repository_transport()."""
928
if repository_format is None:
929
return self.transport
931
repository_format.get_format_string()
932
except NotImplementedError:
933
return self.transport
934
raise errors.IncompatibleFormat(repository_format, self._format)
936
def get_workingtree_transport(self, workingtree_format):
937
"""See BzrDir.get_workingtree_transport()."""
938
if workingtree_format is None:
939
return self.transport
941
workingtree_format.get_format_string()
942
except NotImplementedError:
943
return self.transport
944
raise errors.IncompatibleFormat(workingtree_format, self._format)
946
def needs_format_conversion(self, format=None):
947
"""See BzrDir.needs_format_conversion()."""
948
# if the format is not the same as the system default,
949
# an upgrade is needed.
951
format = BzrDirFormat.get_default_format()
952
return not isinstance(self._format, format.__class__)
954
def open_branch(self, unsupported=False):
955
"""See BzrDir.open_branch."""
956
from bzrlib.branch import BzrBranchFormat4
957
format = BzrBranchFormat4()
958
self._check_supported(format, unsupported)
959
return format.open(self, _found=True)
961
def sprout(self, url, revision_id=None, force_new_repo=False):
962
"""See BzrDir.sprout()."""
963
from bzrlib.workingtree import WorkingTreeFormat2
965
result = self._format._initialize_for_clone(url)
967
self.open_repository().clone(result, revision_id=revision_id)
968
except errors.NoRepositoryPresent:
971
self.open_branch().sprout(result, revision_id=revision_id)
972
except errors.NotBranchError:
974
# we always want a working tree
975
WorkingTreeFormat2().initialize(result)
979
class BzrDir4(BzrDirPreSplitOut):
980
"""A .bzr version 4 control object.
982
This is a deprecated format and may be removed after sept 2006.
985
def create_repository(self, shared=False):
986
"""See BzrDir.create_repository."""
987
return self._format.repository_format.initialize(self, shared)
989
def needs_format_conversion(self, format=None):
990
"""Format 4 dirs are always in need of conversion."""
993
def open_repository(self):
994
"""See BzrDir.open_repository."""
995
from bzrlib.repofmt.weaverepo import RepositoryFormat4
996
return RepositoryFormat4().open(self, _found=True)
999
class BzrDir5(BzrDirPreSplitOut):
1000
"""A .bzr version 5 control object.
1002
This is a deprecated format and may be removed after sept 2006.
1005
def open_repository(self):
1006
"""See BzrDir.open_repository."""
1007
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1008
return RepositoryFormat5().open(self, _found=True)
1010
def open_workingtree(self, _unsupported=False,
1011
recommend_upgrade=True):
1012
"""See BzrDir.create_workingtree."""
1013
from bzrlib.workingtree import WorkingTreeFormat2
1014
wt_format = WorkingTreeFormat2()
1015
# we don't warn here about upgrades; that ought to be handled for the
1017
return wt_format.open(self, _found=True)
1020
class BzrDir6(BzrDirPreSplitOut):
1021
"""A .bzr version 6 control object.
1023
This is a deprecated format and may be removed after sept 2006.
1026
def open_repository(self):
1027
"""See BzrDir.open_repository."""
1028
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1029
return RepositoryFormat6().open(self, _found=True)
1031
def open_workingtree(self, _unsupported=False,
1032
recommend_upgrade=True):
1033
"""See BzrDir.create_workingtree."""
1034
# we don't warn here about upgrades; that ought to be handled for the
1036
from bzrlib.workingtree import WorkingTreeFormat2
1037
return WorkingTreeFormat2().open(self, _found=True)
1040
class BzrDirMeta1(BzrDir):
1041
"""A .bzr meta version 1 control object.
1043
This is the first control object where the
1044
individual aspects are really split out: there are separate repository,
1045
workingtree and branch subdirectories and any subset of the three can be
1046
present within a BzrDir.
1049
def can_convert_format(self):
1050
"""See BzrDir.can_convert_format()."""
1053
def create_branch(self):
1054
"""See BzrDir.create_branch."""
1055
return self._format.get_branch_format().initialize(self)
1057
def create_repository(self, shared=False):
1058
"""See BzrDir.create_repository."""
1059
return self._format.repository_format.initialize(self, shared)
1061
def create_workingtree(self, revision_id=None):
1062
"""See BzrDir.create_workingtree."""
1063
from bzrlib.workingtree import WorkingTreeFormat
1064
return self._format.workingtree_format.initialize(self, revision_id)
1066
def destroy_workingtree(self):
1067
"""See BzrDir.destroy_workingtree."""
1068
wt = self.open_workingtree(recommend_upgrade=False)
1069
repository = wt.branch.repository
1070
empty = repository.revision_tree(_mod_revision.NULL_REVISION)
1071
wt.revert([], old_tree=empty)
1072
self.destroy_workingtree_metadata()
1074
def destroy_workingtree_metadata(self):
1075
self.transport.delete_tree('checkout')
1077
def find_branch_format(self):
1078
"""Find the branch 'format' for this bzrdir.
1080
This might be a synthetic object for e.g. RemoteBranch and SVN.
1082
from bzrlib.branch import BranchFormat
1083
return BranchFormat.find_format(self)
1085
def _get_mkdir_mode(self):
1086
"""Figure out the mode to use when creating a bzrdir subdir."""
1087
temp_control = lockable_files.LockableFiles(self.transport, '',
1088
lockable_files.TransportLock)
1089
return temp_control._dir_mode
1091
def get_branch_reference(self):
1092
"""See BzrDir.get_branch_reference()."""
1093
from bzrlib.branch import BranchFormat
1094
format = BranchFormat.find_format(self)
1095
return format.get_reference(self)
1097
def get_branch_transport(self, branch_format):
1098
"""See BzrDir.get_branch_transport()."""
1099
if branch_format is None:
1100
return self.transport.clone('branch')
1102
branch_format.get_format_string()
1103
except NotImplementedError:
1104
raise errors.IncompatibleFormat(branch_format, self._format)
1106
self.transport.mkdir('branch', mode=self._get_mkdir_mode())
1107
except errors.FileExists:
1109
return self.transport.clone('branch')
1111
def get_repository_transport(self, repository_format):
1112
"""See BzrDir.get_repository_transport()."""
1113
if repository_format is None:
1114
return self.transport.clone('repository')
1116
repository_format.get_format_string()
1117
except NotImplementedError:
1118
raise errors.IncompatibleFormat(repository_format, self._format)
1120
self.transport.mkdir('repository', mode=self._get_mkdir_mode())
1121
except errors.FileExists:
1123
return self.transport.clone('repository')
1125
def get_workingtree_transport(self, workingtree_format):
1126
"""See BzrDir.get_workingtree_transport()."""
1127
if workingtree_format is None:
1128
return self.transport.clone('checkout')
1130
workingtree_format.get_format_string()
1131
except NotImplementedError:
1132
raise errors.IncompatibleFormat(workingtree_format, self._format)
1134
self.transport.mkdir('checkout', mode=self._get_mkdir_mode())
1135
except errors.FileExists:
1137
return self.transport.clone('checkout')
1139
def needs_format_conversion(self, format=None):
1140
"""See BzrDir.needs_format_conversion()."""
1142
format = BzrDirFormat.get_default_format()
1143
if not isinstance(self._format, format.__class__):
1144
# it is not a meta dir format, conversion is needed.
1146
# we might want to push this down to the repository?
1148
if not isinstance(self.open_repository()._format,
1149
format.repository_format.__class__):
1150
# the repository needs an upgrade.
1152
except errors.NoRepositoryPresent:
1155
if not isinstance(self.open_branch()._format,
1156
format.get_branch_format().__class__):
1157
# the branch needs an upgrade.
1159
except errors.NotBranchError:
1162
my_wt = self.open_workingtree(recommend_upgrade=False)
1163
if not isinstance(my_wt._format,
1164
format.workingtree_format.__class__):
1165
# the workingtree needs an upgrade.
1167
except (errors.NoWorkingTree, errors.NotLocalUrl):
1171
def open_branch(self, unsupported=False):
1172
"""See BzrDir.open_branch."""
1173
format = self.find_branch_format()
1174
self._check_supported(format, unsupported)
1175
return format.open(self, _found=True)
1177
def open_repository(self, unsupported=False):
1178
"""See BzrDir.open_repository."""
1179
from bzrlib.repository import RepositoryFormat
1180
format = RepositoryFormat.find_format(self)
1181
self._check_supported(format, unsupported)
1182
return format.open(self, _found=True)
1184
def open_workingtree(self, unsupported=False,
1185
recommend_upgrade=True):
1186
"""See BzrDir.open_workingtree."""
1187
from bzrlib.workingtree import WorkingTreeFormat
1188
format = WorkingTreeFormat.find_format(self)
1189
self._check_supported(format, unsupported,
1191
basedir=self.root_transport.base)
1192
return format.open(self, _found=True)
1195
class BzrDirFormat(object):
1196
"""An encapsulation of the initialization and open routines for a format.
1198
Formats provide three things:
1199
* An initialization routine,
1203
Formats are placed in an dict by their format string for reference
1204
during bzrdir opening. These should be subclasses of BzrDirFormat
1207
Once a format is deprecated, just deprecate the initialize and open
1208
methods on the format class. Do not deprecate the object, as the
1209
object will be created every system load.
1212
_default_format = None
1213
"""The default format used for new .bzr dirs."""
1216
"""The known formats."""
1218
_control_formats = []
1219
"""The registered control formats - .bzr, ....
1221
This is a list of BzrDirFormat objects.
1224
_control_server_formats = []
1225
"""The registered control server formats, e.g. RemoteBzrDirs.
1227
This is a list of BzrDirFormat objects.
1230
_lock_file_name = 'branch-lock'
1232
# _lock_class must be set in subclasses to the lock type, typ.
1233
# TransportLock or LockDir
1236
def find_format(klass, transport, _server_formats=True):
1237
"""Return the format present at transport."""
1239
formats = klass._control_server_formats + klass._control_formats
1241
formats = klass._control_formats
1242
for format in formats:
1244
return format.probe_transport(transport)
1245
except errors.NotBranchError:
1246
# this format does not find a control dir here.
1248
raise errors.NotBranchError(path=transport.base)
1251
def probe_transport(klass, transport):
1252
"""Return the .bzrdir style format present in a directory."""
1254
format_string = transport.get(".bzr/branch-format").read()
1255
except errors.NoSuchFile:
1256
raise errors.NotBranchError(path=transport.base)
1259
return klass._formats[format_string]
1261
raise errors.UnknownFormatError(format=format_string)
1264
def get_default_format(klass):
1265
"""Return the current default format."""
1266
return klass._default_format
1268
def get_format_string(self):
1269
"""Return the ASCII format string that identifies this format."""
1270
raise NotImplementedError(self.get_format_string)
1272
def get_format_description(self):
1273
"""Return the short description for this format."""
1274
raise NotImplementedError(self.get_format_description)
1276
def get_converter(self, format=None):
1277
"""Return the converter to use to convert bzrdirs needing converts.
1279
This returns a bzrlib.bzrdir.Converter object.
1281
This should return the best upgrader to step this format towards the
1282
current default format. In the case of plugins we can/should provide
1283
some means for them to extend the range of returnable converters.
1285
:param format: Optional format to override the default format of the
1288
raise NotImplementedError(self.get_converter)
1290
def initialize(self, url):
1291
"""Create a bzr control dir at this url and return an opened copy.
1293
Subclasses should typically override initialize_on_transport
1294
instead of this method.
1296
return self.initialize_on_transport(get_transport(url))
1298
def initialize_on_transport(self, transport):
1299
"""Initialize a new bzrdir in the base directory of a Transport."""
1300
# Since we don't have a .bzr directory, inherit the
1301
# mode from the root directory
1302
temp_control = lockable_files.LockableFiles(transport,
1303
'', lockable_files.TransportLock)
1304
temp_control._transport.mkdir('.bzr',
1305
# FIXME: RBC 20060121 don't peek under
1307
mode=temp_control._dir_mode)
1308
file_mode = temp_control._file_mode
1310
mutter('created control directory in ' + transport.base)
1311
control = transport.clone('.bzr')
1312
utf8_files = [('README',
1313
"This is a Bazaar-NG control directory.\n"
1314
"Do not change any files in this directory.\n"),
1315
('branch-format', self.get_format_string()),
1317
# NB: no need to escape relative paths that are url safe.
1318
control_files = lockable_files.LockableFiles(control,
1319
self._lock_file_name, self._lock_class)
1320
control_files.create_lock()
1321
control_files.lock_write()
1323
for file, content in utf8_files:
1324
control_files.put_utf8(file, content)
1326
control_files.unlock()
1327
return self.open(transport, _found=True)
1329
def is_supported(self):
1330
"""Is this format supported?
1332
Supported formats must be initializable and openable.
1333
Unsupported formats may not support initialization or committing or
1334
some other features depending on the reason for not being supported.
1338
def same_model(self, target_format):
1339
return (self.repository_format.rich_root_data ==
1340
target_format.rich_root_data)
1343
def known_formats(klass):
1344
"""Return all the known formats.
1346
Concrete formats should override _known_formats.
1348
# There is double indirection here to make sure that control
1349
# formats used by more than one dir format will only be probed
1350
# once. This can otherwise be quite expensive for remote connections.
1352
for format in klass._control_formats:
1353
result.update(format._known_formats())
1357
def _known_formats(klass):
1358
"""Return the known format instances for this control format."""
1359
return set(klass._formats.values())
1361
def open(self, transport, _found=False):
1362
"""Return an instance of this format for the dir transport points at.
1364
_found is a private parameter, do not use it.
1367
found_format = BzrDirFormat.find_format(transport)
1368
if not isinstance(found_format, self.__class__):
1369
raise AssertionError("%s was asked to open %s, but it seems to need "
1371
% (self, transport, found_format))
1372
return self._open(transport)
1374
def _open(self, transport):
1375
"""Template method helper for opening BzrDirectories.
1377
This performs the actual open and any additional logic or parameter
1380
raise NotImplementedError(self._open)
1383
def register_format(klass, format):
1384
klass._formats[format.get_format_string()] = format
1387
def register_control_format(klass, format):
1388
"""Register a format that does not use '.bzr' for its control dir.
1390
TODO: This should be pulled up into a 'ControlDirFormat' base class
1391
which BzrDirFormat can inherit from, and renamed to register_format
1392
there. It has been done without that for now for simplicity of
1395
klass._control_formats.append(format)
1398
def register_control_server_format(klass, format):
1399
"""Register a control format for client-server environments.
1401
These formats will be tried before ones registered with
1402
register_control_format. This gives implementations that decide to the
1403
chance to grab it before anything looks at the contents of the format
1406
klass._control_server_formats.append(format)
1409
@symbol_versioning.deprecated_method(symbol_versioning.zero_fourteen)
1410
def set_default_format(klass, format):
1411
klass._set_default_format(format)
1414
def _set_default_format(klass, format):
1415
"""Set default format (for testing behavior of defaults only)"""
1416
klass._default_format = format
1419
return self.get_format_string()[:-1]
1422
def unregister_format(klass, format):
1423
assert klass._formats[format.get_format_string()] is format
1424
del klass._formats[format.get_format_string()]
1427
def unregister_control_format(klass, format):
1428
klass._control_formats.remove(format)
1431
class BzrDirFormat4(BzrDirFormat):
1432
"""Bzr dir format 4.
1434
This format is a combined format for working tree, branch and repository.
1436
- Format 1 working trees [always]
1437
- Format 4 branches [always]
1438
- Format 4 repositories [always]
1440
This format is deprecated: it indexes texts using a text it which is
1441
removed in format 5; write support for this format has been removed.
1444
_lock_class = lockable_files.TransportLock
1446
def get_format_string(self):
1447
"""See BzrDirFormat.get_format_string()."""
1448
return "Bazaar-NG branch, format 0.0.4\n"
1450
def get_format_description(self):
1451
"""See BzrDirFormat.get_format_description()."""
1452
return "All-in-one format 4"
1454
def get_converter(self, format=None):
1455
"""See BzrDirFormat.get_converter()."""
1456
# there is one and only one upgrade path here.
1457
return ConvertBzrDir4To5()
1459
def initialize_on_transport(self, transport):
1460
"""Format 4 branches cannot be created."""
1461
raise errors.UninitializableFormat(self)
1463
def is_supported(self):
1464
"""Format 4 is not supported.
1466
It is not supported because the model changed from 4 to 5 and the
1467
conversion logic is expensive - so doing it on the fly was not
1472
def _open(self, transport):
1473
"""See BzrDirFormat._open."""
1474
return BzrDir4(transport, self)
1476
def __return_repository_format(self):
1477
"""Circular import protection."""
1478
from bzrlib.repofmt.weaverepo import RepositoryFormat4
1479
return RepositoryFormat4()
1480
repository_format = property(__return_repository_format)
1483
class BzrDirFormat5(BzrDirFormat):
1484
"""Bzr control format 5.
1486
This format is a combined format for working tree, branch and repository.
1488
- Format 2 working trees [always]
1489
- Format 4 branches [always]
1490
- Format 5 repositories [always]
1491
Unhashed stores in the repository.
1494
_lock_class = lockable_files.TransportLock
1496
def get_format_string(self):
1497
"""See BzrDirFormat.get_format_string()."""
1498
return "Bazaar-NG branch, format 5\n"
1500
def get_format_description(self):
1501
"""See BzrDirFormat.get_format_description()."""
1502
return "All-in-one format 5"
1504
def get_converter(self, format=None):
1505
"""See BzrDirFormat.get_converter()."""
1506
# there is one and only one upgrade path here.
1507
return ConvertBzrDir5To6()
1509
def _initialize_for_clone(self, url):
1510
return self.initialize_on_transport(get_transport(url), _cloning=True)
1512
def initialize_on_transport(self, transport, _cloning=False):
1513
"""Format 5 dirs always have working tree, branch and repository.
1515
Except when they are being cloned.
1517
from bzrlib.branch import BzrBranchFormat4
1518
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1519
from bzrlib.workingtree import WorkingTreeFormat2
1520
result = (super(BzrDirFormat5, self).initialize_on_transport(transport))
1521
RepositoryFormat5().initialize(result, _internal=True)
1523
branch = BzrBranchFormat4().initialize(result)
1525
WorkingTreeFormat2().initialize(result)
1526
except errors.NotLocalUrl:
1527
# Even though we can't access the working tree, we need to
1528
# create its control files.
1529
WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
1532
def _open(self, transport):
1533
"""See BzrDirFormat._open."""
1534
return BzrDir5(transport, self)
1536
def __return_repository_format(self):
1537
"""Circular import protection."""
1538
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1539
return RepositoryFormat5()
1540
repository_format = property(__return_repository_format)
1543
class BzrDirFormat6(BzrDirFormat):
1544
"""Bzr control format 6.
1546
This format is a combined format for working tree, branch and repository.
1548
- Format 2 working trees [always]
1549
- Format 4 branches [always]
1550
- Format 6 repositories [always]
1553
_lock_class = lockable_files.TransportLock
1555
def get_format_string(self):
1556
"""See BzrDirFormat.get_format_string()."""
1557
return "Bazaar-NG branch, format 6\n"
1559
def get_format_description(self):
1560
"""See BzrDirFormat.get_format_description()."""
1561
return "All-in-one format 6"
1563
def get_converter(self, format=None):
1564
"""See BzrDirFormat.get_converter()."""
1565
# there is one and only one upgrade path here.
1566
return ConvertBzrDir6ToMeta()
1568
def _initialize_for_clone(self, url):
1569
return self.initialize_on_transport(get_transport(url), _cloning=True)
1571
def initialize_on_transport(self, transport, _cloning=False):
1572
"""Format 6 dirs always have working tree, branch and repository.
1574
Except when they are being cloned.
1576
from bzrlib.branch import BzrBranchFormat4
1577
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1578
from bzrlib.workingtree import WorkingTreeFormat2
1579
result = super(BzrDirFormat6, self).initialize_on_transport(transport)
1580
RepositoryFormat6().initialize(result, _internal=True)
1582
branch = BzrBranchFormat4().initialize(result)
1584
WorkingTreeFormat2().initialize(result)
1585
except errors.NotLocalUrl:
1586
# Even though we can't access the working tree, we need to
1587
# create its control files.
1588
WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
1591
def _open(self, transport):
1592
"""See BzrDirFormat._open."""
1593
return BzrDir6(transport, self)
1595
def __return_repository_format(self):
1596
"""Circular import protection."""
1597
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1598
return RepositoryFormat6()
1599
repository_format = property(__return_repository_format)
1602
class BzrDirMetaFormat1(BzrDirFormat):
1603
"""Bzr meta control format 1
1605
This is the first format with split out working tree, branch and repository
1608
- Format 3 working trees [optional]
1609
- Format 5 branches [optional]
1610
- Format 7 repositories [optional]
1613
_lock_class = lockdir.LockDir
1616
self._workingtree_format = None
1617
self._branch_format = None
1619
def __eq__(self, other):
1620
if other.__class__ is not self.__class__:
1622
if other.repository_format != self.repository_format:
1624
if other.workingtree_format != self.workingtree_format:
1628
def __ne__(self, other):
1629
return not self == other
1631
def get_branch_format(self):
1632
if self._branch_format is None:
1633
from bzrlib.branch import BranchFormat
1634
self._branch_format = BranchFormat.get_default_format()
1635
return self._branch_format
1637
def set_branch_format(self, format):
1638
self._branch_format = format
1640
def get_converter(self, format=None):
1641
"""See BzrDirFormat.get_converter()."""
1643
format = BzrDirFormat.get_default_format()
1644
if not isinstance(self, format.__class__):
1645
# converting away from metadir is not implemented
1646
raise NotImplementedError(self.get_converter)
1647
return ConvertMetaToMeta(format)
1649
def get_format_string(self):
1650
"""See BzrDirFormat.get_format_string()."""
1651
return "Bazaar-NG meta directory, format 1\n"
1653
def get_format_description(self):
1654
"""See BzrDirFormat.get_format_description()."""
1655
return "Meta directory format 1"
1657
def _open(self, transport):
1658
"""See BzrDirFormat._open."""
1659
return BzrDirMeta1(transport, self)
1661
def __return_repository_format(self):
1662
"""Circular import protection."""
1663
if getattr(self, '_repository_format', None):
1664
return self._repository_format
1665
from bzrlib.repository import RepositoryFormat
1666
return RepositoryFormat.get_default_format()
1668
def __set_repository_format(self, value):
1669
"""Allow changint the repository format for metadir formats."""
1670
self._repository_format = value
1672
repository_format = property(__return_repository_format, __set_repository_format)
1674
def __get_workingtree_format(self):
1675
if self._workingtree_format is None:
1676
from bzrlib.workingtree import WorkingTreeFormat
1677
self._workingtree_format = WorkingTreeFormat.get_default_format()
1678
return self._workingtree_format
1680
def __set_workingtree_format(self, wt_format):
1681
self._workingtree_format = wt_format
1683
workingtree_format = property(__get_workingtree_format,
1684
__set_workingtree_format)
1687
# Register bzr control format
1688
BzrDirFormat.register_control_format(BzrDirFormat)
1690
# Register bzr formats
1691
BzrDirFormat.register_format(BzrDirFormat4())
1692
BzrDirFormat.register_format(BzrDirFormat5())
1693
BzrDirFormat.register_format(BzrDirFormat6())
1694
__default_format = BzrDirMetaFormat1()
1695
BzrDirFormat.register_format(__default_format)
1696
BzrDirFormat._default_format = __default_format
1699
class BzrDirTestProviderAdapter(object):
1700
"""A tool to generate a suite testing multiple bzrdir formats at once.
1702
This is done by copying the test once for each transport and injecting
1703
the transport_server, transport_readonly_server, and bzrdir_format
1704
classes into each copy. Each copy is also given a new id() to make it
1708
def __init__(self, vfs_factory, transport_server, transport_readonly_server,
1710
"""Create an object to adapt tests.
1712
:param vfs_server: A factory to create a Transport Server which has
1713
all the VFS methods working, and is writable.
1715
self._vfs_factory = vfs_factory
1716
self._transport_server = transport_server
1717
self._transport_readonly_server = transport_readonly_server
1718
self._formats = formats
1720
def adapt(self, test):
1721
result = unittest.TestSuite()
1722
for format in self._formats:
1723
new_test = deepcopy(test)
1724
new_test.vfs_transport_factory = self._vfs_factory
1725
new_test.transport_server = self._transport_server
1726
new_test.transport_readonly_server = self._transport_readonly_server
1727
new_test.bzrdir_format = format
1728
def make_new_test_id():
1729
new_id = "%s(%s)" % (new_test.id(), format.__class__.__name__)
1730
return lambda: new_id
1731
new_test.id = make_new_test_id()
1732
result.addTest(new_test)
1736
class Converter(object):
1737
"""Converts a disk format object from one format to another."""
1739
def convert(self, to_convert, pb):
1740
"""Perform the conversion of to_convert, giving feedback via pb.
1742
:param to_convert: The disk object to convert.
1743
:param pb: a progress bar to use for progress information.
1746
def step(self, message):
1747
"""Update the pb by a step."""
1749
self.pb.update(message, self.count, self.total)
1752
class ConvertBzrDir4To5(Converter):
1753
"""Converts format 4 bzr dirs to format 5."""
1756
super(ConvertBzrDir4To5, self).__init__()
1757
self.converted_revs = set()
1758
self.absent_revisions = set()
1762
def convert(self, to_convert, pb):
1763
"""See Converter.convert()."""
1764
self.bzrdir = to_convert
1766
self.pb.note('starting upgrade from format 4 to 5')
1767
if isinstance(self.bzrdir.transport, LocalTransport):
1768
self.bzrdir.get_workingtree_transport(None).delete('stat-cache')
1769
self._convert_to_weaves()
1770
return BzrDir.open(self.bzrdir.root_transport.base)
1772
def _convert_to_weaves(self):
1773
self.pb.note('note: upgrade may be faster if all store files are ungzipped first')
1776
stat = self.bzrdir.transport.stat('weaves')
1777
if not S_ISDIR(stat.st_mode):
1778
self.bzrdir.transport.delete('weaves')
1779
self.bzrdir.transport.mkdir('weaves')
1780
except errors.NoSuchFile:
1781
self.bzrdir.transport.mkdir('weaves')
1782
# deliberately not a WeaveFile as we want to build it up slowly.
1783
self.inv_weave = Weave('inventory')
1784
# holds in-memory weaves for all files
1785
self.text_weaves = {}
1786
self.bzrdir.transport.delete('branch-format')
1787
self.branch = self.bzrdir.open_branch()
1788
self._convert_working_inv()
1789
rev_history = self.branch.revision_history()
1790
# to_read is a stack holding the revisions we still need to process;
1791
# appending to it adds new highest-priority revisions
1792
self.known_revisions = set(rev_history)
1793
self.to_read = rev_history[-1:]
1795
rev_id = self.to_read.pop()
1796
if (rev_id not in self.revisions
1797
and rev_id not in self.absent_revisions):
1798
self._load_one_rev(rev_id)
1800
to_import = self._make_order()
1801
for i, rev_id in enumerate(to_import):
1802
self.pb.update('converting revision', i, len(to_import))
1803
self._convert_one_rev(rev_id)
1805
self._write_all_weaves()
1806
self._write_all_revs()
1807
self.pb.note('upgraded to weaves:')
1808
self.pb.note(' %6d revisions and inventories', len(self.revisions))
1809
self.pb.note(' %6d revisions not present', len(self.absent_revisions))
1810
self.pb.note(' %6d texts', self.text_count)
1811
self._cleanup_spare_files_after_format4()
1812
self.branch.control_files.put_utf8('branch-format', BzrDirFormat5().get_format_string())
1814
def _cleanup_spare_files_after_format4(self):
1815
# FIXME working tree upgrade foo.
1816
for n in 'merged-patches', 'pending-merged-patches':
1818
## assert os.path.getsize(p) == 0
1819
self.bzrdir.transport.delete(n)
1820
except errors.NoSuchFile:
1822
self.bzrdir.transport.delete_tree('inventory-store')
1823
self.bzrdir.transport.delete_tree('text-store')
1825
def _convert_working_inv(self):
1826
inv = xml4.serializer_v4.read_inventory(
1827
self.branch.control_files.get('inventory'))
1828
new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
1829
# FIXME inventory is a working tree change.
1830
self.branch.control_files.put('inventory', StringIO(new_inv_xml))
1832
def _write_all_weaves(self):
1833
controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)
1834
weave_transport = self.bzrdir.transport.clone('weaves')
1835
weaves = WeaveStore(weave_transport, prefixed=False)
1836
transaction = WriteTransaction()
1840
for file_id, file_weave in self.text_weaves.items():
1841
self.pb.update('writing weave', i, len(self.text_weaves))
1842
weaves._put_weave(file_id, file_weave, transaction)
1844
self.pb.update('inventory', 0, 1)
1845
controlweaves._put_weave('inventory', self.inv_weave, transaction)
1846
self.pb.update('inventory', 1, 1)
1850
def _write_all_revs(self):
1851
"""Write all revisions out in new form."""
1852
self.bzrdir.transport.delete_tree('revision-store')
1853
self.bzrdir.transport.mkdir('revision-store')
1854
revision_transport = self.bzrdir.transport.clone('revision-store')
1856
_revision_store = TextRevisionStore(TextStore(revision_transport,
1860
transaction = WriteTransaction()
1861
for i, rev_id in enumerate(self.converted_revs):
1862
self.pb.update('write revision', i, len(self.converted_revs))
1863
_revision_store.add_revision(self.revisions[rev_id], transaction)
1867
def _load_one_rev(self, rev_id):
1868
"""Load a revision object into memory.
1870
Any parents not either loaded or abandoned get queued to be
1872
self.pb.update('loading revision',
1873
len(self.revisions),
1874
len(self.known_revisions))
1875
if not self.branch.repository.has_revision(rev_id):
1877
self.pb.note('revision {%s} not present in branch; '
1878
'will be converted as a ghost',
1880
self.absent_revisions.add(rev_id)
1882
rev = self.branch.repository._revision_store.get_revision(rev_id,
1883
self.branch.repository.get_transaction())
1884
for parent_id in rev.parent_ids:
1885
self.known_revisions.add(parent_id)
1886
self.to_read.append(parent_id)
1887
self.revisions[rev_id] = rev
1889
def _load_old_inventory(self, rev_id):
1890
assert rev_id not in self.converted_revs
1891
old_inv_xml = self.branch.repository.inventory_store.get(rev_id).read()
1892
inv = xml4.serializer_v4.read_inventory_from_string(old_inv_xml)
1893
inv.revision_id = rev_id
1894
rev = self.revisions[rev_id]
1895
if rev.inventory_sha1:
1896
assert rev.inventory_sha1 == sha_string(old_inv_xml), \
1897
'inventory sha mismatch for {%s}' % rev_id
1900
def _load_updated_inventory(self, rev_id):
1901
assert rev_id in self.converted_revs
1902
inv_xml = self.inv_weave.get_text(rev_id)
1903
inv = xml5.serializer_v5.read_inventory_from_string(inv_xml)
1906
def _convert_one_rev(self, rev_id):
1907
"""Convert revision and all referenced objects to new format."""
1908
rev = self.revisions[rev_id]
1909
inv = self._load_old_inventory(rev_id)
1910
present_parents = [p for p in rev.parent_ids
1911
if p not in self.absent_revisions]
1912
self._convert_revision_contents(rev, inv, present_parents)
1913
self._store_new_weave(rev, inv, present_parents)
1914
self.converted_revs.add(rev_id)
1916
def _store_new_weave(self, rev, inv, present_parents):
1917
# the XML is now updated with text versions
1919
entries = inv.iter_entries()
1921
for path, ie in entries:
1922
assert getattr(ie, 'revision', None) is not None, \
1923
'no revision on {%s} in {%s}' % \
1924
(file_id, rev.revision_id)
1925
new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
1926
new_inv_sha1 = sha_string(new_inv_xml)
1927
self.inv_weave.add_lines(rev.revision_id,
1929
new_inv_xml.splitlines(True))
1930
rev.inventory_sha1 = new_inv_sha1
1932
def _convert_revision_contents(self, rev, inv, present_parents):
1933
"""Convert all the files within a revision.
1935
Also upgrade the inventory to refer to the text revision ids."""
1936
rev_id = rev.revision_id
1937
mutter('converting texts of revision {%s}',
1939
parent_invs = map(self._load_updated_inventory, present_parents)
1940
entries = inv.iter_entries()
1942
for path, ie in entries:
1943
self._convert_file_version(rev, ie, parent_invs)
1945
def _convert_file_version(self, rev, ie, parent_invs):
1946
"""Convert one version of one file.
1948
The file needs to be added into the weave if it is a merge
1949
of >=2 parents or if it's changed from its parent.
1951
file_id = ie.file_id
1952
rev_id = rev.revision_id
1953
w = self.text_weaves.get(file_id)
1956
self.text_weaves[file_id] = w
1957
text_changed = False
1958
previous_entries = ie.find_previous_heads(parent_invs,
1962
for old_revision in previous_entries:
1963
# if this fails, its a ghost ?
1964
assert old_revision in self.converted_revs, \
1965
"Revision {%s} not in converted_revs" % old_revision
1966
self.snapshot_ie(previous_entries, ie, w, rev_id)
1968
assert getattr(ie, 'revision', None) is not None
1970
def snapshot_ie(self, previous_revisions, ie, w, rev_id):
1971
# TODO: convert this logic, which is ~= snapshot to
1972
# a call to:. This needs the path figured out. rather than a work_tree
1973
# a v4 revision_tree can be given, or something that looks enough like
1974
# one to give the file content to the entry if it needs it.
1975
# and we need something that looks like a weave store for snapshot to
1977
#ie.snapshot(rev, PATH, previous_revisions, REVISION_TREE, InMemoryWeaveStore(self.text_weaves))
1978
if len(previous_revisions) == 1:
1979
previous_ie = previous_revisions.values()[0]
1980
if ie._unchanged(previous_ie):
1981
ie.revision = previous_ie.revision
1984
text = self.branch.repository.text_store.get(ie.text_id)
1985
file_lines = text.readlines()
1986
assert sha_strings(file_lines) == ie.text_sha1
1987
assert sum(map(len, file_lines)) == ie.text_size
1988
w.add_lines(rev_id, previous_revisions, file_lines)
1989
self.text_count += 1
1991
w.add_lines(rev_id, previous_revisions, [])
1992
ie.revision = rev_id
1994
def _make_order(self):
1995
"""Return a suitable order for importing revisions.
1997
The order must be such that an revision is imported after all
1998
its (present) parents.
2000
todo = set(self.revisions.keys())
2001
done = self.absent_revisions.copy()
2004
# scan through looking for a revision whose parents
2006
for rev_id in sorted(list(todo)):
2007
rev = self.revisions[rev_id]
2008
parent_ids = set(rev.parent_ids)
2009
if parent_ids.issubset(done):
2010
# can take this one now
2011
order.append(rev_id)
2017
class ConvertBzrDir5To6(Converter):
2018
"""Converts format 5 bzr dirs to format 6."""
2020
def convert(self, to_convert, pb):
2021
"""See Converter.convert()."""
2022
self.bzrdir = to_convert
2024
self.pb.note('starting upgrade from format 5 to 6')
2025
self._convert_to_prefixed()
2026
return BzrDir.open(self.bzrdir.root_transport.base)
2028
def _convert_to_prefixed(self):
2029
from bzrlib.store import TransportStore
2030
self.bzrdir.transport.delete('branch-format')
2031
for store_name in ["weaves", "revision-store"]:
2032
self.pb.note("adding prefixes to %s" % store_name)
2033
store_transport = self.bzrdir.transport.clone(store_name)
2034
store = TransportStore(store_transport, prefixed=True)
2035
for urlfilename in store_transport.list_dir('.'):
2036
filename = urlutils.unescape(urlfilename)
2037
if (filename.endswith(".weave") or
2038
filename.endswith(".gz") or
2039
filename.endswith(".sig")):
2040
file_id = os.path.splitext(filename)[0]
2043
prefix_dir = store.hash_prefix(file_id)
2044
# FIXME keep track of the dirs made RBC 20060121
2046
store_transport.move(filename, prefix_dir + '/' + filename)
2047
except errors.NoSuchFile: # catches missing dirs strangely enough
2048
store_transport.mkdir(prefix_dir)
2049
store_transport.move(filename, prefix_dir + '/' + filename)
2050
self.bzrdir._control_files.put_utf8('branch-format', BzrDirFormat6().get_format_string())
2053
class ConvertBzrDir6ToMeta(Converter):
2054
"""Converts format 6 bzr dirs to metadirs."""
2056
def convert(self, to_convert, pb):
2057
"""See Converter.convert()."""
2058
from bzrlib.repofmt.weaverepo import RepositoryFormat7
2059
from bzrlib.branch import BzrBranchFormat5
2060
self.bzrdir = to_convert
2063
self.total = 20 # the steps we know about
2064
self.garbage_inventories = []
2066
self.pb.note('starting upgrade from format 6 to metadir')
2067
self.bzrdir._control_files.put_utf8('branch-format', "Converting to format 6")
2068
# its faster to move specific files around than to open and use the apis...
2069
# first off, nuke ancestry.weave, it was never used.
2071
self.step('Removing ancestry.weave')
2072
self.bzrdir.transport.delete('ancestry.weave')
2073
except errors.NoSuchFile:
2075
# find out whats there
2076
self.step('Finding branch files')
2077
last_revision = self.bzrdir.open_branch().last_revision()
2078
bzrcontents = self.bzrdir.transport.list_dir('.')
2079
for name in bzrcontents:
2080
if name.startswith('basis-inventory.'):
2081
self.garbage_inventories.append(name)
2082
# create new directories for repository, working tree and branch
2083
self.dir_mode = self.bzrdir._control_files._dir_mode
2084
self.file_mode = self.bzrdir._control_files._file_mode
2085
repository_names = [('inventory.weave', True),
2086
('revision-store', True),
2088
self.step('Upgrading repository ')
2089
self.bzrdir.transport.mkdir('repository', mode=self.dir_mode)
2090
self.make_lock('repository')
2091
# we hard code the formats here because we are converting into
2092
# the meta format. The meta format upgrader can take this to a
2093
# future format within each component.
2094
self.put_format('repository', RepositoryFormat7())
2095
for entry in repository_names:
2096
self.move_entry('repository', entry)
2098
self.step('Upgrading branch ')
2099
self.bzrdir.transport.mkdir('branch', mode=self.dir_mode)
2100
self.make_lock('branch')
2101
self.put_format('branch', BzrBranchFormat5())
2102
branch_files = [('revision-history', True),
2103
('branch-name', True),
2105
for entry in branch_files:
2106
self.move_entry('branch', entry)
2108
checkout_files = [('pending-merges', True),
2109
('inventory', True),
2110
('stat-cache', False)]
2111
# If a mandatory checkout file is not present, the branch does not have
2112
# a functional checkout. Do not create a checkout in the converted
2114
for name, mandatory in checkout_files:
2115
if mandatory and name not in bzrcontents:
2116
has_checkout = False
2120
if not has_checkout:
2121
self.pb.note('No working tree.')
2122
# If some checkout files are there, we may as well get rid of them.
2123
for name, mandatory in checkout_files:
2124
if name in bzrcontents:
2125
self.bzrdir.transport.delete(name)
2127
from bzrlib.workingtree import WorkingTreeFormat3
2128
self.step('Upgrading working tree')
2129
self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
2130
self.make_lock('checkout')
2132
'checkout', WorkingTreeFormat3())
2133
self.bzrdir.transport.delete_multi(
2134
self.garbage_inventories, self.pb)
2135
for entry in checkout_files:
2136
self.move_entry('checkout', entry)
2137
if last_revision is not None:
2138
self.bzrdir._control_files.put_utf8(
2139
'checkout/last-revision', last_revision)
2140
self.bzrdir._control_files.put_utf8(
2141
'branch-format', BzrDirMetaFormat1().get_format_string())
2142
return BzrDir.open(self.bzrdir.root_transport.base)
2144
def make_lock(self, name):
2145
"""Make a lock for the new control dir name."""
2146
self.step('Make %s lock' % name)
2147
ld = lockdir.LockDir(self.bzrdir.transport,
2149
file_modebits=self.file_mode,
2150
dir_modebits=self.dir_mode)
2153
def move_entry(self, new_dir, entry):
2154
"""Move then entry name into new_dir."""
2156
mandatory = entry[1]
2157
self.step('Moving %s' % name)
2159
self.bzrdir.transport.move(name, '%s/%s' % (new_dir, name))
2160
except errors.NoSuchFile:
2164
def put_format(self, dirname, format):
2165
self.bzrdir._control_files.put_utf8('%s/format' % dirname, format.get_format_string())
2168
class ConvertMetaToMeta(Converter):
2169
"""Converts the components of metadirs."""
2171
def __init__(self, target_format):
2172
"""Create a metadir to metadir converter.
2174
:param target_format: The final metadir format that is desired.
2176
self.target_format = target_format
2178
def convert(self, to_convert, pb):
2179
"""See Converter.convert()."""
2180
self.bzrdir = to_convert
2184
self.step('checking repository format')
2186
repo = self.bzrdir.open_repository()
2187
except errors.NoRepositoryPresent:
2190
if not isinstance(repo._format, self.target_format.repository_format.__class__):
2191
from bzrlib.repository import CopyConverter
2192
self.pb.note('starting repository conversion')
2193
converter = CopyConverter(self.target_format.repository_format)
2194
converter.convert(repo, pb)
2196
branch = self.bzrdir.open_branch()
2197
except errors.NotBranchError:
2200
# TODO: conversions of Branch and Tree should be done by
2201
# InterXFormat lookups
2202
# Avoid circular imports
2203
from bzrlib import branch as _mod_branch
2204
if (branch._format.__class__ is _mod_branch.BzrBranchFormat5 and
2205
self.target_format.get_branch_format().__class__ is
2206
_mod_branch.BzrBranchFormat6):
2207
branch_converter = _mod_branch.Converter5to6()
2208
branch_converter.convert(branch)
2210
tree = self.bzrdir.open_workingtree(recommend_upgrade=False)
2211
except (errors.NoWorkingTree, errors.NotLocalUrl):
2214
# TODO: conversions of Branch and Tree should be done by
2215
# InterXFormat lookups
2216
if (isinstance(tree, workingtree.WorkingTree3) and
2217
not isinstance(tree, workingtree_4.WorkingTree4) and
2218
isinstance(self.target_format.workingtree_format,
2219
workingtree_4.WorkingTreeFormat4)):
2220
workingtree_4.Converter3to4().convert(tree)
2224
# This is not in remote.py because it's small, and needs to be registered.
2225
# Putting it in remote.py creates a circular import problem.
2226
# we can make it a lazy object if the control formats is turned into something
2228
class RemoteBzrDirFormat(BzrDirMetaFormat1):
2229
"""Format representing bzrdirs accessed via a smart server"""
2231
def get_format_description(self):
2232
return 'bzr remote bzrdir'
2235
def probe_transport(klass, transport):
2236
"""Return a RemoteBzrDirFormat object if it looks possible."""
2238
transport.get_smart_client()
2239
except (NotImplementedError, AttributeError,
2240
errors.TransportNotPossible):
2241
# no smart server, so not a branch for this format type.
2242
raise errors.NotBranchError(path=transport.base)
2246
def initialize_on_transport(self, transport):
2248
# hand off the request to the smart server
2249
medium = transport.get_smart_medium()
2250
except errors.NoSmartMedium:
2251
# TODO: lookup the local format from a server hint.
2252
local_dir_format = BzrDirMetaFormat1()
2253
return local_dir_format.initialize_on_transport(transport)
2254
client = _SmartClient(medium)
2255
path = client.remote_path_from_transport(transport)
2256
response = _SmartClient(medium).call('BzrDirFormat.initialize', path)
2257
assert response[0] in ('ok', ), 'unexpected response code %s' % (response,)
2258
return remote.RemoteBzrDir(transport)
2260
def _open(self, transport):
2261
return remote.RemoteBzrDir(transport)
2263
def __eq__(self, other):
2264
if not isinstance(other, RemoteBzrDirFormat):
2266
return self.get_format_description() == other.get_format_description()
2269
BzrDirFormat.register_control_server_format(RemoteBzrDirFormat)
2272
class BzrDirFormatInfo(object):
2274
def __init__(self, native, deprecated, hidden):
2275
self.deprecated = deprecated
2276
self.native = native
2277
self.hidden = hidden
2280
class BzrDirFormatRegistry(registry.Registry):
2281
"""Registry of user-selectable BzrDir subformats.
2283
Differs from BzrDirFormat._control_formats in that it provides sub-formats,
2284
e.g. BzrDirMeta1 with weave repository. Also, it's more user-oriented.
2287
def register_metadir(self, key,
2288
repository_format, help, native=True, deprecated=False,
2292
"""Register a metadir subformat.
2294
These all use a BzrDirMetaFormat1 bzrdir, but can be parameterized
2295
by the Repository format.
2297
:param repository_format: The fully-qualified repository format class
2299
:param branch_format: Fully-qualified branch format class name as
2301
:param tree_format: Fully-qualified tree format class name as
2304
# This should be expanded to support setting WorkingTree and Branch
2305
# formats, once BzrDirMetaFormat1 supports that.
2306
def _load(full_name):
2307
mod_name, factory_name = full_name.rsplit('.', 1)
2309
mod = __import__(mod_name, globals(), locals(),
2311
except ImportError, e:
2312
raise ImportError('failed to load %s: %s' % (full_name, e))
2314
factory = getattr(mod, factory_name)
2315
except AttributeError:
2316
raise AttributeError('no factory %s in module %r'
2321
bd = BzrDirMetaFormat1()
2322
if branch_format is not None:
2323
bd.set_branch_format(_load(branch_format))
2324
if tree_format is not None:
2325
bd.workingtree_format = _load(tree_format)
2326
if repository_format is not None:
2327
bd.repository_format = _load(repository_format)
2329
self.register(key, helper, help, native, deprecated, hidden)
2331
def register(self, key, factory, help, native=True, deprecated=False,
2333
"""Register a BzrDirFormat factory.
2335
The factory must be a callable that takes one parameter: the key.
2336
It must produce an instance of the BzrDirFormat when called.
2338
This function mainly exists to prevent the info object from being
2341
registry.Registry.register(self, key, factory, help,
2342
BzrDirFormatInfo(native, deprecated, hidden))
2344
def register_lazy(self, key, module_name, member_name, help, native=True,
2345
deprecated=False, hidden=False):
2346
registry.Registry.register_lazy(self, key, module_name, member_name,
2347
help, BzrDirFormatInfo(native, deprecated, hidden))
2349
def set_default(self, key):
2350
"""Set the 'default' key to be a clone of the supplied key.
2352
This method must be called once and only once.
2354
registry.Registry.register(self, 'default', self.get(key),
2355
self.get_help(key), info=self.get_info(key))
2357
def set_default_repository(self, key):
2358
"""Set the FormatRegistry default and Repository default.
2360
This is a transitional method while Repository.set_default_format
2363
if 'default' in self:
2364
self.remove('default')
2365
self.set_default(key)
2366
format = self.get('default')()
2367
assert isinstance(format, BzrDirMetaFormat1)
2369
def make_bzrdir(self, key):
2370
return self.get(key)()
2372
def help_topic(self, topic):
2373
output = textwrap.dedent("""\
2374
Bazaar directory formats
2375
------------------------
2377
These formats can be used for creating branches, working trees, and
2381
default_help = self.get_help('default')
2383
for key in self.keys():
2384
if key == 'default':
2386
help = self.get_help(key)
2387
if help == default_help:
2388
default_realkey = key
2390
help_pairs.append((key, help))
2392
def wrapped(key, help, info):
2394
help = '(native) ' + help
2395
return ' %s:\n%s\n\n' % (key,
2396
textwrap.fill(help, initial_indent=' ',
2397
subsequent_indent=' '))
2398
output += wrapped('%s/default' % default_realkey, default_help,
2399
self.get_info('default'))
2400
deprecated_pairs = []
2401
for key, help in help_pairs:
2402
info = self.get_info(key)
2405
elif info.deprecated:
2406
deprecated_pairs.append((key, help))
2408
output += wrapped(key, help, info)
2409
if len(deprecated_pairs) > 0:
2410
output += "Deprecated formats\n------------------\n\n"
2411
for key, help in deprecated_pairs:
2412
info = self.get_info(key)
2413
output += wrapped(key, help, info)
2418
format_registry = BzrDirFormatRegistry()
2419
format_registry.register('weave', BzrDirFormat6,
2420
'Pre-0.8 format. Slower than knit and does not'
2421
' support checkouts or shared repositories.',
2423
format_registry.register_metadir('knit',
2424
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2425
'Format using knits. Recommended for interoperation with bzr <= 0.14.',
2426
branch_format='bzrlib.branch.BzrBranchFormat5',
2427
tree_format='bzrlib.workingtree.WorkingTreeFormat3')
2428
format_registry.register_metadir('metaweave',
2429
'bzrlib.repofmt.weaverepo.RepositoryFormat7',
2430
'Transitional format in 0.8. Slower than knit.',
2431
branch_format='bzrlib.branch.BzrBranchFormat5',
2432
tree_format='bzrlib.workingtree.WorkingTreeFormat3',
2434
format_registry.register_metadir('dirstate',
2435
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2436
help='New in 0.15: Fast local operations. Compatible with bzr 0.8 and '
2437
'above when accessed over the network.',
2438
branch_format='bzrlib.branch.BzrBranchFormat5',
2439
# this uses bzrlib.workingtree.WorkingTreeFormat4 because importing
2440
# directly from workingtree_4 triggers a circular import.
2441
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2443
format_registry.register_metadir('dirstate-tags',
2444
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2445
help='New in 0.15: Fast local operations and improved scaling for '
2446
'network operations. Additionally adds support for tags.'
2447
' Incompatible with bzr < 0.15.',
2448
branch_format='bzrlib.branch.BzrBranchFormat6',
2449
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2451
format_registry.register_metadir('dirstate-with-subtree',
2452
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
2453
help='New in 0.15: Fast local operations and improved scaling for '
2454
'network operations. Additionally adds support for versioning nested '
2455
'bzr branches. Incompatible with bzr < 0.15.',
2456
branch_format='bzrlib.branch.BzrBranchFormat6',
2457
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2460
format_registry.set_default('dirstate')