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)
247
def destroy_branch(self):
248
"""Destroy the branch in this BzrDir"""
249
raise NotImplementedError(self.destroy_branch)
252
def create_branch_and_repo(base, force_new_repo=False, format=None):
253
"""Create a new BzrDir, Branch and Repository at the url 'base'.
255
This will use the current default BzrDirFormat, and use whatever
256
repository format that that uses via bzrdir.create_branch and
257
create_repository. If a shared repository is available that is used
260
The created Branch object is returned.
262
:param base: The URL to create the branch at.
263
:param force_new_repo: If True a new repository is always created.
265
bzrdir = BzrDir.create(base, format)
266
bzrdir._find_or_create_repository(force_new_repo)
267
return bzrdir.create_branch()
269
def _find_or_create_repository(self, force_new_repo):
270
"""Create a new repository if needed, returning the repository."""
272
return self.create_repository()
274
return self.find_repository()
275
except errors.NoRepositoryPresent:
276
return self.create_repository()
279
def create_branch_convenience(base, force_new_repo=False,
280
force_new_tree=None, format=None,
281
possible_transports=None):
282
"""Create a new BzrDir, Branch and Repository at the url 'base'.
284
This is a convenience function - it will use an existing repository
285
if possible, can be told explicitly whether to create a working tree or
288
This will use the current default BzrDirFormat, and use whatever
289
repository format that that uses via bzrdir.create_branch and
290
create_repository. If a shared repository is available that is used
291
preferentially. Whatever repository is used, its tree creation policy
294
The created Branch object is returned.
295
If a working tree cannot be made due to base not being a file:// url,
296
no error is raised unless force_new_tree is True, in which case no
297
data is created on disk and NotLocalUrl is raised.
299
:param base: The URL to create the branch at.
300
:param force_new_repo: If True a new repository is always created.
301
:param force_new_tree: If True or False force creation of a tree or
302
prevent such creation respectively.
303
:param format: Override for the for the bzrdir format to create.
304
:param possible_transports: An optional reusable transports list.
307
# check for non local urls
308
t = get_transport(base, possible_transports)
309
if not isinstance(t, LocalTransport):
310
raise errors.NotLocalUrl(base)
311
bzrdir = BzrDir.create(base, format, possible_transports)
312
repo = bzrdir._find_or_create_repository(force_new_repo)
313
result = bzrdir.create_branch()
314
if force_new_tree or (repo.make_working_trees() and
315
force_new_tree is None):
317
bzrdir.create_workingtree()
318
except errors.NotLocalUrl:
323
@deprecated_function(zero_ninetyone)
324
def create_repository(base, shared=False, format=None):
325
"""Create a new BzrDir and Repository at the url 'base'.
327
If no format is supplied, this will default to the current default
328
BzrDirFormat by default, and use whatever repository format that that
329
uses for bzrdirformat.create_repository.
331
:param shared: Create a shared repository rather than a standalone
333
The Repository object is returned.
335
This must be overridden as an instance method in child classes, where
336
it should take no parameters and construct whatever repository format
337
that child class desires.
339
This method is deprecated, please call create_repository on a bzrdir
342
bzrdir = BzrDir.create(base, format)
343
return bzrdir.create_repository(shared)
346
def create_standalone_workingtree(base, format=None):
347
"""Create a new BzrDir, WorkingTree, Branch and Repository at 'base'.
349
'base' must be a local path or a file:// url.
351
This will use the current default BzrDirFormat, and use whatever
352
repository format that that uses for bzrdirformat.create_workingtree,
353
create_branch and create_repository.
355
:return: The WorkingTree object.
357
t = get_transport(base)
358
if not isinstance(t, LocalTransport):
359
raise errors.NotLocalUrl(base)
360
bzrdir = BzrDir.create_branch_and_repo(base,
362
format=format).bzrdir
363
return bzrdir.create_workingtree()
365
def create_workingtree(self, revision_id=None):
366
"""Create a working tree at this BzrDir.
368
revision_id: create it as of this revision id.
370
raise NotImplementedError(self.create_workingtree)
372
def retire_bzrdir(self):
373
"""Permanently disable the bzrdir.
375
This is done by renaming it to give the user some ability to recover
376
if there was a problem.
378
This will have horrible consequences if anyone has anything locked or
381
for i in xrange(10000):
383
to_path = '.bzr.retired.%d' % i
384
self.root_transport.rename('.bzr', to_path)
385
note("renamed %s to %s"
386
% (self.root_transport.abspath('.bzr'), to_path))
388
except (errors.TransportError, IOError, errors.PathError):
391
def destroy_workingtree(self):
392
"""Destroy the working tree at this BzrDir.
394
Formats that do not support this may raise UnsupportedOperation.
396
raise NotImplementedError(self.destroy_workingtree)
398
def destroy_workingtree_metadata(self):
399
"""Destroy the control files for the working tree at this BzrDir.
401
The contents of working tree files are not affected.
402
Formats that do not support this may raise UnsupportedOperation.
404
raise NotImplementedError(self.destroy_workingtree_metadata)
406
def find_repository(self):
407
"""Find the repository that should be used for a_bzrdir.
409
This does not require a branch as we use it to find the repo for
410
new branches as well as to hook existing branches up to their
414
return self.open_repository()
415
except errors.NoRepositoryPresent:
417
next_transport = self.root_transport.clone('..')
419
# find the next containing bzrdir
421
found_bzrdir = BzrDir.open_containing_from_transport(
423
except errors.NotBranchError:
425
raise errors.NoRepositoryPresent(self)
426
# does it have a repository ?
428
repository = found_bzrdir.open_repository()
429
except errors.NoRepositoryPresent:
430
next_transport = found_bzrdir.root_transport.clone('..')
431
if (found_bzrdir.root_transport.base == next_transport.base):
432
# top of the file system
436
if ((found_bzrdir.root_transport.base ==
437
self.root_transport.base) or repository.is_shared()):
440
raise errors.NoRepositoryPresent(self)
441
raise errors.NoRepositoryPresent(self)
443
def get_branch_reference(self):
444
"""Return the referenced URL for the branch in this bzrdir.
446
:raises NotBranchError: If there is no Branch.
447
:return: The URL the branch in this bzrdir references if it is a
448
reference branch, or None for regular branches.
452
def get_branch_transport(self, branch_format):
453
"""Get the transport for use by branch format in this BzrDir.
455
Note that bzr dirs that do not support format strings will raise
456
IncompatibleFormat if the branch format they are given has
457
a format string, and vice versa.
459
If branch_format is None, the transport is returned with no
460
checking. if it is not None, then the returned transport is
461
guaranteed to point to an existing directory ready for use.
463
raise NotImplementedError(self.get_branch_transport)
465
def get_repository_transport(self, repository_format):
466
"""Get the transport for use by repository format in this BzrDir.
468
Note that bzr dirs that do not support format strings will raise
469
IncompatibleFormat if the repository format they are given has
470
a format string, and vice versa.
472
If repository_format is None, the transport is returned with no
473
checking. if it is not None, then the returned transport is
474
guaranteed to point to an existing directory ready for use.
476
raise NotImplementedError(self.get_repository_transport)
478
def get_workingtree_transport(self, tree_format):
479
"""Get the transport for use by workingtree format in this BzrDir.
481
Note that bzr dirs that do not support format strings will raise
482
IncompatibleFormat if the workingtree format they are given has a
483
format string, and vice versa.
485
If workingtree_format is None, the transport is returned with no
486
checking. if it is not None, then the returned transport is
487
guaranteed to point to an existing directory ready for use.
489
raise NotImplementedError(self.get_workingtree_transport)
491
def __init__(self, _transport, _format):
492
"""Initialize a Bzr control dir object.
494
Only really common logic should reside here, concrete classes should be
495
made with varying behaviours.
497
:param _format: the format that is creating this BzrDir instance.
498
:param _transport: the transport this dir is based at.
500
self._format = _format
501
self.transport = _transport.clone('.bzr')
502
self.root_transport = _transport
504
def is_control_filename(self, filename):
505
"""True if filename is the name of a path which is reserved for bzrdir's.
507
:param filename: A filename within the root transport of this bzrdir.
509
This is true IF and ONLY IF the filename is part of the namespace reserved
510
for bzr control dirs. Currently this is the '.bzr' directory in the root
511
of the root_transport. it is expected that plugins will need to extend
512
this in the future - for instance to make bzr talk with svn working
515
# this might be better on the BzrDirFormat class because it refers to
516
# all the possible bzrdir disk formats.
517
# This method is tested via the workingtree is_control_filename tests-
518
# it was extracted from WorkingTree.is_control_filename. If the methods
519
# contract is extended beyond the current trivial implementation please
520
# add new tests for it to the appropriate place.
521
return filename == '.bzr' or filename.startswith('.bzr/')
523
def needs_format_conversion(self, format=None):
524
"""Return true if this bzrdir needs convert_format run on it.
526
For instance, if the repository format is out of date but the
527
branch and working tree are not, this should return True.
529
:param format: Optional parameter indicating a specific desired
530
format we plan to arrive at.
532
raise NotImplementedError(self.needs_format_conversion)
535
def open_unsupported(base):
536
"""Open a branch which is not supported."""
537
return BzrDir.open(base, _unsupported=True)
540
def open(base, _unsupported=False, possible_transports=None):
541
"""Open an existing bzrdir, rooted at 'base' (url)
543
_unsupported is a private parameter to the BzrDir class.
545
t = get_transport(base, possible_transports=possible_transports)
546
return BzrDir.open_from_transport(t, _unsupported=_unsupported)
549
def open_from_transport(transport, _unsupported=False,
550
_server_formats=True):
551
"""Open a bzrdir within a particular directory.
553
:param transport: Transport containing the bzrdir.
554
:param _unsupported: private.
556
base = transport.base
558
def find_format(transport):
559
return transport, BzrDirFormat.find_format(
560
transport, _server_formats=_server_formats)
562
def redirected(transport, e, redirection_notice):
563
qualified_source = e.get_source_url()
564
relpath = transport.relpath(qualified_source)
565
if not e.target.endswith(relpath):
566
# Not redirected to a branch-format, not a branch
567
raise errors.NotBranchError(path=e.target)
568
target = e.target[:-len(relpath)]
569
note('%s is%s redirected to %s',
570
transport.base, e.permanently, target)
571
# Let's try with a new transport
572
qualified_target = e.get_target_url()[:-len(relpath)]
573
# FIXME: If 'transport' has a qualifier, this should
574
# be applied again to the new transport *iff* the
575
# schemes used are the same. It's a bit tricky to
576
# verify, so I'll punt for now
578
return get_transport(target)
581
transport, format = do_catching_redirections(find_format,
584
except errors.TooManyRedirections:
585
raise errors.NotBranchError(base)
587
BzrDir._check_supported(format, _unsupported)
588
return format.open(transport, _found=True)
590
def open_branch(self, unsupported=False):
591
"""Open the branch object at this BzrDir if one is present.
593
If unsupported is True, then no longer supported branch formats can
596
TODO: static convenience version of this?
598
raise NotImplementedError(self.open_branch)
601
def open_containing(url, possible_transports=None):
602
"""Open an existing branch which contains url.
604
:param url: url to search from.
605
See open_containing_from_transport for more detail.
607
transport = get_transport(url, possible_transports)
608
return BzrDir.open_containing_from_transport(transport)
611
def open_containing_from_transport(a_transport):
612
"""Open an existing branch which contains a_transport.base
614
This probes for a branch at a_transport, and searches upwards from there.
616
Basically we keep looking up until we find the control directory or
617
run into the root. If there isn't one, raises NotBranchError.
618
If there is one and it is either an unrecognised format or an unsupported
619
format, UnknownFormatError or UnsupportedFormatError are raised.
620
If there is one, it is returned, along with the unused portion of url.
622
:return: The BzrDir that contains the path, and a Unicode path
623
for the rest of the URL.
625
# this gets the normalised url back. I.e. '.' -> the full path.
626
url = a_transport.base
629
result = BzrDir.open_from_transport(a_transport)
630
return result, urlutils.unescape(a_transport.relpath(url))
631
except errors.NotBranchError, e:
634
new_t = a_transport.clone('..')
635
except errors.InvalidURLJoin:
636
# reached the root, whatever that may be
637
raise errors.NotBranchError(path=url)
638
if new_t.base == a_transport.base:
639
# reached the root, whatever that may be
640
raise errors.NotBranchError(path=url)
644
def open_containing_tree_or_branch(klass, location):
645
"""Return the branch and working tree contained by a location.
647
Returns (tree, branch, relpath).
648
If there is no tree at containing the location, tree will be None.
649
If there is no branch containing the location, an exception will be
651
relpath is the portion of the path that is contained by the branch.
653
bzrdir, relpath = klass.open_containing(location)
655
tree = bzrdir.open_workingtree()
656
except (errors.NoWorkingTree, errors.NotLocalUrl):
658
branch = bzrdir.open_branch()
661
return tree, branch, relpath
663
def open_repository(self, _unsupported=False):
664
"""Open the repository object at this BzrDir if one is present.
666
This will not follow the Branch object pointer - its strictly a direct
667
open facility. Most client code should use open_branch().repository to
670
_unsupported is a private parameter, not part of the api.
671
TODO: static convenience version of this?
673
raise NotImplementedError(self.open_repository)
675
def open_workingtree(self, _unsupported=False,
676
recommend_upgrade=True):
677
"""Open the workingtree object at this BzrDir if one is present.
679
:param recommend_upgrade: Optional keyword parameter, when True (the
680
default), emit through the ui module a recommendation that the user
681
upgrade the working tree when the workingtree being opened is old
682
(but still fully supported).
684
raise NotImplementedError(self.open_workingtree)
686
def has_branch(self):
687
"""Tell if this bzrdir contains a branch.
689
Note: if you're going to open the branch, you should just go ahead
690
and try, and not ask permission first. (This method just opens the
691
branch and discards it, and that's somewhat expensive.)
696
except errors.NotBranchError:
699
def has_workingtree(self):
700
"""Tell if this bzrdir contains a working tree.
702
This will still raise an exception if the bzrdir has a workingtree that
703
is remote & inaccessible.
705
Note: if you're going to open the working tree, you should just go ahead
706
and try, and not ask permission first. (This method just opens the
707
workingtree and discards it, and that's somewhat expensive.)
710
self.open_workingtree(recommend_upgrade=False)
712
except errors.NoWorkingTree:
715
def _cloning_metadir(self):
716
"""Produce a metadir suitable for cloning with"""
717
result_format = self._format.__class__()
720
branch = self.open_branch()
721
source_repository = branch.repository
722
except errors.NotBranchError:
724
source_repository = self.open_repository()
725
except errors.NoRepositoryPresent:
726
source_repository = None
728
# XXX TODO: This isinstance is here because we have not implemented
729
# the fix recommended in bug # 103195 - to delegate this choice the
731
repo_format = source_repository._format
732
if not isinstance(repo_format, remote.RemoteRepositoryFormat):
733
result_format.repository_format = repo_format
735
# TODO: Couldn't we just probe for the format in these cases,
736
# rather than opening the whole tree? It would be a little
737
# faster. mbp 20070401
738
tree = self.open_workingtree(recommend_upgrade=False)
739
except (errors.NoWorkingTree, errors.NotLocalUrl):
740
result_format.workingtree_format = None
742
result_format.workingtree_format = tree._format.__class__()
743
return result_format, source_repository
745
def cloning_metadir(self):
746
"""Produce a metadir suitable for cloning or sprouting with.
748
These operations may produce workingtrees (yes, even though they're
749
"cloning" something that doesn't have a tree, so a viable workingtree
750
format must be selected.
752
format, repository = self._cloning_metadir()
753
if format._workingtree_format is None:
754
if repository is None:
756
tree_format = repository._format._matchingbzrdir.workingtree_format
757
format.workingtree_format = tree_format.__class__()
760
def checkout_metadir(self):
761
return self.cloning_metadir()
763
def sprout(self, url, revision_id=None, force_new_repo=False,
764
recurse='down', possible_transports=None):
765
"""Create a copy of this bzrdir prepared for use as a new line of
768
If urls last component does not exist, it will be created.
770
Attributes related to the identity of the source branch like
771
branch nickname will be cleaned, a working tree is created
772
whether one existed before or not; and a local branch is always
775
if revision_id is not None, then the clone operation may tune
776
itself to download less data.
778
target_transport = get_transport(url, possible_transports)
779
target_transport.ensure_base()
780
cloning_format = self.cloning_metadir()
781
result = cloning_format.initialize_on_transport(target_transport)
783
source_branch = self.open_branch()
784
source_repository = source_branch.repository
785
except errors.NotBranchError:
788
source_repository = self.open_repository()
789
except errors.NoRepositoryPresent:
790
source_repository = None
795
result_repo = result.find_repository()
796
except errors.NoRepositoryPresent:
798
if source_repository is None and result_repo is not None:
800
elif source_repository is None and result_repo is None:
801
# no repo available, make a new one
802
result.create_repository()
803
elif source_repository is not None and result_repo is None:
804
# have source, and want to make a new target repo
805
result_repo = source_repository.sprout(result,
806
revision_id=revision_id)
808
# fetch needed content into target.
809
if source_repository is not None:
811
# source_repository.copy_content_into(result_repo,
812
# revision_id=revision_id)
813
# so we can override the copy method
814
result_repo.fetch(source_repository, revision_id=revision_id)
815
if source_branch is not None:
816
source_branch.sprout(result, revision_id=revision_id)
818
result.create_branch()
819
if isinstance(target_transport, LocalTransport) and (
820
result_repo is None or result_repo.make_working_trees()):
821
wt = result.create_workingtree()
824
if wt.path2id('') is None:
826
wt.set_root_id(self.open_workingtree.get_root_id())
827
except errors.NoWorkingTree:
833
if recurse == 'down':
835
basis = wt.basis_tree()
837
subtrees = basis.iter_references()
838
recurse_branch = wt.branch
839
elif source_branch is not None:
840
basis = source_branch.basis_tree()
842
subtrees = basis.iter_references()
843
recurse_branch = source_branch
848
for path, file_id in subtrees:
849
target = urlutils.join(url, urlutils.escape(path))
850
sublocation = source_branch.reference_parent(file_id, path)
851
sublocation.bzrdir.sprout(target,
852
basis.get_reference_revision(file_id, path),
853
force_new_repo=force_new_repo, recurse=recurse)
855
if basis is not None:
860
class BzrDirPreSplitOut(BzrDir):
861
"""A common class for the all-in-one formats."""
863
def __init__(self, _transport, _format):
864
"""See BzrDir.__init__."""
865
super(BzrDirPreSplitOut, self).__init__(_transport, _format)
866
assert self._format._lock_class == lockable_files.TransportLock
867
assert self._format._lock_file_name == 'branch-lock'
868
self._control_files = lockable_files.LockableFiles(
869
self.get_branch_transport(None),
870
self._format._lock_file_name,
871
self._format._lock_class)
873
def break_lock(self):
874
"""Pre-splitout bzrdirs do not suffer from stale locks."""
875
raise NotImplementedError(self.break_lock)
877
def clone(self, url, revision_id=None, force_new_repo=False):
878
"""See BzrDir.clone()."""
879
from bzrlib.workingtree import WorkingTreeFormat2
881
result = self._format._initialize_for_clone(url)
882
self.open_repository().clone(result, revision_id=revision_id)
883
from_branch = self.open_branch()
884
from_branch.clone(result, revision_id=revision_id)
886
self.open_workingtree().clone(result)
887
except errors.NotLocalUrl:
888
# make a new one, this format always has to have one.
890
WorkingTreeFormat2().initialize(result)
891
except errors.NotLocalUrl:
892
# but we cannot do it for remote trees.
893
to_branch = result.open_branch()
894
WorkingTreeFormat2().stub_initialize_remote(to_branch.control_files)
897
def create_branch(self):
898
"""See BzrDir.create_branch."""
899
return self.open_branch()
901
def destroy_branch(self):
902
"""See BzrDir.destroy_branch."""
903
raise errors.UnsupportedOperation(self.destroy_branch, self)
905
def create_repository(self, shared=False):
906
"""See BzrDir.create_repository."""
908
raise errors.IncompatibleFormat('shared repository', self._format)
909
return self.open_repository()
911
def create_workingtree(self, revision_id=None):
912
"""See BzrDir.create_workingtree."""
913
# this looks buggy but is not -really-
914
# because this format creates the workingtree when the bzrdir is
916
# clone and sprout will have set the revision_id
917
# and that will have set it for us, its only
918
# specific uses of create_workingtree in isolation
919
# that can do wonky stuff here, and that only
920
# happens for creating checkouts, which cannot be
921
# done on this format anyway. So - acceptable wart.
922
result = self.open_workingtree(recommend_upgrade=False)
923
if revision_id is not None:
924
if revision_id == _mod_revision.NULL_REVISION:
925
result.set_parent_ids([])
927
result.set_parent_ids([revision_id])
930
def destroy_workingtree(self):
931
"""See BzrDir.destroy_workingtree."""
932
raise errors.UnsupportedOperation(self.destroy_workingtree, self)
934
def destroy_workingtree_metadata(self):
935
"""See BzrDir.destroy_workingtree_metadata."""
936
raise errors.UnsupportedOperation(self.destroy_workingtree_metadata,
939
def get_branch_transport(self, branch_format):
940
"""See BzrDir.get_branch_transport()."""
941
if branch_format is None:
942
return self.transport
944
branch_format.get_format_string()
945
except NotImplementedError:
946
return self.transport
947
raise errors.IncompatibleFormat(branch_format, self._format)
949
def get_repository_transport(self, repository_format):
950
"""See BzrDir.get_repository_transport()."""
951
if repository_format is None:
952
return self.transport
954
repository_format.get_format_string()
955
except NotImplementedError:
956
return self.transport
957
raise errors.IncompatibleFormat(repository_format, self._format)
959
def get_workingtree_transport(self, workingtree_format):
960
"""See BzrDir.get_workingtree_transport()."""
961
if workingtree_format is None:
962
return self.transport
964
workingtree_format.get_format_string()
965
except NotImplementedError:
966
return self.transport
967
raise errors.IncompatibleFormat(workingtree_format, self._format)
969
def needs_format_conversion(self, format=None):
970
"""See BzrDir.needs_format_conversion()."""
971
# if the format is not the same as the system default,
972
# an upgrade is needed.
974
format = BzrDirFormat.get_default_format()
975
return not isinstance(self._format, format.__class__)
977
def open_branch(self, unsupported=False):
978
"""See BzrDir.open_branch."""
979
from bzrlib.branch import BzrBranchFormat4
980
format = BzrBranchFormat4()
981
self._check_supported(format, unsupported)
982
return format.open(self, _found=True)
984
def sprout(self, url, revision_id=None, force_new_repo=False,
985
possible_transports=None):
986
"""See BzrDir.sprout()."""
987
from bzrlib.workingtree import WorkingTreeFormat2
989
result = self._format._initialize_for_clone(url)
991
self.open_repository().clone(result, revision_id=revision_id)
992
except errors.NoRepositoryPresent:
995
self.open_branch().sprout(result, revision_id=revision_id)
996
except errors.NotBranchError:
998
# we always want a working tree
999
WorkingTreeFormat2().initialize(result)
1003
class BzrDir4(BzrDirPreSplitOut):
1004
"""A .bzr version 4 control object.
1006
This is a deprecated format and may be removed after sept 2006.
1009
def create_repository(self, shared=False):
1010
"""See BzrDir.create_repository."""
1011
return self._format.repository_format.initialize(self, shared)
1013
def needs_format_conversion(self, format=None):
1014
"""Format 4 dirs are always in need of conversion."""
1017
def open_repository(self):
1018
"""See BzrDir.open_repository."""
1019
from bzrlib.repofmt.weaverepo import RepositoryFormat4
1020
return RepositoryFormat4().open(self, _found=True)
1023
class BzrDir5(BzrDirPreSplitOut):
1024
"""A .bzr version 5 control object.
1026
This is a deprecated format and may be removed after sept 2006.
1029
def open_repository(self):
1030
"""See BzrDir.open_repository."""
1031
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1032
return RepositoryFormat5().open(self, _found=True)
1034
def open_workingtree(self, _unsupported=False,
1035
recommend_upgrade=True):
1036
"""See BzrDir.create_workingtree."""
1037
from bzrlib.workingtree import WorkingTreeFormat2
1038
wt_format = WorkingTreeFormat2()
1039
# we don't warn here about upgrades; that ought to be handled for the
1041
return wt_format.open(self, _found=True)
1044
class BzrDir6(BzrDirPreSplitOut):
1045
"""A .bzr version 6 control object.
1047
This is a deprecated format and may be removed after sept 2006.
1050
def open_repository(self):
1051
"""See BzrDir.open_repository."""
1052
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1053
return RepositoryFormat6().open(self, _found=True)
1055
def open_workingtree(self, _unsupported=False,
1056
recommend_upgrade=True):
1057
"""See BzrDir.create_workingtree."""
1058
# we don't warn here about upgrades; that ought to be handled for the
1060
from bzrlib.workingtree import WorkingTreeFormat2
1061
return WorkingTreeFormat2().open(self, _found=True)
1064
class BzrDirMeta1(BzrDir):
1065
"""A .bzr meta version 1 control object.
1067
This is the first control object where the
1068
individual aspects are really split out: there are separate repository,
1069
workingtree and branch subdirectories and any subset of the three can be
1070
present within a BzrDir.
1073
def can_convert_format(self):
1074
"""See BzrDir.can_convert_format()."""
1077
def create_branch(self):
1078
"""See BzrDir.create_branch."""
1079
return self._format.get_branch_format().initialize(self)
1081
def destroy_branch(self):
1082
"""See BzrDir.create_branch."""
1083
self.transport.delete_tree('branch')
1085
def create_repository(self, shared=False):
1086
"""See BzrDir.create_repository."""
1087
return self._format.repository_format.initialize(self, shared)
1089
def create_workingtree(self, revision_id=None):
1090
"""See BzrDir.create_workingtree."""
1091
from bzrlib.workingtree import WorkingTreeFormat
1092
return self._format.workingtree_format.initialize(self, revision_id)
1094
def destroy_workingtree(self):
1095
"""See BzrDir.destroy_workingtree."""
1096
wt = self.open_workingtree(recommend_upgrade=False)
1097
repository = wt.branch.repository
1098
empty = repository.revision_tree(_mod_revision.NULL_REVISION)
1099
wt.revert(old_tree=empty)
1100
self.destroy_workingtree_metadata()
1102
def destroy_workingtree_metadata(self):
1103
self.transport.delete_tree('checkout')
1105
def find_branch_format(self):
1106
"""Find the branch 'format' for this bzrdir.
1108
This might be a synthetic object for e.g. RemoteBranch and SVN.
1110
from bzrlib.branch import BranchFormat
1111
return BranchFormat.find_format(self)
1113
def _get_mkdir_mode(self):
1114
"""Figure out the mode to use when creating a bzrdir subdir."""
1115
temp_control = lockable_files.LockableFiles(self.transport, '',
1116
lockable_files.TransportLock)
1117
return temp_control._dir_mode
1119
def get_branch_reference(self):
1120
"""See BzrDir.get_branch_reference()."""
1121
from bzrlib.branch import BranchFormat
1122
format = BranchFormat.find_format(self)
1123
return format.get_reference(self)
1125
def get_branch_transport(self, branch_format):
1126
"""See BzrDir.get_branch_transport()."""
1127
if branch_format is None:
1128
return self.transport.clone('branch')
1130
branch_format.get_format_string()
1131
except NotImplementedError:
1132
raise errors.IncompatibleFormat(branch_format, self._format)
1134
self.transport.mkdir('branch', mode=self._get_mkdir_mode())
1135
except errors.FileExists:
1137
return self.transport.clone('branch')
1139
def get_repository_transport(self, repository_format):
1140
"""See BzrDir.get_repository_transport()."""
1141
if repository_format is None:
1142
return self.transport.clone('repository')
1144
repository_format.get_format_string()
1145
except NotImplementedError:
1146
raise errors.IncompatibleFormat(repository_format, self._format)
1148
self.transport.mkdir('repository', mode=self._get_mkdir_mode())
1149
except errors.FileExists:
1151
return self.transport.clone('repository')
1153
def get_workingtree_transport(self, workingtree_format):
1154
"""See BzrDir.get_workingtree_transport()."""
1155
if workingtree_format is None:
1156
return self.transport.clone('checkout')
1158
workingtree_format.get_format_string()
1159
except NotImplementedError:
1160
raise errors.IncompatibleFormat(workingtree_format, self._format)
1162
self.transport.mkdir('checkout', mode=self._get_mkdir_mode())
1163
except errors.FileExists:
1165
return self.transport.clone('checkout')
1167
def needs_format_conversion(self, format=None):
1168
"""See BzrDir.needs_format_conversion()."""
1170
format = BzrDirFormat.get_default_format()
1171
if not isinstance(self._format, format.__class__):
1172
# it is not a meta dir format, conversion is needed.
1174
# we might want to push this down to the repository?
1176
if not isinstance(self.open_repository()._format,
1177
format.repository_format.__class__):
1178
# the repository needs an upgrade.
1180
except errors.NoRepositoryPresent:
1183
if not isinstance(self.open_branch()._format,
1184
format.get_branch_format().__class__):
1185
# the branch needs an upgrade.
1187
except errors.NotBranchError:
1190
my_wt = self.open_workingtree(recommend_upgrade=False)
1191
if not isinstance(my_wt._format,
1192
format.workingtree_format.__class__):
1193
# the workingtree needs an upgrade.
1195
except (errors.NoWorkingTree, errors.NotLocalUrl):
1199
def open_branch(self, unsupported=False):
1200
"""See BzrDir.open_branch."""
1201
format = self.find_branch_format()
1202
self._check_supported(format, unsupported)
1203
return format.open(self, _found=True)
1205
def open_repository(self, unsupported=False):
1206
"""See BzrDir.open_repository."""
1207
from bzrlib.repository import RepositoryFormat
1208
format = RepositoryFormat.find_format(self)
1209
self._check_supported(format, unsupported)
1210
return format.open(self, _found=True)
1212
def open_workingtree(self, unsupported=False,
1213
recommend_upgrade=True):
1214
"""See BzrDir.open_workingtree."""
1215
from bzrlib.workingtree import WorkingTreeFormat
1216
format = WorkingTreeFormat.find_format(self)
1217
self._check_supported(format, unsupported,
1219
basedir=self.root_transport.base)
1220
return format.open(self, _found=True)
1223
class BzrDirFormat(object):
1224
"""An encapsulation of the initialization and open routines for a format.
1226
Formats provide three things:
1227
* An initialization routine,
1231
Formats are placed in an dict by their format string for reference
1232
during bzrdir opening. These should be subclasses of BzrDirFormat
1235
Once a format is deprecated, just deprecate the initialize and open
1236
methods on the format class. Do not deprecate the object, as the
1237
object will be created every system load.
1240
_default_format = None
1241
"""The default format used for new .bzr dirs."""
1244
"""The known formats."""
1246
_control_formats = []
1247
"""The registered control formats - .bzr, ....
1249
This is a list of BzrDirFormat objects.
1252
_control_server_formats = []
1253
"""The registered control server formats, e.g. RemoteBzrDirs.
1255
This is a list of BzrDirFormat objects.
1258
_lock_file_name = 'branch-lock'
1260
# _lock_class must be set in subclasses to the lock type, typ.
1261
# TransportLock or LockDir
1264
def find_format(klass, transport, _server_formats=True):
1265
"""Return the format present at transport."""
1267
formats = klass._control_server_formats + klass._control_formats
1269
formats = klass._control_formats
1270
for format in formats:
1272
return format.probe_transport(transport)
1273
except errors.NotBranchError:
1274
# this format does not find a control dir here.
1276
raise errors.NotBranchError(path=transport.base)
1279
def probe_transport(klass, transport):
1280
"""Return the .bzrdir style format present in a directory."""
1282
format_string = transport.get(".bzr/branch-format").read()
1283
except errors.NoSuchFile:
1284
raise errors.NotBranchError(path=transport.base)
1287
return klass._formats[format_string]
1289
raise errors.UnknownFormatError(format=format_string)
1292
def get_default_format(klass):
1293
"""Return the current default format."""
1294
return klass._default_format
1296
def get_format_string(self):
1297
"""Return the ASCII format string that identifies this format."""
1298
raise NotImplementedError(self.get_format_string)
1300
def get_format_description(self):
1301
"""Return the short description for this format."""
1302
raise NotImplementedError(self.get_format_description)
1304
def get_converter(self, format=None):
1305
"""Return the converter to use to convert bzrdirs needing converts.
1307
This returns a bzrlib.bzrdir.Converter object.
1309
This should return the best upgrader to step this format towards the
1310
current default format. In the case of plugins we can/should provide
1311
some means for them to extend the range of returnable converters.
1313
:param format: Optional format to override the default format of the
1316
raise NotImplementedError(self.get_converter)
1318
def initialize(self, url, possible_transports=None):
1319
"""Create a bzr control dir at this url and return an opened copy.
1321
Subclasses should typically override initialize_on_transport
1322
instead of this method.
1324
return self.initialize_on_transport(get_transport(url,
1325
possible_transports))
1327
def initialize_on_transport(self, transport):
1328
"""Initialize a new bzrdir in the base directory of a Transport."""
1329
# Since we don't have a .bzr directory, inherit the
1330
# mode from the root directory
1331
temp_control = lockable_files.LockableFiles(transport,
1332
'', lockable_files.TransportLock)
1333
temp_control._transport.mkdir('.bzr',
1334
# FIXME: RBC 20060121 don't peek under
1336
mode=temp_control._dir_mode)
1337
file_mode = temp_control._file_mode
1339
mutter('created control directory in ' + transport.base)
1340
control = transport.clone('.bzr')
1341
utf8_files = [('README',
1342
"This is a Bazaar-NG control directory.\n"
1343
"Do not change any files in this directory.\n"),
1344
('branch-format', self.get_format_string()),
1346
# NB: no need to escape relative paths that are url safe.
1347
control_files = lockable_files.LockableFiles(control,
1348
self._lock_file_name, self._lock_class)
1349
control_files.create_lock()
1350
control_files.lock_write()
1352
for file, content in utf8_files:
1353
control_files.put_utf8(file, content)
1355
control_files.unlock()
1356
return self.open(transport, _found=True)
1358
def is_supported(self):
1359
"""Is this format supported?
1361
Supported formats must be initializable and openable.
1362
Unsupported formats may not support initialization or committing or
1363
some other features depending on the reason for not being supported.
1367
def same_model(self, target_format):
1368
return (self.repository_format.rich_root_data ==
1369
target_format.rich_root_data)
1372
def known_formats(klass):
1373
"""Return all the known formats.
1375
Concrete formats should override _known_formats.
1377
# There is double indirection here to make sure that control
1378
# formats used by more than one dir format will only be probed
1379
# once. This can otherwise be quite expensive for remote connections.
1381
for format in klass._control_formats:
1382
result.update(format._known_formats())
1386
def _known_formats(klass):
1387
"""Return the known format instances for this control format."""
1388
return set(klass._formats.values())
1390
def open(self, transport, _found=False):
1391
"""Return an instance of this format for the dir transport points at.
1393
_found is a private parameter, do not use it.
1396
found_format = BzrDirFormat.find_format(transport)
1397
if not isinstance(found_format, self.__class__):
1398
raise AssertionError("%s was asked to open %s, but it seems to need "
1400
% (self, transport, found_format))
1401
return self._open(transport)
1403
def _open(self, transport):
1404
"""Template method helper for opening BzrDirectories.
1406
This performs the actual open and any additional logic or parameter
1409
raise NotImplementedError(self._open)
1412
def register_format(klass, format):
1413
klass._formats[format.get_format_string()] = format
1416
def register_control_format(klass, format):
1417
"""Register a format that does not use '.bzr' for its control dir.
1419
TODO: This should be pulled up into a 'ControlDirFormat' base class
1420
which BzrDirFormat can inherit from, and renamed to register_format
1421
there. It has been done without that for now for simplicity of
1424
klass._control_formats.append(format)
1427
def register_control_server_format(klass, format):
1428
"""Register a control format for client-server environments.
1430
These formats will be tried before ones registered with
1431
register_control_format. This gives implementations that decide to the
1432
chance to grab it before anything looks at the contents of the format
1435
klass._control_server_formats.append(format)
1438
@symbol_versioning.deprecated_method(symbol_versioning.zero_fourteen)
1439
def set_default_format(klass, format):
1440
klass._set_default_format(format)
1443
def _set_default_format(klass, format):
1444
"""Set default format (for testing behavior of defaults only)"""
1445
klass._default_format = format
1448
return self.get_format_string()[:-1]
1451
def unregister_format(klass, format):
1452
assert klass._formats[format.get_format_string()] is format
1453
del klass._formats[format.get_format_string()]
1456
def unregister_control_format(klass, format):
1457
klass._control_formats.remove(format)
1460
class BzrDirFormat4(BzrDirFormat):
1461
"""Bzr dir format 4.
1463
This format is a combined format for working tree, branch and repository.
1465
- Format 1 working trees [always]
1466
- Format 4 branches [always]
1467
- Format 4 repositories [always]
1469
This format is deprecated: it indexes texts using a text it which is
1470
removed in format 5; write support for this format has been removed.
1473
_lock_class = lockable_files.TransportLock
1475
def get_format_string(self):
1476
"""See BzrDirFormat.get_format_string()."""
1477
return "Bazaar-NG branch, format 0.0.4\n"
1479
def get_format_description(self):
1480
"""See BzrDirFormat.get_format_description()."""
1481
return "All-in-one format 4"
1483
def get_converter(self, format=None):
1484
"""See BzrDirFormat.get_converter()."""
1485
# there is one and only one upgrade path here.
1486
return ConvertBzrDir4To5()
1488
def initialize_on_transport(self, transport):
1489
"""Format 4 branches cannot be created."""
1490
raise errors.UninitializableFormat(self)
1492
def is_supported(self):
1493
"""Format 4 is not supported.
1495
It is not supported because the model changed from 4 to 5 and the
1496
conversion logic is expensive - so doing it on the fly was not
1501
def _open(self, transport):
1502
"""See BzrDirFormat._open."""
1503
return BzrDir4(transport, self)
1505
def __return_repository_format(self):
1506
"""Circular import protection."""
1507
from bzrlib.repofmt.weaverepo import RepositoryFormat4
1508
return RepositoryFormat4()
1509
repository_format = property(__return_repository_format)
1512
class BzrDirFormat5(BzrDirFormat):
1513
"""Bzr control format 5.
1515
This format is a combined format for working tree, branch and repository.
1517
- Format 2 working trees [always]
1518
- Format 4 branches [always]
1519
- Format 5 repositories [always]
1520
Unhashed stores in the repository.
1523
_lock_class = lockable_files.TransportLock
1525
def get_format_string(self):
1526
"""See BzrDirFormat.get_format_string()."""
1527
return "Bazaar-NG branch, format 5\n"
1529
def get_format_description(self):
1530
"""See BzrDirFormat.get_format_description()."""
1531
return "All-in-one format 5"
1533
def get_converter(self, format=None):
1534
"""See BzrDirFormat.get_converter()."""
1535
# there is one and only one upgrade path here.
1536
return ConvertBzrDir5To6()
1538
def _initialize_for_clone(self, url):
1539
return self.initialize_on_transport(get_transport(url), _cloning=True)
1541
def initialize_on_transport(self, transport, _cloning=False):
1542
"""Format 5 dirs always have working tree, branch and repository.
1544
Except when they are being cloned.
1546
from bzrlib.branch import BzrBranchFormat4
1547
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1548
from bzrlib.workingtree import WorkingTreeFormat2
1549
result = (super(BzrDirFormat5, self).initialize_on_transport(transport))
1550
RepositoryFormat5().initialize(result, _internal=True)
1552
branch = BzrBranchFormat4().initialize(result)
1554
WorkingTreeFormat2().initialize(result)
1555
except errors.NotLocalUrl:
1556
# Even though we can't access the working tree, we need to
1557
# create its control files.
1558
WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
1561
def _open(self, transport):
1562
"""See BzrDirFormat._open."""
1563
return BzrDir5(transport, self)
1565
def __return_repository_format(self):
1566
"""Circular import protection."""
1567
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1568
return RepositoryFormat5()
1569
repository_format = property(__return_repository_format)
1572
class BzrDirFormat6(BzrDirFormat):
1573
"""Bzr control format 6.
1575
This format is a combined format for working tree, branch and repository.
1577
- Format 2 working trees [always]
1578
- Format 4 branches [always]
1579
- Format 6 repositories [always]
1582
_lock_class = lockable_files.TransportLock
1584
def get_format_string(self):
1585
"""See BzrDirFormat.get_format_string()."""
1586
return "Bazaar-NG branch, format 6\n"
1588
def get_format_description(self):
1589
"""See BzrDirFormat.get_format_description()."""
1590
return "All-in-one format 6"
1592
def get_converter(self, format=None):
1593
"""See BzrDirFormat.get_converter()."""
1594
# there is one and only one upgrade path here.
1595
return ConvertBzrDir6ToMeta()
1597
def _initialize_for_clone(self, url):
1598
return self.initialize_on_transport(get_transport(url), _cloning=True)
1600
def initialize_on_transport(self, transport, _cloning=False):
1601
"""Format 6 dirs always have working tree, branch and repository.
1603
Except when they are being cloned.
1605
from bzrlib.branch import BzrBranchFormat4
1606
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1607
from bzrlib.workingtree import WorkingTreeFormat2
1608
result = super(BzrDirFormat6, self).initialize_on_transport(transport)
1609
RepositoryFormat6().initialize(result, _internal=True)
1611
branch = BzrBranchFormat4().initialize(result)
1613
WorkingTreeFormat2().initialize(result)
1614
except errors.NotLocalUrl:
1615
# Even though we can't access the working tree, we need to
1616
# create its control files.
1617
WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
1620
def _open(self, transport):
1621
"""See BzrDirFormat._open."""
1622
return BzrDir6(transport, self)
1624
def __return_repository_format(self):
1625
"""Circular import protection."""
1626
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1627
return RepositoryFormat6()
1628
repository_format = property(__return_repository_format)
1631
class BzrDirMetaFormat1(BzrDirFormat):
1632
"""Bzr meta control format 1
1634
This is the first format with split out working tree, branch and repository
1637
- Format 3 working trees [optional]
1638
- Format 5 branches [optional]
1639
- Format 7 repositories [optional]
1642
_lock_class = lockdir.LockDir
1645
self._workingtree_format = None
1646
self._branch_format = None
1648
def __eq__(self, other):
1649
if other.__class__ is not self.__class__:
1651
if other.repository_format != self.repository_format:
1653
if other.workingtree_format != self.workingtree_format:
1657
def __ne__(self, other):
1658
return not self == other
1660
def get_branch_format(self):
1661
if self._branch_format is None:
1662
from bzrlib.branch import BranchFormat
1663
self._branch_format = BranchFormat.get_default_format()
1664
return self._branch_format
1666
def set_branch_format(self, format):
1667
self._branch_format = format
1669
def get_converter(self, format=None):
1670
"""See BzrDirFormat.get_converter()."""
1672
format = BzrDirFormat.get_default_format()
1673
if not isinstance(self, format.__class__):
1674
# converting away from metadir is not implemented
1675
raise NotImplementedError(self.get_converter)
1676
return ConvertMetaToMeta(format)
1678
def get_format_string(self):
1679
"""See BzrDirFormat.get_format_string()."""
1680
return "Bazaar-NG meta directory, format 1\n"
1682
def get_format_description(self):
1683
"""See BzrDirFormat.get_format_description()."""
1684
return "Meta directory format 1"
1686
def _open(self, transport):
1687
"""See BzrDirFormat._open."""
1688
return BzrDirMeta1(transport, self)
1690
def __return_repository_format(self):
1691
"""Circular import protection."""
1692
if getattr(self, '_repository_format', None):
1693
return self._repository_format
1694
from bzrlib.repository import RepositoryFormat
1695
return RepositoryFormat.get_default_format()
1697
def __set_repository_format(self, value):
1698
"""Allow changint the repository format for metadir formats."""
1699
self._repository_format = value
1701
repository_format = property(__return_repository_format, __set_repository_format)
1703
def __get_workingtree_format(self):
1704
if self._workingtree_format is None:
1705
from bzrlib.workingtree import WorkingTreeFormat
1706
self._workingtree_format = WorkingTreeFormat.get_default_format()
1707
return self._workingtree_format
1709
def __set_workingtree_format(self, wt_format):
1710
self._workingtree_format = wt_format
1712
workingtree_format = property(__get_workingtree_format,
1713
__set_workingtree_format)
1716
# Register bzr control format
1717
BzrDirFormat.register_control_format(BzrDirFormat)
1719
# Register bzr formats
1720
BzrDirFormat.register_format(BzrDirFormat4())
1721
BzrDirFormat.register_format(BzrDirFormat5())
1722
BzrDirFormat.register_format(BzrDirFormat6())
1723
__default_format = BzrDirMetaFormat1()
1724
BzrDirFormat.register_format(__default_format)
1725
BzrDirFormat._default_format = __default_format
1728
class Converter(object):
1729
"""Converts a disk format object from one format to another."""
1731
def convert(self, to_convert, pb):
1732
"""Perform the conversion of to_convert, giving feedback via pb.
1734
:param to_convert: The disk object to convert.
1735
:param pb: a progress bar to use for progress information.
1738
def step(self, message):
1739
"""Update the pb by a step."""
1741
self.pb.update(message, self.count, self.total)
1744
class ConvertBzrDir4To5(Converter):
1745
"""Converts format 4 bzr dirs to format 5."""
1748
super(ConvertBzrDir4To5, self).__init__()
1749
self.converted_revs = set()
1750
self.absent_revisions = set()
1754
def convert(self, to_convert, pb):
1755
"""See Converter.convert()."""
1756
self.bzrdir = to_convert
1758
self.pb.note('starting upgrade from format 4 to 5')
1759
if isinstance(self.bzrdir.transport, LocalTransport):
1760
self.bzrdir.get_workingtree_transport(None).delete('stat-cache')
1761
self._convert_to_weaves()
1762
return BzrDir.open(self.bzrdir.root_transport.base)
1764
def _convert_to_weaves(self):
1765
self.pb.note('note: upgrade may be faster if all store files are ungzipped first')
1768
stat = self.bzrdir.transport.stat('weaves')
1769
if not S_ISDIR(stat.st_mode):
1770
self.bzrdir.transport.delete('weaves')
1771
self.bzrdir.transport.mkdir('weaves')
1772
except errors.NoSuchFile:
1773
self.bzrdir.transport.mkdir('weaves')
1774
# deliberately not a WeaveFile as we want to build it up slowly.
1775
self.inv_weave = Weave('inventory')
1776
# holds in-memory weaves for all files
1777
self.text_weaves = {}
1778
self.bzrdir.transport.delete('branch-format')
1779
self.branch = self.bzrdir.open_branch()
1780
self._convert_working_inv()
1781
rev_history = self.branch.revision_history()
1782
# to_read is a stack holding the revisions we still need to process;
1783
# appending to it adds new highest-priority revisions
1784
self.known_revisions = set(rev_history)
1785
self.to_read = rev_history[-1:]
1787
rev_id = self.to_read.pop()
1788
if (rev_id not in self.revisions
1789
and rev_id not in self.absent_revisions):
1790
self._load_one_rev(rev_id)
1792
to_import = self._make_order()
1793
for i, rev_id in enumerate(to_import):
1794
self.pb.update('converting revision', i, len(to_import))
1795
self._convert_one_rev(rev_id)
1797
self._write_all_weaves()
1798
self._write_all_revs()
1799
self.pb.note('upgraded to weaves:')
1800
self.pb.note(' %6d revisions and inventories', len(self.revisions))
1801
self.pb.note(' %6d revisions not present', len(self.absent_revisions))
1802
self.pb.note(' %6d texts', self.text_count)
1803
self._cleanup_spare_files_after_format4()
1804
self.branch.control_files.put_utf8('branch-format', BzrDirFormat5().get_format_string())
1806
def _cleanup_spare_files_after_format4(self):
1807
# FIXME working tree upgrade foo.
1808
for n in 'merged-patches', 'pending-merged-patches':
1810
## assert os.path.getsize(p) == 0
1811
self.bzrdir.transport.delete(n)
1812
except errors.NoSuchFile:
1814
self.bzrdir.transport.delete_tree('inventory-store')
1815
self.bzrdir.transport.delete_tree('text-store')
1817
def _convert_working_inv(self):
1818
inv = xml4.serializer_v4.read_inventory(
1819
self.branch.control_files.get('inventory'))
1820
new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv, working=True)
1821
# FIXME inventory is a working tree change.
1822
self.branch.control_files.put('inventory', StringIO(new_inv_xml))
1824
def _write_all_weaves(self):
1825
controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)
1826
weave_transport = self.bzrdir.transport.clone('weaves')
1827
weaves = WeaveStore(weave_transport, prefixed=False)
1828
transaction = WriteTransaction()
1832
for file_id, file_weave in self.text_weaves.items():
1833
self.pb.update('writing weave', i, len(self.text_weaves))
1834
weaves._put_weave(file_id, file_weave, transaction)
1836
self.pb.update('inventory', 0, 1)
1837
controlweaves._put_weave('inventory', self.inv_weave, transaction)
1838
self.pb.update('inventory', 1, 1)
1842
def _write_all_revs(self):
1843
"""Write all revisions out in new form."""
1844
self.bzrdir.transport.delete_tree('revision-store')
1845
self.bzrdir.transport.mkdir('revision-store')
1846
revision_transport = self.bzrdir.transport.clone('revision-store')
1848
_revision_store = TextRevisionStore(TextStore(revision_transport,
1852
transaction = WriteTransaction()
1853
for i, rev_id in enumerate(self.converted_revs):
1854
self.pb.update('write revision', i, len(self.converted_revs))
1855
_revision_store.add_revision(self.revisions[rev_id], transaction)
1859
def _load_one_rev(self, rev_id):
1860
"""Load a revision object into memory.
1862
Any parents not either loaded or abandoned get queued to be
1864
self.pb.update('loading revision',
1865
len(self.revisions),
1866
len(self.known_revisions))
1867
if not self.branch.repository.has_revision(rev_id):
1869
self.pb.note('revision {%s} not present in branch; '
1870
'will be converted as a ghost',
1872
self.absent_revisions.add(rev_id)
1874
rev = self.branch.repository._revision_store.get_revision(rev_id,
1875
self.branch.repository.get_transaction())
1876
for parent_id in rev.parent_ids:
1877
self.known_revisions.add(parent_id)
1878
self.to_read.append(parent_id)
1879
self.revisions[rev_id] = rev
1881
def _load_old_inventory(self, rev_id):
1882
assert rev_id not in self.converted_revs
1883
old_inv_xml = self.branch.repository.inventory_store.get(rev_id).read()
1884
inv = xml4.serializer_v4.read_inventory_from_string(old_inv_xml)
1885
inv.revision_id = rev_id
1886
rev = self.revisions[rev_id]
1887
if rev.inventory_sha1:
1888
assert rev.inventory_sha1 == sha_string(old_inv_xml), \
1889
'inventory sha mismatch for {%s}' % rev_id
1892
def _load_updated_inventory(self, rev_id):
1893
assert rev_id in self.converted_revs
1894
inv_xml = self.inv_weave.get_text(rev_id)
1895
inv = xml5.serializer_v5.read_inventory_from_string(inv_xml)
1898
def _convert_one_rev(self, rev_id):
1899
"""Convert revision and all referenced objects to new format."""
1900
rev = self.revisions[rev_id]
1901
inv = self._load_old_inventory(rev_id)
1902
present_parents = [p for p in rev.parent_ids
1903
if p not in self.absent_revisions]
1904
self._convert_revision_contents(rev, inv, present_parents)
1905
self._store_new_inv(rev, inv, present_parents)
1906
self.converted_revs.add(rev_id)
1908
def _store_new_inv(self, rev, inv, present_parents):
1909
# the XML is now updated with text versions
1911
entries = inv.iter_entries()
1913
for path, ie in entries:
1914
assert getattr(ie, 'revision', None) is not None, \
1915
'no revision on {%s} in {%s}' % \
1916
(file_id, rev.revision_id)
1917
new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
1918
new_inv_sha1 = sha_string(new_inv_xml)
1919
self.inv_weave.add_lines(rev.revision_id,
1921
new_inv_xml.splitlines(True))
1922
rev.inventory_sha1 = new_inv_sha1
1924
def _convert_revision_contents(self, rev, inv, present_parents):
1925
"""Convert all the files within a revision.
1927
Also upgrade the inventory to refer to the text revision ids."""
1928
rev_id = rev.revision_id
1929
mutter('converting texts of revision {%s}',
1931
parent_invs = map(self._load_updated_inventory, present_parents)
1932
entries = inv.iter_entries()
1934
for path, ie in entries:
1935
self._convert_file_version(rev, ie, parent_invs)
1937
def _convert_file_version(self, rev, ie, parent_invs):
1938
"""Convert one version of one file.
1940
The file needs to be added into the weave if it is a merge
1941
of >=2 parents or if it's changed from its parent.
1943
file_id = ie.file_id
1944
rev_id = rev.revision_id
1945
w = self.text_weaves.get(file_id)
1948
self.text_weaves[file_id] = w
1949
text_changed = False
1950
parent_candiate_entries = ie.parent_candidates(parent_invs)
1951
for old_revision in parent_candiate_entries.keys():
1952
# if this fails, its a ghost ?
1953
assert old_revision in self.converted_revs, \
1954
"Revision {%s} not in converted_revs" % old_revision
1955
heads = graph.Graph(self).heads(parent_candiate_entries.keys())
1956
# XXX: Note that this is unordered - and this is tolerable because
1957
# the previous code was also unordered.
1958
previous_entries = dict((head, parent_candiate_entries[head]) for head
1960
self.snapshot_ie(previous_entries, ie, w, rev_id)
1962
assert getattr(ie, 'revision', None) is not None
1964
def get_parents(self, revision_ids):
1965
for revision_id in revision_ids:
1966
yield self.revisions[revision_id].parent_ids
1968
def snapshot_ie(self, previous_revisions, ie, w, rev_id):
1969
# TODO: convert this logic, which is ~= snapshot to
1970
# a call to:. This needs the path figured out. rather than a work_tree
1971
# a v4 revision_tree can be given, or something that looks enough like
1972
# one to give the file content to the entry if it needs it.
1973
# and we need something that looks like a weave store for snapshot to
1975
#ie.snapshot(rev, PATH, previous_revisions, REVISION_TREE, InMemoryWeaveStore(self.text_weaves))
1976
if len(previous_revisions) == 1:
1977
previous_ie = previous_revisions.values()[0]
1978
if ie._unchanged(previous_ie):
1979
ie.revision = previous_ie.revision
1982
text = self.branch.repository.weave_store.get(ie.text_id)
1983
file_lines = text.readlines()
1984
assert sha_strings(file_lines) == ie.text_sha1
1985
assert sum(map(len, file_lines)) == ie.text_size
1986
w.add_lines(rev_id, previous_revisions, file_lines)
1987
self.text_count += 1
1989
w.add_lines(rev_id, previous_revisions, [])
1990
ie.revision = rev_id
1992
def _make_order(self):
1993
"""Return a suitable order for importing revisions.
1995
The order must be such that an revision is imported after all
1996
its (present) parents.
1998
todo = set(self.revisions.keys())
1999
done = self.absent_revisions.copy()
2002
# scan through looking for a revision whose parents
2004
for rev_id in sorted(list(todo)):
2005
rev = self.revisions[rev_id]
2006
parent_ids = set(rev.parent_ids)
2007
if parent_ids.issubset(done):
2008
# can take this one now
2009
order.append(rev_id)
2015
class ConvertBzrDir5To6(Converter):
2016
"""Converts format 5 bzr dirs to format 6."""
2018
def convert(self, to_convert, pb):
2019
"""See Converter.convert()."""
2020
self.bzrdir = to_convert
2022
self.pb.note('starting upgrade from format 5 to 6')
2023
self._convert_to_prefixed()
2024
return BzrDir.open(self.bzrdir.root_transport.base)
2026
def _convert_to_prefixed(self):
2027
from bzrlib.store import TransportStore
2028
self.bzrdir.transport.delete('branch-format')
2029
for store_name in ["weaves", "revision-store"]:
2030
self.pb.note("adding prefixes to %s" % store_name)
2031
store_transport = self.bzrdir.transport.clone(store_name)
2032
store = TransportStore(store_transport, prefixed=True)
2033
for urlfilename in store_transport.list_dir('.'):
2034
filename = urlutils.unescape(urlfilename)
2035
if (filename.endswith(".weave") or
2036
filename.endswith(".gz") or
2037
filename.endswith(".sig")):
2038
file_id = os.path.splitext(filename)[0]
2041
prefix_dir = store.hash_prefix(file_id)
2042
# FIXME keep track of the dirs made RBC 20060121
2044
store_transport.move(filename, prefix_dir + '/' + filename)
2045
except errors.NoSuchFile: # catches missing dirs strangely enough
2046
store_transport.mkdir(prefix_dir)
2047
store_transport.move(filename, prefix_dir + '/' + filename)
2048
self.bzrdir._control_files.put_utf8('branch-format', BzrDirFormat6().get_format_string())
2051
class ConvertBzrDir6ToMeta(Converter):
2052
"""Converts format 6 bzr dirs to metadirs."""
2054
def convert(self, to_convert, pb):
2055
"""See Converter.convert()."""
2056
from bzrlib.repofmt.weaverepo import RepositoryFormat7
2057
from bzrlib.branch import BzrBranchFormat5
2058
self.bzrdir = to_convert
2061
self.total = 20 # the steps we know about
2062
self.garbage_inventories = []
2064
self.pb.note('starting upgrade from format 6 to metadir')
2065
self.bzrdir._control_files.put_utf8('branch-format', "Converting to format 6")
2066
# its faster to move specific files around than to open and use the apis...
2067
# first off, nuke ancestry.weave, it was never used.
2069
self.step('Removing ancestry.weave')
2070
self.bzrdir.transport.delete('ancestry.weave')
2071
except errors.NoSuchFile:
2073
# find out whats there
2074
self.step('Finding branch files')
2075
last_revision = self.bzrdir.open_branch().last_revision()
2076
bzrcontents = self.bzrdir.transport.list_dir('.')
2077
for name in bzrcontents:
2078
if name.startswith('basis-inventory.'):
2079
self.garbage_inventories.append(name)
2080
# create new directories for repository, working tree and branch
2081
self.dir_mode = self.bzrdir._control_files._dir_mode
2082
self.file_mode = self.bzrdir._control_files._file_mode
2083
repository_names = [('inventory.weave', True),
2084
('revision-store', True),
2086
self.step('Upgrading repository ')
2087
self.bzrdir.transport.mkdir('repository', mode=self.dir_mode)
2088
self.make_lock('repository')
2089
# we hard code the formats here because we are converting into
2090
# the meta format. The meta format upgrader can take this to a
2091
# future format within each component.
2092
self.put_format('repository', RepositoryFormat7())
2093
for entry in repository_names:
2094
self.move_entry('repository', entry)
2096
self.step('Upgrading branch ')
2097
self.bzrdir.transport.mkdir('branch', mode=self.dir_mode)
2098
self.make_lock('branch')
2099
self.put_format('branch', BzrBranchFormat5())
2100
branch_files = [('revision-history', True),
2101
('branch-name', True),
2103
for entry in branch_files:
2104
self.move_entry('branch', entry)
2106
checkout_files = [('pending-merges', True),
2107
('inventory', True),
2108
('stat-cache', False)]
2109
# If a mandatory checkout file is not present, the branch does not have
2110
# a functional checkout. Do not create a checkout in the converted
2112
for name, mandatory in checkout_files:
2113
if mandatory and name not in bzrcontents:
2114
has_checkout = False
2118
if not has_checkout:
2119
self.pb.note('No working tree.')
2120
# If some checkout files are there, we may as well get rid of them.
2121
for name, mandatory in checkout_files:
2122
if name in bzrcontents:
2123
self.bzrdir.transport.delete(name)
2125
from bzrlib.workingtree import WorkingTreeFormat3
2126
self.step('Upgrading working tree')
2127
self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
2128
self.make_lock('checkout')
2130
'checkout', WorkingTreeFormat3())
2131
self.bzrdir.transport.delete_multi(
2132
self.garbage_inventories, self.pb)
2133
for entry in checkout_files:
2134
self.move_entry('checkout', entry)
2135
if last_revision is not None:
2136
self.bzrdir._control_files.put_utf8(
2137
'checkout/last-revision', last_revision)
2138
self.bzrdir._control_files.put_utf8(
2139
'branch-format', BzrDirMetaFormat1().get_format_string())
2140
return BzrDir.open(self.bzrdir.root_transport.base)
2142
def make_lock(self, name):
2143
"""Make a lock for the new control dir name."""
2144
self.step('Make %s lock' % name)
2145
ld = lockdir.LockDir(self.bzrdir.transport,
2147
file_modebits=self.file_mode,
2148
dir_modebits=self.dir_mode)
2151
def move_entry(self, new_dir, entry):
2152
"""Move then entry name into new_dir."""
2154
mandatory = entry[1]
2155
self.step('Moving %s' % name)
2157
self.bzrdir.transport.move(name, '%s/%s' % (new_dir, name))
2158
except errors.NoSuchFile:
2162
def put_format(self, dirname, format):
2163
self.bzrdir._control_files.put_utf8('%s/format' % dirname, format.get_format_string())
2166
class ConvertMetaToMeta(Converter):
2167
"""Converts the components of metadirs."""
2169
def __init__(self, target_format):
2170
"""Create a metadir to metadir converter.
2172
:param target_format: The final metadir format that is desired.
2174
self.target_format = target_format
2176
def convert(self, to_convert, pb):
2177
"""See Converter.convert()."""
2178
self.bzrdir = to_convert
2182
self.step('checking repository format')
2184
repo = self.bzrdir.open_repository()
2185
except errors.NoRepositoryPresent:
2188
if not isinstance(repo._format, self.target_format.repository_format.__class__):
2189
from bzrlib.repository import CopyConverter
2190
self.pb.note('starting repository conversion')
2191
converter = CopyConverter(self.target_format.repository_format)
2192
converter.convert(repo, pb)
2194
branch = self.bzrdir.open_branch()
2195
except errors.NotBranchError:
2198
# TODO: conversions of Branch and Tree should be done by
2199
# InterXFormat lookups
2200
# Avoid circular imports
2201
from bzrlib import branch as _mod_branch
2202
if (branch._format.__class__ is _mod_branch.BzrBranchFormat5 and
2203
self.target_format.get_branch_format().__class__ is
2204
_mod_branch.BzrBranchFormat6):
2205
branch_converter = _mod_branch.Converter5to6()
2206
branch_converter.convert(branch)
2208
tree = self.bzrdir.open_workingtree(recommend_upgrade=False)
2209
except (errors.NoWorkingTree, errors.NotLocalUrl):
2212
# TODO: conversions of Branch and Tree should be done by
2213
# InterXFormat lookups
2214
if (isinstance(tree, workingtree.WorkingTree3) and
2215
not isinstance(tree, workingtree_4.WorkingTree4) and
2216
isinstance(self.target_format.workingtree_format,
2217
workingtree_4.WorkingTreeFormat4)):
2218
workingtree_4.Converter3to4().convert(tree)
2222
# This is not in remote.py because it's small, and needs to be registered.
2223
# Putting it in remote.py creates a circular import problem.
2224
# we can make it a lazy object if the control formats is turned into something
2226
class RemoteBzrDirFormat(BzrDirMetaFormat1):
2227
"""Format representing bzrdirs accessed via a smart server"""
2229
def get_format_description(self):
2230
return 'bzr remote bzrdir'
2233
def probe_transport(klass, transport):
2234
"""Return a RemoteBzrDirFormat object if it looks possible."""
2236
client = transport.get_smart_client()
2237
except (NotImplementedError, AttributeError,
2238
errors.TransportNotPossible):
2239
# no smart server, so not a branch for this format type.
2240
raise errors.NotBranchError(path=transport.base)
2242
# Send a 'hello' request in protocol version one, and decline to
2243
# open it if the server doesn't support our required version (2) so
2244
# that the VFS-based transport will do it.
2245
request = client.get_request()
2246
smart_protocol = protocol.SmartClientRequestProtocolOne(request)
2247
server_version = smart_protocol.query_version()
2248
if server_version != 2:
2249
raise errors.NotBranchError(path=transport.base)
2252
def initialize_on_transport(self, transport):
2254
# hand off the request to the smart server
2255
shared_medium = transport.get_shared_medium()
2256
except errors.NoSmartMedium:
2257
# TODO: lookup the local format from a server hint.
2258
local_dir_format = BzrDirMetaFormat1()
2259
return local_dir_format.initialize_on_transport(transport)
2260
client = _SmartClient(shared_medium)
2261
path = client.remote_path_from_transport(transport)
2262
response = _SmartClient(shared_medium).call('BzrDirFormat.initialize',
2264
assert response[0] in ('ok', ), 'unexpected response code %s' % (response,)
2265
return remote.RemoteBzrDir(transport)
2267
def _open(self, transport):
2268
return remote.RemoteBzrDir(transport)
2270
def __eq__(self, other):
2271
if not isinstance(other, RemoteBzrDirFormat):
2273
return self.get_format_description() == other.get_format_description()
2276
BzrDirFormat.register_control_server_format(RemoteBzrDirFormat)
2279
class BzrDirFormatInfo(object):
2281
def __init__(self, native, deprecated, hidden):
2282
self.deprecated = deprecated
2283
self.native = native
2284
self.hidden = hidden
2287
class BzrDirFormatRegistry(registry.Registry):
2288
"""Registry of user-selectable BzrDir subformats.
2290
Differs from BzrDirFormat._control_formats in that it provides sub-formats,
2291
e.g. BzrDirMeta1 with weave repository. Also, it's more user-oriented.
2294
def register_metadir(self, key,
2295
repository_format, help, native=True, deprecated=False,
2299
"""Register a metadir subformat.
2301
These all use a BzrDirMetaFormat1 bzrdir, but can be parameterized
2302
by the Repository format.
2304
:param repository_format: The fully-qualified repository format class
2306
:param branch_format: Fully-qualified branch format class name as
2308
:param tree_format: Fully-qualified tree format class name as
2311
# This should be expanded to support setting WorkingTree and Branch
2312
# formats, once BzrDirMetaFormat1 supports that.
2313
def _load(full_name):
2314
mod_name, factory_name = full_name.rsplit('.', 1)
2316
mod = __import__(mod_name, globals(), locals(),
2318
except ImportError, e:
2319
raise ImportError('failed to load %s: %s' % (full_name, e))
2321
factory = getattr(mod, factory_name)
2322
except AttributeError:
2323
raise AttributeError('no factory %s in module %r'
2328
bd = BzrDirMetaFormat1()
2329
if branch_format is not None:
2330
bd.set_branch_format(_load(branch_format))
2331
if tree_format is not None:
2332
bd.workingtree_format = _load(tree_format)
2333
if repository_format is not None:
2334
bd.repository_format = _load(repository_format)
2336
self.register(key, helper, help, native, deprecated, hidden)
2338
def register(self, key, factory, help, native=True, deprecated=False,
2340
"""Register a BzrDirFormat factory.
2342
The factory must be a callable that takes one parameter: the key.
2343
It must produce an instance of the BzrDirFormat when called.
2345
This function mainly exists to prevent the info object from being
2348
registry.Registry.register(self, key, factory, help,
2349
BzrDirFormatInfo(native, deprecated, hidden))
2351
def register_lazy(self, key, module_name, member_name, help, native=True,
2352
deprecated=False, hidden=False):
2353
registry.Registry.register_lazy(self, key, module_name, member_name,
2354
help, BzrDirFormatInfo(native, deprecated, hidden))
2356
def set_default(self, key):
2357
"""Set the 'default' key to be a clone of the supplied key.
2359
This method must be called once and only once.
2361
registry.Registry.register(self, 'default', self.get(key),
2362
self.get_help(key), info=self.get_info(key))
2364
def set_default_repository(self, key):
2365
"""Set the FormatRegistry default and Repository default.
2367
This is a transitional method while Repository.set_default_format
2370
if 'default' in self:
2371
self.remove('default')
2372
self.set_default(key)
2373
format = self.get('default')()
2374
assert isinstance(format, BzrDirMetaFormat1)
2376
def make_bzrdir(self, key):
2377
return self.get(key)()
2379
def help_topic(self, topic):
2380
output = textwrap.dedent("""\
2381
These formats can be used for creating branches, working trees, and
2385
default_realkey = None
2386
default_help = self.get_help('default')
2388
for key in self.keys():
2389
if key == 'default':
2391
help = self.get_help(key)
2392
if help == default_help:
2393
default_realkey = key
2395
help_pairs.append((key, help))
2397
def wrapped(key, help, info):
2399
help = '(native) ' + help
2400
return ':%s:\n%s\n\n' % (key,
2401
textwrap.fill(help, initial_indent=' ',
2402
subsequent_indent=' '))
2403
if default_realkey is not None:
2404
output += wrapped(default_realkey, '(default) %s' % default_help,
2405
self.get_info('default'))
2406
deprecated_pairs = []
2407
for key, help in help_pairs:
2408
info = self.get_info(key)
2411
elif info.deprecated:
2412
deprecated_pairs.append((key, help))
2414
output += wrapped(key, help, info)
2415
if len(deprecated_pairs) > 0:
2416
output += "Deprecated formats are shown below.\n\n"
2417
for key, help in deprecated_pairs:
2418
info = self.get_info(key)
2419
output += wrapped(key, help, info)
2424
format_registry = BzrDirFormatRegistry()
2425
format_registry.register('weave', BzrDirFormat6,
2426
'Pre-0.8 format. Slower than knit and does not'
2427
' support checkouts or shared repositories.',
2429
format_registry.register_metadir('knit',
2430
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2431
'Format using knits. Recommended for interoperation with bzr <= 0.14.',
2432
branch_format='bzrlib.branch.BzrBranchFormat5',
2433
tree_format='bzrlib.workingtree.WorkingTreeFormat3')
2434
format_registry.register_metadir('metaweave',
2435
'bzrlib.repofmt.weaverepo.RepositoryFormat7',
2436
'Transitional format in 0.8. Slower than knit.',
2437
branch_format='bzrlib.branch.BzrBranchFormat5',
2438
tree_format='bzrlib.workingtree.WorkingTreeFormat3',
2440
format_registry.register_metadir('dirstate',
2441
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2442
help='New in 0.15: Fast local operations. Compatible with bzr 0.8 and '
2443
'above when accessed over the network.',
2444
branch_format='bzrlib.branch.BzrBranchFormat5',
2445
# this uses bzrlib.workingtree.WorkingTreeFormat4 because importing
2446
# directly from workingtree_4 triggers a circular import.
2447
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2449
format_registry.register_metadir('dirstate-tags',
2450
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2451
help='New in 0.15: Fast local operations and improved scaling for '
2452
'network operations. Additionally adds support for tags.'
2453
' Incompatible with bzr < 0.15.',
2454
branch_format='bzrlib.branch.BzrBranchFormat6',
2455
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2457
format_registry.register_metadir('dirstate-with-subtree',
2458
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
2459
help='New in 0.15: Fast local operations and improved scaling for '
2460
'network operations. Additionally adds support for versioning nested '
2461
'bzr branches. Incompatible with bzr < 0.15.',
2462
branch_format='bzrlib.branch.BzrBranchFormat6',
2463
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2466
format_registry.set_default('dirstate-tags')