1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
"""BzrDir logic. The BzrDir is the basic control directory used by bzr.
19
At format 7 this was split out into Branch, Repository and Checkout control
23
# TODO: remove unittest dependency; put that stuff inside the test suite
25
# TODO: Can we move specific formats into separate modules to make this file
28
from cStringIO import StringIO
32
from bzrlib.lazy_import import lazy_import
33
lazy_import(globals(), """
34
from copy import deepcopy
35
from stat import S_ISDIR
45
revision as _mod_revision,
54
from bzrlib.osutils import (
59
from bzrlib.smart.client import SmartClient
60
from bzrlib.store.revision.text import TextRevisionStore
61
from bzrlib.store.text import TextStore
62
from bzrlib.store.versioned import WeaveStore
63
from bzrlib.transactions import WriteTransaction
64
from bzrlib.transport import (
65
do_catching_redirections,
68
from bzrlib.weave import Weave
71
from bzrlib.trace import (
75
from bzrlib.transport.local import LocalTransport
79
"""A .bzr control diretory.
81
BzrDir instances let you create or open any of the things that can be
82
found within .bzr - checkouts, branches and repositories.
85
the transport which this bzr dir is rooted at (i.e. file:///.../.bzr/)
87
a transport connected to the directory this bzr was opened from.
91
"""Invoke break_lock on the first object in the bzrdir.
93
If there is a tree, the tree is opened and break_lock() called.
94
Otherwise, branch is tried, and finally repository.
96
# XXX: This seems more like a UI function than something that really
97
# belongs in this class.
99
thing_to_unlock = self.open_workingtree()
100
except (errors.NotLocalUrl, errors.NoWorkingTree):
102
thing_to_unlock = self.open_branch()
103
except errors.NotBranchError:
105
thing_to_unlock = self.open_repository()
106
except errors.NoRepositoryPresent:
108
thing_to_unlock.break_lock()
110
def can_convert_format(self):
111
"""Return true if this bzrdir is one whose format we can convert from."""
114
def check_conversion_target(self, target_format):
115
target_repo_format = target_format.repository_format
116
source_repo_format = self._format.repository_format
117
source_repo_format.check_conversion_target(target_repo_format)
120
def _check_supported(format, allow_unsupported,
121
recommend_upgrade=True,
123
"""Give an error or warning on old formats.
125
:param format: may be any kind of format - workingtree, branch,
128
:param allow_unsupported: If true, allow opening
129
formats that are strongly deprecated, and which may
130
have limited functionality.
132
:param recommend_upgrade: If true (default), warn
133
the user through the ui object that they may wish
134
to upgrade the object.
136
# TODO: perhaps move this into a base Format class; it's not BzrDir
137
# specific. mbp 20070323
138
if not allow_unsupported and not format.is_supported():
139
# see open_downlevel to open legacy branches.
140
raise errors.UnsupportedFormatError(format=format)
141
if recommend_upgrade \
142
and getattr(format, 'upgrade_recommended', False):
143
ui.ui_factory.recommend_upgrade(
144
format.get_format_description(),
147
def clone(self, url, revision_id=None, force_new_repo=False):
148
"""Clone this bzrdir and its contents to url verbatim.
150
If urls last component does not exist, it will be created.
152
if revision_id is not None, then the clone operation may tune
153
itself to download less data.
154
:param force_new_repo: Do not use a shared repository for the target
155
even if one is available.
158
result = self._format.initialize(url)
160
local_repo = self.find_repository()
161
except errors.NoRepositoryPresent:
164
# may need to copy content in
166
result_repo = local_repo.clone(
168
revision_id=revision_id)
169
result_repo.set_make_working_trees(local_repo.make_working_trees())
172
result_repo = result.find_repository()
173
# fetch content this dir needs.
174
result_repo.fetch(local_repo, revision_id=revision_id)
175
except errors.NoRepositoryPresent:
176
# needed to make one anyway.
177
result_repo = local_repo.clone(
179
revision_id=revision_id)
180
result_repo.set_make_working_trees(local_repo.make_working_trees())
181
# 1 if there is a branch present
182
# make sure its content is available in the target repository
185
self.open_branch().clone(result, revision_id=revision_id)
186
except errors.NotBranchError:
189
self.open_workingtree().clone(result)
190
except (errors.NoWorkingTree, errors.NotLocalUrl):
194
# TODO: This should be given a Transport, and should chdir up; otherwise
195
# this will open a new connection.
196
def _make_tail(self, url):
197
head, tail = urlutils.split(url)
198
if tail and tail != '.':
199
t = get_transport(head)
202
except errors.FileExists:
205
# TODO: Should take a Transport
207
def create(cls, base, format=None):
208
"""Create a new BzrDir at the url 'base'.
210
This will call the current default formats initialize with base
211
as the only parameter.
213
:param format: If supplied, the format of branch to create. If not
214
supplied, the default is used.
216
if cls is not BzrDir:
217
raise AssertionError("BzrDir.create always creates the default"
218
" format, not one of %r" % cls)
219
head, tail = urlutils.split(base)
220
if tail and tail != '.':
221
t = get_transport(head)
224
except errors.FileExists:
227
format = BzrDirFormat.get_default_format()
228
return format.initialize(safe_unicode(base))
230
def create_branch(self):
231
"""Create a branch in this BzrDir.
233
The bzrdirs format will control what branch format is created.
234
For more control see BranchFormatXX.create(a_bzrdir).
236
raise NotImplementedError(self.create_branch)
239
def create_branch_and_repo(base, force_new_repo=False, format=None):
240
"""Create a new BzrDir, Branch and Repository at the url 'base'.
242
This will use the current default BzrDirFormat, and use whatever
243
repository format that that uses via bzrdir.create_branch and
244
create_repository. If a shared repository is available that is used
247
The created Branch object is returned.
249
:param base: The URL to create the branch at.
250
:param force_new_repo: If True a new repository is always created.
252
bzrdir = BzrDir.create(base, format)
253
bzrdir._find_or_create_repository(force_new_repo)
254
return bzrdir.create_branch()
256
def _find_or_create_repository(self, force_new_repo):
257
"""Create a new repository if needed, returning the repository."""
259
return self.create_repository()
261
return self.find_repository()
262
except errors.NoRepositoryPresent:
263
return self.create_repository()
266
def create_branch_convenience(base, force_new_repo=False,
267
force_new_tree=None, format=None):
268
"""Create a new BzrDir, Branch and Repository at the url 'base'.
270
This is a convenience function - it will use an existing repository
271
if possible, can be told explicitly whether to create a working tree or
274
This will use the current default BzrDirFormat, and use whatever
275
repository format that that uses via bzrdir.create_branch and
276
create_repository. If a shared repository is available that is used
277
preferentially. Whatever repository is used, its tree creation policy
280
The created Branch object is returned.
281
If a working tree cannot be made due to base not being a file:// url,
282
no error is raised unless force_new_tree is True, in which case no
283
data is created on disk and NotLocalUrl is raised.
285
:param base: The URL to create the branch at.
286
:param force_new_repo: If True a new repository is always created.
287
:param force_new_tree: If True or False force creation of a tree or
288
prevent such creation respectively.
289
:param format: Override for the for the bzrdir format to create
292
# check for non local urls
293
t = get_transport(safe_unicode(base))
294
if not isinstance(t, LocalTransport):
295
raise errors.NotLocalUrl(base)
296
bzrdir = BzrDir.create(base, format)
297
repo = bzrdir._find_or_create_repository(force_new_repo)
298
result = bzrdir.create_branch()
299
if force_new_tree or (repo.make_working_trees() and
300
force_new_tree is None):
302
bzrdir.create_workingtree()
303
except errors.NotLocalUrl:
308
def create_repository(base, shared=False, format=None):
309
"""Create a new BzrDir and Repository at the url 'base'.
311
If no format is supplied, this will default to the current default
312
BzrDirFormat by default, and use whatever repository format that that
313
uses for bzrdirformat.create_repository.
315
:param shared: Create a shared repository rather than a standalone
317
The Repository object is returned.
319
This must be overridden as an instance method in child classes, where
320
it should take no parameters and construct whatever repository format
321
that child class desires.
323
bzrdir = BzrDir.create(base, format)
324
return bzrdir.create_repository(shared)
327
def create_standalone_workingtree(base, format=None):
328
"""Create a new BzrDir, WorkingTree, Branch and Repository at 'base'.
330
'base' must be a local path or a file:// url.
332
This will use the current default BzrDirFormat, and use whatever
333
repository format that that uses for bzrdirformat.create_workingtree,
334
create_branch and create_repository.
336
:return: The WorkingTree object.
338
t = get_transport(safe_unicode(base))
339
if not isinstance(t, LocalTransport):
340
raise errors.NotLocalUrl(base)
341
bzrdir = BzrDir.create_branch_and_repo(safe_unicode(base),
343
format=format).bzrdir
344
return bzrdir.create_workingtree()
346
def create_workingtree(self, revision_id=None):
347
"""Create a working tree at this BzrDir.
349
revision_id: create it as of this revision id.
351
raise NotImplementedError(self.create_workingtree)
353
def retire_bzrdir(self):
354
"""Permanently disable the bzrdir.
356
This is done by renaming it to give the user some ability to recover
357
if there was a problem.
359
This will have horrible consequences if anyone has anything locked or
362
for i in xrange(10000):
364
to_path = '.bzr.retired.%d' % i
365
self.root_transport.rename('.bzr', to_path)
366
note("renamed %s to %s"
367
% (self.root_transport.abspath('.bzr'), to_path))
369
except (errors.TransportError, IOError, errors.PathError):
372
def destroy_workingtree(self):
373
"""Destroy the working tree at this BzrDir.
375
Formats that do not support this may raise UnsupportedOperation.
377
raise NotImplementedError(self.destroy_workingtree)
379
def destroy_workingtree_metadata(self):
380
"""Destroy the control files for the working tree at this BzrDir.
382
The contents of working tree files are not affected.
383
Formats that do not support this may raise UnsupportedOperation.
385
raise NotImplementedError(self.destroy_workingtree_metadata)
387
def find_repository(self):
388
"""Find the repository that should be used for a_bzrdir.
390
This does not require a branch as we use it to find the repo for
391
new branches as well as to hook existing branches up to their
395
return self.open_repository()
396
except errors.NoRepositoryPresent:
398
next_transport = self.root_transport.clone('..')
400
# find the next containing bzrdir
402
found_bzrdir = BzrDir.open_containing_from_transport(
404
except errors.NotBranchError:
406
raise errors.NoRepositoryPresent(self)
407
# does it have a repository ?
409
repository = found_bzrdir.open_repository()
410
except errors.NoRepositoryPresent:
411
next_transport = found_bzrdir.root_transport.clone('..')
412
if (found_bzrdir.root_transport.base == next_transport.base):
413
# top of the file system
417
if ((found_bzrdir.root_transport.base ==
418
self.root_transport.base) or repository.is_shared()):
421
raise errors.NoRepositoryPresent(self)
422
raise errors.NoRepositoryPresent(self)
424
def get_branch_reference(self):
425
"""Return the referenced URL for the branch in this bzrdir.
427
:raises NotBranchError: If there is no Branch.
428
:return: The URL the branch in this bzrdir references if it is a
429
reference branch, or None for regular branches.
433
def get_branch_transport(self, branch_format):
434
"""Get the transport for use by branch format in this BzrDir.
436
Note that bzr dirs that do not support format strings will raise
437
IncompatibleFormat if the branch format they are given has
438
a format string, and vice versa.
440
If branch_format is None, the transport is returned with no
441
checking. if it is not None, then the returned transport is
442
guaranteed to point to an existing directory ready for use.
444
raise NotImplementedError(self.get_branch_transport)
446
def get_repository_transport(self, repository_format):
447
"""Get the transport for use by repository format in this BzrDir.
449
Note that bzr dirs that do not support format strings will raise
450
IncompatibleFormat if the repository format they are given has
451
a format string, and vice versa.
453
If repository_format is None, the transport is returned with no
454
checking. if it is not None, then the returned transport is
455
guaranteed to point to an existing directory ready for use.
457
raise NotImplementedError(self.get_repository_transport)
459
def get_workingtree_transport(self, tree_format):
460
"""Get the transport for use by workingtree format in this BzrDir.
462
Note that bzr dirs that do not support format strings will raise
463
IncompatibleFormat if the workingtree format they are given has a
464
format string, and vice versa.
466
If workingtree_format is None, the transport is returned with no
467
checking. if it is not None, then the returned transport is
468
guaranteed to point to an existing directory ready for use.
470
raise NotImplementedError(self.get_workingtree_transport)
472
def __init__(self, _transport, _format):
473
"""Initialize a Bzr control dir object.
475
Only really common logic should reside here, concrete classes should be
476
made with varying behaviours.
478
:param _format: the format that is creating this BzrDir instance.
479
:param _transport: the transport this dir is based at.
481
self._format = _format
482
self.transport = _transport.clone('.bzr')
483
self.root_transport = _transport
485
def is_control_filename(self, filename):
486
"""True if filename is the name of a path which is reserved for bzrdir's.
488
:param filename: A filename within the root transport of this bzrdir.
490
This is true IF and ONLY IF the filename is part of the namespace reserved
491
for bzr control dirs. Currently this is the '.bzr' directory in the root
492
of the root_transport. it is expected that plugins will need to extend
493
this in the future - for instance to make bzr talk with svn working
496
# this might be better on the BzrDirFormat class because it refers to
497
# all the possible bzrdir disk formats.
498
# This method is tested via the workingtree is_control_filename tests-
499
# it was extracted from WorkingTree.is_control_filename. If the methods
500
# contract is extended beyond the current trivial implementation please
501
# add new tests for it to the appropriate place.
502
return filename == '.bzr' or filename.startswith('.bzr/')
504
def needs_format_conversion(self, format=None):
505
"""Return true if this bzrdir needs convert_format run on it.
507
For instance, if the repository format is out of date but the
508
branch and working tree are not, this should return True.
510
:param format: Optional parameter indicating a specific desired
511
format we plan to arrive at.
513
raise NotImplementedError(self.needs_format_conversion)
516
def open_unsupported(base):
517
"""Open a branch which is not supported."""
518
return BzrDir.open(base, _unsupported=True)
521
def open(base, _unsupported=False):
522
"""Open an existing bzrdir, rooted at 'base' (url)
524
_unsupported is a private parameter to the BzrDir class.
526
t = get_transport(base)
527
return BzrDir.open_from_transport(t, _unsupported=_unsupported)
530
def open_from_transport(transport, _unsupported=False):
531
"""Open a bzrdir within a particular directory.
533
:param transport: Transport containing the bzrdir.
534
:param _unsupported: private.
536
base = transport.base
538
def find_format(transport):
539
return transport, BzrDirFormat.find_format(transport)
541
def redirected(transport, e, redirection_notice):
542
qualified_source = e.get_source_url()
543
relpath = transport.relpath(qualified_source)
544
if not e.target.endswith(relpath):
545
# Not redirected to a branch-format, not a branch
546
raise errors.NotBranchError(path=e.target)
547
target = e.target[:-len(relpath)]
548
note('%s is%s redirected to %s',
549
transport.base, e.permanently, target)
550
# Let's try with a new transport
551
qualified_target = e.get_target_url()[:-len(relpath)]
552
# FIXME: If 'transport' has a qualifier, this should
553
# be applied again to the new transport *iff* the
554
# schemes used are the same. It's a bit tricky to
555
# verify, so I'll punt for now
557
return get_transport(target)
560
transport, format = do_catching_redirections(find_format,
563
except errors.TooManyRedirections:
564
raise errors.NotBranchError(base)
566
BzrDir._check_supported(format, _unsupported)
567
return format.open(transport, _found=True)
569
def open_branch(self, unsupported=False):
570
"""Open the branch object at this BzrDir if one is present.
572
If unsupported is True, then no longer supported branch formats can
575
TODO: static convenience version of this?
577
raise NotImplementedError(self.open_branch)
580
def open_containing(url):
581
"""Open an existing branch which contains url.
583
:param url: url to search from.
584
See open_containing_from_transport for more detail.
586
return BzrDir.open_containing_from_transport(get_transport(url))
589
def open_containing_from_transport(a_transport):
590
"""Open an existing branch which contains a_transport.base
592
This probes for a branch at a_transport, and searches upwards from there.
594
Basically we keep looking up until we find the control directory or
595
run into the root. If there isn't one, raises NotBranchError.
596
If there is one and it is either an unrecognised format or an unsupported
597
format, UnknownFormatError or UnsupportedFormatError are raised.
598
If there is one, it is returned, along with the unused portion of url.
600
:return: The BzrDir that contains the path, and a Unicode path
601
for the rest of the URL.
603
# this gets the normalised url back. I.e. '.' -> the full path.
604
url = a_transport.base
607
result = BzrDir.open_from_transport(a_transport)
608
return result, urlutils.unescape(a_transport.relpath(url))
609
except errors.NotBranchError, e:
612
new_t = a_transport.clone('..')
613
except errors.InvalidURLJoin:
614
# reached the root, whatever that may be
615
raise errors.NotBranchError(path=url)
616
if new_t.base == a_transport.base:
617
# reached the root, whatever that may be
618
raise errors.NotBranchError(path=url)
622
def open_containing_tree_or_branch(klass, location):
623
"""Return the branch and working tree contained by a location.
625
Returns (tree, branch, relpath).
626
If there is no tree at containing the location, tree will be None.
627
If there is no branch containing the location, an exception will be
629
relpath is the portion of the path that is contained by the branch.
631
bzrdir, relpath = klass.open_containing(location)
633
tree = bzrdir.open_workingtree()
634
except (errors.NoWorkingTree, errors.NotLocalUrl):
636
branch = bzrdir.open_branch()
639
return tree, branch, relpath
641
def open_repository(self, _unsupported=False):
642
"""Open the repository object at this BzrDir if one is present.
644
This will not follow the Branch object pointer - its strictly a direct
645
open facility. Most client code should use open_branch().repository to
648
_unsupported is a private parameter, not part of the api.
649
TODO: static convenience version of this?
651
raise NotImplementedError(self.open_repository)
653
def open_workingtree(self, _unsupported=False,
654
recommend_upgrade=True):
655
"""Open the workingtree object at this BzrDir if one is present.
657
TODO: static convenience version of this?
659
raise NotImplementedError(self.open_workingtree)
661
def has_branch(self):
662
"""Tell if this bzrdir contains a branch.
664
Note: if you're going to open the branch, you should just go ahead
665
and try, and not ask permission first. (This method just opens the
666
branch and discards it, and that's somewhat expensive.)
671
except errors.NotBranchError:
674
def has_workingtree(self):
675
"""Tell if this bzrdir contains a working tree.
677
This will still raise an exception if the bzrdir has a workingtree that
678
is remote & inaccessible.
680
Note: if you're going to open the working tree, you should just go ahead
681
and try, and not ask permission first. (This method just opens the
682
workingtree and discards it, and that's somewhat expensive.)
685
self.open_workingtree(recommend_upgrade=False)
687
except errors.NoWorkingTree:
690
def _cloning_metadir(self):
691
"""Produce a metadir suitable for cloning with"""
692
result_format = self._format.__class__()
695
branch = self.open_branch()
696
source_repository = branch.repository
697
except errors.NotBranchError:
699
source_repository = self.open_repository()
700
except errors.NoRepositoryPresent:
701
source_repository = None
703
# XXX TODO: This isinstance is here because we have not implemented
704
# the fix recommended in bug # 103195 - to delegate this choice the
706
repo_format = source_repository._format
707
if not isinstance(repo_format, remote.RemoteRepositoryFormat):
708
result_format.repository_format = repo_format
710
# TODO: Couldn't we just probe for the format in these cases,
711
# rather than opening the whole tree? It would be a little
712
# faster. mbp 20070401
713
tree = self.open_workingtree(recommend_upgrade=False)
714
except (errors.NoWorkingTree, errors.NotLocalUrl):
715
result_format.workingtree_format = None
717
result_format.workingtree_format = tree._format.__class__()
718
return result_format, source_repository
720
def cloning_metadir(self):
721
"""Produce a metadir suitable for cloning or sprouting with.
723
These operations may produce workingtrees (yes, even though they're
724
"cloning" something that doesn't have a tree, so a viable workingtree
725
format must be selected.
727
format, repository = self._cloning_metadir()
728
if format._workingtree_format is None:
729
if repository is None:
731
tree_format = repository._format._matchingbzrdir.workingtree_format
732
format.workingtree_format = tree_format.__class__()
735
def checkout_metadir(self):
736
return self.cloning_metadir()
738
def sprout(self, url, revision_id=None, force_new_repo=False,
740
"""Create a copy of this bzrdir prepared for use as a new line of
743
If urls last component does not exist, it will be created.
745
Attributes related to the identity of the source branch like
746
branch nickname will be cleaned, a working tree is created
747
whether one existed before or not; and a local branch is always
750
if revision_id is not None, then the clone operation may tune
751
itself to download less data.
754
cloning_format = self.cloning_metadir()
755
result = cloning_format.initialize(url)
757
source_branch = self.open_branch()
758
source_repository = source_branch.repository
759
except errors.NotBranchError:
762
source_repository = self.open_repository()
763
except errors.NoRepositoryPresent:
764
source_repository = None
769
result_repo = result.find_repository()
770
except errors.NoRepositoryPresent:
772
if source_repository is None and result_repo is not None:
774
elif source_repository is None and result_repo is None:
775
# no repo available, make a new one
776
result.create_repository()
777
elif source_repository is not None and result_repo is None:
778
# have source, and want to make a new target repo
779
# we don't clone the repo because that preserves attributes
780
# like is_shared(), and we have not yet implemented a
781
# repository sprout().
782
result_repo = result.create_repository()
783
if result_repo is not None:
784
# fetch needed content into target.
785
if source_repository is not None:
786
result_repo.fetch(source_repository, revision_id=revision_id)
787
if source_branch is not None:
788
source_branch.sprout(result, revision_id=revision_id)
790
result.create_branch()
791
# TODO: jam 20060426 we probably need a test in here in the
792
# case that the newly sprouted branch is a remote one
793
if result_repo is None or result_repo.make_working_trees():
794
wt = result.create_workingtree()
797
if wt.path2id('') is None:
799
wt.set_root_id(self.open_workingtree.get_root_id())
800
except errors.NoWorkingTree:
806
if recurse == 'down':
808
basis = wt.basis_tree()
810
subtrees = basis.iter_references()
811
recurse_branch = wt.branch
812
elif source_branch is not None:
813
basis = source_branch.basis_tree()
815
subtrees = basis.iter_references()
816
recurse_branch = source_branch
821
for path, file_id in subtrees:
822
target = urlutils.join(url, urlutils.escape(path))
823
sublocation = source_branch.reference_parent(file_id, path)
824
sublocation.bzrdir.sprout(target,
825
basis.get_reference_revision(file_id, path),
826
force_new_repo=force_new_repo, recurse=recurse)
828
if basis is not None:
833
class BzrDirPreSplitOut(BzrDir):
834
"""A common class for the all-in-one formats."""
836
def __init__(self, _transport, _format):
837
"""See BzrDir.__init__."""
838
super(BzrDirPreSplitOut, self).__init__(_transport, _format)
839
assert self._format._lock_class == lockable_files.TransportLock
840
assert self._format._lock_file_name == 'branch-lock'
841
self._control_files = lockable_files.LockableFiles(
842
self.get_branch_transport(None),
843
self._format._lock_file_name,
844
self._format._lock_class)
846
def break_lock(self):
847
"""Pre-splitout bzrdirs do not suffer from stale locks."""
848
raise NotImplementedError(self.break_lock)
850
def clone(self, url, revision_id=None, force_new_repo=False):
851
"""See BzrDir.clone()."""
852
from bzrlib.workingtree import WorkingTreeFormat2
854
result = self._format._initialize_for_clone(url)
855
self.open_repository().clone(result, revision_id=revision_id)
856
from_branch = self.open_branch()
857
from_branch.clone(result, revision_id=revision_id)
859
self.open_workingtree().clone(result)
860
except errors.NotLocalUrl:
861
# make a new one, this format always has to have one.
863
WorkingTreeFormat2().initialize(result)
864
except errors.NotLocalUrl:
865
# but we cannot do it for remote trees.
866
to_branch = result.open_branch()
867
WorkingTreeFormat2().stub_initialize_remote(to_branch.control_files)
870
def create_branch(self):
871
"""See BzrDir.create_branch."""
872
return self.open_branch()
874
def create_repository(self, shared=False):
875
"""See BzrDir.create_repository."""
877
raise errors.IncompatibleFormat('shared repository', self._format)
878
return self.open_repository()
880
def create_workingtree(self, revision_id=None):
881
"""See BzrDir.create_workingtree."""
882
# this looks buggy but is not -really-
883
# because this format creates the workingtree when the bzrdir is
885
# clone and sprout will have set the revision_id
886
# and that will have set it for us, its only
887
# specific uses of create_workingtree in isolation
888
# that can do wonky stuff here, and that only
889
# happens for creating checkouts, which cannot be
890
# done on this format anyway. So - acceptable wart.
891
result = self.open_workingtree(recommend_upgrade=False)
892
if revision_id is not None:
893
if revision_id == _mod_revision.NULL_REVISION:
894
result.set_parent_ids([])
896
result.set_parent_ids([revision_id])
899
def destroy_workingtree(self):
900
"""See BzrDir.destroy_workingtree."""
901
raise errors.UnsupportedOperation(self.destroy_workingtree, self)
903
def destroy_workingtree_metadata(self):
904
"""See BzrDir.destroy_workingtree_metadata."""
905
raise errors.UnsupportedOperation(self.destroy_workingtree_metadata,
908
def get_branch_transport(self, branch_format):
909
"""See BzrDir.get_branch_transport()."""
910
if branch_format is None:
911
return self.transport
913
branch_format.get_format_string()
914
except NotImplementedError:
915
return self.transport
916
raise errors.IncompatibleFormat(branch_format, self._format)
918
def get_repository_transport(self, repository_format):
919
"""See BzrDir.get_repository_transport()."""
920
if repository_format is None:
921
return self.transport
923
repository_format.get_format_string()
924
except NotImplementedError:
925
return self.transport
926
raise errors.IncompatibleFormat(repository_format, self._format)
928
def get_workingtree_transport(self, workingtree_format):
929
"""See BzrDir.get_workingtree_transport()."""
930
if workingtree_format is None:
931
return self.transport
933
workingtree_format.get_format_string()
934
except NotImplementedError:
935
return self.transport
936
raise errors.IncompatibleFormat(workingtree_format, self._format)
938
def needs_format_conversion(self, format=None):
939
"""See BzrDir.needs_format_conversion()."""
940
# if the format is not the same as the system default,
941
# an upgrade is needed.
943
format = BzrDirFormat.get_default_format()
944
return not isinstance(self._format, format.__class__)
946
def open_branch(self, unsupported=False):
947
"""See BzrDir.open_branch."""
948
from bzrlib.branch import BzrBranchFormat4
949
format = BzrBranchFormat4()
950
self._check_supported(format, unsupported)
951
return format.open(self, _found=True)
953
def sprout(self, url, revision_id=None, force_new_repo=False):
954
"""See BzrDir.sprout()."""
955
from bzrlib.workingtree import WorkingTreeFormat2
957
result = self._format._initialize_for_clone(url)
959
self.open_repository().clone(result, revision_id=revision_id)
960
except errors.NoRepositoryPresent:
963
self.open_branch().sprout(result, revision_id=revision_id)
964
except errors.NotBranchError:
966
# we always want a working tree
967
WorkingTreeFormat2().initialize(result)
971
class BzrDir4(BzrDirPreSplitOut):
972
"""A .bzr version 4 control object.
974
This is a deprecated format and may be removed after sept 2006.
977
def create_repository(self, shared=False):
978
"""See BzrDir.create_repository."""
979
return self._format.repository_format.initialize(self, shared)
981
def needs_format_conversion(self, format=None):
982
"""Format 4 dirs are always in need of conversion."""
985
def open_repository(self):
986
"""See BzrDir.open_repository."""
987
from bzrlib.repofmt.weaverepo import RepositoryFormat4
988
return RepositoryFormat4().open(self, _found=True)
991
class BzrDir5(BzrDirPreSplitOut):
992
"""A .bzr version 5 control object.
994
This is a deprecated format and may be removed after sept 2006.
997
def open_repository(self):
998
"""See BzrDir.open_repository."""
999
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1000
return RepositoryFormat5().open(self, _found=True)
1002
def open_workingtree(self, _unsupported=False,
1003
recommend_upgrade=True):
1004
"""See BzrDir.create_workingtree."""
1005
from bzrlib.workingtree import WorkingTreeFormat2
1006
wt_format = WorkingTreeFormat2()
1007
# we don't warn here about upgrades; that ought to be handled for the
1009
return wt_format.open(self, _found=True)
1012
class BzrDir6(BzrDirPreSplitOut):
1013
"""A .bzr version 6 control object.
1015
This is a deprecated format and may be removed after sept 2006.
1018
def open_repository(self):
1019
"""See BzrDir.open_repository."""
1020
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1021
return RepositoryFormat6().open(self, _found=True)
1023
def open_workingtree(self, _unsupported=False,
1024
recommend_upgrade=True):
1025
"""See BzrDir.create_workingtree."""
1026
# we don't warn here about upgrades; that ought to be handled for the
1028
from bzrlib.workingtree import WorkingTreeFormat2
1029
return WorkingTreeFormat2().open(self, _found=True)
1032
class BzrDirMeta1(BzrDir):
1033
"""A .bzr meta version 1 control object.
1035
This is the first control object where the
1036
individual aspects are really split out: there are separate repository,
1037
workingtree and branch subdirectories and any subset of the three can be
1038
present within a BzrDir.
1041
def can_convert_format(self):
1042
"""See BzrDir.can_convert_format()."""
1045
def create_branch(self):
1046
"""See BzrDir.create_branch."""
1047
return self._format.get_branch_format().initialize(self)
1049
def create_repository(self, shared=False):
1050
"""See BzrDir.create_repository."""
1051
return self._format.repository_format.initialize(self, shared)
1053
def create_workingtree(self, revision_id=None):
1054
"""See BzrDir.create_workingtree."""
1055
from bzrlib.workingtree import WorkingTreeFormat
1056
return self._format.workingtree_format.initialize(self, revision_id)
1058
def destroy_workingtree(self):
1059
"""See BzrDir.destroy_workingtree."""
1060
wt = self.open_workingtree(recommend_upgrade=False)
1061
repository = wt.branch.repository
1062
empty = repository.revision_tree(_mod_revision.NULL_REVISION)
1063
wt.revert([], old_tree=empty)
1064
self.destroy_workingtree_metadata()
1066
def destroy_workingtree_metadata(self):
1067
self.transport.delete_tree('checkout')
1069
def find_branch_format(self):
1070
"""Find the branch 'format' for this bzrdir.
1072
This might be a synthetic object for e.g. RemoteBranch and SVN.
1074
from bzrlib.branch import BranchFormat
1075
return BranchFormat.find_format(self)
1077
def _get_mkdir_mode(self):
1078
"""Figure out the mode to use when creating a bzrdir subdir."""
1079
temp_control = lockable_files.LockableFiles(self.transport, '',
1080
lockable_files.TransportLock)
1081
return temp_control._dir_mode
1083
def get_branch_reference(self):
1084
"""See BzrDir.get_branch_reference()."""
1085
from bzrlib.branch import BranchFormat
1086
format = BranchFormat.find_format(self)
1087
return format.get_reference(self)
1089
def get_branch_transport(self, branch_format):
1090
"""See BzrDir.get_branch_transport()."""
1091
if branch_format is None:
1092
return self.transport.clone('branch')
1094
branch_format.get_format_string()
1095
except NotImplementedError:
1096
raise errors.IncompatibleFormat(branch_format, self._format)
1098
self.transport.mkdir('branch', mode=self._get_mkdir_mode())
1099
except errors.FileExists:
1101
return self.transport.clone('branch')
1103
def get_repository_transport(self, repository_format):
1104
"""See BzrDir.get_repository_transport()."""
1105
if repository_format is None:
1106
return self.transport.clone('repository')
1108
repository_format.get_format_string()
1109
except NotImplementedError:
1110
raise errors.IncompatibleFormat(repository_format, self._format)
1112
self.transport.mkdir('repository', mode=self._get_mkdir_mode())
1113
except errors.FileExists:
1115
return self.transport.clone('repository')
1117
def get_workingtree_transport(self, workingtree_format):
1118
"""See BzrDir.get_workingtree_transport()."""
1119
if workingtree_format is None:
1120
return self.transport.clone('checkout')
1122
workingtree_format.get_format_string()
1123
except NotImplementedError:
1124
raise errors.IncompatibleFormat(workingtree_format, self._format)
1126
self.transport.mkdir('checkout', mode=self._get_mkdir_mode())
1127
except errors.FileExists:
1129
return self.transport.clone('checkout')
1131
def needs_format_conversion(self, format=None):
1132
"""See BzrDir.needs_format_conversion()."""
1134
format = BzrDirFormat.get_default_format()
1135
if not isinstance(self._format, format.__class__):
1136
# it is not a meta dir format, conversion is needed.
1138
# we might want to push this down to the repository?
1140
if not isinstance(self.open_repository()._format,
1141
format.repository_format.__class__):
1142
# the repository needs an upgrade.
1144
except errors.NoRepositoryPresent:
1147
if not isinstance(self.open_branch()._format,
1148
format.get_branch_format().__class__):
1149
# the branch needs an upgrade.
1151
except errors.NotBranchError:
1154
my_wt = self.open_workingtree(recommend_upgrade=False)
1155
if not isinstance(my_wt._format,
1156
format.workingtree_format.__class__):
1157
# the workingtree needs an upgrade.
1159
except (errors.NoWorkingTree, errors.NotLocalUrl):
1163
def open_branch(self, unsupported=False):
1164
"""See BzrDir.open_branch."""
1165
format = self.find_branch_format()
1166
self._check_supported(format, unsupported)
1167
return format.open(self, _found=True)
1169
def open_repository(self, unsupported=False):
1170
"""See BzrDir.open_repository."""
1171
from bzrlib.repository import RepositoryFormat
1172
format = RepositoryFormat.find_format(self)
1173
self._check_supported(format, unsupported)
1174
return format.open(self, _found=True)
1176
def open_workingtree(self, unsupported=False,
1177
recommend_upgrade=True):
1178
"""See BzrDir.open_workingtree."""
1179
from bzrlib.workingtree import WorkingTreeFormat
1180
format = WorkingTreeFormat.find_format(self)
1181
self._check_supported(format, unsupported,
1183
basedir=self.root_transport.base)
1184
return format.open(self, _found=True)
1187
class BzrDirFormat(object):
1188
"""An encapsulation of the initialization and open routines for a format.
1190
Formats provide three things:
1191
* An initialization routine,
1195
Formats are placed in an dict by their format string for reference
1196
during bzrdir opening. These should be subclasses of BzrDirFormat
1199
Once a format is deprecated, just deprecate the initialize and open
1200
methods on the format class. Do not deprecate the object, as the
1201
object will be created every system load.
1204
_default_format = None
1205
"""The default format used for new .bzr dirs."""
1208
"""The known formats."""
1210
_control_formats = []
1211
"""The registered control formats - .bzr, ....
1213
This is a list of BzrDirFormat objects.
1216
_lock_file_name = 'branch-lock'
1218
# _lock_class must be set in subclasses to the lock type, typ.
1219
# TransportLock or LockDir
1222
def find_format(klass, transport):
1223
"""Return the format present at transport."""
1224
for format in klass._control_formats:
1226
return format.probe_transport(transport)
1227
except errors.NotBranchError:
1228
# this format does not find a control dir here.
1230
raise errors.NotBranchError(path=transport.base)
1233
def probe_transport(klass, transport):
1234
"""Return the .bzrdir style format present in a directory."""
1236
format_string = transport.get(".bzr/branch-format").read()
1237
except errors.NoSuchFile:
1238
raise errors.NotBranchError(path=transport.base)
1241
return klass._formats[format_string]
1243
raise errors.UnknownFormatError(format=format_string)
1246
def get_default_format(klass):
1247
"""Return the current default format."""
1248
return klass._default_format
1250
def get_format_string(self):
1251
"""Return the ASCII format string that identifies this format."""
1252
raise NotImplementedError(self.get_format_string)
1254
def get_format_description(self):
1255
"""Return the short description for this format."""
1256
raise NotImplementedError(self.get_format_description)
1258
def get_converter(self, format=None):
1259
"""Return the converter to use to convert bzrdirs needing converts.
1261
This returns a bzrlib.bzrdir.Converter object.
1263
This should return the best upgrader to step this format towards the
1264
current default format. In the case of plugins we can/should provide
1265
some means for them to extend the range of returnable converters.
1267
:param format: Optional format to override the default format of the
1270
raise NotImplementedError(self.get_converter)
1272
def initialize(self, url):
1273
"""Create a bzr control dir at this url and return an opened copy.
1275
Subclasses should typically override initialize_on_transport
1276
instead of this method.
1278
return self.initialize_on_transport(get_transport(url))
1280
def initialize_on_transport(self, transport):
1281
"""Initialize a new bzrdir in the base directory of a Transport."""
1282
# Since we don't have a .bzr directory, inherit the
1283
# mode from the root directory
1284
temp_control = lockable_files.LockableFiles(transport,
1285
'', lockable_files.TransportLock)
1286
temp_control._transport.mkdir('.bzr',
1287
# FIXME: RBC 20060121 don't peek under
1289
mode=temp_control._dir_mode)
1290
file_mode = temp_control._file_mode
1292
mutter('created control directory in ' + transport.base)
1293
control = transport.clone('.bzr')
1294
utf8_files = [('README',
1295
"This is a Bazaar-NG control directory.\n"
1296
"Do not change any files in this directory.\n"),
1297
('branch-format', self.get_format_string()),
1299
# NB: no need to escape relative paths that are url safe.
1300
control_files = lockable_files.LockableFiles(control,
1301
self._lock_file_name, self._lock_class)
1302
control_files.create_lock()
1303
control_files.lock_write()
1305
for file, content in utf8_files:
1306
control_files.put_utf8(file, content)
1308
control_files.unlock()
1309
return self.open(transport, _found=True)
1311
def is_supported(self):
1312
"""Is this format supported?
1314
Supported formats must be initializable and openable.
1315
Unsupported formats may not support initialization or committing or
1316
some other features depending on the reason for not being supported.
1320
def same_model(self, target_format):
1321
return (self.repository_format.rich_root_data ==
1322
target_format.rich_root_data)
1325
def known_formats(klass):
1326
"""Return all the known formats.
1328
Concrete formats should override _known_formats.
1330
# There is double indirection here to make sure that control
1331
# formats used by more than one dir format will only be probed
1332
# once. This can otherwise be quite expensive for remote connections.
1334
for format in klass._control_formats:
1335
result.update(format._known_formats())
1339
def _known_formats(klass):
1340
"""Return the known format instances for this control format."""
1341
return set(klass._formats.values())
1343
def open(self, transport, _found=False):
1344
"""Return an instance of this format for the dir transport points at.
1346
_found is a private parameter, do not use it.
1349
found_format = BzrDirFormat.find_format(transport)
1350
if not isinstance(found_format, self.__class__):
1351
raise AssertionError("%s was asked to open %s, but it seems to need "
1353
% (self, transport, found_format))
1354
return self._open(transport)
1356
def _open(self, transport):
1357
"""Template method helper for opening BzrDirectories.
1359
This performs the actual open and any additional logic or parameter
1362
raise NotImplementedError(self._open)
1365
def register_format(klass, format):
1366
klass._formats[format.get_format_string()] = format
1369
def register_control_format(klass, format):
1370
"""Register a format that does not use '.bzr' for its control dir.
1372
TODO: This should be pulled up into a 'ControlDirFormat' base class
1373
which BzrDirFormat can inherit from, and renamed to register_format
1374
there. It has been done without that for now for simplicity of
1377
klass._control_formats.append(format)
1380
@symbol_versioning.deprecated_method(symbol_versioning.zero_fourteen)
1381
def set_default_format(klass, format):
1382
klass._set_default_format(format)
1385
def _set_default_format(klass, format):
1386
"""Set default format (for testing behavior of defaults only)"""
1387
klass._default_format = format
1390
return self.get_format_string()[:-1]
1393
def unregister_format(klass, format):
1394
assert klass._formats[format.get_format_string()] is format
1395
del klass._formats[format.get_format_string()]
1398
def unregister_control_format(klass, format):
1399
klass._control_formats.remove(format)
1402
class BzrDirFormat4(BzrDirFormat):
1403
"""Bzr dir format 4.
1405
This format is a combined format for working tree, branch and repository.
1407
- Format 1 working trees [always]
1408
- Format 4 branches [always]
1409
- Format 4 repositories [always]
1411
This format is deprecated: it indexes texts using a text it which is
1412
removed in format 5; write support for this format has been removed.
1415
_lock_class = lockable_files.TransportLock
1417
def get_format_string(self):
1418
"""See BzrDirFormat.get_format_string()."""
1419
return "Bazaar-NG branch, format 0.0.4\n"
1421
def get_format_description(self):
1422
"""See BzrDirFormat.get_format_description()."""
1423
return "All-in-one format 4"
1425
def get_converter(self, format=None):
1426
"""See BzrDirFormat.get_converter()."""
1427
# there is one and only one upgrade path here.
1428
return ConvertBzrDir4To5()
1430
def initialize_on_transport(self, transport):
1431
"""Format 4 branches cannot be created."""
1432
raise errors.UninitializableFormat(self)
1434
def is_supported(self):
1435
"""Format 4 is not supported.
1437
It is not supported because the model changed from 4 to 5 and the
1438
conversion logic is expensive - so doing it on the fly was not
1443
def _open(self, transport):
1444
"""See BzrDirFormat._open."""
1445
return BzrDir4(transport, self)
1447
def __return_repository_format(self):
1448
"""Circular import protection."""
1449
from bzrlib.repofmt.weaverepo import RepositoryFormat4
1450
return RepositoryFormat4()
1451
repository_format = property(__return_repository_format)
1454
class BzrDirFormat5(BzrDirFormat):
1455
"""Bzr control format 5.
1457
This format is a combined format for working tree, branch and repository.
1459
- Format 2 working trees [always]
1460
- Format 4 branches [always]
1461
- Format 5 repositories [always]
1462
Unhashed stores in the repository.
1465
_lock_class = lockable_files.TransportLock
1467
def get_format_string(self):
1468
"""See BzrDirFormat.get_format_string()."""
1469
return "Bazaar-NG branch, format 5\n"
1471
def get_format_description(self):
1472
"""See BzrDirFormat.get_format_description()."""
1473
return "All-in-one format 5"
1475
def get_converter(self, format=None):
1476
"""See BzrDirFormat.get_converter()."""
1477
# there is one and only one upgrade path here.
1478
return ConvertBzrDir5To6()
1480
def _initialize_for_clone(self, url):
1481
return self.initialize_on_transport(get_transport(url), _cloning=True)
1483
def initialize_on_transport(self, transport, _cloning=False):
1484
"""Format 5 dirs always have working tree, branch and repository.
1486
Except when they are being cloned.
1488
from bzrlib.branch import BzrBranchFormat4
1489
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1490
from bzrlib.workingtree import WorkingTreeFormat2
1491
result = (super(BzrDirFormat5, self).initialize_on_transport(transport))
1492
RepositoryFormat5().initialize(result, _internal=True)
1494
branch = BzrBranchFormat4().initialize(result)
1496
WorkingTreeFormat2().initialize(result)
1497
except errors.NotLocalUrl:
1498
# Even though we can't access the working tree, we need to
1499
# create its control files.
1500
WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
1503
def _open(self, transport):
1504
"""See BzrDirFormat._open."""
1505
return BzrDir5(transport, self)
1507
def __return_repository_format(self):
1508
"""Circular import protection."""
1509
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1510
return RepositoryFormat5()
1511
repository_format = property(__return_repository_format)
1514
class BzrDirFormat6(BzrDirFormat):
1515
"""Bzr control format 6.
1517
This format is a combined format for working tree, branch and repository.
1519
- Format 2 working trees [always]
1520
- Format 4 branches [always]
1521
- Format 6 repositories [always]
1524
_lock_class = lockable_files.TransportLock
1526
def get_format_string(self):
1527
"""See BzrDirFormat.get_format_string()."""
1528
return "Bazaar-NG branch, format 6\n"
1530
def get_format_description(self):
1531
"""See BzrDirFormat.get_format_description()."""
1532
return "All-in-one format 6"
1534
def get_converter(self, format=None):
1535
"""See BzrDirFormat.get_converter()."""
1536
# there is one and only one upgrade path here.
1537
return ConvertBzrDir6ToMeta()
1539
def _initialize_for_clone(self, url):
1540
return self.initialize_on_transport(get_transport(url), _cloning=True)
1542
def initialize_on_transport(self, transport, _cloning=False):
1543
"""Format 6 dirs always have working tree, branch and repository.
1545
Except when they are being cloned.
1547
from bzrlib.branch import BzrBranchFormat4
1548
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1549
from bzrlib.workingtree import WorkingTreeFormat2
1550
result = super(BzrDirFormat6, self).initialize_on_transport(transport)
1551
RepositoryFormat6().initialize(result, _internal=True)
1553
branch = BzrBranchFormat4().initialize(result)
1555
WorkingTreeFormat2().initialize(result)
1556
except errors.NotLocalUrl:
1557
# Even though we can't access the working tree, we need to
1558
# create its control files.
1559
WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
1562
def _open(self, transport):
1563
"""See BzrDirFormat._open."""
1564
return BzrDir6(transport, self)
1566
def __return_repository_format(self):
1567
"""Circular import protection."""
1568
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1569
return RepositoryFormat6()
1570
repository_format = property(__return_repository_format)
1573
class BzrDirMetaFormat1(BzrDirFormat):
1574
"""Bzr meta control format 1
1576
This is the first format with split out working tree, branch and repository
1579
- Format 3 working trees [optional]
1580
- Format 5 branches [optional]
1581
- Format 7 repositories [optional]
1584
_lock_class = lockdir.LockDir
1587
self._workingtree_format = None
1588
self._branch_format = None
1590
def __eq__(self, other):
1591
if other.__class__ is not self.__class__:
1593
if other.repository_format != self.repository_format:
1595
if other.workingtree_format != self.workingtree_format:
1599
def __ne__(self, other):
1600
return not self == other
1602
def get_branch_format(self):
1603
if self._branch_format is None:
1604
from bzrlib.branch import BranchFormat
1605
self._branch_format = BranchFormat.get_default_format()
1606
return self._branch_format
1608
def set_branch_format(self, format):
1609
self._branch_format = format
1611
def get_converter(self, format=None):
1612
"""See BzrDirFormat.get_converter()."""
1614
format = BzrDirFormat.get_default_format()
1615
if not isinstance(self, format.__class__):
1616
# converting away from metadir is not implemented
1617
raise NotImplementedError(self.get_converter)
1618
return ConvertMetaToMeta(format)
1620
def get_format_string(self):
1621
"""See BzrDirFormat.get_format_string()."""
1622
return "Bazaar-NG meta directory, format 1\n"
1624
def get_format_description(self):
1625
"""See BzrDirFormat.get_format_description()."""
1626
return "Meta directory format 1"
1628
def _open(self, transport):
1629
"""See BzrDirFormat._open."""
1630
return BzrDirMeta1(transport, self)
1632
def __return_repository_format(self):
1633
"""Circular import protection."""
1634
if getattr(self, '_repository_format', None):
1635
return self._repository_format
1636
from bzrlib.repository import RepositoryFormat
1637
return RepositoryFormat.get_default_format()
1639
def __set_repository_format(self, value):
1640
"""Allow changint the repository format for metadir formats."""
1641
self._repository_format = value
1643
repository_format = property(__return_repository_format, __set_repository_format)
1645
def __get_workingtree_format(self):
1646
if self._workingtree_format is None:
1647
from bzrlib.workingtree import WorkingTreeFormat
1648
self._workingtree_format = WorkingTreeFormat.get_default_format()
1649
return self._workingtree_format
1651
def __set_workingtree_format(self, wt_format):
1652
self._workingtree_format = wt_format
1654
workingtree_format = property(__get_workingtree_format,
1655
__set_workingtree_format)
1658
# Register bzr control format
1659
BzrDirFormat.register_control_format(BzrDirFormat)
1661
# Register bzr formats
1662
BzrDirFormat.register_format(BzrDirFormat4())
1663
BzrDirFormat.register_format(BzrDirFormat5())
1664
BzrDirFormat.register_format(BzrDirFormat6())
1665
__default_format = BzrDirMetaFormat1()
1666
BzrDirFormat.register_format(__default_format)
1667
BzrDirFormat._default_format = __default_format
1670
class BzrDirTestProviderAdapter(object):
1671
"""A tool to generate a suite testing multiple bzrdir formats at once.
1673
This is done by copying the test once for each transport and injecting
1674
the transport_server, transport_readonly_server, and bzrdir_format
1675
classes into each copy. Each copy is also given a new id() to make it
1679
def __init__(self, vfs_factory, transport_server, transport_readonly_server,
1681
"""Create an object to adapt tests.
1683
:param vfs_server: A factory to create a Transport Server which has
1684
all the VFS methods working, and is writable.
1686
self._vfs_factory = vfs_factory
1687
self._transport_server = transport_server
1688
self._transport_readonly_server = transport_readonly_server
1689
self._formats = formats
1691
def adapt(self, test):
1692
result = unittest.TestSuite()
1693
for format in self._formats:
1694
new_test = deepcopy(test)
1695
new_test.vfs_transport_factory = self._vfs_factory
1696
new_test.transport_server = self._transport_server
1697
new_test.transport_readonly_server = self._transport_readonly_server
1698
new_test.bzrdir_format = format
1699
def make_new_test_id():
1700
new_id = "%s(%s)" % (new_test.id(), format.__class__.__name__)
1701
return lambda: new_id
1702
new_test.id = make_new_test_id()
1703
result.addTest(new_test)
1707
class Converter(object):
1708
"""Converts a disk format object from one format to another."""
1710
def convert(self, to_convert, pb):
1711
"""Perform the conversion of to_convert, giving feedback via pb.
1713
:param to_convert: The disk object to convert.
1714
:param pb: a progress bar to use for progress information.
1717
def step(self, message):
1718
"""Update the pb by a step."""
1720
self.pb.update(message, self.count, self.total)
1723
class ConvertBzrDir4To5(Converter):
1724
"""Converts format 4 bzr dirs to format 5."""
1727
super(ConvertBzrDir4To5, self).__init__()
1728
self.converted_revs = set()
1729
self.absent_revisions = set()
1733
def convert(self, to_convert, pb):
1734
"""See Converter.convert()."""
1735
self.bzrdir = to_convert
1737
self.pb.note('starting upgrade from format 4 to 5')
1738
if isinstance(self.bzrdir.transport, LocalTransport):
1739
self.bzrdir.get_workingtree_transport(None).delete('stat-cache')
1740
self._convert_to_weaves()
1741
return BzrDir.open(self.bzrdir.root_transport.base)
1743
def _convert_to_weaves(self):
1744
self.pb.note('note: upgrade may be faster if all store files are ungzipped first')
1747
stat = self.bzrdir.transport.stat('weaves')
1748
if not S_ISDIR(stat.st_mode):
1749
self.bzrdir.transport.delete('weaves')
1750
self.bzrdir.transport.mkdir('weaves')
1751
except errors.NoSuchFile:
1752
self.bzrdir.transport.mkdir('weaves')
1753
# deliberately not a WeaveFile as we want to build it up slowly.
1754
self.inv_weave = Weave('inventory')
1755
# holds in-memory weaves for all files
1756
self.text_weaves = {}
1757
self.bzrdir.transport.delete('branch-format')
1758
self.branch = self.bzrdir.open_branch()
1759
self._convert_working_inv()
1760
rev_history = self.branch.revision_history()
1761
# to_read is a stack holding the revisions we still need to process;
1762
# appending to it adds new highest-priority revisions
1763
self.known_revisions = set(rev_history)
1764
self.to_read = rev_history[-1:]
1766
rev_id = self.to_read.pop()
1767
if (rev_id not in self.revisions
1768
and rev_id not in self.absent_revisions):
1769
self._load_one_rev(rev_id)
1771
to_import = self._make_order()
1772
for i, rev_id in enumerate(to_import):
1773
self.pb.update('converting revision', i, len(to_import))
1774
self._convert_one_rev(rev_id)
1776
self._write_all_weaves()
1777
self._write_all_revs()
1778
self.pb.note('upgraded to weaves:')
1779
self.pb.note(' %6d revisions and inventories', len(self.revisions))
1780
self.pb.note(' %6d revisions not present', len(self.absent_revisions))
1781
self.pb.note(' %6d texts', self.text_count)
1782
self._cleanup_spare_files_after_format4()
1783
self.branch.control_files.put_utf8('branch-format', BzrDirFormat5().get_format_string())
1785
def _cleanup_spare_files_after_format4(self):
1786
# FIXME working tree upgrade foo.
1787
for n in 'merged-patches', 'pending-merged-patches':
1789
## assert os.path.getsize(p) == 0
1790
self.bzrdir.transport.delete(n)
1791
except errors.NoSuchFile:
1793
self.bzrdir.transport.delete_tree('inventory-store')
1794
self.bzrdir.transport.delete_tree('text-store')
1796
def _convert_working_inv(self):
1797
inv = xml4.serializer_v4.read_inventory(
1798
self.branch.control_files.get('inventory'))
1799
new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
1800
# FIXME inventory is a working tree change.
1801
self.branch.control_files.put('inventory', StringIO(new_inv_xml))
1803
def _write_all_weaves(self):
1804
controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)
1805
weave_transport = self.bzrdir.transport.clone('weaves')
1806
weaves = WeaveStore(weave_transport, prefixed=False)
1807
transaction = WriteTransaction()
1811
for file_id, file_weave in self.text_weaves.items():
1812
self.pb.update('writing weave', i, len(self.text_weaves))
1813
weaves._put_weave(file_id, file_weave, transaction)
1815
self.pb.update('inventory', 0, 1)
1816
controlweaves._put_weave('inventory', self.inv_weave, transaction)
1817
self.pb.update('inventory', 1, 1)
1821
def _write_all_revs(self):
1822
"""Write all revisions out in new form."""
1823
self.bzrdir.transport.delete_tree('revision-store')
1824
self.bzrdir.transport.mkdir('revision-store')
1825
revision_transport = self.bzrdir.transport.clone('revision-store')
1827
_revision_store = TextRevisionStore(TextStore(revision_transport,
1831
transaction = WriteTransaction()
1832
for i, rev_id in enumerate(self.converted_revs):
1833
self.pb.update('write revision', i, len(self.converted_revs))
1834
_revision_store.add_revision(self.revisions[rev_id], transaction)
1838
def _load_one_rev(self, rev_id):
1839
"""Load a revision object into memory.
1841
Any parents not either loaded or abandoned get queued to be
1843
self.pb.update('loading revision',
1844
len(self.revisions),
1845
len(self.known_revisions))
1846
if not self.branch.repository.has_revision(rev_id):
1848
self.pb.note('revision {%s} not present in branch; '
1849
'will be converted as a ghost',
1851
self.absent_revisions.add(rev_id)
1853
rev = self.branch.repository._revision_store.get_revision(rev_id,
1854
self.branch.repository.get_transaction())
1855
for parent_id in rev.parent_ids:
1856
self.known_revisions.add(parent_id)
1857
self.to_read.append(parent_id)
1858
self.revisions[rev_id] = rev
1860
def _load_old_inventory(self, rev_id):
1861
assert rev_id not in self.converted_revs
1862
old_inv_xml = self.branch.repository.inventory_store.get(rev_id).read()
1863
inv = xml4.serializer_v4.read_inventory_from_string(old_inv_xml)
1864
inv.revision_id = rev_id
1865
rev = self.revisions[rev_id]
1866
if rev.inventory_sha1:
1867
assert rev.inventory_sha1 == sha_string(old_inv_xml), \
1868
'inventory sha mismatch for {%s}' % rev_id
1871
def _load_updated_inventory(self, rev_id):
1872
assert rev_id in self.converted_revs
1873
inv_xml = self.inv_weave.get_text(rev_id)
1874
inv = xml5.serializer_v5.read_inventory_from_string(inv_xml)
1877
def _convert_one_rev(self, rev_id):
1878
"""Convert revision and all referenced objects to new format."""
1879
rev = self.revisions[rev_id]
1880
inv = self._load_old_inventory(rev_id)
1881
present_parents = [p for p in rev.parent_ids
1882
if p not in self.absent_revisions]
1883
self._convert_revision_contents(rev, inv, present_parents)
1884
self._store_new_weave(rev, inv, present_parents)
1885
self.converted_revs.add(rev_id)
1887
def _store_new_weave(self, rev, inv, present_parents):
1888
# the XML is now updated with text versions
1890
entries = inv.iter_entries()
1892
for path, ie in entries:
1893
assert getattr(ie, 'revision', None) is not None, \
1894
'no revision on {%s} in {%s}' % \
1895
(file_id, rev.revision_id)
1896
new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
1897
new_inv_sha1 = sha_string(new_inv_xml)
1898
self.inv_weave.add_lines(rev.revision_id,
1900
new_inv_xml.splitlines(True))
1901
rev.inventory_sha1 = new_inv_sha1
1903
def _convert_revision_contents(self, rev, inv, present_parents):
1904
"""Convert all the files within a revision.
1906
Also upgrade the inventory to refer to the text revision ids."""
1907
rev_id = rev.revision_id
1908
mutter('converting texts of revision {%s}',
1910
parent_invs = map(self._load_updated_inventory, present_parents)
1911
entries = inv.iter_entries()
1913
for path, ie in entries:
1914
self._convert_file_version(rev, ie, parent_invs)
1916
def _convert_file_version(self, rev, ie, parent_invs):
1917
"""Convert one version of one file.
1919
The file needs to be added into the weave if it is a merge
1920
of >=2 parents or if it's changed from its parent.
1922
file_id = ie.file_id
1923
rev_id = rev.revision_id
1924
w = self.text_weaves.get(file_id)
1927
self.text_weaves[file_id] = w
1928
text_changed = False
1929
previous_entries = ie.find_previous_heads(parent_invs,
1933
for old_revision in previous_entries:
1934
# if this fails, its a ghost ?
1935
assert old_revision in self.converted_revs, \
1936
"Revision {%s} not in converted_revs" % old_revision
1937
self.snapshot_ie(previous_entries, ie, w, rev_id)
1939
assert getattr(ie, 'revision', None) is not None
1941
def snapshot_ie(self, previous_revisions, ie, w, rev_id):
1942
# TODO: convert this logic, which is ~= snapshot to
1943
# a call to:. This needs the path figured out. rather than a work_tree
1944
# a v4 revision_tree can be given, or something that looks enough like
1945
# one to give the file content to the entry if it needs it.
1946
# and we need something that looks like a weave store for snapshot to
1948
#ie.snapshot(rev, PATH, previous_revisions, REVISION_TREE, InMemoryWeaveStore(self.text_weaves))
1949
if len(previous_revisions) == 1:
1950
previous_ie = previous_revisions.values()[0]
1951
if ie._unchanged(previous_ie):
1952
ie.revision = previous_ie.revision
1955
text = self.branch.repository.text_store.get(ie.text_id)
1956
file_lines = text.readlines()
1957
assert sha_strings(file_lines) == ie.text_sha1
1958
assert sum(map(len, file_lines)) == ie.text_size
1959
w.add_lines(rev_id, previous_revisions, file_lines)
1960
self.text_count += 1
1962
w.add_lines(rev_id, previous_revisions, [])
1963
ie.revision = rev_id
1965
def _make_order(self):
1966
"""Return a suitable order for importing revisions.
1968
The order must be such that an revision is imported after all
1969
its (present) parents.
1971
todo = set(self.revisions.keys())
1972
done = self.absent_revisions.copy()
1975
# scan through looking for a revision whose parents
1977
for rev_id in sorted(list(todo)):
1978
rev = self.revisions[rev_id]
1979
parent_ids = set(rev.parent_ids)
1980
if parent_ids.issubset(done):
1981
# can take this one now
1982
order.append(rev_id)
1988
class ConvertBzrDir5To6(Converter):
1989
"""Converts format 5 bzr dirs to format 6."""
1991
def convert(self, to_convert, pb):
1992
"""See Converter.convert()."""
1993
self.bzrdir = to_convert
1995
self.pb.note('starting upgrade from format 5 to 6')
1996
self._convert_to_prefixed()
1997
return BzrDir.open(self.bzrdir.root_transport.base)
1999
def _convert_to_prefixed(self):
2000
from bzrlib.store import TransportStore
2001
self.bzrdir.transport.delete('branch-format')
2002
for store_name in ["weaves", "revision-store"]:
2003
self.pb.note("adding prefixes to %s" % store_name)
2004
store_transport = self.bzrdir.transport.clone(store_name)
2005
store = TransportStore(store_transport, prefixed=True)
2006
for urlfilename in store_transport.list_dir('.'):
2007
filename = urlutils.unescape(urlfilename)
2008
if (filename.endswith(".weave") or
2009
filename.endswith(".gz") or
2010
filename.endswith(".sig")):
2011
file_id = os.path.splitext(filename)[0]
2014
prefix_dir = store.hash_prefix(file_id)
2015
# FIXME keep track of the dirs made RBC 20060121
2017
store_transport.move(filename, prefix_dir + '/' + filename)
2018
except errors.NoSuchFile: # catches missing dirs strangely enough
2019
store_transport.mkdir(prefix_dir)
2020
store_transport.move(filename, prefix_dir + '/' + filename)
2021
self.bzrdir._control_files.put_utf8('branch-format', BzrDirFormat6().get_format_string())
2024
class ConvertBzrDir6ToMeta(Converter):
2025
"""Converts format 6 bzr dirs to metadirs."""
2027
def convert(self, to_convert, pb):
2028
"""See Converter.convert()."""
2029
from bzrlib.repofmt.weaverepo import RepositoryFormat7
2030
from bzrlib.branch import BzrBranchFormat5
2031
self.bzrdir = to_convert
2034
self.total = 20 # the steps we know about
2035
self.garbage_inventories = []
2037
self.pb.note('starting upgrade from format 6 to metadir')
2038
self.bzrdir._control_files.put_utf8('branch-format', "Converting to format 6")
2039
# its faster to move specific files around than to open and use the apis...
2040
# first off, nuke ancestry.weave, it was never used.
2042
self.step('Removing ancestry.weave')
2043
self.bzrdir.transport.delete('ancestry.weave')
2044
except errors.NoSuchFile:
2046
# find out whats there
2047
self.step('Finding branch files')
2048
last_revision = self.bzrdir.open_branch().last_revision()
2049
bzrcontents = self.bzrdir.transport.list_dir('.')
2050
for name in bzrcontents:
2051
if name.startswith('basis-inventory.'):
2052
self.garbage_inventories.append(name)
2053
# create new directories for repository, working tree and branch
2054
self.dir_mode = self.bzrdir._control_files._dir_mode
2055
self.file_mode = self.bzrdir._control_files._file_mode
2056
repository_names = [('inventory.weave', True),
2057
('revision-store', True),
2059
self.step('Upgrading repository ')
2060
self.bzrdir.transport.mkdir('repository', mode=self.dir_mode)
2061
self.make_lock('repository')
2062
# we hard code the formats here because we are converting into
2063
# the meta format. The meta format upgrader can take this to a
2064
# future format within each component.
2065
self.put_format('repository', RepositoryFormat7())
2066
for entry in repository_names:
2067
self.move_entry('repository', entry)
2069
self.step('Upgrading branch ')
2070
self.bzrdir.transport.mkdir('branch', mode=self.dir_mode)
2071
self.make_lock('branch')
2072
self.put_format('branch', BzrBranchFormat5())
2073
branch_files = [('revision-history', True),
2074
('branch-name', True),
2076
for entry in branch_files:
2077
self.move_entry('branch', entry)
2079
checkout_files = [('pending-merges', True),
2080
('inventory', True),
2081
('stat-cache', False)]
2082
# If a mandatory checkout file is not present, the branch does not have
2083
# a functional checkout. Do not create a checkout in the converted
2085
for name, mandatory in checkout_files:
2086
if mandatory and name not in bzrcontents:
2087
has_checkout = False
2091
if not has_checkout:
2092
self.pb.note('No working tree.')
2093
# If some checkout files are there, we may as well get rid of them.
2094
for name, mandatory in checkout_files:
2095
if name in bzrcontents:
2096
self.bzrdir.transport.delete(name)
2098
from bzrlib.workingtree import WorkingTreeFormat3
2099
self.step('Upgrading working tree')
2100
self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
2101
self.make_lock('checkout')
2103
'checkout', WorkingTreeFormat3())
2104
self.bzrdir.transport.delete_multi(
2105
self.garbage_inventories, self.pb)
2106
for entry in checkout_files:
2107
self.move_entry('checkout', entry)
2108
if last_revision is not None:
2109
self.bzrdir._control_files.put_utf8(
2110
'checkout/last-revision', last_revision)
2111
self.bzrdir._control_files.put_utf8(
2112
'branch-format', BzrDirMetaFormat1().get_format_string())
2113
return BzrDir.open(self.bzrdir.root_transport.base)
2115
def make_lock(self, name):
2116
"""Make a lock for the new control dir name."""
2117
self.step('Make %s lock' % name)
2118
ld = lockdir.LockDir(self.bzrdir.transport,
2120
file_modebits=self.file_mode,
2121
dir_modebits=self.dir_mode)
2124
def move_entry(self, new_dir, entry):
2125
"""Move then entry name into new_dir."""
2127
mandatory = entry[1]
2128
self.step('Moving %s' % name)
2130
self.bzrdir.transport.move(name, '%s/%s' % (new_dir, name))
2131
except errors.NoSuchFile:
2135
def put_format(self, dirname, format):
2136
self.bzrdir._control_files.put_utf8('%s/format' % dirname, format.get_format_string())
2139
class ConvertMetaToMeta(Converter):
2140
"""Converts the components of metadirs."""
2142
def __init__(self, target_format):
2143
"""Create a metadir to metadir converter.
2145
:param target_format: The final metadir format that is desired.
2147
self.target_format = target_format
2149
def convert(self, to_convert, pb):
2150
"""See Converter.convert()."""
2151
self.bzrdir = to_convert
2155
self.step('checking repository format')
2157
repo = self.bzrdir.open_repository()
2158
except errors.NoRepositoryPresent:
2161
if not isinstance(repo._format, self.target_format.repository_format.__class__):
2162
from bzrlib.repository import CopyConverter
2163
self.pb.note('starting repository conversion')
2164
converter = CopyConverter(self.target_format.repository_format)
2165
converter.convert(repo, pb)
2167
branch = self.bzrdir.open_branch()
2168
except errors.NotBranchError:
2171
# TODO: conversions of Branch and Tree should be done by
2172
# InterXFormat lookups
2173
# Avoid circular imports
2174
from bzrlib import branch as _mod_branch
2175
if (branch._format.__class__ is _mod_branch.BzrBranchFormat5 and
2176
self.target_format.get_branch_format().__class__ is
2177
_mod_branch.BzrBranchFormat6):
2178
branch_converter = _mod_branch.Converter5to6()
2179
branch_converter.convert(branch)
2181
tree = self.bzrdir.open_workingtree(recommend_upgrade=False)
2182
except (errors.NoWorkingTree, errors.NotLocalUrl):
2185
# TODO: conversions of Branch and Tree should be done by
2186
# InterXFormat lookups
2187
if (isinstance(tree, workingtree.WorkingTree3) and
2188
not isinstance(tree, workingtree_4.WorkingTree4) and
2189
isinstance(self.target_format.workingtree_format,
2190
workingtree_4.WorkingTreeFormat4)):
2191
workingtree_4.Converter3to4().convert(tree)
2195
# This is not in remote.py because it's small, and needs to be registered.
2196
# Putting it in remote.py creates a circular import problem.
2197
# we can make it a lazy object if the control formats is turned into something
2199
class RemoteBzrDirFormat(BzrDirMetaFormat1):
2200
"""Format representing bzrdirs accessed via a smart server"""
2202
def get_format_description(self):
2203
return 'bzr remote bzrdir'
2206
def probe_transport(klass, transport):
2207
"""Return a RemoteBzrDirFormat object if it looks possible."""
2209
transport.get_smart_client()
2210
except (NotImplementedError, AttributeError,
2211
errors.TransportNotPossible):
2212
# no smart server, so not a branch for this format type.
2213
raise errors.NotBranchError(path=transport.base)
2217
def initialize_on_transport(self, transport):
2219
# hand off the request to the smart server
2220
medium = transport.get_smart_medium()
2221
except errors.NoSmartMedium:
2222
# TODO: lookup the local format from a server hint.
2223
local_dir_format = BzrDirMetaFormat1()
2224
return local_dir_format.initialize_on_transport(transport)
2225
client = SmartClient(medium)
2226
path = client.remote_path_from_transport(transport)
2227
response = SmartClient(medium).call('BzrDirFormat.initialize', path)
2228
assert response[0] in ('ok', ), 'unexpected response code %s' % (response,)
2229
return remote.RemoteBzrDir(transport)
2231
def _open(self, transport):
2232
return remote.RemoteBzrDir(transport)
2234
def __eq__(self, other):
2235
if not isinstance(other, RemoteBzrDirFormat):
2237
return self.get_format_description() == other.get_format_description()
2240
# We can't use register_control_format because it adds it at a lower priority
2241
# than the existing branches, whereas this should take priority.
2242
BzrDirFormat._control_formats.insert(0, RemoteBzrDirFormat)
2245
class BzrDirFormatInfo(object):
2247
def __init__(self, native, deprecated, hidden):
2248
self.deprecated = deprecated
2249
self.native = native
2250
self.hidden = hidden
2253
class BzrDirFormatRegistry(registry.Registry):
2254
"""Registry of user-selectable BzrDir subformats.
2256
Differs from BzrDirFormat._control_formats in that it provides sub-formats,
2257
e.g. BzrDirMeta1 with weave repository. Also, it's more user-oriented.
2260
def register_metadir(self, key,
2261
repository_format, help, native=True, deprecated=False,
2265
"""Register a metadir subformat.
2267
These all use a BzrDirMetaFormat1 bzrdir, but can be parameterized
2268
by the Repository format.
2270
:param repository_format: The fully-qualified repository format class
2272
:param branch_format: Fully-qualified branch format class name as
2274
:param tree_format: Fully-qualified tree format class name as
2277
# This should be expanded to support setting WorkingTree and Branch
2278
# formats, once BzrDirMetaFormat1 supports that.
2279
def _load(full_name):
2280
mod_name, factory_name = full_name.rsplit('.', 1)
2282
mod = __import__(mod_name, globals(), locals(),
2284
except ImportError, e:
2285
raise ImportError('failed to load %s: %s' % (full_name, e))
2287
factory = getattr(mod, factory_name)
2288
except AttributeError:
2289
raise AttributeError('no factory %s in module %r'
2294
bd = BzrDirMetaFormat1()
2295
if branch_format is not None:
2296
bd.set_branch_format(_load(branch_format))
2297
if tree_format is not None:
2298
bd.workingtree_format = _load(tree_format)
2299
if repository_format is not None:
2300
bd.repository_format = _load(repository_format)
2302
self.register(key, helper, help, native, deprecated, hidden)
2304
def register(self, key, factory, help, native=True, deprecated=False,
2306
"""Register a BzrDirFormat factory.
2308
The factory must be a callable that takes one parameter: the key.
2309
It must produce an instance of the BzrDirFormat when called.
2311
This function mainly exists to prevent the info object from being
2314
registry.Registry.register(self, key, factory, help,
2315
BzrDirFormatInfo(native, deprecated, hidden))
2317
def register_lazy(self, key, module_name, member_name, help, native=True,
2318
deprecated=False, hidden=False):
2319
registry.Registry.register_lazy(self, key, module_name, member_name,
2320
help, BzrDirFormatInfo(native, deprecated, hidden))
2322
def set_default(self, key):
2323
"""Set the 'default' key to be a clone of the supplied key.
2325
This method must be called once and only once.
2327
registry.Registry.register(self, 'default', self.get(key),
2328
self.get_help(key), info=self.get_info(key))
2330
def set_default_repository(self, key):
2331
"""Set the FormatRegistry default and Repository default.
2333
This is a transitional method while Repository.set_default_format
2336
if 'default' in self:
2337
self.remove('default')
2338
self.set_default(key)
2339
format = self.get('default')()
2340
assert isinstance(format, BzrDirMetaFormat1)
2342
def make_bzrdir(self, key):
2343
return self.get(key)()
2345
def help_topic(self, topic):
2346
output = textwrap.dedent("""\
2347
Bazaar directory formats
2348
------------------------
2350
These formats can be used for creating branches, working trees, and
2354
default_help = self.get_help('default')
2356
for key in self.keys():
2357
if key == 'default':
2359
help = self.get_help(key)
2360
if help == default_help:
2361
default_realkey = key
2363
help_pairs.append((key, help))
2365
def wrapped(key, help, info):
2367
help = '(native) ' + help
2368
return ' %s:\n%s\n\n' % (key,
2369
textwrap.fill(help, initial_indent=' ',
2370
subsequent_indent=' '))
2371
output += wrapped('%s/default' % default_realkey, default_help,
2372
self.get_info('default'))
2373
deprecated_pairs = []
2374
for key, help in help_pairs:
2375
info = self.get_info(key)
2378
elif info.deprecated:
2379
deprecated_pairs.append((key, help))
2381
output += wrapped(key, help, info)
2382
if len(deprecated_pairs) > 0:
2383
output += "Deprecated formats\n------------------\n\n"
2384
for key, help in deprecated_pairs:
2385
info = self.get_info(key)
2386
output += wrapped(key, help, info)
2391
format_registry = BzrDirFormatRegistry()
2392
format_registry.register('weave', BzrDirFormat6,
2393
'Pre-0.8 format. Slower than knit and does not'
2394
' support checkouts or shared repositories.',
2396
format_registry.register_metadir('knit',
2397
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2398
'Format using knits. Recommended for interoperation with bzr <= 0.14.',
2399
branch_format='bzrlib.branch.BzrBranchFormat5',
2400
tree_format='bzrlib.workingtree.WorkingTreeFormat3')
2401
format_registry.register_metadir('metaweave',
2402
'bzrlib.repofmt.weaverepo.RepositoryFormat7',
2403
'Transitional format in 0.8. Slower than knit.',
2404
branch_format='bzrlib.branch.BzrBranchFormat5',
2405
tree_format='bzrlib.workingtree.WorkingTreeFormat3',
2407
format_registry.register_metadir('dirstate',
2408
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2409
help='New in 0.15: Fast local operations. Compatible with bzr 0.8 and '
2410
'above when accessed over the network.',
2411
branch_format='bzrlib.branch.BzrBranchFormat5',
2412
# this uses bzrlib.workingtree.WorkingTreeFormat4 because importing
2413
# directly from workingtree_4 triggers a circular import.
2414
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2416
format_registry.register_metadir('dirstate-tags',
2417
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2418
help='New in 0.15: Fast local operations and improved scaling for '
2419
'network operations. Additionally adds support for tags.'
2420
' Incompatible with bzr < 0.15.',
2421
branch_format='bzrlib.branch.BzrBranchFormat6',
2422
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2424
format_registry.register_metadir('dirstate-with-subtree',
2425
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
2426
help='New in 0.15: Fast local operations and improved scaling for '
2427
'network operations. Additionally adds support for versioning nested '
2428
'bzr branches. Incompatible with bzr < 0.15.',
2429
branch_format='bzrlib.branch.BzrBranchFormat6',
2430
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2433
format_registry.set_default('dirstate')