1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
"""BzrDir logic. The BzrDir is the basic control directory used by bzr.
19
At format 7 this was split out into Branch, Repository and Checkout control
22
Note: This module has a lot of ``open`` functions/methods that return
23
references to in-memory objects. As a rule, there are no matching ``close``
24
methods. To free any associated resources, simply stop referencing the
28
# TODO: Move old formats into a plugin to make this file smaller.
30
from cStringIO import StringIO
34
from bzrlib.lazy_import import lazy_import
35
lazy_import(globals(), """
36
from stat import S_ISDIR
38
from warnings import warn
48
revision as _mod_revision,
58
from bzrlib.osutils import (
62
from bzrlib.smart.client import _SmartClient
63
from bzrlib.smart import protocol
64
from bzrlib.store.revision.text import TextRevisionStore
65
from bzrlib.store.text import TextStore
66
from bzrlib.store.versioned import WeaveStore
67
from bzrlib.transactions import WriteTransaction
68
from bzrlib.transport import (
69
do_catching_redirections,
72
from bzrlib.weave import Weave
75
from bzrlib.trace import (
79
from bzrlib.transport.local import LocalTransport
80
from bzrlib.symbol_versioning import (
88
"""A .bzr control diretory.
90
BzrDir instances let you create or open any of the things that can be
91
found within .bzr - checkouts, branches and repositories.
94
the transport which this bzr dir is rooted at (i.e. file:///.../.bzr/)
96
a transport connected to the directory this bzr was opened from
97
(i.e. the parent directory holding the .bzr directory).
100
def break_lock(self):
101
"""Invoke break_lock on the first object in the bzrdir.
103
If there is a tree, the tree is opened and break_lock() called.
104
Otherwise, branch is tried, and finally repository.
106
# XXX: This seems more like a UI function than something that really
107
# belongs in this class.
109
thing_to_unlock = self.open_workingtree()
110
except (errors.NotLocalUrl, errors.NoWorkingTree):
112
thing_to_unlock = self.open_branch()
113
except errors.NotBranchError:
115
thing_to_unlock = self.open_repository()
116
except errors.NoRepositoryPresent:
118
thing_to_unlock.break_lock()
120
def can_convert_format(self):
121
"""Return true if this bzrdir is one whose format we can convert from."""
124
def check_conversion_target(self, target_format):
125
target_repo_format = target_format.repository_format
126
source_repo_format = self._format.repository_format
127
source_repo_format.check_conversion_target(target_repo_format)
130
def _check_supported(format, allow_unsupported,
131
recommend_upgrade=True,
133
"""Give an error or warning on old formats.
135
:param format: may be any kind of format - workingtree, branch,
138
:param allow_unsupported: If true, allow opening
139
formats that are strongly deprecated, and which may
140
have limited functionality.
142
:param recommend_upgrade: If true (default), warn
143
the user through the ui object that they may wish
144
to upgrade the object.
146
# TODO: perhaps move this into a base Format class; it's not BzrDir
147
# specific. mbp 20070323
148
if not allow_unsupported and not format.is_supported():
149
# see open_downlevel to open legacy branches.
150
raise errors.UnsupportedFormatError(format=format)
151
if recommend_upgrade \
152
and getattr(format, 'upgrade_recommended', False):
153
ui.ui_factory.recommend_upgrade(
154
format.get_format_description(),
157
def clone(self, url, revision_id=None, force_new_repo=False):
158
"""Clone this bzrdir and its contents to url verbatim.
160
If url's last component does not exist, it will be created.
162
if revision_id is not None, then the clone operation may tune
163
itself to download less data.
164
:param force_new_repo: Do not use a shared repository for the target
165
even if one is available.
167
return self.clone_on_transport(get_transport(url),
168
revision_id=revision_id,
169
force_new_repo=force_new_repo)
171
def clone_on_transport(self, transport, revision_id=None,
172
force_new_repo=False):
173
"""Clone this bzrdir and its contents to transport verbatim.
175
If the target directory does not exist, it will be created.
177
if revision_id is not None, then the clone operation may tune
178
itself to download less data.
179
:param force_new_repo: Do not use a shared repository for the target
180
even if one is available.
182
from remote import RemoteBzrDir
183
transport.ensure_base()
184
result = self.cloning_metadir().initialize_on_transport(transport)
185
repository_policy = None
187
local_repo = self.find_repository()
188
except errors.NoRepositoryPresent:
191
# may need to copy content in
192
repository_policy = result.determine_repository_policy(
194
make_working_trees = local_repo.make_working_trees()
195
if isinstance(result, RemoteBzrDir):
196
make_working_trees = None
197
result_repo = repository_policy.acquire_repository(
198
make_working_trees, local_repo.is_shared())
199
result_repo.fetch(local_repo, revision_id=revision_id)
200
# 1 if there is a branch present
201
# make sure its content is available in the target repository
204
local_branch = self.open_branch()
205
except errors.NotBranchError:
208
result_branch = local_branch.clone(result, revision_id=revision_id)
209
if repository_policy is not None:
210
repository_policy.configure_branch(result_branch)
212
result_repo = result.find_repository()
213
except errors.NoRepositoryPresent:
215
if result_repo is None or result_repo.make_working_trees():
217
self.open_workingtree().clone(result)
218
except (errors.NoWorkingTree, errors.NotLocalUrl):
222
# TODO: This should be given a Transport, and should chdir up; otherwise
223
# this will open a new connection.
224
def _make_tail(self, url):
225
t = get_transport(url)
229
def create(cls, base, format=None, possible_transports=None):
230
"""Create a new BzrDir at the url 'base'.
232
:param format: If supplied, the format of branch to create. If not
233
supplied, the default is used.
234
:param possible_transports: If supplied, a list of transports that
235
can be reused to share a remote connection.
237
if cls is not BzrDir:
238
raise AssertionError("BzrDir.create always creates the default"
239
" format, not one of %r" % cls)
240
t = get_transport(base, possible_transports)
243
format = BzrDirFormat.get_default_format()
244
return format.initialize_on_transport(t)
247
def find_bzrdirs(transport, evaluate=None, list_current=None):
248
"""Find bzrdirs recursively from current location.
250
This is intended primarily as a building block for more sophisticated
251
functionality, like finding trees under a directory, or finding
252
branches that use a given repository.
253
:param evaluate: An optional callable that yields recurse, value,
254
where recurse controls whether this bzrdir is recursed into
255
and value is the value to yield. By default, all bzrdirs
256
are recursed into, and the return value is the bzrdir.
257
:param list_current: if supplied, use this function to list the current
258
directory, instead of Transport.list_dir
259
:return: a generator of found bzrdirs, or whatever evaluate returns.
261
if list_current is None:
262
def list_current(transport):
263
return transport.list_dir('')
265
def evaluate(bzrdir):
268
pending = [transport]
269
while len(pending) > 0:
270
current_transport = pending.pop()
273
bzrdir = BzrDir.open_from_transport(current_transport)
274
except errors.NotBranchError:
277
recurse, value = evaluate(bzrdir)
280
subdirs = list_current(current_transport)
281
except errors.NoSuchFile:
284
for subdir in sorted(subdirs, reverse=True):
285
pending.append(current_transport.clone(subdir))
288
def find_branches(transport):
289
"""Find all branches under a transport.
291
This will find all branches below the transport, including branches
292
inside other branches. Where possible, it will use
293
Repository.find_branches.
295
To list all the branches that use a particular Repository, see
296
Repository.find_branches
298
def evaluate(bzrdir):
300
repository = bzrdir.open_repository()
301
except errors.NoRepositoryPresent:
304
return False, (None, repository)
306
branch = bzrdir.open_branch()
307
except errors.NotBranchError:
308
return True, (None, None)
310
return True, (branch, None)
312
for branch, repo in BzrDir.find_bzrdirs(transport, evaluate=evaluate):
314
branches.extend(repo.find_branches())
315
if branch is not None:
316
branches.append(branch)
320
def destroy_repository(self):
321
"""Destroy the repository in this BzrDir"""
322
raise NotImplementedError(self.destroy_repository)
324
def create_branch(self):
325
"""Create a branch in this BzrDir.
327
The bzrdir's format will control what branch format is created.
328
For more control see BranchFormatXX.create(a_bzrdir).
330
raise NotImplementedError(self.create_branch)
332
def destroy_branch(self):
333
"""Destroy the branch in this BzrDir"""
334
raise NotImplementedError(self.destroy_branch)
337
def create_branch_and_repo(base, force_new_repo=False, format=None):
338
"""Create a new BzrDir, Branch and Repository at the url 'base'.
340
This will use the current default BzrDirFormat unless one is
341
specified, and use whatever
342
repository format that that uses via bzrdir.create_branch and
343
create_repository. If a shared repository is available that is used
346
The created Branch object is returned.
348
:param base: The URL to create the branch at.
349
:param force_new_repo: If True a new repository is always created.
350
:param format: If supplied, the format of branch to create. If not
351
supplied, the default is used.
353
bzrdir = BzrDir.create(base, format)
354
bzrdir._find_or_create_repository(force_new_repo)
355
return bzrdir.create_branch()
357
def determine_repository_policy(self, force_new_repo=False):
358
"""Return an object representing a policy to use.
360
This controls whether a new repository is created, or a shared
361
repository used instead.
363
def repository_policy(found_bzrdir):
365
# does it have a repository ?
367
repository = found_bzrdir.open_repository()
368
except errors.NoRepositoryPresent:
371
if ((found_bzrdir.root_transport.base !=
372
self.root_transport.base) and not repository.is_shared()):
379
return UseExistingRepository(repository), True
381
return CreateRepository(self), True
383
if not force_new_repo:
384
policy = self._find_containing(repository_policy)
385
if policy is not None:
387
return CreateRepository(self)
389
def _find_or_create_repository(self, force_new_repo):
390
"""Create a new repository if needed, returning the repository."""
391
policy = self.determine_repository_policy(force_new_repo)
392
return policy.acquire_repository()
395
def create_branch_convenience(base, force_new_repo=False,
396
force_new_tree=None, format=None,
397
possible_transports=None):
398
"""Create a new BzrDir, Branch and Repository at the url 'base'.
400
This is a convenience function - it will use an existing repository
401
if possible, can be told explicitly whether to create a working tree or
404
This will use the current default BzrDirFormat unless one is
405
specified, and use whatever
406
repository format that that uses via bzrdir.create_branch and
407
create_repository. If a shared repository is available that is used
408
preferentially. Whatever repository is used, its tree creation policy
411
The created Branch object is returned.
412
If a working tree cannot be made due to base not being a file:// url,
413
no error is raised unless force_new_tree is True, in which case no
414
data is created on disk and NotLocalUrl is raised.
416
:param base: The URL to create the branch at.
417
:param force_new_repo: If True a new repository is always created.
418
:param force_new_tree: If True or False force creation of a tree or
419
prevent such creation respectively.
420
:param format: Override for the bzrdir format to create.
421
:param possible_transports: An optional reusable transports list.
424
# check for non local urls
425
t = get_transport(base, possible_transports)
426
if not isinstance(t, LocalTransport):
427
raise errors.NotLocalUrl(base)
428
bzrdir = BzrDir.create(base, format, possible_transports)
429
repo = bzrdir._find_or_create_repository(force_new_repo)
430
result = bzrdir.create_branch()
431
if force_new_tree or (repo.make_working_trees() and
432
force_new_tree is None):
434
bzrdir.create_workingtree()
435
except errors.NotLocalUrl:
440
@deprecated_function(zero_ninetyone)
441
def create_repository(base, shared=False, format=None):
442
"""Create a new BzrDir and Repository at the url 'base'.
444
If no format is supplied, this will default to the current default
445
BzrDirFormat by default, and use whatever repository format that that
446
uses for bzrdirformat.create_repository.
448
:param shared: Create a shared repository rather than a standalone
450
The Repository object is returned.
452
This must be overridden as an instance method in child classes, where
453
it should take no parameters and construct whatever repository format
454
that child class desires.
456
This method is deprecated, please call create_repository on a bzrdir
459
bzrdir = BzrDir.create(base, format)
460
return bzrdir.create_repository(shared)
463
def create_standalone_workingtree(base, format=None):
464
"""Create a new BzrDir, WorkingTree, Branch and Repository at 'base'.
466
'base' must be a local path or a file:// url.
468
This will use the current default BzrDirFormat unless one is
469
specified, and use whatever
470
repository format that that uses for bzrdirformat.create_workingtree,
471
create_branch and create_repository.
473
:param format: Override for the bzrdir format to create.
474
:return: The WorkingTree object.
476
t = get_transport(base)
477
if not isinstance(t, LocalTransport):
478
raise errors.NotLocalUrl(base)
479
bzrdir = BzrDir.create_branch_and_repo(base,
481
format=format).bzrdir
482
return bzrdir.create_workingtree()
484
def create_workingtree(self, revision_id=None, from_branch=None,
485
accelerator_tree=None, hardlink=False):
486
"""Create a working tree at this BzrDir.
488
:param revision_id: create it as of this revision id.
489
:param from_branch: override bzrdir branch (for lightweight checkouts)
490
:param accelerator_tree: A tree which can be used for retrieving file
491
contents more quickly than the revision tree, i.e. a workingtree.
492
The revision tree will be used for cases where accelerator_tree's
493
content is different.
495
raise NotImplementedError(self.create_workingtree)
497
def retire_bzrdir(self, limit=10000):
498
"""Permanently disable the bzrdir.
500
This is done by renaming it to give the user some ability to recover
501
if there was a problem.
503
This will have horrible consequences if anyone has anything locked or
505
:param limit: number of times to retry
510
to_path = '.bzr.retired.%d' % i
511
self.root_transport.rename('.bzr', to_path)
512
note("renamed %s to %s"
513
% (self.root_transport.abspath('.bzr'), to_path))
515
except (errors.TransportError, IOError, errors.PathError):
522
def destroy_workingtree(self):
523
"""Destroy the working tree at this BzrDir.
525
Formats that do not support this may raise UnsupportedOperation.
527
raise NotImplementedError(self.destroy_workingtree)
529
def destroy_workingtree_metadata(self):
530
"""Destroy the control files for the working tree at this BzrDir.
532
The contents of working tree files are not affected.
533
Formats that do not support this may raise UnsupportedOperation.
535
raise NotImplementedError(self.destroy_workingtree_metadata)
537
def _find_containing(self, evaluate):
538
"""Find something in a containing control directory.
540
This method will scan containing control dirs, until it finds what
541
it is looking for, decides that it will never find it, or runs out
542
of containing control directories to check.
544
It is used to implement find_repository and
545
determine_repository_policy.
547
:param evaluate: A function returning (value, stop). If stop is True,
548
the value will be returned.
552
result, stop = evaluate(found_bzrdir)
555
next_transport = found_bzrdir.root_transport.clone('..')
556
if (found_bzrdir.root_transport.base == next_transport.base):
557
# top of the file system
559
# find the next containing bzrdir
561
found_bzrdir = BzrDir.open_containing_from_transport(
563
except errors.NotBranchError:
566
def find_repository(self):
567
"""Find the repository that should be used.
569
This does not require a branch as we use it to find the repo for
570
new branches as well as to hook existing branches up to their
573
def usable_repository(found_bzrdir):
574
# does it have a repository ?
576
repository = found_bzrdir.open_repository()
577
except errors.NoRepositoryPresent:
579
if found_bzrdir.root_transport.base == self.root_transport.base:
580
return repository, True
581
elif repository.is_shared():
582
return repository, True
586
found_repo = self._find_containing(usable_repository)
587
if found_repo is None:
588
raise errors.NoRepositoryPresent(self)
591
def get_branch_reference(self):
592
"""Return the referenced URL for the branch in this bzrdir.
594
:raises NotBranchError: If there is no Branch.
595
:return: The URL the branch in this bzrdir references if it is a
596
reference branch, or None for regular branches.
600
def get_branch_transport(self, branch_format):
601
"""Get the transport for use by branch format in this BzrDir.
603
Note that bzr dirs that do not support format strings will raise
604
IncompatibleFormat if the branch format they are given has
605
a format string, and vice versa.
607
If branch_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_branch_transport)
613
def get_repository_transport(self, repository_format):
614
"""Get the transport for use by repository format in this BzrDir.
616
Note that bzr dirs that do not support format strings will raise
617
IncompatibleFormat if the repository format they are given has
618
a format string, and vice versa.
620
If repository_format is None, the transport is returned with no
621
checking. If it is not None, then the returned transport is
622
guaranteed to point to an existing directory ready for use.
624
raise NotImplementedError(self.get_repository_transport)
626
def get_workingtree_transport(self, tree_format):
627
"""Get the transport for use by workingtree format in this BzrDir.
629
Note that bzr dirs that do not support format strings will raise
630
IncompatibleFormat if the workingtree format they are given has a
631
format string, and vice versa.
633
If workingtree_format is None, the transport is returned with no
634
checking. If it is not None, then the returned transport is
635
guaranteed to point to an existing directory ready for use.
637
raise NotImplementedError(self.get_workingtree_transport)
639
def __init__(self, _transport, _format):
640
"""Initialize a Bzr control dir object.
642
Only really common logic should reside here, concrete classes should be
643
made with varying behaviours.
645
:param _format: the format that is creating this BzrDir instance.
646
:param _transport: the transport this dir is based at.
648
self._format = _format
649
self.transport = _transport.clone('.bzr')
650
self.root_transport = _transport
652
def is_control_filename(self, filename):
653
"""True if filename is the name of a path which is reserved for bzrdir's.
655
:param filename: A filename within the root transport of this bzrdir.
657
This is true IF and ONLY IF the filename is part of the namespace reserved
658
for bzr control dirs. Currently this is the '.bzr' directory in the root
659
of the root_transport. it is expected that plugins will need to extend
660
this in the future - for instance to make bzr talk with svn working
663
# this might be better on the BzrDirFormat class because it refers to
664
# all the possible bzrdir disk formats.
665
# This method is tested via the workingtree is_control_filename tests-
666
# it was extracted from WorkingTree.is_control_filename. If the method's
667
# contract is extended beyond the current trivial implementation, please
668
# add new tests for it to the appropriate place.
669
return filename == '.bzr' or filename.startswith('.bzr/')
671
def needs_format_conversion(self, format=None):
672
"""Return true if this bzrdir needs convert_format run on it.
674
For instance, if the repository format is out of date but the
675
branch and working tree are not, this should return True.
677
:param format: Optional parameter indicating a specific desired
678
format we plan to arrive at.
680
raise NotImplementedError(self.needs_format_conversion)
683
def open_unsupported(base):
684
"""Open a branch which is not supported."""
685
return BzrDir.open(base, _unsupported=True)
688
def open(base, _unsupported=False, possible_transports=None):
689
"""Open an existing bzrdir, rooted at 'base' (url).
691
:param _unsupported: a private parameter to the BzrDir class.
693
t = get_transport(base, possible_transports=possible_transports)
694
return BzrDir.open_from_transport(t, _unsupported=_unsupported)
697
def open_from_transport(transport, _unsupported=False,
698
_server_formats=True):
699
"""Open a bzrdir within a particular directory.
701
:param transport: Transport containing the bzrdir.
702
:param _unsupported: private.
704
base = transport.base
706
def find_format(transport):
707
return transport, BzrDirFormat.find_format(
708
transport, _server_formats=_server_formats)
710
def redirected(transport, e, redirection_notice):
711
qualified_source = e.get_source_url()
712
relpath = transport.relpath(qualified_source)
713
if not e.target.endswith(relpath):
714
# Not redirected to a branch-format, not a branch
715
raise errors.NotBranchError(path=e.target)
716
target = e.target[:-len(relpath)]
717
note('%s is%s redirected to %s',
718
transport.base, e.permanently, target)
719
# Let's try with a new transport
720
# FIXME: If 'transport' has a qualifier, this should
721
# be applied again to the new transport *iff* the
722
# schemes used are the same. Uncomment this code
723
# once the function (and tests) exist.
725
#target = urlutils.copy_url_qualifiers(original, target)
726
return get_transport(target)
729
transport, format = do_catching_redirections(find_format,
732
except errors.TooManyRedirections:
733
raise errors.NotBranchError(base)
735
BzrDir._check_supported(format, _unsupported)
736
return format.open(transport, _found=True)
738
def open_branch(self, unsupported=False):
739
"""Open the branch object at this BzrDir if one is present.
741
If unsupported is True, then no longer supported branch formats can
744
TODO: static convenience version of this?
746
raise NotImplementedError(self.open_branch)
749
def open_containing(url, possible_transports=None):
750
"""Open an existing branch which contains url.
752
:param url: url to search from.
753
See open_containing_from_transport for more detail.
755
transport = get_transport(url, possible_transports)
756
return BzrDir.open_containing_from_transport(transport)
759
def open_containing_from_transport(a_transport):
760
"""Open an existing branch which contains a_transport.base.
762
This probes for a branch at a_transport, and searches upwards from there.
764
Basically we keep looking up until we find the control directory or
765
run into the root. If there isn't one, raises NotBranchError.
766
If there is one and it is either an unrecognised format or an unsupported
767
format, UnknownFormatError or UnsupportedFormatError are raised.
768
If there is one, it is returned, along with the unused portion of url.
770
:return: The BzrDir that contains the path, and a Unicode path
771
for the rest of the URL.
773
# this gets the normalised url back. I.e. '.' -> the full path.
774
url = a_transport.base
777
result = BzrDir.open_from_transport(a_transport)
778
return result, urlutils.unescape(a_transport.relpath(url))
779
except errors.NotBranchError, e:
782
new_t = a_transport.clone('..')
783
except errors.InvalidURLJoin:
784
# reached the root, whatever that may be
785
raise errors.NotBranchError(path=url)
786
if new_t.base == a_transport.base:
787
# reached the root, whatever that may be
788
raise errors.NotBranchError(path=url)
791
def _get_tree_branch(self):
792
"""Return the branch and tree, if any, for this bzrdir.
794
Return None for tree if not present or inaccessible.
795
Raise NotBranchError if no branch is present.
796
:return: (tree, branch)
799
tree = self.open_workingtree()
800
except (errors.NoWorkingTree, errors.NotLocalUrl):
802
branch = self.open_branch()
808
def open_tree_or_branch(klass, location):
809
"""Return the branch and working tree at a location.
811
If there is no tree at the location, tree will be None.
812
If there is no branch at the location, an exception will be
814
:return: (tree, branch)
816
bzrdir = klass.open(location)
817
return bzrdir._get_tree_branch()
820
def open_containing_tree_or_branch(klass, location):
821
"""Return the branch and working tree contained by a location.
823
Returns (tree, branch, relpath).
824
If there is no tree at containing the location, tree will be None.
825
If there is no branch containing the location, an exception will be
827
relpath is the portion of the path that is contained by the branch.
829
bzrdir, relpath = klass.open_containing(location)
830
tree, branch = bzrdir._get_tree_branch()
831
return tree, branch, relpath
833
def open_repository(self, _unsupported=False):
834
"""Open the repository object at this BzrDir if one is present.
836
This will not follow the Branch object pointer - it's strictly a direct
837
open facility. Most client code should use open_branch().repository to
840
:param _unsupported: a private parameter, not part of the api.
841
TODO: static convenience version of this?
843
raise NotImplementedError(self.open_repository)
845
def open_workingtree(self, _unsupported=False,
846
recommend_upgrade=True, from_branch=None):
847
"""Open the workingtree object at this BzrDir if one is present.
849
:param recommend_upgrade: Optional keyword parameter, when True (the
850
default), emit through the ui module a recommendation that the user
851
upgrade the working tree when the workingtree being opened is old
852
(but still fully supported).
853
:param from_branch: override bzrdir branch (for lightweight checkouts)
855
raise NotImplementedError(self.open_workingtree)
857
def has_branch(self):
858
"""Tell if this bzrdir contains a branch.
860
Note: if you're going to open the branch, you should just go ahead
861
and try, and not ask permission first. (This method just opens the
862
branch and discards it, and that's somewhat expensive.)
867
except errors.NotBranchError:
870
def has_workingtree(self):
871
"""Tell if this bzrdir contains a working tree.
873
This will still raise an exception if the bzrdir has a workingtree that
874
is remote & inaccessible.
876
Note: if you're going to open the working tree, you should just go ahead
877
and try, and not ask permission first. (This method just opens the
878
workingtree and discards it, and that's somewhat expensive.)
881
self.open_workingtree(recommend_upgrade=False)
883
except errors.NoWorkingTree:
886
def _cloning_metadir(self):
887
"""Produce a metadir suitable for cloning with."""
888
result_format = self._format.__class__()
891
branch = self.open_branch()
892
source_repository = branch.repository
893
except errors.NotBranchError:
895
source_repository = self.open_repository()
896
except errors.NoRepositoryPresent:
897
source_repository = None
899
# XXX TODO: This isinstance is here because we have not implemented
900
# the fix recommended in bug # 103195 - to delegate this choice the
902
repo_format = source_repository._format
903
if not isinstance(repo_format, remote.RemoteRepositoryFormat):
904
result_format.repository_format = repo_format
906
# TODO: Couldn't we just probe for the format in these cases,
907
# rather than opening the whole tree? It would be a little
908
# faster. mbp 20070401
909
tree = self.open_workingtree(recommend_upgrade=False)
910
except (errors.NoWorkingTree, errors.NotLocalUrl):
911
result_format.workingtree_format = None
913
result_format.workingtree_format = tree._format.__class__()
914
return result_format, source_repository
916
def cloning_metadir(self):
917
"""Produce a metadir suitable for cloning or sprouting with.
919
These operations may produce workingtrees (yes, even though they're
920
"cloning" something that doesn't have a tree), so a viable workingtree
921
format must be selected.
923
format, repository = self._cloning_metadir()
924
if format._workingtree_format is None:
925
if repository is None:
927
tree_format = repository._format._matchingbzrdir.workingtree_format
928
format.workingtree_format = tree_format.__class__()
931
def checkout_metadir(self):
932
return self.cloning_metadir()
934
def sprout(self, url, revision_id=None, force_new_repo=False,
935
recurse='down', possible_transports=None,
936
accelerator_tree=None, hardlink=False):
937
"""Create a copy of this bzrdir prepared for use as a new line of
940
If url's last component does not exist, it will be created.
942
Attributes related to the identity of the source branch like
943
branch nickname will be cleaned, a working tree is created
944
whether one existed before or not; and a local branch is always
947
if revision_id is not None, then the clone operation may tune
948
itself to download less data.
949
:param accelerator_tree: A tree which can be used for retrieving file
950
contents more quickly than the revision tree, i.e. a workingtree.
951
The revision tree will be used for cases where accelerator_tree's
952
content is different.
953
:param hardlink: If true, hard-link files from accelerator_tree,
956
target_transport = get_transport(url, possible_transports)
957
target_transport.ensure_base()
958
cloning_format = self.cloning_metadir()
959
result = cloning_format.initialize_on_transport(target_transport)
961
source_branch = self.open_branch()
962
source_repository = source_branch.repository
963
except errors.NotBranchError:
966
source_repository = self.open_repository()
967
except errors.NoRepositoryPresent:
968
source_repository = None
973
result_repo = result.find_repository()
974
except errors.NoRepositoryPresent:
976
if source_repository is None and result_repo is not None:
978
elif source_repository is None and result_repo is None:
979
# no repo available, make a new one
980
result.create_repository()
981
elif source_repository is not None and result_repo is None:
982
# have source, and want to make a new target repo
983
result_repo = source_repository.sprout(result,
984
revision_id=revision_id)
986
# fetch needed content into target.
987
if source_repository is not None:
989
# source_repository.copy_content_into(result_repo,
990
# revision_id=revision_id)
991
# so we can override the copy method
992
result_repo.fetch(source_repository, revision_id=revision_id)
993
if source_branch is not None:
994
source_branch.sprout(result, revision_id=revision_id)
996
result.create_branch()
997
if isinstance(target_transport, LocalTransport) and (
998
result_repo is None or result_repo.make_working_trees()):
999
wt = result.create_workingtree(accelerator_tree=accelerator_tree,
1003
if wt.path2id('') is None:
1005
wt.set_root_id(self.open_workingtree.get_root_id())
1006
except errors.NoWorkingTree:
1012
if recurse == 'down':
1014
basis = wt.basis_tree()
1016
subtrees = basis.iter_references()
1017
recurse_branch = wt.branch
1018
elif source_branch is not None:
1019
basis = source_branch.basis_tree()
1021
subtrees = basis.iter_references()
1022
recurse_branch = source_branch
1027
for path, file_id in subtrees:
1028
target = urlutils.join(url, urlutils.escape(path))
1029
sublocation = source_branch.reference_parent(file_id, path)
1030
sublocation.bzrdir.sprout(target,
1031
basis.get_reference_revision(file_id, path),
1032
force_new_repo=force_new_repo, recurse=recurse)
1034
if basis is not None:
1039
class BzrDirPreSplitOut(BzrDir):
1040
"""A common class for the all-in-one formats."""
1042
def __init__(self, _transport, _format):
1043
"""See BzrDir.__init__."""
1044
super(BzrDirPreSplitOut, self).__init__(_transport, _format)
1045
assert self._format._lock_class == lockable_files.TransportLock
1046
assert self._format._lock_file_name == 'branch-lock'
1047
self._control_files = lockable_files.LockableFiles(
1048
self.get_branch_transport(None),
1049
self._format._lock_file_name,
1050
self._format._lock_class)
1052
def break_lock(self):
1053
"""Pre-splitout bzrdirs do not suffer from stale locks."""
1054
raise NotImplementedError(self.break_lock)
1056
def cloning_metadir(self):
1057
"""Produce a metadir suitable for cloning with."""
1058
return self._format.__class__()
1060
def clone(self, url, revision_id=None, force_new_repo=False):
1061
"""See BzrDir.clone()."""
1062
from bzrlib.workingtree import WorkingTreeFormat2
1063
self._make_tail(url)
1064
result = self._format._initialize_for_clone(url)
1065
self.open_repository().clone(result, revision_id=revision_id)
1066
from_branch = self.open_branch()
1067
from_branch.clone(result, revision_id=revision_id)
1069
self.open_workingtree().clone(result)
1070
except errors.NotLocalUrl:
1071
# make a new one, this format always has to have one.
1073
WorkingTreeFormat2().initialize(result)
1074
except errors.NotLocalUrl:
1075
# but we cannot do it for remote trees.
1076
to_branch = result.open_branch()
1077
WorkingTreeFormat2().stub_initialize_remote(to_branch.control_files)
1080
def create_branch(self):
1081
"""See BzrDir.create_branch."""
1082
return self.open_branch()
1084
def destroy_branch(self):
1085
"""See BzrDir.destroy_branch."""
1086
raise errors.UnsupportedOperation(self.destroy_branch, self)
1088
def create_repository(self, shared=False):
1089
"""See BzrDir.create_repository."""
1091
raise errors.IncompatibleFormat('shared repository', self._format)
1092
return self.open_repository()
1094
def destroy_repository(self):
1095
"""See BzrDir.destroy_repository."""
1096
raise errors.UnsupportedOperation(self.destroy_repository, self)
1098
def create_workingtree(self, revision_id=None, from_branch=None,
1099
accelerator_tree=None, hardlink=False):
1100
"""See BzrDir.create_workingtree."""
1101
# this looks buggy but is not -really-
1102
# because this format creates the workingtree when the bzrdir is
1104
# clone and sprout will have set the revision_id
1105
# and that will have set it for us, its only
1106
# specific uses of create_workingtree in isolation
1107
# that can do wonky stuff here, and that only
1108
# happens for creating checkouts, which cannot be
1109
# done on this format anyway. So - acceptable wart.
1110
result = self.open_workingtree(recommend_upgrade=False)
1111
if revision_id is not None:
1112
if revision_id == _mod_revision.NULL_REVISION:
1113
result.set_parent_ids([])
1115
result.set_parent_ids([revision_id])
1118
def destroy_workingtree(self):
1119
"""See BzrDir.destroy_workingtree."""
1120
raise errors.UnsupportedOperation(self.destroy_workingtree, self)
1122
def destroy_workingtree_metadata(self):
1123
"""See BzrDir.destroy_workingtree_metadata."""
1124
raise errors.UnsupportedOperation(self.destroy_workingtree_metadata,
1127
def get_branch_transport(self, branch_format):
1128
"""See BzrDir.get_branch_transport()."""
1129
if branch_format is None:
1130
return self.transport
1132
branch_format.get_format_string()
1133
except NotImplementedError:
1134
return self.transport
1135
raise errors.IncompatibleFormat(branch_format, self._format)
1137
def get_repository_transport(self, repository_format):
1138
"""See BzrDir.get_repository_transport()."""
1139
if repository_format is None:
1140
return self.transport
1142
repository_format.get_format_string()
1143
except NotImplementedError:
1144
return self.transport
1145
raise errors.IncompatibleFormat(repository_format, self._format)
1147
def get_workingtree_transport(self, workingtree_format):
1148
"""See BzrDir.get_workingtree_transport()."""
1149
if workingtree_format is None:
1150
return self.transport
1152
workingtree_format.get_format_string()
1153
except NotImplementedError:
1154
return self.transport
1155
raise errors.IncompatibleFormat(workingtree_format, self._format)
1157
def needs_format_conversion(self, format=None):
1158
"""See BzrDir.needs_format_conversion()."""
1159
# if the format is not the same as the system default,
1160
# an upgrade is needed.
1162
format = BzrDirFormat.get_default_format()
1163
return not isinstance(self._format, format.__class__)
1165
def open_branch(self, unsupported=False):
1166
"""See BzrDir.open_branch."""
1167
from bzrlib.branch import BzrBranchFormat4
1168
format = BzrBranchFormat4()
1169
self._check_supported(format, unsupported)
1170
return format.open(self, _found=True)
1172
def sprout(self, url, revision_id=None, force_new_repo=False,
1173
possible_transports=None, accelerator_tree=None,
1175
"""See BzrDir.sprout()."""
1176
from bzrlib.workingtree import WorkingTreeFormat2
1177
self._make_tail(url)
1178
result = self._format._initialize_for_clone(url)
1180
self.open_repository().clone(result, revision_id=revision_id)
1181
except errors.NoRepositoryPresent:
1184
self.open_branch().sprout(result, revision_id=revision_id)
1185
except errors.NotBranchError:
1187
# we always want a working tree
1188
WorkingTreeFormat2().initialize(result,
1189
accelerator_tree=accelerator_tree,
1194
class BzrDir4(BzrDirPreSplitOut):
1195
"""A .bzr version 4 control object.
1197
This is a deprecated format and may be removed after sept 2006.
1200
def create_repository(self, shared=False):
1201
"""See BzrDir.create_repository."""
1202
return self._format.repository_format.initialize(self, shared)
1204
def needs_format_conversion(self, format=None):
1205
"""Format 4 dirs are always in need of conversion."""
1208
def open_repository(self):
1209
"""See BzrDir.open_repository."""
1210
from bzrlib.repofmt.weaverepo import RepositoryFormat4
1211
return RepositoryFormat4().open(self, _found=True)
1214
class BzrDir5(BzrDirPreSplitOut):
1215
"""A .bzr version 5 control object.
1217
This is a deprecated format and may be removed after sept 2006.
1220
def open_repository(self):
1221
"""See BzrDir.open_repository."""
1222
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1223
return RepositoryFormat5().open(self, _found=True)
1225
def open_workingtree(self, _unsupported=False,
1226
recommend_upgrade=True):
1227
"""See BzrDir.create_workingtree."""
1228
from bzrlib.workingtree import WorkingTreeFormat2
1229
wt_format = WorkingTreeFormat2()
1230
# we don't warn here about upgrades; that ought to be handled for the
1232
return wt_format.open(self, _found=True)
1235
class BzrDir6(BzrDirPreSplitOut):
1236
"""A .bzr version 6 control object.
1238
This is a deprecated format and may be removed after sept 2006.
1241
def open_repository(self):
1242
"""See BzrDir.open_repository."""
1243
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1244
return RepositoryFormat6().open(self, _found=True)
1246
def open_workingtree(self, _unsupported=False,
1247
recommend_upgrade=True):
1248
"""See BzrDir.create_workingtree."""
1249
# we don't warn here about upgrades; that ought to be handled for the
1251
from bzrlib.workingtree import WorkingTreeFormat2
1252
return WorkingTreeFormat2().open(self, _found=True)
1255
class BzrDirMeta1(BzrDir):
1256
"""A .bzr meta version 1 control object.
1258
This is the first control object where the
1259
individual aspects are really split out: there are separate repository,
1260
workingtree and branch subdirectories and any subset of the three can be
1261
present within a BzrDir.
1264
def can_convert_format(self):
1265
"""See BzrDir.can_convert_format()."""
1268
def create_branch(self):
1269
"""See BzrDir.create_branch."""
1270
return self._format.get_branch_format().initialize(self)
1272
def destroy_branch(self):
1273
"""See BzrDir.create_branch."""
1274
self.transport.delete_tree('branch')
1276
def create_repository(self, shared=False):
1277
"""See BzrDir.create_repository."""
1278
return self._format.repository_format.initialize(self, shared)
1280
def destroy_repository(self):
1281
"""See BzrDir.destroy_repository."""
1282
self.transport.delete_tree('repository')
1284
def create_workingtree(self, revision_id=None, from_branch=None,
1285
accelerator_tree=None, hardlink=False):
1286
"""See BzrDir.create_workingtree."""
1287
return self._format.workingtree_format.initialize(
1288
self, revision_id, from_branch=from_branch,
1289
accelerator_tree=accelerator_tree, hardlink=hardlink)
1291
def destroy_workingtree(self):
1292
"""See BzrDir.destroy_workingtree."""
1293
wt = self.open_workingtree(recommend_upgrade=False)
1294
repository = wt.branch.repository
1295
empty = repository.revision_tree(_mod_revision.NULL_REVISION)
1296
wt.revert(old_tree=empty)
1297
self.destroy_workingtree_metadata()
1299
def destroy_workingtree_metadata(self):
1300
self.transport.delete_tree('checkout')
1302
def find_branch_format(self):
1303
"""Find the branch 'format' for this bzrdir.
1305
This might be a synthetic object for e.g. RemoteBranch and SVN.
1307
from bzrlib.branch import BranchFormat
1308
return BranchFormat.find_format(self)
1310
def _get_mkdir_mode(self):
1311
"""Figure out the mode to use when creating a bzrdir subdir."""
1312
temp_control = lockable_files.LockableFiles(self.transport, '',
1313
lockable_files.TransportLock)
1314
return temp_control._dir_mode
1316
def get_branch_reference(self):
1317
"""See BzrDir.get_branch_reference()."""
1318
from bzrlib.branch import BranchFormat
1319
format = BranchFormat.find_format(self)
1320
return format.get_reference(self)
1322
def get_branch_transport(self, branch_format):
1323
"""See BzrDir.get_branch_transport()."""
1324
if branch_format is None:
1325
return self.transport.clone('branch')
1327
branch_format.get_format_string()
1328
except NotImplementedError:
1329
raise errors.IncompatibleFormat(branch_format, self._format)
1331
self.transport.mkdir('branch', mode=self._get_mkdir_mode())
1332
except errors.FileExists:
1334
return self.transport.clone('branch')
1336
def get_repository_transport(self, repository_format):
1337
"""See BzrDir.get_repository_transport()."""
1338
if repository_format is None:
1339
return self.transport.clone('repository')
1341
repository_format.get_format_string()
1342
except NotImplementedError:
1343
raise errors.IncompatibleFormat(repository_format, self._format)
1345
self.transport.mkdir('repository', mode=self._get_mkdir_mode())
1346
except errors.FileExists:
1348
return self.transport.clone('repository')
1350
def get_workingtree_transport(self, workingtree_format):
1351
"""See BzrDir.get_workingtree_transport()."""
1352
if workingtree_format is None:
1353
return self.transport.clone('checkout')
1355
workingtree_format.get_format_string()
1356
except NotImplementedError:
1357
raise errors.IncompatibleFormat(workingtree_format, self._format)
1359
self.transport.mkdir('checkout', mode=self._get_mkdir_mode())
1360
except errors.FileExists:
1362
return self.transport.clone('checkout')
1364
def needs_format_conversion(self, format=None):
1365
"""See BzrDir.needs_format_conversion()."""
1367
format = BzrDirFormat.get_default_format()
1368
if not isinstance(self._format, format.__class__):
1369
# it is not a meta dir format, conversion is needed.
1371
# we might want to push this down to the repository?
1373
if not isinstance(self.open_repository()._format,
1374
format.repository_format.__class__):
1375
# the repository needs an upgrade.
1377
except errors.NoRepositoryPresent:
1380
if not isinstance(self.open_branch()._format,
1381
format.get_branch_format().__class__):
1382
# the branch needs an upgrade.
1384
except errors.NotBranchError:
1387
my_wt = self.open_workingtree(recommend_upgrade=False)
1388
if not isinstance(my_wt._format,
1389
format.workingtree_format.__class__):
1390
# the workingtree needs an upgrade.
1392
except (errors.NoWorkingTree, errors.NotLocalUrl):
1396
def open_branch(self, unsupported=False):
1397
"""See BzrDir.open_branch."""
1398
format = self.find_branch_format()
1399
self._check_supported(format, unsupported)
1400
return format.open(self, _found=True)
1402
def open_repository(self, unsupported=False):
1403
"""See BzrDir.open_repository."""
1404
from bzrlib.repository import RepositoryFormat
1405
format = RepositoryFormat.find_format(self)
1406
self._check_supported(format, unsupported)
1407
return format.open(self, _found=True)
1409
def open_workingtree(self, unsupported=False,
1410
recommend_upgrade=True):
1411
"""See BzrDir.open_workingtree."""
1412
from bzrlib.workingtree import WorkingTreeFormat
1413
format = WorkingTreeFormat.find_format(self)
1414
self._check_supported(format, unsupported,
1416
basedir=self.root_transport.base)
1417
return format.open(self, _found=True)
1420
class BzrDirFormat(object):
1421
"""An encapsulation of the initialization and open routines for a format.
1423
Formats provide three things:
1424
* An initialization routine,
1428
Formats are placed in a dict by their format string for reference
1429
during bzrdir opening. These should be subclasses of BzrDirFormat
1432
Once a format is deprecated, just deprecate the initialize and open
1433
methods on the format class. Do not deprecate the object, as the
1434
object will be created every system load.
1437
_default_format = None
1438
"""The default format used for new .bzr dirs."""
1441
"""The known formats."""
1443
_control_formats = []
1444
"""The registered control formats - .bzr, ....
1446
This is a list of BzrDirFormat objects.
1449
_control_server_formats = []
1450
"""The registered control server formats, e.g. RemoteBzrDirs.
1452
This is a list of BzrDirFormat objects.
1455
_lock_file_name = 'branch-lock'
1457
# _lock_class must be set in subclasses to the lock type, typ.
1458
# TransportLock or LockDir
1461
def find_format(klass, transport, _server_formats=True):
1462
"""Return the format present at transport."""
1464
formats = klass._control_server_formats + klass._control_formats
1466
formats = klass._control_formats
1467
for format in formats:
1469
return format.probe_transport(transport)
1470
except errors.NotBranchError:
1471
# this format does not find a control dir here.
1473
raise errors.NotBranchError(path=transport.base)
1476
def probe_transport(klass, transport):
1477
"""Return the .bzrdir style format present in a directory."""
1479
format_string = transport.get(".bzr/branch-format").read()
1480
except errors.NoSuchFile:
1481
raise errors.NotBranchError(path=transport.base)
1484
return klass._formats[format_string]
1486
raise errors.UnknownFormatError(format=format_string)
1489
def get_default_format(klass):
1490
"""Return the current default format."""
1491
return klass._default_format
1493
def get_format_string(self):
1494
"""Return the ASCII format string that identifies this format."""
1495
raise NotImplementedError(self.get_format_string)
1497
def get_format_description(self):
1498
"""Return the short description for this format."""
1499
raise NotImplementedError(self.get_format_description)
1501
def get_converter(self, format=None):
1502
"""Return the converter to use to convert bzrdirs needing converts.
1504
This returns a bzrlib.bzrdir.Converter object.
1506
This should return the best upgrader to step this format towards the
1507
current default format. In the case of plugins we can/should provide
1508
some means for them to extend the range of returnable converters.
1510
:param format: Optional format to override the default format of the
1513
raise NotImplementedError(self.get_converter)
1515
def initialize(self, url, possible_transports=None):
1516
"""Create a bzr control dir at this url and return an opened copy.
1518
Subclasses should typically override initialize_on_transport
1519
instead of this method.
1521
return self.initialize_on_transport(get_transport(url,
1522
possible_transports))
1524
def initialize_on_transport(self, transport):
1525
"""Initialize a new bzrdir in the base directory of a Transport."""
1526
# Since we don't have a .bzr directory, inherit the
1527
# mode from the root directory
1528
temp_control = lockable_files.LockableFiles(transport,
1529
'', lockable_files.TransportLock)
1530
temp_control._transport.mkdir('.bzr',
1531
# FIXME: RBC 20060121 don't peek under
1533
mode=temp_control._dir_mode)
1534
if sys.platform == 'win32' and isinstance(transport, LocalTransport):
1535
win32utils.set_file_attr_hidden(transport._abspath('.bzr'))
1536
file_mode = temp_control._file_mode
1538
mutter('created control directory in ' + transport.base)
1539
control = transport.clone('.bzr')
1540
utf8_files = [('README',
1541
"This is a Bazaar-NG control directory.\n"
1542
"Do not change any files in this directory.\n"),
1543
('branch-format', self.get_format_string()),
1545
# NB: no need to escape relative paths that are url safe.
1546
control_files = lockable_files.LockableFiles(control,
1547
self._lock_file_name, self._lock_class)
1548
control_files.create_lock()
1549
control_files.lock_write()
1551
for file, content in utf8_files:
1552
control_files.put_utf8(file, content)
1554
control_files.unlock()
1555
return self.open(transport, _found=True)
1557
def is_supported(self):
1558
"""Is this format supported?
1560
Supported formats must be initializable and openable.
1561
Unsupported formats may not support initialization or committing or
1562
some other features depending on the reason for not being supported.
1566
def same_model(self, target_format):
1567
return (self.repository_format.rich_root_data ==
1568
target_format.rich_root_data)
1571
def known_formats(klass):
1572
"""Return all the known formats.
1574
Concrete formats should override _known_formats.
1576
# There is double indirection here to make sure that control
1577
# formats used by more than one dir format will only be probed
1578
# once. This can otherwise be quite expensive for remote connections.
1580
for format in klass._control_formats:
1581
result.update(format._known_formats())
1585
def _known_formats(klass):
1586
"""Return the known format instances for this control format."""
1587
return set(klass._formats.values())
1589
def open(self, transport, _found=False):
1590
"""Return an instance of this format for the dir transport points at.
1592
_found is a private parameter, do not use it.
1595
found_format = BzrDirFormat.find_format(transport)
1596
if not isinstance(found_format, self.__class__):
1597
raise AssertionError("%s was asked to open %s, but it seems to need "
1599
% (self, transport, found_format))
1600
return self._open(transport)
1602
def _open(self, transport):
1603
"""Template method helper for opening BzrDirectories.
1605
This performs the actual open and any additional logic or parameter
1608
raise NotImplementedError(self._open)
1611
def register_format(klass, format):
1612
klass._formats[format.get_format_string()] = format
1615
def register_control_format(klass, format):
1616
"""Register a format that does not use '.bzr' for its control dir.
1618
TODO: This should be pulled up into a 'ControlDirFormat' base class
1619
which BzrDirFormat can inherit from, and renamed to register_format
1620
there. It has been done without that for now for simplicity of
1623
klass._control_formats.append(format)
1626
def register_control_server_format(klass, format):
1627
"""Register a control format for client-server environments.
1629
These formats will be tried before ones registered with
1630
register_control_format. This gives implementations that decide to the
1631
chance to grab it before anything looks at the contents of the format
1634
klass._control_server_formats.append(format)
1637
@symbol_versioning.deprecated_method(symbol_versioning.zero_fourteen)
1638
def set_default_format(klass, format):
1639
klass._set_default_format(format)
1642
def _set_default_format(klass, format):
1643
"""Set default format (for testing behavior of defaults only)"""
1644
klass._default_format = format
1648
return self.get_format_string().rstrip()
1651
def unregister_format(klass, format):
1652
assert klass._formats[format.get_format_string()] is format
1653
del klass._formats[format.get_format_string()]
1656
def unregister_control_format(klass, format):
1657
klass._control_formats.remove(format)
1660
class BzrDirFormat4(BzrDirFormat):
1661
"""Bzr dir format 4.
1663
This format is a combined format for working tree, branch and repository.
1665
- Format 1 working trees [always]
1666
- Format 4 branches [always]
1667
- Format 4 repositories [always]
1669
This format is deprecated: it indexes texts using a text it which is
1670
removed in format 5; write support for this format has been removed.
1673
_lock_class = lockable_files.TransportLock
1675
def get_format_string(self):
1676
"""See BzrDirFormat.get_format_string()."""
1677
return "Bazaar-NG branch, format 0.0.4\n"
1679
def get_format_description(self):
1680
"""See BzrDirFormat.get_format_description()."""
1681
return "All-in-one format 4"
1683
def get_converter(self, format=None):
1684
"""See BzrDirFormat.get_converter()."""
1685
# there is one and only one upgrade path here.
1686
return ConvertBzrDir4To5()
1688
def initialize_on_transport(self, transport):
1689
"""Format 4 branches cannot be created."""
1690
raise errors.UninitializableFormat(self)
1692
def is_supported(self):
1693
"""Format 4 is not supported.
1695
It is not supported because the model changed from 4 to 5 and the
1696
conversion logic is expensive - so doing it on the fly was not
1701
def _open(self, transport):
1702
"""See BzrDirFormat._open."""
1703
return BzrDir4(transport, self)
1705
def __return_repository_format(self):
1706
"""Circular import protection."""
1707
from bzrlib.repofmt.weaverepo import RepositoryFormat4
1708
return RepositoryFormat4()
1709
repository_format = property(__return_repository_format)
1712
class BzrDirFormat5(BzrDirFormat):
1713
"""Bzr control format 5.
1715
This format is a combined format for working tree, branch and repository.
1717
- Format 2 working trees [always]
1718
- Format 4 branches [always]
1719
- Format 5 repositories [always]
1720
Unhashed stores in the repository.
1723
_lock_class = lockable_files.TransportLock
1725
def get_format_string(self):
1726
"""See BzrDirFormat.get_format_string()."""
1727
return "Bazaar-NG branch, format 5\n"
1729
def get_format_description(self):
1730
"""See BzrDirFormat.get_format_description()."""
1731
return "All-in-one format 5"
1733
def get_converter(self, format=None):
1734
"""See BzrDirFormat.get_converter()."""
1735
# there is one and only one upgrade path here.
1736
return ConvertBzrDir5To6()
1738
def _initialize_for_clone(self, url):
1739
return self.initialize_on_transport(get_transport(url), _cloning=True)
1741
def initialize_on_transport(self, transport, _cloning=False):
1742
"""Format 5 dirs always have working tree, branch and repository.
1744
Except when they are being cloned.
1746
from bzrlib.branch import BzrBranchFormat4
1747
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1748
from bzrlib.workingtree import WorkingTreeFormat2
1749
result = (super(BzrDirFormat5, self).initialize_on_transport(transport))
1750
RepositoryFormat5().initialize(result, _internal=True)
1752
branch = BzrBranchFormat4().initialize(result)
1754
WorkingTreeFormat2().initialize(result)
1755
except errors.NotLocalUrl:
1756
# Even though we can't access the working tree, we need to
1757
# create its control files.
1758
WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
1761
def _open(self, transport):
1762
"""See BzrDirFormat._open."""
1763
return BzrDir5(transport, self)
1765
def __return_repository_format(self):
1766
"""Circular import protection."""
1767
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1768
return RepositoryFormat5()
1769
repository_format = property(__return_repository_format)
1772
class BzrDirFormat6(BzrDirFormat):
1773
"""Bzr control format 6.
1775
This format is a combined format for working tree, branch and repository.
1777
- Format 2 working trees [always]
1778
- Format 4 branches [always]
1779
- Format 6 repositories [always]
1782
_lock_class = lockable_files.TransportLock
1784
def get_format_string(self):
1785
"""See BzrDirFormat.get_format_string()."""
1786
return "Bazaar-NG branch, format 6\n"
1788
def get_format_description(self):
1789
"""See BzrDirFormat.get_format_description()."""
1790
return "All-in-one format 6"
1792
def get_converter(self, format=None):
1793
"""See BzrDirFormat.get_converter()."""
1794
# there is one and only one upgrade path here.
1795
return ConvertBzrDir6ToMeta()
1797
def _initialize_for_clone(self, url):
1798
return self.initialize_on_transport(get_transport(url), _cloning=True)
1800
def initialize_on_transport(self, transport, _cloning=False):
1801
"""Format 6 dirs always have working tree, branch and repository.
1803
Except when they are being cloned.
1805
from bzrlib.branch import BzrBranchFormat4
1806
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1807
from bzrlib.workingtree import WorkingTreeFormat2
1808
result = super(BzrDirFormat6, self).initialize_on_transport(transport)
1809
RepositoryFormat6().initialize(result, _internal=True)
1811
branch = BzrBranchFormat4().initialize(result)
1813
WorkingTreeFormat2().initialize(result)
1814
except errors.NotLocalUrl:
1815
# Even though we can't access the working tree, we need to
1816
# create its control files.
1817
WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
1820
def _open(self, transport):
1821
"""See BzrDirFormat._open."""
1822
return BzrDir6(transport, self)
1824
def __return_repository_format(self):
1825
"""Circular import protection."""
1826
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1827
return RepositoryFormat6()
1828
repository_format = property(__return_repository_format)
1831
class BzrDirMetaFormat1(BzrDirFormat):
1832
"""Bzr meta control format 1
1834
This is the first format with split out working tree, branch and repository
1837
- Format 3 working trees [optional]
1838
- Format 5 branches [optional]
1839
- Format 7 repositories [optional]
1842
_lock_class = lockdir.LockDir
1845
self._workingtree_format = None
1846
self._branch_format = None
1848
def __eq__(self, other):
1849
if other.__class__ is not self.__class__:
1851
if other.repository_format != self.repository_format:
1853
if other.workingtree_format != self.workingtree_format:
1857
def __ne__(self, other):
1858
return not self == other
1860
def get_branch_format(self):
1861
if self._branch_format is None:
1862
from bzrlib.branch import BranchFormat
1863
self._branch_format = BranchFormat.get_default_format()
1864
return self._branch_format
1866
def set_branch_format(self, format):
1867
self._branch_format = format
1869
def get_converter(self, format=None):
1870
"""See BzrDirFormat.get_converter()."""
1872
format = BzrDirFormat.get_default_format()
1873
if not isinstance(self, format.__class__):
1874
# converting away from metadir is not implemented
1875
raise NotImplementedError(self.get_converter)
1876
return ConvertMetaToMeta(format)
1878
def get_format_string(self):
1879
"""See BzrDirFormat.get_format_string()."""
1880
return "Bazaar-NG meta directory, format 1\n"
1882
def get_format_description(self):
1883
"""See BzrDirFormat.get_format_description()."""
1884
return "Meta directory format 1"
1886
def _open(self, transport):
1887
"""See BzrDirFormat._open."""
1888
return BzrDirMeta1(transport, self)
1890
def __return_repository_format(self):
1891
"""Circular import protection."""
1892
if getattr(self, '_repository_format', None):
1893
return self._repository_format
1894
from bzrlib.repository import RepositoryFormat
1895
return RepositoryFormat.get_default_format()
1897
def __set_repository_format(self, value):
1898
"""Allow changing the repository format for metadir formats."""
1899
self._repository_format = value
1901
repository_format = property(__return_repository_format, __set_repository_format)
1903
def __get_workingtree_format(self):
1904
if self._workingtree_format is None:
1905
from bzrlib.workingtree import WorkingTreeFormat
1906
self._workingtree_format = WorkingTreeFormat.get_default_format()
1907
return self._workingtree_format
1909
def __set_workingtree_format(self, wt_format):
1910
self._workingtree_format = wt_format
1912
workingtree_format = property(__get_workingtree_format,
1913
__set_workingtree_format)
1916
# Register bzr control format
1917
BzrDirFormat.register_control_format(BzrDirFormat)
1919
# Register bzr formats
1920
BzrDirFormat.register_format(BzrDirFormat4())
1921
BzrDirFormat.register_format(BzrDirFormat5())
1922
BzrDirFormat.register_format(BzrDirFormat6())
1923
__default_format = BzrDirMetaFormat1()
1924
BzrDirFormat.register_format(__default_format)
1925
BzrDirFormat._default_format = __default_format
1928
class Converter(object):
1929
"""Converts a disk format object from one format to another."""
1931
def convert(self, to_convert, pb):
1932
"""Perform the conversion of to_convert, giving feedback via pb.
1934
:param to_convert: The disk object to convert.
1935
:param pb: a progress bar to use for progress information.
1938
def step(self, message):
1939
"""Update the pb by a step."""
1941
self.pb.update(message, self.count, self.total)
1944
class ConvertBzrDir4To5(Converter):
1945
"""Converts format 4 bzr dirs to format 5."""
1948
super(ConvertBzrDir4To5, self).__init__()
1949
self.converted_revs = set()
1950
self.absent_revisions = set()
1954
def convert(self, to_convert, pb):
1955
"""See Converter.convert()."""
1956
self.bzrdir = to_convert
1958
self.pb.note('starting upgrade from format 4 to 5')
1959
if isinstance(self.bzrdir.transport, LocalTransport):
1960
self.bzrdir.get_workingtree_transport(None).delete('stat-cache')
1961
self._convert_to_weaves()
1962
return BzrDir.open(self.bzrdir.root_transport.base)
1964
def _convert_to_weaves(self):
1965
self.pb.note('note: upgrade may be faster if all store files are ungzipped first')
1968
stat = self.bzrdir.transport.stat('weaves')
1969
if not S_ISDIR(stat.st_mode):
1970
self.bzrdir.transport.delete('weaves')
1971
self.bzrdir.transport.mkdir('weaves')
1972
except errors.NoSuchFile:
1973
self.bzrdir.transport.mkdir('weaves')
1974
# deliberately not a WeaveFile as we want to build it up slowly.
1975
self.inv_weave = Weave('inventory')
1976
# holds in-memory weaves for all files
1977
self.text_weaves = {}
1978
self.bzrdir.transport.delete('branch-format')
1979
self.branch = self.bzrdir.open_branch()
1980
self._convert_working_inv()
1981
rev_history = self.branch.revision_history()
1982
# to_read is a stack holding the revisions we still need to process;
1983
# appending to it adds new highest-priority revisions
1984
self.known_revisions = set(rev_history)
1985
self.to_read = rev_history[-1:]
1987
rev_id = self.to_read.pop()
1988
if (rev_id not in self.revisions
1989
and rev_id not in self.absent_revisions):
1990
self._load_one_rev(rev_id)
1992
to_import = self._make_order()
1993
for i, rev_id in enumerate(to_import):
1994
self.pb.update('converting revision', i, len(to_import))
1995
self._convert_one_rev(rev_id)
1997
self._write_all_weaves()
1998
self._write_all_revs()
1999
self.pb.note('upgraded to weaves:')
2000
self.pb.note(' %6d revisions and inventories', len(self.revisions))
2001
self.pb.note(' %6d revisions not present', len(self.absent_revisions))
2002
self.pb.note(' %6d texts', self.text_count)
2003
self._cleanup_spare_files_after_format4()
2004
self.branch.control_files.put_utf8('branch-format', BzrDirFormat5().get_format_string())
2006
def _cleanup_spare_files_after_format4(self):
2007
# FIXME working tree upgrade foo.
2008
for n in 'merged-patches', 'pending-merged-patches':
2010
## assert os.path.getsize(p) == 0
2011
self.bzrdir.transport.delete(n)
2012
except errors.NoSuchFile:
2014
self.bzrdir.transport.delete_tree('inventory-store')
2015
self.bzrdir.transport.delete_tree('text-store')
2017
def _convert_working_inv(self):
2018
inv = xml4.serializer_v4.read_inventory(
2019
self.branch.control_files.get('inventory'))
2020
new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv, working=True)
2021
# FIXME inventory is a working tree change.
2022
self.branch.control_files.put('inventory', StringIO(new_inv_xml))
2024
def _write_all_weaves(self):
2025
controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)
2026
weave_transport = self.bzrdir.transport.clone('weaves')
2027
weaves = WeaveStore(weave_transport, prefixed=False)
2028
transaction = WriteTransaction()
2032
for file_id, file_weave in self.text_weaves.items():
2033
self.pb.update('writing weave', i, len(self.text_weaves))
2034
weaves._put_weave(file_id, file_weave, transaction)
2036
self.pb.update('inventory', 0, 1)
2037
controlweaves._put_weave('inventory', self.inv_weave, transaction)
2038
self.pb.update('inventory', 1, 1)
2042
def _write_all_revs(self):
2043
"""Write all revisions out in new form."""
2044
self.bzrdir.transport.delete_tree('revision-store')
2045
self.bzrdir.transport.mkdir('revision-store')
2046
revision_transport = self.bzrdir.transport.clone('revision-store')
2048
_revision_store = TextRevisionStore(TextStore(revision_transport,
2052
transaction = WriteTransaction()
2053
for i, rev_id in enumerate(self.converted_revs):
2054
self.pb.update('write revision', i, len(self.converted_revs))
2055
_revision_store.add_revision(self.revisions[rev_id], transaction)
2059
def _load_one_rev(self, rev_id):
2060
"""Load a revision object into memory.
2062
Any parents not either loaded or abandoned get queued to be
2064
self.pb.update('loading revision',
2065
len(self.revisions),
2066
len(self.known_revisions))
2067
if not self.branch.repository.has_revision(rev_id):
2069
self.pb.note('revision {%s} not present in branch; '
2070
'will be converted as a ghost',
2072
self.absent_revisions.add(rev_id)
2074
rev = self.branch.repository._revision_store.get_revision(rev_id,
2075
self.branch.repository.get_transaction())
2076
for parent_id in rev.parent_ids:
2077
self.known_revisions.add(parent_id)
2078
self.to_read.append(parent_id)
2079
self.revisions[rev_id] = rev
2081
def _load_old_inventory(self, rev_id):
2082
assert rev_id not in self.converted_revs
2083
old_inv_xml = self.branch.repository.inventory_store.get(rev_id).read()
2084
inv = xml4.serializer_v4.read_inventory_from_string(old_inv_xml)
2085
inv.revision_id = rev_id
2086
rev = self.revisions[rev_id]
2087
if rev.inventory_sha1:
2088
assert rev.inventory_sha1 == sha_string(old_inv_xml), \
2089
'inventory sha mismatch for {%s}' % rev_id
2092
def _load_updated_inventory(self, rev_id):
2093
assert rev_id in self.converted_revs
2094
inv_xml = self.inv_weave.get_text(rev_id)
2095
inv = xml5.serializer_v5.read_inventory_from_string(inv_xml, rev_id)
2098
def _convert_one_rev(self, rev_id):
2099
"""Convert revision and all referenced objects to new format."""
2100
rev = self.revisions[rev_id]
2101
inv = self._load_old_inventory(rev_id)
2102
present_parents = [p for p in rev.parent_ids
2103
if p not in self.absent_revisions]
2104
self._convert_revision_contents(rev, inv, present_parents)
2105
self._store_new_inv(rev, inv, present_parents)
2106
self.converted_revs.add(rev_id)
2108
def _store_new_inv(self, rev, inv, present_parents):
2109
# the XML is now updated with text versions
2111
entries = inv.iter_entries()
2113
for path, ie in entries:
2114
assert getattr(ie, 'revision', None) is not None, \
2115
'no revision on {%s} in {%s}' % \
2116
(file_id, rev.revision_id)
2117
new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
2118
new_inv_sha1 = sha_string(new_inv_xml)
2119
self.inv_weave.add_lines(rev.revision_id,
2121
new_inv_xml.splitlines(True))
2122
rev.inventory_sha1 = new_inv_sha1
2124
def _convert_revision_contents(self, rev, inv, present_parents):
2125
"""Convert all the files within a revision.
2127
Also upgrade the inventory to refer to the text revision ids."""
2128
rev_id = rev.revision_id
2129
mutter('converting texts of revision {%s}',
2131
parent_invs = map(self._load_updated_inventory, present_parents)
2132
entries = inv.iter_entries()
2134
for path, ie in entries:
2135
self._convert_file_version(rev, ie, parent_invs)
2137
def _convert_file_version(self, rev, ie, parent_invs):
2138
"""Convert one version of one file.
2140
The file needs to be added into the weave if it is a merge
2141
of >=2 parents or if it's changed from its parent.
2143
file_id = ie.file_id
2144
rev_id = rev.revision_id
2145
w = self.text_weaves.get(file_id)
2148
self.text_weaves[file_id] = w
2149
text_changed = False
2150
parent_candiate_entries = ie.parent_candidates(parent_invs)
2151
for old_revision in parent_candiate_entries.keys():
2152
# if this fails, its a ghost ?
2153
assert old_revision in self.converted_revs, \
2154
"Revision {%s} not in converted_revs" % old_revision
2155
heads = graph.Graph(self).heads(parent_candiate_entries.keys())
2156
# XXX: Note that this is unordered - and this is tolerable because
2157
# the previous code was also unordered.
2158
previous_entries = dict((head, parent_candiate_entries[head]) for head
2160
self.snapshot_ie(previous_entries, ie, w, rev_id)
2162
assert getattr(ie, 'revision', None) is not None
2164
@symbol_versioning.deprecated_method(symbol_versioning.one_one)
2165
def get_parents(self, revision_ids):
2166
for revision_id in revision_ids:
2167
yield self.revisions[revision_id].parent_ids
2169
def get_parent_map(self, revision_ids):
2170
"""See graph._StackedParentsProvider.get_parent_map"""
2171
return dict((revision_id, self.revisions[revision_id])
2172
for revision_id in revision_ids
2173
if revision_id in self.revisions)
2175
def snapshot_ie(self, previous_revisions, ie, w, rev_id):
2176
# TODO: convert this logic, which is ~= snapshot to
2177
# a call to:. This needs the path figured out. rather than a work_tree
2178
# a v4 revision_tree can be given, or something that looks enough like
2179
# one to give the file content to the entry if it needs it.
2180
# and we need something that looks like a weave store for snapshot to
2182
#ie.snapshot(rev, PATH, previous_revisions, REVISION_TREE, InMemoryWeaveStore(self.text_weaves))
2183
if len(previous_revisions) == 1:
2184
previous_ie = previous_revisions.values()[0]
2185
if ie._unchanged(previous_ie):
2186
ie.revision = previous_ie.revision
2189
text = self.branch.repository.weave_store.get(ie.text_id)
2190
file_lines = text.readlines()
2191
assert sha_strings(file_lines) == ie.text_sha1
2192
assert sum(map(len, file_lines)) == ie.text_size
2193
w.add_lines(rev_id, previous_revisions, file_lines)
2194
self.text_count += 1
2196
w.add_lines(rev_id, previous_revisions, [])
2197
ie.revision = rev_id
2199
def _make_order(self):
2200
"""Return a suitable order for importing revisions.
2202
The order must be such that an revision is imported after all
2203
its (present) parents.
2205
todo = set(self.revisions.keys())
2206
done = self.absent_revisions.copy()
2209
# scan through looking for a revision whose parents
2211
for rev_id in sorted(list(todo)):
2212
rev = self.revisions[rev_id]
2213
parent_ids = set(rev.parent_ids)
2214
if parent_ids.issubset(done):
2215
# can take this one now
2216
order.append(rev_id)
2222
class ConvertBzrDir5To6(Converter):
2223
"""Converts format 5 bzr dirs to format 6."""
2225
def convert(self, to_convert, pb):
2226
"""See Converter.convert()."""
2227
self.bzrdir = to_convert
2229
self.pb.note('starting upgrade from format 5 to 6')
2230
self._convert_to_prefixed()
2231
return BzrDir.open(self.bzrdir.root_transport.base)
2233
def _convert_to_prefixed(self):
2234
from bzrlib.store import TransportStore
2235
self.bzrdir.transport.delete('branch-format')
2236
for store_name in ["weaves", "revision-store"]:
2237
self.pb.note("adding prefixes to %s" % store_name)
2238
store_transport = self.bzrdir.transport.clone(store_name)
2239
store = TransportStore(store_transport, prefixed=True)
2240
for urlfilename in store_transport.list_dir('.'):
2241
filename = urlutils.unescape(urlfilename)
2242
if (filename.endswith(".weave") or
2243
filename.endswith(".gz") or
2244
filename.endswith(".sig")):
2245
file_id = os.path.splitext(filename)[0]
2248
prefix_dir = store.hash_prefix(file_id)
2249
# FIXME keep track of the dirs made RBC 20060121
2251
store_transport.move(filename, prefix_dir + '/' + filename)
2252
except errors.NoSuchFile: # catches missing dirs strangely enough
2253
store_transport.mkdir(prefix_dir)
2254
store_transport.move(filename, prefix_dir + '/' + filename)
2255
self.bzrdir._control_files.put_utf8('branch-format', BzrDirFormat6().get_format_string())
2258
class ConvertBzrDir6ToMeta(Converter):
2259
"""Converts format 6 bzr dirs to metadirs."""
2261
def convert(self, to_convert, pb):
2262
"""See Converter.convert()."""
2263
from bzrlib.repofmt.weaverepo import RepositoryFormat7
2264
from bzrlib.branch import BzrBranchFormat5
2265
self.bzrdir = to_convert
2268
self.total = 20 # the steps we know about
2269
self.garbage_inventories = []
2271
self.pb.note('starting upgrade from format 6 to metadir')
2272
self.bzrdir._control_files.put_utf8('branch-format', "Converting to format 6")
2273
# its faster to move specific files around than to open and use the apis...
2274
# first off, nuke ancestry.weave, it was never used.
2276
self.step('Removing ancestry.weave')
2277
self.bzrdir.transport.delete('ancestry.weave')
2278
except errors.NoSuchFile:
2280
# find out whats there
2281
self.step('Finding branch files')
2282
last_revision = self.bzrdir.open_branch().last_revision()
2283
bzrcontents = self.bzrdir.transport.list_dir('.')
2284
for name in bzrcontents:
2285
if name.startswith('basis-inventory.'):
2286
self.garbage_inventories.append(name)
2287
# create new directories for repository, working tree and branch
2288
self.dir_mode = self.bzrdir._control_files._dir_mode
2289
self.file_mode = self.bzrdir._control_files._file_mode
2290
repository_names = [('inventory.weave', True),
2291
('revision-store', True),
2293
self.step('Upgrading repository ')
2294
self.bzrdir.transport.mkdir('repository', mode=self.dir_mode)
2295
self.make_lock('repository')
2296
# we hard code the formats here because we are converting into
2297
# the meta format. The meta format upgrader can take this to a
2298
# future format within each component.
2299
self.put_format('repository', RepositoryFormat7())
2300
for entry in repository_names:
2301
self.move_entry('repository', entry)
2303
self.step('Upgrading branch ')
2304
self.bzrdir.transport.mkdir('branch', mode=self.dir_mode)
2305
self.make_lock('branch')
2306
self.put_format('branch', BzrBranchFormat5())
2307
branch_files = [('revision-history', True),
2308
('branch-name', True),
2310
for entry in branch_files:
2311
self.move_entry('branch', entry)
2313
checkout_files = [('pending-merges', True),
2314
('inventory', True),
2315
('stat-cache', False)]
2316
# If a mandatory checkout file is not present, the branch does not have
2317
# a functional checkout. Do not create a checkout in the converted
2319
for name, mandatory in checkout_files:
2320
if mandatory and name not in bzrcontents:
2321
has_checkout = False
2325
if not has_checkout:
2326
self.pb.note('No working tree.')
2327
# If some checkout files are there, we may as well get rid of them.
2328
for name, mandatory in checkout_files:
2329
if name in bzrcontents:
2330
self.bzrdir.transport.delete(name)
2332
from bzrlib.workingtree import WorkingTreeFormat3
2333
self.step('Upgrading working tree')
2334
self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
2335
self.make_lock('checkout')
2337
'checkout', WorkingTreeFormat3())
2338
self.bzrdir.transport.delete_multi(
2339
self.garbage_inventories, self.pb)
2340
for entry in checkout_files:
2341
self.move_entry('checkout', entry)
2342
if last_revision is not None:
2343
self.bzrdir._control_files.put_utf8(
2344
'checkout/last-revision', last_revision)
2345
self.bzrdir._control_files.put_utf8(
2346
'branch-format', BzrDirMetaFormat1().get_format_string())
2347
return BzrDir.open(self.bzrdir.root_transport.base)
2349
def make_lock(self, name):
2350
"""Make a lock for the new control dir name."""
2351
self.step('Make %s lock' % name)
2352
ld = lockdir.LockDir(self.bzrdir.transport,
2354
file_modebits=self.file_mode,
2355
dir_modebits=self.dir_mode)
2358
def move_entry(self, new_dir, entry):
2359
"""Move then entry name into new_dir."""
2361
mandatory = entry[1]
2362
self.step('Moving %s' % name)
2364
self.bzrdir.transport.move(name, '%s/%s' % (new_dir, name))
2365
except errors.NoSuchFile:
2369
def put_format(self, dirname, format):
2370
self.bzrdir._control_files.put_utf8('%s/format' % dirname, format.get_format_string())
2373
class ConvertMetaToMeta(Converter):
2374
"""Converts the components of metadirs."""
2376
def __init__(self, target_format):
2377
"""Create a metadir to metadir converter.
2379
:param target_format: The final metadir format that is desired.
2381
self.target_format = target_format
2383
def convert(self, to_convert, pb):
2384
"""See Converter.convert()."""
2385
self.bzrdir = to_convert
2389
self.step('checking repository format')
2391
repo = self.bzrdir.open_repository()
2392
except errors.NoRepositoryPresent:
2395
if not isinstance(repo._format, self.target_format.repository_format.__class__):
2396
from bzrlib.repository import CopyConverter
2397
self.pb.note('starting repository conversion')
2398
converter = CopyConverter(self.target_format.repository_format)
2399
converter.convert(repo, pb)
2401
branch = self.bzrdir.open_branch()
2402
except errors.NotBranchError:
2405
# TODO: conversions of Branch and Tree should be done by
2406
# InterXFormat lookups
2407
# Avoid circular imports
2408
from bzrlib import branch as _mod_branch
2409
if (branch._format.__class__ is _mod_branch.BzrBranchFormat5 and
2410
self.target_format.get_branch_format().__class__ is
2411
_mod_branch.BzrBranchFormat6):
2412
branch_converter = _mod_branch.Converter5to6()
2413
branch_converter.convert(branch)
2415
tree = self.bzrdir.open_workingtree(recommend_upgrade=False)
2416
except (errors.NoWorkingTree, errors.NotLocalUrl):
2419
# TODO: conversions of Branch and Tree should be done by
2420
# InterXFormat lookups
2421
if (isinstance(tree, workingtree.WorkingTree3) and
2422
not isinstance(tree, workingtree_4.WorkingTree4) and
2423
isinstance(self.target_format.workingtree_format,
2424
workingtree_4.WorkingTreeFormat4)):
2425
workingtree_4.Converter3to4().convert(tree)
2429
# This is not in remote.py because it's small, and needs to be registered.
2430
# Putting it in remote.py creates a circular import problem.
2431
# we can make it a lazy object if the control formats is turned into something
2433
class RemoteBzrDirFormat(BzrDirMetaFormat1):
2434
"""Format representing bzrdirs accessed via a smart server"""
2436
def get_format_description(self):
2437
return 'bzr remote bzrdir'
2440
def probe_transport(klass, transport):
2441
"""Return a RemoteBzrDirFormat object if it looks possible."""
2443
client = transport.get_smart_client()
2444
except (NotImplementedError, AttributeError,
2445
errors.TransportNotPossible):
2446
# no smart server, so not a branch for this format type.
2447
raise errors.NotBranchError(path=transport.base)
2449
# Send a 'hello' request in protocol version one, and decline to
2450
# open it if the server doesn't support our required version (2) so
2451
# that the VFS-based transport will do it.
2452
request = client.get_request()
2453
smart_protocol = protocol.SmartClientRequestProtocolOne(request)
2454
server_version = smart_protocol.query_version()
2455
if server_version != 2:
2456
raise errors.NotBranchError(path=transport.base)
2459
def initialize_on_transport(self, transport):
2461
# hand off the request to the smart server
2462
shared_medium = transport.get_shared_medium()
2463
except errors.NoSmartMedium:
2464
# TODO: lookup the local format from a server hint.
2465
local_dir_format = BzrDirMetaFormat1()
2466
return local_dir_format.initialize_on_transport(transport)
2467
client = _SmartClient(shared_medium)
2468
path = client.remote_path_from_transport(transport)
2469
response = _SmartClient(shared_medium).call('BzrDirFormat.initialize',
2471
assert response[0] in ('ok', ), 'unexpected response code %s' % (response,)
2472
return remote.RemoteBzrDir(transport)
2474
def _open(self, transport):
2475
return remote.RemoteBzrDir(transport)
2477
def __eq__(self, other):
2478
if not isinstance(other, RemoteBzrDirFormat):
2480
return self.get_format_description() == other.get_format_description()
2483
BzrDirFormat.register_control_server_format(RemoteBzrDirFormat)
2486
class BzrDirFormatInfo(object):
2488
def __init__(self, native, deprecated, hidden, experimental):
2489
self.deprecated = deprecated
2490
self.native = native
2491
self.hidden = hidden
2492
self.experimental = experimental
2495
class BzrDirFormatRegistry(registry.Registry):
2496
"""Registry of user-selectable BzrDir subformats.
2498
Differs from BzrDirFormat._control_formats in that it provides sub-formats,
2499
e.g. BzrDirMeta1 with weave repository. Also, it's more user-oriented.
2503
"""Create a BzrDirFormatRegistry."""
2504
self._aliases = set()
2505
super(BzrDirFormatRegistry, self).__init__()
2508
"""Return a set of the format names which are aliases."""
2509
return frozenset(self._aliases)
2511
def register_metadir(self, key,
2512
repository_format, help, native=True, deprecated=False,
2518
"""Register a metadir subformat.
2520
These all use a BzrDirMetaFormat1 bzrdir, but can be parameterized
2521
by the Repository format.
2523
:param repository_format: The fully-qualified repository format class
2525
:param branch_format: Fully-qualified branch format class name as
2527
:param tree_format: Fully-qualified tree format class name as
2530
# This should be expanded to support setting WorkingTree and Branch
2531
# formats, once BzrDirMetaFormat1 supports that.
2532
def _load(full_name):
2533
mod_name, factory_name = full_name.rsplit('.', 1)
2535
mod = __import__(mod_name, globals(), locals(),
2537
except ImportError, e:
2538
raise ImportError('failed to load %s: %s' % (full_name, e))
2540
factory = getattr(mod, factory_name)
2541
except AttributeError:
2542
raise AttributeError('no factory %s in module %r'
2547
bd = BzrDirMetaFormat1()
2548
if branch_format is not None:
2549
bd.set_branch_format(_load(branch_format))
2550
if tree_format is not None:
2551
bd.workingtree_format = _load(tree_format)
2552
if repository_format is not None:
2553
bd.repository_format = _load(repository_format)
2555
self.register(key, helper, help, native, deprecated, hidden,
2556
experimental, alias)
2558
def register(self, key, factory, help, native=True, deprecated=False,
2559
hidden=False, experimental=False, alias=False):
2560
"""Register a BzrDirFormat factory.
2562
The factory must be a callable that takes one parameter: the key.
2563
It must produce an instance of the BzrDirFormat when called.
2565
This function mainly exists to prevent the info object from being
2568
registry.Registry.register(self, key, factory, help,
2569
BzrDirFormatInfo(native, deprecated, hidden, experimental))
2571
self._aliases.add(key)
2573
def register_lazy(self, key, module_name, member_name, help, native=True,
2574
deprecated=False, hidden=False, experimental=False, alias=False):
2575
registry.Registry.register_lazy(self, key, module_name, member_name,
2576
help, BzrDirFormatInfo(native, deprecated, hidden, experimental))
2578
self._aliases.add(key)
2580
def set_default(self, key):
2581
"""Set the 'default' key to be a clone of the supplied key.
2583
This method must be called once and only once.
2585
registry.Registry.register(self, 'default', self.get(key),
2586
self.get_help(key), info=self.get_info(key))
2587
self._aliases.add('default')
2589
def set_default_repository(self, key):
2590
"""Set the FormatRegistry default and Repository default.
2592
This is a transitional method while Repository.set_default_format
2595
if 'default' in self:
2596
self.remove('default')
2597
self.set_default(key)
2598
format = self.get('default')()
2599
assert isinstance(format, BzrDirMetaFormat1)
2601
def make_bzrdir(self, key):
2602
return self.get(key)()
2604
def help_topic(self, topic):
2605
output = textwrap.dedent("""\
2606
These formats can be used for creating branches, working trees, and
2610
default_realkey = None
2611
default_help = self.get_help('default')
2613
for key in self.keys():
2614
if key == 'default':
2616
help = self.get_help(key)
2617
if help == default_help:
2618
default_realkey = key
2620
help_pairs.append((key, help))
2622
def wrapped(key, help, info):
2624
help = '(native) ' + help
2625
return ':%s:\n%s\n\n' % (key,
2626
textwrap.fill(help, initial_indent=' ',
2627
subsequent_indent=' '))
2628
if default_realkey is not None:
2629
output += wrapped(default_realkey, '(default) %s' % default_help,
2630
self.get_info('default'))
2631
deprecated_pairs = []
2632
experimental_pairs = []
2633
for key, help in help_pairs:
2634
info = self.get_info(key)
2637
elif info.deprecated:
2638
deprecated_pairs.append((key, help))
2639
elif info.experimental:
2640
experimental_pairs.append((key, help))
2642
output += wrapped(key, help, info)
2643
if len(experimental_pairs) > 0:
2644
output += "Experimental formats are shown below.\n\n"
2645
for key, help in experimental_pairs:
2646
info = self.get_info(key)
2647
output += wrapped(key, help, info)
2648
if len(deprecated_pairs) > 0:
2649
output += "Deprecated formats are shown below.\n\n"
2650
for key, help in deprecated_pairs:
2651
info = self.get_info(key)
2652
output += wrapped(key, help, info)
2657
class RepositoryAcquisitionPolicy(object):
2658
"""Abstract base class for repository acquisition policies.
2660
A repository acquisition policy decides how a BzrDir acquires a repository
2661
for a branch that is being created. The most basic policy decision is
2662
whether to create a new repository or use an existing one.
2665
def configure_branch(self, branch):
2666
"""Apply any configuration data from this policy to the branch.
2668
Default implementation does nothing.
2672
def acquire_repository(self, make_working_trees=None, shared=False):
2673
"""Acquire a repository for this bzrdir.
2675
Implementations may create a new repository or use a pre-exising
2677
:param make_working_trees: If creating a repository, set
2678
make_working_trees to this value (if non-None)
2679
:param shared: If creating a repository, make it shared if True
2680
:return: A repository
2682
raise NotImplemented(RepositoryAcquisitionPolicy.acquire_repository)
2685
class CreateRepository(RepositoryAcquisitionPolicy):
2686
"""A policy of creating a new repository"""
2688
def __init__(self, bzrdir):
2689
RepositoryAcquisitionPolicy.__init__(self)
2690
self._bzrdir = bzrdir
2692
def acquire_repository(self, make_working_trees=None, shared=False):
2693
"""Implementation of RepositoryAcquisitionPolicy.acquire_repository
2695
Creates the desired repository in the bzrdir we already have.
2697
repository = self._bzrdir.create_repository(shared=shared)
2698
if make_working_trees is not None:
2699
repository.set_make_working_trees(make_working_trees)
2703
class UseExistingRepository(RepositoryAcquisitionPolicy):
2704
"""A policy of reusing an existing repository"""
2706
def __init__(self, repository):
2707
RepositoryAcquisitionPolicy.__init__(self)
2708
self._repository = repository
2710
def acquire_repository(self, make_working_trees=None, shared=False):
2711
"""Implementation of RepositoryAcquisitionPolicy.acquire_repository
2713
Returns an existing repository to use
2715
return self._repository
2718
format_registry = BzrDirFormatRegistry()
2719
format_registry.register('weave', BzrDirFormat6,
2720
'Pre-0.8 format. Slower than knit and does not'
2721
' support checkouts or shared repositories.',
2723
format_registry.register_metadir('knit',
2724
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2725
'Format using knits. Recommended for interoperation with bzr <= 0.14.',
2726
branch_format='bzrlib.branch.BzrBranchFormat5',
2727
tree_format='bzrlib.workingtree.WorkingTreeFormat3')
2728
format_registry.register_metadir('metaweave',
2729
'bzrlib.repofmt.weaverepo.RepositoryFormat7',
2730
'Transitional format in 0.8. Slower than knit.',
2731
branch_format='bzrlib.branch.BzrBranchFormat5',
2732
tree_format='bzrlib.workingtree.WorkingTreeFormat3',
2734
format_registry.register_metadir('dirstate',
2735
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2736
help='New in 0.15: Fast local operations. Compatible with bzr 0.8 and '
2737
'above when accessed over the network.',
2738
branch_format='bzrlib.branch.BzrBranchFormat5',
2739
# this uses bzrlib.workingtree.WorkingTreeFormat4 because importing
2740
# directly from workingtree_4 triggers a circular import.
2741
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2743
format_registry.register_metadir('dirstate-tags',
2744
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2745
help='New in 0.15: Fast local operations and improved scaling for '
2746
'network operations. Additionally adds support for tags.'
2747
' Incompatible with bzr < 0.15.',
2748
branch_format='bzrlib.branch.BzrBranchFormat6',
2749
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2751
format_registry.register_metadir('rich-root',
2752
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit4',
2753
help='New in 1.0. Better handling of tree roots. Incompatible with'
2755
branch_format='bzrlib.branch.BzrBranchFormat6',
2756
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2758
format_registry.register_metadir('dirstate-with-subtree',
2759
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
2760
help='New in 0.15: Fast local operations and improved scaling for '
2761
'network operations. Additionally adds support for versioning nested '
2762
'bzr branches. Incompatible with bzr < 0.15.',
2763
branch_format='bzrlib.branch.BzrBranchFormat6',
2764
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2768
format_registry.register_metadir('pack-0.92',
2769
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack1',
2770
help='New in 0.92: Pack-based format with data compatible with '
2771
'dirstate-tags format repositories. Interoperates with '
2772
'bzr repositories before 0.92 but cannot be read by bzr < 0.92. '
2773
'Previously called knitpack-experimental. '
2774
'For more information, see '
2775
'http://doc.bazaar-vcs.org/latest/developers/packrepo.html.',
2776
branch_format='bzrlib.branch.BzrBranchFormat6',
2777
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2779
format_registry.register_metadir('pack-0.92-subtree',
2780
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack3',
2781
help='New in 0.92: Pack-based format with data compatible with '
2782
'dirstate-with-subtree format repositories. Interoperates with '
2783
'bzr repositories before 0.92 but cannot be read by bzr < 0.92. '
2784
'Previously called knitpack-experimental. '
2785
'For more information, see '
2786
'http://doc.bazaar-vcs.org/latest/developers/packrepo.html.',
2787
branch_format='bzrlib.branch.BzrBranchFormat6',
2788
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2792
format_registry.register_metadir('rich-root-pack',
2793
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack4',
2794
help='New in 1.0: Pack-based format with data compatible with '
2795
'rich-root format repositories. Incompatible with'
2797
branch_format='bzrlib.branch.BzrBranchFormat6',
2798
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2800
# The following two formats should always just be aliases.
2801
format_registry.register_metadir('development',
2802
'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment0',
2803
help='Current development format. Can convert data to and from pack-0.92 '
2804
'(and anything compatible with pack-0.92) format repositories. '
2805
'Repositories in this format can only be read by bzr.dev. '
2807
'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
2809
branch_format='bzrlib.branch.BzrBranchFormat6',
2810
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2814
format_registry.register_metadir('development-subtree',
2815
'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment0Subtree',
2816
help='Current development format, subtree variant. Can convert data to and '
2817
'from pack-0.92 (and anything compatible with pack-0.92) format '
2818
'repositories. Repositories in this format can only be read by '
2819
'bzr.dev. Please read '
2820
'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
2822
branch_format='bzrlib.branch.BzrBranchFormat6',
2823
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2827
# And the development formats which the will have aliased one of follow:
2828
format_registry.register_metadir('development0',
2829
'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment0',
2830
help='Trivial rename of pack-0.92 to provide a development format. '
2832
'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
2834
branch_format='bzrlib.branch.BzrBranchFormat6',
2835
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2839
format_registry.register_metadir('development0-subtree',
2840
'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment0Subtree',
2841
help='Trivial rename of pack-0.92-subtree to provide a development format. '
2843
'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
2845
branch_format='bzrlib.branch.BzrBranchFormat6',
2846
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2850
format_registry.set_default('pack-0.92')