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
22
Note: This module has a lot of ``open`` functions/methods that return
23
references to in-memory objects. As a rule, there are no matching ``close``
24
methods. To free any associated resources, simply stop referencing the
28
# TODO: Move old formats into a plugin to make this file smaller.
30
from cStringIO import StringIO
34
from bzrlib.lazy_import import lazy_import
35
lazy_import(globals(), """
36
from stat import S_ISDIR
38
from warnings import warn
48
revision as _mod_revision,
58
from bzrlib.osutils import (
62
from bzrlib.smart.client import _SmartClient
63
from bzrlib.smart import protocol
64
from bzrlib.store.revision.text import TextRevisionStore
65
from bzrlib.store.text import TextStore
66
from bzrlib.store.versioned import WeaveStore
67
from bzrlib.transactions import WriteTransaction
68
from bzrlib.transport import (
69
do_catching_redirections,
72
from bzrlib.weave import Weave
75
from bzrlib.trace import (
79
from bzrlib.transport.local import LocalTransport
80
from bzrlib.symbol_versioning import (
88
"""A .bzr control diretory.
90
BzrDir instances let you create or open any of the things that can be
91
found within .bzr - checkouts, branches and repositories.
94
the transport which this bzr dir is rooted at (i.e. file:///.../.bzr/)
96
a transport connected to the directory this bzr was opened from
97
(i.e. the parent directory holding the .bzr directory).
100
def break_lock(self):
101
"""Invoke break_lock on the first object in the bzrdir.
103
If there is a tree, the tree is opened and break_lock() called.
104
Otherwise, branch is tried, and finally repository.
106
# XXX: This seems more like a UI function than something that really
107
# belongs in this class.
109
thing_to_unlock = self.open_workingtree()
110
except (errors.NotLocalUrl, errors.NoWorkingTree):
112
thing_to_unlock = self.open_branch()
113
except errors.NotBranchError:
115
thing_to_unlock = self.open_repository()
116
except errors.NoRepositoryPresent:
118
thing_to_unlock.break_lock()
120
def can_convert_format(self):
121
"""Return true if this bzrdir is one whose format we can convert from."""
124
def check_conversion_target(self, target_format):
125
target_repo_format = target_format.repository_format
126
source_repo_format = self._format.repository_format
127
source_repo_format.check_conversion_target(target_repo_format)
130
def _check_supported(format, allow_unsupported,
131
recommend_upgrade=True,
133
"""Give an error or warning on old formats.
135
:param format: may be any kind of format - workingtree, branch,
138
:param allow_unsupported: If true, allow opening
139
formats that are strongly deprecated, and which may
140
have limited functionality.
142
:param recommend_upgrade: If true (default), warn
143
the user through the ui object that they may wish
144
to upgrade the object.
146
# TODO: perhaps move this into a base Format class; it's not BzrDir
147
# specific. mbp 20070323
148
if not allow_unsupported and not format.is_supported():
149
# see open_downlevel to open legacy branches.
150
raise errors.UnsupportedFormatError(format=format)
151
if recommend_upgrade \
152
and getattr(format, 'upgrade_recommended', False):
153
ui.ui_factory.recommend_upgrade(
154
format.get_format_description(),
157
def clone(self, url, revision_id=None, force_new_repo=False):
158
"""Clone this bzrdir and its contents to url verbatim.
160
If url's last component does not exist, it will be created.
162
if revision_id is not None, then the clone operation may tune
163
itself to download less data.
164
:param force_new_repo: Do not use a shared repository for the target
165
even if one is available.
167
return self.clone_on_transport(get_transport(url),
168
revision_id=revision_id,
169
force_new_repo=force_new_repo)
171
def clone_on_transport(self, transport, revision_id=None,
172
force_new_repo=False):
173
"""Clone this bzrdir and its contents to transport verbatim.
175
If the target directory does not exist, it will be created.
177
if revision_id is not None, then the clone operation may tune
178
itself to download less data.
179
:param force_new_repo: Do not use a shared repository for the target
180
even if one is available.
182
transport.ensure_base()
183
result = self._format.initialize_on_transport(transport)
185
local_repo = self.find_repository()
186
except errors.NoRepositoryPresent:
189
# may need to copy content in
191
result_repo = local_repo.clone(
193
revision_id=revision_id)
194
result_repo.set_make_working_trees(local_repo.make_working_trees())
197
result_repo = result.find_repository()
198
# fetch content this dir needs.
199
result_repo.fetch(local_repo, revision_id=revision_id)
200
except errors.NoRepositoryPresent:
201
# needed to make one anyway.
202
result_repo = local_repo.clone(
204
revision_id=revision_id)
205
result_repo.set_make_working_trees(local_repo.make_working_trees())
206
# 1 if there is a branch present
207
# make sure its content is available in the target repository
210
self.open_branch().clone(result, revision_id=revision_id)
211
except errors.NotBranchError:
214
result_repo = result.find_repository()
215
except errors.NoRepositoryPresent:
217
if result_repo is None or result_repo.make_working_trees():
219
self.open_workingtree().clone(result)
220
except (errors.NoWorkingTree, errors.NotLocalUrl):
224
# TODO: This should be given a Transport, and should chdir up; otherwise
225
# this will open a new connection.
226
def _make_tail(self, url):
227
t = get_transport(url)
231
def create(cls, base, format=None, possible_transports=None):
232
"""Create a new BzrDir at the url 'base'.
234
:param format: If supplied, the format of branch to create. If not
235
supplied, the default is used.
236
:param possible_transports: If supplied, a list of transports that
237
can be reused to share a remote connection.
239
if cls is not BzrDir:
240
raise AssertionError("BzrDir.create always creates the default"
241
" format, not one of %r" % cls)
242
t = get_transport(base, possible_transports)
245
format = BzrDirFormat.get_default_format()
246
return format.initialize_on_transport(t)
249
def find_bzrdirs(transport, evaluate=None, list_current=None):
250
"""Find bzrdirs recursively from current location.
252
This is intended primarily as a building block for more sophisticated
253
functionality, like finding trees under a directory, or finding
254
branches that use a given repository.
255
:param evaluate: An optional callable that yields recurse, value,
256
where recurse controls whether this bzrdir is recursed into
257
and value is the value to yield. By default, all bzrdirs
258
are recursed into, and the return value is the bzrdir.
259
:param list_current: if supplied, use this function to list the current
260
directory, instead of Transport.list_dir
261
:return: a generator of found bzrdirs, or whatever evaluate returns.
263
if list_current is None:
264
def list_current(transport):
265
return transport.list_dir('')
267
def evaluate(bzrdir):
270
pending = [transport]
271
while len(pending) > 0:
272
current_transport = pending.pop()
275
bzrdir = BzrDir.open_from_transport(current_transport)
276
except errors.NotBranchError:
279
recurse, value = evaluate(bzrdir)
282
subdirs = list_current(current_transport)
283
except errors.NoSuchFile:
286
for subdir in sorted(subdirs, reverse=True):
287
pending.append(current_transport.clone(subdir))
290
def find_branches(transport):
291
"""Find all branches under a transport.
293
This will find all branches below the transport, including branches
294
inside other branches. Where possible, it will use
295
Repository.find_branches.
297
To list all the branches that use a particular Repository, see
298
Repository.find_branches
300
def evaluate(bzrdir):
302
repository = bzrdir.open_repository()
303
except errors.NoRepositoryPresent:
306
return False, (None, repository)
308
branch = bzrdir.open_branch()
309
except errors.NotBranchError:
310
return True, (None, None)
312
return True, (branch, None)
314
for branch, repo in BzrDir.find_bzrdirs(transport, evaluate=evaluate):
316
branches.extend(repo.find_branches())
317
if branch is not None:
318
branches.append(branch)
322
def destroy_repository(self):
323
"""Destroy the repository in this BzrDir"""
324
raise NotImplementedError(self.destroy_repository)
326
def create_branch(self):
327
"""Create a branch in this BzrDir.
329
The bzrdir's format will control what branch format is created.
330
For more control see BranchFormatXX.create(a_bzrdir).
332
raise NotImplementedError(self.create_branch)
334
def destroy_branch(self):
335
"""Destroy the branch in this BzrDir"""
336
raise NotImplementedError(self.destroy_branch)
339
def create_branch_and_repo(base, force_new_repo=False, format=None):
340
"""Create a new BzrDir, Branch and Repository at the url 'base'.
342
This will use the current default BzrDirFormat unless one is
343
specified, and use whatever
344
repository format that that uses via bzrdir.create_branch and
345
create_repository. If a shared repository is available that is used
348
The created Branch object is returned.
350
:param base: The URL to create the branch at.
351
:param force_new_repo: If True a new repository is always created.
352
:param format: If supplied, the format of branch to create. If not
353
supplied, the default is used.
355
bzrdir = BzrDir.create(base, format)
356
bzrdir._find_or_create_repository(force_new_repo)
357
return bzrdir.create_branch()
359
def _find_or_create_repository(self, force_new_repo):
360
"""Create a new repository if needed, returning the repository."""
362
return self.create_repository()
364
return self.find_repository()
365
except errors.NoRepositoryPresent:
366
return self.create_repository()
369
def create_branch_convenience(base, force_new_repo=False,
370
force_new_tree=None, format=None,
371
possible_transports=None):
372
"""Create a new BzrDir, Branch and Repository at the url 'base'.
374
This is a convenience function - it will use an existing repository
375
if possible, can be told explicitly whether to create a working tree or
378
This will use the current default BzrDirFormat unless one is
379
specified, and use whatever
380
repository format that that uses via bzrdir.create_branch and
381
create_repository. If a shared repository is available that is used
382
preferentially. Whatever repository is used, its tree creation policy
385
The created Branch object is returned.
386
If a working tree cannot be made due to base not being a file:// url,
387
no error is raised unless force_new_tree is True, in which case no
388
data is created on disk and NotLocalUrl is raised.
390
:param base: The URL to create the branch at.
391
:param force_new_repo: If True a new repository is always created.
392
:param force_new_tree: If True or False force creation of a tree or
393
prevent such creation respectively.
394
:param format: Override for the bzrdir format to create.
395
:param possible_transports: An optional reusable transports list.
398
# check for non local urls
399
t = get_transport(base, possible_transports)
400
if not isinstance(t, LocalTransport):
401
raise errors.NotLocalUrl(base)
402
bzrdir = BzrDir.create(base, format, possible_transports)
403
repo = bzrdir._find_or_create_repository(force_new_repo)
404
result = bzrdir.create_branch()
405
if force_new_tree or (repo.make_working_trees() and
406
force_new_tree is None):
408
bzrdir.create_workingtree()
409
except errors.NotLocalUrl:
414
@deprecated_function(zero_ninetyone)
415
def create_repository(base, shared=False, format=None):
416
"""Create a new BzrDir and Repository at the url 'base'.
418
If no format is supplied, this will default to the current default
419
BzrDirFormat by default, and use whatever repository format that that
420
uses for bzrdirformat.create_repository.
422
:param shared: Create a shared repository rather than a standalone
424
The Repository object is returned.
426
This must be overridden as an instance method in child classes, where
427
it should take no parameters and construct whatever repository format
428
that child class desires.
430
This method is deprecated, please call create_repository on a bzrdir
433
bzrdir = BzrDir.create(base, format)
434
return bzrdir.create_repository(shared)
437
def create_standalone_workingtree(base, format=None):
438
"""Create a new BzrDir, WorkingTree, Branch and Repository at 'base'.
440
'base' must be a local path or a file:// url.
442
This will use the current default BzrDirFormat unless one is
443
specified, and use whatever
444
repository format that that uses for bzrdirformat.create_workingtree,
445
create_branch and create_repository.
447
:param format: Override for the bzrdir format to create.
448
:return: The WorkingTree object.
450
t = get_transport(base)
451
if not isinstance(t, LocalTransport):
452
raise errors.NotLocalUrl(base)
453
bzrdir = BzrDir.create_branch_and_repo(base,
455
format=format).bzrdir
456
return bzrdir.create_workingtree()
458
def create_workingtree(self, revision_id=None, from_branch=None,
459
accelerator_tree=None):
460
"""Create a working tree at this BzrDir.
462
:param revision_id: create it as of this revision id.
463
:param from_branch: override bzrdir branch (for lightweight checkouts)
464
:param accelerator_tree: A tree which can be used for retrieving file
465
contents more quickly than the revision tree, i.e. a workingtree.
466
The revision tree will be used for cases where accelerator_tree's
467
content is different.
469
raise NotImplementedError(self.create_workingtree)
471
def retire_bzrdir(self, limit=10000):
472
"""Permanently disable the bzrdir.
474
This is done by renaming it to give the user some ability to recover
475
if there was a problem.
477
This will have horrible consequences if anyone has anything locked or
479
:param limit: number of times to retry
484
to_path = '.bzr.retired.%d' % i
485
self.root_transport.rename('.bzr', to_path)
486
note("renamed %s to %s"
487
% (self.root_transport.abspath('.bzr'), to_path))
489
except (errors.TransportError, IOError, errors.PathError):
496
def destroy_workingtree(self):
497
"""Destroy the working tree at this BzrDir.
499
Formats that do not support this may raise UnsupportedOperation.
501
raise NotImplementedError(self.destroy_workingtree)
503
def destroy_workingtree_metadata(self):
504
"""Destroy the control files for the working tree at this BzrDir.
506
The contents of working tree files are not affected.
507
Formats that do not support this may raise UnsupportedOperation.
509
raise NotImplementedError(self.destroy_workingtree_metadata)
511
def find_repository(self):
512
"""Find the repository that should be used.
514
This does not require a branch as we use it to find the repo for
515
new branches as well as to hook existing branches up to their
519
return self.open_repository()
520
except errors.NoRepositoryPresent:
522
next_transport = self.root_transport.clone('..')
524
# find the next containing bzrdir
526
found_bzrdir = BzrDir.open_containing_from_transport(
528
except errors.NotBranchError:
530
raise errors.NoRepositoryPresent(self)
531
# does it have a repository ?
533
repository = found_bzrdir.open_repository()
534
except errors.NoRepositoryPresent:
535
next_transport = found_bzrdir.root_transport.clone('..')
536
if (found_bzrdir.root_transport.base == next_transport.base):
537
# top of the file system
541
if ((found_bzrdir.root_transport.base ==
542
self.root_transport.base) or repository.is_shared()):
545
raise errors.NoRepositoryPresent(self)
546
raise errors.NoRepositoryPresent(self)
548
def get_branch_reference(self):
549
"""Return the referenced URL for the branch in this bzrdir.
551
:raises NotBranchError: If there is no Branch.
552
:return: The URL the branch in this bzrdir references if it is a
553
reference branch, or None for regular branches.
557
def get_branch_transport(self, branch_format):
558
"""Get the transport for use by branch format in this BzrDir.
560
Note that bzr dirs that do not support format strings will raise
561
IncompatibleFormat if the branch format they are given has
562
a format string, and vice versa.
564
If branch_format is None, the transport is returned with no
565
checking. If it is not None, then the returned transport is
566
guaranteed to point to an existing directory ready for use.
568
raise NotImplementedError(self.get_branch_transport)
570
def get_repository_transport(self, repository_format):
571
"""Get the transport for use by repository format in this BzrDir.
573
Note that bzr dirs that do not support format strings will raise
574
IncompatibleFormat if the repository format they are given has
575
a format string, and vice versa.
577
If repository_format is None, the transport is returned with no
578
checking. If it is not None, then the returned transport is
579
guaranteed to point to an existing directory ready for use.
581
raise NotImplementedError(self.get_repository_transport)
583
def get_workingtree_transport(self, tree_format):
584
"""Get the transport for use by workingtree format in this BzrDir.
586
Note that bzr dirs that do not support format strings will raise
587
IncompatibleFormat if the workingtree format they are given has a
588
format string, and vice versa.
590
If workingtree_format is None, the transport is returned with no
591
checking. If it is not None, then the returned transport is
592
guaranteed to point to an existing directory ready for use.
594
raise NotImplementedError(self.get_workingtree_transport)
596
def __init__(self, _transport, _format):
597
"""Initialize a Bzr control dir object.
599
Only really common logic should reside here, concrete classes should be
600
made with varying behaviours.
602
:param _format: the format that is creating this BzrDir instance.
603
:param _transport: the transport this dir is based at.
605
self._format = _format
606
self.transport = _transport.clone('.bzr')
607
self.root_transport = _transport
609
def is_control_filename(self, filename):
610
"""True if filename is the name of a path which is reserved for bzrdir's.
612
:param filename: A filename within the root transport of this bzrdir.
614
This is true IF and ONLY IF the filename is part of the namespace reserved
615
for bzr control dirs. Currently this is the '.bzr' directory in the root
616
of the root_transport. it is expected that plugins will need to extend
617
this in the future - for instance to make bzr talk with svn working
620
# this might be better on the BzrDirFormat class because it refers to
621
# all the possible bzrdir disk formats.
622
# This method is tested via the workingtree is_control_filename tests-
623
# it was extracted from WorkingTree.is_control_filename. If the method's
624
# contract is extended beyond the current trivial implementation, please
625
# add new tests for it to the appropriate place.
626
return filename == '.bzr' or filename.startswith('.bzr/')
628
def needs_format_conversion(self, format=None):
629
"""Return true if this bzrdir needs convert_format run on it.
631
For instance, if the repository format is out of date but the
632
branch and working tree are not, this should return True.
634
:param format: Optional parameter indicating a specific desired
635
format we plan to arrive at.
637
raise NotImplementedError(self.needs_format_conversion)
640
def open_unsupported(base):
641
"""Open a branch which is not supported."""
642
return BzrDir.open(base, _unsupported=True)
645
def open(base, _unsupported=False, possible_transports=None):
646
"""Open an existing bzrdir, rooted at 'base' (url).
648
:param _unsupported: a private parameter to the BzrDir class.
650
t = get_transport(base, possible_transports=possible_transports)
651
return BzrDir.open_from_transport(t, _unsupported=_unsupported)
654
def open_from_transport(transport, _unsupported=False,
655
_server_formats=True):
656
"""Open a bzrdir within a particular directory.
658
:param transport: Transport containing the bzrdir.
659
:param _unsupported: private.
661
base = transport.base
663
def find_format(transport):
664
return transport, BzrDirFormat.find_format(
665
transport, _server_formats=_server_formats)
667
def redirected(transport, e, redirection_notice):
668
qualified_source = e.get_source_url()
669
relpath = transport.relpath(qualified_source)
670
if not e.target.endswith(relpath):
671
# Not redirected to a branch-format, not a branch
672
raise errors.NotBranchError(path=e.target)
673
target = e.target[:-len(relpath)]
674
note('%s is%s redirected to %s',
675
transport.base, e.permanently, target)
676
# Let's try with a new transport
677
# FIXME: If 'transport' has a qualifier, this should
678
# be applied again to the new transport *iff* the
679
# schemes used are the same. Uncomment this code
680
# once the function (and tests) exist.
682
#target = urlutils.copy_url_qualifiers(original, target)
683
return get_transport(target)
686
transport, format = do_catching_redirections(find_format,
689
except errors.TooManyRedirections:
690
raise errors.NotBranchError(base)
692
BzrDir._check_supported(format, _unsupported)
693
return format.open(transport, _found=True)
695
def open_branch(self, unsupported=False):
696
"""Open the branch object at this BzrDir if one is present.
698
If unsupported is True, then no longer supported branch formats can
701
TODO: static convenience version of this?
703
raise NotImplementedError(self.open_branch)
706
def open_containing(url, possible_transports=None):
707
"""Open an existing branch which contains url.
709
:param url: url to search from.
710
See open_containing_from_transport for more detail.
712
transport = get_transport(url, possible_transports)
713
return BzrDir.open_containing_from_transport(transport)
716
def open_containing_from_transport(a_transport):
717
"""Open an existing branch which contains a_transport.base.
719
This probes for a branch at a_transport, and searches upwards from there.
721
Basically we keep looking up until we find the control directory or
722
run into the root. If there isn't one, raises NotBranchError.
723
If there is one and it is either an unrecognised format or an unsupported
724
format, UnknownFormatError or UnsupportedFormatError are raised.
725
If there is one, it is returned, along with the unused portion of url.
727
:return: The BzrDir that contains the path, and a Unicode path
728
for the rest of the URL.
730
# this gets the normalised url back. I.e. '.' -> the full path.
731
url = a_transport.base
734
result = BzrDir.open_from_transport(a_transport)
735
return result, urlutils.unescape(a_transport.relpath(url))
736
except errors.NotBranchError, e:
739
new_t = a_transport.clone('..')
740
except errors.InvalidURLJoin:
741
# reached the root, whatever that may be
742
raise errors.NotBranchError(path=url)
743
if new_t.base == a_transport.base:
744
# reached the root, whatever that may be
745
raise errors.NotBranchError(path=url)
748
def _get_tree_branch(self):
749
"""Return the branch and tree, if any, for this bzrdir.
751
Return None for tree if not present or inaccessible.
752
Raise NotBranchError if no branch is present.
753
:return: (tree, branch)
756
tree = self.open_workingtree()
757
except (errors.NoWorkingTree, errors.NotLocalUrl):
759
branch = self.open_branch()
765
def open_tree_or_branch(klass, location):
766
"""Return the branch and working tree at a location.
768
If there is no tree at the location, tree will be None.
769
If there is no branch at the location, an exception will be
771
:return: (tree, branch)
773
bzrdir = klass.open(location)
774
return bzrdir._get_tree_branch()
777
def open_containing_tree_or_branch(klass, location):
778
"""Return the branch and working tree contained by a location.
780
Returns (tree, branch, relpath).
781
If there is no tree at containing the location, tree will be None.
782
If there is no branch containing the location, an exception will be
784
relpath is the portion of the path that is contained by the branch.
786
bzrdir, relpath = klass.open_containing(location)
787
tree, branch = bzrdir._get_tree_branch()
788
return tree, branch, relpath
790
def open_repository(self, _unsupported=False):
791
"""Open the repository object at this BzrDir if one is present.
793
This will not follow the Branch object pointer - it's strictly a direct
794
open facility. Most client code should use open_branch().repository to
797
:param _unsupported: a private parameter, not part of the api.
798
TODO: static convenience version of this?
800
raise NotImplementedError(self.open_repository)
802
def open_workingtree(self, _unsupported=False,
803
recommend_upgrade=True, from_branch=None):
804
"""Open the workingtree object at this BzrDir if one is present.
806
:param recommend_upgrade: Optional keyword parameter, when True (the
807
default), emit through the ui module a recommendation that the user
808
upgrade the working tree when the workingtree being opened is old
809
(but still fully supported).
810
:param from_branch: override bzrdir branch (for lightweight checkouts)
812
raise NotImplementedError(self.open_workingtree)
814
def has_branch(self):
815
"""Tell if this bzrdir contains a branch.
817
Note: if you're going to open the branch, you should just go ahead
818
and try, and not ask permission first. (This method just opens the
819
branch and discards it, and that's somewhat expensive.)
824
except errors.NotBranchError:
827
def has_workingtree(self):
828
"""Tell if this bzrdir contains a working tree.
830
This will still raise an exception if the bzrdir has a workingtree that
831
is remote & inaccessible.
833
Note: if you're going to open the working tree, you should just go ahead
834
and try, and not ask permission first. (This method just opens the
835
workingtree and discards it, and that's somewhat expensive.)
838
self.open_workingtree(recommend_upgrade=False)
840
except errors.NoWorkingTree:
843
def _cloning_metadir(self):
844
"""Produce a metadir suitable for cloning with."""
845
result_format = self._format.__class__()
848
branch = self.open_branch()
849
source_repository = branch.repository
850
except errors.NotBranchError:
852
source_repository = self.open_repository()
853
except errors.NoRepositoryPresent:
854
source_repository = None
856
# XXX TODO: This isinstance is here because we have not implemented
857
# the fix recommended in bug # 103195 - to delegate this choice the
859
repo_format = source_repository._format
860
if not isinstance(repo_format, remote.RemoteRepositoryFormat):
861
result_format.repository_format = repo_format
863
# TODO: Couldn't we just probe for the format in these cases,
864
# rather than opening the whole tree? It would be a little
865
# faster. mbp 20070401
866
tree = self.open_workingtree(recommend_upgrade=False)
867
except (errors.NoWorkingTree, errors.NotLocalUrl):
868
result_format.workingtree_format = None
870
result_format.workingtree_format = tree._format.__class__()
871
return result_format, source_repository
873
def cloning_metadir(self):
874
"""Produce a metadir suitable for cloning or sprouting with.
876
These operations may produce workingtrees (yes, even though they're
877
"cloning" something that doesn't have a tree), so a viable workingtree
878
format must be selected.
880
format, repository = self._cloning_metadir()
881
if format._workingtree_format is None:
882
if repository is None:
884
tree_format = repository._format._matchingbzrdir.workingtree_format
885
format.workingtree_format = tree_format.__class__()
888
def checkout_metadir(self):
889
return self.cloning_metadir()
891
def sprout(self, url, revision_id=None, force_new_repo=False,
892
recurse='down', possible_transports=None,
893
accelerator_tree=None):
894
"""Create a copy of this bzrdir prepared for use as a new line of
897
If url's last component does not exist, it will be created.
899
Attributes related to the identity of the source branch like
900
branch nickname will be cleaned, a working tree is created
901
whether one existed before or not; and a local branch is always
904
if revision_id is not None, then the clone operation may tune
905
itself to download less data.
906
:param accelerator_tree: A tree which can be used for retrieving file
907
contents more quickly than the revision tree, i.e. a workingtree.
908
The revision tree will be used for cases where accelerator_tree's
909
content is different.
911
target_transport = get_transport(url, possible_transports)
912
target_transport.ensure_base()
913
cloning_format = self.cloning_metadir()
914
result = cloning_format.initialize_on_transport(target_transport)
916
source_branch = self.open_branch()
917
source_repository = source_branch.repository
918
except errors.NotBranchError:
921
source_repository = self.open_repository()
922
except errors.NoRepositoryPresent:
923
source_repository = None
928
result_repo = result.find_repository()
929
except errors.NoRepositoryPresent:
931
if source_repository is None and result_repo is not None:
933
elif source_repository is None and result_repo is None:
934
# no repo available, make a new one
935
result.create_repository()
936
elif source_repository is not None and result_repo is None:
937
# have source, and want to make a new target repo
938
result_repo = source_repository.sprout(result,
939
revision_id=revision_id)
941
# fetch needed content into target.
942
if source_repository is not None:
944
# source_repository.copy_content_into(result_repo,
945
# revision_id=revision_id)
946
# so we can override the copy method
947
result_repo.fetch(source_repository, revision_id=revision_id)
948
if source_branch is not None:
949
source_branch.sprout(result, revision_id=revision_id)
951
result.create_branch()
952
if isinstance(target_transport, LocalTransport) and (
953
result_repo is None or result_repo.make_working_trees()):
954
wt = result.create_workingtree(accelerator_tree=accelerator_tree)
957
if wt.path2id('') is None:
959
wt.set_root_id(self.open_workingtree.get_root_id())
960
except errors.NoWorkingTree:
966
if recurse == 'down':
968
basis = wt.basis_tree()
970
subtrees = basis.iter_references()
971
recurse_branch = wt.branch
972
elif source_branch is not None:
973
basis = source_branch.basis_tree()
975
subtrees = basis.iter_references()
976
recurse_branch = source_branch
981
for path, file_id in subtrees:
982
target = urlutils.join(url, urlutils.escape(path))
983
sublocation = source_branch.reference_parent(file_id, path)
984
sublocation.bzrdir.sprout(target,
985
basis.get_reference_revision(file_id, path),
986
force_new_repo=force_new_repo, recurse=recurse)
988
if basis is not None:
993
class BzrDirPreSplitOut(BzrDir):
994
"""A common class for the all-in-one formats."""
996
def __init__(self, _transport, _format):
997
"""See BzrDir.__init__."""
998
super(BzrDirPreSplitOut, self).__init__(_transport, _format)
999
assert self._format._lock_class == lockable_files.TransportLock
1000
assert self._format._lock_file_name == 'branch-lock'
1001
self._control_files = lockable_files.LockableFiles(
1002
self.get_branch_transport(None),
1003
self._format._lock_file_name,
1004
self._format._lock_class)
1006
def break_lock(self):
1007
"""Pre-splitout bzrdirs do not suffer from stale locks."""
1008
raise NotImplementedError(self.break_lock)
1010
def clone(self, url, revision_id=None, force_new_repo=False):
1011
"""See BzrDir.clone()."""
1012
from bzrlib.workingtree import WorkingTreeFormat2
1013
self._make_tail(url)
1014
result = self._format._initialize_for_clone(url)
1015
self.open_repository().clone(result, revision_id=revision_id)
1016
from_branch = self.open_branch()
1017
from_branch.clone(result, revision_id=revision_id)
1019
self.open_workingtree().clone(result)
1020
except errors.NotLocalUrl:
1021
# make a new one, this format always has to have one.
1023
WorkingTreeFormat2().initialize(result)
1024
except errors.NotLocalUrl:
1025
# but we cannot do it for remote trees.
1026
to_branch = result.open_branch()
1027
WorkingTreeFormat2().stub_initialize_remote(to_branch.control_files)
1030
def create_branch(self):
1031
"""See BzrDir.create_branch."""
1032
return self.open_branch()
1034
def destroy_branch(self):
1035
"""See BzrDir.destroy_branch."""
1036
raise errors.UnsupportedOperation(self.destroy_branch, self)
1038
def create_repository(self, shared=False):
1039
"""See BzrDir.create_repository."""
1041
raise errors.IncompatibleFormat('shared repository', self._format)
1042
return self.open_repository()
1044
def destroy_repository(self):
1045
"""See BzrDir.destroy_repository."""
1046
raise errors.UnsupportedOperation(self.destroy_repository, self)
1048
def create_workingtree(self, revision_id=None, from_branch=None,
1049
accelerator_tree=None):
1050
"""See BzrDir.create_workingtree."""
1051
# this looks buggy but is not -really-
1052
# because this format creates the workingtree when the bzrdir is
1054
# clone and sprout will have set the revision_id
1055
# and that will have set it for us, its only
1056
# specific uses of create_workingtree in isolation
1057
# that can do wonky stuff here, and that only
1058
# happens for creating checkouts, which cannot be
1059
# done on this format anyway. So - acceptable wart.
1060
result = self.open_workingtree(recommend_upgrade=False)
1061
if revision_id is not None:
1062
if revision_id == _mod_revision.NULL_REVISION:
1063
result.set_parent_ids([])
1065
result.set_parent_ids([revision_id])
1068
def destroy_workingtree(self):
1069
"""See BzrDir.destroy_workingtree."""
1070
raise errors.UnsupportedOperation(self.destroy_workingtree, self)
1072
def destroy_workingtree_metadata(self):
1073
"""See BzrDir.destroy_workingtree_metadata."""
1074
raise errors.UnsupportedOperation(self.destroy_workingtree_metadata,
1077
def get_branch_transport(self, branch_format):
1078
"""See BzrDir.get_branch_transport()."""
1079
if branch_format is None:
1080
return self.transport
1082
branch_format.get_format_string()
1083
except NotImplementedError:
1084
return self.transport
1085
raise errors.IncompatibleFormat(branch_format, self._format)
1087
def get_repository_transport(self, repository_format):
1088
"""See BzrDir.get_repository_transport()."""
1089
if repository_format is None:
1090
return self.transport
1092
repository_format.get_format_string()
1093
except NotImplementedError:
1094
return self.transport
1095
raise errors.IncompatibleFormat(repository_format, self._format)
1097
def get_workingtree_transport(self, workingtree_format):
1098
"""See BzrDir.get_workingtree_transport()."""
1099
if workingtree_format is None:
1100
return self.transport
1102
workingtree_format.get_format_string()
1103
except NotImplementedError:
1104
return self.transport
1105
raise errors.IncompatibleFormat(workingtree_format, self._format)
1107
def needs_format_conversion(self, format=None):
1108
"""See BzrDir.needs_format_conversion()."""
1109
# if the format is not the same as the system default,
1110
# an upgrade is needed.
1112
format = BzrDirFormat.get_default_format()
1113
return not isinstance(self._format, format.__class__)
1115
def open_branch(self, unsupported=False):
1116
"""See BzrDir.open_branch."""
1117
from bzrlib.branch import BzrBranchFormat4
1118
format = BzrBranchFormat4()
1119
self._check_supported(format, unsupported)
1120
return format.open(self, _found=True)
1122
def sprout(self, url, revision_id=None, force_new_repo=False,
1123
possible_transports=None, accelerator_tree=None):
1124
"""See BzrDir.sprout()."""
1125
from bzrlib.workingtree import WorkingTreeFormat2
1126
self._make_tail(url)
1127
result = self._format._initialize_for_clone(url)
1129
self.open_repository().clone(result, revision_id=revision_id)
1130
except errors.NoRepositoryPresent:
1133
self.open_branch().sprout(result, revision_id=revision_id)
1134
except errors.NotBranchError:
1136
# we always want a working tree
1137
WorkingTreeFormat2().initialize(result,
1138
accelerator_tree=accelerator_tree)
1142
class BzrDir4(BzrDirPreSplitOut):
1143
"""A .bzr version 4 control object.
1145
This is a deprecated format and may be removed after sept 2006.
1148
def create_repository(self, shared=False):
1149
"""See BzrDir.create_repository."""
1150
return self._format.repository_format.initialize(self, shared)
1152
def needs_format_conversion(self, format=None):
1153
"""Format 4 dirs are always in need of conversion."""
1156
def open_repository(self):
1157
"""See BzrDir.open_repository."""
1158
from bzrlib.repofmt.weaverepo import RepositoryFormat4
1159
return RepositoryFormat4().open(self, _found=True)
1162
class BzrDir5(BzrDirPreSplitOut):
1163
"""A .bzr version 5 control object.
1165
This is a deprecated format and may be removed after sept 2006.
1168
def open_repository(self):
1169
"""See BzrDir.open_repository."""
1170
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1171
return RepositoryFormat5().open(self, _found=True)
1173
def open_workingtree(self, _unsupported=False,
1174
recommend_upgrade=True):
1175
"""See BzrDir.create_workingtree."""
1176
from bzrlib.workingtree import WorkingTreeFormat2
1177
wt_format = WorkingTreeFormat2()
1178
# we don't warn here about upgrades; that ought to be handled for the
1180
return wt_format.open(self, _found=True)
1183
class BzrDir6(BzrDirPreSplitOut):
1184
"""A .bzr version 6 control object.
1186
This is a deprecated format and may be removed after sept 2006.
1189
def open_repository(self):
1190
"""See BzrDir.open_repository."""
1191
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1192
return RepositoryFormat6().open(self, _found=True)
1194
def open_workingtree(self, _unsupported=False,
1195
recommend_upgrade=True):
1196
"""See BzrDir.create_workingtree."""
1197
# we don't warn here about upgrades; that ought to be handled for the
1199
from bzrlib.workingtree import WorkingTreeFormat2
1200
return WorkingTreeFormat2().open(self, _found=True)
1203
class BzrDirMeta1(BzrDir):
1204
"""A .bzr meta version 1 control object.
1206
This is the first control object where the
1207
individual aspects are really split out: there are separate repository,
1208
workingtree and branch subdirectories and any subset of the three can be
1209
present within a BzrDir.
1212
def can_convert_format(self):
1213
"""See BzrDir.can_convert_format()."""
1216
def create_branch(self):
1217
"""See BzrDir.create_branch."""
1218
return self._format.get_branch_format().initialize(self)
1220
def destroy_branch(self):
1221
"""See BzrDir.create_branch."""
1222
self.transport.delete_tree('branch')
1224
def create_repository(self, shared=False):
1225
"""See BzrDir.create_repository."""
1226
return self._format.repository_format.initialize(self, shared)
1228
def destroy_repository(self):
1229
"""See BzrDir.destroy_repository."""
1230
self.transport.delete_tree('repository')
1232
def create_workingtree(self, revision_id=None, from_branch=None,
1233
accelerator_tree=None):
1234
"""See BzrDir.create_workingtree."""
1235
return self._format.workingtree_format.initialize(
1236
self, revision_id, from_branch=from_branch,
1237
accelerator_tree=accelerator_tree)
1239
def destroy_workingtree(self):
1240
"""See BzrDir.destroy_workingtree."""
1241
wt = self.open_workingtree(recommend_upgrade=False)
1242
repository = wt.branch.repository
1243
empty = repository.revision_tree(_mod_revision.NULL_REVISION)
1244
wt.revert(old_tree=empty)
1245
self.destroy_workingtree_metadata()
1247
def destroy_workingtree_metadata(self):
1248
self.transport.delete_tree('checkout')
1250
def find_branch_format(self):
1251
"""Find the branch 'format' for this bzrdir.
1253
This might be a synthetic object for e.g. RemoteBranch and SVN.
1255
from bzrlib.branch import BranchFormat
1256
return BranchFormat.find_format(self)
1258
def _get_mkdir_mode(self):
1259
"""Figure out the mode to use when creating a bzrdir subdir."""
1260
temp_control = lockable_files.LockableFiles(self.transport, '',
1261
lockable_files.TransportLock)
1262
return temp_control._dir_mode
1264
def get_branch_reference(self):
1265
"""See BzrDir.get_branch_reference()."""
1266
from bzrlib.branch import BranchFormat
1267
format = BranchFormat.find_format(self)
1268
return format.get_reference(self)
1270
def get_branch_transport(self, branch_format):
1271
"""See BzrDir.get_branch_transport()."""
1272
if branch_format is None:
1273
return self.transport.clone('branch')
1275
branch_format.get_format_string()
1276
except NotImplementedError:
1277
raise errors.IncompatibleFormat(branch_format, self._format)
1279
self.transport.mkdir('branch', mode=self._get_mkdir_mode())
1280
except errors.FileExists:
1282
return self.transport.clone('branch')
1284
def get_repository_transport(self, repository_format):
1285
"""See BzrDir.get_repository_transport()."""
1286
if repository_format is None:
1287
return self.transport.clone('repository')
1289
repository_format.get_format_string()
1290
except NotImplementedError:
1291
raise errors.IncompatibleFormat(repository_format, self._format)
1293
self.transport.mkdir('repository', mode=self._get_mkdir_mode())
1294
except errors.FileExists:
1296
return self.transport.clone('repository')
1298
def get_workingtree_transport(self, workingtree_format):
1299
"""See BzrDir.get_workingtree_transport()."""
1300
if workingtree_format is None:
1301
return self.transport.clone('checkout')
1303
workingtree_format.get_format_string()
1304
except NotImplementedError:
1305
raise errors.IncompatibleFormat(workingtree_format, self._format)
1307
self.transport.mkdir('checkout', mode=self._get_mkdir_mode())
1308
except errors.FileExists:
1310
return self.transport.clone('checkout')
1312
def needs_format_conversion(self, format=None):
1313
"""See BzrDir.needs_format_conversion()."""
1315
format = BzrDirFormat.get_default_format()
1316
if not isinstance(self._format, format.__class__):
1317
# it is not a meta dir format, conversion is needed.
1319
# we might want to push this down to the repository?
1321
if not isinstance(self.open_repository()._format,
1322
format.repository_format.__class__):
1323
# the repository needs an upgrade.
1325
except errors.NoRepositoryPresent:
1328
if not isinstance(self.open_branch()._format,
1329
format.get_branch_format().__class__):
1330
# the branch needs an upgrade.
1332
except errors.NotBranchError:
1335
my_wt = self.open_workingtree(recommend_upgrade=False)
1336
if not isinstance(my_wt._format,
1337
format.workingtree_format.__class__):
1338
# the workingtree needs an upgrade.
1340
except (errors.NoWorkingTree, errors.NotLocalUrl):
1344
def open_branch(self, unsupported=False):
1345
"""See BzrDir.open_branch."""
1346
format = self.find_branch_format()
1347
self._check_supported(format, unsupported)
1348
return format.open(self, _found=True)
1350
def open_repository(self, unsupported=False):
1351
"""See BzrDir.open_repository."""
1352
from bzrlib.repository import RepositoryFormat
1353
format = RepositoryFormat.find_format(self)
1354
self._check_supported(format, unsupported)
1355
return format.open(self, _found=True)
1357
def open_workingtree(self, unsupported=False,
1358
recommend_upgrade=True):
1359
"""See BzrDir.open_workingtree."""
1360
from bzrlib.workingtree import WorkingTreeFormat
1361
format = WorkingTreeFormat.find_format(self)
1362
self._check_supported(format, unsupported,
1364
basedir=self.root_transport.base)
1365
return format.open(self, _found=True)
1368
class BzrDirFormat(object):
1369
"""An encapsulation of the initialization and open routines for a format.
1371
Formats provide three things:
1372
* An initialization routine,
1376
Formats are placed in a dict by their format string for reference
1377
during bzrdir opening. These should be subclasses of BzrDirFormat
1380
Once a format is deprecated, just deprecate the initialize and open
1381
methods on the format class. Do not deprecate the object, as the
1382
object will be created every system load.
1385
_default_format = None
1386
"""The default format used for new .bzr dirs."""
1389
"""The known formats."""
1391
_control_formats = []
1392
"""The registered control formats - .bzr, ....
1394
This is a list of BzrDirFormat objects.
1397
_control_server_formats = []
1398
"""The registered control server formats, e.g. RemoteBzrDirs.
1400
This is a list of BzrDirFormat objects.
1403
_lock_file_name = 'branch-lock'
1405
# _lock_class must be set in subclasses to the lock type, typ.
1406
# TransportLock or LockDir
1409
def find_format(klass, transport, _server_formats=True):
1410
"""Return the format present at transport."""
1412
formats = klass._control_server_formats + klass._control_formats
1414
formats = klass._control_formats
1415
for format in formats:
1417
return format.probe_transport(transport)
1418
except errors.NotBranchError:
1419
# this format does not find a control dir here.
1421
raise errors.NotBranchError(path=transport.base)
1424
def probe_transport(klass, transport):
1425
"""Return the .bzrdir style format present in a directory."""
1427
format_string = transport.get(".bzr/branch-format").read()
1428
except errors.NoSuchFile:
1429
raise errors.NotBranchError(path=transport.base)
1432
return klass._formats[format_string]
1434
raise errors.UnknownFormatError(format=format_string)
1437
def get_default_format(klass):
1438
"""Return the current default format."""
1439
return klass._default_format
1441
def get_format_string(self):
1442
"""Return the ASCII format string that identifies this format."""
1443
raise NotImplementedError(self.get_format_string)
1445
def get_format_description(self):
1446
"""Return the short description for this format."""
1447
raise NotImplementedError(self.get_format_description)
1449
def get_converter(self, format=None):
1450
"""Return the converter to use to convert bzrdirs needing converts.
1452
This returns a bzrlib.bzrdir.Converter object.
1454
This should return the best upgrader to step this format towards the
1455
current default format. In the case of plugins we can/should provide
1456
some means for them to extend the range of returnable converters.
1458
:param format: Optional format to override the default format of the
1461
raise NotImplementedError(self.get_converter)
1463
def initialize(self, url, possible_transports=None):
1464
"""Create a bzr control dir at this url and return an opened copy.
1466
Subclasses should typically override initialize_on_transport
1467
instead of this method.
1469
return self.initialize_on_transport(get_transport(url,
1470
possible_transports))
1472
def initialize_on_transport(self, transport):
1473
"""Initialize a new bzrdir in the base directory of a Transport."""
1474
# Since we don't have a .bzr directory, inherit the
1475
# mode from the root directory
1476
temp_control = lockable_files.LockableFiles(transport,
1477
'', lockable_files.TransportLock)
1478
temp_control._transport.mkdir('.bzr',
1479
# FIXME: RBC 20060121 don't peek under
1481
mode=temp_control._dir_mode)
1482
if sys.platform == 'win32' and isinstance(transport, LocalTransport):
1483
win32utils.set_file_attr_hidden(transport._abspath('.bzr'))
1484
file_mode = temp_control._file_mode
1486
mutter('created control directory in ' + transport.base)
1487
control = transport.clone('.bzr')
1488
utf8_files = [('README',
1489
"This is a Bazaar-NG control directory.\n"
1490
"Do not change any files in this directory.\n"),
1491
('branch-format', self.get_format_string()),
1493
# NB: no need to escape relative paths that are url safe.
1494
control_files = lockable_files.LockableFiles(control,
1495
self._lock_file_name, self._lock_class)
1496
control_files.create_lock()
1497
control_files.lock_write()
1499
for file, content in utf8_files:
1500
control_files.put_utf8(file, content)
1502
control_files.unlock()
1503
return self.open(transport, _found=True)
1505
def is_supported(self):
1506
"""Is this format supported?
1508
Supported formats must be initializable and openable.
1509
Unsupported formats may not support initialization or committing or
1510
some other features depending on the reason for not being supported.
1514
def same_model(self, target_format):
1515
return (self.repository_format.rich_root_data ==
1516
target_format.rich_root_data)
1519
def known_formats(klass):
1520
"""Return all the known formats.
1522
Concrete formats should override _known_formats.
1524
# There is double indirection here to make sure that control
1525
# formats used by more than one dir format will only be probed
1526
# once. This can otherwise be quite expensive for remote connections.
1528
for format in klass._control_formats:
1529
result.update(format._known_formats())
1533
def _known_formats(klass):
1534
"""Return the known format instances for this control format."""
1535
return set(klass._formats.values())
1537
def open(self, transport, _found=False):
1538
"""Return an instance of this format for the dir transport points at.
1540
_found is a private parameter, do not use it.
1543
found_format = BzrDirFormat.find_format(transport)
1544
if not isinstance(found_format, self.__class__):
1545
raise AssertionError("%s was asked to open %s, but it seems to need "
1547
% (self, transport, found_format))
1548
return self._open(transport)
1550
def _open(self, transport):
1551
"""Template method helper for opening BzrDirectories.
1553
This performs the actual open and any additional logic or parameter
1556
raise NotImplementedError(self._open)
1559
def register_format(klass, format):
1560
klass._formats[format.get_format_string()] = format
1563
def register_control_format(klass, format):
1564
"""Register a format that does not use '.bzr' for its control dir.
1566
TODO: This should be pulled up into a 'ControlDirFormat' base class
1567
which BzrDirFormat can inherit from, and renamed to register_format
1568
there. It has been done without that for now for simplicity of
1571
klass._control_formats.append(format)
1574
def register_control_server_format(klass, format):
1575
"""Register a control format for client-server environments.
1577
These formats will be tried before ones registered with
1578
register_control_format. This gives implementations that decide to the
1579
chance to grab it before anything looks at the contents of the format
1582
klass._control_server_formats.append(format)
1585
@symbol_versioning.deprecated_method(symbol_versioning.zero_fourteen)
1586
def set_default_format(klass, format):
1587
klass._set_default_format(format)
1590
def _set_default_format(klass, format):
1591
"""Set default format (for testing behavior of defaults only)"""
1592
klass._default_format = format
1596
return self.get_format_string().rstrip()
1599
def unregister_format(klass, format):
1600
assert klass._formats[format.get_format_string()] is format
1601
del klass._formats[format.get_format_string()]
1604
def unregister_control_format(klass, format):
1605
klass._control_formats.remove(format)
1608
class BzrDirFormat4(BzrDirFormat):
1609
"""Bzr dir format 4.
1611
This format is a combined format for working tree, branch and repository.
1613
- Format 1 working trees [always]
1614
- Format 4 branches [always]
1615
- Format 4 repositories [always]
1617
This format is deprecated: it indexes texts using a text it which is
1618
removed in format 5; write support for this format has been removed.
1621
_lock_class = lockable_files.TransportLock
1623
def get_format_string(self):
1624
"""See BzrDirFormat.get_format_string()."""
1625
return "Bazaar-NG branch, format 0.0.4\n"
1627
def get_format_description(self):
1628
"""See BzrDirFormat.get_format_description()."""
1629
return "All-in-one format 4"
1631
def get_converter(self, format=None):
1632
"""See BzrDirFormat.get_converter()."""
1633
# there is one and only one upgrade path here.
1634
return ConvertBzrDir4To5()
1636
def initialize_on_transport(self, transport):
1637
"""Format 4 branches cannot be created."""
1638
raise errors.UninitializableFormat(self)
1640
def is_supported(self):
1641
"""Format 4 is not supported.
1643
It is not supported because the model changed from 4 to 5 and the
1644
conversion logic is expensive - so doing it on the fly was not
1649
def _open(self, transport):
1650
"""See BzrDirFormat._open."""
1651
return BzrDir4(transport, self)
1653
def __return_repository_format(self):
1654
"""Circular import protection."""
1655
from bzrlib.repofmt.weaverepo import RepositoryFormat4
1656
return RepositoryFormat4()
1657
repository_format = property(__return_repository_format)
1660
class BzrDirFormat5(BzrDirFormat):
1661
"""Bzr control format 5.
1663
This format is a combined format for working tree, branch and repository.
1665
- Format 2 working trees [always]
1666
- Format 4 branches [always]
1667
- Format 5 repositories [always]
1668
Unhashed stores in the repository.
1671
_lock_class = lockable_files.TransportLock
1673
def get_format_string(self):
1674
"""See BzrDirFormat.get_format_string()."""
1675
return "Bazaar-NG branch, format 5\n"
1677
def get_format_description(self):
1678
"""See BzrDirFormat.get_format_description()."""
1679
return "All-in-one format 5"
1681
def get_converter(self, format=None):
1682
"""See BzrDirFormat.get_converter()."""
1683
# there is one and only one upgrade path here.
1684
return ConvertBzrDir5To6()
1686
def _initialize_for_clone(self, url):
1687
return self.initialize_on_transport(get_transport(url), _cloning=True)
1689
def initialize_on_transport(self, transport, _cloning=False):
1690
"""Format 5 dirs always have working tree, branch and repository.
1692
Except when they are being cloned.
1694
from bzrlib.branch import BzrBranchFormat4
1695
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1696
from bzrlib.workingtree import WorkingTreeFormat2
1697
result = (super(BzrDirFormat5, self).initialize_on_transport(transport))
1698
RepositoryFormat5().initialize(result, _internal=True)
1700
branch = BzrBranchFormat4().initialize(result)
1702
WorkingTreeFormat2().initialize(result)
1703
except errors.NotLocalUrl:
1704
# Even though we can't access the working tree, we need to
1705
# create its control files.
1706
WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
1709
def _open(self, transport):
1710
"""See BzrDirFormat._open."""
1711
return BzrDir5(transport, self)
1713
def __return_repository_format(self):
1714
"""Circular import protection."""
1715
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1716
return RepositoryFormat5()
1717
repository_format = property(__return_repository_format)
1720
class BzrDirFormat6(BzrDirFormat):
1721
"""Bzr control format 6.
1723
This format is a combined format for working tree, branch and repository.
1725
- Format 2 working trees [always]
1726
- Format 4 branches [always]
1727
- Format 6 repositories [always]
1730
_lock_class = lockable_files.TransportLock
1732
def get_format_string(self):
1733
"""See BzrDirFormat.get_format_string()."""
1734
return "Bazaar-NG branch, format 6\n"
1736
def get_format_description(self):
1737
"""See BzrDirFormat.get_format_description()."""
1738
return "All-in-one format 6"
1740
def get_converter(self, format=None):
1741
"""See BzrDirFormat.get_converter()."""
1742
# there is one and only one upgrade path here.
1743
return ConvertBzrDir6ToMeta()
1745
def _initialize_for_clone(self, url):
1746
return self.initialize_on_transport(get_transport(url), _cloning=True)
1748
def initialize_on_transport(self, transport, _cloning=False):
1749
"""Format 6 dirs always have working tree, branch and repository.
1751
Except when they are being cloned.
1753
from bzrlib.branch import BzrBranchFormat4
1754
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1755
from bzrlib.workingtree import WorkingTreeFormat2
1756
result = super(BzrDirFormat6, self).initialize_on_transport(transport)
1757
RepositoryFormat6().initialize(result, _internal=True)
1759
branch = BzrBranchFormat4().initialize(result)
1761
WorkingTreeFormat2().initialize(result)
1762
except errors.NotLocalUrl:
1763
# Even though we can't access the working tree, we need to
1764
# create its control files.
1765
WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
1768
def _open(self, transport):
1769
"""See BzrDirFormat._open."""
1770
return BzrDir6(transport, self)
1772
def __return_repository_format(self):
1773
"""Circular import protection."""
1774
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1775
return RepositoryFormat6()
1776
repository_format = property(__return_repository_format)
1779
class BzrDirMetaFormat1(BzrDirFormat):
1780
"""Bzr meta control format 1
1782
This is the first format with split out working tree, branch and repository
1785
- Format 3 working trees [optional]
1786
- Format 5 branches [optional]
1787
- Format 7 repositories [optional]
1790
_lock_class = lockdir.LockDir
1793
self._workingtree_format = None
1794
self._branch_format = None
1796
def __eq__(self, other):
1797
if other.__class__ is not self.__class__:
1799
if other.repository_format != self.repository_format:
1801
if other.workingtree_format != self.workingtree_format:
1805
def __ne__(self, other):
1806
return not self == other
1808
def get_branch_format(self):
1809
if self._branch_format is None:
1810
from bzrlib.branch import BranchFormat
1811
self._branch_format = BranchFormat.get_default_format()
1812
return self._branch_format
1814
def set_branch_format(self, format):
1815
self._branch_format = format
1817
def get_converter(self, format=None):
1818
"""See BzrDirFormat.get_converter()."""
1820
format = BzrDirFormat.get_default_format()
1821
if not isinstance(self, format.__class__):
1822
# converting away from metadir is not implemented
1823
raise NotImplementedError(self.get_converter)
1824
return ConvertMetaToMeta(format)
1826
def get_format_string(self):
1827
"""See BzrDirFormat.get_format_string()."""
1828
return "Bazaar-NG meta directory, format 1\n"
1830
def get_format_description(self):
1831
"""See BzrDirFormat.get_format_description()."""
1832
return "Meta directory format 1"
1834
def _open(self, transport):
1835
"""See BzrDirFormat._open."""
1836
return BzrDirMeta1(transport, self)
1838
def __return_repository_format(self):
1839
"""Circular import protection."""
1840
if getattr(self, '_repository_format', None):
1841
return self._repository_format
1842
from bzrlib.repository import RepositoryFormat
1843
return RepositoryFormat.get_default_format()
1845
def __set_repository_format(self, value):
1846
"""Allow changing the repository format for metadir formats."""
1847
self._repository_format = value
1849
repository_format = property(__return_repository_format, __set_repository_format)
1851
def __get_workingtree_format(self):
1852
if self._workingtree_format is None:
1853
from bzrlib.workingtree import WorkingTreeFormat
1854
self._workingtree_format = WorkingTreeFormat.get_default_format()
1855
return self._workingtree_format
1857
def __set_workingtree_format(self, wt_format):
1858
self._workingtree_format = wt_format
1860
workingtree_format = property(__get_workingtree_format,
1861
__set_workingtree_format)
1864
# Register bzr control format
1865
BzrDirFormat.register_control_format(BzrDirFormat)
1867
# Register bzr formats
1868
BzrDirFormat.register_format(BzrDirFormat4())
1869
BzrDirFormat.register_format(BzrDirFormat5())
1870
BzrDirFormat.register_format(BzrDirFormat6())
1871
__default_format = BzrDirMetaFormat1()
1872
BzrDirFormat.register_format(__default_format)
1873
BzrDirFormat._default_format = __default_format
1876
class Converter(object):
1877
"""Converts a disk format object from one format to another."""
1879
def convert(self, to_convert, pb):
1880
"""Perform the conversion of to_convert, giving feedback via pb.
1882
:param to_convert: The disk object to convert.
1883
:param pb: a progress bar to use for progress information.
1886
def step(self, message):
1887
"""Update the pb by a step."""
1889
self.pb.update(message, self.count, self.total)
1892
class ConvertBzrDir4To5(Converter):
1893
"""Converts format 4 bzr dirs to format 5."""
1896
super(ConvertBzrDir4To5, self).__init__()
1897
self.converted_revs = set()
1898
self.absent_revisions = set()
1902
def convert(self, to_convert, pb):
1903
"""See Converter.convert()."""
1904
self.bzrdir = to_convert
1906
self.pb.note('starting upgrade from format 4 to 5')
1907
if isinstance(self.bzrdir.transport, LocalTransport):
1908
self.bzrdir.get_workingtree_transport(None).delete('stat-cache')
1909
self._convert_to_weaves()
1910
return BzrDir.open(self.bzrdir.root_transport.base)
1912
def _convert_to_weaves(self):
1913
self.pb.note('note: upgrade may be faster if all store files are ungzipped first')
1916
stat = self.bzrdir.transport.stat('weaves')
1917
if not S_ISDIR(stat.st_mode):
1918
self.bzrdir.transport.delete('weaves')
1919
self.bzrdir.transport.mkdir('weaves')
1920
except errors.NoSuchFile:
1921
self.bzrdir.transport.mkdir('weaves')
1922
# deliberately not a WeaveFile as we want to build it up slowly.
1923
self.inv_weave = Weave('inventory')
1924
# holds in-memory weaves for all files
1925
self.text_weaves = {}
1926
self.bzrdir.transport.delete('branch-format')
1927
self.branch = self.bzrdir.open_branch()
1928
self._convert_working_inv()
1929
rev_history = self.branch.revision_history()
1930
# to_read is a stack holding the revisions we still need to process;
1931
# appending to it adds new highest-priority revisions
1932
self.known_revisions = set(rev_history)
1933
self.to_read = rev_history[-1:]
1935
rev_id = self.to_read.pop()
1936
if (rev_id not in self.revisions
1937
and rev_id not in self.absent_revisions):
1938
self._load_one_rev(rev_id)
1940
to_import = self._make_order()
1941
for i, rev_id in enumerate(to_import):
1942
self.pb.update('converting revision', i, len(to_import))
1943
self._convert_one_rev(rev_id)
1945
self._write_all_weaves()
1946
self._write_all_revs()
1947
self.pb.note('upgraded to weaves:')
1948
self.pb.note(' %6d revisions and inventories', len(self.revisions))
1949
self.pb.note(' %6d revisions not present', len(self.absent_revisions))
1950
self.pb.note(' %6d texts', self.text_count)
1951
self._cleanup_spare_files_after_format4()
1952
self.branch.control_files.put_utf8('branch-format', BzrDirFormat5().get_format_string())
1954
def _cleanup_spare_files_after_format4(self):
1955
# FIXME working tree upgrade foo.
1956
for n in 'merged-patches', 'pending-merged-patches':
1958
## assert os.path.getsize(p) == 0
1959
self.bzrdir.transport.delete(n)
1960
except errors.NoSuchFile:
1962
self.bzrdir.transport.delete_tree('inventory-store')
1963
self.bzrdir.transport.delete_tree('text-store')
1965
def _convert_working_inv(self):
1966
inv = xml4.serializer_v4.read_inventory(
1967
self.branch.control_files.get('inventory'))
1968
new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv, working=True)
1969
# FIXME inventory is a working tree change.
1970
self.branch.control_files.put('inventory', StringIO(new_inv_xml))
1972
def _write_all_weaves(self):
1973
controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)
1974
weave_transport = self.bzrdir.transport.clone('weaves')
1975
weaves = WeaveStore(weave_transport, prefixed=False)
1976
transaction = WriteTransaction()
1980
for file_id, file_weave in self.text_weaves.items():
1981
self.pb.update('writing weave', i, len(self.text_weaves))
1982
weaves._put_weave(file_id, file_weave, transaction)
1984
self.pb.update('inventory', 0, 1)
1985
controlweaves._put_weave('inventory', self.inv_weave, transaction)
1986
self.pb.update('inventory', 1, 1)
1990
def _write_all_revs(self):
1991
"""Write all revisions out in new form."""
1992
self.bzrdir.transport.delete_tree('revision-store')
1993
self.bzrdir.transport.mkdir('revision-store')
1994
revision_transport = self.bzrdir.transport.clone('revision-store')
1996
_revision_store = TextRevisionStore(TextStore(revision_transport,
2000
transaction = WriteTransaction()
2001
for i, rev_id in enumerate(self.converted_revs):
2002
self.pb.update('write revision', i, len(self.converted_revs))
2003
_revision_store.add_revision(self.revisions[rev_id], transaction)
2007
def _load_one_rev(self, rev_id):
2008
"""Load a revision object into memory.
2010
Any parents not either loaded or abandoned get queued to be
2012
self.pb.update('loading revision',
2013
len(self.revisions),
2014
len(self.known_revisions))
2015
if not self.branch.repository.has_revision(rev_id):
2017
self.pb.note('revision {%s} not present in branch; '
2018
'will be converted as a ghost',
2020
self.absent_revisions.add(rev_id)
2022
rev = self.branch.repository._revision_store.get_revision(rev_id,
2023
self.branch.repository.get_transaction())
2024
for parent_id in rev.parent_ids:
2025
self.known_revisions.add(parent_id)
2026
self.to_read.append(parent_id)
2027
self.revisions[rev_id] = rev
2029
def _load_old_inventory(self, rev_id):
2030
assert rev_id not in self.converted_revs
2031
old_inv_xml = self.branch.repository.inventory_store.get(rev_id).read()
2032
inv = xml4.serializer_v4.read_inventory_from_string(old_inv_xml)
2033
inv.revision_id = rev_id
2034
rev = self.revisions[rev_id]
2035
if rev.inventory_sha1:
2036
assert rev.inventory_sha1 == sha_string(old_inv_xml), \
2037
'inventory sha mismatch for {%s}' % rev_id
2040
def _load_updated_inventory(self, rev_id):
2041
assert rev_id in self.converted_revs
2042
inv_xml = self.inv_weave.get_text(rev_id)
2043
inv = xml5.serializer_v5.read_inventory_from_string(inv_xml, rev_id)
2046
def _convert_one_rev(self, rev_id):
2047
"""Convert revision and all referenced objects to new format."""
2048
rev = self.revisions[rev_id]
2049
inv = self._load_old_inventory(rev_id)
2050
present_parents = [p for p in rev.parent_ids
2051
if p not in self.absent_revisions]
2052
self._convert_revision_contents(rev, inv, present_parents)
2053
self._store_new_inv(rev, inv, present_parents)
2054
self.converted_revs.add(rev_id)
2056
def _store_new_inv(self, rev, inv, present_parents):
2057
# the XML is now updated with text versions
2059
entries = inv.iter_entries()
2061
for path, ie in entries:
2062
assert getattr(ie, 'revision', None) is not None, \
2063
'no revision on {%s} in {%s}' % \
2064
(file_id, rev.revision_id)
2065
new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
2066
new_inv_sha1 = sha_string(new_inv_xml)
2067
self.inv_weave.add_lines(rev.revision_id,
2069
new_inv_xml.splitlines(True))
2070
rev.inventory_sha1 = new_inv_sha1
2072
def _convert_revision_contents(self, rev, inv, present_parents):
2073
"""Convert all the files within a revision.
2075
Also upgrade the inventory to refer to the text revision ids."""
2076
rev_id = rev.revision_id
2077
mutter('converting texts of revision {%s}',
2079
parent_invs = map(self._load_updated_inventory, present_parents)
2080
entries = inv.iter_entries()
2082
for path, ie in entries:
2083
self._convert_file_version(rev, ie, parent_invs)
2085
def _convert_file_version(self, rev, ie, parent_invs):
2086
"""Convert one version of one file.
2088
The file needs to be added into the weave if it is a merge
2089
of >=2 parents or if it's changed from its parent.
2091
file_id = ie.file_id
2092
rev_id = rev.revision_id
2093
w = self.text_weaves.get(file_id)
2096
self.text_weaves[file_id] = w
2097
text_changed = False
2098
parent_candiate_entries = ie.parent_candidates(parent_invs)
2099
for old_revision in parent_candiate_entries.keys():
2100
# if this fails, its a ghost ?
2101
assert old_revision in self.converted_revs, \
2102
"Revision {%s} not in converted_revs" % old_revision
2103
heads = graph.Graph(self).heads(parent_candiate_entries.keys())
2104
# XXX: Note that this is unordered - and this is tolerable because
2105
# the previous code was also unordered.
2106
previous_entries = dict((head, parent_candiate_entries[head]) for head
2108
self.snapshot_ie(previous_entries, ie, w, rev_id)
2110
assert getattr(ie, 'revision', None) is not None
2112
@symbol_versioning.deprecated_method(symbol_versioning.one_one)
2113
def get_parents(self, revision_ids):
2114
for revision_id in revision_ids:
2115
yield self.revisions[revision_id].parent_ids
2117
def get_parent_map(self, revision_ids):
2118
"""See graph._StackedParentsProvider.get_parent_map"""
2119
return dict((revision_id, self.revisions[revision_id])
2120
for revision_id in revision_ids
2121
if revision_id in self.revisions)
2123
def snapshot_ie(self, previous_revisions, ie, w, rev_id):
2124
# TODO: convert this logic, which is ~= snapshot to
2125
# a call to:. This needs the path figured out. rather than a work_tree
2126
# a v4 revision_tree can be given, or something that looks enough like
2127
# one to give the file content to the entry if it needs it.
2128
# and we need something that looks like a weave store for snapshot to
2130
#ie.snapshot(rev, PATH, previous_revisions, REVISION_TREE, InMemoryWeaveStore(self.text_weaves))
2131
if len(previous_revisions) == 1:
2132
previous_ie = previous_revisions.values()[0]
2133
if ie._unchanged(previous_ie):
2134
ie.revision = previous_ie.revision
2137
text = self.branch.repository.weave_store.get(ie.text_id)
2138
file_lines = text.readlines()
2139
assert sha_strings(file_lines) == ie.text_sha1
2140
assert sum(map(len, file_lines)) == ie.text_size
2141
w.add_lines(rev_id, previous_revisions, file_lines)
2142
self.text_count += 1
2144
w.add_lines(rev_id, previous_revisions, [])
2145
ie.revision = rev_id
2147
def _make_order(self):
2148
"""Return a suitable order for importing revisions.
2150
The order must be such that an revision is imported after all
2151
its (present) parents.
2153
todo = set(self.revisions.keys())
2154
done = self.absent_revisions.copy()
2157
# scan through looking for a revision whose parents
2159
for rev_id in sorted(list(todo)):
2160
rev = self.revisions[rev_id]
2161
parent_ids = set(rev.parent_ids)
2162
if parent_ids.issubset(done):
2163
# can take this one now
2164
order.append(rev_id)
2170
class ConvertBzrDir5To6(Converter):
2171
"""Converts format 5 bzr dirs to format 6."""
2173
def convert(self, to_convert, pb):
2174
"""See Converter.convert()."""
2175
self.bzrdir = to_convert
2177
self.pb.note('starting upgrade from format 5 to 6')
2178
self._convert_to_prefixed()
2179
return BzrDir.open(self.bzrdir.root_transport.base)
2181
def _convert_to_prefixed(self):
2182
from bzrlib.store import TransportStore
2183
self.bzrdir.transport.delete('branch-format')
2184
for store_name in ["weaves", "revision-store"]:
2185
self.pb.note("adding prefixes to %s" % store_name)
2186
store_transport = self.bzrdir.transport.clone(store_name)
2187
store = TransportStore(store_transport, prefixed=True)
2188
for urlfilename in store_transport.list_dir('.'):
2189
filename = urlutils.unescape(urlfilename)
2190
if (filename.endswith(".weave") or
2191
filename.endswith(".gz") or
2192
filename.endswith(".sig")):
2193
file_id = os.path.splitext(filename)[0]
2196
prefix_dir = store.hash_prefix(file_id)
2197
# FIXME keep track of the dirs made RBC 20060121
2199
store_transport.move(filename, prefix_dir + '/' + filename)
2200
except errors.NoSuchFile: # catches missing dirs strangely enough
2201
store_transport.mkdir(prefix_dir)
2202
store_transport.move(filename, prefix_dir + '/' + filename)
2203
self.bzrdir._control_files.put_utf8('branch-format', BzrDirFormat6().get_format_string())
2206
class ConvertBzrDir6ToMeta(Converter):
2207
"""Converts format 6 bzr dirs to metadirs."""
2209
def convert(self, to_convert, pb):
2210
"""See Converter.convert()."""
2211
from bzrlib.repofmt.weaverepo import RepositoryFormat7
2212
from bzrlib.branch import BzrBranchFormat5
2213
self.bzrdir = to_convert
2216
self.total = 20 # the steps we know about
2217
self.garbage_inventories = []
2219
self.pb.note('starting upgrade from format 6 to metadir')
2220
self.bzrdir._control_files.put_utf8('branch-format', "Converting to format 6")
2221
# its faster to move specific files around than to open and use the apis...
2222
# first off, nuke ancestry.weave, it was never used.
2224
self.step('Removing ancestry.weave')
2225
self.bzrdir.transport.delete('ancestry.weave')
2226
except errors.NoSuchFile:
2228
# find out whats there
2229
self.step('Finding branch files')
2230
last_revision = self.bzrdir.open_branch().last_revision()
2231
bzrcontents = self.bzrdir.transport.list_dir('.')
2232
for name in bzrcontents:
2233
if name.startswith('basis-inventory.'):
2234
self.garbage_inventories.append(name)
2235
# create new directories for repository, working tree and branch
2236
self.dir_mode = self.bzrdir._control_files._dir_mode
2237
self.file_mode = self.bzrdir._control_files._file_mode
2238
repository_names = [('inventory.weave', True),
2239
('revision-store', True),
2241
self.step('Upgrading repository ')
2242
self.bzrdir.transport.mkdir('repository', mode=self.dir_mode)
2243
self.make_lock('repository')
2244
# we hard code the formats here because we are converting into
2245
# the meta format. The meta format upgrader can take this to a
2246
# future format within each component.
2247
self.put_format('repository', RepositoryFormat7())
2248
for entry in repository_names:
2249
self.move_entry('repository', entry)
2251
self.step('Upgrading branch ')
2252
self.bzrdir.transport.mkdir('branch', mode=self.dir_mode)
2253
self.make_lock('branch')
2254
self.put_format('branch', BzrBranchFormat5())
2255
branch_files = [('revision-history', True),
2256
('branch-name', True),
2258
for entry in branch_files:
2259
self.move_entry('branch', entry)
2261
checkout_files = [('pending-merges', True),
2262
('inventory', True),
2263
('stat-cache', False)]
2264
# If a mandatory checkout file is not present, the branch does not have
2265
# a functional checkout. Do not create a checkout in the converted
2267
for name, mandatory in checkout_files:
2268
if mandatory and name not in bzrcontents:
2269
has_checkout = False
2273
if not has_checkout:
2274
self.pb.note('No working tree.')
2275
# If some checkout files are there, we may as well get rid of them.
2276
for name, mandatory in checkout_files:
2277
if name in bzrcontents:
2278
self.bzrdir.transport.delete(name)
2280
from bzrlib.workingtree import WorkingTreeFormat3
2281
self.step('Upgrading working tree')
2282
self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
2283
self.make_lock('checkout')
2285
'checkout', WorkingTreeFormat3())
2286
self.bzrdir.transport.delete_multi(
2287
self.garbage_inventories, self.pb)
2288
for entry in checkout_files:
2289
self.move_entry('checkout', entry)
2290
if last_revision is not None:
2291
self.bzrdir._control_files.put_utf8(
2292
'checkout/last-revision', last_revision)
2293
self.bzrdir._control_files.put_utf8(
2294
'branch-format', BzrDirMetaFormat1().get_format_string())
2295
return BzrDir.open(self.bzrdir.root_transport.base)
2297
def make_lock(self, name):
2298
"""Make a lock for the new control dir name."""
2299
self.step('Make %s lock' % name)
2300
ld = lockdir.LockDir(self.bzrdir.transport,
2302
file_modebits=self.file_mode,
2303
dir_modebits=self.dir_mode)
2306
def move_entry(self, new_dir, entry):
2307
"""Move then entry name into new_dir."""
2309
mandatory = entry[1]
2310
self.step('Moving %s' % name)
2312
self.bzrdir.transport.move(name, '%s/%s' % (new_dir, name))
2313
except errors.NoSuchFile:
2317
def put_format(self, dirname, format):
2318
self.bzrdir._control_files.put_utf8('%s/format' % dirname, format.get_format_string())
2321
class ConvertMetaToMeta(Converter):
2322
"""Converts the components of metadirs."""
2324
def __init__(self, target_format):
2325
"""Create a metadir to metadir converter.
2327
:param target_format: The final metadir format that is desired.
2329
self.target_format = target_format
2331
def convert(self, to_convert, pb):
2332
"""See Converter.convert()."""
2333
self.bzrdir = to_convert
2337
self.step('checking repository format')
2339
repo = self.bzrdir.open_repository()
2340
except errors.NoRepositoryPresent:
2343
if not isinstance(repo._format, self.target_format.repository_format.__class__):
2344
from bzrlib.repository import CopyConverter
2345
self.pb.note('starting repository conversion')
2346
converter = CopyConverter(self.target_format.repository_format)
2347
converter.convert(repo, pb)
2349
branch = self.bzrdir.open_branch()
2350
except errors.NotBranchError:
2353
# TODO: conversions of Branch and Tree should be done by
2354
# InterXFormat lookups
2355
# Avoid circular imports
2356
from bzrlib import branch as _mod_branch
2357
if (branch._format.__class__ is _mod_branch.BzrBranchFormat5 and
2358
self.target_format.get_branch_format().__class__ is
2359
_mod_branch.BzrBranchFormat6):
2360
branch_converter = _mod_branch.Converter5to6()
2361
branch_converter.convert(branch)
2363
tree = self.bzrdir.open_workingtree(recommend_upgrade=False)
2364
except (errors.NoWorkingTree, errors.NotLocalUrl):
2367
# TODO: conversions of Branch and Tree should be done by
2368
# InterXFormat lookups
2369
if (isinstance(tree, workingtree.WorkingTree3) and
2370
not isinstance(tree, workingtree_4.WorkingTree4) and
2371
isinstance(self.target_format.workingtree_format,
2372
workingtree_4.WorkingTreeFormat4)):
2373
workingtree_4.Converter3to4().convert(tree)
2377
# This is not in remote.py because it's small, and needs to be registered.
2378
# Putting it in remote.py creates a circular import problem.
2379
# we can make it a lazy object if the control formats is turned into something
2381
class RemoteBzrDirFormat(BzrDirMetaFormat1):
2382
"""Format representing bzrdirs accessed via a smart server"""
2384
def get_format_description(self):
2385
return 'bzr remote bzrdir'
2388
def probe_transport(klass, transport):
2389
"""Return a RemoteBzrDirFormat object if it looks possible."""
2391
client = transport.get_smart_client()
2392
except (NotImplementedError, AttributeError,
2393
errors.TransportNotPossible):
2394
# no smart server, so not a branch for this format type.
2395
raise errors.NotBranchError(path=transport.base)
2397
# Send a 'hello' request in protocol version one, and decline to
2398
# open it if the server doesn't support our required version (2) so
2399
# that the VFS-based transport will do it.
2400
request = client.get_request()
2401
smart_protocol = protocol.SmartClientRequestProtocolOne(request)
2402
server_version = smart_protocol.query_version()
2403
if server_version != 2:
2404
raise errors.NotBranchError(path=transport.base)
2407
def initialize_on_transport(self, transport):
2409
# hand off the request to the smart server
2410
shared_medium = transport.get_shared_medium()
2411
except errors.NoSmartMedium:
2412
# TODO: lookup the local format from a server hint.
2413
local_dir_format = BzrDirMetaFormat1()
2414
return local_dir_format.initialize_on_transport(transport)
2415
client = _SmartClient(shared_medium)
2416
path = client.remote_path_from_transport(transport)
2417
response = _SmartClient(shared_medium).call('BzrDirFormat.initialize',
2419
assert response[0] in ('ok', ), 'unexpected response code %s' % (response,)
2420
return remote.RemoteBzrDir(transport)
2422
def _open(self, transport):
2423
return remote.RemoteBzrDir(transport)
2425
def __eq__(self, other):
2426
if not isinstance(other, RemoteBzrDirFormat):
2428
return self.get_format_description() == other.get_format_description()
2431
BzrDirFormat.register_control_server_format(RemoteBzrDirFormat)
2434
class BzrDirFormatInfo(object):
2436
def __init__(self, native, deprecated, hidden, experimental):
2437
self.deprecated = deprecated
2438
self.native = native
2439
self.hidden = hidden
2440
self.experimental = experimental
2443
class BzrDirFormatRegistry(registry.Registry):
2444
"""Registry of user-selectable BzrDir subformats.
2446
Differs from BzrDirFormat._control_formats in that it provides sub-formats,
2447
e.g. BzrDirMeta1 with weave repository. Also, it's more user-oriented.
2451
"""Create a BzrDirFormatRegistry."""
2452
self._aliases = set()
2453
super(BzrDirFormatRegistry, self).__init__()
2456
"""Return a set of the format names which are aliases."""
2457
return frozenset(self._aliases)
2459
def register_metadir(self, key,
2460
repository_format, help, native=True, deprecated=False,
2466
"""Register a metadir subformat.
2468
These all use a BzrDirMetaFormat1 bzrdir, but can be parameterized
2469
by the Repository format.
2471
:param repository_format: The fully-qualified repository format class
2473
:param branch_format: Fully-qualified branch format class name as
2475
:param tree_format: Fully-qualified tree format class name as
2478
# This should be expanded to support setting WorkingTree and Branch
2479
# formats, once BzrDirMetaFormat1 supports that.
2480
def _load(full_name):
2481
mod_name, factory_name = full_name.rsplit('.', 1)
2483
mod = __import__(mod_name, globals(), locals(),
2485
except ImportError, e:
2486
raise ImportError('failed to load %s: %s' % (full_name, e))
2488
factory = getattr(mod, factory_name)
2489
except AttributeError:
2490
raise AttributeError('no factory %s in module %r'
2495
bd = BzrDirMetaFormat1()
2496
if branch_format is not None:
2497
bd.set_branch_format(_load(branch_format))
2498
if tree_format is not None:
2499
bd.workingtree_format = _load(tree_format)
2500
if repository_format is not None:
2501
bd.repository_format = _load(repository_format)
2503
self.register(key, helper, help, native, deprecated, hidden,
2504
experimental, alias)
2506
def register(self, key, factory, help, native=True, deprecated=False,
2507
hidden=False, experimental=False, alias=False):
2508
"""Register a BzrDirFormat factory.
2510
The factory must be a callable that takes one parameter: the key.
2511
It must produce an instance of the BzrDirFormat when called.
2513
This function mainly exists to prevent the info object from being
2516
registry.Registry.register(self, key, factory, help,
2517
BzrDirFormatInfo(native, deprecated, hidden, experimental))
2519
self._aliases.add(key)
2521
def register_lazy(self, key, module_name, member_name, help, native=True,
2522
deprecated=False, hidden=False, experimental=False, alias=False):
2523
registry.Registry.register_lazy(self, key, module_name, member_name,
2524
help, BzrDirFormatInfo(native, deprecated, hidden, experimental))
2526
self._aliases.add(key)
2528
def set_default(self, key):
2529
"""Set the 'default' key to be a clone of the supplied key.
2531
This method must be called once and only once.
2533
registry.Registry.register(self, 'default', self.get(key),
2534
self.get_help(key), info=self.get_info(key))
2535
self._aliases.add('default')
2537
def set_default_repository(self, key):
2538
"""Set the FormatRegistry default and Repository default.
2540
This is a transitional method while Repository.set_default_format
2543
if 'default' in self:
2544
self.remove('default')
2545
self.set_default(key)
2546
format = self.get('default')()
2547
assert isinstance(format, BzrDirMetaFormat1)
2549
def make_bzrdir(self, key):
2550
return self.get(key)()
2552
def help_topic(self, topic):
2553
output = textwrap.dedent("""\
2554
These formats can be used for creating branches, working trees, and
2558
default_realkey = None
2559
default_help = self.get_help('default')
2561
for key in self.keys():
2562
if key == 'default':
2564
help = self.get_help(key)
2565
if help == default_help:
2566
default_realkey = key
2568
help_pairs.append((key, help))
2570
def wrapped(key, help, info):
2572
help = '(native) ' + help
2573
return ':%s:\n%s\n\n' % (key,
2574
textwrap.fill(help, initial_indent=' ',
2575
subsequent_indent=' '))
2576
if default_realkey is not None:
2577
output += wrapped(default_realkey, '(default) %s' % default_help,
2578
self.get_info('default'))
2579
deprecated_pairs = []
2580
experimental_pairs = []
2581
for key, help in help_pairs:
2582
info = self.get_info(key)
2585
elif info.deprecated:
2586
deprecated_pairs.append((key, help))
2587
elif info.experimental:
2588
experimental_pairs.append((key, help))
2590
output += wrapped(key, help, info)
2591
if len(experimental_pairs) > 0:
2592
output += "Experimental formats are shown below.\n\n"
2593
for key, help in experimental_pairs:
2594
info = self.get_info(key)
2595
output += wrapped(key, help, info)
2596
if len(deprecated_pairs) > 0:
2597
output += "Deprecated formats are shown below.\n\n"
2598
for key, help in deprecated_pairs:
2599
info = self.get_info(key)
2600
output += wrapped(key, help, info)
2605
format_registry = BzrDirFormatRegistry()
2606
format_registry.register('weave', BzrDirFormat6,
2607
'Pre-0.8 format. Slower than knit and does not'
2608
' support checkouts or shared repositories.',
2610
format_registry.register_metadir('knit',
2611
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2612
'Format using knits. Recommended for interoperation with bzr <= 0.14.',
2613
branch_format='bzrlib.branch.BzrBranchFormat5',
2614
tree_format='bzrlib.workingtree.WorkingTreeFormat3')
2615
format_registry.register_metadir('metaweave',
2616
'bzrlib.repofmt.weaverepo.RepositoryFormat7',
2617
'Transitional format in 0.8. Slower than knit.',
2618
branch_format='bzrlib.branch.BzrBranchFormat5',
2619
tree_format='bzrlib.workingtree.WorkingTreeFormat3',
2621
format_registry.register_metadir('dirstate',
2622
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2623
help='New in 0.15: Fast local operations. Compatible with bzr 0.8 and '
2624
'above when accessed over the network.',
2625
branch_format='bzrlib.branch.BzrBranchFormat5',
2626
# this uses bzrlib.workingtree.WorkingTreeFormat4 because importing
2627
# directly from workingtree_4 triggers a circular import.
2628
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2630
format_registry.register_metadir('dirstate-tags',
2631
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2632
help='New in 0.15: Fast local operations and improved scaling for '
2633
'network operations. Additionally adds support for tags.'
2634
' Incompatible with bzr < 0.15.',
2635
branch_format='bzrlib.branch.BzrBranchFormat6',
2636
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2638
format_registry.register_metadir('rich-root',
2639
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit4',
2640
help='New in 1.0. Better handling of tree roots. Incompatible with'
2642
branch_format='bzrlib.branch.BzrBranchFormat6',
2643
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2645
format_registry.register_metadir('dirstate-with-subtree',
2646
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
2647
help='New in 0.15: Fast local operations and improved scaling for '
2648
'network operations. Additionally adds support for versioning nested '
2649
'bzr branches. Incompatible with bzr < 0.15.',
2650
branch_format='bzrlib.branch.BzrBranchFormat6',
2651
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2655
format_registry.register_metadir('pack-0.92',
2656
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack1',
2657
help='New in 0.92: Pack-based format with data compatible with '
2658
'dirstate-tags format repositories. Interoperates with '
2659
'bzr repositories before 0.92 but cannot be read by bzr < 0.92. '
2660
'Previously called knitpack-experimental. '
2661
'For more information, see '
2662
'http://doc.bazaar-vcs.org/latest/developers/packrepo.html.',
2663
branch_format='bzrlib.branch.BzrBranchFormat6',
2664
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2666
format_registry.register_metadir('pack-0.92-subtree',
2667
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack3',
2668
help='New in 0.92: Pack-based format with data compatible with '
2669
'dirstate-with-subtree format repositories. Interoperates with '
2670
'bzr repositories before 0.92 but cannot be read by bzr < 0.92. '
2671
'Previously called knitpack-experimental. '
2672
'For more information, see '
2673
'http://doc.bazaar-vcs.org/latest/developers/packrepo.html.',
2674
branch_format='bzrlib.branch.BzrBranchFormat6',
2675
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2679
format_registry.register_metadir('rich-root-pack',
2680
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack4',
2681
help='New in 1.0: Pack-based format with data compatible with '
2682
'rich-root format repositories. Incompatible with'
2684
branch_format='bzrlib.branch.BzrBranchFormat6',
2685
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2687
# The following two formats should always just be aliases.
2688
format_registry.register_metadir('development',
2689
'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment0',
2690
help='Current development format. Can convert data to and from pack-0.92 '
2691
'(and anything compatible with pack-0.92) format repositories. '
2692
'Repositories in this format can only be read by bzr.dev. '
2694
'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
2696
branch_format='bzrlib.branch.BzrBranchFormat6',
2697
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2701
format_registry.register_metadir('development-subtree',
2702
'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment0Subtree',
2703
help='Current development format, subtree variant. Can convert data to and '
2704
'from pack-0.92 (and anything compatible with pack-0.92) format '
2705
'repositories. Repositories in this format can only be read by '
2706
'bzr.dev. Please read '
2707
'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
2709
branch_format='bzrlib.branch.BzrBranchFormat6',
2710
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2714
# And the development formats which the will have aliased one of follow:
2715
format_registry.register_metadir('development0',
2716
'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment0',
2717
help='Trivial rename of pack-0.92 to provide a development format. '
2719
'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
2721
branch_format='bzrlib.branch.BzrBranchFormat6',
2722
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2726
format_registry.register_metadir('development0-subtree',
2727
'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment0Subtree',
2728
help='Trivial rename of pack-0.92-subtree to provide a development format. '
2730
'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
2732
branch_format='bzrlib.branch.BzrBranchFormat6',
2733
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2737
format_registry.set_default('pack-0.92')