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
49
revision as _mod_revision,
59
from bzrlib.osutils import (
63
from bzrlib.smart.client import _SmartClient
64
from bzrlib.smart import protocol
65
from bzrlib.store.revision.text import TextRevisionStore
66
from bzrlib.store.text import TextStore
67
from bzrlib.store.versioned import WeaveStore
68
from bzrlib.transactions import WriteTransaction
69
from bzrlib.transport import (
70
do_catching_redirections,
73
from bzrlib.weave import Weave
76
from bzrlib.trace import (
80
from bzrlib.transport.local import LocalTransport
81
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.cloning_metadir().initialize_on_transport(transport)
184
repository_policy = None
186
local_repo = self.find_repository()
187
except errors.NoRepositoryPresent:
190
# may need to copy content in
191
repository_policy = result.determine_repository_policy(
193
make_working_trees = local_repo.make_working_trees()
194
result_repo = repository_policy.acquire_repository(
195
make_working_trees, local_repo.is_shared())
196
result_repo.fetch(local_repo, revision_id=revision_id)
197
# 1 if there is a branch present
198
# make sure its content is available in the target repository
201
local_branch = self.open_branch()
202
except errors.NotBranchError:
205
result_branch = local_branch.clone(result, revision_id=revision_id)
206
if repository_policy is not None:
207
repository_policy.configure_branch(result_branch)
209
result_repo = result.find_repository()
210
except errors.NoRepositoryPresent:
212
if result_repo is None or result_repo.make_working_trees():
214
self.open_workingtree().clone(result)
215
except (errors.NoWorkingTree, errors.NotLocalUrl):
219
# TODO: This should be given a Transport, and should chdir up; otherwise
220
# this will open a new connection.
221
def _make_tail(self, url):
222
t = get_transport(url)
226
def create(cls, base, format=None, possible_transports=None):
227
"""Create a new BzrDir at the url 'base'.
229
:param format: If supplied, the format of branch to create. If not
230
supplied, the default is used.
231
:param possible_transports: If supplied, a list of transports that
232
can be reused to share a remote connection.
234
if cls is not BzrDir:
235
raise AssertionError("BzrDir.create always creates the default"
236
" format, not one of %r" % cls)
237
t = get_transport(base, possible_transports)
240
format = BzrDirFormat.get_default_format()
241
return format.initialize_on_transport(t)
244
def find_bzrdirs(transport, evaluate=None, list_current=None):
245
"""Find bzrdirs recursively from current location.
247
This is intended primarily as a building block for more sophisticated
248
functionality, like finding trees under a directory, or finding
249
branches that use a given repository.
250
:param evaluate: An optional callable that yields recurse, value,
251
where recurse controls whether this bzrdir is recursed into
252
and value is the value to yield. By default, all bzrdirs
253
are recursed into, and the return value is the bzrdir.
254
:param list_current: if supplied, use this function to list the current
255
directory, instead of Transport.list_dir
256
:return: a generator of found bzrdirs, or whatever evaluate returns.
258
if list_current is None:
259
def list_current(transport):
260
return transport.list_dir('')
262
def evaluate(bzrdir):
265
pending = [transport]
266
while len(pending) > 0:
267
current_transport = pending.pop()
270
bzrdir = BzrDir.open_from_transport(current_transport)
271
except errors.NotBranchError:
274
recurse, value = evaluate(bzrdir)
277
subdirs = list_current(current_transport)
278
except errors.NoSuchFile:
281
for subdir in sorted(subdirs, reverse=True):
282
pending.append(current_transport.clone(subdir))
285
def find_branches(transport):
286
"""Find all branches under a transport.
288
This will find all branches below the transport, including branches
289
inside other branches. Where possible, it will use
290
Repository.find_branches.
292
To list all the branches that use a particular Repository, see
293
Repository.find_branches
295
def evaluate(bzrdir):
297
repository = bzrdir.open_repository()
298
except errors.NoRepositoryPresent:
301
return False, (None, repository)
303
branch = bzrdir.open_branch()
304
except errors.NotBranchError:
305
return True, (None, None)
307
return True, (branch, None)
309
for branch, repo in BzrDir.find_bzrdirs(transport, evaluate=evaluate):
311
branches.extend(repo.find_branches())
312
if branch is not None:
313
branches.append(branch)
317
def destroy_repository(self):
318
"""Destroy the repository in this BzrDir"""
319
raise NotImplementedError(self.destroy_repository)
321
def create_branch(self):
322
"""Create a branch in this BzrDir.
324
The bzrdir's format will control what branch format is created.
325
For more control see BranchFormatXX.create(a_bzrdir).
327
raise NotImplementedError(self.create_branch)
329
def destroy_branch(self):
330
"""Destroy the branch in this BzrDir"""
331
raise NotImplementedError(self.destroy_branch)
334
def create_branch_and_repo(base, force_new_repo=False, format=None):
335
"""Create a new BzrDir, Branch and Repository at the url 'base'.
337
This will use the current default BzrDirFormat unless one is
338
specified, and use whatever
339
repository format that that uses via bzrdir.create_branch and
340
create_repository. If a shared repository is available that is used
343
The created Branch object is returned.
345
:param base: The URL to create the branch at.
346
:param force_new_repo: If True a new repository is always created.
347
:param format: If supplied, the format of branch to create. If not
348
supplied, the default is used.
350
bzrdir = BzrDir.create(base, format)
351
bzrdir._find_or_create_repository(force_new_repo)
352
return bzrdir.create_branch()
354
def determine_repository_policy(self, force_new_repo=False):
355
"""Return an object representing a policy to use.
357
This controls whether a new repository is created, or a shared
358
repository used instead.
360
def repository_policy(found_bzrdir):
362
# does it have a repository ?
364
repository = found_bzrdir.open_repository()
365
except errors.NoRepositoryPresent:
368
if ((found_bzrdir.root_transport.base !=
369
self.root_transport.base) and not repository.is_shared()):
376
return UseExistingRepository(repository), True
378
return CreateRepository(self), True
380
if not force_new_repo:
381
policy = self._find_containing(repository_policy)
382
if policy is not None:
384
return CreateRepository(self)
386
def _find_or_create_repository(self, force_new_repo):
387
"""Create a new repository if needed, returning the repository."""
388
policy = self.determine_repository_policy(force_new_repo)
389
return policy.acquire_repository()
392
def create_branch_convenience(base, force_new_repo=False,
393
force_new_tree=None, format=None,
394
possible_transports=None):
395
"""Create a new BzrDir, Branch and Repository at the url 'base'.
397
This is a convenience function - it will use an existing repository
398
if possible, can be told explicitly whether to create a working tree or
401
This will use the current default BzrDirFormat unless one is
402
specified, and use whatever
403
repository format that that uses via bzrdir.create_branch and
404
create_repository. If a shared repository is available that is used
405
preferentially. Whatever repository is used, its tree creation policy
408
The created Branch object is returned.
409
If a working tree cannot be made due to base not being a file:// url,
410
no error is raised unless force_new_tree is True, in which case no
411
data is created on disk and NotLocalUrl is raised.
413
:param base: The URL to create the branch at.
414
:param force_new_repo: If True a new repository is always created.
415
:param force_new_tree: If True or False force creation of a tree or
416
prevent such creation respectively.
417
:param format: Override for the bzrdir format to create.
418
:param possible_transports: An optional reusable transports list.
421
# check for non local urls
422
t = get_transport(base, possible_transports)
423
if not isinstance(t, LocalTransport):
424
raise errors.NotLocalUrl(base)
425
bzrdir = BzrDir.create(base, format, possible_transports)
426
repo = bzrdir._find_or_create_repository(force_new_repo)
427
result = bzrdir.create_branch()
428
if force_new_tree or (repo.make_working_trees() and
429
force_new_tree is None):
431
bzrdir.create_workingtree()
432
except errors.NotLocalUrl:
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, hardlink=False):
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_containing(self, evaluate):
512
"""Find something in a containing control directory.
514
This method will scan containing control dirs, until it finds what
515
it is looking for, decides that it will never find it, or runs out
516
of containing control directories to check.
518
It is used to implement find_repository and
519
determine_repository_policy.
521
:param evaluate: A function returning (value, stop). If stop is True,
522
the value will be returned.
526
result, stop = evaluate(found_bzrdir)
529
next_transport = found_bzrdir.root_transport.clone('..')
530
if (found_bzrdir.root_transport.base == next_transport.base):
531
# top of the file system
533
# find the next containing bzrdir
535
found_bzrdir = BzrDir.open_containing_from_transport(
537
except errors.NotBranchError:
540
def find_repository(self):
541
"""Find the repository that should be used.
543
This does not require a branch as we use it to find the repo for
544
new branches as well as to hook existing branches up to their
547
def usable_repository(found_bzrdir):
548
# does it have a repository ?
550
repository = found_bzrdir.open_repository()
551
except errors.NoRepositoryPresent:
553
if found_bzrdir.root_transport.base == self.root_transport.base:
554
return repository, True
555
elif repository.is_shared():
556
return repository, True
560
found_repo = self._find_containing(usable_repository)
561
if found_repo is None:
562
raise errors.NoRepositoryPresent(self)
565
def get_branch_reference(self):
566
"""Return the referenced URL for the branch in this bzrdir.
568
:raises NotBranchError: If there is no Branch.
569
:return: The URL the branch in this bzrdir references if it is a
570
reference branch, or None for regular branches.
574
def get_branch_transport(self, branch_format):
575
"""Get the transport for use by branch format in this BzrDir.
577
Note that bzr dirs that do not support format strings will raise
578
IncompatibleFormat if the branch format they are given has
579
a format string, and vice versa.
581
If branch_format is None, the transport is returned with no
582
checking. If it is not None, then the returned transport is
583
guaranteed to point to an existing directory ready for use.
585
raise NotImplementedError(self.get_branch_transport)
587
def get_repository_transport(self, repository_format):
588
"""Get the transport for use by repository format in this BzrDir.
590
Note that bzr dirs that do not support format strings will raise
591
IncompatibleFormat if the repository format they are given has
592
a format string, and vice versa.
594
If repository_format is None, the transport is returned with no
595
checking. If it is not None, then the returned transport is
596
guaranteed to point to an existing directory ready for use.
598
raise NotImplementedError(self.get_repository_transport)
600
def get_workingtree_transport(self, tree_format):
601
"""Get the transport for use by workingtree format in this BzrDir.
603
Note that bzr dirs that do not support format strings will raise
604
IncompatibleFormat if the workingtree format they are given has a
605
format string, and vice versa.
607
If workingtree_format is None, the transport is returned with no
608
checking. If it is not None, then the returned transport is
609
guaranteed to point to an existing directory ready for use.
611
raise NotImplementedError(self.get_workingtree_transport)
613
def __init__(self, _transport, _format):
614
"""Initialize a Bzr control dir object.
616
Only really common logic should reside here, concrete classes should be
617
made with varying behaviours.
619
:param _format: the format that is creating this BzrDir instance.
620
:param _transport: the transport this dir is based at.
622
self._format = _format
623
self.transport = _transport.clone('.bzr')
624
self.root_transport = _transport
626
def is_control_filename(self, filename):
627
"""True if filename is the name of a path which is reserved for bzrdir's.
629
:param filename: A filename within the root transport of this bzrdir.
631
This is true IF and ONLY IF the filename is part of the namespace reserved
632
for bzr control dirs. Currently this is the '.bzr' directory in the root
633
of the root_transport. it is expected that plugins will need to extend
634
this in the future - for instance to make bzr talk with svn working
637
# this might be better on the BzrDirFormat class because it refers to
638
# all the possible bzrdir disk formats.
639
# This method is tested via the workingtree is_control_filename tests-
640
# it was extracted from WorkingTree.is_control_filename. If the method's
641
# contract is extended beyond the current trivial implementation, please
642
# add new tests for it to the appropriate place.
643
return filename == '.bzr' or filename.startswith('.bzr/')
645
def needs_format_conversion(self, format=None):
646
"""Return true if this bzrdir needs convert_format run on it.
648
For instance, if the repository format is out of date but the
649
branch and working tree are not, this should return True.
651
:param format: Optional parameter indicating a specific desired
652
format we plan to arrive at.
654
raise NotImplementedError(self.needs_format_conversion)
657
def open_unsupported(base):
658
"""Open a branch which is not supported."""
659
return BzrDir.open(base, _unsupported=True)
662
def open(base, _unsupported=False, possible_transports=None):
663
"""Open an existing bzrdir, rooted at 'base' (url).
665
:param _unsupported: a private parameter to the BzrDir class.
667
t = get_transport(base, possible_transports=possible_transports)
668
return BzrDir.open_from_transport(t, _unsupported=_unsupported)
671
def open_from_transport(transport, _unsupported=False,
672
_server_formats=True):
673
"""Open a bzrdir within a particular directory.
675
:param transport: Transport containing the bzrdir.
676
:param _unsupported: private.
678
base = transport.base
680
def find_format(transport):
681
return transport, BzrDirFormat.find_format(
682
transport, _server_formats=_server_formats)
684
def redirected(transport, e, redirection_notice):
685
qualified_source = e.get_source_url()
686
relpath = transport.relpath(qualified_source)
687
if not e.target.endswith(relpath):
688
# Not redirected to a branch-format, not a branch
689
raise errors.NotBranchError(path=e.target)
690
target = e.target[:-len(relpath)]
691
note('%s is%s redirected to %s',
692
transport.base, e.permanently, target)
693
# Let's try with a new transport
694
# FIXME: If 'transport' has a qualifier, this should
695
# be applied again to the new transport *iff* the
696
# schemes used are the same. Uncomment this code
697
# once the function (and tests) exist.
699
#target = urlutils.copy_url_qualifiers(original, target)
700
return get_transport(target)
703
transport, format = do_catching_redirections(find_format,
706
except errors.TooManyRedirections:
707
raise errors.NotBranchError(base)
709
BzrDir._check_supported(format, _unsupported)
710
return format.open(transport, _found=True)
712
def open_branch(self, unsupported=False):
713
"""Open the branch object at this BzrDir if one is present.
715
If unsupported is True, then no longer supported branch formats can
718
TODO: static convenience version of this?
720
raise NotImplementedError(self.open_branch)
723
def open_containing(url, possible_transports=None):
724
"""Open an existing branch which contains url.
726
:param url: url to search from.
727
See open_containing_from_transport for more detail.
729
transport = get_transport(url, possible_transports)
730
return BzrDir.open_containing_from_transport(transport)
733
def open_containing_from_transport(a_transport):
734
"""Open an existing branch which contains a_transport.base.
736
This probes for a branch at a_transport, and searches upwards from there.
738
Basically we keep looking up until we find the control directory or
739
run into the root. If there isn't one, raises NotBranchError.
740
If there is one and it is either an unrecognised format or an unsupported
741
format, UnknownFormatError or UnsupportedFormatError are raised.
742
If there is one, it is returned, along with the unused portion of url.
744
:return: The BzrDir that contains the path, and a Unicode path
745
for the rest of the URL.
747
# this gets the normalised url back. I.e. '.' -> the full path.
748
url = a_transport.base
751
result = BzrDir.open_from_transport(a_transport)
752
return result, urlutils.unescape(a_transport.relpath(url))
753
except errors.NotBranchError, e:
756
new_t = a_transport.clone('..')
757
except errors.InvalidURLJoin:
758
# reached the root, whatever that may be
759
raise errors.NotBranchError(path=url)
760
if new_t.base == a_transport.base:
761
# reached the root, whatever that may be
762
raise errors.NotBranchError(path=url)
765
def _get_tree_branch(self):
766
"""Return the branch and tree, if any, for this bzrdir.
768
Return None for tree if not present or inaccessible.
769
Raise NotBranchError if no branch is present.
770
:return: (tree, branch)
773
tree = self.open_workingtree()
774
except (errors.NoWorkingTree, errors.NotLocalUrl):
776
branch = self.open_branch()
782
def open_tree_or_branch(klass, location):
783
"""Return the branch and working tree at a location.
785
If there is no tree at the location, tree will be None.
786
If there is no branch at the location, an exception will be
788
:return: (tree, branch)
790
bzrdir = klass.open(location)
791
return bzrdir._get_tree_branch()
794
def open_containing_tree_or_branch(klass, location):
795
"""Return the branch and working tree contained by a location.
797
Returns (tree, branch, relpath).
798
If there is no tree at containing the location, tree will be None.
799
If there is no branch containing the location, an exception will be
801
relpath is the portion of the path that is contained by the branch.
803
bzrdir, relpath = klass.open_containing(location)
804
tree, branch = bzrdir._get_tree_branch()
805
return tree, branch, relpath
807
def open_repository(self, _unsupported=False):
808
"""Open the repository object at this BzrDir if one is present.
810
This will not follow the Branch object pointer - it's strictly a direct
811
open facility. Most client code should use open_branch().repository to
814
:param _unsupported: a private parameter, not part of the api.
815
TODO: static convenience version of this?
817
raise NotImplementedError(self.open_repository)
819
def open_workingtree(self, _unsupported=False,
820
recommend_upgrade=True, from_branch=None):
821
"""Open the workingtree object at this BzrDir if one is present.
823
:param recommend_upgrade: Optional keyword parameter, when True (the
824
default), emit through the ui module a recommendation that the user
825
upgrade the working tree when the workingtree being opened is old
826
(but still fully supported).
827
:param from_branch: override bzrdir branch (for lightweight checkouts)
829
raise NotImplementedError(self.open_workingtree)
831
def has_branch(self):
832
"""Tell if this bzrdir contains a branch.
834
Note: if you're going to open the branch, you should just go ahead
835
and try, and not ask permission first. (This method just opens the
836
branch and discards it, and that's somewhat expensive.)
841
except errors.NotBranchError:
844
def has_workingtree(self):
845
"""Tell if this bzrdir contains a working tree.
847
This will still raise an exception if the bzrdir has a workingtree that
848
is remote & inaccessible.
850
Note: if you're going to open the working tree, you should just go ahead
851
and try, and not ask permission first. (This method just opens the
852
workingtree and discards it, and that's somewhat expensive.)
855
self.open_workingtree(recommend_upgrade=False)
857
except errors.NoWorkingTree:
860
def _cloning_metadir(self):
861
"""Produce a metadir suitable for cloning with."""
862
result_format = self._format.__class__()
865
branch = self.open_branch()
866
source_repository = branch.repository
867
except errors.NotBranchError:
869
source_repository = self.open_repository()
870
except errors.NoRepositoryPresent:
871
source_repository = None
873
# XXX TODO: This isinstance is here because we have not implemented
874
# the fix recommended in bug # 103195 - to delegate this choice the
876
repo_format = source_repository._format
877
if not isinstance(repo_format, remote.RemoteRepositoryFormat):
878
result_format.repository_format = repo_format
880
# TODO: Couldn't we just probe for the format in these cases,
881
# rather than opening the whole tree? It would be a little
882
# faster. mbp 20070401
883
tree = self.open_workingtree(recommend_upgrade=False)
884
except (errors.NoWorkingTree, errors.NotLocalUrl):
885
result_format.workingtree_format = None
887
result_format.workingtree_format = tree._format.__class__()
888
return result_format, source_repository
890
def cloning_metadir(self):
891
"""Produce a metadir suitable for cloning or sprouting with.
893
These operations may produce workingtrees (yes, even though they're
894
"cloning" something that doesn't have a tree), so a viable workingtree
895
format must be selected.
897
format, repository = self._cloning_metadir()
898
if format._workingtree_format is None:
899
if repository is None:
901
tree_format = repository._format._matchingbzrdir.workingtree_format
902
format.workingtree_format = tree_format.__class__()
905
def checkout_metadir(self):
906
return self.cloning_metadir()
908
def sprout(self, url, revision_id=None, force_new_repo=False,
909
recurse='down', possible_transports=None,
910
accelerator_tree=None, hardlink=False):
911
"""Create a copy of this bzrdir prepared for use as a new line of
914
If url's last component does not exist, it will be created.
916
Attributes related to the identity of the source branch like
917
branch nickname will be cleaned, a working tree is created
918
whether one existed before or not; and a local branch is always
921
if revision_id is not None, then the clone operation may tune
922
itself to download less data.
923
:param accelerator_tree: A tree which can be used for retrieving file
924
contents more quickly than the revision tree, i.e. a workingtree.
925
The revision tree will be used for cases where accelerator_tree's
926
content is different.
927
:param hardlink: If true, hard-link files from accelerator_tree,
930
target_transport = get_transport(url, possible_transports)
931
target_transport.ensure_base()
932
cloning_format = self.cloning_metadir()
933
result = cloning_format.initialize_on_transport(target_transport)
935
source_branch = self.open_branch()
936
source_repository = source_branch.repository
937
except errors.NotBranchError:
940
source_repository = self.open_repository()
941
except errors.NoRepositoryPresent:
942
source_repository = None
947
result_repo = result.find_repository()
948
except errors.NoRepositoryPresent:
950
if source_repository is None and result_repo is not None:
952
elif source_repository is None and result_repo is None:
953
# no repo available, make a new one
954
result.create_repository()
955
elif source_repository is not None and result_repo is None:
956
# have source, and want to make a new target repo
957
result_repo = source_repository.sprout(result,
958
revision_id=revision_id)
960
# fetch needed content into target.
961
if source_repository is not None:
963
# source_repository.copy_content_into(result_repo,
964
# revision_id=revision_id)
965
# so we can override the copy method
966
result_repo.fetch(source_repository, revision_id=revision_id)
967
if source_branch is not None:
968
source_branch.sprout(result, revision_id=revision_id)
970
result.create_branch()
971
if isinstance(target_transport, LocalTransport) and (
972
result_repo is None or result_repo.make_working_trees()):
973
wt = result.create_workingtree(accelerator_tree=accelerator_tree,
977
if wt.path2id('') is None:
979
wt.set_root_id(self.open_workingtree.get_root_id())
980
except errors.NoWorkingTree:
986
if recurse == 'down':
988
basis = wt.basis_tree()
990
subtrees = basis.iter_references()
991
recurse_branch = wt.branch
992
elif source_branch is not None:
993
basis = source_branch.basis_tree()
995
subtrees = basis.iter_references()
996
recurse_branch = source_branch
1001
for path, file_id in subtrees:
1002
target = urlutils.join(url, urlutils.escape(path))
1003
sublocation = source_branch.reference_parent(file_id, path)
1004
sublocation.bzrdir.sprout(target,
1005
basis.get_reference_revision(file_id, path),
1006
force_new_repo=force_new_repo, recurse=recurse)
1008
if basis is not None:
1013
class BzrDirPreSplitOut(BzrDir):
1014
"""A common class for the all-in-one formats."""
1016
def __init__(self, _transport, _format):
1017
"""See BzrDir.__init__."""
1018
super(BzrDirPreSplitOut, self).__init__(_transport, _format)
1019
self._control_files = lockable_files.LockableFiles(
1020
self.get_branch_transport(None),
1021
self._format._lock_file_name,
1022
self._format._lock_class)
1024
def break_lock(self):
1025
"""Pre-splitout bzrdirs do not suffer from stale locks."""
1026
raise NotImplementedError(self.break_lock)
1028
def cloning_metadir(self):
1029
"""Produce a metadir suitable for cloning with."""
1030
return self._format.__class__()
1032
def clone(self, url, revision_id=None, force_new_repo=False):
1033
"""See BzrDir.clone()."""
1034
from bzrlib.workingtree import WorkingTreeFormat2
1035
self._make_tail(url)
1036
result = self._format._initialize_for_clone(url)
1037
self.open_repository().clone(result, revision_id=revision_id)
1038
from_branch = self.open_branch()
1039
from_branch.clone(result, revision_id=revision_id)
1041
self.open_workingtree().clone(result)
1042
except errors.NotLocalUrl:
1043
# make a new one, this format always has to have one.
1045
WorkingTreeFormat2().initialize(result)
1046
except errors.NotLocalUrl:
1047
# but we cannot do it for remote trees.
1048
to_branch = result.open_branch()
1049
WorkingTreeFormat2().stub_initialize_remote(to_branch.control_files)
1052
def create_branch(self):
1053
"""See BzrDir.create_branch."""
1054
return self.open_branch()
1056
def destroy_branch(self):
1057
"""See BzrDir.destroy_branch."""
1058
raise errors.UnsupportedOperation(self.destroy_branch, self)
1060
def create_repository(self, shared=False):
1061
"""See BzrDir.create_repository."""
1063
raise errors.IncompatibleFormat('shared repository', self._format)
1064
return self.open_repository()
1066
def destroy_repository(self):
1067
"""See BzrDir.destroy_repository."""
1068
raise errors.UnsupportedOperation(self.destroy_repository, self)
1070
def create_workingtree(self, revision_id=None, from_branch=None,
1071
accelerator_tree=None, hardlink=False):
1072
"""See BzrDir.create_workingtree."""
1073
# this looks buggy but is not -really-
1074
# because this format creates the workingtree when the bzrdir is
1076
# clone and sprout will have set the revision_id
1077
# and that will have set it for us, its only
1078
# specific uses of create_workingtree in isolation
1079
# that can do wonky stuff here, and that only
1080
# happens for creating checkouts, which cannot be
1081
# done on this format anyway. So - acceptable wart.
1082
result = self.open_workingtree(recommend_upgrade=False)
1083
if revision_id is not None:
1084
if revision_id == _mod_revision.NULL_REVISION:
1085
result.set_parent_ids([])
1087
result.set_parent_ids([revision_id])
1090
def destroy_workingtree(self):
1091
"""See BzrDir.destroy_workingtree."""
1092
raise errors.UnsupportedOperation(self.destroy_workingtree, self)
1094
def destroy_workingtree_metadata(self):
1095
"""See BzrDir.destroy_workingtree_metadata."""
1096
raise errors.UnsupportedOperation(self.destroy_workingtree_metadata,
1099
def get_branch_transport(self, branch_format):
1100
"""See BzrDir.get_branch_transport()."""
1101
if branch_format is None:
1102
return self.transport
1104
branch_format.get_format_string()
1105
except NotImplementedError:
1106
return self.transport
1107
raise errors.IncompatibleFormat(branch_format, self._format)
1109
def get_repository_transport(self, repository_format):
1110
"""See BzrDir.get_repository_transport()."""
1111
if repository_format is None:
1112
return self.transport
1114
repository_format.get_format_string()
1115
except NotImplementedError:
1116
return self.transport
1117
raise errors.IncompatibleFormat(repository_format, self._format)
1119
def get_workingtree_transport(self, workingtree_format):
1120
"""See BzrDir.get_workingtree_transport()."""
1121
if workingtree_format is None:
1122
return self.transport
1124
workingtree_format.get_format_string()
1125
except NotImplementedError:
1126
return self.transport
1127
raise errors.IncompatibleFormat(workingtree_format, self._format)
1129
def needs_format_conversion(self, format=None):
1130
"""See BzrDir.needs_format_conversion()."""
1131
# if the format is not the same as the system default,
1132
# an upgrade is needed.
1134
format = BzrDirFormat.get_default_format()
1135
return not isinstance(self._format, format.__class__)
1137
def open_branch(self, unsupported=False):
1138
"""See BzrDir.open_branch."""
1139
from bzrlib.branch import BzrBranchFormat4
1140
format = BzrBranchFormat4()
1141
self._check_supported(format, unsupported)
1142
return format.open(self, _found=True)
1144
def sprout(self, url, revision_id=None, force_new_repo=False,
1145
possible_transports=None, accelerator_tree=None,
1147
"""See BzrDir.sprout()."""
1148
from bzrlib.workingtree import WorkingTreeFormat2
1149
self._make_tail(url)
1150
result = self._format._initialize_for_clone(url)
1152
self.open_repository().clone(result, revision_id=revision_id)
1153
except errors.NoRepositoryPresent:
1156
self.open_branch().sprout(result, revision_id=revision_id)
1157
except errors.NotBranchError:
1159
# we always want a working tree
1160
WorkingTreeFormat2().initialize(result,
1161
accelerator_tree=accelerator_tree,
1166
class BzrDir4(BzrDirPreSplitOut):
1167
"""A .bzr version 4 control object.
1169
This is a deprecated format and may be removed after sept 2006.
1172
def create_repository(self, shared=False):
1173
"""See BzrDir.create_repository."""
1174
return self._format.repository_format.initialize(self, shared)
1176
def needs_format_conversion(self, format=None):
1177
"""Format 4 dirs are always in need of conversion."""
1180
def open_repository(self):
1181
"""See BzrDir.open_repository."""
1182
from bzrlib.repofmt.weaverepo import RepositoryFormat4
1183
return RepositoryFormat4().open(self, _found=True)
1186
class BzrDir5(BzrDirPreSplitOut):
1187
"""A .bzr version 5 control object.
1189
This is a deprecated format and may be removed after sept 2006.
1192
def open_repository(self):
1193
"""See BzrDir.open_repository."""
1194
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1195
return RepositoryFormat5().open(self, _found=True)
1197
def open_workingtree(self, _unsupported=False,
1198
recommend_upgrade=True):
1199
"""See BzrDir.create_workingtree."""
1200
from bzrlib.workingtree import WorkingTreeFormat2
1201
wt_format = WorkingTreeFormat2()
1202
# we don't warn here about upgrades; that ought to be handled for the
1204
return wt_format.open(self, _found=True)
1207
class BzrDir6(BzrDirPreSplitOut):
1208
"""A .bzr version 6 control object.
1210
This is a deprecated format and may be removed after sept 2006.
1213
def open_repository(self):
1214
"""See BzrDir.open_repository."""
1215
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1216
return RepositoryFormat6().open(self, _found=True)
1218
def open_workingtree(self, _unsupported=False,
1219
recommend_upgrade=True):
1220
"""See BzrDir.create_workingtree."""
1221
# we don't warn here about upgrades; that ought to be handled for the
1223
from bzrlib.workingtree import WorkingTreeFormat2
1224
return WorkingTreeFormat2().open(self, _found=True)
1227
class BzrDirMeta1(BzrDir):
1228
"""A .bzr meta version 1 control object.
1230
This is the first control object where the
1231
individual aspects are really split out: there are separate repository,
1232
workingtree and branch subdirectories and any subset of the three can be
1233
present within a BzrDir.
1236
def can_convert_format(self):
1237
"""See BzrDir.can_convert_format()."""
1240
def create_branch(self):
1241
"""See BzrDir.create_branch."""
1242
return self._format.get_branch_format().initialize(self)
1244
def destroy_branch(self):
1245
"""See BzrDir.create_branch."""
1246
self.transport.delete_tree('branch')
1248
def create_repository(self, shared=False):
1249
"""See BzrDir.create_repository."""
1250
return self._format.repository_format.initialize(self, shared)
1252
def destroy_repository(self):
1253
"""See BzrDir.destroy_repository."""
1254
self.transport.delete_tree('repository')
1256
def create_workingtree(self, revision_id=None, from_branch=None,
1257
accelerator_tree=None, hardlink=False):
1258
"""See BzrDir.create_workingtree."""
1259
return self._format.workingtree_format.initialize(
1260
self, revision_id, from_branch=from_branch,
1261
accelerator_tree=accelerator_tree, hardlink=hardlink)
1263
def destroy_workingtree(self):
1264
"""See BzrDir.destroy_workingtree."""
1265
wt = self.open_workingtree(recommend_upgrade=False)
1266
repository = wt.branch.repository
1267
empty = repository.revision_tree(_mod_revision.NULL_REVISION)
1268
wt.revert(old_tree=empty)
1269
self.destroy_workingtree_metadata()
1271
def destroy_workingtree_metadata(self):
1272
self.transport.delete_tree('checkout')
1274
def find_branch_format(self):
1275
"""Find the branch 'format' for this bzrdir.
1277
This might be a synthetic object for e.g. RemoteBranch and SVN.
1279
from bzrlib.branch import BranchFormat
1280
return BranchFormat.find_format(self)
1282
def _get_mkdir_mode(self):
1283
"""Figure out the mode to use when creating a bzrdir subdir."""
1284
temp_control = lockable_files.LockableFiles(self.transport, '',
1285
lockable_files.TransportLock)
1286
return temp_control._dir_mode
1288
def get_branch_reference(self):
1289
"""See BzrDir.get_branch_reference()."""
1290
from bzrlib.branch import BranchFormat
1291
format = BranchFormat.find_format(self)
1292
return format.get_reference(self)
1294
def get_branch_transport(self, branch_format):
1295
"""See BzrDir.get_branch_transport()."""
1296
if branch_format is None:
1297
return self.transport.clone('branch')
1299
branch_format.get_format_string()
1300
except NotImplementedError:
1301
raise errors.IncompatibleFormat(branch_format, self._format)
1303
self.transport.mkdir('branch', mode=self._get_mkdir_mode())
1304
except errors.FileExists:
1306
return self.transport.clone('branch')
1308
def get_repository_transport(self, repository_format):
1309
"""See BzrDir.get_repository_transport()."""
1310
if repository_format is None:
1311
return self.transport.clone('repository')
1313
repository_format.get_format_string()
1314
except NotImplementedError:
1315
raise errors.IncompatibleFormat(repository_format, self._format)
1317
self.transport.mkdir('repository', mode=self._get_mkdir_mode())
1318
except errors.FileExists:
1320
return self.transport.clone('repository')
1322
def get_workingtree_transport(self, workingtree_format):
1323
"""See BzrDir.get_workingtree_transport()."""
1324
if workingtree_format is None:
1325
return self.transport.clone('checkout')
1327
workingtree_format.get_format_string()
1328
except NotImplementedError:
1329
raise errors.IncompatibleFormat(workingtree_format, self._format)
1331
self.transport.mkdir('checkout', mode=self._get_mkdir_mode())
1332
except errors.FileExists:
1334
return self.transport.clone('checkout')
1336
def needs_format_conversion(self, format=None):
1337
"""See BzrDir.needs_format_conversion()."""
1339
format = BzrDirFormat.get_default_format()
1340
if not isinstance(self._format, format.__class__):
1341
# it is not a meta dir format, conversion is needed.
1343
# we might want to push this down to the repository?
1345
if not isinstance(self.open_repository()._format,
1346
format.repository_format.__class__):
1347
# the repository needs an upgrade.
1349
except errors.NoRepositoryPresent:
1352
if not isinstance(self.open_branch()._format,
1353
format.get_branch_format().__class__):
1354
# the branch needs an upgrade.
1356
except errors.NotBranchError:
1359
my_wt = self.open_workingtree(recommend_upgrade=False)
1360
if not isinstance(my_wt._format,
1361
format.workingtree_format.__class__):
1362
# the workingtree needs an upgrade.
1364
except (errors.NoWorkingTree, errors.NotLocalUrl):
1368
def open_branch(self, unsupported=False):
1369
"""See BzrDir.open_branch."""
1370
format = self.find_branch_format()
1371
self._check_supported(format, unsupported)
1372
return format.open(self, _found=True)
1374
def open_repository(self, unsupported=False):
1375
"""See BzrDir.open_repository."""
1376
from bzrlib.repository import RepositoryFormat
1377
format = RepositoryFormat.find_format(self)
1378
self._check_supported(format, unsupported)
1379
return format.open(self, _found=True)
1381
def open_workingtree(self, unsupported=False,
1382
recommend_upgrade=True):
1383
"""See BzrDir.open_workingtree."""
1384
from bzrlib.workingtree import WorkingTreeFormat
1385
format = WorkingTreeFormat.find_format(self)
1386
self._check_supported(format, unsupported,
1388
basedir=self.root_transport.base)
1389
return format.open(self, _found=True)
1392
class BzrDirFormat(object):
1393
"""An encapsulation of the initialization and open routines for a format.
1395
Formats provide three things:
1396
* An initialization routine,
1400
Formats are placed in a dict by their format string for reference
1401
during bzrdir opening. These should be subclasses of BzrDirFormat
1404
Once a format is deprecated, just deprecate the initialize and open
1405
methods on the format class. Do not deprecate the object, as the
1406
object will be created every system load.
1409
_default_format = None
1410
"""The default format used for new .bzr dirs."""
1413
"""The known formats."""
1415
_control_formats = []
1416
"""The registered control formats - .bzr, ....
1418
This is a list of BzrDirFormat objects.
1421
_control_server_formats = []
1422
"""The registered control server formats, e.g. RemoteBzrDirs.
1424
This is a list of BzrDirFormat objects.
1427
_lock_file_name = 'branch-lock'
1429
# _lock_class must be set in subclasses to the lock type, typ.
1430
# TransportLock or LockDir
1433
def find_format(klass, transport, _server_formats=True):
1434
"""Return the format present at transport."""
1436
formats = klass._control_server_formats + klass._control_formats
1438
formats = klass._control_formats
1439
for format in formats:
1441
return format.probe_transport(transport)
1442
except errors.NotBranchError:
1443
# this format does not find a control dir here.
1445
raise errors.NotBranchError(path=transport.base)
1448
def probe_transport(klass, transport):
1449
"""Return the .bzrdir style format present in a directory."""
1451
format_string = transport.get(".bzr/branch-format").read()
1452
except errors.NoSuchFile:
1453
raise errors.NotBranchError(path=transport.base)
1456
return klass._formats[format_string]
1458
raise errors.UnknownFormatError(format=format_string, kind='bzrdir')
1461
def get_default_format(klass):
1462
"""Return the current default format."""
1463
return klass._default_format
1465
def get_format_string(self):
1466
"""Return the ASCII format string that identifies this format."""
1467
raise NotImplementedError(self.get_format_string)
1469
def get_format_description(self):
1470
"""Return the short description for this format."""
1471
raise NotImplementedError(self.get_format_description)
1473
def get_converter(self, format=None):
1474
"""Return the converter to use to convert bzrdirs needing converts.
1476
This returns a bzrlib.bzrdir.Converter object.
1478
This should return the best upgrader to step this format towards the
1479
current default format. In the case of plugins we can/should provide
1480
some means for them to extend the range of returnable converters.
1482
:param format: Optional format to override the default format of the
1485
raise NotImplementedError(self.get_converter)
1487
def initialize(self, url, possible_transports=None):
1488
"""Create a bzr control dir at this url and return an opened copy.
1490
Subclasses should typically override initialize_on_transport
1491
instead of this method.
1493
return self.initialize_on_transport(get_transport(url,
1494
possible_transports))
1496
def initialize_on_transport(self, transport):
1497
"""Initialize a new bzrdir in the base directory of a Transport."""
1498
# Since we don't have a .bzr directory, inherit the
1499
# mode from the root directory
1500
temp_control = lockable_files.LockableFiles(transport,
1501
'', lockable_files.TransportLock)
1502
temp_control._transport.mkdir('.bzr',
1503
# FIXME: RBC 20060121 don't peek under
1505
mode=temp_control._dir_mode)
1506
if sys.platform == 'win32' and isinstance(transport, LocalTransport):
1507
win32utils.set_file_attr_hidden(transport._abspath('.bzr'))
1508
file_mode = temp_control._file_mode
1510
mutter('created control directory in ' + transport.base)
1511
control = transport.clone('.bzr')
1512
utf8_files = [('README',
1513
"This is a Bazaar control directory.\n"
1514
"Do not change any files in this directory.\n"
1515
"See http://bazaar-vcs.org/ for more information about Bazaar.\n"),
1516
('branch-format', self.get_format_string()),
1518
# NB: no need to escape relative paths that are url safe.
1519
control_files = lockable_files.LockableFiles(control,
1520
self._lock_file_name, self._lock_class)
1521
control_files.create_lock()
1522
control_files.lock_write()
1524
for file, content in utf8_files:
1525
control_files.put_utf8(file, content)
1527
control_files.unlock()
1528
return self.open(transport, _found=True)
1530
def is_supported(self):
1531
"""Is this format supported?
1533
Supported formats must be initializable and openable.
1534
Unsupported formats may not support initialization or committing or
1535
some other features depending on the reason for not being supported.
1539
def same_model(self, target_format):
1540
return (self.repository_format.rich_root_data ==
1541
target_format.rich_root_data)
1544
def known_formats(klass):
1545
"""Return all the known formats.
1547
Concrete formats should override _known_formats.
1549
# There is double indirection here to make sure that control
1550
# formats used by more than one dir format will only be probed
1551
# once. This can otherwise be quite expensive for remote connections.
1553
for format in klass._control_formats:
1554
result.update(format._known_formats())
1558
def _known_formats(klass):
1559
"""Return the known format instances for this control format."""
1560
return set(klass._formats.values())
1562
def open(self, transport, _found=False):
1563
"""Return an instance of this format for the dir transport points at.
1565
_found is a private parameter, do not use it.
1568
found_format = BzrDirFormat.find_format(transport)
1569
if not isinstance(found_format, self.__class__):
1570
raise AssertionError("%s was asked to open %s, but it seems to need "
1572
% (self, transport, found_format))
1573
return self._open(transport)
1575
def _open(self, transport):
1576
"""Template method helper for opening BzrDirectories.
1578
This performs the actual open and any additional logic or parameter
1581
raise NotImplementedError(self._open)
1584
def register_format(klass, format):
1585
klass._formats[format.get_format_string()] = format
1588
def register_control_format(klass, format):
1589
"""Register a format that does not use '.bzr' for its control dir.
1591
TODO: This should be pulled up into a 'ControlDirFormat' base class
1592
which BzrDirFormat can inherit from, and renamed to register_format
1593
there. It has been done without that for now for simplicity of
1596
klass._control_formats.append(format)
1599
def register_control_server_format(klass, format):
1600
"""Register a control format for client-server environments.
1602
These formats will be tried before ones registered with
1603
register_control_format. This gives implementations that decide to the
1604
chance to grab it before anything looks at the contents of the format
1607
klass._control_server_formats.append(format)
1610
def _set_default_format(klass, format):
1611
"""Set default format (for testing behavior of defaults only)"""
1612
klass._default_format = format
1616
return self.get_format_string().rstrip()
1619
def unregister_format(klass, format):
1620
del klass._formats[format.get_format_string()]
1623
def unregister_control_format(klass, format):
1624
klass._control_formats.remove(format)
1627
class BzrDirFormat4(BzrDirFormat):
1628
"""Bzr dir format 4.
1630
This format is a combined format for working tree, branch and repository.
1632
- Format 1 working trees [always]
1633
- Format 4 branches [always]
1634
- Format 4 repositories [always]
1636
This format is deprecated: it indexes texts using a text it which is
1637
removed in format 5; write support for this format has been removed.
1640
_lock_class = lockable_files.TransportLock
1642
def get_format_string(self):
1643
"""See BzrDirFormat.get_format_string()."""
1644
return "Bazaar-NG branch, format 0.0.4\n"
1646
def get_format_description(self):
1647
"""See BzrDirFormat.get_format_description()."""
1648
return "All-in-one format 4"
1650
def get_converter(self, format=None):
1651
"""See BzrDirFormat.get_converter()."""
1652
# there is one and only one upgrade path here.
1653
return ConvertBzrDir4To5()
1655
def initialize_on_transport(self, transport):
1656
"""Format 4 branches cannot be created."""
1657
raise errors.UninitializableFormat(self)
1659
def is_supported(self):
1660
"""Format 4 is not supported.
1662
It is not supported because the model changed from 4 to 5 and the
1663
conversion logic is expensive - so doing it on the fly was not
1668
def _open(self, transport):
1669
"""See BzrDirFormat._open."""
1670
return BzrDir4(transport, self)
1672
def __return_repository_format(self):
1673
"""Circular import protection."""
1674
from bzrlib.repofmt.weaverepo import RepositoryFormat4
1675
return RepositoryFormat4()
1676
repository_format = property(__return_repository_format)
1679
class BzrDirFormat5(BzrDirFormat):
1680
"""Bzr control format 5.
1682
This format is a combined format for working tree, branch and repository.
1684
- Format 2 working trees [always]
1685
- Format 4 branches [always]
1686
- Format 5 repositories [always]
1687
Unhashed stores in the repository.
1690
_lock_class = lockable_files.TransportLock
1692
def get_format_string(self):
1693
"""See BzrDirFormat.get_format_string()."""
1694
return "Bazaar-NG branch, format 5\n"
1696
def get_format_description(self):
1697
"""See BzrDirFormat.get_format_description()."""
1698
return "All-in-one format 5"
1700
def get_converter(self, format=None):
1701
"""See BzrDirFormat.get_converter()."""
1702
# there is one and only one upgrade path here.
1703
return ConvertBzrDir5To6()
1705
def _initialize_for_clone(self, url):
1706
return self.initialize_on_transport(get_transport(url), _cloning=True)
1708
def initialize_on_transport(self, transport, _cloning=False):
1709
"""Format 5 dirs always have working tree, branch and repository.
1711
Except when they are being cloned.
1713
from bzrlib.branch import BzrBranchFormat4
1714
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1715
from bzrlib.workingtree import WorkingTreeFormat2
1716
result = (super(BzrDirFormat5, self).initialize_on_transport(transport))
1717
RepositoryFormat5().initialize(result, _internal=True)
1719
branch = BzrBranchFormat4().initialize(result)
1721
WorkingTreeFormat2().initialize(result)
1722
except errors.NotLocalUrl:
1723
# Even though we can't access the working tree, we need to
1724
# create its control files.
1725
WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
1728
def _open(self, transport):
1729
"""See BzrDirFormat._open."""
1730
return BzrDir5(transport, self)
1732
def __return_repository_format(self):
1733
"""Circular import protection."""
1734
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1735
return RepositoryFormat5()
1736
repository_format = property(__return_repository_format)
1739
class BzrDirFormat6(BzrDirFormat):
1740
"""Bzr control format 6.
1742
This format is a combined format for working tree, branch and repository.
1744
- Format 2 working trees [always]
1745
- Format 4 branches [always]
1746
- Format 6 repositories [always]
1749
_lock_class = lockable_files.TransportLock
1751
def get_format_string(self):
1752
"""See BzrDirFormat.get_format_string()."""
1753
return "Bazaar-NG branch, format 6\n"
1755
def get_format_description(self):
1756
"""See BzrDirFormat.get_format_description()."""
1757
return "All-in-one format 6"
1759
def get_converter(self, format=None):
1760
"""See BzrDirFormat.get_converter()."""
1761
# there is one and only one upgrade path here.
1762
return ConvertBzrDir6ToMeta()
1764
def _initialize_for_clone(self, url):
1765
return self.initialize_on_transport(get_transport(url), _cloning=True)
1767
def initialize_on_transport(self, transport, _cloning=False):
1768
"""Format 6 dirs always have working tree, branch and repository.
1770
Except when they are being cloned.
1772
from bzrlib.branch import BzrBranchFormat4
1773
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1774
from bzrlib.workingtree import WorkingTreeFormat2
1775
result = super(BzrDirFormat6, self).initialize_on_transport(transport)
1776
RepositoryFormat6().initialize(result, _internal=True)
1778
branch = BzrBranchFormat4().initialize(result)
1780
WorkingTreeFormat2().initialize(result)
1781
except errors.NotLocalUrl:
1782
# Even though we can't access the working tree, we need to
1783
# create its control files.
1784
WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
1787
def _open(self, transport):
1788
"""See BzrDirFormat._open."""
1789
return BzrDir6(transport, self)
1791
def __return_repository_format(self):
1792
"""Circular import protection."""
1793
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1794
return RepositoryFormat6()
1795
repository_format = property(__return_repository_format)
1798
class BzrDirMetaFormat1(BzrDirFormat):
1799
"""Bzr meta control format 1
1801
This is the first format with split out working tree, branch and repository
1804
- Format 3 working trees [optional]
1805
- Format 5 branches [optional]
1806
- Format 7 repositories [optional]
1809
_lock_class = lockdir.LockDir
1812
self._workingtree_format = None
1813
self._branch_format = None
1815
def __eq__(self, other):
1816
if other.__class__ is not self.__class__:
1818
if other.repository_format != self.repository_format:
1820
if other.workingtree_format != self.workingtree_format:
1824
def __ne__(self, other):
1825
return not self == other
1827
def get_branch_format(self):
1828
if self._branch_format is None:
1829
from bzrlib.branch import BranchFormat
1830
self._branch_format = BranchFormat.get_default_format()
1831
return self._branch_format
1833
def set_branch_format(self, format):
1834
self._branch_format = format
1836
def get_converter(self, format=None):
1837
"""See BzrDirFormat.get_converter()."""
1839
format = BzrDirFormat.get_default_format()
1840
if not isinstance(self, format.__class__):
1841
# converting away from metadir is not implemented
1842
raise NotImplementedError(self.get_converter)
1843
return ConvertMetaToMeta(format)
1845
def get_format_string(self):
1846
"""See BzrDirFormat.get_format_string()."""
1847
return "Bazaar-NG meta directory, format 1\n"
1849
def get_format_description(self):
1850
"""See BzrDirFormat.get_format_description()."""
1851
return "Meta directory format 1"
1853
def _open(self, transport):
1854
"""See BzrDirFormat._open."""
1855
return BzrDirMeta1(transport, self)
1857
def __return_repository_format(self):
1858
"""Circular import protection."""
1859
if getattr(self, '_repository_format', None):
1860
return self._repository_format
1861
from bzrlib.repository import RepositoryFormat
1862
return RepositoryFormat.get_default_format()
1864
def __set_repository_format(self, value):
1865
"""Allow changing the repository format for metadir formats."""
1866
self._repository_format = value
1868
repository_format = property(__return_repository_format, __set_repository_format)
1870
def __get_workingtree_format(self):
1871
if self._workingtree_format is None:
1872
from bzrlib.workingtree import WorkingTreeFormat
1873
self._workingtree_format = WorkingTreeFormat.get_default_format()
1874
return self._workingtree_format
1876
def __set_workingtree_format(self, wt_format):
1877
self._workingtree_format = wt_format
1879
workingtree_format = property(__get_workingtree_format,
1880
__set_workingtree_format)
1883
# Register bzr control format
1884
BzrDirFormat.register_control_format(BzrDirFormat)
1886
# Register bzr formats
1887
BzrDirFormat.register_format(BzrDirFormat4())
1888
BzrDirFormat.register_format(BzrDirFormat5())
1889
BzrDirFormat.register_format(BzrDirFormat6())
1890
__default_format = BzrDirMetaFormat1()
1891
BzrDirFormat.register_format(__default_format)
1892
BzrDirFormat._default_format = __default_format
1895
class Converter(object):
1896
"""Converts a disk format object from one format to another."""
1898
def convert(self, to_convert, pb):
1899
"""Perform the conversion of to_convert, giving feedback via pb.
1901
:param to_convert: The disk object to convert.
1902
:param pb: a progress bar to use for progress information.
1905
def step(self, message):
1906
"""Update the pb by a step."""
1908
self.pb.update(message, self.count, self.total)
1911
class ConvertBzrDir4To5(Converter):
1912
"""Converts format 4 bzr dirs to format 5."""
1915
super(ConvertBzrDir4To5, self).__init__()
1916
self.converted_revs = set()
1917
self.absent_revisions = set()
1921
def convert(self, to_convert, pb):
1922
"""See Converter.convert()."""
1923
self.bzrdir = to_convert
1925
self.pb.note('starting upgrade from format 4 to 5')
1926
if isinstance(self.bzrdir.transport, LocalTransport):
1927
self.bzrdir.get_workingtree_transport(None).delete('stat-cache')
1928
self._convert_to_weaves()
1929
return BzrDir.open(self.bzrdir.root_transport.base)
1931
def _convert_to_weaves(self):
1932
self.pb.note('note: upgrade may be faster if all store files are ungzipped first')
1935
stat = self.bzrdir.transport.stat('weaves')
1936
if not S_ISDIR(stat.st_mode):
1937
self.bzrdir.transport.delete('weaves')
1938
self.bzrdir.transport.mkdir('weaves')
1939
except errors.NoSuchFile:
1940
self.bzrdir.transport.mkdir('weaves')
1941
# deliberately not a WeaveFile as we want to build it up slowly.
1942
self.inv_weave = Weave('inventory')
1943
# holds in-memory weaves for all files
1944
self.text_weaves = {}
1945
self.bzrdir.transport.delete('branch-format')
1946
self.branch = self.bzrdir.open_branch()
1947
self._convert_working_inv()
1948
rev_history = self.branch.revision_history()
1949
# to_read is a stack holding the revisions we still need to process;
1950
# appending to it adds new highest-priority revisions
1951
self.known_revisions = set(rev_history)
1952
self.to_read = rev_history[-1:]
1954
rev_id = self.to_read.pop()
1955
if (rev_id not in self.revisions
1956
and rev_id not in self.absent_revisions):
1957
self._load_one_rev(rev_id)
1959
to_import = self._make_order()
1960
for i, rev_id in enumerate(to_import):
1961
self.pb.update('converting revision', i, len(to_import))
1962
self._convert_one_rev(rev_id)
1964
self._write_all_weaves()
1965
self._write_all_revs()
1966
self.pb.note('upgraded to weaves:')
1967
self.pb.note(' %6d revisions and inventories', len(self.revisions))
1968
self.pb.note(' %6d revisions not present', len(self.absent_revisions))
1969
self.pb.note(' %6d texts', self.text_count)
1970
self._cleanup_spare_files_after_format4()
1971
self.branch.control_files.put_utf8('branch-format', BzrDirFormat5().get_format_string())
1973
def _cleanup_spare_files_after_format4(self):
1974
# FIXME working tree upgrade foo.
1975
for n in 'merged-patches', 'pending-merged-patches':
1977
## assert os.path.getsize(p) == 0
1978
self.bzrdir.transport.delete(n)
1979
except errors.NoSuchFile:
1981
self.bzrdir.transport.delete_tree('inventory-store')
1982
self.bzrdir.transport.delete_tree('text-store')
1984
def _convert_working_inv(self):
1985
inv = xml4.serializer_v4.read_inventory(
1986
self.branch.control_files.get('inventory'))
1987
new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv, working=True)
1988
# FIXME inventory is a working tree change.
1989
self.branch.control_files.put('inventory', StringIO(new_inv_xml))
1991
def _write_all_weaves(self):
1992
controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)
1993
weave_transport = self.bzrdir.transport.clone('weaves')
1994
weaves = WeaveStore(weave_transport, prefixed=False)
1995
transaction = WriteTransaction()
1999
for file_id, file_weave in self.text_weaves.items():
2000
self.pb.update('writing weave', i, len(self.text_weaves))
2001
weaves._put_weave(file_id, file_weave, transaction)
2003
self.pb.update('inventory', 0, 1)
2004
controlweaves._put_weave('inventory', self.inv_weave, transaction)
2005
self.pb.update('inventory', 1, 1)
2009
def _write_all_revs(self):
2010
"""Write all revisions out in new form."""
2011
self.bzrdir.transport.delete_tree('revision-store')
2012
self.bzrdir.transport.mkdir('revision-store')
2013
revision_transport = self.bzrdir.transport.clone('revision-store')
2015
_revision_store = TextRevisionStore(TextStore(revision_transport,
2019
transaction = WriteTransaction()
2020
for i, rev_id in enumerate(self.converted_revs):
2021
self.pb.update('write revision', i, len(self.converted_revs))
2022
_revision_store.add_revision(self.revisions[rev_id], transaction)
2026
def _load_one_rev(self, rev_id):
2027
"""Load a revision object into memory.
2029
Any parents not either loaded or abandoned get queued to be
2031
self.pb.update('loading revision',
2032
len(self.revisions),
2033
len(self.known_revisions))
2034
if not self.branch.repository.has_revision(rev_id):
2036
self.pb.note('revision {%s} not present in branch; '
2037
'will be converted as a ghost',
2039
self.absent_revisions.add(rev_id)
2041
rev = self.branch.repository._revision_store.get_revision(rev_id,
2042
self.branch.repository.get_transaction())
2043
for parent_id in rev.parent_ids:
2044
self.known_revisions.add(parent_id)
2045
self.to_read.append(parent_id)
2046
self.revisions[rev_id] = rev
2048
def _load_old_inventory(self, rev_id):
2049
old_inv_xml = self.branch.repository.inventory_store.get(rev_id).read()
2050
inv = xml4.serializer_v4.read_inventory_from_string(old_inv_xml)
2051
inv.revision_id = rev_id
2052
rev = self.revisions[rev_id]
2055
def _load_updated_inventory(self, rev_id):
2056
inv_xml = self.inv_weave.get_text(rev_id)
2057
inv = xml5.serializer_v5.read_inventory_from_string(inv_xml, rev_id)
2060
def _convert_one_rev(self, rev_id):
2061
"""Convert revision and all referenced objects to new format."""
2062
rev = self.revisions[rev_id]
2063
inv = self._load_old_inventory(rev_id)
2064
present_parents = [p for p in rev.parent_ids
2065
if p not in self.absent_revisions]
2066
self._convert_revision_contents(rev, inv, present_parents)
2067
self._store_new_inv(rev, inv, present_parents)
2068
self.converted_revs.add(rev_id)
2070
def _store_new_inv(self, rev, inv, present_parents):
2071
new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
2072
new_inv_sha1 = sha_string(new_inv_xml)
2073
self.inv_weave.add_lines(rev.revision_id,
2075
new_inv_xml.splitlines(True))
2076
rev.inventory_sha1 = new_inv_sha1
2078
def _convert_revision_contents(self, rev, inv, present_parents):
2079
"""Convert all the files within a revision.
2081
Also upgrade the inventory to refer to the text revision ids."""
2082
rev_id = rev.revision_id
2083
mutter('converting texts of revision {%s}',
2085
parent_invs = map(self._load_updated_inventory, present_parents)
2086
entries = inv.iter_entries()
2088
for path, ie in entries:
2089
self._convert_file_version(rev, ie, parent_invs)
2091
def _convert_file_version(self, rev, ie, parent_invs):
2092
"""Convert one version of one file.
2094
The file needs to be added into the weave if it is a merge
2095
of >=2 parents or if it's changed from its parent.
2097
file_id = ie.file_id
2098
rev_id = rev.revision_id
2099
w = self.text_weaves.get(file_id)
2102
self.text_weaves[file_id] = w
2103
text_changed = False
2104
parent_candiate_entries = ie.parent_candidates(parent_invs)
2105
heads = graph.Graph(self).heads(parent_candiate_entries.keys())
2106
# XXX: Note that this is unordered - and this is tolerable because
2107
# the previous code was also unordered.
2108
previous_entries = dict((head, parent_candiate_entries[head]) for head
2110
self.snapshot_ie(previous_entries, ie, w, rev_id)
2113
@symbol_versioning.deprecated_method(symbol_versioning.one_one)
2114
def get_parents(self, revision_ids):
2115
for revision_id in revision_ids:
2116
yield self.revisions[revision_id].parent_ids
2118
def get_parent_map(self, revision_ids):
2119
"""See graph._StackedParentsProvider.get_parent_map"""
2120
return dict((revision_id, self.revisions[revision_id])
2121
for revision_id in revision_ids
2122
if revision_id in self.revisions)
2124
def snapshot_ie(self, previous_revisions, ie, w, rev_id):
2125
# TODO: convert this logic, which is ~= snapshot to
2126
# a call to:. This needs the path figured out. rather than a work_tree
2127
# a v4 revision_tree can be given, or something that looks enough like
2128
# one to give the file content to the entry if it needs it.
2129
# and we need something that looks like a weave store for snapshot to
2131
#ie.snapshot(rev, PATH, previous_revisions, REVISION_TREE, InMemoryWeaveStore(self.text_weaves))
2132
if len(previous_revisions) == 1:
2133
previous_ie = previous_revisions.values()[0]
2134
if ie._unchanged(previous_ie):
2135
ie.revision = previous_ie.revision
2138
text = self.branch.repository.weave_store.get(ie.text_id)
2139
file_lines = text.readlines()
2140
w.add_lines(rev_id, previous_revisions, file_lines)
2141
self.text_count += 1
2143
w.add_lines(rev_id, previous_revisions, [])
2144
ie.revision = rev_id
2146
def _make_order(self):
2147
"""Return a suitable order for importing revisions.
2149
The order must be such that an revision is imported after all
2150
its (present) parents.
2152
todo = set(self.revisions.keys())
2153
done = self.absent_revisions.copy()
2156
# scan through looking for a revision whose parents
2158
for rev_id in sorted(list(todo)):
2159
rev = self.revisions[rev_id]
2160
parent_ids = set(rev.parent_ids)
2161
if parent_ids.issubset(done):
2162
# can take this one now
2163
order.append(rev_id)
2169
class ConvertBzrDir5To6(Converter):
2170
"""Converts format 5 bzr dirs to format 6."""
2172
def convert(self, to_convert, pb):
2173
"""See Converter.convert()."""
2174
self.bzrdir = to_convert
2176
self.pb.note('starting upgrade from format 5 to 6')
2177
self._convert_to_prefixed()
2178
return BzrDir.open(self.bzrdir.root_transport.base)
2180
def _convert_to_prefixed(self):
2181
from bzrlib.store import TransportStore
2182
self.bzrdir.transport.delete('branch-format')
2183
for store_name in ["weaves", "revision-store"]:
2184
self.pb.note("adding prefixes to %s" % store_name)
2185
store_transport = self.bzrdir.transport.clone(store_name)
2186
store = TransportStore(store_transport, prefixed=True)
2187
for urlfilename in store_transport.list_dir('.'):
2188
filename = urlutils.unescape(urlfilename)
2189
if (filename.endswith(".weave") or
2190
filename.endswith(".gz") or
2191
filename.endswith(".sig")):
2192
file_id, suffix = os.path.splitext(filename)
2196
new_name = store._mapper.map((file_id,)) + suffix
2197
# FIXME keep track of the dirs made RBC 20060121
2199
store_transport.move(filename, new_name)
2200
except errors.NoSuchFile: # catches missing dirs strangely enough
2201
store_transport.mkdir(osutils.dirname(new_name))
2202
store_transport.move(filename, new_name)
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
medium = transport.get_smart_medium()
2392
except (NotImplementedError, AttributeError,
2393
errors.TransportNotPossible, errors.NoSmartMedium):
2394
# no smart server, so not a branch for this format type.
2395
raise errors.NotBranchError(path=transport.base)
2397
# Decline to open it if the server doesn't support our required
2398
# version (2) so that the VFS-based transport will do it.
2400
server_version = medium.protocol_version()
2401
except errors.SmartProtocolError:
2402
# Apparently there's no usable smart server there, even though
2403
# the medium supports the smart protocol.
2404
raise errors.NotBranchError(path=transport.base)
2405
if server_version != 2:
2406
raise errors.NotBranchError(path=transport.base)
2409
def initialize_on_transport(self, transport):
2411
# hand off the request to the smart server
2412
client_medium = transport.get_smart_medium()
2413
except errors.NoSmartMedium:
2414
# TODO: lookup the local format from a server hint.
2415
local_dir_format = BzrDirMetaFormat1()
2416
return local_dir_format.initialize_on_transport(transport)
2417
client = _SmartClient(client_medium, transport.base)
2418
path = client.remote_path_from_transport(transport)
2419
response = client.call('BzrDirFormat.initialize', path)
2420
if response[0] != 'ok':
2421
raise errors.SmartProtocolError('unexpected response code %s' % (response,))
2422
return remote.RemoteBzrDir(transport)
2424
def _open(self, transport):
2425
return remote.RemoteBzrDir(transport)
2427
def __eq__(self, other):
2428
if not isinstance(other, RemoteBzrDirFormat):
2430
return self.get_format_description() == other.get_format_description()
2433
BzrDirFormat.register_control_server_format(RemoteBzrDirFormat)
2436
class BzrDirFormatInfo(object):
2438
def __init__(self, native, deprecated, hidden, experimental):
2439
self.deprecated = deprecated
2440
self.native = native
2441
self.hidden = hidden
2442
self.experimental = experimental
2445
class BzrDirFormatRegistry(registry.Registry):
2446
"""Registry of user-selectable BzrDir subformats.
2448
Differs from BzrDirFormat._control_formats in that it provides sub-formats,
2449
e.g. BzrDirMeta1 with weave repository. Also, it's more user-oriented.
2453
"""Create a BzrDirFormatRegistry."""
2454
self._aliases = set()
2455
super(BzrDirFormatRegistry, self).__init__()
2458
"""Return a set of the format names which are aliases."""
2459
return frozenset(self._aliases)
2461
def register_metadir(self, key,
2462
repository_format, help, native=True, deprecated=False,
2468
"""Register a metadir subformat.
2470
These all use a BzrDirMetaFormat1 bzrdir, but can be parameterized
2471
by the Repository format.
2473
:param repository_format: The fully-qualified repository format class
2475
:param branch_format: Fully-qualified branch format class name as
2477
:param tree_format: Fully-qualified tree format class name as
2480
# This should be expanded to support setting WorkingTree and Branch
2481
# formats, once BzrDirMetaFormat1 supports that.
2482
def _load(full_name):
2483
mod_name, factory_name = full_name.rsplit('.', 1)
2485
mod = __import__(mod_name, globals(), locals(),
2487
except ImportError, e:
2488
raise ImportError('failed to load %s: %s' % (full_name, e))
2490
factory = getattr(mod, factory_name)
2491
except AttributeError:
2492
raise AttributeError('no factory %s in module %r'
2497
bd = BzrDirMetaFormat1()
2498
if branch_format is not None:
2499
bd.set_branch_format(_load(branch_format))
2500
if tree_format is not None:
2501
bd.workingtree_format = _load(tree_format)
2502
if repository_format is not None:
2503
bd.repository_format = _load(repository_format)
2505
self.register(key, helper, help, native, deprecated, hidden,
2506
experimental, alias)
2508
def register(self, key, factory, help, native=True, deprecated=False,
2509
hidden=False, experimental=False, alias=False):
2510
"""Register a BzrDirFormat factory.
2512
The factory must be a callable that takes one parameter: the key.
2513
It must produce an instance of the BzrDirFormat when called.
2515
This function mainly exists to prevent the info object from being
2518
registry.Registry.register(self, key, factory, help,
2519
BzrDirFormatInfo(native, deprecated, hidden, experimental))
2521
self._aliases.add(key)
2523
def register_lazy(self, key, module_name, member_name, help, native=True,
2524
deprecated=False, hidden=False, experimental=False, alias=False):
2525
registry.Registry.register_lazy(self, key, module_name, member_name,
2526
help, BzrDirFormatInfo(native, deprecated, hidden, experimental))
2528
self._aliases.add(key)
2530
def set_default(self, key):
2531
"""Set the 'default' key to be a clone of the supplied key.
2533
This method must be called once and only once.
2535
registry.Registry.register(self, 'default', self.get(key),
2536
self.get_help(key), info=self.get_info(key))
2537
self._aliases.add('default')
2539
def set_default_repository(self, key):
2540
"""Set the FormatRegistry default and Repository default.
2542
This is a transitional method while Repository.set_default_format
2545
if 'default' in self:
2546
self.remove('default')
2547
self.set_default(key)
2548
format = self.get('default')()
2550
def make_bzrdir(self, key):
2551
return self.get(key)()
2553
def help_topic(self, topic):
2554
output = textwrap.dedent("""\
2555
These formats can be used for creating branches, working trees, and
2559
default_realkey = None
2560
default_help = self.get_help('default')
2562
for key in self.keys():
2563
if key == 'default':
2565
help = self.get_help(key)
2566
if help == default_help:
2567
default_realkey = key
2569
help_pairs.append((key, help))
2571
def wrapped(key, help, info):
2573
help = '(native) ' + help
2574
return ':%s:\n%s\n\n' % (key,
2575
textwrap.fill(help, initial_indent=' ',
2576
subsequent_indent=' '))
2577
if default_realkey is not None:
2578
output += wrapped(default_realkey, '(default) %s' % default_help,
2579
self.get_info('default'))
2580
deprecated_pairs = []
2581
experimental_pairs = []
2582
for key, help in help_pairs:
2583
info = self.get_info(key)
2586
elif info.deprecated:
2587
deprecated_pairs.append((key, help))
2588
elif info.experimental:
2589
experimental_pairs.append((key, help))
2591
output += wrapped(key, help, info)
2592
if len(experimental_pairs) > 0:
2593
output += "Experimental formats are shown below.\n\n"
2594
for key, help in experimental_pairs:
2595
info = self.get_info(key)
2596
output += wrapped(key, help, info)
2597
if len(deprecated_pairs) > 0:
2598
output += "Deprecated formats are shown below.\n\n"
2599
for key, help in deprecated_pairs:
2600
info = self.get_info(key)
2601
output += wrapped(key, help, info)
2606
class RepositoryAcquisitionPolicy(object):
2607
"""Abstract base class for repository acquisition policies.
2609
A repository acquisition policy decides how a BzrDir acquires a repository
2610
for a branch that is being created. The most basic policy decision is
2611
whether to create a new repository or use an existing one.
2614
def configure_branch(self, branch):
2615
"""Apply any configuration data from this policy to the branch.
2617
Default implementation does nothing.
2621
def acquire_repository(self, make_working_trees=None, shared=False):
2622
"""Acquire a repository for this bzrdir.
2624
Implementations may create a new repository or use a pre-exising
2626
:param make_working_trees: If creating a repository, set
2627
make_working_trees to this value (if non-None)
2628
:param shared: If creating a repository, make it shared if True
2629
:return: A repository
2631
raise NotImplemented(RepositoryAcquisitionPolicy.acquire_repository)
2634
class CreateRepository(RepositoryAcquisitionPolicy):
2635
"""A policy of creating a new repository"""
2637
def __init__(self, bzrdir):
2638
RepositoryAcquisitionPolicy.__init__(self)
2639
self._bzrdir = bzrdir
2641
def acquire_repository(self, make_working_trees=None, shared=False):
2642
"""Implementation of RepositoryAcquisitionPolicy.acquire_repository
2644
Creates the desired repository in the bzrdir we already have.
2646
repository = self._bzrdir.create_repository(shared=shared)
2647
if make_working_trees is not None:
2648
repository.set_make_working_trees(make_working_trees)
2652
class UseExistingRepository(RepositoryAcquisitionPolicy):
2653
"""A policy of reusing an existing repository"""
2655
def __init__(self, repository):
2656
RepositoryAcquisitionPolicy.__init__(self)
2657
self._repository = repository
2659
def acquire_repository(self, make_working_trees=None, shared=False):
2660
"""Implementation of RepositoryAcquisitionPolicy.acquire_repository
2662
Returns an existing repository to use
2664
return self._repository
2667
format_registry = BzrDirFormatRegistry()
2668
format_registry.register('weave', BzrDirFormat6,
2669
'Pre-0.8 format. Slower than knit and does not'
2670
' support checkouts or shared repositories.',
2672
format_registry.register_metadir('knit',
2673
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2674
'Format using knits. Recommended for interoperation with bzr <= 0.14.',
2675
branch_format='bzrlib.branch.BzrBranchFormat5',
2676
tree_format='bzrlib.workingtree.WorkingTreeFormat3')
2677
format_registry.register_metadir('metaweave',
2678
'bzrlib.repofmt.weaverepo.RepositoryFormat7',
2679
'Transitional format in 0.8. Slower than knit.',
2680
branch_format='bzrlib.branch.BzrBranchFormat5',
2681
tree_format='bzrlib.workingtree.WorkingTreeFormat3',
2683
format_registry.register_metadir('dirstate',
2684
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2685
help='New in 0.15: Fast local operations. Compatible with bzr 0.8 and '
2686
'above when accessed over the network.',
2687
branch_format='bzrlib.branch.BzrBranchFormat5',
2688
# this uses bzrlib.workingtree.WorkingTreeFormat4 because importing
2689
# directly from workingtree_4 triggers a circular import.
2690
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2692
format_registry.register_metadir('dirstate-tags',
2693
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2694
help='New in 0.15: Fast local operations and improved scaling for '
2695
'network operations. Additionally adds support for tags.'
2696
' Incompatible with bzr < 0.15.',
2697
branch_format='bzrlib.branch.BzrBranchFormat6',
2698
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2700
format_registry.register_metadir('rich-root',
2701
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit4',
2702
help='New in 1.0. Better handling of tree roots. Incompatible with'
2704
branch_format='bzrlib.branch.BzrBranchFormat6',
2705
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2707
format_registry.register_metadir('dirstate-with-subtree',
2708
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
2709
help='New in 0.15: Fast local operations and improved scaling for '
2710
'network operations. Additionally adds support for versioning nested '
2711
'bzr branches. Incompatible with bzr < 0.15.',
2712
branch_format='bzrlib.branch.BzrBranchFormat6',
2713
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2717
format_registry.register_metadir('pack-0.92',
2718
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack1',
2719
help='New in 0.92: Pack-based format with data compatible with '
2720
'dirstate-tags format repositories. Interoperates with '
2721
'bzr repositories before 0.92 but cannot be read by bzr < 0.92. '
2722
'Previously called knitpack-experimental. '
2723
'For more information, see '
2724
'http://doc.bazaar-vcs.org/latest/developers/packrepo.html.',
2725
branch_format='bzrlib.branch.BzrBranchFormat6',
2726
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2728
format_registry.register_metadir('pack-0.92-subtree',
2729
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack3',
2730
help='New in 0.92: Pack-based format with data compatible with '
2731
'dirstate-with-subtree format repositories. Interoperates with '
2732
'bzr repositories before 0.92 but cannot be read by bzr < 0.92. '
2733
'Previously called knitpack-experimental. '
2734
'For more information, see '
2735
'http://doc.bazaar-vcs.org/latest/developers/packrepo.html.',
2736
branch_format='bzrlib.branch.BzrBranchFormat6',
2737
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2741
format_registry.register_metadir('rich-root-pack',
2742
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack4',
2743
help='New in 1.0: Pack-based format with data compatible with '
2744
'rich-root format repositories. Incompatible with'
2746
branch_format='bzrlib.branch.BzrBranchFormat6',
2747
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2749
# The following two formats should always just be aliases.
2750
format_registry.register_metadir('development',
2751
'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment0',
2752
help='Current development format. Can convert data to and from pack-0.92 '
2753
'(and anything compatible with pack-0.92) format repositories. '
2754
'Repositories in this format can only be read by bzr.dev. '
2756
'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
2758
branch_format='bzrlib.branch.BzrBranchFormat6',
2759
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2763
format_registry.register_metadir('development-subtree',
2764
'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment0Subtree',
2765
help='Current development format, subtree variant. Can convert data to and '
2766
'from pack-0.92 (and anything compatible with pack-0.92) format '
2767
'repositories. Repositories in this format can only be read by '
2768
'bzr.dev. Please read '
2769
'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
2771
branch_format='bzrlib.branch.BzrBranchFormat6',
2772
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2776
# And the development formats which the will have aliased one of follow:
2777
format_registry.register_metadir('development0',
2778
'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment0',
2779
help='Trivial rename of pack-0.92 to provide a development format. '
2781
'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
2783
branch_format='bzrlib.branch.BzrBranchFormat6',
2784
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2788
format_registry.register_metadir('development0-subtree',
2789
'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment0Subtree',
2790
help='Trivial rename of pack-0.92-subtree to provide a development format. '
2792
'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
2794
branch_format='bzrlib.branch.BzrBranchFormat6',
2795
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2799
format_registry.set_default('pack-0.92')