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: Can we move specific formats into separate modules to make this file
26
from cStringIO import StringIO
29
from bzrlib.lazy_import import lazy_import
30
lazy_import(globals(), """
31
from stat import S_ISDIR
33
from warnings import warn
43
revision as _mod_revision,
52
from bzrlib.osutils import (
56
from bzrlib.smart.client import _SmartClient
57
from bzrlib.smart import protocol
58
from bzrlib.store.revision.text import TextRevisionStore
59
from bzrlib.store.text import TextStore
60
from bzrlib.store.versioned import WeaveStore
61
from bzrlib.transactions import WriteTransaction
62
from bzrlib.transport import (
63
do_catching_redirections,
66
from bzrlib.weave import Weave
69
from bzrlib.trace import (
73
from bzrlib.transport.local import LocalTransport
74
from bzrlib.symbol_versioning import (
82
"""A .bzr control diretory.
84
BzrDir instances let you create or open any of the things that can be
85
found within .bzr - checkouts, branches and repositories.
88
the transport which this bzr dir is rooted at (i.e. file:///.../.bzr/)
90
a transport connected to the directory this bzr was opened from.
94
"""Invoke break_lock on the first object in the bzrdir.
96
If there is a tree, the tree is opened and break_lock() called.
97
Otherwise, branch is tried, and finally repository.
99
# XXX: This seems more like a UI function than something that really
100
# belongs in this class.
102
thing_to_unlock = self.open_workingtree()
103
except (errors.NotLocalUrl, errors.NoWorkingTree):
105
thing_to_unlock = self.open_branch()
106
except errors.NotBranchError:
108
thing_to_unlock = self.open_repository()
109
except errors.NoRepositoryPresent:
111
thing_to_unlock.break_lock()
113
def can_convert_format(self):
114
"""Return true if this bzrdir is one whose format we can convert from."""
117
def check_conversion_target(self, target_format):
118
target_repo_format = target_format.repository_format
119
source_repo_format = self._format.repository_format
120
source_repo_format.check_conversion_target(target_repo_format)
123
def _check_supported(format, allow_unsupported,
124
recommend_upgrade=True,
126
"""Give an error or warning on old formats.
128
:param format: may be any kind of format - workingtree, branch,
131
:param allow_unsupported: If true, allow opening
132
formats that are strongly deprecated, and which may
133
have limited functionality.
135
:param recommend_upgrade: If true (default), warn
136
the user through the ui object that they may wish
137
to upgrade the object.
139
# TODO: perhaps move this into a base Format class; it's not BzrDir
140
# specific. mbp 20070323
141
if not allow_unsupported and not format.is_supported():
142
# see open_downlevel to open legacy branches.
143
raise errors.UnsupportedFormatError(format=format)
144
if recommend_upgrade \
145
and getattr(format, 'upgrade_recommended', False):
146
ui.ui_factory.recommend_upgrade(
147
format.get_format_description(),
150
def clone(self, url, revision_id=None, force_new_repo=False):
151
"""Clone this bzrdir and its contents to url verbatim.
153
If urls last component does not exist, it will be created.
155
if revision_id is not None, then the clone operation may tune
156
itself to download less data.
157
:param force_new_repo: Do not use a shared repository for the target
158
even if one is available.
160
return self.clone_on_transport(get_transport(url),
161
revision_id=revision_id,
162
force_new_repo=force_new_repo)
164
def clone_on_transport(self, transport, revision_id=None,
165
force_new_repo=False):
166
"""Clone this bzrdir and its contents to transport verbatim.
168
If the target directory does not exist, it will be created.
170
if revision_id is not None, then the clone operation may tune
171
itself to download less data.
172
:param force_new_repo: Do not use a shared repository for the target
173
even if one is available.
175
transport.ensure_base()
176
result = self._format.initialize_on_transport(transport)
178
local_repo = self.find_repository()
179
except errors.NoRepositoryPresent:
182
# may need to copy content in
184
result_repo = local_repo.clone(
186
revision_id=revision_id)
187
result_repo.set_make_working_trees(local_repo.make_working_trees())
190
result_repo = result.find_repository()
191
# fetch content this dir needs.
192
result_repo.fetch(local_repo, revision_id=revision_id)
193
except errors.NoRepositoryPresent:
194
# needed to make one anyway.
195
result_repo = local_repo.clone(
197
revision_id=revision_id)
198
result_repo.set_make_working_trees(local_repo.make_working_trees())
199
# 1 if there is a branch present
200
# make sure its content is available in the target repository
203
self.open_branch().clone(result, revision_id=revision_id)
204
except errors.NotBranchError:
207
self.open_workingtree().clone(result)
208
except (errors.NoWorkingTree, errors.NotLocalUrl):
212
# TODO: This should be given a Transport, and should chdir up; otherwise
213
# this will open a new connection.
214
def _make_tail(self, url):
215
t = get_transport(url)
219
def create(cls, base, format=None, possible_transports=None):
220
"""Create a new BzrDir at the url 'base'.
222
This will call the current default formats initialize with base
223
as the only parameter.
225
:param format: If supplied, the format of branch to create. If not
226
supplied, the default is used.
227
:param possible_transports: If supplied, a list of transports that
228
can be reused to share a remote connection.
230
if cls is not BzrDir:
231
raise AssertionError("BzrDir.create always creates the default"
232
" format, not one of %r" % cls)
233
t = get_transport(base, possible_transports)
236
format = BzrDirFormat.get_default_format()
237
return format.initialize(base, possible_transports)
239
def create_branch(self):
240
"""Create a branch in this BzrDir.
242
The bzrdirs format will control what branch format is created.
243
For more control see BranchFormatXX.create(a_bzrdir).
245
raise NotImplementedError(self.create_branch)
248
def create_branch_and_repo(base, force_new_repo=False, format=None):
249
"""Create a new BzrDir, Branch and Repository at the url 'base'.
251
This will use the current default BzrDirFormat, and use whatever
252
repository format that that uses via bzrdir.create_branch and
253
create_repository. If a shared repository is available that is used
256
The created Branch object is returned.
258
:param base: The URL to create the branch at.
259
:param force_new_repo: If True a new repository is always created.
261
bzrdir = BzrDir.create(base, format)
262
bzrdir._find_or_create_repository(force_new_repo)
263
return bzrdir.create_branch()
265
def _find_or_create_repository(self, force_new_repo):
266
"""Create a new repository if needed, returning the repository."""
268
return self.create_repository()
270
return self.find_repository()
271
except errors.NoRepositoryPresent:
272
return self.create_repository()
275
def create_branch_convenience(base, force_new_repo=False,
276
force_new_tree=None, format=None,
277
possible_transports=None):
278
"""Create a new BzrDir, Branch and Repository at the url 'base'.
280
This is a convenience function - it will use an existing repository
281
if possible, can be told explicitly whether to create a working tree or
284
This will use the current default BzrDirFormat, and use whatever
285
repository format that that uses via bzrdir.create_branch and
286
create_repository. If a shared repository is available that is used
287
preferentially. Whatever repository is used, its tree creation policy
290
The created Branch object is returned.
291
If a working tree cannot be made due to base not being a file:// url,
292
no error is raised unless force_new_tree is True, in which case no
293
data is created on disk and NotLocalUrl is raised.
295
:param base: The URL to create the branch at.
296
:param force_new_repo: If True a new repository is always created.
297
:param force_new_tree: If True or False force creation of a tree or
298
prevent such creation respectively.
299
:param format: Override for the for the bzrdir format to create.
300
:param possible_transports: An optional reusable transports list.
303
# check for non local urls
304
t = get_transport(base, possible_transports)
305
if not isinstance(t, LocalTransport):
306
raise errors.NotLocalUrl(base)
307
bzrdir = BzrDir.create(base, format, possible_transports)
308
repo = bzrdir._find_or_create_repository(force_new_repo)
309
result = bzrdir.create_branch()
310
if force_new_tree or (repo.make_working_trees() and
311
force_new_tree is None):
313
bzrdir.create_workingtree()
314
except errors.NotLocalUrl:
319
@deprecated_function(zero_ninetyone)
320
def create_repository(base, shared=False, format=None):
321
"""Create a new BzrDir and Repository at the url 'base'.
323
If no format is supplied, this will default to the current default
324
BzrDirFormat by default, and use whatever repository format that that
325
uses for bzrdirformat.create_repository.
327
:param shared: Create a shared repository rather than a standalone
329
The Repository object is returned.
331
This must be overridden as an instance method in child classes, where
332
it should take no parameters and construct whatever repository format
333
that child class desires.
335
This method is deprecated, please call create_repository on a bzrdir
338
bzrdir = BzrDir.create(base, format)
339
return bzrdir.create_repository(shared)
342
def create_standalone_workingtree(base, format=None):
343
"""Create a new BzrDir, WorkingTree, Branch and Repository at 'base'.
345
'base' must be a local path or a file:// url.
347
This will use the current default BzrDirFormat, and use whatever
348
repository format that that uses for bzrdirformat.create_workingtree,
349
create_branch and create_repository.
351
:return: The WorkingTree object.
353
t = get_transport(base)
354
if not isinstance(t, LocalTransport):
355
raise errors.NotLocalUrl(base)
356
bzrdir = BzrDir.create_branch_and_repo(base,
358
format=format).bzrdir
359
return bzrdir.create_workingtree()
361
def create_workingtree(self, revision_id=None):
362
"""Create a working tree at this BzrDir.
364
revision_id: create it as of this revision id.
366
raise NotImplementedError(self.create_workingtree)
368
def retire_bzrdir(self):
369
"""Permanently disable the bzrdir.
371
This is done by renaming it to give the user some ability to recover
372
if there was a problem.
374
This will have horrible consequences if anyone has anything locked or
377
for i in xrange(10000):
379
to_path = '.bzr.retired.%d' % i
380
self.root_transport.rename('.bzr', to_path)
381
note("renamed %s to %s"
382
% (self.root_transport.abspath('.bzr'), to_path))
384
except (errors.TransportError, IOError, errors.PathError):
387
def destroy_workingtree(self):
388
"""Destroy the working tree at this BzrDir.
390
Formats that do not support this may raise UnsupportedOperation.
392
raise NotImplementedError(self.destroy_workingtree)
394
def destroy_workingtree_metadata(self):
395
"""Destroy the control files for the working tree at this BzrDir.
397
The contents of working tree files are not affected.
398
Formats that do not support this may raise UnsupportedOperation.
400
raise NotImplementedError(self.destroy_workingtree_metadata)
402
def find_repository(self):
403
"""Find the repository that should be used for a_bzrdir.
405
This does not require a branch as we use it to find the repo for
406
new branches as well as to hook existing branches up to their
410
return self.open_repository()
411
except errors.NoRepositoryPresent:
413
next_transport = self.root_transport.clone('..')
415
# find the next containing bzrdir
417
found_bzrdir = BzrDir.open_containing_from_transport(
419
except errors.NotBranchError:
421
raise errors.NoRepositoryPresent(self)
422
# does it have a repository ?
424
repository = found_bzrdir.open_repository()
425
except errors.NoRepositoryPresent:
426
next_transport = found_bzrdir.root_transport.clone('..')
427
if (found_bzrdir.root_transport.base == next_transport.base):
428
# top of the file system
432
if ((found_bzrdir.root_transport.base ==
433
self.root_transport.base) or repository.is_shared()):
436
raise errors.NoRepositoryPresent(self)
437
raise errors.NoRepositoryPresent(self)
439
def get_branch_reference(self):
440
"""Return the referenced URL for the branch in this bzrdir.
442
:raises NotBranchError: If there is no Branch.
443
:return: The URL the branch in this bzrdir references if it is a
444
reference branch, or None for regular branches.
448
def get_branch_transport(self, branch_format):
449
"""Get the transport for use by branch format in this BzrDir.
451
Note that bzr dirs that do not support format strings will raise
452
IncompatibleFormat if the branch format they are given has
453
a format string, and vice versa.
455
If branch_format is None, the transport is returned with no
456
checking. if it is not None, then the returned transport is
457
guaranteed to point to an existing directory ready for use.
459
raise NotImplementedError(self.get_branch_transport)
461
def get_repository_transport(self, repository_format):
462
"""Get the transport for use by repository format in this BzrDir.
464
Note that bzr dirs that do not support format strings will raise
465
IncompatibleFormat if the repository format they are given has
466
a format string, and vice versa.
468
If repository_format is None, the transport is returned with no
469
checking. if it is not None, then the returned transport is
470
guaranteed to point to an existing directory ready for use.
472
raise NotImplementedError(self.get_repository_transport)
474
def get_workingtree_transport(self, tree_format):
475
"""Get the transport for use by workingtree format in this BzrDir.
477
Note that bzr dirs that do not support format strings will raise
478
IncompatibleFormat if the workingtree format they are given has a
479
format string, and vice versa.
481
If workingtree_format is None, the transport is returned with no
482
checking. if it is not None, then the returned transport is
483
guaranteed to point to an existing directory ready for use.
485
raise NotImplementedError(self.get_workingtree_transport)
487
def __init__(self, _transport, _format):
488
"""Initialize a Bzr control dir object.
490
Only really common logic should reside here, concrete classes should be
491
made with varying behaviours.
493
:param _format: the format that is creating this BzrDir instance.
494
:param _transport: the transport this dir is based at.
496
self._format = _format
497
self.transport = _transport.clone('.bzr')
498
self.root_transport = _transport
500
def is_control_filename(self, filename):
501
"""True if filename is the name of a path which is reserved for bzrdir's.
503
:param filename: A filename within the root transport of this bzrdir.
505
This is true IF and ONLY IF the filename is part of the namespace reserved
506
for bzr control dirs. Currently this is the '.bzr' directory in the root
507
of the root_transport. it is expected that plugins will need to extend
508
this in the future - for instance to make bzr talk with svn working
511
# this might be better on the BzrDirFormat class because it refers to
512
# all the possible bzrdir disk formats.
513
# This method is tested via the workingtree is_control_filename tests-
514
# it was extracted from WorkingTree.is_control_filename. If the methods
515
# contract is extended beyond the current trivial implementation please
516
# add new tests for it to the appropriate place.
517
return filename == '.bzr' or filename.startswith('.bzr/')
519
def needs_format_conversion(self, format=None):
520
"""Return true if this bzrdir needs convert_format run on it.
522
For instance, if the repository format is out of date but the
523
branch and working tree are not, this should return True.
525
:param format: Optional parameter indicating a specific desired
526
format we plan to arrive at.
528
raise NotImplementedError(self.needs_format_conversion)
531
def open_unsupported(base):
532
"""Open a branch which is not supported."""
533
return BzrDir.open(base, _unsupported=True)
536
def open(base, _unsupported=False, possible_transports=None):
537
"""Open an existing bzrdir, rooted at 'base' (url)
539
_unsupported is a private parameter to the BzrDir class.
541
t = get_transport(base, possible_transports=possible_transports)
542
return BzrDir.open_from_transport(t, _unsupported=_unsupported)
545
def open_from_transport(transport, _unsupported=False,
546
_server_formats=True):
547
"""Open a bzrdir within a particular directory.
549
:param transport: Transport containing the bzrdir.
550
:param _unsupported: private.
552
base = transport.base
554
def find_format(transport):
555
return transport, BzrDirFormat.find_format(
556
transport, _server_formats=_server_formats)
558
def redirected(transport, e, redirection_notice):
559
qualified_source = e.get_source_url()
560
relpath = transport.relpath(qualified_source)
561
if not e.target.endswith(relpath):
562
# Not redirected to a branch-format, not a branch
563
raise errors.NotBranchError(path=e.target)
564
target = e.target[:-len(relpath)]
565
note('%s is%s redirected to %s',
566
transport.base, e.permanently, target)
567
# Let's try with a new transport
568
qualified_target = e.get_target_url()[:-len(relpath)]
569
# FIXME: If 'transport' has a qualifier, this should
570
# be applied again to the new transport *iff* the
571
# schemes used are the same. It's a bit tricky to
572
# verify, so I'll punt for now
574
return get_transport(target)
577
transport, format = do_catching_redirections(find_format,
580
except errors.TooManyRedirections:
581
raise errors.NotBranchError(base)
583
BzrDir._check_supported(format, _unsupported)
584
return format.open(transport, _found=True)
586
def open_branch(self, unsupported=False):
587
"""Open the branch object at this BzrDir if one is present.
589
If unsupported is True, then no longer supported branch formats can
592
TODO: static convenience version of this?
594
raise NotImplementedError(self.open_branch)
597
def open_containing(url, possible_transports=None):
598
"""Open an existing branch which contains url.
600
:param url: url to search from.
601
See open_containing_from_transport for more detail.
603
transport = get_transport(url, possible_transports)
604
return BzrDir.open_containing_from_transport(transport)
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:
630
new_t = a_transport.clone('..')
631
except errors.InvalidURLJoin:
632
# reached the root, whatever that may be
633
raise errors.NotBranchError(path=url)
634
if new_t.base == a_transport.base:
635
# reached the root, whatever that may be
636
raise errors.NotBranchError(path=url)
640
def open_containing_tree_or_branch(klass, location):
641
"""Return the branch and working tree contained by a location.
643
Returns (tree, branch, relpath).
644
If there is no tree at containing the location, tree will be None.
645
If there is no branch containing the location, an exception will be
647
relpath is the portion of the path that is contained by the branch.
649
bzrdir, relpath = klass.open_containing(location)
651
tree = bzrdir.open_workingtree()
652
except (errors.NoWorkingTree, errors.NotLocalUrl):
654
branch = bzrdir.open_branch()
657
return tree, branch, relpath
659
def open_repository(self, _unsupported=False):
660
"""Open the repository object at this BzrDir if one is present.
662
This will not follow the Branch object pointer - its strictly a direct
663
open facility. Most client code should use open_branch().repository to
666
_unsupported is a private parameter, not part of the api.
667
TODO: static convenience version of this?
669
raise NotImplementedError(self.open_repository)
671
def open_workingtree(self, _unsupported=False,
672
recommend_upgrade=True):
673
"""Open the workingtree object at this BzrDir if one is present.
675
:param recommend_upgrade: Optional keyword parameter, when True (the
676
default), emit through the ui module a recommendation that the user
677
upgrade the working tree when the workingtree being opened is old
678
(but still fully supported).
680
raise NotImplementedError(self.open_workingtree)
682
def has_branch(self):
683
"""Tell if this bzrdir contains a branch.
685
Note: if you're going to open the branch, you should just go ahead
686
and try, and not ask permission first. (This method just opens the
687
branch and discards it, and that's somewhat expensive.)
692
except errors.NotBranchError:
695
def has_workingtree(self):
696
"""Tell if this bzrdir contains a working tree.
698
This will still raise an exception if the bzrdir has a workingtree that
699
is remote & inaccessible.
701
Note: if you're going to open the working tree, you should just go ahead
702
and try, and not ask permission first. (This method just opens the
703
workingtree and discards it, and that's somewhat expensive.)
706
self.open_workingtree(recommend_upgrade=False)
708
except errors.NoWorkingTree:
711
def _cloning_metadir(self):
712
"""Produce a metadir suitable for cloning with"""
713
result_format = self._format.__class__()
716
branch = self.open_branch()
717
source_repository = branch.repository
718
except errors.NotBranchError:
720
source_repository = self.open_repository()
721
except errors.NoRepositoryPresent:
722
source_repository = None
724
# XXX TODO: This isinstance is here because we have not implemented
725
# the fix recommended in bug # 103195 - to delegate this choice the
727
repo_format = source_repository._format
728
if not isinstance(repo_format, remote.RemoteRepositoryFormat):
729
result_format.repository_format = repo_format
731
# TODO: Couldn't we just probe for the format in these cases,
732
# rather than opening the whole tree? It would be a little
733
# faster. mbp 20070401
734
tree = self.open_workingtree(recommend_upgrade=False)
735
except (errors.NoWorkingTree, errors.NotLocalUrl):
736
result_format.workingtree_format = None
738
result_format.workingtree_format = tree._format.__class__()
739
return result_format, source_repository
741
def cloning_metadir(self):
742
"""Produce a metadir suitable for cloning or sprouting with.
744
These operations may produce workingtrees (yes, even though they're
745
"cloning" something that doesn't have a tree, so a viable workingtree
746
format must be selected.
748
format, repository = self._cloning_metadir()
749
if format._workingtree_format is None:
750
if repository is None:
752
tree_format = repository._format._matchingbzrdir.workingtree_format
753
format.workingtree_format = tree_format.__class__()
756
def checkout_metadir(self):
757
return self.cloning_metadir()
759
def sprout(self, url, revision_id=None, force_new_repo=False,
760
recurse='down', possible_transports=None):
761
"""Create a copy of this bzrdir prepared for use as a new line of
764
If urls last component does not exist, it will be created.
766
Attributes related to the identity of the source branch like
767
branch nickname will be cleaned, a working tree is created
768
whether one existed before or not; and a local branch is always
771
if revision_id is not None, then the clone operation may tune
772
itself to download less data.
774
target_transport = get_transport(url, possible_transports)
775
target_transport.ensure_base()
776
cloning_format = self.cloning_metadir()
777
result = cloning_format.initialize_on_transport(target_transport)
779
source_branch = self.open_branch()
780
source_repository = source_branch.repository
781
except errors.NotBranchError:
784
source_repository = self.open_repository()
785
except errors.NoRepositoryPresent:
786
source_repository = None
791
result_repo = result.find_repository()
792
except errors.NoRepositoryPresent:
794
if source_repository is None and result_repo is not None:
796
elif source_repository is None and result_repo is None:
797
# no repo available, make a new one
798
result.create_repository()
799
elif source_repository is not None and result_repo is None:
800
# have source, and want to make a new target repo
801
result_repo = source_repository.sprout(result,
802
revision_id=revision_id)
804
# fetch needed content into target.
805
if source_repository is not None:
807
# source_repository.copy_content_into(result_repo,
808
# revision_id=revision_id)
809
# so we can override the copy method
810
result_repo.fetch(source_repository, revision_id=revision_id)
811
if source_branch is not None:
812
source_branch.sprout(result, revision_id=revision_id)
814
result.create_branch()
815
if isinstance(target_transport, LocalTransport) and (
816
result_repo is None or result_repo.make_working_trees()):
817
wt = result.create_workingtree()
820
if wt.path2id('') is None:
822
wt.set_root_id(self.open_workingtree.get_root_id())
823
except errors.NoWorkingTree:
829
if recurse == 'down':
831
basis = wt.basis_tree()
833
subtrees = basis.iter_references()
834
recurse_branch = wt.branch
835
elif source_branch is not None:
836
basis = source_branch.basis_tree()
838
subtrees = basis.iter_references()
839
recurse_branch = source_branch
844
for path, file_id in subtrees:
845
target = urlutils.join(url, urlutils.escape(path))
846
sublocation = source_branch.reference_parent(file_id, path)
847
sublocation.bzrdir.sprout(target,
848
basis.get_reference_revision(file_id, path),
849
force_new_repo=force_new_repo, recurse=recurse)
851
if basis is not None:
856
class BzrDirPreSplitOut(BzrDir):
857
"""A common class for the all-in-one formats."""
859
def __init__(self, _transport, _format):
860
"""See BzrDir.__init__."""
861
super(BzrDirPreSplitOut, self).__init__(_transport, _format)
862
assert self._format._lock_class == lockable_files.TransportLock
863
assert self._format._lock_file_name == 'branch-lock'
864
self._control_files = lockable_files.LockableFiles(
865
self.get_branch_transport(None),
866
self._format._lock_file_name,
867
self._format._lock_class)
869
def break_lock(self):
870
"""Pre-splitout bzrdirs do not suffer from stale locks."""
871
raise NotImplementedError(self.break_lock)
873
def clone(self, url, revision_id=None, force_new_repo=False):
874
"""See BzrDir.clone()."""
875
from bzrlib.workingtree import WorkingTreeFormat2
877
result = self._format._initialize_for_clone(url)
878
self.open_repository().clone(result, revision_id=revision_id)
879
from_branch = self.open_branch()
880
from_branch.clone(result, revision_id=revision_id)
882
self.open_workingtree().clone(result)
883
except errors.NotLocalUrl:
884
# make a new one, this format always has to have one.
886
WorkingTreeFormat2().initialize(result)
887
except errors.NotLocalUrl:
888
# but we cannot do it for remote trees.
889
to_branch = result.open_branch()
890
WorkingTreeFormat2().stub_initialize_remote(to_branch.control_files)
893
def create_branch(self):
894
"""See BzrDir.create_branch."""
895
return self.open_branch()
897
def create_repository(self, shared=False):
898
"""See BzrDir.create_repository."""
900
raise errors.IncompatibleFormat('shared repository', self._format)
901
return self.open_repository()
903
def create_workingtree(self, revision_id=None):
904
"""See BzrDir.create_workingtree."""
905
# this looks buggy but is not -really-
906
# because this format creates the workingtree when the bzrdir is
908
# clone and sprout will have set the revision_id
909
# and that will have set it for us, its only
910
# specific uses of create_workingtree in isolation
911
# that can do wonky stuff here, and that only
912
# happens for creating checkouts, which cannot be
913
# done on this format anyway. So - acceptable wart.
914
result = self.open_workingtree(recommend_upgrade=False)
915
if revision_id is not None:
916
if revision_id == _mod_revision.NULL_REVISION:
917
result.set_parent_ids([])
919
result.set_parent_ids([revision_id])
922
def destroy_workingtree(self):
923
"""See BzrDir.destroy_workingtree."""
924
raise errors.UnsupportedOperation(self.destroy_workingtree, self)
926
def destroy_workingtree_metadata(self):
927
"""See BzrDir.destroy_workingtree_metadata."""
928
raise errors.UnsupportedOperation(self.destroy_workingtree_metadata,
931
def get_branch_transport(self, branch_format):
932
"""See BzrDir.get_branch_transport()."""
933
if branch_format is None:
934
return self.transport
936
branch_format.get_format_string()
937
except NotImplementedError:
938
return self.transport
939
raise errors.IncompatibleFormat(branch_format, self._format)
941
def get_repository_transport(self, repository_format):
942
"""See BzrDir.get_repository_transport()."""
943
if repository_format is None:
944
return self.transport
946
repository_format.get_format_string()
947
except NotImplementedError:
948
return self.transport
949
raise errors.IncompatibleFormat(repository_format, self._format)
951
def get_workingtree_transport(self, workingtree_format):
952
"""See BzrDir.get_workingtree_transport()."""
953
if workingtree_format is None:
954
return self.transport
956
workingtree_format.get_format_string()
957
except NotImplementedError:
958
return self.transport
959
raise errors.IncompatibleFormat(workingtree_format, self._format)
961
def needs_format_conversion(self, format=None):
962
"""See BzrDir.needs_format_conversion()."""
963
# if the format is not the same as the system default,
964
# an upgrade is needed.
966
format = BzrDirFormat.get_default_format()
967
return not isinstance(self._format, format.__class__)
969
def open_branch(self, unsupported=False):
970
"""See BzrDir.open_branch."""
971
from bzrlib.branch import BzrBranchFormat4
972
format = BzrBranchFormat4()
973
self._check_supported(format, unsupported)
974
return format.open(self, _found=True)
976
def sprout(self, url, revision_id=None, force_new_repo=False,
977
possible_transports=None):
978
"""See BzrDir.sprout()."""
979
from bzrlib.workingtree import WorkingTreeFormat2
981
result = self._format._initialize_for_clone(url)
983
self.open_repository().clone(result, revision_id=revision_id)
984
except errors.NoRepositoryPresent:
987
self.open_branch().sprout(result, revision_id=revision_id)
988
except errors.NotBranchError:
990
# we always want a working tree
991
WorkingTreeFormat2().initialize(result)
995
class BzrDir4(BzrDirPreSplitOut):
996
"""A .bzr version 4 control object.
998
This is a deprecated format and may be removed after sept 2006.
1001
def create_repository(self, shared=False):
1002
"""See BzrDir.create_repository."""
1003
return self._format.repository_format.initialize(self, shared)
1005
def needs_format_conversion(self, format=None):
1006
"""Format 4 dirs are always in need of conversion."""
1009
def open_repository(self):
1010
"""See BzrDir.open_repository."""
1011
from bzrlib.repofmt.weaverepo import RepositoryFormat4
1012
return RepositoryFormat4().open(self, _found=True)
1015
class BzrDir5(BzrDirPreSplitOut):
1016
"""A .bzr version 5 control object.
1018
This is a deprecated format and may be removed after sept 2006.
1021
def open_repository(self):
1022
"""See BzrDir.open_repository."""
1023
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1024
return RepositoryFormat5().open(self, _found=True)
1026
def open_workingtree(self, _unsupported=False,
1027
recommend_upgrade=True):
1028
"""See BzrDir.create_workingtree."""
1029
from bzrlib.workingtree import WorkingTreeFormat2
1030
wt_format = WorkingTreeFormat2()
1031
# we don't warn here about upgrades; that ought to be handled for the
1033
return wt_format.open(self, _found=True)
1036
class BzrDir6(BzrDirPreSplitOut):
1037
"""A .bzr version 6 control object.
1039
This is a deprecated format and may be removed after sept 2006.
1042
def open_repository(self):
1043
"""See BzrDir.open_repository."""
1044
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1045
return RepositoryFormat6().open(self, _found=True)
1047
def open_workingtree(self, _unsupported=False,
1048
recommend_upgrade=True):
1049
"""See BzrDir.create_workingtree."""
1050
# we don't warn here about upgrades; that ought to be handled for the
1052
from bzrlib.workingtree import WorkingTreeFormat2
1053
return WorkingTreeFormat2().open(self, _found=True)
1056
class BzrDirMeta1(BzrDir):
1057
"""A .bzr meta version 1 control object.
1059
This is the first control object where the
1060
individual aspects are really split out: there are separate repository,
1061
workingtree and branch subdirectories and any subset of the three can be
1062
present within a BzrDir.
1065
def can_convert_format(self):
1066
"""See BzrDir.can_convert_format()."""
1069
def create_branch(self):
1070
"""See BzrDir.create_branch."""
1071
return self._format.get_branch_format().initialize(self)
1073
def create_repository(self, shared=False):
1074
"""See BzrDir.create_repository."""
1075
return self._format.repository_format.initialize(self, shared)
1077
def create_workingtree(self, revision_id=None):
1078
"""See BzrDir.create_workingtree."""
1079
from bzrlib.workingtree import WorkingTreeFormat
1080
return self._format.workingtree_format.initialize(self, revision_id)
1082
def destroy_workingtree(self):
1083
"""See BzrDir.destroy_workingtree."""
1084
wt = self.open_workingtree(recommend_upgrade=False)
1085
repository = wt.branch.repository
1086
empty = repository.revision_tree(_mod_revision.NULL_REVISION)
1087
wt.revert(old_tree=empty)
1088
self.destroy_workingtree_metadata()
1090
def destroy_workingtree_metadata(self):
1091
self.transport.delete_tree('checkout')
1093
def find_branch_format(self):
1094
"""Find the branch 'format' for this bzrdir.
1096
This might be a synthetic object for e.g. RemoteBranch and SVN.
1098
from bzrlib.branch import BranchFormat
1099
return BranchFormat.find_format(self)
1101
def _get_mkdir_mode(self):
1102
"""Figure out the mode to use when creating a bzrdir subdir."""
1103
temp_control = lockable_files.LockableFiles(self.transport, '',
1104
lockable_files.TransportLock)
1105
return temp_control._dir_mode
1107
def get_branch_reference(self):
1108
"""See BzrDir.get_branch_reference()."""
1109
from bzrlib.branch import BranchFormat
1110
format = BranchFormat.find_format(self)
1111
return format.get_reference(self)
1113
def get_branch_transport(self, branch_format):
1114
"""See BzrDir.get_branch_transport()."""
1115
if branch_format is None:
1116
return self.transport.clone('branch')
1118
branch_format.get_format_string()
1119
except NotImplementedError:
1120
raise errors.IncompatibleFormat(branch_format, self._format)
1122
self.transport.mkdir('branch', mode=self._get_mkdir_mode())
1123
except errors.FileExists:
1125
return self.transport.clone('branch')
1127
def get_repository_transport(self, repository_format):
1128
"""See BzrDir.get_repository_transport()."""
1129
if repository_format is None:
1130
return self.transport.clone('repository')
1132
repository_format.get_format_string()
1133
except NotImplementedError:
1134
raise errors.IncompatibleFormat(repository_format, self._format)
1136
self.transport.mkdir('repository', mode=self._get_mkdir_mode())
1137
except errors.FileExists:
1139
return self.transport.clone('repository')
1141
def get_workingtree_transport(self, workingtree_format):
1142
"""See BzrDir.get_workingtree_transport()."""
1143
if workingtree_format is None:
1144
return self.transport.clone('checkout')
1146
workingtree_format.get_format_string()
1147
except NotImplementedError:
1148
raise errors.IncompatibleFormat(workingtree_format, self._format)
1150
self.transport.mkdir('checkout', mode=self._get_mkdir_mode())
1151
except errors.FileExists:
1153
return self.transport.clone('checkout')
1155
def needs_format_conversion(self, format=None):
1156
"""See BzrDir.needs_format_conversion()."""
1158
format = BzrDirFormat.get_default_format()
1159
if not isinstance(self._format, format.__class__):
1160
# it is not a meta dir format, conversion is needed.
1162
# we might want to push this down to the repository?
1164
if not isinstance(self.open_repository()._format,
1165
format.repository_format.__class__):
1166
# the repository needs an upgrade.
1168
except errors.NoRepositoryPresent:
1171
if not isinstance(self.open_branch()._format,
1172
format.get_branch_format().__class__):
1173
# the branch needs an upgrade.
1175
except errors.NotBranchError:
1178
my_wt = self.open_workingtree(recommend_upgrade=False)
1179
if not isinstance(my_wt._format,
1180
format.workingtree_format.__class__):
1181
# the workingtree needs an upgrade.
1183
except (errors.NoWorkingTree, errors.NotLocalUrl):
1187
def open_branch(self, unsupported=False):
1188
"""See BzrDir.open_branch."""
1189
format = self.find_branch_format()
1190
self._check_supported(format, unsupported)
1191
return format.open(self, _found=True)
1193
def open_repository(self, unsupported=False):
1194
"""See BzrDir.open_repository."""
1195
from bzrlib.repository import RepositoryFormat
1196
format = RepositoryFormat.find_format(self)
1197
self._check_supported(format, unsupported)
1198
return format.open(self, _found=True)
1200
def open_workingtree(self, unsupported=False,
1201
recommend_upgrade=True):
1202
"""See BzrDir.open_workingtree."""
1203
from bzrlib.workingtree import WorkingTreeFormat
1204
format = WorkingTreeFormat.find_format(self)
1205
self._check_supported(format, unsupported,
1207
basedir=self.root_transport.base)
1208
return format.open(self, _found=True)
1211
class BzrDirFormat(object):
1212
"""An encapsulation of the initialization and open routines for a format.
1214
Formats provide three things:
1215
* An initialization routine,
1219
Formats are placed in an dict by their format string for reference
1220
during bzrdir opening. These should be subclasses of BzrDirFormat
1223
Once a format is deprecated, just deprecate the initialize and open
1224
methods on the format class. Do not deprecate the object, as the
1225
object will be created every system load.
1228
_default_format = None
1229
"""The default format used for new .bzr dirs."""
1232
"""The known formats."""
1234
_control_formats = []
1235
"""The registered control formats - .bzr, ....
1237
This is a list of BzrDirFormat objects.
1240
_control_server_formats = []
1241
"""The registered control server formats, e.g. RemoteBzrDirs.
1243
This is a list of BzrDirFormat objects.
1246
_lock_file_name = 'branch-lock'
1248
# _lock_class must be set in subclasses to the lock type, typ.
1249
# TransportLock or LockDir
1252
def find_format(klass, transport, _server_formats=True):
1253
"""Return the format present at transport."""
1255
formats = klass._control_server_formats + klass._control_formats
1257
formats = klass._control_formats
1258
for format in formats:
1260
return format.probe_transport(transport)
1261
except errors.NotBranchError:
1262
# this format does not find a control dir here.
1264
raise errors.NotBranchError(path=transport.base)
1267
def probe_transport(klass, transport):
1268
"""Return the .bzrdir style format present in a directory."""
1270
format_string = transport.get(".bzr/branch-format").read()
1271
except errors.NoSuchFile:
1272
raise errors.NotBranchError(path=transport.base)
1275
return klass._formats[format_string]
1277
raise errors.UnknownFormatError(format=format_string)
1280
def get_default_format(klass):
1281
"""Return the current default format."""
1282
return klass._default_format
1284
def get_format_string(self):
1285
"""Return the ASCII format string that identifies this format."""
1286
raise NotImplementedError(self.get_format_string)
1288
def get_format_description(self):
1289
"""Return the short description for this format."""
1290
raise NotImplementedError(self.get_format_description)
1292
def get_converter(self, format=None):
1293
"""Return the converter to use to convert bzrdirs needing converts.
1295
This returns a bzrlib.bzrdir.Converter object.
1297
This should return the best upgrader to step this format towards the
1298
current default format. In the case of plugins we can/should provide
1299
some means for them to extend the range of returnable converters.
1301
:param format: Optional format to override the default format of the
1304
raise NotImplementedError(self.get_converter)
1306
def initialize(self, url, possible_transports=None):
1307
"""Create a bzr control dir at this url and return an opened copy.
1309
Subclasses should typically override initialize_on_transport
1310
instead of this method.
1312
return self.initialize_on_transport(get_transport(url,
1313
possible_transports))
1315
def initialize_on_transport(self, transport):
1316
"""Initialize a new bzrdir in the base directory of a Transport."""
1317
# Since we don't have a .bzr directory, inherit the
1318
# mode from the root directory
1319
temp_control = lockable_files.LockableFiles(transport,
1320
'', lockable_files.TransportLock)
1321
temp_control._transport.mkdir('.bzr',
1322
# FIXME: RBC 20060121 don't peek under
1324
mode=temp_control._dir_mode)
1325
file_mode = temp_control._file_mode
1327
mutter('created control directory in ' + transport.base)
1328
control = transport.clone('.bzr')
1329
utf8_files = [('README',
1330
"This is a Bazaar-NG control directory.\n"
1331
"Do not change any files in this directory.\n"),
1332
('branch-format', self.get_format_string()),
1334
# NB: no need to escape relative paths that are url safe.
1335
control_files = lockable_files.LockableFiles(control,
1336
self._lock_file_name, self._lock_class)
1337
control_files.create_lock()
1338
control_files.lock_write()
1340
for file, content in utf8_files:
1341
control_files.put_utf8(file, content)
1343
control_files.unlock()
1344
return self.open(transport, _found=True)
1346
def is_supported(self):
1347
"""Is this format supported?
1349
Supported formats must be initializable and openable.
1350
Unsupported formats may not support initialization or committing or
1351
some other features depending on the reason for not being supported.
1355
def same_model(self, target_format):
1356
return (self.repository_format.rich_root_data ==
1357
target_format.rich_root_data)
1360
def known_formats(klass):
1361
"""Return all the known formats.
1363
Concrete formats should override _known_formats.
1365
# There is double indirection here to make sure that control
1366
# formats used by more than one dir format will only be probed
1367
# once. This can otherwise be quite expensive for remote connections.
1369
for format in klass._control_formats:
1370
result.update(format._known_formats())
1374
def _known_formats(klass):
1375
"""Return the known format instances for this control format."""
1376
return set(klass._formats.values())
1378
def open(self, transport, _found=False):
1379
"""Return an instance of this format for the dir transport points at.
1381
_found is a private parameter, do not use it.
1384
found_format = BzrDirFormat.find_format(transport)
1385
if not isinstance(found_format, self.__class__):
1386
raise AssertionError("%s was asked to open %s, but it seems to need "
1388
% (self, transport, found_format))
1389
return self._open(transport)
1391
def _open(self, transport):
1392
"""Template method helper for opening BzrDirectories.
1394
This performs the actual open and any additional logic or parameter
1397
raise NotImplementedError(self._open)
1400
def register_format(klass, format):
1401
klass._formats[format.get_format_string()] = format
1404
def register_control_format(klass, format):
1405
"""Register a format that does not use '.bzr' for its control dir.
1407
TODO: This should be pulled up into a 'ControlDirFormat' base class
1408
which BzrDirFormat can inherit from, and renamed to register_format
1409
there. It has been done without that for now for simplicity of
1412
klass._control_formats.append(format)
1415
def register_control_server_format(klass, format):
1416
"""Register a control format for client-server environments.
1418
These formats will be tried before ones registered with
1419
register_control_format. This gives implementations that decide to the
1420
chance to grab it before anything looks at the contents of the format
1423
klass._control_server_formats.append(format)
1426
@symbol_versioning.deprecated_method(symbol_versioning.zero_fourteen)
1427
def set_default_format(klass, format):
1428
klass._set_default_format(format)
1431
def _set_default_format(klass, format):
1432
"""Set default format (for testing behavior of defaults only)"""
1433
klass._default_format = format
1436
return self.get_format_string()[:-1]
1439
def unregister_format(klass, format):
1440
assert klass._formats[format.get_format_string()] is format
1441
del klass._formats[format.get_format_string()]
1444
def unregister_control_format(klass, format):
1445
klass._control_formats.remove(format)
1448
class BzrDirFormat4(BzrDirFormat):
1449
"""Bzr dir format 4.
1451
This format is a combined format for working tree, branch and repository.
1453
- Format 1 working trees [always]
1454
- Format 4 branches [always]
1455
- Format 4 repositories [always]
1457
This format is deprecated: it indexes texts using a text it which is
1458
removed in format 5; write support for this format has been removed.
1461
_lock_class = lockable_files.TransportLock
1463
def get_format_string(self):
1464
"""See BzrDirFormat.get_format_string()."""
1465
return "Bazaar-NG branch, format 0.0.4\n"
1467
def get_format_description(self):
1468
"""See BzrDirFormat.get_format_description()."""
1469
return "All-in-one format 4"
1471
def get_converter(self, format=None):
1472
"""See BzrDirFormat.get_converter()."""
1473
# there is one and only one upgrade path here.
1474
return ConvertBzrDir4To5()
1476
def initialize_on_transport(self, transport):
1477
"""Format 4 branches cannot be created."""
1478
raise errors.UninitializableFormat(self)
1480
def is_supported(self):
1481
"""Format 4 is not supported.
1483
It is not supported because the model changed from 4 to 5 and the
1484
conversion logic is expensive - so doing it on the fly was not
1489
def _open(self, transport):
1490
"""See BzrDirFormat._open."""
1491
return BzrDir4(transport, self)
1493
def __return_repository_format(self):
1494
"""Circular import protection."""
1495
from bzrlib.repofmt.weaverepo import RepositoryFormat4
1496
return RepositoryFormat4()
1497
repository_format = property(__return_repository_format)
1500
class BzrDirFormat5(BzrDirFormat):
1501
"""Bzr control format 5.
1503
This format is a combined format for working tree, branch and repository.
1505
- Format 2 working trees [always]
1506
- Format 4 branches [always]
1507
- Format 5 repositories [always]
1508
Unhashed stores in the repository.
1511
_lock_class = lockable_files.TransportLock
1513
def get_format_string(self):
1514
"""See BzrDirFormat.get_format_string()."""
1515
return "Bazaar-NG branch, format 5\n"
1517
def get_format_description(self):
1518
"""See BzrDirFormat.get_format_description()."""
1519
return "All-in-one format 5"
1521
def get_converter(self, format=None):
1522
"""See BzrDirFormat.get_converter()."""
1523
# there is one and only one upgrade path here.
1524
return ConvertBzrDir5To6()
1526
def _initialize_for_clone(self, url):
1527
return self.initialize_on_transport(get_transport(url), _cloning=True)
1529
def initialize_on_transport(self, transport, _cloning=False):
1530
"""Format 5 dirs always have working tree, branch and repository.
1532
Except when they are being cloned.
1534
from bzrlib.branch import BzrBranchFormat4
1535
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1536
from bzrlib.workingtree import WorkingTreeFormat2
1537
result = (super(BzrDirFormat5, self).initialize_on_transport(transport))
1538
RepositoryFormat5().initialize(result, _internal=True)
1540
branch = BzrBranchFormat4().initialize(result)
1542
WorkingTreeFormat2().initialize(result)
1543
except errors.NotLocalUrl:
1544
# Even though we can't access the working tree, we need to
1545
# create its control files.
1546
WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
1549
def _open(self, transport):
1550
"""See BzrDirFormat._open."""
1551
return BzrDir5(transport, self)
1553
def __return_repository_format(self):
1554
"""Circular import protection."""
1555
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1556
return RepositoryFormat5()
1557
repository_format = property(__return_repository_format)
1560
class BzrDirFormat6(BzrDirFormat):
1561
"""Bzr control format 6.
1563
This format is a combined format for working tree, branch and repository.
1565
- Format 2 working trees [always]
1566
- Format 4 branches [always]
1567
- Format 6 repositories [always]
1570
_lock_class = lockable_files.TransportLock
1572
def get_format_string(self):
1573
"""See BzrDirFormat.get_format_string()."""
1574
return "Bazaar-NG branch, format 6\n"
1576
def get_format_description(self):
1577
"""See BzrDirFormat.get_format_description()."""
1578
return "All-in-one format 6"
1580
def get_converter(self, format=None):
1581
"""See BzrDirFormat.get_converter()."""
1582
# there is one and only one upgrade path here.
1583
return ConvertBzrDir6ToMeta()
1585
def _initialize_for_clone(self, url):
1586
return self.initialize_on_transport(get_transport(url), _cloning=True)
1588
def initialize_on_transport(self, transport, _cloning=False):
1589
"""Format 6 dirs always have working tree, branch and repository.
1591
Except when they are being cloned.
1593
from bzrlib.branch import BzrBranchFormat4
1594
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1595
from bzrlib.workingtree import WorkingTreeFormat2
1596
result = super(BzrDirFormat6, self).initialize_on_transport(transport)
1597
RepositoryFormat6().initialize(result, _internal=True)
1599
branch = BzrBranchFormat4().initialize(result)
1601
WorkingTreeFormat2().initialize(result)
1602
except errors.NotLocalUrl:
1603
# Even though we can't access the working tree, we need to
1604
# create its control files.
1605
WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
1608
def _open(self, transport):
1609
"""See BzrDirFormat._open."""
1610
return BzrDir6(transport, self)
1612
def __return_repository_format(self):
1613
"""Circular import protection."""
1614
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1615
return RepositoryFormat6()
1616
repository_format = property(__return_repository_format)
1619
class BzrDirMetaFormat1(BzrDirFormat):
1620
"""Bzr meta control format 1
1622
This is the first format with split out working tree, branch and repository
1625
- Format 3 working trees [optional]
1626
- Format 5 branches [optional]
1627
- Format 7 repositories [optional]
1630
_lock_class = lockdir.LockDir
1633
self._workingtree_format = None
1634
self._branch_format = None
1636
def __eq__(self, other):
1637
if other.__class__ is not self.__class__:
1639
if other.repository_format != self.repository_format:
1641
if other.workingtree_format != self.workingtree_format:
1645
def __ne__(self, other):
1646
return not self == other
1648
def get_branch_format(self):
1649
if self._branch_format is None:
1650
from bzrlib.branch import BranchFormat
1651
self._branch_format = BranchFormat.get_default_format()
1652
return self._branch_format
1654
def set_branch_format(self, format):
1655
self._branch_format = format
1657
def get_converter(self, format=None):
1658
"""See BzrDirFormat.get_converter()."""
1660
format = BzrDirFormat.get_default_format()
1661
if not isinstance(self, format.__class__):
1662
# converting away from metadir is not implemented
1663
raise NotImplementedError(self.get_converter)
1664
return ConvertMetaToMeta(format)
1666
def get_format_string(self):
1667
"""See BzrDirFormat.get_format_string()."""
1668
return "Bazaar-NG meta directory, format 1\n"
1670
def get_format_description(self):
1671
"""See BzrDirFormat.get_format_description()."""
1672
return "Meta directory format 1"
1674
def _open(self, transport):
1675
"""See BzrDirFormat._open."""
1676
return BzrDirMeta1(transport, self)
1678
def __return_repository_format(self):
1679
"""Circular import protection."""
1680
if getattr(self, '_repository_format', None):
1681
return self._repository_format
1682
from bzrlib.repository import RepositoryFormat
1683
return RepositoryFormat.get_default_format()
1685
def __set_repository_format(self, value):
1686
"""Allow changint the repository format for metadir formats."""
1687
self._repository_format = value
1689
repository_format = property(__return_repository_format, __set_repository_format)
1691
def __get_workingtree_format(self):
1692
if self._workingtree_format is None:
1693
from bzrlib.workingtree import WorkingTreeFormat
1694
self._workingtree_format = WorkingTreeFormat.get_default_format()
1695
return self._workingtree_format
1697
def __set_workingtree_format(self, wt_format):
1698
self._workingtree_format = wt_format
1700
workingtree_format = property(__get_workingtree_format,
1701
__set_workingtree_format)
1704
# Register bzr control format
1705
BzrDirFormat.register_control_format(BzrDirFormat)
1707
# Register bzr formats
1708
BzrDirFormat.register_format(BzrDirFormat4())
1709
BzrDirFormat.register_format(BzrDirFormat5())
1710
BzrDirFormat.register_format(BzrDirFormat6())
1711
__default_format = BzrDirMetaFormat1()
1712
BzrDirFormat.register_format(__default_format)
1713
BzrDirFormat._default_format = __default_format
1716
class Converter(object):
1717
"""Converts a disk format object from one format to another."""
1719
def convert(self, to_convert, pb):
1720
"""Perform the conversion of to_convert, giving feedback via pb.
1722
:param to_convert: The disk object to convert.
1723
:param pb: a progress bar to use for progress information.
1726
def step(self, message):
1727
"""Update the pb by a step."""
1729
self.pb.update(message, self.count, self.total)
1732
class ConvertBzrDir4To5(Converter):
1733
"""Converts format 4 bzr dirs to format 5."""
1736
super(ConvertBzrDir4To5, self).__init__()
1737
self.converted_revs = set()
1738
self.absent_revisions = set()
1742
def convert(self, to_convert, pb):
1743
"""See Converter.convert()."""
1744
self.bzrdir = to_convert
1746
self.pb.note('starting upgrade from format 4 to 5')
1747
if isinstance(self.bzrdir.transport, LocalTransport):
1748
self.bzrdir.get_workingtree_transport(None).delete('stat-cache')
1749
self._convert_to_weaves()
1750
return BzrDir.open(self.bzrdir.root_transport.base)
1752
def _convert_to_weaves(self):
1753
self.pb.note('note: upgrade may be faster if all store files are ungzipped first')
1756
stat = self.bzrdir.transport.stat('weaves')
1757
if not S_ISDIR(stat.st_mode):
1758
self.bzrdir.transport.delete('weaves')
1759
self.bzrdir.transport.mkdir('weaves')
1760
except errors.NoSuchFile:
1761
self.bzrdir.transport.mkdir('weaves')
1762
# deliberately not a WeaveFile as we want to build it up slowly.
1763
self.inv_weave = Weave('inventory')
1764
# holds in-memory weaves for all files
1765
self.text_weaves = {}
1766
self.bzrdir.transport.delete('branch-format')
1767
self.branch = self.bzrdir.open_branch()
1768
self._convert_working_inv()
1769
rev_history = self.branch.revision_history()
1770
# to_read is a stack holding the revisions we still need to process;
1771
# appending to it adds new highest-priority revisions
1772
self.known_revisions = set(rev_history)
1773
self.to_read = rev_history[-1:]
1775
rev_id = self.to_read.pop()
1776
if (rev_id not in self.revisions
1777
and rev_id not in self.absent_revisions):
1778
self._load_one_rev(rev_id)
1780
to_import = self._make_order()
1781
for i, rev_id in enumerate(to_import):
1782
self.pb.update('converting revision', i, len(to_import))
1783
self._convert_one_rev(rev_id)
1785
self._write_all_weaves()
1786
self._write_all_revs()
1787
self.pb.note('upgraded to weaves:')
1788
self.pb.note(' %6d revisions and inventories', len(self.revisions))
1789
self.pb.note(' %6d revisions not present', len(self.absent_revisions))
1790
self.pb.note(' %6d texts', self.text_count)
1791
self._cleanup_spare_files_after_format4()
1792
self.branch.control_files.put_utf8('branch-format', BzrDirFormat5().get_format_string())
1794
def _cleanup_spare_files_after_format4(self):
1795
# FIXME working tree upgrade foo.
1796
for n in 'merged-patches', 'pending-merged-patches':
1798
## assert os.path.getsize(p) == 0
1799
self.bzrdir.transport.delete(n)
1800
except errors.NoSuchFile:
1802
self.bzrdir.transport.delete_tree('inventory-store')
1803
self.bzrdir.transport.delete_tree('text-store')
1805
def _convert_working_inv(self):
1806
inv = xml4.serializer_v4.read_inventory(
1807
self.branch.control_files.get('inventory'))
1808
new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv, working=True)
1809
# FIXME inventory is a working tree change.
1810
self.branch.control_files.put('inventory', StringIO(new_inv_xml))
1812
def _write_all_weaves(self):
1813
controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)
1814
weave_transport = self.bzrdir.transport.clone('weaves')
1815
weaves = WeaveStore(weave_transport, prefixed=False)
1816
transaction = WriteTransaction()
1820
for file_id, file_weave in self.text_weaves.items():
1821
self.pb.update('writing weave', i, len(self.text_weaves))
1822
weaves._put_weave(file_id, file_weave, transaction)
1824
self.pb.update('inventory', 0, 1)
1825
controlweaves._put_weave('inventory', self.inv_weave, transaction)
1826
self.pb.update('inventory', 1, 1)
1830
def _write_all_revs(self):
1831
"""Write all revisions out in new form."""
1832
self.bzrdir.transport.delete_tree('revision-store')
1833
self.bzrdir.transport.mkdir('revision-store')
1834
revision_transport = self.bzrdir.transport.clone('revision-store')
1836
_revision_store = TextRevisionStore(TextStore(revision_transport,
1840
transaction = WriteTransaction()
1841
for i, rev_id in enumerate(self.converted_revs):
1842
self.pb.update('write revision', i, len(self.converted_revs))
1843
_revision_store.add_revision(self.revisions[rev_id], transaction)
1847
def _load_one_rev(self, rev_id):
1848
"""Load a revision object into memory.
1850
Any parents not either loaded or abandoned get queued to be
1852
self.pb.update('loading revision',
1853
len(self.revisions),
1854
len(self.known_revisions))
1855
if not self.branch.repository.has_revision(rev_id):
1857
self.pb.note('revision {%s} not present in branch; '
1858
'will be converted as a ghost',
1860
self.absent_revisions.add(rev_id)
1862
rev = self.branch.repository._revision_store.get_revision(rev_id,
1863
self.branch.repository.get_transaction())
1864
for parent_id in rev.parent_ids:
1865
self.known_revisions.add(parent_id)
1866
self.to_read.append(parent_id)
1867
self.revisions[rev_id] = rev
1869
def _load_old_inventory(self, rev_id):
1870
assert rev_id not in self.converted_revs
1871
old_inv_xml = self.branch.repository.inventory_store.get(rev_id).read()
1872
inv = xml4.serializer_v4.read_inventory_from_string(old_inv_xml)
1873
inv.revision_id = rev_id
1874
rev = self.revisions[rev_id]
1875
if rev.inventory_sha1:
1876
assert rev.inventory_sha1 == sha_string(old_inv_xml), \
1877
'inventory sha mismatch for {%s}' % rev_id
1880
def _load_updated_inventory(self, rev_id):
1881
assert rev_id in self.converted_revs
1882
inv_xml = self.inv_weave.get_text(rev_id)
1883
inv = xml5.serializer_v5.read_inventory_from_string(inv_xml)
1886
def _convert_one_rev(self, rev_id):
1887
"""Convert revision and all referenced objects to new format."""
1888
rev = self.revisions[rev_id]
1889
inv = self._load_old_inventory(rev_id)
1890
present_parents = [p for p in rev.parent_ids
1891
if p not in self.absent_revisions]
1892
self._convert_revision_contents(rev, inv, present_parents)
1893
self._store_new_inv(rev, inv, present_parents)
1894
self.converted_revs.add(rev_id)
1896
def _store_new_inv(self, rev, inv, present_parents):
1897
# the XML is now updated with text versions
1899
entries = inv.iter_entries()
1901
for path, ie in entries:
1902
assert getattr(ie, 'revision', None) is not None, \
1903
'no revision on {%s} in {%s}' % \
1904
(file_id, rev.revision_id)
1905
new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
1906
new_inv_sha1 = sha_string(new_inv_xml)
1907
self.inv_weave.add_lines(rev.revision_id,
1909
new_inv_xml.splitlines(True))
1910
rev.inventory_sha1 = new_inv_sha1
1912
def _convert_revision_contents(self, rev, inv, present_parents):
1913
"""Convert all the files within a revision.
1915
Also upgrade the inventory to refer to the text revision ids."""
1916
rev_id = rev.revision_id
1917
mutter('converting texts of revision {%s}',
1919
parent_invs = map(self._load_updated_inventory, present_parents)
1920
entries = inv.iter_entries()
1922
for path, ie in entries:
1923
self._convert_file_version(rev, ie, parent_invs)
1925
def _convert_file_version(self, rev, ie, parent_invs):
1926
"""Convert one version of one file.
1928
The file needs to be added into the weave if it is a merge
1929
of >=2 parents or if it's changed from its parent.
1931
file_id = ie.file_id
1932
rev_id = rev.revision_id
1933
w = self.text_weaves.get(file_id)
1936
self.text_weaves[file_id] = w
1937
text_changed = False
1938
parent_candiate_entries = ie.parent_candidates(parent_invs)
1939
for old_revision in parent_candiate_entries.keys():
1940
# if this fails, its a ghost ?
1941
assert old_revision in self.converted_revs, \
1942
"Revision {%s} not in converted_revs" % old_revision
1943
heads = graph.Graph(self).heads(parent_candiate_entries.keys())
1944
# XXX: Note that this is unordered - and this is tolerable because
1945
# the previous code was also unordered.
1946
previous_entries = dict((head, parent_candiate_entries[head]) for head
1948
self.snapshot_ie(previous_entries, ie, w, rev_id)
1950
assert getattr(ie, 'revision', None) is not None
1952
def get_parents(self, revision_ids):
1953
for revision_id in revision_ids:
1954
yield self.revisions[revision_id].parent_ids
1956
def snapshot_ie(self, previous_revisions, ie, w, rev_id):
1957
# TODO: convert this logic, which is ~= snapshot to
1958
# a call to:. This needs the path figured out. rather than a work_tree
1959
# a v4 revision_tree can be given, or something that looks enough like
1960
# one to give the file content to the entry if it needs it.
1961
# and we need something that looks like a weave store for snapshot to
1963
#ie.snapshot(rev, PATH, previous_revisions, REVISION_TREE, InMemoryWeaveStore(self.text_weaves))
1964
if len(previous_revisions) == 1:
1965
previous_ie = previous_revisions.values()[0]
1966
if ie._unchanged(previous_ie):
1967
ie.revision = previous_ie.revision
1970
text = self.branch.repository.weave_store.get(ie.text_id)
1971
file_lines = text.readlines()
1972
assert sha_strings(file_lines) == ie.text_sha1
1973
assert sum(map(len, file_lines)) == ie.text_size
1974
w.add_lines(rev_id, previous_revisions, file_lines)
1975
self.text_count += 1
1977
w.add_lines(rev_id, previous_revisions, [])
1978
ie.revision = rev_id
1980
def _make_order(self):
1981
"""Return a suitable order for importing revisions.
1983
The order must be such that an revision is imported after all
1984
its (present) parents.
1986
todo = set(self.revisions.keys())
1987
done = self.absent_revisions.copy()
1990
# scan through looking for a revision whose parents
1992
for rev_id in sorted(list(todo)):
1993
rev = self.revisions[rev_id]
1994
parent_ids = set(rev.parent_ids)
1995
if parent_ids.issubset(done):
1996
# can take this one now
1997
order.append(rev_id)
2003
class ConvertBzrDir5To6(Converter):
2004
"""Converts format 5 bzr dirs to format 6."""
2006
def convert(self, to_convert, pb):
2007
"""See Converter.convert()."""
2008
self.bzrdir = to_convert
2010
self.pb.note('starting upgrade from format 5 to 6')
2011
self._convert_to_prefixed()
2012
return BzrDir.open(self.bzrdir.root_transport.base)
2014
def _convert_to_prefixed(self):
2015
from bzrlib.store import TransportStore
2016
self.bzrdir.transport.delete('branch-format')
2017
for store_name in ["weaves", "revision-store"]:
2018
self.pb.note("adding prefixes to %s" % store_name)
2019
store_transport = self.bzrdir.transport.clone(store_name)
2020
store = TransportStore(store_transport, prefixed=True)
2021
for urlfilename in store_transport.list_dir('.'):
2022
filename = urlutils.unescape(urlfilename)
2023
if (filename.endswith(".weave") or
2024
filename.endswith(".gz") or
2025
filename.endswith(".sig")):
2026
file_id = os.path.splitext(filename)[0]
2029
prefix_dir = store.hash_prefix(file_id)
2030
# FIXME keep track of the dirs made RBC 20060121
2032
store_transport.move(filename, prefix_dir + '/' + filename)
2033
except errors.NoSuchFile: # catches missing dirs strangely enough
2034
store_transport.mkdir(prefix_dir)
2035
store_transport.move(filename, prefix_dir + '/' + filename)
2036
self.bzrdir._control_files.put_utf8('branch-format', BzrDirFormat6().get_format_string())
2039
class ConvertBzrDir6ToMeta(Converter):
2040
"""Converts format 6 bzr dirs to metadirs."""
2042
def convert(self, to_convert, pb):
2043
"""See Converter.convert()."""
2044
from bzrlib.repofmt.weaverepo import RepositoryFormat7
2045
from bzrlib.branch import BzrBranchFormat5
2046
self.bzrdir = to_convert
2049
self.total = 20 # the steps we know about
2050
self.garbage_inventories = []
2052
self.pb.note('starting upgrade from format 6 to metadir')
2053
self.bzrdir._control_files.put_utf8('branch-format', "Converting to format 6")
2054
# its faster to move specific files around than to open and use the apis...
2055
# first off, nuke ancestry.weave, it was never used.
2057
self.step('Removing ancestry.weave')
2058
self.bzrdir.transport.delete('ancestry.weave')
2059
except errors.NoSuchFile:
2061
# find out whats there
2062
self.step('Finding branch files')
2063
last_revision = self.bzrdir.open_branch().last_revision()
2064
bzrcontents = self.bzrdir.transport.list_dir('.')
2065
for name in bzrcontents:
2066
if name.startswith('basis-inventory.'):
2067
self.garbage_inventories.append(name)
2068
# create new directories for repository, working tree and branch
2069
self.dir_mode = self.bzrdir._control_files._dir_mode
2070
self.file_mode = self.bzrdir._control_files._file_mode
2071
repository_names = [('inventory.weave', True),
2072
('revision-store', True),
2074
self.step('Upgrading repository ')
2075
self.bzrdir.transport.mkdir('repository', mode=self.dir_mode)
2076
self.make_lock('repository')
2077
# we hard code the formats here because we are converting into
2078
# the meta format. The meta format upgrader can take this to a
2079
# future format within each component.
2080
self.put_format('repository', RepositoryFormat7())
2081
for entry in repository_names:
2082
self.move_entry('repository', entry)
2084
self.step('Upgrading branch ')
2085
self.bzrdir.transport.mkdir('branch', mode=self.dir_mode)
2086
self.make_lock('branch')
2087
self.put_format('branch', BzrBranchFormat5())
2088
branch_files = [('revision-history', True),
2089
('branch-name', True),
2091
for entry in branch_files:
2092
self.move_entry('branch', entry)
2094
checkout_files = [('pending-merges', True),
2095
('inventory', True),
2096
('stat-cache', False)]
2097
# If a mandatory checkout file is not present, the branch does not have
2098
# a functional checkout. Do not create a checkout in the converted
2100
for name, mandatory in checkout_files:
2101
if mandatory and name not in bzrcontents:
2102
has_checkout = False
2106
if not has_checkout:
2107
self.pb.note('No working tree.')
2108
# If some checkout files are there, we may as well get rid of them.
2109
for name, mandatory in checkout_files:
2110
if name in bzrcontents:
2111
self.bzrdir.transport.delete(name)
2113
from bzrlib.workingtree import WorkingTreeFormat3
2114
self.step('Upgrading working tree')
2115
self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
2116
self.make_lock('checkout')
2118
'checkout', WorkingTreeFormat3())
2119
self.bzrdir.transport.delete_multi(
2120
self.garbage_inventories, self.pb)
2121
for entry in checkout_files:
2122
self.move_entry('checkout', entry)
2123
if last_revision is not None:
2124
self.bzrdir._control_files.put_utf8(
2125
'checkout/last-revision', last_revision)
2126
self.bzrdir._control_files.put_utf8(
2127
'branch-format', BzrDirMetaFormat1().get_format_string())
2128
return BzrDir.open(self.bzrdir.root_transport.base)
2130
def make_lock(self, name):
2131
"""Make a lock for the new control dir name."""
2132
self.step('Make %s lock' % name)
2133
ld = lockdir.LockDir(self.bzrdir.transport,
2135
file_modebits=self.file_mode,
2136
dir_modebits=self.dir_mode)
2139
def move_entry(self, new_dir, entry):
2140
"""Move then entry name into new_dir."""
2142
mandatory = entry[1]
2143
self.step('Moving %s' % name)
2145
self.bzrdir.transport.move(name, '%s/%s' % (new_dir, name))
2146
except errors.NoSuchFile:
2150
def put_format(self, dirname, format):
2151
self.bzrdir._control_files.put_utf8('%s/format' % dirname, format.get_format_string())
2154
class ConvertMetaToMeta(Converter):
2155
"""Converts the components of metadirs."""
2157
def __init__(self, target_format):
2158
"""Create a metadir to metadir converter.
2160
:param target_format: The final metadir format that is desired.
2162
self.target_format = target_format
2164
def convert(self, to_convert, pb):
2165
"""See Converter.convert()."""
2166
self.bzrdir = to_convert
2170
self.step('checking repository format')
2172
repo = self.bzrdir.open_repository()
2173
except errors.NoRepositoryPresent:
2176
if not isinstance(repo._format, self.target_format.repository_format.__class__):
2177
from bzrlib.repository import CopyConverter
2178
self.pb.note('starting repository conversion')
2179
converter = CopyConverter(self.target_format.repository_format)
2180
converter.convert(repo, pb)
2182
branch = self.bzrdir.open_branch()
2183
except errors.NotBranchError:
2186
# TODO: conversions of Branch and Tree should be done by
2187
# InterXFormat lookups
2188
# Avoid circular imports
2189
from bzrlib import branch as _mod_branch
2190
if (branch._format.__class__ is _mod_branch.BzrBranchFormat5 and
2191
self.target_format.get_branch_format().__class__ is
2192
_mod_branch.BzrBranchFormat6):
2193
branch_converter = _mod_branch.Converter5to6()
2194
branch_converter.convert(branch)
2196
tree = self.bzrdir.open_workingtree(recommend_upgrade=False)
2197
except (errors.NoWorkingTree, errors.NotLocalUrl):
2200
# TODO: conversions of Branch and Tree should be done by
2201
# InterXFormat lookups
2202
if (isinstance(tree, workingtree.WorkingTree3) and
2203
not isinstance(tree, workingtree_4.WorkingTree4) and
2204
isinstance(self.target_format.workingtree_format,
2205
workingtree_4.WorkingTreeFormat4)):
2206
workingtree_4.Converter3to4().convert(tree)
2210
# This is not in remote.py because it's small, and needs to be registered.
2211
# Putting it in remote.py creates a circular import problem.
2212
# we can make it a lazy object if the control formats is turned into something
2214
class RemoteBzrDirFormat(BzrDirMetaFormat1):
2215
"""Format representing bzrdirs accessed via a smart server"""
2217
def get_format_description(self):
2218
return 'bzr remote bzrdir'
2221
def probe_transport(klass, transport):
2222
"""Return a RemoteBzrDirFormat object if it looks possible."""
2224
client = transport.get_smart_client()
2225
except (NotImplementedError, AttributeError,
2226
errors.TransportNotPossible):
2227
# no smart server, so not a branch for this format type.
2228
raise errors.NotBranchError(path=transport.base)
2230
# Send a 'hello' request in protocol version one, and decline to
2231
# open it if the server doesn't support our required version (2) so
2232
# that the VFS-based transport will do it.
2233
request = client.get_request()
2234
smart_protocol = protocol.SmartClientRequestProtocolOne(request)
2235
server_version = smart_protocol.query_version()
2236
if server_version != 2:
2237
raise errors.NotBranchError(path=transport.base)
2240
def initialize_on_transport(self, transport):
2242
# hand off the request to the smart server
2243
shared_medium = transport.get_shared_medium()
2244
except errors.NoSmartMedium:
2245
# TODO: lookup the local format from a server hint.
2246
local_dir_format = BzrDirMetaFormat1()
2247
return local_dir_format.initialize_on_transport(transport)
2248
client = _SmartClient(shared_medium)
2249
path = client.remote_path_from_transport(transport)
2250
response = _SmartClient(shared_medium).call('BzrDirFormat.initialize',
2252
assert response[0] in ('ok', ), 'unexpected response code %s' % (response,)
2253
return remote.RemoteBzrDir(transport)
2255
def _open(self, transport):
2256
return remote.RemoteBzrDir(transport)
2258
def __eq__(self, other):
2259
if not isinstance(other, RemoteBzrDirFormat):
2261
return self.get_format_description() == other.get_format_description()
2264
BzrDirFormat.register_control_server_format(RemoteBzrDirFormat)
2267
class BzrDirFormatInfo(object):
2269
def __init__(self, native, deprecated, hidden):
2270
self.deprecated = deprecated
2271
self.native = native
2272
self.hidden = hidden
2275
class BzrDirFormatRegistry(registry.Registry):
2276
"""Registry of user-selectable BzrDir subformats.
2278
Differs from BzrDirFormat._control_formats in that it provides sub-formats,
2279
e.g. BzrDirMeta1 with weave repository. Also, it's more user-oriented.
2282
def register_metadir(self, key,
2283
repository_format, help, native=True, deprecated=False,
2287
"""Register a metadir subformat.
2289
These all use a BzrDirMetaFormat1 bzrdir, but can be parameterized
2290
by the Repository format.
2292
:param repository_format: The fully-qualified repository format class
2294
:param branch_format: Fully-qualified branch format class name as
2296
:param tree_format: Fully-qualified tree format class name as
2299
# This should be expanded to support setting WorkingTree and Branch
2300
# formats, once BzrDirMetaFormat1 supports that.
2301
def _load(full_name):
2302
mod_name, factory_name = full_name.rsplit('.', 1)
2304
mod = __import__(mod_name, globals(), locals(),
2306
except ImportError, e:
2307
raise ImportError('failed to load %s: %s' % (full_name, e))
2309
factory = getattr(mod, factory_name)
2310
except AttributeError:
2311
raise AttributeError('no factory %s in module %r'
2316
bd = BzrDirMetaFormat1()
2317
if branch_format is not None:
2318
bd.set_branch_format(_load(branch_format))
2319
if tree_format is not None:
2320
bd.workingtree_format = _load(tree_format)
2321
if repository_format is not None:
2322
bd.repository_format = _load(repository_format)
2324
self.register(key, helper, help, native, deprecated, hidden)
2326
def register(self, key, factory, help, native=True, deprecated=False,
2328
"""Register a BzrDirFormat factory.
2330
The factory must be a callable that takes one parameter: the key.
2331
It must produce an instance of the BzrDirFormat when called.
2333
This function mainly exists to prevent the info object from being
2336
registry.Registry.register(self, key, factory, help,
2337
BzrDirFormatInfo(native, deprecated, hidden))
2339
def register_lazy(self, key, module_name, member_name, help, native=True,
2340
deprecated=False, hidden=False):
2341
registry.Registry.register_lazy(self, key, module_name, member_name,
2342
help, BzrDirFormatInfo(native, deprecated, hidden))
2344
def set_default(self, key):
2345
"""Set the 'default' key to be a clone of the supplied key.
2347
This method must be called once and only once.
2349
registry.Registry.register(self, 'default', self.get(key),
2350
self.get_help(key), info=self.get_info(key))
2352
def set_default_repository(self, key):
2353
"""Set the FormatRegistry default and Repository default.
2355
This is a transitional method while Repository.set_default_format
2358
if 'default' in self:
2359
self.remove('default')
2360
self.set_default(key)
2361
format = self.get('default')()
2362
assert isinstance(format, BzrDirMetaFormat1)
2364
def make_bzrdir(self, key):
2365
return self.get(key)()
2367
def help_topic(self, topic):
2368
output = textwrap.dedent("""\
2369
These formats can be used for creating branches, working trees, and
2373
default_realkey = None
2374
default_help = self.get_help('default')
2376
for key in self.keys():
2377
if key == 'default':
2379
help = self.get_help(key)
2380
if help == default_help:
2381
default_realkey = key
2383
help_pairs.append((key, help))
2385
def wrapped(key, help, info):
2387
help = '(native) ' + help
2388
return ':%s:\n%s\n\n' % (key,
2389
textwrap.fill(help, initial_indent=' ',
2390
subsequent_indent=' '))
2391
if default_realkey is not None:
2392
output += wrapped(default_realkey, '(default) %s' % default_help,
2393
self.get_info('default'))
2394
deprecated_pairs = []
2395
for key, help in help_pairs:
2396
info = self.get_info(key)
2399
elif info.deprecated:
2400
deprecated_pairs.append((key, help))
2402
output += wrapped(key, help, info)
2403
if len(deprecated_pairs) > 0:
2404
output += "Deprecated formats are shown below.\n\n"
2405
for key, help in deprecated_pairs:
2406
info = self.get_info(key)
2407
output += wrapped(key, help, info)
2412
format_registry = BzrDirFormatRegistry()
2413
format_registry.register('weave', BzrDirFormat6,
2414
'Pre-0.8 format. Slower than knit and does not'
2415
' support checkouts or shared repositories.',
2417
format_registry.register_metadir('knit',
2418
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2419
'Format using knits. Recommended for interoperation with bzr <= 0.14.',
2420
branch_format='bzrlib.branch.BzrBranchFormat5',
2421
tree_format='bzrlib.workingtree.WorkingTreeFormat3')
2422
format_registry.register_metadir('metaweave',
2423
'bzrlib.repofmt.weaverepo.RepositoryFormat7',
2424
'Transitional format in 0.8. Slower than knit.',
2425
branch_format='bzrlib.branch.BzrBranchFormat5',
2426
tree_format='bzrlib.workingtree.WorkingTreeFormat3',
2428
format_registry.register_metadir('dirstate',
2429
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2430
help='New in 0.15: Fast local operations. Compatible with bzr 0.8 and '
2431
'above when accessed over the network.',
2432
branch_format='bzrlib.branch.BzrBranchFormat5',
2433
# this uses bzrlib.workingtree.WorkingTreeFormat4 because importing
2434
# directly from workingtree_4 triggers a circular import.
2435
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2437
format_registry.register_metadir('dirstate-tags',
2438
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2439
help='New in 0.15: Fast local operations and improved scaling for '
2440
'network operations. Additionally adds support for tags.'
2441
' Incompatible with bzr < 0.15.',
2442
branch_format='bzrlib.branch.BzrBranchFormat6',
2443
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2445
format_registry.register_metadir('dirstate-with-subtree',
2446
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
2447
help='New in 0.15: Fast local operations and improved scaling for '
2448
'network operations. Additionally adds support for versioning nested '
2449
'bzr branches. Incompatible with bzr < 0.15.',
2450
branch_format='bzrlib.branch.BzrBranchFormat6',
2451
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2454
format_registry.register_metadir('experimental',
2455
'bzrlib.repofmt.pack_repo.RepositoryFormatGraphKnit1',
2456
help='New in XXX: Experimental format with data compatible with dirstate '
2457
'format repositories. Cannot be read except with bzr.dev. '
2458
'WARNING: This format is unstable and data in it will not be upgradable'
2459
' to release formats of bzr.',
2460
branch_format='bzrlib.branch.BzrBranchFormat6',
2461
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2464
format_registry.register_metadir('experimental-subtree',
2465
'bzrlib.repofmt.pack_repo.RepositoryFormatGraphKnit3',
2466
help='New in XXX: Experimental format with data compatible with '
2467
'dirstate-with-subtree format repositories. Cannot be read except with'
2468
' bzr.dev. WARNING: This format is unstable and data in it will not be'
2469
' upgradable to release formats of bzr.',
2470
branch_format='bzrlib.branch.BzrBranchFormat6',
2471
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2474
format_registry.set_default('dirstate-tags')