1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
"""BzrDir logic. The BzrDir is the basic control directory used by bzr.
19
At format 7 this was split out into Branch, Repository and Checkout control
23
# TODO: remove unittest dependency; put that stuff inside the test suite
25
# TODO: Can we move specific formats into separate modules to make this file
28
from cStringIO import StringIO
32
from bzrlib.lazy_import import lazy_import
33
lazy_import(globals(), """
34
from copy import deepcopy
35
from stat import S_ISDIR
45
revision as _mod_revision,
54
from bzrlib.osutils import (
59
from bzrlib.smart.client import _SmartClient
60
from bzrlib.smart import protocol
61
from bzrlib.store.revision.text import TextRevisionStore
62
from bzrlib.store.text import TextStore
63
from bzrlib.store.versioned import WeaveStore
64
from bzrlib.transactions import WriteTransaction
65
from bzrlib.transport import (
66
do_catching_redirections,
69
from bzrlib.weave import Weave
72
from bzrlib.trace import (
76
from bzrlib.transport.local import LocalTransport
80
"""A .bzr control diretory.
82
BzrDir instances let you create or open any of the things that can be
83
found within .bzr - checkouts, branches and repositories.
86
the transport which this bzr dir is rooted at (i.e. file:///.../.bzr/)
88
a transport connected to the directory this bzr was opened from.
92
"""Invoke break_lock on the first object in the bzrdir.
94
If there is a tree, the tree is opened and break_lock() called.
95
Otherwise, branch is tried, and finally repository.
97
# XXX: This seems more like a UI function than something that really
98
# belongs in this class.
100
thing_to_unlock = self.open_workingtree()
101
except (errors.NotLocalUrl, errors.NoWorkingTree):
103
thing_to_unlock = self.open_branch()
104
except errors.NotBranchError:
106
thing_to_unlock = self.open_repository()
107
except errors.NoRepositoryPresent:
109
thing_to_unlock.break_lock()
111
def can_convert_format(self):
112
"""Return true if this bzrdir is one whose format we can convert from."""
115
def check_conversion_target(self, target_format):
116
target_repo_format = target_format.repository_format
117
source_repo_format = self._format.repository_format
118
source_repo_format.check_conversion_target(target_repo_format)
121
def _check_supported(format, allow_unsupported,
122
recommend_upgrade=True,
124
"""Give an error or warning on old formats.
126
:param format: may be any kind of format - workingtree, branch,
129
:param allow_unsupported: If true, allow opening
130
formats that are strongly deprecated, and which may
131
have limited functionality.
133
:param recommend_upgrade: If true (default), warn
134
the user through the ui object that they may wish
135
to upgrade the object.
137
# TODO: perhaps move this into a base Format class; it's not BzrDir
138
# specific. mbp 20070323
139
if not allow_unsupported and not format.is_supported():
140
# see open_downlevel to open legacy branches.
141
raise errors.UnsupportedFormatError(format=format)
142
if recommend_upgrade \
143
and getattr(format, 'upgrade_recommended', False):
144
ui.ui_factory.recommend_upgrade(
145
format.get_format_description(),
148
def clone(self, url, revision_id=None, force_new_repo=False):
149
"""Clone this bzrdir and its contents to url verbatim.
151
If urls last component does not exist, it will be created.
153
if revision_id is not None, then the clone operation may tune
154
itself to download less data.
155
:param force_new_repo: Do not use a shared repository for the target
156
even if one is available.
158
return self.clone_on_transport(get_transport(url),
159
revision_id=revision_id,
160
force_new_repo=force_new_repo)
162
def clone_on_transport(self, transport, revision_id=None,
163
force_new_repo=False):
164
"""Clone this bzrdir and its contents to transport verbatim.
166
If the target directory does not exist, it will be created.
168
if revision_id is not None, then the clone operation may tune
169
itself to download less data.
170
:param force_new_repo: Do not use a shared repository for the target
171
even if one is available.
173
transport.ensure_base()
174
result = self._format.initialize_on_transport(transport)
176
local_repo = self.find_repository()
177
except errors.NoRepositoryPresent:
180
# may need to copy content in
182
result_repo = local_repo.clone(
184
revision_id=revision_id)
185
result_repo.set_make_working_trees(local_repo.make_working_trees())
188
result_repo = result.find_repository()
189
# fetch content this dir needs.
190
result_repo.fetch(local_repo, revision_id=revision_id)
191
except errors.NoRepositoryPresent:
192
# needed to make one anyway.
193
result_repo = local_repo.clone(
195
revision_id=revision_id)
196
result_repo.set_make_working_trees(local_repo.make_working_trees())
197
# 1 if there is a branch present
198
# make sure its content is available in the target repository
201
self.open_branch().clone(result, revision_id=revision_id)
202
except errors.NotBranchError:
205
self.open_workingtree().clone(result)
206
except (errors.NoWorkingTree, errors.NotLocalUrl):
210
# TODO: This should be given a Transport, and should chdir up; otherwise
211
# this will open a new connection.
212
def _make_tail(self, url):
213
t = get_transport(url)
216
# TODO: Should take a Transport
218
def create(cls, base, format=None):
219
"""Create a new BzrDir at the url 'base'.
221
This will call the current default formats initialize with base
222
as the only parameter.
224
:param format: If supplied, the format of branch to create. If not
225
supplied, the default is used.
227
if cls is not BzrDir:
228
raise AssertionError("BzrDir.create always creates the default"
229
" format, not one of %r" % cls)
230
t = get_transport(base)
233
format = BzrDirFormat.get_default_format()
234
return format.initialize(safe_unicode(base))
236
def create_branch(self):
237
"""Create a branch in this BzrDir.
239
The bzrdirs format will control what branch format is created.
240
For more control see BranchFormatXX.create(a_bzrdir).
242
raise NotImplementedError(self.create_branch)
245
def create_branch_and_repo(base, force_new_repo=False, format=None):
246
"""Create a new BzrDir, Branch and Repository at the url 'base'.
248
This will use the current default BzrDirFormat, and use whatever
249
repository format that that uses via bzrdir.create_branch and
250
create_repository. If a shared repository is available that is used
253
The created Branch object is returned.
255
:param base: The URL to create the branch at.
256
:param force_new_repo: If True a new repository is always created.
258
bzrdir = BzrDir.create(base, format)
259
bzrdir._find_or_create_repository(force_new_repo)
260
return bzrdir.create_branch()
262
def _find_or_create_repository(self, force_new_repo):
263
"""Create a new repository if needed, returning the repository."""
265
return self.create_repository()
267
return self.find_repository()
268
except errors.NoRepositoryPresent:
269
return self.create_repository()
272
def create_branch_convenience(base, force_new_repo=False,
273
force_new_tree=None, format=None):
274
"""Create a new BzrDir, Branch and Repository at the url 'base'.
276
This is a convenience function - it will use an existing repository
277
if possible, can be told explicitly whether to create a working tree or
280
This will use the current default BzrDirFormat, and use whatever
281
repository format that that uses via bzrdir.create_branch and
282
create_repository. If a shared repository is available that is used
283
preferentially. Whatever repository is used, its tree creation policy
286
The created Branch object is returned.
287
If a working tree cannot be made due to base not being a file:// url,
288
no error is raised unless force_new_tree is True, in which case no
289
data is created on disk and NotLocalUrl is raised.
291
:param base: The URL to create the branch at.
292
:param force_new_repo: If True a new repository is always created.
293
:param force_new_tree: If True or False force creation of a tree or
294
prevent such creation respectively.
295
:param format: Override for the for the bzrdir format to create
298
# check for non local urls
299
t = get_transport(safe_unicode(base))
300
if not isinstance(t, LocalTransport):
301
raise errors.NotLocalUrl(base)
302
bzrdir = BzrDir.create(base, format)
303
repo = bzrdir._find_or_create_repository(force_new_repo)
304
result = bzrdir.create_branch()
305
if force_new_tree or (repo.make_working_trees() and
306
force_new_tree is None):
308
bzrdir.create_workingtree()
309
except errors.NotLocalUrl:
314
def create_repository(base, shared=False, format=None):
315
"""Create a new BzrDir and Repository at the url 'base'.
317
If no format is supplied, this will default to the current default
318
BzrDirFormat by default, and use whatever repository format that that
319
uses for bzrdirformat.create_repository.
321
:param shared: Create a shared repository rather than a standalone
323
The Repository object is returned.
325
This must be overridden as an instance method in child classes, where
326
it should take no parameters and construct whatever repository format
327
that child class desires.
329
bzrdir = BzrDir.create(base, format)
330
return bzrdir.create_repository(shared)
333
def create_standalone_workingtree(base, format=None):
334
"""Create a new BzrDir, WorkingTree, Branch and Repository at 'base'.
336
'base' must be a local path or a file:// url.
338
This will use the current default BzrDirFormat, and use whatever
339
repository format that that uses for bzrdirformat.create_workingtree,
340
create_branch and create_repository.
342
:return: The WorkingTree object.
344
t = get_transport(safe_unicode(base))
345
if not isinstance(t, LocalTransport):
346
raise errors.NotLocalUrl(base)
347
bzrdir = BzrDir.create_branch_and_repo(safe_unicode(base),
349
format=format).bzrdir
350
return bzrdir.create_workingtree()
352
def create_workingtree(self, revision_id=None):
353
"""Create a working tree at this BzrDir.
355
revision_id: create it as of this revision id.
357
raise NotImplementedError(self.create_workingtree)
359
def retire_bzrdir(self):
360
"""Permanently disable the bzrdir.
362
This is done by renaming it to give the user some ability to recover
363
if there was a problem.
365
This will have horrible consequences if anyone has anything locked or
368
for i in xrange(10000):
370
to_path = '.bzr.retired.%d' % i
371
self.root_transport.rename('.bzr', to_path)
372
note("renamed %s to %s"
373
% (self.root_transport.abspath('.bzr'), to_path))
375
except (errors.TransportError, IOError, errors.PathError):
378
def destroy_workingtree(self):
379
"""Destroy the working tree at this BzrDir.
381
Formats that do not support this may raise UnsupportedOperation.
383
raise NotImplementedError(self.destroy_workingtree)
385
def destroy_workingtree_metadata(self):
386
"""Destroy the control files for the working tree at this BzrDir.
388
The contents of working tree files are not affected.
389
Formats that do not support this may raise UnsupportedOperation.
391
raise NotImplementedError(self.destroy_workingtree_metadata)
393
def find_repository(self):
394
"""Find the repository that should be used for a_bzrdir.
396
This does not require a branch as we use it to find the repo for
397
new branches as well as to hook existing branches up to their
401
return self.open_repository()
402
except errors.NoRepositoryPresent:
404
next_transport = self.root_transport.clone('..')
406
# find the next containing bzrdir
408
found_bzrdir = BzrDir.open_containing_from_transport(
410
except errors.NotBranchError:
412
raise errors.NoRepositoryPresent(self)
413
# does it have a repository ?
415
repository = found_bzrdir.open_repository()
416
except errors.NoRepositoryPresent:
417
next_transport = found_bzrdir.root_transport.clone('..')
418
if (found_bzrdir.root_transport.base == next_transport.base):
419
# top of the file system
423
if ((found_bzrdir.root_transport.base ==
424
self.root_transport.base) or repository.is_shared()):
427
raise errors.NoRepositoryPresent(self)
428
raise errors.NoRepositoryPresent(self)
430
def get_branch_reference(self):
431
"""Return the referenced URL for the branch in this bzrdir.
433
:raises NotBranchError: If there is no Branch.
434
:return: The URL the branch in this bzrdir references if it is a
435
reference branch, or None for regular branches.
439
def get_branch_transport(self, branch_format):
440
"""Get the transport for use by branch format in this BzrDir.
442
Note that bzr dirs that do not support format strings will raise
443
IncompatibleFormat if the branch format they are given has
444
a format string, and vice versa.
446
If branch_format is None, the transport is returned with no
447
checking. if it is not None, then the returned transport is
448
guaranteed to point to an existing directory ready for use.
450
raise NotImplementedError(self.get_branch_transport)
452
def get_repository_transport(self, repository_format):
453
"""Get the transport for use by repository format in this BzrDir.
455
Note that bzr dirs that do not support format strings will raise
456
IncompatibleFormat if the repository format they are given has
457
a format string, and vice versa.
459
If repository_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_repository_transport)
465
def get_workingtree_transport(self, tree_format):
466
"""Get the transport for use by workingtree format in this BzrDir.
468
Note that bzr dirs that do not support format strings will raise
469
IncompatibleFormat if the workingtree format they are given has a
470
format string, and vice versa.
472
If workingtree_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_workingtree_transport)
478
def __init__(self, _transport, _format):
479
"""Initialize a Bzr control dir object.
481
Only really common logic should reside here, concrete classes should be
482
made with varying behaviours.
484
:param _format: the format that is creating this BzrDir instance.
485
:param _transport: the transport this dir is based at.
487
self._format = _format
488
self.transport = _transport.clone('.bzr')
489
self.root_transport = _transport
491
def is_control_filename(self, filename):
492
"""True if filename is the name of a path which is reserved for bzrdir's.
494
:param filename: A filename within the root transport of this bzrdir.
496
This is true IF and ONLY IF the filename is part of the namespace reserved
497
for bzr control dirs. Currently this is the '.bzr' directory in the root
498
of the root_transport. it is expected that plugins will need to extend
499
this in the future - for instance to make bzr talk with svn working
502
# this might be better on the BzrDirFormat class because it refers to
503
# all the possible bzrdir disk formats.
504
# This method is tested via the workingtree is_control_filename tests-
505
# it was extracted from WorkingTree.is_control_filename. If the methods
506
# contract is extended beyond the current trivial implementation please
507
# add new tests for it to the appropriate place.
508
return filename == '.bzr' or filename.startswith('.bzr/')
510
def needs_format_conversion(self, format=None):
511
"""Return true if this bzrdir needs convert_format run on it.
513
For instance, if the repository format is out of date but the
514
branch and working tree are not, this should return True.
516
:param format: Optional parameter indicating a specific desired
517
format we plan to arrive at.
519
raise NotImplementedError(self.needs_format_conversion)
522
def open_unsupported(base):
523
"""Open a branch which is not supported."""
524
return BzrDir.open(base, _unsupported=True)
527
def open(base, _unsupported=False):
528
"""Open an existing bzrdir, rooted at 'base' (url)
530
_unsupported is a private parameter to the BzrDir class.
532
t = get_transport(base)
533
return BzrDir.open_from_transport(t, _unsupported=_unsupported)
536
def open_from_transport(transport, _unsupported=False,
537
_server_formats=True):
538
"""Open a bzrdir within a particular directory.
540
:param transport: Transport containing the bzrdir.
541
:param _unsupported: private.
543
base = transport.base
545
def find_format(transport):
546
return transport, BzrDirFormat.find_format(
547
transport, _server_formats=_server_formats)
549
def redirected(transport, e, redirection_notice):
550
qualified_source = e.get_source_url()
551
relpath = transport.relpath(qualified_source)
552
if not e.target.endswith(relpath):
553
# Not redirected to a branch-format, not a branch
554
raise errors.NotBranchError(path=e.target)
555
target = e.target[:-len(relpath)]
556
note('%s is%s redirected to %s',
557
transport.base, e.permanently, target)
558
# Let's try with a new transport
559
qualified_target = e.get_target_url()[:-len(relpath)]
560
# FIXME: If 'transport' has a qualifier, this should
561
# be applied again to the new transport *iff* the
562
# schemes used are the same. It's a bit tricky to
563
# verify, so I'll punt for now
565
return get_transport(target)
568
transport, format = do_catching_redirections(find_format,
571
except errors.TooManyRedirections:
572
raise errors.NotBranchError(base)
574
BzrDir._check_supported(format, _unsupported)
575
return format.open(transport, _found=True)
577
def open_branch(self, unsupported=False):
578
"""Open the branch object at this BzrDir if one is present.
580
If unsupported is True, then no longer supported branch formats can
583
TODO: static convenience version of this?
585
raise NotImplementedError(self.open_branch)
588
def open_containing(url):
589
"""Open an existing branch which contains url.
591
:param url: url to search from.
592
See open_containing_from_transport for more detail.
594
return BzrDir.open_containing_from_transport(get_transport(url))
597
def open_containing_from_transport(a_transport):
598
"""Open an existing branch which contains a_transport.base
600
This probes for a branch at a_transport, and searches upwards from there.
602
Basically we keep looking up until we find the control directory or
603
run into the root. If there isn't one, raises NotBranchError.
604
If there is one and it is either an unrecognised format or an unsupported
605
format, UnknownFormatError or UnsupportedFormatError are raised.
606
If there is one, it is returned, along with the unused portion of url.
608
:return: The BzrDir that contains the path, and a Unicode path
609
for the rest of the URL.
611
# this gets the normalised url back. I.e. '.' -> the full path.
612
url = a_transport.base
615
result = BzrDir.open_from_transport(a_transport)
616
return result, urlutils.unescape(a_transport.relpath(url))
617
except errors.NotBranchError, e:
620
new_t = a_transport.clone('..')
621
except errors.InvalidURLJoin:
622
# reached the root, whatever that may be
623
raise errors.NotBranchError(path=url)
624
if new_t.base == a_transport.base:
625
# reached the root, whatever that may be
626
raise errors.NotBranchError(path=url)
630
def open_containing_tree_or_branch(klass, location):
631
"""Return the branch and working tree contained by a location.
633
Returns (tree, branch, relpath).
634
If there is no tree at containing the location, tree will be None.
635
If there is no branch containing the location, an exception will be
637
relpath is the portion of the path that is contained by the branch.
639
bzrdir, relpath = klass.open_containing(location)
641
tree = bzrdir.open_workingtree()
642
except (errors.NoWorkingTree, errors.NotLocalUrl):
644
branch = bzrdir.open_branch()
647
return tree, branch, relpath
649
def open_repository(self, _unsupported=False):
650
"""Open the repository object at this BzrDir if one is present.
652
This will not follow the Branch object pointer - its strictly a direct
653
open facility. Most client code should use open_branch().repository to
656
_unsupported is a private parameter, not part of the api.
657
TODO: static convenience version of this?
659
raise NotImplementedError(self.open_repository)
661
def open_workingtree(self, _unsupported=False,
662
recommend_upgrade=True):
663
"""Open the workingtree object at this BzrDir if one is present.
665
:param recommend_upgrade: Optional keyword parameter, when True (the
666
default), emit through the ui module a recommendation that the user
667
upgrade the working tree when the workingtree being opened is old
668
(but still fully supported).
670
raise NotImplementedError(self.open_workingtree)
672
def has_branch(self):
673
"""Tell if this bzrdir contains a branch.
675
Note: if you're going to open the branch, you should just go ahead
676
and try, and not ask permission first. (This method just opens the
677
branch and discards it, and that's somewhat expensive.)
682
except errors.NotBranchError:
685
def has_workingtree(self):
686
"""Tell if this bzrdir contains a working tree.
688
This will still raise an exception if the bzrdir has a workingtree that
689
is remote & inaccessible.
691
Note: if you're going to open the working tree, you should just go ahead
692
and try, and not ask permission first. (This method just opens the
693
workingtree and discards it, and that's somewhat expensive.)
696
self.open_workingtree(recommend_upgrade=False)
698
except errors.NoWorkingTree:
701
def _cloning_metadir(self):
702
"""Produce a metadir suitable for cloning with"""
703
result_format = self._format.__class__()
706
branch = self.open_branch()
707
source_repository = branch.repository
708
except errors.NotBranchError:
710
source_repository = self.open_repository()
711
except errors.NoRepositoryPresent:
712
source_repository = None
714
# XXX TODO: This isinstance is here because we have not implemented
715
# the fix recommended in bug # 103195 - to delegate this choice the
717
repo_format = source_repository._format
718
if not isinstance(repo_format, remote.RemoteRepositoryFormat):
719
result_format.repository_format = repo_format
721
# TODO: Couldn't we just probe for the format in these cases,
722
# rather than opening the whole tree? It would be a little
723
# faster. mbp 20070401
724
tree = self.open_workingtree(recommend_upgrade=False)
725
except (errors.NoWorkingTree, errors.NotLocalUrl):
726
result_format.workingtree_format = None
728
result_format.workingtree_format = tree._format.__class__()
729
return result_format, source_repository
731
def cloning_metadir(self):
732
"""Produce a metadir suitable for cloning or sprouting with.
734
These operations may produce workingtrees (yes, even though they're
735
"cloning" something that doesn't have a tree, so a viable workingtree
736
format must be selected.
738
format, repository = self._cloning_metadir()
739
if format._workingtree_format is None:
740
if repository is None:
742
tree_format = repository._format._matchingbzrdir.workingtree_format
743
format.workingtree_format = tree_format.__class__()
746
def checkout_metadir(self):
747
return self.cloning_metadir()
749
def sprout(self, url, revision_id=None, force_new_repo=False,
751
"""Create a copy of this bzrdir prepared for use as a new line of
754
If urls last component does not exist, it will be created.
756
Attributes related to the identity of the source branch like
757
branch nickname will be cleaned, a working tree is created
758
whether one existed before or not; and a local branch is always
761
if revision_id is not None, then the clone operation may tune
762
itself to download less data.
764
target_transport = get_transport(url)
765
target_transport.ensure_base()
766
cloning_format = self.cloning_metadir()
767
result = cloning_format.initialize_on_transport(target_transport)
769
source_branch = self.open_branch()
770
source_repository = source_branch.repository
771
except errors.NotBranchError:
774
source_repository = self.open_repository()
775
except errors.NoRepositoryPresent:
776
source_repository = None
781
result_repo = result.find_repository()
782
except errors.NoRepositoryPresent:
784
if source_repository is None and result_repo is not None:
786
elif source_repository is None and result_repo is None:
787
# no repo available, make a new one
788
result.create_repository()
789
elif source_repository is not None and result_repo is None:
790
# have source, and want to make a new target repo
791
result_repo = source_repository.sprout(result, revision_id=revision_id)
793
# fetch needed content into target.
794
if source_repository is not None:
796
# source_repository.copy_content_into(result_repo, revision_id=revision_id)
797
# so we can override the copy method
798
result_repo.fetch(source_repository, revision_id=revision_id)
799
if source_branch is not None:
800
source_branch.sprout(result, revision_id=revision_id)
802
result.create_branch()
803
# TODO: jam 20060426 we probably need a test in here in the
804
# case that the newly sprouted branch is a remote one
805
if result_repo is None or result_repo.make_working_trees():
806
wt = result.create_workingtree()
809
if wt.path2id('') is None:
811
wt.set_root_id(self.open_workingtree.get_root_id())
812
except errors.NoWorkingTree:
818
if recurse == 'down':
820
basis = wt.basis_tree()
822
subtrees = basis.iter_references()
823
recurse_branch = wt.branch
824
elif source_branch is not None:
825
basis = source_branch.basis_tree()
827
subtrees = basis.iter_references()
828
recurse_branch = source_branch
833
for path, file_id in subtrees:
834
target = urlutils.join(url, urlutils.escape(path))
835
sublocation = source_branch.reference_parent(file_id, path)
836
sublocation.bzrdir.sprout(target,
837
basis.get_reference_revision(file_id, path),
838
force_new_repo=force_new_repo, recurse=recurse)
840
if basis is not None:
845
class BzrDirPreSplitOut(BzrDir):
846
"""A common class for the all-in-one formats."""
848
def __init__(self, _transport, _format):
849
"""See BzrDir.__init__."""
850
super(BzrDirPreSplitOut, self).__init__(_transport, _format)
851
assert self._format._lock_class == lockable_files.TransportLock
852
assert self._format._lock_file_name == 'branch-lock'
853
self._control_files = lockable_files.LockableFiles(
854
self.get_branch_transport(None),
855
self._format._lock_file_name,
856
self._format._lock_class)
858
def break_lock(self):
859
"""Pre-splitout bzrdirs do not suffer from stale locks."""
860
raise NotImplementedError(self.break_lock)
862
def clone(self, url, revision_id=None, force_new_repo=False):
863
"""See BzrDir.clone()."""
864
from bzrlib.workingtree import WorkingTreeFormat2
866
result = self._format._initialize_for_clone(url)
867
self.open_repository().clone(result, revision_id=revision_id)
868
from_branch = self.open_branch()
869
from_branch.clone(result, revision_id=revision_id)
871
self.open_workingtree().clone(result)
872
except errors.NotLocalUrl:
873
# make a new one, this format always has to have one.
875
WorkingTreeFormat2().initialize(result)
876
except errors.NotLocalUrl:
877
# but we cannot do it for remote trees.
878
to_branch = result.open_branch()
879
WorkingTreeFormat2().stub_initialize_remote(to_branch.control_files)
882
def create_branch(self):
883
"""See BzrDir.create_branch."""
884
return self.open_branch()
886
def create_repository(self, shared=False):
887
"""See BzrDir.create_repository."""
889
raise errors.IncompatibleFormat('shared repository', self._format)
890
return self.open_repository()
892
def create_workingtree(self, revision_id=None):
893
"""See BzrDir.create_workingtree."""
894
# this looks buggy but is not -really-
895
# because this format creates the workingtree when the bzrdir is
897
# clone and sprout will have set the revision_id
898
# and that will have set it for us, its only
899
# specific uses of create_workingtree in isolation
900
# that can do wonky stuff here, and that only
901
# happens for creating checkouts, which cannot be
902
# done on this format anyway. So - acceptable wart.
903
result = self.open_workingtree(recommend_upgrade=False)
904
if revision_id is not None:
905
if revision_id == _mod_revision.NULL_REVISION:
906
result.set_parent_ids([])
908
result.set_parent_ids([revision_id])
911
def destroy_workingtree(self):
912
"""See BzrDir.destroy_workingtree."""
913
raise errors.UnsupportedOperation(self.destroy_workingtree, self)
915
def destroy_workingtree_metadata(self):
916
"""See BzrDir.destroy_workingtree_metadata."""
917
raise errors.UnsupportedOperation(self.destroy_workingtree_metadata,
920
def get_branch_transport(self, branch_format):
921
"""See BzrDir.get_branch_transport()."""
922
if branch_format is None:
923
return self.transport
925
branch_format.get_format_string()
926
except NotImplementedError:
927
return self.transport
928
raise errors.IncompatibleFormat(branch_format, self._format)
930
def get_repository_transport(self, repository_format):
931
"""See BzrDir.get_repository_transport()."""
932
if repository_format is None:
933
return self.transport
935
repository_format.get_format_string()
936
except NotImplementedError:
937
return self.transport
938
raise errors.IncompatibleFormat(repository_format, self._format)
940
def get_workingtree_transport(self, workingtree_format):
941
"""See BzrDir.get_workingtree_transport()."""
942
if workingtree_format is None:
943
return self.transport
945
workingtree_format.get_format_string()
946
except NotImplementedError:
947
return self.transport
948
raise errors.IncompatibleFormat(workingtree_format, self._format)
950
def needs_format_conversion(self, format=None):
951
"""See BzrDir.needs_format_conversion()."""
952
# if the format is not the same as the system default,
953
# an upgrade is needed.
955
format = BzrDirFormat.get_default_format()
956
return not isinstance(self._format, format.__class__)
958
def open_branch(self, unsupported=False):
959
"""See BzrDir.open_branch."""
960
from bzrlib.branch import BzrBranchFormat4
961
format = BzrBranchFormat4()
962
self._check_supported(format, unsupported)
963
return format.open(self, _found=True)
965
def sprout(self, url, revision_id=None, force_new_repo=False):
966
"""See BzrDir.sprout()."""
967
from bzrlib.workingtree import WorkingTreeFormat2
969
result = self._format._initialize_for_clone(url)
971
self.open_repository().clone(result, revision_id=revision_id)
972
except errors.NoRepositoryPresent:
975
self.open_branch().sprout(result, revision_id=revision_id)
976
except errors.NotBranchError:
978
# we always want a working tree
979
WorkingTreeFormat2().initialize(result)
983
class BzrDir4(BzrDirPreSplitOut):
984
"""A .bzr version 4 control object.
986
This is a deprecated format and may be removed after sept 2006.
989
def create_repository(self, shared=False):
990
"""See BzrDir.create_repository."""
991
return self._format.repository_format.initialize(self, shared)
993
def needs_format_conversion(self, format=None):
994
"""Format 4 dirs are always in need of conversion."""
997
def open_repository(self):
998
"""See BzrDir.open_repository."""
999
from bzrlib.repofmt.weaverepo import RepositoryFormat4
1000
return RepositoryFormat4().open(self, _found=True)
1003
class BzrDir5(BzrDirPreSplitOut):
1004
"""A .bzr version 5 control object.
1006
This is a deprecated format and may be removed after sept 2006.
1009
def open_repository(self):
1010
"""See BzrDir.open_repository."""
1011
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1012
return RepositoryFormat5().open(self, _found=True)
1014
def open_workingtree(self, _unsupported=False,
1015
recommend_upgrade=True):
1016
"""See BzrDir.create_workingtree."""
1017
from bzrlib.workingtree import WorkingTreeFormat2
1018
wt_format = WorkingTreeFormat2()
1019
# we don't warn here about upgrades; that ought to be handled for the
1021
return wt_format.open(self, _found=True)
1024
class BzrDir6(BzrDirPreSplitOut):
1025
"""A .bzr version 6 control object.
1027
This is a deprecated format and may be removed after sept 2006.
1030
def open_repository(self):
1031
"""See BzrDir.open_repository."""
1032
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1033
return RepositoryFormat6().open(self, _found=True)
1035
def open_workingtree(self, _unsupported=False,
1036
recommend_upgrade=True):
1037
"""See BzrDir.create_workingtree."""
1038
# we don't warn here about upgrades; that ought to be handled for the
1040
from bzrlib.workingtree import WorkingTreeFormat2
1041
return WorkingTreeFormat2().open(self, _found=True)
1044
class BzrDirMeta1(BzrDir):
1045
"""A .bzr meta version 1 control object.
1047
This is the first control object where the
1048
individual aspects are really split out: there are separate repository,
1049
workingtree and branch subdirectories and any subset of the three can be
1050
present within a BzrDir.
1053
def can_convert_format(self):
1054
"""See BzrDir.can_convert_format()."""
1057
def create_branch(self):
1058
"""See BzrDir.create_branch."""
1059
return self._format.get_branch_format().initialize(self)
1061
def create_repository(self, shared=False):
1062
"""See BzrDir.create_repository."""
1063
return self._format.repository_format.initialize(self, shared)
1065
def create_workingtree(self, revision_id=None):
1066
"""See BzrDir.create_workingtree."""
1067
from bzrlib.workingtree import WorkingTreeFormat
1068
return self._format.workingtree_format.initialize(self, revision_id)
1070
def destroy_workingtree(self):
1071
"""See BzrDir.destroy_workingtree."""
1072
wt = self.open_workingtree(recommend_upgrade=False)
1073
repository = wt.branch.repository
1074
empty = repository.revision_tree(_mod_revision.NULL_REVISION)
1075
wt.revert([], old_tree=empty)
1076
self.destroy_workingtree_metadata()
1078
def destroy_workingtree_metadata(self):
1079
self.transport.delete_tree('checkout')
1081
def find_branch_format(self):
1082
"""Find the branch 'format' for this bzrdir.
1084
This might be a synthetic object for e.g. RemoteBranch and SVN.
1086
from bzrlib.branch import BranchFormat
1087
return BranchFormat.find_format(self)
1089
def _get_mkdir_mode(self):
1090
"""Figure out the mode to use when creating a bzrdir subdir."""
1091
temp_control = lockable_files.LockableFiles(self.transport, '',
1092
lockable_files.TransportLock)
1093
return temp_control._dir_mode
1095
def get_branch_reference(self):
1096
"""See BzrDir.get_branch_reference()."""
1097
from bzrlib.branch import BranchFormat
1098
format = BranchFormat.find_format(self)
1099
return format.get_reference(self)
1101
def get_branch_transport(self, branch_format):
1102
"""See BzrDir.get_branch_transport()."""
1103
if branch_format is None:
1104
return self.transport.clone('branch')
1106
branch_format.get_format_string()
1107
except NotImplementedError:
1108
raise errors.IncompatibleFormat(branch_format, self._format)
1110
self.transport.mkdir('branch', mode=self._get_mkdir_mode())
1111
except errors.FileExists:
1113
return self.transport.clone('branch')
1115
def get_repository_transport(self, repository_format):
1116
"""See BzrDir.get_repository_transport()."""
1117
if repository_format is None:
1118
return self.transport.clone('repository')
1120
repository_format.get_format_string()
1121
except NotImplementedError:
1122
raise errors.IncompatibleFormat(repository_format, self._format)
1124
self.transport.mkdir('repository', mode=self._get_mkdir_mode())
1125
except errors.FileExists:
1127
return self.transport.clone('repository')
1129
def get_workingtree_transport(self, workingtree_format):
1130
"""See BzrDir.get_workingtree_transport()."""
1131
if workingtree_format is None:
1132
return self.transport.clone('checkout')
1134
workingtree_format.get_format_string()
1135
except NotImplementedError:
1136
raise errors.IncompatibleFormat(workingtree_format, self._format)
1138
self.transport.mkdir('checkout', mode=self._get_mkdir_mode())
1139
except errors.FileExists:
1141
return self.transport.clone('checkout')
1143
def needs_format_conversion(self, format=None):
1144
"""See BzrDir.needs_format_conversion()."""
1146
format = BzrDirFormat.get_default_format()
1147
if not isinstance(self._format, format.__class__):
1148
# it is not a meta dir format, conversion is needed.
1150
# we might want to push this down to the repository?
1152
if not isinstance(self.open_repository()._format,
1153
format.repository_format.__class__):
1154
# the repository needs an upgrade.
1156
except errors.NoRepositoryPresent:
1159
if not isinstance(self.open_branch()._format,
1160
format.get_branch_format().__class__):
1161
# the branch needs an upgrade.
1163
except errors.NotBranchError:
1166
my_wt = self.open_workingtree(recommend_upgrade=False)
1167
if not isinstance(my_wt._format,
1168
format.workingtree_format.__class__):
1169
# the workingtree needs an upgrade.
1171
except (errors.NoWorkingTree, errors.NotLocalUrl):
1175
def open_branch(self, unsupported=False):
1176
"""See BzrDir.open_branch."""
1177
format = self.find_branch_format()
1178
self._check_supported(format, unsupported)
1179
return format.open(self, _found=True)
1181
def open_repository(self, unsupported=False):
1182
"""See BzrDir.open_repository."""
1183
from bzrlib.repository import RepositoryFormat
1184
format = RepositoryFormat.find_format(self)
1185
self._check_supported(format, unsupported)
1186
return format.open(self, _found=True)
1188
def open_workingtree(self, unsupported=False,
1189
recommend_upgrade=True):
1190
"""See BzrDir.open_workingtree."""
1191
from bzrlib.workingtree import WorkingTreeFormat
1192
format = WorkingTreeFormat.find_format(self)
1193
self._check_supported(format, unsupported,
1195
basedir=self.root_transport.base)
1196
return format.open(self, _found=True)
1199
class BzrDirFormat(object):
1200
"""An encapsulation of the initialization and open routines for a format.
1202
Formats provide three things:
1203
* An initialization routine,
1207
Formats are placed in an dict by their format string for reference
1208
during bzrdir opening. These should be subclasses of BzrDirFormat
1211
Once a format is deprecated, just deprecate the initialize and open
1212
methods on the format class. Do not deprecate the object, as the
1213
object will be created every system load.
1216
_default_format = None
1217
"""The default format used for new .bzr dirs."""
1220
"""The known formats."""
1222
_control_formats = []
1223
"""The registered control formats - .bzr, ....
1225
This is a list of BzrDirFormat objects.
1228
_control_server_formats = []
1229
"""The registered control server formats, e.g. RemoteBzrDirs.
1231
This is a list of BzrDirFormat objects.
1234
_lock_file_name = 'branch-lock'
1236
# _lock_class must be set in subclasses to the lock type, typ.
1237
# TransportLock or LockDir
1240
def find_format(klass, transport, _server_formats=True):
1241
"""Return the format present at transport."""
1243
formats = klass._control_server_formats + klass._control_formats
1245
formats = klass._control_formats
1246
for format in formats:
1248
return format.probe_transport(transport)
1249
except errors.NotBranchError:
1250
# this format does not find a control dir here.
1252
raise errors.NotBranchError(path=transport.base)
1255
def probe_transport(klass, transport):
1256
"""Return the .bzrdir style format present in a directory."""
1258
format_string = transport.get(".bzr/branch-format").read()
1259
except errors.NoSuchFile:
1260
raise errors.NotBranchError(path=transport.base)
1263
return klass._formats[format_string]
1265
raise errors.UnknownFormatError(format=format_string)
1268
def get_default_format(klass):
1269
"""Return the current default format."""
1270
return klass._default_format
1272
def get_format_string(self):
1273
"""Return the ASCII format string that identifies this format."""
1274
raise NotImplementedError(self.get_format_string)
1276
def get_format_description(self):
1277
"""Return the short description for this format."""
1278
raise NotImplementedError(self.get_format_description)
1280
def get_converter(self, format=None):
1281
"""Return the converter to use to convert bzrdirs needing converts.
1283
This returns a bzrlib.bzrdir.Converter object.
1285
This should return the best upgrader to step this format towards the
1286
current default format. In the case of plugins we can/should provide
1287
some means for them to extend the range of returnable converters.
1289
:param format: Optional format to override the default format of the
1292
raise NotImplementedError(self.get_converter)
1294
def initialize(self, url):
1295
"""Create a bzr control dir at this url and return an opened copy.
1297
Subclasses should typically override initialize_on_transport
1298
instead of this method.
1300
return self.initialize_on_transport(get_transport(url))
1302
def initialize_on_transport(self, transport):
1303
"""Initialize a new bzrdir in the base directory of a Transport."""
1304
# Since we don't have a .bzr directory, inherit the
1305
# mode from the root directory
1306
temp_control = lockable_files.LockableFiles(transport,
1307
'', lockable_files.TransportLock)
1308
temp_control._transport.mkdir('.bzr',
1309
# FIXME: RBC 20060121 don't peek under
1311
mode=temp_control._dir_mode)
1312
file_mode = temp_control._file_mode
1314
mutter('created control directory in ' + transport.base)
1315
control = transport.clone('.bzr')
1316
utf8_files = [('README',
1317
"This is a Bazaar-NG control directory.\n"
1318
"Do not change any files in this directory.\n"),
1319
('branch-format', self.get_format_string()),
1321
# NB: no need to escape relative paths that are url safe.
1322
control_files = lockable_files.LockableFiles(control,
1323
self._lock_file_name, self._lock_class)
1324
control_files.create_lock()
1325
control_files.lock_write()
1327
for file, content in utf8_files:
1328
control_files.put_utf8(file, content)
1330
control_files.unlock()
1331
return self.open(transport, _found=True)
1333
def is_supported(self):
1334
"""Is this format supported?
1336
Supported formats must be initializable and openable.
1337
Unsupported formats may not support initialization or committing or
1338
some other features depending on the reason for not being supported.
1342
def same_model(self, target_format):
1343
return (self.repository_format.rich_root_data ==
1344
target_format.rich_root_data)
1347
def known_formats(klass):
1348
"""Return all the known formats.
1350
Concrete formats should override _known_formats.
1352
# There is double indirection here to make sure that control
1353
# formats used by more than one dir format will only be probed
1354
# once. This can otherwise be quite expensive for remote connections.
1356
for format in klass._control_formats:
1357
result.update(format._known_formats())
1361
def _known_formats(klass):
1362
"""Return the known format instances for this control format."""
1363
return set(klass._formats.values())
1365
def open(self, transport, _found=False):
1366
"""Return an instance of this format for the dir transport points at.
1368
_found is a private parameter, do not use it.
1371
found_format = BzrDirFormat.find_format(transport)
1372
if not isinstance(found_format, self.__class__):
1373
raise AssertionError("%s was asked to open %s, but it seems to need "
1375
% (self, transport, found_format))
1376
return self._open(transport)
1378
def _open(self, transport):
1379
"""Template method helper for opening BzrDirectories.
1381
This performs the actual open and any additional logic or parameter
1384
raise NotImplementedError(self._open)
1387
def register_format(klass, format):
1388
klass._formats[format.get_format_string()] = format
1391
def register_control_format(klass, format):
1392
"""Register a format that does not use '.bzr' for its control dir.
1394
TODO: This should be pulled up into a 'ControlDirFormat' base class
1395
which BzrDirFormat can inherit from, and renamed to register_format
1396
there. It has been done without that for now for simplicity of
1399
klass._control_formats.append(format)
1402
def register_control_server_format(klass, format):
1403
"""Register a control format for client-server environments.
1405
These formats will be tried before ones registered with
1406
register_control_format. This gives implementations that decide to the
1407
chance to grab it before anything looks at the contents of the format
1410
klass._control_server_formats.append(format)
1413
@symbol_versioning.deprecated_method(symbol_versioning.zero_fourteen)
1414
def set_default_format(klass, format):
1415
klass._set_default_format(format)
1418
def _set_default_format(klass, format):
1419
"""Set default format (for testing behavior of defaults only)"""
1420
klass._default_format = format
1423
return self.get_format_string()[:-1]
1426
def unregister_format(klass, format):
1427
assert klass._formats[format.get_format_string()] is format
1428
del klass._formats[format.get_format_string()]
1431
def unregister_control_format(klass, format):
1432
klass._control_formats.remove(format)
1435
class BzrDirFormat4(BzrDirFormat):
1436
"""Bzr dir format 4.
1438
This format is a combined format for working tree, branch and repository.
1440
- Format 1 working trees [always]
1441
- Format 4 branches [always]
1442
- Format 4 repositories [always]
1444
This format is deprecated: it indexes texts using a text it which is
1445
removed in format 5; write support for this format has been removed.
1448
_lock_class = lockable_files.TransportLock
1450
def get_format_string(self):
1451
"""See BzrDirFormat.get_format_string()."""
1452
return "Bazaar-NG branch, format 0.0.4\n"
1454
def get_format_description(self):
1455
"""See BzrDirFormat.get_format_description()."""
1456
return "All-in-one format 4"
1458
def get_converter(self, format=None):
1459
"""See BzrDirFormat.get_converter()."""
1460
# there is one and only one upgrade path here.
1461
return ConvertBzrDir4To5()
1463
def initialize_on_transport(self, transport):
1464
"""Format 4 branches cannot be created."""
1465
raise errors.UninitializableFormat(self)
1467
def is_supported(self):
1468
"""Format 4 is not supported.
1470
It is not supported because the model changed from 4 to 5 and the
1471
conversion logic is expensive - so doing it on the fly was not
1476
def _open(self, transport):
1477
"""See BzrDirFormat._open."""
1478
return BzrDir4(transport, self)
1480
def __return_repository_format(self):
1481
"""Circular import protection."""
1482
from bzrlib.repofmt.weaverepo import RepositoryFormat4
1483
return RepositoryFormat4()
1484
repository_format = property(__return_repository_format)
1487
class BzrDirFormat5(BzrDirFormat):
1488
"""Bzr control format 5.
1490
This format is a combined format for working tree, branch and repository.
1492
- Format 2 working trees [always]
1493
- Format 4 branches [always]
1494
- Format 5 repositories [always]
1495
Unhashed stores in the repository.
1498
_lock_class = lockable_files.TransportLock
1500
def get_format_string(self):
1501
"""See BzrDirFormat.get_format_string()."""
1502
return "Bazaar-NG branch, format 5\n"
1504
def get_format_description(self):
1505
"""See BzrDirFormat.get_format_description()."""
1506
return "All-in-one format 5"
1508
def get_converter(self, format=None):
1509
"""See BzrDirFormat.get_converter()."""
1510
# there is one and only one upgrade path here.
1511
return ConvertBzrDir5To6()
1513
def _initialize_for_clone(self, url):
1514
return self.initialize_on_transport(get_transport(url), _cloning=True)
1516
def initialize_on_transport(self, transport, _cloning=False):
1517
"""Format 5 dirs always have working tree, branch and repository.
1519
Except when they are being cloned.
1521
from bzrlib.branch import BzrBranchFormat4
1522
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1523
from bzrlib.workingtree import WorkingTreeFormat2
1524
result = (super(BzrDirFormat5, self).initialize_on_transport(transport))
1525
RepositoryFormat5().initialize(result, _internal=True)
1527
branch = BzrBranchFormat4().initialize(result)
1529
WorkingTreeFormat2().initialize(result)
1530
except errors.NotLocalUrl:
1531
# Even though we can't access the working tree, we need to
1532
# create its control files.
1533
WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
1536
def _open(self, transport):
1537
"""See BzrDirFormat._open."""
1538
return BzrDir5(transport, self)
1540
def __return_repository_format(self):
1541
"""Circular import protection."""
1542
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1543
return RepositoryFormat5()
1544
repository_format = property(__return_repository_format)
1547
class BzrDirFormat6(BzrDirFormat):
1548
"""Bzr control format 6.
1550
This format is a combined format for working tree, branch and repository.
1552
- Format 2 working trees [always]
1553
- Format 4 branches [always]
1554
- Format 6 repositories [always]
1557
_lock_class = lockable_files.TransportLock
1559
def get_format_string(self):
1560
"""See BzrDirFormat.get_format_string()."""
1561
return "Bazaar-NG branch, format 6\n"
1563
def get_format_description(self):
1564
"""See BzrDirFormat.get_format_description()."""
1565
return "All-in-one format 6"
1567
def get_converter(self, format=None):
1568
"""See BzrDirFormat.get_converter()."""
1569
# there is one and only one upgrade path here.
1570
return ConvertBzrDir6ToMeta()
1572
def _initialize_for_clone(self, url):
1573
return self.initialize_on_transport(get_transport(url), _cloning=True)
1575
def initialize_on_transport(self, transport, _cloning=False):
1576
"""Format 6 dirs always have working tree, branch and repository.
1578
Except when they are being cloned.
1580
from bzrlib.branch import BzrBranchFormat4
1581
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1582
from bzrlib.workingtree import WorkingTreeFormat2
1583
result = super(BzrDirFormat6, self).initialize_on_transport(transport)
1584
RepositoryFormat6().initialize(result, _internal=True)
1586
branch = BzrBranchFormat4().initialize(result)
1588
WorkingTreeFormat2().initialize(result)
1589
except errors.NotLocalUrl:
1590
# Even though we can't access the working tree, we need to
1591
# create its control files.
1592
WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
1595
def _open(self, transport):
1596
"""See BzrDirFormat._open."""
1597
return BzrDir6(transport, self)
1599
def __return_repository_format(self):
1600
"""Circular import protection."""
1601
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1602
return RepositoryFormat6()
1603
repository_format = property(__return_repository_format)
1606
class BzrDirMetaFormat1(BzrDirFormat):
1607
"""Bzr meta control format 1
1609
This is the first format with split out working tree, branch and repository
1612
- Format 3 working trees [optional]
1613
- Format 5 branches [optional]
1614
- Format 7 repositories [optional]
1617
_lock_class = lockdir.LockDir
1620
self._workingtree_format = None
1621
self._branch_format = None
1623
def __eq__(self, other):
1624
if other.__class__ is not self.__class__:
1626
if other.repository_format != self.repository_format:
1628
if other.workingtree_format != self.workingtree_format:
1632
def __ne__(self, other):
1633
return not self == other
1635
def get_branch_format(self):
1636
if self._branch_format is None:
1637
from bzrlib.branch import BranchFormat
1638
self._branch_format = BranchFormat.get_default_format()
1639
return self._branch_format
1641
def set_branch_format(self, format):
1642
self._branch_format = format
1644
def get_converter(self, format=None):
1645
"""See BzrDirFormat.get_converter()."""
1647
format = BzrDirFormat.get_default_format()
1648
if not isinstance(self, format.__class__):
1649
# converting away from metadir is not implemented
1650
raise NotImplementedError(self.get_converter)
1651
return ConvertMetaToMeta(format)
1653
def get_format_string(self):
1654
"""See BzrDirFormat.get_format_string()."""
1655
return "Bazaar-NG meta directory, format 1\n"
1657
def get_format_description(self):
1658
"""See BzrDirFormat.get_format_description()."""
1659
return "Meta directory format 1"
1661
def _open(self, transport):
1662
"""See BzrDirFormat._open."""
1663
return BzrDirMeta1(transport, self)
1665
def __return_repository_format(self):
1666
"""Circular import protection."""
1667
if getattr(self, '_repository_format', None):
1668
return self._repository_format
1669
from bzrlib.repository import RepositoryFormat
1670
return RepositoryFormat.get_default_format()
1672
def __set_repository_format(self, value):
1673
"""Allow changint the repository format for metadir formats."""
1674
self._repository_format = value
1676
repository_format = property(__return_repository_format, __set_repository_format)
1678
def __get_workingtree_format(self):
1679
if self._workingtree_format is None:
1680
from bzrlib.workingtree import WorkingTreeFormat
1681
self._workingtree_format = WorkingTreeFormat.get_default_format()
1682
return self._workingtree_format
1684
def __set_workingtree_format(self, wt_format):
1685
self._workingtree_format = wt_format
1687
workingtree_format = property(__get_workingtree_format,
1688
__set_workingtree_format)
1691
# Register bzr control format
1692
BzrDirFormat.register_control_format(BzrDirFormat)
1694
# Register bzr formats
1695
BzrDirFormat.register_format(BzrDirFormat4())
1696
BzrDirFormat.register_format(BzrDirFormat5())
1697
BzrDirFormat.register_format(BzrDirFormat6())
1698
__default_format = BzrDirMetaFormat1()
1699
BzrDirFormat.register_format(__default_format)
1700
BzrDirFormat._default_format = __default_format
1703
class BzrDirTestProviderAdapter(object):
1704
"""A tool to generate a suite testing multiple bzrdir formats at once.
1706
This is done by copying the test once for each transport and injecting
1707
the transport_server, transport_readonly_server, and bzrdir_format
1708
classes into each copy. Each copy is also given a new id() to make it
1712
def __init__(self, vfs_factory, transport_server, transport_readonly_server,
1714
"""Create an object to adapt tests.
1716
:param vfs_server: A factory to create a Transport Server which has
1717
all the VFS methods working, and is writable.
1719
self._vfs_factory = vfs_factory
1720
self._transport_server = transport_server
1721
self._transport_readonly_server = transport_readonly_server
1722
self._formats = formats
1724
def adapt(self, test):
1725
result = unittest.TestSuite()
1726
for format in self._formats:
1727
new_test = deepcopy(test)
1728
new_test.vfs_transport_factory = self._vfs_factory
1729
new_test.transport_server = self._transport_server
1730
new_test.transport_readonly_server = self._transport_readonly_server
1731
new_test.bzrdir_format = format
1732
def make_new_test_id():
1733
new_id = "%s(%s)" % (new_test.id(), format.__class__.__name__)
1734
return lambda: new_id
1735
new_test.id = make_new_test_id()
1736
result.addTest(new_test)
1740
class Converter(object):
1741
"""Converts a disk format object from one format to another."""
1743
def convert(self, to_convert, pb):
1744
"""Perform the conversion of to_convert, giving feedback via pb.
1746
:param to_convert: The disk object to convert.
1747
:param pb: a progress bar to use for progress information.
1750
def step(self, message):
1751
"""Update the pb by a step."""
1753
self.pb.update(message, self.count, self.total)
1756
class ConvertBzrDir4To5(Converter):
1757
"""Converts format 4 bzr dirs to format 5."""
1760
super(ConvertBzrDir4To5, self).__init__()
1761
self.converted_revs = set()
1762
self.absent_revisions = set()
1766
def convert(self, to_convert, pb):
1767
"""See Converter.convert()."""
1768
self.bzrdir = to_convert
1770
self.pb.note('starting upgrade from format 4 to 5')
1771
if isinstance(self.bzrdir.transport, LocalTransport):
1772
self.bzrdir.get_workingtree_transport(None).delete('stat-cache')
1773
self._convert_to_weaves()
1774
return BzrDir.open(self.bzrdir.root_transport.base)
1776
def _convert_to_weaves(self):
1777
self.pb.note('note: upgrade may be faster if all store files are ungzipped first')
1780
stat = self.bzrdir.transport.stat('weaves')
1781
if not S_ISDIR(stat.st_mode):
1782
self.bzrdir.transport.delete('weaves')
1783
self.bzrdir.transport.mkdir('weaves')
1784
except errors.NoSuchFile:
1785
self.bzrdir.transport.mkdir('weaves')
1786
# deliberately not a WeaveFile as we want to build it up slowly.
1787
self.inv_weave = Weave('inventory')
1788
# holds in-memory weaves for all files
1789
self.text_weaves = {}
1790
self.bzrdir.transport.delete('branch-format')
1791
self.branch = self.bzrdir.open_branch()
1792
self._convert_working_inv()
1793
rev_history = self.branch.revision_history()
1794
# to_read is a stack holding the revisions we still need to process;
1795
# appending to it adds new highest-priority revisions
1796
self.known_revisions = set(rev_history)
1797
self.to_read = rev_history[-1:]
1799
rev_id = self.to_read.pop()
1800
if (rev_id not in self.revisions
1801
and rev_id not in self.absent_revisions):
1802
self._load_one_rev(rev_id)
1804
to_import = self._make_order()
1805
for i, rev_id in enumerate(to_import):
1806
self.pb.update('converting revision', i, len(to_import))
1807
self._convert_one_rev(rev_id)
1809
self._write_all_weaves()
1810
self._write_all_revs()
1811
self.pb.note('upgraded to weaves:')
1812
self.pb.note(' %6d revisions and inventories', len(self.revisions))
1813
self.pb.note(' %6d revisions not present', len(self.absent_revisions))
1814
self.pb.note(' %6d texts', self.text_count)
1815
self._cleanup_spare_files_after_format4()
1816
self.branch.control_files.put_utf8('branch-format', BzrDirFormat5().get_format_string())
1818
def _cleanup_spare_files_after_format4(self):
1819
# FIXME working tree upgrade foo.
1820
for n in 'merged-patches', 'pending-merged-patches':
1822
## assert os.path.getsize(p) == 0
1823
self.bzrdir.transport.delete(n)
1824
except errors.NoSuchFile:
1826
self.bzrdir.transport.delete_tree('inventory-store')
1827
self.bzrdir.transport.delete_tree('text-store')
1829
def _convert_working_inv(self):
1830
inv = xml4.serializer_v4.read_inventory(
1831
self.branch.control_files.get('inventory'))
1832
new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
1833
# FIXME inventory is a working tree change.
1834
self.branch.control_files.put('inventory', StringIO(new_inv_xml))
1836
def _write_all_weaves(self):
1837
controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)
1838
weave_transport = self.bzrdir.transport.clone('weaves')
1839
weaves = WeaveStore(weave_transport, prefixed=False)
1840
transaction = WriteTransaction()
1844
for file_id, file_weave in self.text_weaves.items():
1845
self.pb.update('writing weave', i, len(self.text_weaves))
1846
weaves._put_weave(file_id, file_weave, transaction)
1848
self.pb.update('inventory', 0, 1)
1849
controlweaves._put_weave('inventory', self.inv_weave, transaction)
1850
self.pb.update('inventory', 1, 1)
1854
def _write_all_revs(self):
1855
"""Write all revisions out in new form."""
1856
self.bzrdir.transport.delete_tree('revision-store')
1857
self.bzrdir.transport.mkdir('revision-store')
1858
revision_transport = self.bzrdir.transport.clone('revision-store')
1860
_revision_store = TextRevisionStore(TextStore(revision_transport,
1864
transaction = WriteTransaction()
1865
for i, rev_id in enumerate(self.converted_revs):
1866
self.pb.update('write revision', i, len(self.converted_revs))
1867
_revision_store.add_revision(self.revisions[rev_id], transaction)
1871
def _load_one_rev(self, rev_id):
1872
"""Load a revision object into memory.
1874
Any parents not either loaded or abandoned get queued to be
1876
self.pb.update('loading revision',
1877
len(self.revisions),
1878
len(self.known_revisions))
1879
if not self.branch.repository.has_revision(rev_id):
1881
self.pb.note('revision {%s} not present in branch; '
1882
'will be converted as a ghost',
1884
self.absent_revisions.add(rev_id)
1886
rev = self.branch.repository._revision_store.get_revision(rev_id,
1887
self.branch.repository.get_transaction())
1888
for parent_id in rev.parent_ids:
1889
self.known_revisions.add(parent_id)
1890
self.to_read.append(parent_id)
1891
self.revisions[rev_id] = rev
1893
def _load_old_inventory(self, rev_id):
1894
assert rev_id not in self.converted_revs
1895
old_inv_xml = self.branch.repository.inventory_store.get(rev_id).read()
1896
inv = xml4.serializer_v4.read_inventory_from_string(old_inv_xml)
1897
inv.revision_id = rev_id
1898
rev = self.revisions[rev_id]
1899
if rev.inventory_sha1:
1900
assert rev.inventory_sha1 == sha_string(old_inv_xml), \
1901
'inventory sha mismatch for {%s}' % rev_id
1904
def _load_updated_inventory(self, rev_id):
1905
assert rev_id in self.converted_revs
1906
inv_xml = self.inv_weave.get_text(rev_id)
1907
inv = xml5.serializer_v5.read_inventory_from_string(inv_xml)
1910
def _convert_one_rev(self, rev_id):
1911
"""Convert revision and all referenced objects to new format."""
1912
rev = self.revisions[rev_id]
1913
inv = self._load_old_inventory(rev_id)
1914
present_parents = [p for p in rev.parent_ids
1915
if p not in self.absent_revisions]
1916
self._convert_revision_contents(rev, inv, present_parents)
1917
self._store_new_weave(rev, inv, present_parents)
1918
self.converted_revs.add(rev_id)
1920
def _store_new_weave(self, rev, inv, present_parents):
1921
# the XML is now updated with text versions
1923
entries = inv.iter_entries()
1925
for path, ie in entries:
1926
assert getattr(ie, 'revision', None) is not None, \
1927
'no revision on {%s} in {%s}' % \
1928
(file_id, rev.revision_id)
1929
new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
1930
new_inv_sha1 = sha_string(new_inv_xml)
1931
self.inv_weave.add_lines(rev.revision_id,
1933
new_inv_xml.splitlines(True))
1934
rev.inventory_sha1 = new_inv_sha1
1936
def _convert_revision_contents(self, rev, inv, present_parents):
1937
"""Convert all the files within a revision.
1939
Also upgrade the inventory to refer to the text revision ids."""
1940
rev_id = rev.revision_id
1941
mutter('converting texts of revision {%s}',
1943
parent_invs = map(self._load_updated_inventory, present_parents)
1944
entries = inv.iter_entries()
1946
for path, ie in entries:
1947
self._convert_file_version(rev, ie, parent_invs)
1949
def _convert_file_version(self, rev, ie, parent_invs):
1950
"""Convert one version of one file.
1952
The file needs to be added into the weave if it is a merge
1953
of >=2 parents or if it's changed from its parent.
1955
file_id = ie.file_id
1956
rev_id = rev.revision_id
1957
w = self.text_weaves.get(file_id)
1960
self.text_weaves[file_id] = w
1961
text_changed = False
1962
previous_entries = ie.find_previous_heads(parent_invs,
1966
for old_revision in previous_entries:
1967
# if this fails, its a ghost ?
1968
assert old_revision in self.converted_revs, \
1969
"Revision {%s} not in converted_revs" % old_revision
1970
self.snapshot_ie(previous_entries, ie, w, rev_id)
1972
assert getattr(ie, 'revision', None) is not None
1974
def snapshot_ie(self, previous_revisions, ie, w, rev_id):
1975
# TODO: convert this logic, which is ~= snapshot to
1976
# a call to:. This needs the path figured out. rather than a work_tree
1977
# a v4 revision_tree can be given, or something that looks enough like
1978
# one to give the file content to the entry if it needs it.
1979
# and we need something that looks like a weave store for snapshot to
1981
#ie.snapshot(rev, PATH, previous_revisions, REVISION_TREE, InMemoryWeaveStore(self.text_weaves))
1982
if len(previous_revisions) == 1:
1983
previous_ie = previous_revisions.values()[0]
1984
if ie._unchanged(previous_ie):
1985
ie.revision = previous_ie.revision
1988
text = self.branch.repository.text_store.get(ie.text_id)
1989
file_lines = text.readlines()
1990
assert sha_strings(file_lines) == ie.text_sha1
1991
assert sum(map(len, file_lines)) == ie.text_size
1992
w.add_lines(rev_id, previous_revisions, file_lines)
1993
self.text_count += 1
1995
w.add_lines(rev_id, previous_revisions, [])
1996
ie.revision = rev_id
1998
def _make_order(self):
1999
"""Return a suitable order for importing revisions.
2001
The order must be such that an revision is imported after all
2002
its (present) parents.
2004
todo = set(self.revisions.keys())
2005
done = self.absent_revisions.copy()
2008
# scan through looking for a revision whose parents
2010
for rev_id in sorted(list(todo)):
2011
rev = self.revisions[rev_id]
2012
parent_ids = set(rev.parent_ids)
2013
if parent_ids.issubset(done):
2014
# can take this one now
2015
order.append(rev_id)
2021
class ConvertBzrDir5To6(Converter):
2022
"""Converts format 5 bzr dirs to format 6."""
2024
def convert(self, to_convert, pb):
2025
"""See Converter.convert()."""
2026
self.bzrdir = to_convert
2028
self.pb.note('starting upgrade from format 5 to 6')
2029
self._convert_to_prefixed()
2030
return BzrDir.open(self.bzrdir.root_transport.base)
2032
def _convert_to_prefixed(self):
2033
from bzrlib.store import TransportStore
2034
self.bzrdir.transport.delete('branch-format')
2035
for store_name in ["weaves", "revision-store"]:
2036
self.pb.note("adding prefixes to %s" % store_name)
2037
store_transport = self.bzrdir.transport.clone(store_name)
2038
store = TransportStore(store_transport, prefixed=True)
2039
for urlfilename in store_transport.list_dir('.'):
2040
filename = urlutils.unescape(urlfilename)
2041
if (filename.endswith(".weave") or
2042
filename.endswith(".gz") or
2043
filename.endswith(".sig")):
2044
file_id = os.path.splitext(filename)[0]
2047
prefix_dir = store.hash_prefix(file_id)
2048
# FIXME keep track of the dirs made RBC 20060121
2050
store_transport.move(filename, prefix_dir + '/' + filename)
2051
except errors.NoSuchFile: # catches missing dirs strangely enough
2052
store_transport.mkdir(prefix_dir)
2053
store_transport.move(filename, prefix_dir + '/' + filename)
2054
self.bzrdir._control_files.put_utf8('branch-format', BzrDirFormat6().get_format_string())
2057
class ConvertBzrDir6ToMeta(Converter):
2058
"""Converts format 6 bzr dirs to metadirs."""
2060
def convert(self, to_convert, pb):
2061
"""See Converter.convert()."""
2062
from bzrlib.repofmt.weaverepo import RepositoryFormat7
2063
from bzrlib.branch import BzrBranchFormat5
2064
self.bzrdir = to_convert
2067
self.total = 20 # the steps we know about
2068
self.garbage_inventories = []
2070
self.pb.note('starting upgrade from format 6 to metadir')
2071
self.bzrdir._control_files.put_utf8('branch-format', "Converting to format 6")
2072
# its faster to move specific files around than to open and use the apis...
2073
# first off, nuke ancestry.weave, it was never used.
2075
self.step('Removing ancestry.weave')
2076
self.bzrdir.transport.delete('ancestry.weave')
2077
except errors.NoSuchFile:
2079
# find out whats there
2080
self.step('Finding branch files')
2081
last_revision = self.bzrdir.open_branch().last_revision()
2082
bzrcontents = self.bzrdir.transport.list_dir('.')
2083
for name in bzrcontents:
2084
if name.startswith('basis-inventory.'):
2085
self.garbage_inventories.append(name)
2086
# create new directories for repository, working tree and branch
2087
self.dir_mode = self.bzrdir._control_files._dir_mode
2088
self.file_mode = self.bzrdir._control_files._file_mode
2089
repository_names = [('inventory.weave', True),
2090
('revision-store', True),
2092
self.step('Upgrading repository ')
2093
self.bzrdir.transport.mkdir('repository', mode=self.dir_mode)
2094
self.make_lock('repository')
2095
# we hard code the formats here because we are converting into
2096
# the meta format. The meta format upgrader can take this to a
2097
# future format within each component.
2098
self.put_format('repository', RepositoryFormat7())
2099
for entry in repository_names:
2100
self.move_entry('repository', entry)
2102
self.step('Upgrading branch ')
2103
self.bzrdir.transport.mkdir('branch', mode=self.dir_mode)
2104
self.make_lock('branch')
2105
self.put_format('branch', BzrBranchFormat5())
2106
branch_files = [('revision-history', True),
2107
('branch-name', True),
2109
for entry in branch_files:
2110
self.move_entry('branch', entry)
2112
checkout_files = [('pending-merges', True),
2113
('inventory', True),
2114
('stat-cache', False)]
2115
# If a mandatory checkout file is not present, the branch does not have
2116
# a functional checkout. Do not create a checkout in the converted
2118
for name, mandatory in checkout_files:
2119
if mandatory and name not in bzrcontents:
2120
has_checkout = False
2124
if not has_checkout:
2125
self.pb.note('No working tree.')
2126
# If some checkout files are there, we may as well get rid of them.
2127
for name, mandatory in checkout_files:
2128
if name in bzrcontents:
2129
self.bzrdir.transport.delete(name)
2131
from bzrlib.workingtree import WorkingTreeFormat3
2132
self.step('Upgrading working tree')
2133
self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
2134
self.make_lock('checkout')
2136
'checkout', WorkingTreeFormat3())
2137
self.bzrdir.transport.delete_multi(
2138
self.garbage_inventories, self.pb)
2139
for entry in checkout_files:
2140
self.move_entry('checkout', entry)
2141
if last_revision is not None:
2142
self.bzrdir._control_files.put_utf8(
2143
'checkout/last-revision', last_revision)
2144
self.bzrdir._control_files.put_utf8(
2145
'branch-format', BzrDirMetaFormat1().get_format_string())
2146
return BzrDir.open(self.bzrdir.root_transport.base)
2148
def make_lock(self, name):
2149
"""Make a lock for the new control dir name."""
2150
self.step('Make %s lock' % name)
2151
ld = lockdir.LockDir(self.bzrdir.transport,
2153
file_modebits=self.file_mode,
2154
dir_modebits=self.dir_mode)
2157
def move_entry(self, new_dir, entry):
2158
"""Move then entry name into new_dir."""
2160
mandatory = entry[1]
2161
self.step('Moving %s' % name)
2163
self.bzrdir.transport.move(name, '%s/%s' % (new_dir, name))
2164
except errors.NoSuchFile:
2168
def put_format(self, dirname, format):
2169
self.bzrdir._control_files.put_utf8('%s/format' % dirname, format.get_format_string())
2172
class ConvertMetaToMeta(Converter):
2173
"""Converts the components of metadirs."""
2175
def __init__(self, target_format):
2176
"""Create a metadir to metadir converter.
2178
:param target_format: The final metadir format that is desired.
2180
self.target_format = target_format
2182
def convert(self, to_convert, pb):
2183
"""See Converter.convert()."""
2184
self.bzrdir = to_convert
2188
self.step('checking repository format')
2190
repo = self.bzrdir.open_repository()
2191
except errors.NoRepositoryPresent:
2194
if not isinstance(repo._format, self.target_format.repository_format.__class__):
2195
from bzrlib.repository import CopyConverter
2196
self.pb.note('starting repository conversion')
2197
converter = CopyConverter(self.target_format.repository_format)
2198
converter.convert(repo, pb)
2200
branch = self.bzrdir.open_branch()
2201
except errors.NotBranchError:
2204
# TODO: conversions of Branch and Tree should be done by
2205
# InterXFormat lookups
2206
# Avoid circular imports
2207
from bzrlib import branch as _mod_branch
2208
if (branch._format.__class__ is _mod_branch.BzrBranchFormat5 and
2209
self.target_format.get_branch_format().__class__ is
2210
_mod_branch.BzrBranchFormat6):
2211
branch_converter = _mod_branch.Converter5to6()
2212
branch_converter.convert(branch)
2214
tree = self.bzrdir.open_workingtree(recommend_upgrade=False)
2215
except (errors.NoWorkingTree, errors.NotLocalUrl):
2218
# TODO: conversions of Branch and Tree should be done by
2219
# InterXFormat lookups
2220
if (isinstance(tree, workingtree.WorkingTree3) and
2221
not isinstance(tree, workingtree_4.WorkingTree4) and
2222
isinstance(self.target_format.workingtree_format,
2223
workingtree_4.WorkingTreeFormat4)):
2224
workingtree_4.Converter3to4().convert(tree)
2228
# This is not in remote.py because it's small, and needs to be registered.
2229
# Putting it in remote.py creates a circular import problem.
2230
# we can make it a lazy object if the control formats is turned into something
2232
class RemoteBzrDirFormat(BzrDirMetaFormat1):
2233
"""Format representing bzrdirs accessed via a smart server"""
2235
def get_format_description(self):
2236
return 'bzr remote bzrdir'
2239
def probe_transport(klass, transport):
2240
"""Return a RemoteBzrDirFormat object if it looks possible."""
2242
client = transport.get_smart_client()
2243
except (NotImplementedError, AttributeError,
2244
errors.TransportNotPossible):
2245
# no smart server, so not a branch for this format type.
2246
raise errors.NotBranchError(path=transport.base)
2248
# Send a 'hello' request in protocol version one, and decline to
2249
# open it if the server doesn't support our required version (2) so
2250
# that the VFS-based transport will do it.
2251
request = client.get_request()
2252
smart_protocol = protocol.SmartClientRequestProtocolOne(request)
2253
server_version = smart_protocol.query_version()
2254
if server_version != 2:
2255
raise errors.NotBranchError(path=transport.base)
2258
def initialize_on_transport(self, transport):
2260
# hand off the request to the smart server
2261
medium = transport.get_smart_medium()
2262
except errors.NoSmartMedium:
2263
# TODO: lookup the local format from a server hint.
2264
local_dir_format = BzrDirMetaFormat1()
2265
return local_dir_format.initialize_on_transport(transport)
2266
client = _SmartClient(medium)
2267
path = client.remote_path_from_transport(transport)
2268
response = _SmartClient(medium).call('BzrDirFormat.initialize', path)
2269
assert response[0] in ('ok', ), 'unexpected response code %s' % (response,)
2270
return remote.RemoteBzrDir(transport)
2272
def _open(self, transport):
2273
return remote.RemoteBzrDir(transport)
2275
def __eq__(self, other):
2276
if not isinstance(other, RemoteBzrDirFormat):
2278
return self.get_format_description() == other.get_format_description()
2281
BzrDirFormat.register_control_server_format(RemoteBzrDirFormat)
2284
class BzrDirFormatInfo(object):
2286
def __init__(self, native, deprecated, hidden):
2287
self.deprecated = deprecated
2288
self.native = native
2289
self.hidden = hidden
2292
class BzrDirFormatRegistry(registry.Registry):
2293
"""Registry of user-selectable BzrDir subformats.
2295
Differs from BzrDirFormat._control_formats in that it provides sub-formats,
2296
e.g. BzrDirMeta1 with weave repository. Also, it's more user-oriented.
2299
def register_metadir(self, key,
2300
repository_format, help, native=True, deprecated=False,
2304
"""Register a metadir subformat.
2306
These all use a BzrDirMetaFormat1 bzrdir, but can be parameterized
2307
by the Repository format.
2309
:param repository_format: The fully-qualified repository format class
2311
:param branch_format: Fully-qualified branch format class name as
2313
:param tree_format: Fully-qualified tree format class name as
2316
# This should be expanded to support setting WorkingTree and Branch
2317
# formats, once BzrDirMetaFormat1 supports that.
2318
def _load(full_name):
2319
mod_name, factory_name = full_name.rsplit('.', 1)
2321
mod = __import__(mod_name, globals(), locals(),
2323
except ImportError, e:
2324
raise ImportError('failed to load %s: %s' % (full_name, e))
2326
factory = getattr(mod, factory_name)
2327
except AttributeError:
2328
raise AttributeError('no factory %s in module %r'
2333
bd = BzrDirMetaFormat1()
2334
if branch_format is not None:
2335
bd.set_branch_format(_load(branch_format))
2336
if tree_format is not None:
2337
bd.workingtree_format = _load(tree_format)
2338
if repository_format is not None:
2339
bd.repository_format = _load(repository_format)
2341
self.register(key, helper, help, native, deprecated, hidden)
2343
def register(self, key, factory, help, native=True, deprecated=False,
2345
"""Register a BzrDirFormat factory.
2347
The factory must be a callable that takes one parameter: the key.
2348
It must produce an instance of the BzrDirFormat when called.
2350
This function mainly exists to prevent the info object from being
2353
registry.Registry.register(self, key, factory, help,
2354
BzrDirFormatInfo(native, deprecated, hidden))
2356
def register_lazy(self, key, module_name, member_name, help, native=True,
2357
deprecated=False, hidden=False):
2358
registry.Registry.register_lazy(self, key, module_name, member_name,
2359
help, BzrDirFormatInfo(native, deprecated, hidden))
2361
def set_default(self, key):
2362
"""Set the 'default' key to be a clone of the supplied key.
2364
This method must be called once and only once.
2366
registry.Registry.register(self, 'default', self.get(key),
2367
self.get_help(key), info=self.get_info(key))
2369
def set_default_repository(self, key):
2370
"""Set the FormatRegistry default and Repository default.
2372
This is a transitional method while Repository.set_default_format
2375
if 'default' in self:
2376
self.remove('default')
2377
self.set_default(key)
2378
format = self.get('default')()
2379
assert isinstance(format, BzrDirMetaFormat1)
2381
def make_bzrdir(self, key):
2382
return self.get(key)()
2384
def help_topic(self, topic):
2385
output = textwrap.dedent("""\
2386
Bazaar directory formats
2387
------------------------
2389
These formats can be used for creating branches, working trees, and
2393
default_help = self.get_help('default')
2395
for key in self.keys():
2396
if key == 'default':
2398
help = self.get_help(key)
2399
if help == default_help:
2400
default_realkey = key
2402
help_pairs.append((key, help))
2404
def wrapped(key, help, info):
2406
help = '(native) ' + help
2407
return ' %s:\n%s\n\n' % (key,
2408
textwrap.fill(help, initial_indent=' ',
2409
subsequent_indent=' '))
2410
output += wrapped('%s/default' % default_realkey, default_help,
2411
self.get_info('default'))
2412
deprecated_pairs = []
2413
for key, help in help_pairs:
2414
info = self.get_info(key)
2417
elif info.deprecated:
2418
deprecated_pairs.append((key, help))
2420
output += wrapped(key, help, info)
2421
if len(deprecated_pairs) > 0:
2422
output += "Deprecated formats\n------------------\n\n"
2423
for key, help in deprecated_pairs:
2424
info = self.get_info(key)
2425
output += wrapped(key, help, info)
2430
format_registry = BzrDirFormatRegistry()
2431
format_registry.register('weave', BzrDirFormat6,
2432
'Pre-0.8 format. Slower than knit and does not'
2433
' support checkouts or shared repositories.',
2435
format_registry.register_metadir('knit',
2436
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2437
'Format using knits. Recommended for interoperation with bzr <= 0.14.',
2438
branch_format='bzrlib.branch.BzrBranchFormat5',
2439
tree_format='bzrlib.workingtree.WorkingTreeFormat3')
2440
format_registry.register_metadir('metaweave',
2441
'bzrlib.repofmt.weaverepo.RepositoryFormat7',
2442
'Transitional format in 0.8. Slower than knit.',
2443
branch_format='bzrlib.branch.BzrBranchFormat5',
2444
tree_format='bzrlib.workingtree.WorkingTreeFormat3',
2446
format_registry.register_metadir('dirstate',
2447
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2448
help='New in 0.15: Fast local operations. Compatible with bzr 0.8 and '
2449
'above when accessed over the network.',
2450
branch_format='bzrlib.branch.BzrBranchFormat5',
2451
# this uses bzrlib.workingtree.WorkingTreeFormat4 because importing
2452
# directly from workingtree_4 triggers a circular import.
2453
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2455
format_registry.register_metadir('dirstate-tags',
2456
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2457
help='New in 0.15: Fast local operations and improved scaling for '
2458
'network operations. Additionally adds support for tags.'
2459
' Incompatible with bzr < 0.15.',
2460
branch_format='bzrlib.branch.BzrBranchFormat6',
2461
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2463
format_registry.register_metadir('dirstate-with-subtree',
2464
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
2465
help='New in 0.15: Fast local operations and improved scaling for '
2466
'network operations. Additionally adds support for versioning nested '
2467
'bzr branches. Incompatible with bzr < 0.15.',
2468
branch_format='bzrlib.branch.BzrBranchFormat6',
2469
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2472
format_registry.set_default('dirstate')