1
# Copyright (C) 2005, 2006, 2007, 2008, 2009 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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.
33
from bzrlib.lazy_import import lazy_import
34
lazy_import(globals(), """
35
from stat import S_ISDIR
47
revision as _mod_revision,
57
from bzrlib.osutils import (
60
from bzrlib.push import (
63
from bzrlib.smart.client import _SmartClient
64
from bzrlib.store.versioned import WeaveStore
65
from bzrlib.transactions import WriteTransaction
66
from bzrlib.transport import (
67
do_catching_redirections,
70
remote as remote_transport,
72
from bzrlib.weave import Weave
75
from bzrlib.trace 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).
99
Everything in the bzrdir should have the same file permissions.
101
:cvar hooks: An instance of BzrDirHooks.
104
def break_lock(self):
105
"""Invoke break_lock on the first object in the bzrdir.
107
If there is a tree, the tree is opened and break_lock() called.
108
Otherwise, branch is tried, and finally repository.
110
# XXX: This seems more like a UI function than something that really
111
# belongs in this class.
113
thing_to_unlock = self.open_workingtree()
114
except (errors.NotLocalUrl, errors.NoWorkingTree):
116
thing_to_unlock = self.open_branch()
117
except errors.NotBranchError:
119
thing_to_unlock = self.open_repository()
120
except errors.NoRepositoryPresent:
122
thing_to_unlock.break_lock()
124
def can_convert_format(self):
125
"""Return true if this bzrdir is one whose format we can convert from."""
128
def check_conversion_target(self, target_format):
129
target_repo_format = target_format.repository_format
130
source_repo_format = self._format.repository_format
131
source_repo_format.check_conversion_target(target_repo_format)
134
def _check_supported(format, allow_unsupported,
135
recommend_upgrade=True,
137
"""Give an error or warning on old formats.
139
:param format: may be any kind of format - workingtree, branch,
142
:param allow_unsupported: If true, allow opening
143
formats that are strongly deprecated, and which may
144
have limited functionality.
146
:param recommend_upgrade: If true (default), warn
147
the user through the ui object that they may wish
148
to upgrade the object.
150
# TODO: perhaps move this into a base Format class; it's not BzrDir
151
# specific. mbp 20070323
152
if not allow_unsupported and not format.is_supported():
153
# see open_downlevel to open legacy branches.
154
raise errors.UnsupportedFormatError(format=format)
155
if recommend_upgrade \
156
and getattr(format, 'upgrade_recommended', False):
157
ui.ui_factory.recommend_upgrade(
158
format.get_format_description(),
161
def clone(self, url, revision_id=None, force_new_repo=False,
162
preserve_stacking=False):
163
"""Clone this bzrdir and its contents to url verbatim.
165
:param url: The url create the clone at. If url's last component does
166
not exist, it will be created.
167
:param revision_id: The tip revision-id to use for any branch or
168
working tree. If not None, then the clone operation may tune
169
itself to download less data.
170
:param force_new_repo: Do not use a shared repository for the target
171
even if one is available.
172
:param preserve_stacking: When cloning a stacked branch, stack the
173
new branch on top of the other branch's stacked-on branch.
175
return self.clone_on_transport(get_transport(url),
176
revision_id=revision_id,
177
force_new_repo=force_new_repo,
178
preserve_stacking=preserve_stacking)
180
def clone_on_transport(self, transport, revision_id=None,
181
force_new_repo=False, preserve_stacking=False,
183
"""Clone this bzrdir and its contents to transport verbatim.
185
:param transport: The transport for the location to produce the clone
186
at. If the target directory does not exist, it will be created.
187
:param revision_id: The tip revision-id to use for any branch or
188
working tree. If not None, then the clone operation may tune
189
itself to download less data.
190
:param force_new_repo: Do not use a shared repository for the target,
191
even if one is available.
192
:param preserve_stacking: When cloning a stacked branch, stack the
193
new branch on top of the other branch's stacked-on branch.
195
transport.ensure_base()
196
require_stacking = (stacked_on is not None)
197
format = self.cloning_metadir(require_stacking)
198
# Bug: We create a metadir without knowing if it can support stacking,
199
# we should look up the policy needs first.
200
result = format.initialize_on_transport(transport)
201
repository_policy = None
203
local_repo = self.find_repository()
204
except errors.NoRepositoryPresent:
207
local_branch = self.open_branch()
208
except errors.NotBranchError:
211
# enable fallbacks when branch is not a branch reference
212
if local_branch.repository.has_same_location(local_repo):
213
local_repo = local_branch.repository
214
if preserve_stacking:
216
stacked_on = local_branch.get_stacked_on_url()
217
except (errors.UnstackableBranchFormat,
218
errors.UnstackableRepositoryFormat,
223
# may need to copy content in
224
repository_policy = result.determine_repository_policy(
225
force_new_repo, stacked_on, self.root_transport.base,
226
require_stacking=require_stacking)
227
make_working_trees = local_repo.make_working_trees()
228
result_repo, is_new_repo = repository_policy.acquire_repository(
229
make_working_trees, local_repo.is_shared())
230
if not require_stacking and repository_policy._require_stacking:
231
require_stacking = True
232
result._format.require_stacking()
233
if is_new_repo and not require_stacking and revision_id is not None:
234
fetch_spec = graph.PendingAncestryResult(
235
[revision_id], local_repo)
236
result_repo.fetch(local_repo, fetch_spec=fetch_spec)
238
result_repo.fetch(local_repo, revision_id=revision_id)
241
# 1 if there is a branch present
242
# make sure its content is available in the target repository
244
if local_branch is not None:
245
result_branch = local_branch.clone(result, revision_id=revision_id,
246
repository_policy=repository_policy)
248
# Cheaper to check if the target is not local, than to try making
250
result.root_transport.local_abspath('.')
251
if result_repo is None or result_repo.make_working_trees():
252
self.open_workingtree().clone(result)
253
except (errors.NoWorkingTree, errors.NotLocalUrl):
257
# TODO: This should be given a Transport, and should chdir up; otherwise
258
# this will open a new connection.
259
def _make_tail(self, url):
260
t = get_transport(url)
264
def create(cls, base, format=None, possible_transports=None):
265
"""Create a new BzrDir at the url 'base'.
267
:param format: If supplied, the format of branch to create. If not
268
supplied, the default is used.
269
:param possible_transports: If supplied, a list of transports that
270
can be reused to share a remote connection.
272
if cls is not BzrDir:
273
raise AssertionError("BzrDir.create always creates the default"
274
" format, not one of %r" % cls)
275
t = get_transport(base, possible_transports)
278
format = BzrDirFormat.get_default_format()
279
return format.initialize_on_transport(t)
282
def find_bzrdirs(transport, evaluate=None, list_current=None):
283
"""Find bzrdirs recursively from current location.
285
This is intended primarily as a building block for more sophisticated
286
functionality, like finding trees under a directory, or finding
287
branches that use a given repository.
288
:param evaluate: An optional callable that yields recurse, value,
289
where recurse controls whether this bzrdir is recursed into
290
and value is the value to yield. By default, all bzrdirs
291
are recursed into, and the return value is the bzrdir.
292
:param list_current: if supplied, use this function to list the current
293
directory, instead of Transport.list_dir
294
:return: a generator of found bzrdirs, or whatever evaluate returns.
296
if list_current is None:
297
def list_current(transport):
298
return transport.list_dir('')
300
def evaluate(bzrdir):
303
pending = [transport]
304
while len(pending) > 0:
305
current_transport = pending.pop()
308
bzrdir = BzrDir.open_from_transport(current_transport)
309
except errors.NotBranchError:
312
recurse, value = evaluate(bzrdir)
315
subdirs = list_current(current_transport)
316
except errors.NoSuchFile:
319
for subdir in sorted(subdirs, reverse=True):
320
pending.append(current_transport.clone(subdir))
323
def find_branches(transport):
324
"""Find all branches under a transport.
326
This will find all branches below the transport, including branches
327
inside other branches. Where possible, it will use
328
Repository.find_branches.
330
To list all the branches that use a particular Repository, see
331
Repository.find_branches
333
def evaluate(bzrdir):
335
repository = bzrdir.open_repository()
336
except errors.NoRepositoryPresent:
339
return False, (None, repository)
341
branch = bzrdir.open_branch()
342
except errors.NotBranchError:
343
return True, (None, None)
345
return True, (branch, None)
347
for branch, repo in BzrDir.find_bzrdirs(transport, evaluate=evaluate):
349
branches.extend(repo.find_branches())
350
if branch is not None:
351
branches.append(branch)
354
def destroy_repository(self):
355
"""Destroy the repository in this BzrDir"""
356
raise NotImplementedError(self.destroy_repository)
358
def create_branch(self):
359
"""Create a branch in this BzrDir.
361
The bzrdir's format will control what branch format is created.
362
For more control see BranchFormatXX.create(a_bzrdir).
364
raise NotImplementedError(self.create_branch)
366
def destroy_branch(self):
367
"""Destroy the branch in this BzrDir"""
368
raise NotImplementedError(self.destroy_branch)
371
def create_branch_and_repo(base, force_new_repo=False, format=None):
372
"""Create a new BzrDir, Branch and Repository at the url 'base'.
374
This will use the current default BzrDirFormat unless one is
375
specified, and use whatever
376
repository format that that uses via bzrdir.create_branch and
377
create_repository. If a shared repository is available that is used
380
The created Branch object is returned.
382
:param base: The URL to create the branch at.
383
:param force_new_repo: If True a new repository is always created.
384
:param format: If supplied, the format of branch to create. If not
385
supplied, the default is used.
387
bzrdir = BzrDir.create(base, format)
388
bzrdir._find_or_create_repository(force_new_repo)
389
return bzrdir.create_branch()
391
def determine_repository_policy(self, force_new_repo=False, stack_on=None,
392
stack_on_pwd=None, require_stacking=False):
393
"""Return an object representing a policy to use.
395
This controls whether a new repository is created, and the format of
396
that repository, or some existing shared repository used instead.
398
If stack_on is supplied, will not seek a containing shared repo.
400
:param force_new_repo: If True, require a new repository to be created.
401
:param stack_on: If supplied, the location to stack on. If not
402
supplied, a default_stack_on location may be used.
403
:param stack_on_pwd: If stack_on is relative, the location it is
406
def repository_policy(found_bzrdir):
409
config = found_bzrdir.get_config()
411
if config is not None:
412
stack_on = config.get_default_stack_on()
413
if stack_on is not None:
414
stack_on_pwd = found_bzrdir.root_transport.base
416
# does it have a repository ?
418
repository = found_bzrdir.open_repository()
419
except errors.NoRepositoryPresent:
422
if ((found_bzrdir.root_transport.base !=
423
self.root_transport.base) and not repository.is_shared()):
424
# Don't look higher, can't use a higher shared repo.
432
return UseExistingRepository(repository, stack_on,
433
stack_on_pwd, require_stacking=require_stacking), True
435
return CreateRepository(self, stack_on, stack_on_pwd,
436
require_stacking=require_stacking), True
438
if not force_new_repo:
440
policy = self._find_containing(repository_policy)
441
if policy is not None:
445
return UseExistingRepository(self.open_repository(),
446
stack_on, stack_on_pwd,
447
require_stacking=require_stacking)
448
except errors.NoRepositoryPresent:
450
return CreateRepository(self, stack_on, stack_on_pwd,
451
require_stacking=require_stacking)
453
def _find_or_create_repository(self, force_new_repo):
454
"""Create a new repository if needed, returning the repository."""
455
policy = self.determine_repository_policy(force_new_repo)
456
return policy.acquire_repository()[0]
459
def create_branch_convenience(base, force_new_repo=False,
460
force_new_tree=None, format=None,
461
possible_transports=None):
462
"""Create a new BzrDir, Branch and Repository at the url 'base'.
464
This is a convenience function - it will use an existing repository
465
if possible, can be told explicitly whether to create a working tree or
468
This will use the current default BzrDirFormat unless one is
469
specified, and use whatever
470
repository format that that uses via bzrdir.create_branch and
471
create_repository. If a shared repository is available that is used
472
preferentially. Whatever repository is used, its tree creation policy
475
The created Branch object is returned.
476
If a working tree cannot be made due to base not being a file:// url,
477
no error is raised unless force_new_tree is True, in which case no
478
data is created on disk and NotLocalUrl is raised.
480
:param base: The URL to create the branch at.
481
:param force_new_repo: If True a new repository is always created.
482
:param force_new_tree: If True or False force creation of a tree or
483
prevent such creation respectively.
484
:param format: Override for the bzrdir format to create.
485
:param possible_transports: An optional reusable transports list.
488
# check for non local urls
489
t = get_transport(base, possible_transports)
490
if not isinstance(t, local.LocalTransport):
491
raise errors.NotLocalUrl(base)
492
bzrdir = BzrDir.create(base, format, possible_transports)
493
repo = bzrdir._find_or_create_repository(force_new_repo)
494
result = bzrdir.create_branch()
495
if force_new_tree or (repo.make_working_trees() and
496
force_new_tree is None):
498
bzrdir.create_workingtree()
499
except errors.NotLocalUrl:
504
def create_standalone_workingtree(base, format=None):
505
"""Create a new BzrDir, WorkingTree, Branch and Repository at 'base'.
507
'base' must be a local path or a file:// url.
509
This will use the current default BzrDirFormat unless one is
510
specified, and use whatever
511
repository format that that uses for bzrdirformat.create_workingtree,
512
create_branch and create_repository.
514
:param format: Override for the bzrdir format to create.
515
:return: The WorkingTree object.
517
t = get_transport(base)
518
if not isinstance(t, local.LocalTransport):
519
raise errors.NotLocalUrl(base)
520
bzrdir = BzrDir.create_branch_and_repo(base,
522
format=format).bzrdir
523
return bzrdir.create_workingtree()
525
def create_workingtree(self, revision_id=None, from_branch=None,
526
accelerator_tree=None, hardlink=False):
527
"""Create a working tree at this BzrDir.
529
:param revision_id: create it as of this revision id.
530
:param from_branch: override bzrdir branch (for lightweight checkouts)
531
:param accelerator_tree: A tree which can be used for retrieving file
532
contents more quickly than the revision tree, i.e. a workingtree.
533
The revision tree will be used for cases where accelerator_tree's
534
content is different.
536
raise NotImplementedError(self.create_workingtree)
538
def backup_bzrdir(self):
539
"""Backup this bzr control directory.
541
:return: Tuple with old path name and new path name
543
pb = ui.ui_factory.nested_progress_bar()
545
# FIXME: bug 300001 -- the backup fails if the backup directory
546
# already exists, but it should instead either remove it or make
547
# a new backup directory.
549
# FIXME: bug 262450 -- the backup directory should have the same
550
# permissions as the .bzr directory (probably a bug in copy_tree)
551
old_path = self.root_transport.abspath('.bzr')
552
new_path = self.root_transport.abspath('backup.bzr')
553
pb.note('making backup of %s' % (old_path,))
554
pb.note(' to %s' % (new_path,))
555
self.root_transport.copy_tree('.bzr', 'backup.bzr')
556
return (old_path, new_path)
560
def retire_bzrdir(self, limit=10000):
561
"""Permanently disable the bzrdir.
563
This is done by renaming it to give the user some ability to recover
564
if there was a problem.
566
This will have horrible consequences if anyone has anything locked or
568
:param limit: number of times to retry
573
to_path = '.bzr.retired.%d' % i
574
self.root_transport.rename('.bzr', to_path)
575
note("renamed %s to %s"
576
% (self.root_transport.abspath('.bzr'), to_path))
578
except (errors.TransportError, IOError, errors.PathError):
585
def destroy_workingtree(self):
586
"""Destroy the working tree at this BzrDir.
588
Formats that do not support this may raise UnsupportedOperation.
590
raise NotImplementedError(self.destroy_workingtree)
592
def destroy_workingtree_metadata(self):
593
"""Destroy the control files for the working tree at this BzrDir.
595
The contents of working tree files are not affected.
596
Formats that do not support this may raise UnsupportedOperation.
598
raise NotImplementedError(self.destroy_workingtree_metadata)
600
def _find_containing(self, evaluate):
601
"""Find something in a containing control directory.
603
This method will scan containing control dirs, until it finds what
604
it is looking for, decides that it will never find it, or runs out
605
of containing control directories to check.
607
It is used to implement find_repository and
608
determine_repository_policy.
610
:param evaluate: A function returning (value, stop). If stop is True,
611
the value will be returned.
615
result, stop = evaluate(found_bzrdir)
618
next_transport = found_bzrdir.root_transport.clone('..')
619
if (found_bzrdir.root_transport.base == next_transport.base):
620
# top of the file system
622
# find the next containing bzrdir
624
found_bzrdir = BzrDir.open_containing_from_transport(
626
except errors.NotBranchError:
629
def find_repository(self):
630
"""Find the repository that should be used.
632
This does not require a branch as we use it to find the repo for
633
new branches as well as to hook existing branches up to their
636
def usable_repository(found_bzrdir):
637
# does it have a repository ?
639
repository = found_bzrdir.open_repository()
640
except errors.NoRepositoryPresent:
642
if found_bzrdir.root_transport.base == self.root_transport.base:
643
return repository, True
644
elif repository.is_shared():
645
return repository, True
649
found_repo = self._find_containing(usable_repository)
650
if found_repo is None:
651
raise errors.NoRepositoryPresent(self)
654
def get_branch_reference(self):
655
"""Return the referenced URL for the branch in this bzrdir.
657
:raises NotBranchError: If there is no Branch.
658
:return: The URL the branch in this bzrdir references if it is a
659
reference branch, or None for regular branches.
663
def get_branch_transport(self, branch_format):
664
"""Get the transport for use by branch format in this BzrDir.
666
Note that bzr dirs that do not support format strings will raise
667
IncompatibleFormat if the branch format they are given has
668
a format string, and vice versa.
670
If branch_format is None, the transport is returned with no
671
checking. If it is not None, then the returned transport is
672
guaranteed to point to an existing directory ready for use.
674
raise NotImplementedError(self.get_branch_transport)
676
def _find_creation_modes(self):
677
"""Determine the appropriate modes for files and directories.
679
They're always set to be consistent with the base directory,
680
assuming that this transport allows setting modes.
682
# TODO: Do we need or want an option (maybe a config setting) to turn
683
# this off or override it for particular locations? -- mbp 20080512
684
if self._mode_check_done:
686
self._mode_check_done = True
688
st = self.transport.stat('.')
689
except errors.TransportNotPossible:
690
self._dir_mode = None
691
self._file_mode = None
693
# Check the directory mode, but also make sure the created
694
# directories and files are read-write for this user. This is
695
# mostly a workaround for filesystems which lie about being able to
696
# write to a directory (cygwin & win32)
697
if (st.st_mode & 07777 == 00000):
698
# FTP allows stat but does not return dir/file modes
699
self._dir_mode = None
700
self._file_mode = None
702
self._dir_mode = (st.st_mode & 07777) | 00700
703
# Remove the sticky and execute bits for files
704
self._file_mode = self._dir_mode & ~07111
706
def _get_file_mode(self):
707
"""Return Unix mode for newly created files, or None.
709
if not self._mode_check_done:
710
self._find_creation_modes()
711
return self._file_mode
713
def _get_dir_mode(self):
714
"""Return Unix mode for newly created directories, or None.
716
if not self._mode_check_done:
717
self._find_creation_modes()
718
return self._dir_mode
720
def get_repository_transport(self, repository_format):
721
"""Get the transport for use by repository format in this BzrDir.
723
Note that bzr dirs that do not support format strings will raise
724
IncompatibleFormat if the repository format they are given has
725
a format string, and vice versa.
727
If repository_format is None, the transport is returned with no
728
checking. If it is not None, then the returned transport is
729
guaranteed to point to an existing directory ready for use.
731
raise NotImplementedError(self.get_repository_transport)
733
def get_workingtree_transport(self, tree_format):
734
"""Get the transport for use by workingtree format in this BzrDir.
736
Note that bzr dirs that do not support format strings will raise
737
IncompatibleFormat if the workingtree format they are given has a
738
format string, and vice versa.
740
If workingtree_format is None, the transport is returned with no
741
checking. If it is not None, then the returned transport is
742
guaranteed to point to an existing directory ready for use.
744
raise NotImplementedError(self.get_workingtree_transport)
746
def get_config(self):
747
if getattr(self, '_get_config', None) is None:
749
return self._get_config()
751
def __init__(self, _transport, _format):
752
"""Initialize a Bzr control dir object.
754
Only really common logic should reside here, concrete classes should be
755
made with varying behaviours.
757
:param _format: the format that is creating this BzrDir instance.
758
:param _transport: the transport this dir is based at.
760
self._format = _format
761
self.transport = _transport.clone('.bzr')
762
self.root_transport = _transport
763
self._mode_check_done = False
765
def is_control_filename(self, filename):
766
"""True if filename is the name of a path which is reserved for bzrdir's.
768
:param filename: A filename within the root transport of this bzrdir.
770
This is true IF and ONLY IF the filename is part of the namespace reserved
771
for bzr control dirs. Currently this is the '.bzr' directory in the root
772
of the root_transport. it is expected that plugins will need to extend
773
this in the future - for instance to make bzr talk with svn working
776
# this might be better on the BzrDirFormat class because it refers to
777
# all the possible bzrdir disk formats.
778
# This method is tested via the workingtree is_control_filename tests-
779
# it was extracted from WorkingTree.is_control_filename. If the method's
780
# contract is extended beyond the current trivial implementation, please
781
# add new tests for it to the appropriate place.
782
return filename == '.bzr' or filename.startswith('.bzr/')
784
def needs_format_conversion(self, format=None):
785
"""Return true if this bzrdir needs convert_format run on it.
787
For instance, if the repository format is out of date but the
788
branch and working tree are not, this should return True.
790
:param format: Optional parameter indicating a specific desired
791
format we plan to arrive at.
793
raise NotImplementedError(self.needs_format_conversion)
796
def open_unsupported(base):
797
"""Open a branch which is not supported."""
798
return BzrDir.open(base, _unsupported=True)
801
def open(base, _unsupported=False, possible_transports=None):
802
"""Open an existing bzrdir, rooted at 'base' (url).
804
:param _unsupported: a private parameter to the BzrDir class.
806
t = get_transport(base, possible_transports=possible_transports)
807
return BzrDir.open_from_transport(t, _unsupported=_unsupported)
810
def open_from_transport(transport, _unsupported=False,
811
_server_formats=True):
812
"""Open a bzrdir within a particular directory.
814
:param transport: Transport containing the bzrdir.
815
:param _unsupported: private.
817
for hook in BzrDir.hooks['pre_open']:
819
# Keep initial base since 'transport' may be modified while following
821
base = transport.base
822
def find_format(transport):
823
return transport, BzrDirFormat.find_format(
824
transport, _server_formats=_server_formats)
826
def redirected(transport, e, redirection_notice):
827
redirected_transport = transport._redirected_to(e.source, e.target)
828
if redirected_transport is None:
829
raise errors.NotBranchError(base)
830
note('%s is%s redirected to %s',
831
transport.base, e.permanently, redirected_transport.base)
832
return redirected_transport
835
transport, format = do_catching_redirections(find_format,
838
except errors.TooManyRedirections:
839
raise errors.NotBranchError(base)
841
BzrDir._check_supported(format, _unsupported)
842
return format.open(transport, _found=True)
844
def open_branch(self, unsupported=False, ignore_fallbacks=False):
845
"""Open the branch object at this BzrDir if one is present.
847
If unsupported is True, then no longer supported branch formats can
850
TODO: static convenience version of this?
852
raise NotImplementedError(self.open_branch)
855
def open_containing(url, possible_transports=None):
856
"""Open an existing branch which contains url.
858
:param url: url to search from.
859
See open_containing_from_transport for more detail.
861
transport = get_transport(url, possible_transports)
862
return BzrDir.open_containing_from_transport(transport)
865
def open_containing_from_transport(a_transport):
866
"""Open an existing branch which contains a_transport.base.
868
This probes for a branch at a_transport, and searches upwards from there.
870
Basically we keep looking up until we find the control directory or
871
run into the root. If there isn't one, raises NotBranchError.
872
If there is one and it is either an unrecognised format or an unsupported
873
format, UnknownFormatError or UnsupportedFormatError are raised.
874
If there is one, it is returned, along with the unused portion of url.
876
:return: The BzrDir that contains the path, and a Unicode path
877
for the rest of the URL.
879
# this gets the normalised url back. I.e. '.' -> the full path.
880
url = a_transport.base
883
result = BzrDir.open_from_transport(a_transport)
884
return result, urlutils.unescape(a_transport.relpath(url))
885
except errors.NotBranchError, e:
888
new_t = a_transport.clone('..')
889
except errors.InvalidURLJoin:
890
# reached the root, whatever that may be
891
raise errors.NotBranchError(path=url)
892
if new_t.base == a_transport.base:
893
# reached the root, whatever that may be
894
raise errors.NotBranchError(path=url)
897
def _get_tree_branch(self):
898
"""Return the branch and tree, if any, for this bzrdir.
900
Return None for tree if not present or inaccessible.
901
Raise NotBranchError if no branch is present.
902
:return: (tree, branch)
905
tree = self.open_workingtree()
906
except (errors.NoWorkingTree, errors.NotLocalUrl):
908
branch = self.open_branch()
914
def open_tree_or_branch(klass, location):
915
"""Return the branch and working tree at a location.
917
If there is no tree at the location, tree will be None.
918
If there is no branch at the location, an exception will be
920
:return: (tree, branch)
922
bzrdir = klass.open(location)
923
return bzrdir._get_tree_branch()
926
def open_containing_tree_or_branch(klass, location):
927
"""Return the branch and working tree contained by a location.
929
Returns (tree, branch, relpath).
930
If there is no tree at containing the location, tree will be None.
931
If there is no branch containing the location, an exception will be
933
relpath is the portion of the path that is contained by the branch.
935
bzrdir, relpath = klass.open_containing(location)
936
tree, branch = bzrdir._get_tree_branch()
937
return tree, branch, relpath
940
def open_containing_tree_branch_or_repository(klass, location):
941
"""Return the working tree, branch and repo contained by a location.
943
Returns (tree, branch, repository, relpath).
944
If there is no tree containing the location, tree will be None.
945
If there is no branch containing the location, branch will be None.
946
If there is no repository containing the location, repository will be
948
relpath is the portion of the path that is contained by the innermost
951
If no tree, branch or repository is found, a NotBranchError is raised.
953
bzrdir, relpath = klass.open_containing(location)
955
tree, branch = bzrdir._get_tree_branch()
956
except errors.NotBranchError:
958
repo = bzrdir.find_repository()
959
return None, None, repo, relpath
960
except (errors.NoRepositoryPresent):
961
raise errors.NotBranchError(location)
962
return tree, branch, branch.repository, relpath
964
def open_repository(self, _unsupported=False):
965
"""Open the repository object at this BzrDir if one is present.
967
This will not follow the Branch object pointer - it's strictly a direct
968
open facility. Most client code should use open_branch().repository to
971
:param _unsupported: a private parameter, not part of the api.
972
TODO: static convenience version of this?
974
raise NotImplementedError(self.open_repository)
976
def open_workingtree(self, _unsupported=False,
977
recommend_upgrade=True, from_branch=None):
978
"""Open the workingtree object at this BzrDir if one is present.
980
:param recommend_upgrade: Optional keyword parameter, when True (the
981
default), emit through the ui module a recommendation that the user
982
upgrade the working tree when the workingtree being opened is old
983
(but still fully supported).
984
:param from_branch: override bzrdir branch (for lightweight checkouts)
986
raise NotImplementedError(self.open_workingtree)
988
def has_branch(self):
989
"""Tell if this bzrdir contains a branch.
991
Note: if you're going to open the branch, you should just go ahead
992
and try, and not ask permission first. (This method just opens the
993
branch and discards it, and that's somewhat expensive.)
998
except errors.NotBranchError:
1001
def has_workingtree(self):
1002
"""Tell if this bzrdir contains a working tree.
1004
This will still raise an exception if the bzrdir has a workingtree that
1005
is remote & inaccessible.
1007
Note: if you're going to open the working tree, you should just go ahead
1008
and try, and not ask permission first. (This method just opens the
1009
workingtree and discards it, and that's somewhat expensive.)
1012
self.open_workingtree(recommend_upgrade=False)
1014
except errors.NoWorkingTree:
1017
def _cloning_metadir(self):
1018
"""Produce a metadir suitable for cloning with.
1020
:returns: (destination_bzrdir_format, source_repository)
1022
result_format = self._format.__class__()
1025
branch = self.open_branch(ignore_fallbacks=True)
1026
source_repository = branch.repository
1027
result_format._branch_format = branch._format
1028
except errors.NotBranchError:
1029
source_branch = None
1030
source_repository = self.open_repository()
1031
except errors.NoRepositoryPresent:
1032
source_repository = None
1034
# XXX TODO: This isinstance is here because we have not implemented
1035
# the fix recommended in bug # 103195 - to delegate this choice the
1036
# repository itself.
1037
repo_format = source_repository._format
1038
if isinstance(repo_format, remote.RemoteRepositoryFormat):
1039
source_repository._ensure_real()
1040
repo_format = source_repository._real_repository._format
1041
result_format.repository_format = repo_format
1043
# TODO: Couldn't we just probe for the format in these cases,
1044
# rather than opening the whole tree? It would be a little
1045
# faster. mbp 20070401
1046
tree = self.open_workingtree(recommend_upgrade=False)
1047
except (errors.NoWorkingTree, errors.NotLocalUrl):
1048
result_format.workingtree_format = None
1050
result_format.workingtree_format = tree._format.__class__()
1051
return result_format, source_repository
1053
def cloning_metadir(self, require_stacking=False):
1054
"""Produce a metadir suitable for cloning or sprouting with.
1056
These operations may produce workingtrees (yes, even though they're
1057
"cloning" something that doesn't have a tree), so a viable workingtree
1058
format must be selected.
1060
:require_stacking: If True, non-stackable formats will be upgraded
1061
to similar stackable formats.
1062
:returns: a BzrDirFormat with all component formats either set
1063
appropriately or set to None if that component should not be
1066
format, repository = self._cloning_metadir()
1067
if format._workingtree_format is None:
1068
if repository is None:
1070
tree_format = repository._format._matchingbzrdir.workingtree_format
1071
format.workingtree_format = tree_format.__class__()
1072
if require_stacking:
1073
format.require_stacking()
1076
def checkout_metadir(self):
1077
return self.cloning_metadir()
1079
def sprout(self, url, revision_id=None, force_new_repo=False,
1080
recurse='down', possible_transports=None,
1081
accelerator_tree=None, hardlink=False, stacked=False,
1082
source_branch=None, create_tree_if_local=True):
1083
"""Create a copy of this bzrdir prepared for use as a new line of
1086
If url's last component does not exist, it will be created.
1088
Attributes related to the identity of the source branch like
1089
branch nickname will be cleaned, a working tree is created
1090
whether one existed before or not; and a local branch is always
1093
if revision_id is not None, then the clone operation may tune
1094
itself to download less data.
1095
:param accelerator_tree: A tree which can be used for retrieving file
1096
contents more quickly than the revision tree, i.e. a workingtree.
1097
The revision tree will be used for cases where accelerator_tree's
1098
content is different.
1099
:param hardlink: If true, hard-link files from accelerator_tree,
1101
:param stacked: If true, create a stacked branch referring to the
1102
location of this control directory.
1103
:param create_tree_if_local: If true, a working-tree will be created
1104
when working locally.
1106
target_transport = get_transport(url, possible_transports)
1107
target_transport.ensure_base()
1108
cloning_format = self.cloning_metadir(stacked)
1109
# Create/update the result branch
1110
result = cloning_format.initialize_on_transport(target_transport)
1111
# if a stacked branch wasn't requested, we don't create one
1112
# even if the origin was stacked
1113
stacked_branch_url = None
1114
if source_branch is not None:
1116
stacked_branch_url = self.root_transport.base
1117
source_repository = source_branch.repository
1120
source_branch = self.open_branch()
1121
source_repository = source_branch.repository
1123
stacked_branch_url = self.root_transport.base
1124
except errors.NotBranchError:
1125
source_branch = None
1127
source_repository = self.open_repository()
1128
except errors.NoRepositoryPresent:
1129
source_repository = None
1130
repository_policy = result.determine_repository_policy(
1131
force_new_repo, stacked_branch_url, require_stacking=stacked)
1132
result_repo, is_new_repo = repository_policy.acquire_repository()
1133
if is_new_repo and revision_id is not None and not stacked:
1134
fetch_spec = graph.PendingAncestryResult(
1135
[revision_id], source_repository)
1138
if source_repository is not None:
1139
# Fetch while stacked to prevent unstacked fetch from
1141
if fetch_spec is None:
1142
result_repo.fetch(source_repository, revision_id=revision_id)
1144
result_repo.fetch(source_repository, fetch_spec=fetch_spec)
1146
if source_branch is None:
1147
# this is for sprouting a bzrdir without a branch; is that
1149
# Not especially, but it's part of the contract.
1150
result_branch = result.create_branch()
1152
result_branch = source_branch.sprout(result,
1153
revision_id=revision_id, repository_policy=repository_policy)
1154
mutter("created new branch %r" % (result_branch,))
1156
# Create/update the result working tree
1157
if (create_tree_if_local and
1158
isinstance(target_transport, local.LocalTransport) and
1159
(result_repo is None or result_repo.make_working_trees())):
1160
wt = result.create_workingtree(accelerator_tree=accelerator_tree,
1164
if wt.path2id('') is None:
1166
wt.set_root_id(self.open_workingtree.get_root_id())
1167
except errors.NoWorkingTree:
1173
if recurse == 'down':
1175
basis = wt.basis_tree()
1177
subtrees = basis.iter_references()
1178
elif result_branch is not None:
1179
basis = result_branch.basis_tree()
1181
subtrees = basis.iter_references()
1182
elif source_branch is not None:
1183
basis = source_branch.basis_tree()
1185
subtrees = basis.iter_references()
1190
for path, file_id in subtrees:
1191
target = urlutils.join(url, urlutils.escape(path))
1192
sublocation = source_branch.reference_parent(file_id, path)
1193
sublocation.bzrdir.sprout(target,
1194
basis.get_reference_revision(file_id, path),
1195
force_new_repo=force_new_repo, recurse=recurse,
1198
if basis is not None:
1202
def push_branch(self, source, revision_id=None, overwrite=False,
1204
"""Push the source branch into this BzrDir."""
1206
# If we can open a branch, use its direct repository, otherwise see
1207
# if there is a repository without a branch.
1209
br_to = self.open_branch()
1210
except errors.NotBranchError:
1211
# Didn't find a branch, can we find a repository?
1212
repository_to = self.find_repository()
1214
# Found a branch, so we must have found a repository
1215
repository_to = br_to.repository
1217
push_result = PushResult()
1218
push_result.source_branch = source
1220
# We have a repository but no branch, copy the revisions, and then
1222
repository_to.fetch(source.repository, revision_id=revision_id)
1223
br_to = source.clone(self, revision_id=revision_id)
1224
if source.get_push_location() is None or remember:
1225
source.set_push_location(br_to.base)
1226
push_result.stacked_on = None
1227
push_result.branch_push_result = None
1228
push_result.old_revno = None
1229
push_result.old_revid = _mod_revision.NULL_REVISION
1230
push_result.target_branch = br_to
1231
push_result.master_branch = None
1232
push_result.workingtree_updated = False
1234
# We have successfully opened the branch, remember if necessary:
1235
if source.get_push_location() is None or remember:
1236
source.set_push_location(br_to.base)
1238
tree_to = self.open_workingtree()
1239
except errors.NotLocalUrl:
1240
push_result.branch_push_result = source.push(br_to,
1241
overwrite, stop_revision=revision_id)
1242
push_result.workingtree_updated = False
1243
except errors.NoWorkingTree:
1244
push_result.branch_push_result = source.push(br_to,
1245
overwrite, stop_revision=revision_id)
1246
push_result.workingtree_updated = None # Not applicable
1248
tree_to.lock_write()
1250
push_result.branch_push_result = source.push(
1251
tree_to.branch, overwrite, stop_revision=revision_id)
1255
push_result.workingtree_updated = True
1256
push_result.old_revno = push_result.branch_push_result.old_revno
1257
push_result.old_revid = push_result.branch_push_result.old_revid
1258
push_result.target_branch = \
1259
push_result.branch_push_result.target_branch
1263
class BzrDirHooks(hooks.Hooks):
1264
"""Hooks for BzrDir operations."""
1267
"""Create the default hooks."""
1268
hooks.Hooks.__init__(self)
1269
self.create_hook(hooks.HookPoint('pre_open',
1270
"Invoked before attempting to open a BzrDir with the transport "
1271
"that the open will use.", (1, 14), None))
1273
# install the default hooks
1274
BzrDir.hooks = BzrDirHooks()
1277
class BzrDirPreSplitOut(BzrDir):
1278
"""A common class for the all-in-one formats."""
1280
def __init__(self, _transport, _format):
1281
"""See BzrDir.__init__."""
1282
super(BzrDirPreSplitOut, self).__init__(_transport, _format)
1283
self._control_files = lockable_files.LockableFiles(
1284
self.get_branch_transport(None),
1285
self._format._lock_file_name,
1286
self._format._lock_class)
1288
def break_lock(self):
1289
"""Pre-splitout bzrdirs do not suffer from stale locks."""
1290
raise NotImplementedError(self.break_lock)
1292
def cloning_metadir(self, require_stacking=False):
1293
"""Produce a metadir suitable for cloning with."""
1294
if require_stacking:
1295
return format_registry.make_bzrdir('1.6')
1296
return self._format.__class__()
1298
def clone(self, url, revision_id=None, force_new_repo=False,
1299
preserve_stacking=False):
1300
"""See BzrDir.clone().
1302
force_new_repo has no effect, since this family of formats always
1303
require a new repository.
1304
preserve_stacking has no effect, since no source branch using this
1305
family of formats can be stacked, so there is no stacking to preserve.
1307
self._make_tail(url)
1308
result = self._format._initialize_for_clone(url)
1309
self.open_repository().clone(result, revision_id=revision_id)
1310
from_branch = self.open_branch()
1311
from_branch.clone(result, revision_id=revision_id)
1313
tree = self.open_workingtree()
1314
except errors.NotLocalUrl:
1315
# make a new one, this format always has to have one.
1316
result._init_workingtree()
1321
def create_branch(self):
1322
"""See BzrDir.create_branch."""
1323
return self._format.get_branch_format().initialize(self)
1325
def destroy_branch(self):
1326
"""See BzrDir.destroy_branch."""
1327
raise errors.UnsupportedOperation(self.destroy_branch, self)
1329
def create_repository(self, shared=False):
1330
"""See BzrDir.create_repository."""
1332
raise errors.IncompatibleFormat('shared repository', self._format)
1333
return self.open_repository()
1335
def destroy_repository(self):
1336
"""See BzrDir.destroy_repository."""
1337
raise errors.UnsupportedOperation(self.destroy_repository, self)
1339
def create_workingtree(self, revision_id=None, from_branch=None,
1340
accelerator_tree=None, hardlink=False):
1341
"""See BzrDir.create_workingtree."""
1342
# The workingtree is sometimes created when the bzrdir is created,
1343
# but not when cloning.
1345
# this looks buggy but is not -really-
1346
# because this format creates the workingtree when the bzrdir is
1348
# clone and sprout will have set the revision_id
1349
# and that will have set it for us, its only
1350
# specific uses of create_workingtree in isolation
1351
# that can do wonky stuff here, and that only
1352
# happens for creating checkouts, which cannot be
1353
# done on this format anyway. So - acceptable wart.
1355
result = self.open_workingtree(recommend_upgrade=False)
1356
except errors.NoSuchFile:
1357
result = self._init_workingtree()
1358
if revision_id is not None:
1359
if revision_id == _mod_revision.NULL_REVISION:
1360
result.set_parent_ids([])
1362
result.set_parent_ids([revision_id])
1365
def _init_workingtree(self):
1366
from bzrlib.workingtree import WorkingTreeFormat2
1368
return WorkingTreeFormat2().initialize(self)
1369
except errors.NotLocalUrl:
1370
# Even though we can't access the working tree, we need to
1371
# create its control files.
1372
return WorkingTreeFormat2()._stub_initialize_on_transport(
1373
self.transport, self._control_files._file_mode)
1375
def destroy_workingtree(self):
1376
"""See BzrDir.destroy_workingtree."""
1377
raise errors.UnsupportedOperation(self.destroy_workingtree, self)
1379
def destroy_workingtree_metadata(self):
1380
"""See BzrDir.destroy_workingtree_metadata."""
1381
raise errors.UnsupportedOperation(self.destroy_workingtree_metadata,
1384
def get_branch_transport(self, branch_format):
1385
"""See BzrDir.get_branch_transport()."""
1386
if branch_format is None:
1387
return self.transport
1389
branch_format.get_format_string()
1390
except NotImplementedError:
1391
return self.transport
1392
raise errors.IncompatibleFormat(branch_format, self._format)
1394
def get_repository_transport(self, repository_format):
1395
"""See BzrDir.get_repository_transport()."""
1396
if repository_format is None:
1397
return self.transport
1399
repository_format.get_format_string()
1400
except NotImplementedError:
1401
return self.transport
1402
raise errors.IncompatibleFormat(repository_format, self._format)
1404
def get_workingtree_transport(self, workingtree_format):
1405
"""See BzrDir.get_workingtree_transport()."""
1406
if workingtree_format is None:
1407
return self.transport
1409
workingtree_format.get_format_string()
1410
except NotImplementedError:
1411
return self.transport
1412
raise errors.IncompatibleFormat(workingtree_format, self._format)
1414
def needs_format_conversion(self, format=None):
1415
"""See BzrDir.needs_format_conversion()."""
1416
# if the format is not the same as the system default,
1417
# an upgrade is needed.
1419
symbol_versioning.warn(symbol_versioning.deprecated_in((1, 13, 0))
1420
% 'needs_format_conversion(format=None)')
1421
format = BzrDirFormat.get_default_format()
1422
return not isinstance(self._format, format.__class__)
1424
def open_branch(self, unsupported=False, ignore_fallbacks=False):
1425
"""See BzrDir.open_branch."""
1426
from bzrlib.branch import BzrBranchFormat4
1427
format = BzrBranchFormat4()
1428
self._check_supported(format, unsupported)
1429
return format.open(self, _found=True)
1431
def sprout(self, url, revision_id=None, force_new_repo=False,
1432
possible_transports=None, accelerator_tree=None,
1433
hardlink=False, stacked=False, create_tree_if_local=True,
1434
source_branch=None):
1435
"""See BzrDir.sprout()."""
1436
if source_branch is not None:
1437
my_branch = self.open_branch()
1438
if source_branch.base != my_branch.base:
1439
raise AssertionError(
1440
"source branch %r is not within %r with branch %r" %
1441
(source_branch, self, my_branch))
1443
raise errors.UnstackableBranchFormat(
1444
self._format, self.root_transport.base)
1445
if not create_tree_if_local:
1446
raise errors.MustHaveWorkingTree(
1447
self._format, self.root_transport.base)
1448
from bzrlib.workingtree import WorkingTreeFormat2
1449
self._make_tail(url)
1450
result = self._format._initialize_for_clone(url)
1452
self.open_repository().clone(result, revision_id=revision_id)
1453
except errors.NoRepositoryPresent:
1456
self.open_branch().sprout(result, revision_id=revision_id)
1457
except errors.NotBranchError:
1460
# we always want a working tree
1461
WorkingTreeFormat2().initialize(result,
1462
accelerator_tree=accelerator_tree,
1467
class BzrDir4(BzrDirPreSplitOut):
1468
"""A .bzr version 4 control object.
1470
This is a deprecated format and may be removed after sept 2006.
1473
def create_repository(self, shared=False):
1474
"""See BzrDir.create_repository."""
1475
return self._format.repository_format.initialize(self, shared)
1477
def needs_format_conversion(self, format=None):
1478
"""Format 4 dirs are always in need of conversion."""
1480
symbol_versioning.warn(symbol_versioning.deprecated_in((1, 13, 0))
1481
% 'needs_format_conversion(format=None)')
1484
def open_repository(self):
1485
"""See BzrDir.open_repository."""
1486
from bzrlib.repofmt.weaverepo import RepositoryFormat4
1487
return RepositoryFormat4().open(self, _found=True)
1490
class BzrDir5(BzrDirPreSplitOut):
1491
"""A .bzr version 5 control object.
1493
This is a deprecated format and may be removed after sept 2006.
1496
def open_repository(self):
1497
"""See BzrDir.open_repository."""
1498
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1499
return RepositoryFormat5().open(self, _found=True)
1501
def open_workingtree(self, _unsupported=False,
1502
recommend_upgrade=True):
1503
"""See BzrDir.create_workingtree."""
1504
from bzrlib.workingtree import WorkingTreeFormat2
1505
wt_format = WorkingTreeFormat2()
1506
# we don't warn here about upgrades; that ought to be handled for the
1508
return wt_format.open(self, _found=True)
1511
class BzrDir6(BzrDirPreSplitOut):
1512
"""A .bzr version 6 control object.
1514
This is a deprecated format and may be removed after sept 2006.
1517
def open_repository(self):
1518
"""See BzrDir.open_repository."""
1519
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1520
return RepositoryFormat6().open(self, _found=True)
1522
def open_workingtree(self, _unsupported=False,
1523
recommend_upgrade=True):
1524
"""See BzrDir.create_workingtree."""
1525
# we don't warn here about upgrades; that ought to be handled for the
1527
from bzrlib.workingtree import WorkingTreeFormat2
1528
return WorkingTreeFormat2().open(self, _found=True)
1531
class BzrDirMeta1(BzrDir):
1532
"""A .bzr meta version 1 control object.
1534
This is the first control object where the
1535
individual aspects are really split out: there are separate repository,
1536
workingtree and branch subdirectories and any subset of the three can be
1537
present within a BzrDir.
1540
def can_convert_format(self):
1541
"""See BzrDir.can_convert_format()."""
1544
def create_branch(self):
1545
"""See BzrDir.create_branch."""
1546
return self._format.get_branch_format().initialize(self)
1548
def destroy_branch(self):
1549
"""See BzrDir.create_branch."""
1550
self.transport.delete_tree('branch')
1552
def create_repository(self, shared=False):
1553
"""See BzrDir.create_repository."""
1554
return self._format.repository_format.initialize(self, shared)
1556
def destroy_repository(self):
1557
"""See BzrDir.destroy_repository."""
1558
self.transport.delete_tree('repository')
1560
def create_workingtree(self, revision_id=None, from_branch=None,
1561
accelerator_tree=None, hardlink=False):
1562
"""See BzrDir.create_workingtree."""
1563
return self._format.workingtree_format.initialize(
1564
self, revision_id, from_branch=from_branch,
1565
accelerator_tree=accelerator_tree, hardlink=hardlink)
1567
def destroy_workingtree(self):
1568
"""See BzrDir.destroy_workingtree."""
1569
wt = self.open_workingtree(recommend_upgrade=False)
1570
repository = wt.branch.repository
1571
empty = repository.revision_tree(_mod_revision.NULL_REVISION)
1572
wt.revert(old_tree=empty)
1573
self.destroy_workingtree_metadata()
1575
def destroy_workingtree_metadata(self):
1576
self.transport.delete_tree('checkout')
1578
def find_branch_format(self):
1579
"""Find the branch 'format' for this bzrdir.
1581
This might be a synthetic object for e.g. RemoteBranch and SVN.
1583
from bzrlib.branch import BranchFormat
1584
return BranchFormat.find_format(self)
1586
def _get_mkdir_mode(self):
1587
"""Figure out the mode to use when creating a bzrdir subdir."""
1588
temp_control = lockable_files.LockableFiles(self.transport, '',
1589
lockable_files.TransportLock)
1590
return temp_control._dir_mode
1592
def get_branch_reference(self):
1593
"""See BzrDir.get_branch_reference()."""
1594
from bzrlib.branch import BranchFormat
1595
format = BranchFormat.find_format(self)
1596
return format.get_reference(self)
1598
def get_branch_transport(self, branch_format):
1599
"""See BzrDir.get_branch_transport()."""
1600
if branch_format is None:
1601
return self.transport.clone('branch')
1603
branch_format.get_format_string()
1604
except NotImplementedError:
1605
raise errors.IncompatibleFormat(branch_format, self._format)
1607
self.transport.mkdir('branch', mode=self._get_mkdir_mode())
1608
except errors.FileExists:
1610
return self.transport.clone('branch')
1612
def get_repository_transport(self, repository_format):
1613
"""See BzrDir.get_repository_transport()."""
1614
if repository_format is None:
1615
return self.transport.clone('repository')
1617
repository_format.get_format_string()
1618
except NotImplementedError:
1619
raise errors.IncompatibleFormat(repository_format, self._format)
1621
self.transport.mkdir('repository', mode=self._get_mkdir_mode())
1622
except errors.FileExists:
1624
return self.transport.clone('repository')
1626
def get_workingtree_transport(self, workingtree_format):
1627
"""See BzrDir.get_workingtree_transport()."""
1628
if workingtree_format is None:
1629
return self.transport.clone('checkout')
1631
workingtree_format.get_format_string()
1632
except NotImplementedError:
1633
raise errors.IncompatibleFormat(workingtree_format, self._format)
1635
self.transport.mkdir('checkout', mode=self._get_mkdir_mode())
1636
except errors.FileExists:
1638
return self.transport.clone('checkout')
1640
def needs_format_conversion(self, format=None):
1641
"""See BzrDir.needs_format_conversion()."""
1643
symbol_versioning.warn(symbol_versioning.deprecated_in((1, 13, 0))
1644
% 'needs_format_conversion(format=None)')
1646
format = BzrDirFormat.get_default_format()
1647
if not isinstance(self._format, format.__class__):
1648
# it is not a meta dir format, conversion is needed.
1650
# we might want to push this down to the repository?
1652
if not isinstance(self.open_repository()._format,
1653
format.repository_format.__class__):
1654
# the repository needs an upgrade.
1656
except errors.NoRepositoryPresent:
1659
if not isinstance(self.open_branch()._format,
1660
format.get_branch_format().__class__):
1661
# the branch needs an upgrade.
1663
except errors.NotBranchError:
1666
my_wt = self.open_workingtree(recommend_upgrade=False)
1667
if not isinstance(my_wt._format,
1668
format.workingtree_format.__class__):
1669
# the workingtree needs an upgrade.
1671
except (errors.NoWorkingTree, errors.NotLocalUrl):
1675
def open_branch(self, unsupported=False, ignore_fallbacks=False):
1676
"""See BzrDir.open_branch."""
1677
format = self.find_branch_format()
1678
self._check_supported(format, unsupported)
1679
return format.open(self, _found=True, ignore_fallbacks=ignore_fallbacks)
1681
def open_repository(self, unsupported=False):
1682
"""See BzrDir.open_repository."""
1683
from bzrlib.repository import RepositoryFormat
1684
format = RepositoryFormat.find_format(self)
1685
self._check_supported(format, unsupported)
1686
return format.open(self, _found=True)
1688
def open_workingtree(self, unsupported=False,
1689
recommend_upgrade=True):
1690
"""See BzrDir.open_workingtree."""
1691
from bzrlib.workingtree import WorkingTreeFormat
1692
format = WorkingTreeFormat.find_format(self)
1693
self._check_supported(format, unsupported,
1695
basedir=self.root_transport.base)
1696
return format.open(self, _found=True)
1698
def _get_config(self):
1699
return config.BzrDirConfig(self.transport)
1702
class BzrDirFormat(object):
1703
"""An encapsulation of the initialization and open routines for a format.
1705
Formats provide three things:
1706
* An initialization routine,
1710
Formats are placed in a dict by their format string for reference
1711
during bzrdir opening. These should be subclasses of BzrDirFormat
1714
Once a format is deprecated, just deprecate the initialize and open
1715
methods on the format class. Do not deprecate the object, as the
1716
object will be created every system load.
1719
_default_format = None
1720
"""The default format used for new .bzr dirs."""
1723
"""The known formats."""
1725
_control_formats = []
1726
"""The registered control formats - .bzr, ....
1728
This is a list of BzrDirFormat objects.
1731
_control_server_formats = []
1732
"""The registered control server formats, e.g. RemoteBzrDirs.
1734
This is a list of BzrDirFormat objects.
1737
_lock_file_name = 'branch-lock'
1739
# _lock_class must be set in subclasses to the lock type, typ.
1740
# TransportLock or LockDir
1743
def find_format(klass, transport, _server_formats=True):
1744
"""Return the format present at transport."""
1746
formats = klass._control_server_formats + klass._control_formats
1748
formats = klass._control_formats
1749
for format in formats:
1751
return format.probe_transport(transport)
1752
except errors.NotBranchError:
1753
# this format does not find a control dir here.
1755
raise errors.NotBranchError(path=transport.base)
1758
def probe_transport(klass, transport):
1759
"""Return the .bzrdir style format present in a directory."""
1761
format_string = transport.get(".bzr/branch-format").read()
1762
except errors.NoSuchFile:
1763
raise errors.NotBranchError(path=transport.base)
1766
return klass._formats[format_string]
1768
raise errors.UnknownFormatError(format=format_string, kind='bzrdir')
1771
def get_default_format(klass):
1772
"""Return the current default format."""
1773
return klass._default_format
1775
def get_format_string(self):
1776
"""Return the ASCII format string that identifies this format."""
1777
raise NotImplementedError(self.get_format_string)
1779
def get_format_description(self):
1780
"""Return the short description for this format."""
1781
raise NotImplementedError(self.get_format_description)
1783
def get_converter(self, format=None):
1784
"""Return the converter to use to convert bzrdirs needing converts.
1786
This returns a bzrlib.bzrdir.Converter object.
1788
This should return the best upgrader to step this format towards the
1789
current default format. In the case of plugins we can/should provide
1790
some means for them to extend the range of returnable converters.
1792
:param format: Optional format to override the default format of the
1795
raise NotImplementedError(self.get_converter)
1797
def initialize(self, url, possible_transports=None):
1798
"""Create a bzr control dir at this url and return an opened copy.
1800
Subclasses should typically override initialize_on_transport
1801
instead of this method.
1803
return self.initialize_on_transport(get_transport(url,
1804
possible_transports))
1806
def initialize_on_transport(self, transport):
1807
"""Initialize a new bzrdir in the base directory of a Transport."""
1809
# can we hand off the request to the smart server rather than using
1811
client_medium = transport.get_smart_medium()
1812
except errors.NoSmartMedium:
1813
return self._initialize_on_transport_vfs(transport)
1815
# Current RPC's only know how to create bzr metadir1 instances, so
1816
# we still delegate to vfs methods if the requested format is not a
1818
if type(self) != BzrDirMetaFormat1:
1819
return self._initialize_on_transport_vfs(transport)
1820
remote_format = RemoteBzrDirFormat()
1821
self._supply_sub_formats_to(remote_format)
1822
return remote_format.initialize_on_transport(transport)
1824
def _initialize_on_transport_vfs(self, transport):
1825
"""Initialize a new bzrdir using VFS calls.
1827
:param transport: The transport to create the .bzr directory in.
1830
# Since we are creating a .bzr directory, inherit the
1831
# mode from the root directory
1832
temp_control = lockable_files.LockableFiles(transport,
1833
'', lockable_files.TransportLock)
1834
temp_control._transport.mkdir('.bzr',
1835
# FIXME: RBC 20060121 don't peek under
1837
mode=temp_control._dir_mode)
1838
if sys.platform == 'win32' and isinstance(transport, local.LocalTransport):
1839
win32utils.set_file_attr_hidden(transport._abspath('.bzr'))
1840
file_mode = temp_control._file_mode
1842
bzrdir_transport = transport.clone('.bzr')
1843
utf8_files = [('README',
1844
"This is a Bazaar control directory.\n"
1845
"Do not change any files in this directory.\n"
1846
"See http://bazaar-vcs.org/ for more information about Bazaar.\n"),
1847
('branch-format', self.get_format_string()),
1849
# NB: no need to escape relative paths that are url safe.
1850
control_files = lockable_files.LockableFiles(bzrdir_transport,
1851
self._lock_file_name, self._lock_class)
1852
control_files.create_lock()
1853
control_files.lock_write()
1855
for (filename, content) in utf8_files:
1856
bzrdir_transport.put_bytes(filename, content,
1859
control_files.unlock()
1860
return self.open(transport, _found=True)
1862
def is_supported(self):
1863
"""Is this format supported?
1865
Supported formats must be initializable and openable.
1866
Unsupported formats may not support initialization or committing or
1867
some other features depending on the reason for not being supported.
1871
def network_name(self):
1872
"""A simple byte string uniquely identifying this format for RPC calls.
1874
Bzr control formats use thir disk format string to identify the format
1875
over the wire. Its possible that other control formats have more
1876
complex detection requirements, so we permit them to use any unique and
1877
immutable string they desire.
1879
raise NotImplementedError(self.network_name)
1881
def same_model(self, target_format):
1882
return (self.repository_format.rich_root_data ==
1883
target_format.rich_root_data)
1886
def known_formats(klass):
1887
"""Return all the known formats.
1889
Concrete formats should override _known_formats.
1891
# There is double indirection here to make sure that control
1892
# formats used by more than one dir format will only be probed
1893
# once. This can otherwise be quite expensive for remote connections.
1895
for format in klass._control_formats:
1896
result.update(format._known_formats())
1900
def _known_formats(klass):
1901
"""Return the known format instances for this control format."""
1902
return set(klass._formats.values())
1904
def open(self, transport, _found=False):
1905
"""Return an instance of this format for the dir transport points at.
1907
_found is a private parameter, do not use it.
1910
found_format = BzrDirFormat.find_format(transport)
1911
if not isinstance(found_format, self.__class__):
1912
raise AssertionError("%s was asked to open %s, but it seems to need "
1914
% (self, transport, found_format))
1915
# Allow subclasses - use the found format.
1916
self._supply_sub_formats_to(found_format)
1917
return found_format._open(transport)
1918
return self._open(transport)
1920
def _open(self, transport):
1921
"""Template method helper for opening BzrDirectories.
1923
This performs the actual open and any additional logic or parameter
1926
raise NotImplementedError(self._open)
1929
def register_format(klass, format):
1930
klass._formats[format.get_format_string()] = format
1931
# bzr native formats have a network name of their format string.
1932
network_format_registry.register(format.get_format_string(), format.__class__)
1935
def register_control_format(klass, format):
1936
"""Register a format that does not use '.bzr' for its control dir.
1938
TODO: This should be pulled up into a 'ControlDirFormat' base class
1939
which BzrDirFormat can inherit from, and renamed to register_format
1940
there. It has been done without that for now for simplicity of
1943
klass._control_formats.append(format)
1946
def register_control_server_format(klass, format):
1947
"""Register a control format for client-server environments.
1949
These formats will be tried before ones registered with
1950
register_control_format. This gives implementations that decide to the
1951
chance to grab it before anything looks at the contents of the format
1954
klass._control_server_formats.append(format)
1957
def _set_default_format(klass, format):
1958
"""Set default format (for testing behavior of defaults only)"""
1959
klass._default_format = format
1963
return self.get_format_description().rstrip()
1965
def _supply_sub_formats_to(self, other_format):
1966
"""Give other_format the same values for sub formats as this has.
1968
This method is expected to be used when parameterising a
1969
RemoteBzrDirFormat instance with the parameters from a
1970
BzrDirMetaFormat1 instance.
1972
:param other_format: other_format is a format which should be
1973
compatible with whatever sub formats are supported by self.
1978
def unregister_format(klass, format):
1979
del klass._formats[format.get_format_string()]
1982
def unregister_control_format(klass, format):
1983
klass._control_formats.remove(format)
1986
class BzrDirFormat4(BzrDirFormat):
1987
"""Bzr dir format 4.
1989
This format is a combined format for working tree, branch and repository.
1991
- Format 1 working trees [always]
1992
- Format 4 branches [always]
1993
- Format 4 repositories [always]
1995
This format is deprecated: it indexes texts using a text it which is
1996
removed in format 5; write support for this format has been removed.
1999
_lock_class = lockable_files.TransportLock
2001
def get_format_string(self):
2002
"""See BzrDirFormat.get_format_string()."""
2003
return "Bazaar-NG branch, format 0.0.4\n"
2005
def get_format_description(self):
2006
"""See BzrDirFormat.get_format_description()."""
2007
return "All-in-one format 4"
2009
def get_converter(self, format=None):
2010
"""See BzrDirFormat.get_converter()."""
2011
# there is one and only one upgrade path here.
2012
return ConvertBzrDir4To5()
2014
def initialize_on_transport(self, transport):
2015
"""Format 4 branches cannot be created."""
2016
raise errors.UninitializableFormat(self)
2018
def is_supported(self):
2019
"""Format 4 is not supported.
2021
It is not supported because the model changed from 4 to 5 and the
2022
conversion logic is expensive - so doing it on the fly was not
2027
def network_name(self):
2028
return self.get_format_string()
2030
def _open(self, transport):
2031
"""See BzrDirFormat._open."""
2032
return BzrDir4(transport, self)
2034
def __return_repository_format(self):
2035
"""Circular import protection."""
2036
from bzrlib.repofmt.weaverepo import RepositoryFormat4
2037
return RepositoryFormat4()
2038
repository_format = property(__return_repository_format)
2041
class BzrDirFormat5(BzrDirFormat):
2042
"""Bzr control format 5.
2044
This format is a combined format for working tree, branch and repository.
2046
- Format 2 working trees [always]
2047
- Format 4 branches [always]
2048
- Format 5 repositories [always]
2049
Unhashed stores in the repository.
2052
_lock_class = lockable_files.TransportLock
2054
def get_format_string(self):
2055
"""See BzrDirFormat.get_format_string()."""
2056
return "Bazaar-NG branch, format 5\n"
2058
def get_branch_format(self):
2059
from bzrlib import branch
2060
return branch.BzrBranchFormat4()
2062
def get_format_description(self):
2063
"""See BzrDirFormat.get_format_description()."""
2064
return "All-in-one format 5"
2066
def get_converter(self, format=None):
2067
"""See BzrDirFormat.get_converter()."""
2068
# there is one and only one upgrade path here.
2069
return ConvertBzrDir5To6()
2071
def _initialize_for_clone(self, url):
2072
return self.initialize_on_transport(get_transport(url), _cloning=True)
2074
def initialize_on_transport(self, transport, _cloning=False):
2075
"""Format 5 dirs always have working tree, branch and repository.
2077
Except when they are being cloned.
2079
from bzrlib.branch import BzrBranchFormat4
2080
from bzrlib.repofmt.weaverepo import RepositoryFormat5
2081
result = (super(BzrDirFormat5, self).initialize_on_transport(transport))
2082
RepositoryFormat5().initialize(result, _internal=True)
2084
branch = BzrBranchFormat4().initialize(result)
2085
result._init_workingtree()
2088
def network_name(self):
2089
return self.get_format_string()
2091
def _open(self, transport):
2092
"""See BzrDirFormat._open."""
2093
return BzrDir5(transport, self)
2095
def __return_repository_format(self):
2096
"""Circular import protection."""
2097
from bzrlib.repofmt.weaverepo import RepositoryFormat5
2098
return RepositoryFormat5()
2099
repository_format = property(__return_repository_format)
2102
class BzrDirFormat6(BzrDirFormat):
2103
"""Bzr control format 6.
2105
This format is a combined format for working tree, branch and repository.
2107
- Format 2 working trees [always]
2108
- Format 4 branches [always]
2109
- Format 6 repositories [always]
2112
_lock_class = lockable_files.TransportLock
2114
def get_format_string(self):
2115
"""See BzrDirFormat.get_format_string()."""
2116
return "Bazaar-NG branch, format 6\n"
2118
def get_format_description(self):
2119
"""See BzrDirFormat.get_format_description()."""
2120
return "All-in-one format 6"
2122
def get_branch_format(self):
2123
from bzrlib import branch
2124
return branch.BzrBranchFormat4()
2126
def get_converter(self, format=None):
2127
"""See BzrDirFormat.get_converter()."""
2128
# there is one and only one upgrade path here.
2129
return ConvertBzrDir6ToMeta()
2131
def _initialize_for_clone(self, url):
2132
return self.initialize_on_transport(get_transport(url), _cloning=True)
2134
def initialize_on_transport(self, transport, _cloning=False):
2135
"""Format 6 dirs always have working tree, branch and repository.
2137
Except when they are being cloned.
2139
from bzrlib.branch import BzrBranchFormat4
2140
from bzrlib.repofmt.weaverepo import RepositoryFormat6
2141
result = super(BzrDirFormat6, self).initialize_on_transport(transport)
2142
RepositoryFormat6().initialize(result, _internal=True)
2144
branch = BzrBranchFormat4().initialize(result)
2145
result._init_workingtree()
2148
def network_name(self):
2149
return self.get_format_string()
2151
def _open(self, transport):
2152
"""See BzrDirFormat._open."""
2153
return BzrDir6(transport, self)
2155
def __return_repository_format(self):
2156
"""Circular import protection."""
2157
from bzrlib.repofmt.weaverepo import RepositoryFormat6
2158
return RepositoryFormat6()
2159
repository_format = property(__return_repository_format)
2162
class BzrDirMetaFormat1(BzrDirFormat):
2163
"""Bzr meta control format 1
2165
This is the first format with split out working tree, branch and repository
2168
- Format 3 working trees [optional]
2169
- Format 5 branches [optional]
2170
- Format 7 repositories [optional]
2173
_lock_class = lockdir.LockDir
2176
self._workingtree_format = None
2177
self._branch_format = None
2178
self._repository_format = None
2180
def __eq__(self, other):
2181
if other.__class__ is not self.__class__:
2183
if other.repository_format != self.repository_format:
2185
if other.workingtree_format != self.workingtree_format:
2189
def __ne__(self, other):
2190
return not self == other
2192
def get_branch_format(self):
2193
if self._branch_format is None:
2194
from bzrlib.branch import BranchFormat
2195
self._branch_format = BranchFormat.get_default_format()
2196
return self._branch_format
2198
def set_branch_format(self, format):
2199
self._branch_format = format
2201
def require_stacking(self):
2202
if not self.get_branch_format().supports_stacking():
2203
# We need to make a stacked branch, but the default format for the
2204
# target doesn't support stacking. So force a branch that *can*
2206
from bzrlib.branch import BzrBranchFormat7
2207
branch_format = BzrBranchFormat7()
2208
self.set_branch_format(branch_format)
2209
mutter("using %r for stacking" % (branch_format,))
2210
from bzrlib.repofmt import pack_repo
2211
if self.repository_format.rich_root_data:
2212
bzrdir_format_name = '1.6.1-rich-root'
2213
repo_format = pack_repo.RepositoryFormatKnitPack5RichRoot()
2215
bzrdir_format_name = '1.6'
2216
repo_format = pack_repo.RepositoryFormatKnitPack5()
2217
note('Source format does not support stacking, using format:'
2219
bzrdir_format_name, repo_format.get_format_description())
2220
self.repository_format = repo_format
2222
def get_converter(self, format=None):
2223
"""See BzrDirFormat.get_converter()."""
2225
format = BzrDirFormat.get_default_format()
2226
if not isinstance(self, format.__class__):
2227
# converting away from metadir is not implemented
2228
raise NotImplementedError(self.get_converter)
2229
return ConvertMetaToMeta(format)
2231
def get_format_string(self):
2232
"""See BzrDirFormat.get_format_string()."""
2233
return "Bazaar-NG meta directory, format 1\n"
2235
def get_format_description(self):
2236
"""See BzrDirFormat.get_format_description()."""
2237
return "Meta directory format 1"
2239
def network_name(self):
2240
return self.get_format_string()
2242
def _open(self, transport):
2243
"""See BzrDirFormat._open."""
2244
return BzrDirMeta1(transport, self)
2246
def __return_repository_format(self):
2247
"""Circular import protection."""
2248
if self._repository_format:
2249
return self._repository_format
2250
from bzrlib.repository import RepositoryFormat
2251
return RepositoryFormat.get_default_format()
2253
def _set_repository_format(self, value):
2254
"""Allow changing the repository format for metadir formats."""
2255
self._repository_format = value
2257
repository_format = property(__return_repository_format,
2258
_set_repository_format)
2260
def _supply_sub_formats_to(self, other_format):
2261
"""Give other_format the same values for sub formats as this has.
2263
This method is expected to be used when parameterising a
2264
RemoteBzrDirFormat instance with the parameters from a
2265
BzrDirMetaFormat1 instance.
2267
:param other_format: other_format is a format which should be
2268
compatible with whatever sub formats are supported by self.
2271
if getattr(self, '_repository_format', None) is not None:
2272
other_format.repository_format = self.repository_format
2273
if self._branch_format is not None:
2274
other_format._branch_format = self._branch_format
2275
if self._workingtree_format is not None:
2276
other_format.workingtree_format = self.workingtree_format
2278
def __get_workingtree_format(self):
2279
if self._workingtree_format is None:
2280
from bzrlib.workingtree import WorkingTreeFormat
2281
self._workingtree_format = WorkingTreeFormat.get_default_format()
2282
return self._workingtree_format
2284
def __set_workingtree_format(self, wt_format):
2285
self._workingtree_format = wt_format
2287
workingtree_format = property(__get_workingtree_format,
2288
__set_workingtree_format)
2291
network_format_registry = registry.FormatRegistry()
2292
"""Registry of formats indexed by their network name.
2294
The network name for a BzrDirFormat is an identifier that can be used when
2295
referring to formats with smart server operations. See
2296
BzrDirFormat.network_name() for more detail.
2300
# Register bzr control format
2301
BzrDirFormat.register_control_format(BzrDirFormat)
2303
# Register bzr formats
2304
BzrDirFormat.register_format(BzrDirFormat4())
2305
BzrDirFormat.register_format(BzrDirFormat5())
2306
BzrDirFormat.register_format(BzrDirFormat6())
2307
__default_format = BzrDirMetaFormat1()
2308
BzrDirFormat.register_format(__default_format)
2309
BzrDirFormat._default_format = __default_format
2312
class Converter(object):
2313
"""Converts a disk format object from one format to another."""
2315
def convert(self, to_convert, pb):
2316
"""Perform the conversion of to_convert, giving feedback via pb.
2318
:param to_convert: The disk object to convert.
2319
:param pb: a progress bar to use for progress information.
2322
def step(self, message):
2323
"""Update the pb by a step."""
2325
self.pb.update(message, self.count, self.total)
2328
class ConvertBzrDir4To5(Converter):
2329
"""Converts format 4 bzr dirs to format 5."""
2332
super(ConvertBzrDir4To5, self).__init__()
2333
self.converted_revs = set()
2334
self.absent_revisions = set()
2338
def convert(self, to_convert, pb):
2339
"""See Converter.convert()."""
2340
self.bzrdir = to_convert
2342
self.pb.note('starting upgrade from format 4 to 5')
2343
if isinstance(self.bzrdir.transport, local.LocalTransport):
2344
self.bzrdir.get_workingtree_transport(None).delete('stat-cache')
2345
self._convert_to_weaves()
2346
return BzrDir.open(self.bzrdir.root_transport.base)
2348
def _convert_to_weaves(self):
2349
self.pb.note('note: upgrade may be faster if all store files are ungzipped first')
2352
stat = self.bzrdir.transport.stat('weaves')
2353
if not S_ISDIR(stat.st_mode):
2354
self.bzrdir.transport.delete('weaves')
2355
self.bzrdir.transport.mkdir('weaves')
2356
except errors.NoSuchFile:
2357
self.bzrdir.transport.mkdir('weaves')
2358
# deliberately not a WeaveFile as we want to build it up slowly.
2359
self.inv_weave = Weave('inventory')
2360
# holds in-memory weaves for all files
2361
self.text_weaves = {}
2362
self.bzrdir.transport.delete('branch-format')
2363
self.branch = self.bzrdir.open_branch()
2364
self._convert_working_inv()
2365
rev_history = self.branch.revision_history()
2366
# to_read is a stack holding the revisions we still need to process;
2367
# appending to it adds new highest-priority revisions
2368
self.known_revisions = set(rev_history)
2369
self.to_read = rev_history[-1:]
2371
rev_id = self.to_read.pop()
2372
if (rev_id not in self.revisions
2373
and rev_id not in self.absent_revisions):
2374
self._load_one_rev(rev_id)
2376
to_import = self._make_order()
2377
for i, rev_id in enumerate(to_import):
2378
self.pb.update('converting revision', i, len(to_import))
2379
self._convert_one_rev(rev_id)
2381
self._write_all_weaves()
2382
self._write_all_revs()
2383
self.pb.note('upgraded to weaves:')
2384
self.pb.note(' %6d revisions and inventories', len(self.revisions))
2385
self.pb.note(' %6d revisions not present', len(self.absent_revisions))
2386
self.pb.note(' %6d texts', self.text_count)
2387
self._cleanup_spare_files_after_format4()
2388
self.branch._transport.put_bytes(
2390
BzrDirFormat5().get_format_string(),
2391
mode=self.bzrdir._get_file_mode())
2393
def _cleanup_spare_files_after_format4(self):
2394
# FIXME working tree upgrade foo.
2395
for n in 'merged-patches', 'pending-merged-patches':
2397
## assert os.path.getsize(p) == 0
2398
self.bzrdir.transport.delete(n)
2399
except errors.NoSuchFile:
2401
self.bzrdir.transport.delete_tree('inventory-store')
2402
self.bzrdir.transport.delete_tree('text-store')
2404
def _convert_working_inv(self):
2405
inv = xml4.serializer_v4.read_inventory(
2406
self.branch._transport.get('inventory'))
2407
new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv, working=True)
2408
self.branch._transport.put_bytes('inventory', new_inv_xml,
2409
mode=self.bzrdir._get_file_mode())
2411
def _write_all_weaves(self):
2412
controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)
2413
weave_transport = self.bzrdir.transport.clone('weaves')
2414
weaves = WeaveStore(weave_transport, prefixed=False)
2415
transaction = WriteTransaction()
2419
for file_id, file_weave in self.text_weaves.items():
2420
self.pb.update('writing weave', i, len(self.text_weaves))
2421
weaves._put_weave(file_id, file_weave, transaction)
2423
self.pb.update('inventory', 0, 1)
2424
controlweaves._put_weave('inventory', self.inv_weave, transaction)
2425
self.pb.update('inventory', 1, 1)
2429
def _write_all_revs(self):
2430
"""Write all revisions out in new form."""
2431
self.bzrdir.transport.delete_tree('revision-store')
2432
self.bzrdir.transport.mkdir('revision-store')
2433
revision_transport = self.bzrdir.transport.clone('revision-store')
2435
from bzrlib.xml5 import serializer_v5
2436
from bzrlib.repofmt.weaverepo import RevisionTextStore
2437
revision_store = RevisionTextStore(revision_transport,
2438
serializer_v5, False, versionedfile.PrefixMapper(),
2439
lambda:True, lambda:True)
2441
for i, rev_id in enumerate(self.converted_revs):
2442
self.pb.update('write revision', i, len(self.converted_revs))
2443
text = serializer_v5.write_revision_to_string(
2444
self.revisions[rev_id])
2446
revision_store.add_lines(key, None, osutils.split_lines(text))
2450
def _load_one_rev(self, rev_id):
2451
"""Load a revision object into memory.
2453
Any parents not either loaded or abandoned get queued to be
2455
self.pb.update('loading revision',
2456
len(self.revisions),
2457
len(self.known_revisions))
2458
if not self.branch.repository.has_revision(rev_id):
2460
self.pb.note('revision {%s} not present in branch; '
2461
'will be converted as a ghost',
2463
self.absent_revisions.add(rev_id)
2465
rev = self.branch.repository.get_revision(rev_id)
2466
for parent_id in rev.parent_ids:
2467
self.known_revisions.add(parent_id)
2468
self.to_read.append(parent_id)
2469
self.revisions[rev_id] = rev
2471
def _load_old_inventory(self, rev_id):
2472
old_inv_xml = self.branch.repository.inventory_store.get(rev_id).read()
2473
inv = xml4.serializer_v4.read_inventory_from_string(old_inv_xml)
2474
inv.revision_id = rev_id
2475
rev = self.revisions[rev_id]
2478
def _load_updated_inventory(self, rev_id):
2479
inv_xml = self.inv_weave.get_text(rev_id)
2480
inv = xml5.serializer_v5.read_inventory_from_string(inv_xml, rev_id)
2483
def _convert_one_rev(self, rev_id):
2484
"""Convert revision and all referenced objects to new format."""
2485
rev = self.revisions[rev_id]
2486
inv = self._load_old_inventory(rev_id)
2487
present_parents = [p for p in rev.parent_ids
2488
if p not in self.absent_revisions]
2489
self._convert_revision_contents(rev, inv, present_parents)
2490
self._store_new_inv(rev, inv, present_parents)
2491
self.converted_revs.add(rev_id)
2493
def _store_new_inv(self, rev, inv, present_parents):
2494
new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
2495
new_inv_sha1 = sha_string(new_inv_xml)
2496
self.inv_weave.add_lines(rev.revision_id,
2498
new_inv_xml.splitlines(True))
2499
rev.inventory_sha1 = new_inv_sha1
2501
def _convert_revision_contents(self, rev, inv, present_parents):
2502
"""Convert all the files within a revision.
2504
Also upgrade the inventory to refer to the text revision ids."""
2505
rev_id = rev.revision_id
2506
mutter('converting texts of revision {%s}',
2508
parent_invs = map(self._load_updated_inventory, present_parents)
2509
entries = inv.iter_entries()
2511
for path, ie in entries:
2512
self._convert_file_version(rev, ie, parent_invs)
2514
def _convert_file_version(self, rev, ie, parent_invs):
2515
"""Convert one version of one file.
2517
The file needs to be added into the weave if it is a merge
2518
of >=2 parents or if it's changed from its parent.
2520
file_id = ie.file_id
2521
rev_id = rev.revision_id
2522
w = self.text_weaves.get(file_id)
2525
self.text_weaves[file_id] = w
2526
text_changed = False
2527
parent_candiate_entries = ie.parent_candidates(parent_invs)
2528
heads = graph.Graph(self).heads(parent_candiate_entries.keys())
2529
# XXX: Note that this is unordered - and this is tolerable because
2530
# the previous code was also unordered.
2531
previous_entries = dict((head, parent_candiate_entries[head]) for head
2533
self.snapshot_ie(previous_entries, ie, w, rev_id)
2536
def get_parent_map(self, revision_ids):
2537
"""See graph._StackedParentsProvider.get_parent_map"""
2538
return dict((revision_id, self.revisions[revision_id])
2539
for revision_id in revision_ids
2540
if revision_id in self.revisions)
2542
def snapshot_ie(self, previous_revisions, ie, w, rev_id):
2543
# TODO: convert this logic, which is ~= snapshot to
2544
# a call to:. This needs the path figured out. rather than a work_tree
2545
# a v4 revision_tree can be given, or something that looks enough like
2546
# one to give the file content to the entry if it needs it.
2547
# and we need something that looks like a weave store for snapshot to
2549
#ie.snapshot(rev, PATH, previous_revisions, REVISION_TREE, InMemoryWeaveStore(self.text_weaves))
2550
if len(previous_revisions) == 1:
2551
previous_ie = previous_revisions.values()[0]
2552
if ie._unchanged(previous_ie):
2553
ie.revision = previous_ie.revision
2556
text = self.branch.repository._text_store.get(ie.text_id)
2557
file_lines = text.readlines()
2558
w.add_lines(rev_id, previous_revisions, file_lines)
2559
self.text_count += 1
2561
w.add_lines(rev_id, previous_revisions, [])
2562
ie.revision = rev_id
2564
def _make_order(self):
2565
"""Return a suitable order for importing revisions.
2567
The order must be such that an revision is imported after all
2568
its (present) parents.
2570
todo = set(self.revisions.keys())
2571
done = self.absent_revisions.copy()
2574
# scan through looking for a revision whose parents
2576
for rev_id in sorted(list(todo)):
2577
rev = self.revisions[rev_id]
2578
parent_ids = set(rev.parent_ids)
2579
if parent_ids.issubset(done):
2580
# can take this one now
2581
order.append(rev_id)
2587
class ConvertBzrDir5To6(Converter):
2588
"""Converts format 5 bzr dirs to format 6."""
2590
def convert(self, to_convert, pb):
2591
"""See Converter.convert()."""
2592
self.bzrdir = to_convert
2594
self.pb.note('starting upgrade from format 5 to 6')
2595
self._convert_to_prefixed()
2596
return BzrDir.open(self.bzrdir.root_transport.base)
2598
def _convert_to_prefixed(self):
2599
from bzrlib.store import TransportStore
2600
self.bzrdir.transport.delete('branch-format')
2601
for store_name in ["weaves", "revision-store"]:
2602
self.pb.note("adding prefixes to %s" % store_name)
2603
store_transport = self.bzrdir.transport.clone(store_name)
2604
store = TransportStore(store_transport, prefixed=True)
2605
for urlfilename in store_transport.list_dir('.'):
2606
filename = urlutils.unescape(urlfilename)
2607
if (filename.endswith(".weave") or
2608
filename.endswith(".gz") or
2609
filename.endswith(".sig")):
2610
file_id, suffix = os.path.splitext(filename)
2614
new_name = store._mapper.map((file_id,)) + suffix
2615
# FIXME keep track of the dirs made RBC 20060121
2617
store_transport.move(filename, new_name)
2618
except errors.NoSuchFile: # catches missing dirs strangely enough
2619
store_transport.mkdir(osutils.dirname(new_name))
2620
store_transport.move(filename, new_name)
2621
self.bzrdir.transport.put_bytes(
2623
BzrDirFormat6().get_format_string(),
2624
mode=self.bzrdir._get_file_mode())
2627
class ConvertBzrDir6ToMeta(Converter):
2628
"""Converts format 6 bzr dirs to metadirs."""
2630
def convert(self, to_convert, pb):
2631
"""See Converter.convert()."""
2632
from bzrlib.repofmt.weaverepo import RepositoryFormat7
2633
from bzrlib.branch import BzrBranchFormat5
2634
self.bzrdir = to_convert
2637
self.total = 20 # the steps we know about
2638
self.garbage_inventories = []
2639
self.dir_mode = self.bzrdir._get_dir_mode()
2640
self.file_mode = self.bzrdir._get_file_mode()
2642
self.pb.note('starting upgrade from format 6 to metadir')
2643
self.bzrdir.transport.put_bytes(
2645
"Converting to format 6",
2646
mode=self.file_mode)
2647
# its faster to move specific files around than to open and use the apis...
2648
# first off, nuke ancestry.weave, it was never used.
2650
self.step('Removing ancestry.weave')
2651
self.bzrdir.transport.delete('ancestry.weave')
2652
except errors.NoSuchFile:
2654
# find out whats there
2655
self.step('Finding branch files')
2656
last_revision = self.bzrdir.open_branch().last_revision()
2657
bzrcontents = self.bzrdir.transport.list_dir('.')
2658
for name in bzrcontents:
2659
if name.startswith('basis-inventory.'):
2660
self.garbage_inventories.append(name)
2661
# create new directories for repository, working tree and branch
2662
repository_names = [('inventory.weave', True),
2663
('revision-store', True),
2665
self.step('Upgrading repository ')
2666
self.bzrdir.transport.mkdir('repository', mode=self.dir_mode)
2667
self.make_lock('repository')
2668
# we hard code the formats here because we are converting into
2669
# the meta format. The meta format upgrader can take this to a
2670
# future format within each component.
2671
self.put_format('repository', RepositoryFormat7())
2672
for entry in repository_names:
2673
self.move_entry('repository', entry)
2675
self.step('Upgrading branch ')
2676
self.bzrdir.transport.mkdir('branch', mode=self.dir_mode)
2677
self.make_lock('branch')
2678
self.put_format('branch', BzrBranchFormat5())
2679
branch_files = [('revision-history', True),
2680
('branch-name', True),
2682
for entry in branch_files:
2683
self.move_entry('branch', entry)
2685
checkout_files = [('pending-merges', True),
2686
('inventory', True),
2687
('stat-cache', False)]
2688
# If a mandatory checkout file is not present, the branch does not have
2689
# a functional checkout. Do not create a checkout in the converted
2691
for name, mandatory in checkout_files:
2692
if mandatory and name not in bzrcontents:
2693
has_checkout = False
2697
if not has_checkout:
2698
self.pb.note('No working tree.')
2699
# If some checkout files are there, we may as well get rid of them.
2700
for name, mandatory in checkout_files:
2701
if name in bzrcontents:
2702
self.bzrdir.transport.delete(name)
2704
from bzrlib.workingtree import WorkingTreeFormat3
2705
self.step('Upgrading working tree')
2706
self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
2707
self.make_lock('checkout')
2709
'checkout', WorkingTreeFormat3())
2710
self.bzrdir.transport.delete_multi(
2711
self.garbage_inventories, self.pb)
2712
for entry in checkout_files:
2713
self.move_entry('checkout', entry)
2714
if last_revision is not None:
2715
self.bzrdir.transport.put_bytes(
2716
'checkout/last-revision', last_revision)
2717
self.bzrdir.transport.put_bytes(
2719
BzrDirMetaFormat1().get_format_string(),
2720
mode=self.file_mode)
2721
return BzrDir.open(self.bzrdir.root_transport.base)
2723
def make_lock(self, name):
2724
"""Make a lock for the new control dir name."""
2725
self.step('Make %s lock' % name)
2726
ld = lockdir.LockDir(self.bzrdir.transport,
2728
file_modebits=self.file_mode,
2729
dir_modebits=self.dir_mode)
2732
def move_entry(self, new_dir, entry):
2733
"""Move then entry name into new_dir."""
2735
mandatory = entry[1]
2736
self.step('Moving %s' % name)
2738
self.bzrdir.transport.move(name, '%s/%s' % (new_dir, name))
2739
except errors.NoSuchFile:
2743
def put_format(self, dirname, format):
2744
self.bzrdir.transport.put_bytes('%s/format' % dirname,
2745
format.get_format_string(),
2749
class ConvertMetaToMeta(Converter):
2750
"""Converts the components of metadirs."""
2752
def __init__(self, target_format):
2753
"""Create a metadir to metadir converter.
2755
:param target_format: The final metadir format that is desired.
2757
self.target_format = target_format
2759
def convert(self, to_convert, pb):
2760
"""See Converter.convert()."""
2761
self.bzrdir = to_convert
2765
self.step('checking repository format')
2767
repo = self.bzrdir.open_repository()
2768
except errors.NoRepositoryPresent:
2771
if not isinstance(repo._format, self.target_format.repository_format.__class__):
2772
from bzrlib.repository import CopyConverter
2773
self.pb.note('starting repository conversion')
2774
converter = CopyConverter(self.target_format.repository_format)
2775
converter.convert(repo, pb)
2777
branch = self.bzrdir.open_branch()
2778
except errors.NotBranchError:
2781
# TODO: conversions of Branch and Tree should be done by
2782
# InterXFormat lookups/some sort of registry.
2783
# Avoid circular imports
2784
from bzrlib import branch as _mod_branch
2785
old = branch._format.__class__
2786
new = self.target_format.get_branch_format().__class__
2788
if (old == _mod_branch.BzrBranchFormat5 and
2789
new in (_mod_branch.BzrBranchFormat6,
2790
_mod_branch.BzrBranchFormat7)):
2791
branch_converter = _mod_branch.Converter5to6()
2792
elif (old == _mod_branch.BzrBranchFormat6 and
2793
new == _mod_branch.BzrBranchFormat7):
2794
branch_converter = _mod_branch.Converter6to7()
2796
raise errors.BadConversionTarget("No converter", new)
2797
branch_converter.convert(branch)
2798
branch = self.bzrdir.open_branch()
2799
old = branch._format.__class__
2801
tree = self.bzrdir.open_workingtree(recommend_upgrade=False)
2802
except (errors.NoWorkingTree, errors.NotLocalUrl):
2805
# TODO: conversions of Branch and Tree should be done by
2806
# InterXFormat lookups
2807
if (isinstance(tree, workingtree.WorkingTree3) and
2808
not isinstance(tree, workingtree_4.DirStateWorkingTree) and
2809
isinstance(self.target_format.workingtree_format,
2810
workingtree_4.DirStateWorkingTreeFormat)):
2811
workingtree_4.Converter3to4().convert(tree)
2812
if (isinstance(tree, workingtree_4.DirStateWorkingTree) and
2813
not isinstance(tree, workingtree_4.WorkingTree5) and
2814
isinstance(self.target_format.workingtree_format,
2815
workingtree_4.WorkingTreeFormat5)):
2816
workingtree_4.Converter4to5().convert(tree)
2817
if (isinstance(tree, workingtree_4.DirStateWorkingTree) and
2818
not isinstance(tree, workingtree_4.WorkingTree6) and
2819
isinstance(self.target_format.workingtree_format,
2820
workingtree_4.WorkingTreeFormat6)):
2821
workingtree_4.Converter4or5to6().convert(tree)
2825
# This is not in remote.py because it's small, and needs to be registered.
2826
# Putting it in remote.py creates a circular import problem.
2827
# we can make it a lazy object if the control formats is turned into something
2829
class RemoteBzrDirFormat(BzrDirMetaFormat1):
2830
"""Format representing bzrdirs accessed via a smart server"""
2833
BzrDirMetaFormat1.__init__(self)
2834
self._network_name = None
2836
def get_format_description(self):
2837
return 'bzr remote bzrdir'
2839
def get_format_string(self):
2840
raise NotImplementedError(self.get_format_string)
2842
def network_name(self):
2843
if self._network_name:
2844
return self._network_name
2846
raise AssertionError("No network name set.")
2849
def probe_transport(klass, transport):
2850
"""Return a RemoteBzrDirFormat object if it looks possible."""
2852
medium = transport.get_smart_medium()
2853
except (NotImplementedError, AttributeError,
2854
errors.TransportNotPossible, errors.NoSmartMedium,
2855
errors.SmartProtocolError):
2856
# no smart server, so not a branch for this format type.
2857
raise errors.NotBranchError(path=transport.base)
2859
# Decline to open it if the server doesn't support our required
2860
# version (3) so that the VFS-based transport will do it.
2861
if medium.should_probe():
2863
server_version = medium.protocol_version()
2864
except errors.SmartProtocolError:
2865
# Apparently there's no usable smart server there, even though
2866
# the medium supports the smart protocol.
2867
raise errors.NotBranchError(path=transport.base)
2868
if server_version != '2':
2869
raise errors.NotBranchError(path=transport.base)
2872
def initialize_on_transport(self, transport):
2874
# hand off the request to the smart server
2875
client_medium = transport.get_smart_medium()
2876
except errors.NoSmartMedium:
2877
# TODO: lookup the local format from a server hint.
2878
local_dir_format = BzrDirMetaFormat1()
2879
return local_dir_format.initialize_on_transport(transport)
2880
client = _SmartClient(client_medium)
2881
path = client.remote_path_from_transport(transport)
2882
response = client.call('BzrDirFormat.initialize', path)
2883
if response[0] != 'ok':
2884
raise errors.SmartProtocolError('unexpected response code %s' % (response,))
2885
format = RemoteBzrDirFormat()
2886
self._supply_sub_formats_to(format)
2887
return remote.RemoteBzrDir(transport, format)
2889
def _open(self, transport):
2890
return remote.RemoteBzrDir(transport, self)
2892
def __eq__(self, other):
2893
if not isinstance(other, RemoteBzrDirFormat):
2895
return self.get_format_description() == other.get_format_description()
2897
def __return_repository_format(self):
2898
# Always return a RemoteRepositoryFormat object, but if a specific bzr
2899
# repository format has been asked for, tell the RemoteRepositoryFormat
2900
# that it should use that for init() etc.
2901
result = remote.RemoteRepositoryFormat()
2902
custom_format = getattr(self, '_repository_format', None)
2904
if isinstance(custom_format, remote.RemoteRepositoryFormat):
2905
return custom_format
2907
# We will use the custom format to create repositories over the
2908
# wire; expose its details like rich_root_data for code to
2910
result._custom_format = custom_format
2913
def get_branch_format(self):
2914
result = BzrDirMetaFormat1.get_branch_format(self)
2915
if not isinstance(result, remote.RemoteBranchFormat):
2916
new_result = remote.RemoteBranchFormat()
2917
new_result._custom_format = result
2919
self.set_branch_format(new_result)
2923
repository_format = property(__return_repository_format,
2924
BzrDirMetaFormat1._set_repository_format) #.im_func)
2927
BzrDirFormat.register_control_server_format(RemoteBzrDirFormat)
2930
class BzrDirFormatInfo(object):
2932
def __init__(self, native, deprecated, hidden, experimental):
2933
self.deprecated = deprecated
2934
self.native = native
2935
self.hidden = hidden
2936
self.experimental = experimental
2939
class BzrDirFormatRegistry(registry.Registry):
2940
"""Registry of user-selectable BzrDir subformats.
2942
Differs from BzrDirFormat._control_formats in that it provides sub-formats,
2943
e.g. BzrDirMeta1 with weave repository. Also, it's more user-oriented.
2947
"""Create a BzrDirFormatRegistry."""
2948
self._aliases = set()
2949
self._registration_order = list()
2950
super(BzrDirFormatRegistry, self).__init__()
2953
"""Return a set of the format names which are aliases."""
2954
return frozenset(self._aliases)
2956
def register_metadir(self, key,
2957
repository_format, help, native=True, deprecated=False,
2963
"""Register a metadir subformat.
2965
These all use a BzrDirMetaFormat1 bzrdir, but can be parameterized
2966
by the Repository/Branch/WorkingTreeformats.
2968
:param repository_format: The fully-qualified repository format class
2970
:param branch_format: Fully-qualified branch format class name as
2972
:param tree_format: Fully-qualified tree format class name as
2975
# This should be expanded to support setting WorkingTree and Branch
2976
# formats, once BzrDirMetaFormat1 supports that.
2977
def _load(full_name):
2978
mod_name, factory_name = full_name.rsplit('.', 1)
2980
mod = __import__(mod_name, globals(), locals(),
2982
except ImportError, e:
2983
raise ImportError('failed to load %s: %s' % (full_name, e))
2985
factory = getattr(mod, factory_name)
2986
except AttributeError:
2987
raise AttributeError('no factory %s in module %r'
2992
bd = BzrDirMetaFormat1()
2993
if branch_format is not None:
2994
bd.set_branch_format(_load(branch_format))
2995
if tree_format is not None:
2996
bd.workingtree_format = _load(tree_format)
2997
if repository_format is not None:
2998
bd.repository_format = _load(repository_format)
3000
self.register(key, helper, help, native, deprecated, hidden,
3001
experimental, alias)
3003
def register(self, key, factory, help, native=True, deprecated=False,
3004
hidden=False, experimental=False, alias=False):
3005
"""Register a BzrDirFormat factory.
3007
The factory must be a callable that takes one parameter: the key.
3008
It must produce an instance of the BzrDirFormat when called.
3010
This function mainly exists to prevent the info object from being
3013
registry.Registry.register(self, key, factory, help,
3014
BzrDirFormatInfo(native, deprecated, hidden, experimental))
3016
self._aliases.add(key)
3017
self._registration_order.append(key)
3019
def register_lazy(self, key, module_name, member_name, help, native=True,
3020
deprecated=False, hidden=False, experimental=False, alias=False):
3021
registry.Registry.register_lazy(self, key, module_name, member_name,
3022
help, BzrDirFormatInfo(native, deprecated, hidden, experimental))
3024
self._aliases.add(key)
3025
self._registration_order.append(key)
3027
def set_default(self, key):
3028
"""Set the 'default' key to be a clone of the supplied key.
3030
This method must be called once and only once.
3032
registry.Registry.register(self, 'default', self.get(key),
3033
self.get_help(key), info=self.get_info(key))
3034
self._aliases.add('default')
3036
def set_default_repository(self, key):
3037
"""Set the FormatRegistry default and Repository default.
3039
This is a transitional method while Repository.set_default_format
3042
if 'default' in self:
3043
self.remove('default')
3044
self.set_default(key)
3045
format = self.get('default')()
3047
def make_bzrdir(self, key):
3048
return self.get(key)()
3050
def help_topic(self, topic):
3052
default_realkey = None
3053
default_help = self.get_help('default')
3055
for key in self._registration_order:
3056
if key == 'default':
3058
help = self.get_help(key)
3059
if help == default_help:
3060
default_realkey = key
3062
help_pairs.append((key, help))
3064
def wrapped(key, help, info):
3066
help = '(native) ' + help
3067
return ':%s:\n%s\n\n' % (key,
3068
textwrap.fill(help, initial_indent=' ',
3069
subsequent_indent=' '))
3070
if default_realkey is not None:
3071
output += wrapped(default_realkey, '(default) %s' % default_help,
3072
self.get_info('default'))
3073
deprecated_pairs = []
3074
experimental_pairs = []
3075
for key, help in help_pairs:
3076
info = self.get_info(key)
3079
elif info.deprecated:
3080
deprecated_pairs.append((key, help))
3081
elif info.experimental:
3082
experimental_pairs.append((key, help))
3084
output += wrapped(key, help, info)
3085
output += "\nSee ``bzr help formats`` for more about storage formats."
3087
if len(experimental_pairs) > 0:
3088
other_output += "Experimental formats are shown below.\n\n"
3089
for key, help in experimental_pairs:
3090
info = self.get_info(key)
3091
other_output += wrapped(key, help, info)
3094
"No experimental formats are available.\n\n"
3095
if len(deprecated_pairs) > 0:
3096
other_output += "\nDeprecated formats are shown below.\n\n"
3097
for key, help in deprecated_pairs:
3098
info = self.get_info(key)
3099
other_output += wrapped(key, help, info)
3102
"\nNo deprecated formats are available.\n\n"
3104
"\nSee ``bzr help formats`` for more about storage formats."
3106
if topic == 'other-formats':
3112
class RepositoryAcquisitionPolicy(object):
3113
"""Abstract base class for repository acquisition policies.
3115
A repository acquisition policy decides how a BzrDir acquires a repository
3116
for a branch that is being created. The most basic policy decision is
3117
whether to create a new repository or use an existing one.
3119
def __init__(self, stack_on, stack_on_pwd, require_stacking):
3122
:param stack_on: A location to stack on
3123
:param stack_on_pwd: If stack_on is relative, the location it is
3125
:param require_stacking: If True, it is a failure to not stack.
3127
self._stack_on = stack_on
3128
self._stack_on_pwd = stack_on_pwd
3129
self._require_stacking = require_stacking
3131
def configure_branch(self, branch):
3132
"""Apply any configuration data from this policy to the branch.
3134
Default implementation sets repository stacking.
3136
if self._stack_on is None:
3138
if self._stack_on_pwd is None:
3139
stack_on = self._stack_on
3142
stack_on = urlutils.rebase_url(self._stack_on,
3144
branch.bzrdir.root_transport.base)
3145
except errors.InvalidRebaseURLs:
3146
stack_on = self._get_full_stack_on()
3148
branch.set_stacked_on_url(stack_on)
3149
except (errors.UnstackableBranchFormat,
3150
errors.UnstackableRepositoryFormat):
3151
if self._require_stacking:
3154
def _get_full_stack_on(self):
3155
"""Get a fully-qualified URL for the stack_on location."""
3156
if self._stack_on is None:
3158
if self._stack_on_pwd is None:
3159
return self._stack_on
3161
return urlutils.join(self._stack_on_pwd, self._stack_on)
3163
def _add_fallback(self, repository, possible_transports=None):
3164
"""Add a fallback to the supplied repository, if stacking is set."""
3165
stack_on = self._get_full_stack_on()
3166
if stack_on is None:
3168
stacked_dir = BzrDir.open(stack_on,
3169
possible_transports=possible_transports)
3171
stacked_repo = stacked_dir.open_branch().repository
3172
except errors.NotBranchError:
3173
stacked_repo = stacked_dir.open_repository()
3175
repository.add_fallback_repository(stacked_repo)
3176
except errors.UnstackableRepositoryFormat:
3177
if self._require_stacking:
3180
self._require_stacking = True
3182
def acquire_repository(self, make_working_trees=None, shared=False):
3183
"""Acquire a repository for this bzrdir.
3185
Implementations may create a new repository or use a pre-exising
3187
:param make_working_trees: If creating a repository, set
3188
make_working_trees to this value (if non-None)
3189
:param shared: If creating a repository, make it shared if True
3190
:return: A repository, is_new_flag (True if the repository was
3193
raise NotImplemented(RepositoryAcquisitionPolicy.acquire_repository)
3196
class CreateRepository(RepositoryAcquisitionPolicy):
3197
"""A policy of creating a new repository"""
3199
def __init__(self, bzrdir, stack_on=None, stack_on_pwd=None,
3200
require_stacking=False):
3203
:param bzrdir: The bzrdir to create the repository on.
3204
:param stack_on: A location to stack on
3205
:param stack_on_pwd: If stack_on is relative, the location it is
3208
RepositoryAcquisitionPolicy.__init__(self, stack_on, stack_on_pwd,
3210
self._bzrdir = bzrdir
3212
def acquire_repository(self, make_working_trees=None, shared=False):
3213
"""Implementation of RepositoryAcquisitionPolicy.acquire_repository
3215
Creates the desired repository in the bzrdir we already have.
3217
stack_on = self._get_full_stack_on()
3219
# Stacking is desired. requested by the target, but does the place it
3220
# points at support stacking? If it doesn't then we should
3221
# not implicitly upgrade. We check this here.
3222
format = self._bzrdir._format
3223
if not (format.repository_format.supports_external_lookups
3224
and format.get_branch_format().supports_stacking()):
3225
# May need to upgrade - but only do if the target also
3226
# supports stacking. Note that this currently wastes
3227
# network round trips to check - but we only do this
3228
# when the source can't stack so it will fade away
3229
# as people do upgrade.
3231
target_dir = BzrDir.open(stack_on,
3232
possible_transports=[self._bzrdir.root_transport])
3233
except errors.NotBranchError:
3234
# Nothing there, don't change formats
3238
target_branch = target_dir.open_branch()
3239
except errors.NotBranchError:
3240
# No branch, don't change formats
3243
branch_format = target_branch._format
3244
repo_format = target_branch.repository._format
3245
if not (branch_format.supports_stacking()
3246
and repo_format.supports_external_lookups):
3247
# Doesn't stack itself, don't force an upgrade
3250
# Does support stacking, use its format.
3251
format.repository_format = repo_format
3252
format.set_branch_format(branch_format)
3253
note('Source format does not support stacking, '
3254
'using format: \'%s\'\n %s\n',
3255
branch_format.get_format_description(),
3256
repo_format.get_format_description())
3257
if not self._require_stacking:
3258
# We have picked up automatic stacking somewhere.
3259
note('Using default stacking branch %s at %s', self._stack_on,
3261
repository = self._bzrdir.create_repository(shared=shared)
3262
self._add_fallback(repository,
3263
possible_transports=[self._bzrdir.transport])
3264
if make_working_trees is not None:
3265
repository.set_make_working_trees(make_working_trees)
3266
return repository, True
3269
class UseExistingRepository(RepositoryAcquisitionPolicy):
3270
"""A policy of reusing an existing repository"""
3272
def __init__(self, repository, stack_on=None, stack_on_pwd=None,
3273
require_stacking=False):
3276
:param repository: The repository to use.
3277
:param stack_on: A location to stack on
3278
:param stack_on_pwd: If stack_on is relative, the location it is
3281
RepositoryAcquisitionPolicy.__init__(self, stack_on, stack_on_pwd,
3283
self._repository = repository
3285
def acquire_repository(self, make_working_trees=None, shared=False):
3286
"""Implementation of RepositoryAcquisitionPolicy.acquire_repository
3288
Returns an existing repository to use.
3290
self._add_fallback(self._repository,
3291
possible_transports=[self._repository.bzrdir.transport])
3292
return self._repository, False
3295
# Please register new formats after old formats so that formats
3296
# appear in chronological order and format descriptions can build
3298
format_registry = BzrDirFormatRegistry()
3299
# The pre-0.8 formats have their repository format network name registered in
3300
# repository.py. MetaDir formats have their repository format network name
3301
# inferred from their disk format string.
3302
format_registry.register('weave', BzrDirFormat6,
3303
'Pre-0.8 format. Slower than knit and does not'
3304
' support checkouts or shared repositories.',
3306
format_registry.register_metadir('metaweave',
3307
'bzrlib.repofmt.weaverepo.RepositoryFormat7',
3308
'Transitional format in 0.8. Slower than knit.',
3309
branch_format='bzrlib.branch.BzrBranchFormat5',
3310
tree_format='bzrlib.workingtree.WorkingTreeFormat3',
3312
format_registry.register_metadir('knit',
3313
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
3314
'Format using knits. Recommended for interoperation with bzr <= 0.14.',
3315
branch_format='bzrlib.branch.BzrBranchFormat5',
3316
tree_format='bzrlib.workingtree.WorkingTreeFormat3',
3318
format_registry.register_metadir('dirstate',
3319
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
3320
help='New in 0.15: Fast local operations. Compatible with bzr 0.8 and '
3321
'above when accessed over the network.',
3322
branch_format='bzrlib.branch.BzrBranchFormat5',
3323
# this uses bzrlib.workingtree.WorkingTreeFormat4 because importing
3324
# directly from workingtree_4 triggers a circular import.
3325
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3327
format_registry.register_metadir('dirstate-tags',
3328
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
3329
help='New in 0.15: Fast local operations and improved scaling for '
3330
'network operations. Additionally adds support for tags.'
3331
' Incompatible with bzr < 0.15.',
3332
branch_format='bzrlib.branch.BzrBranchFormat6',
3333
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3335
format_registry.register_metadir('rich-root',
3336
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit4',
3337
help='New in 1.0. Better handling of tree roots. Incompatible with'
3339
branch_format='bzrlib.branch.BzrBranchFormat6',
3340
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3342
format_registry.register_metadir('dirstate-with-subtree',
3343
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
3344
help='New in 0.15: Fast local operations and improved scaling for '
3345
'network operations. Additionally adds support for versioning nested '
3346
'bzr branches. Incompatible with bzr < 0.15.',
3347
branch_format='bzrlib.branch.BzrBranchFormat6',
3348
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3352
format_registry.register_metadir('pack-0.92',
3353
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack1',
3354
help='New in 0.92: Pack-based format with data compatible with '
3355
'dirstate-tags format repositories. Interoperates with '
3356
'bzr repositories before 0.92 but cannot be read by bzr < 0.92. '
3357
'Previously called knitpack-experimental. '
3358
'For more information, see '
3359
'http://doc.bazaar-vcs.org/latest/developers/packrepo.html.',
3360
branch_format='bzrlib.branch.BzrBranchFormat6',
3361
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3363
format_registry.register_metadir('pack-0.92-subtree',
3364
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack3',
3365
help='New in 0.92: Pack-based format with data compatible with '
3366
'dirstate-with-subtree format repositories. Interoperates with '
3367
'bzr repositories before 0.92 but cannot be read by bzr < 0.92. '
3368
'Previously called knitpack-experimental. '
3369
'For more information, see '
3370
'http://doc.bazaar-vcs.org/latest/developers/packrepo.html.',
3371
branch_format='bzrlib.branch.BzrBranchFormat6',
3372
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3376
format_registry.register_metadir('rich-root-pack',
3377
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack4',
3378
help='New in 1.0: A variant of pack-0.92 that supports rich-root data '
3379
'(needed for bzr-svn and bzr-git).',
3380
branch_format='bzrlib.branch.BzrBranchFormat6',
3381
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3383
format_registry.register_metadir('1.6',
3384
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack5',
3385
help='A format that allows a branch to indicate that there is another '
3386
'(stacked) repository that should be used to access data that is '
3387
'not present locally.',
3388
branch_format='bzrlib.branch.BzrBranchFormat7',
3389
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3391
format_registry.register_metadir('1.6.1-rich-root',
3392
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack5RichRoot',
3393
help='A variant of 1.6 that supports rich-root data '
3394
'(needed for bzr-svn and bzr-git).',
3395
branch_format='bzrlib.branch.BzrBranchFormat7',
3396
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3398
format_registry.register_metadir('1.9',
3399
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack6',
3400
help='A repository format using B+tree indexes. These indexes '
3401
'are smaller in size, have smarter caching and provide faster '
3402
'performance for most operations.',
3403
branch_format='bzrlib.branch.BzrBranchFormat7',
3404
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3406
format_registry.register_metadir('1.9-rich-root',
3407
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack6RichRoot',
3408
help='A variant of 1.9 that supports rich-root data '
3409
'(needed for bzr-svn and bzr-git).',
3410
branch_format='bzrlib.branch.BzrBranchFormat7',
3411
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3413
format_registry.register_metadir('1.14',
3414
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack6',
3415
help='A working-tree format that supports content filtering.',
3416
branch_format='bzrlib.branch.BzrBranchFormat7',
3417
tree_format='bzrlib.workingtree.WorkingTreeFormat5',
3419
format_registry.register_metadir('1.14-rich-root',
3420
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack6RichRoot',
3421
help='A variant of 1.14 that supports rich-root data '
3422
'(needed for bzr-svn and bzr-git).',
3423
branch_format='bzrlib.branch.BzrBranchFormat7',
3424
tree_format='bzrlib.workingtree.WorkingTreeFormat5',
3426
# The following un-numbered 'development' formats should always just be aliases.
3427
format_registry.register_metadir('development-rich-root',
3428
'bzrlib.repofmt.groupcompress_repo.RepositoryFormatCHK1',
3429
help='Current development format. Can convert data to and from pack-0.92 '
3430
'(and anything compatible with pack-0.92) format repositories. '
3431
'Repositories and branches in this format can only be read by bzr.dev. '
3433
'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
3435
branch_format='bzrlib.branch.BzrBranchFormat7',
3436
tree_format='bzrlib.workingtree.WorkingTreeFormat6',
3440
format_registry.register_metadir('development-subtree',
3441
'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment2Subtree',
3442
help='Current development format, subtree variant. Can convert data to and '
3443
'from pack-0.92-subtree (and anything compatible with '
3444
'pack-0.92-subtree) format repositories. Repositories and branches in '
3445
'this format can only be read by bzr.dev. Please read '
3446
'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
3448
branch_format='bzrlib.branch.BzrBranchFormat7',
3449
tree_format='bzrlib.workingtree.WorkingTreeFormat6',
3451
alias=False, # Restore to being an alias when an actual development subtree format is added
3452
# This current non-alias status is simply because we did not introduce a
3453
# chk based subtree format.
3456
# And the development formats above will have aliased one of the following:
3457
format_registry.register_metadir('development6-rich-root',
3458
'bzrlib.repofmt.groupcompress_repo.RepositoryFormatCHK1',
3459
help='pack-1.9 with 255-way hashed CHK inv, group compress, rich roots '
3461
'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
3463
branch_format='bzrlib.branch.BzrBranchFormat7',
3464
tree_format='bzrlib.workingtree.WorkingTreeFormat6',
3469
# The following format should be an alias for the rich root equivalent
3470
# of the default format
3471
format_registry.register_metadir('default-rich-root',
3472
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack4',
3473
help='Default format, rich root variant. (needed for bzr-svn and bzr-git).',
3474
branch_format='bzrlib.branch.BzrBranchFormat6',
3475
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3478
# The current format that is made on 'bzr init'.
3479
format_registry.set_default('pack-0.92')