1
# Copyright (C) 2006-2010 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.
34
from bzrlib.lazy_import import lazy_import
35
lazy_import(globals(), """
36
from stat import S_ISDIR
51
revision as _mod_revision,
61
from bzrlib.osutils import (
64
from bzrlib.push import (
67
from bzrlib.repofmt import pack_repo
68
from bzrlib.smart.client import _SmartClient
69
from bzrlib.store.versioned import WeaveStore
70
from bzrlib.transactions import WriteTransaction
71
from bzrlib.transport import (
72
do_catching_redirections,
76
from bzrlib.weave import Weave
79
from bzrlib.trace import (
90
from bzrlib.symbol_versioning import (
96
class BzrDir(controldir.ControlDir):
97
"""A .bzr control diretory.
99
BzrDir instances let you create or open any of the things that can be
100
found within .bzr - checkouts, branches and repositories.
103
the transport which this bzr dir is rooted at (i.e. file:///.../.bzr/)
104
:ivar root_transport:
105
a transport connected to the directory this bzr was opened from
106
(i.e. the parent directory holding the .bzr directory).
108
Everything in the bzrdir should have the same file permissions.
110
:cvar hooks: An instance of BzrDirHooks.
113
def break_lock(self):
114
"""Invoke break_lock on the first object in the bzrdir.
116
If there is a tree, the tree is opened and break_lock() called.
117
Otherwise, branch is tried, and finally repository.
119
# XXX: This seems more like a UI function than something that really
120
# belongs in this class.
122
thing_to_unlock = self.open_workingtree()
123
except (errors.NotLocalUrl, errors.NoWorkingTree):
125
thing_to_unlock = self.open_branch()
126
except errors.NotBranchError:
128
thing_to_unlock = self.open_repository()
129
except errors.NoRepositoryPresent:
131
thing_to_unlock.break_lock()
133
def check_conversion_target(self, target_format):
134
"""Check that a bzrdir as a whole can be converted to a new format."""
135
# The only current restriction is that the repository content can be
136
# fetched compatibly with the target.
137
target_repo_format = target_format.repository_format
139
self.open_repository()._format.check_conversion_target(
141
except errors.NoRepositoryPresent:
142
# No repo, no problem.
146
def _check_supported(format, allow_unsupported,
147
recommend_upgrade=True,
149
"""Give an error or warning on old formats.
151
:param format: may be any kind of format - workingtree, branch,
154
:param allow_unsupported: If true, allow opening
155
formats that are strongly deprecated, and which may
156
have limited functionality.
158
:param recommend_upgrade: If true (default), warn
159
the user through the ui object that they may wish
160
to upgrade the object.
162
# TODO: perhaps move this into a base Format class; it's not BzrDir
163
# specific. mbp 20070323
164
if not allow_unsupported and not format.is_supported():
165
# see open_downlevel to open legacy branches.
166
raise errors.UnsupportedFormatError(format=format)
167
if recommend_upgrade \
168
and getattr(format, 'upgrade_recommended', False):
169
ui.ui_factory.recommend_upgrade(
170
format.get_format_description(),
173
def clone_on_transport(self, transport, revision_id=None,
174
force_new_repo=False, preserve_stacking=False, stacked_on=None,
175
create_prefix=False, use_existing_dir=True, no_tree=False):
176
"""Clone this bzrdir and its contents to transport verbatim.
178
:param transport: The transport for the location to produce the clone
179
at. If the target directory does not exist, it will be created.
180
:param revision_id: The tip revision-id to use for any branch or
181
working tree. If not None, then the clone operation may tune
182
itself to download less data.
183
:param force_new_repo: Do not use a shared repository for the target,
184
even if one is available.
185
:param preserve_stacking: When cloning a stacked branch, stack the
186
new branch on top of the other branch's stacked-on branch.
187
:param create_prefix: Create any missing directories leading up to
189
:param use_existing_dir: Use an existing directory if one exists.
191
# Overview: put together a broad description of what we want to end up
192
# with; then make as few api calls as possible to do it.
194
# We may want to create a repo/branch/tree, if we do so what format
195
# would we want for each:
196
require_stacking = (stacked_on is not None)
197
format = self.cloning_metadir(require_stacking)
199
# Figure out what objects we want:
201
local_repo = self.find_repository()
202
except errors.NoRepositoryPresent:
205
local_branch = self.open_branch()
206
except errors.NotBranchError:
209
# enable fallbacks when branch is not a branch reference
210
if local_branch.repository.has_same_location(local_repo):
211
local_repo = local_branch.repository
212
if preserve_stacking:
214
stacked_on = local_branch.get_stacked_on_url()
215
except (errors.UnstackableBranchFormat,
216
errors.UnstackableRepositoryFormat,
219
# Bug: We create a metadir without knowing if it can support stacking,
220
# we should look up the policy needs first, or just use it as a hint,
223
make_working_trees = local_repo.make_working_trees() and not no_tree
224
want_shared = local_repo.is_shared()
225
repo_format_name = format.repository_format.network_name()
227
make_working_trees = False
229
repo_format_name = None
231
result_repo, result, require_stacking, repository_policy = \
232
format.initialize_on_transport_ex(transport,
233
use_existing_dir=use_existing_dir, create_prefix=create_prefix,
234
force_new_repo=force_new_repo, stacked_on=stacked_on,
235
stack_on_pwd=self.root_transport.base,
236
repo_format_name=repo_format_name,
237
make_working_trees=make_working_trees, shared_repo=want_shared)
240
# If the result repository is in the same place as the
241
# resulting bzr dir, it will have no content, further if the
242
# result is not stacked then we know all content should be
243
# copied, and finally if we are copying up to a specific
244
# revision_id then we can use the pending-ancestry-result which
245
# does not require traversing all of history to describe it.
246
if (result_repo.user_url == result.user_url
247
and not require_stacking and
248
revision_id is not None):
249
fetch_spec = graph.PendingAncestryResult(
250
[revision_id], local_repo)
251
result_repo.fetch(local_repo, fetch_spec=fetch_spec)
253
result_repo.fetch(local_repo, revision_id=revision_id)
257
if result_repo is not None:
258
raise AssertionError('result_repo not None(%r)' % result_repo)
259
# 1 if there is a branch present
260
# make sure its content is available in the target repository
262
if local_branch is not None:
263
result_branch = local_branch.clone(result, revision_id=revision_id,
264
repository_policy=repository_policy)
266
# Cheaper to check if the target is not local, than to try making
268
result.root_transport.local_abspath('.')
269
if result_repo is None or result_repo.make_working_trees():
270
self.open_workingtree().clone(result)
271
except (errors.NoWorkingTree, errors.NotLocalUrl):
275
# TODO: This should be given a Transport, and should chdir up; otherwise
276
# this will open a new connection.
277
def _make_tail(self, url):
278
t = get_transport(url)
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, errors.PermissionDenied):
312
recurse, value = evaluate(bzrdir)
315
subdirs = list_current(current_transport)
316
except (errors.NoSuchFile, errors.PermissionDenied):
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, ([], repository)
340
return True, (bzrdir.list_branches(), None)
342
for branches, repo in BzrDir.find_bzrdirs(transport,
345
ret.extend(repo.find_branches())
346
if branches is not None:
351
def create_branch_and_repo(base, force_new_repo=False, format=None):
352
"""Create a new BzrDir, Branch and Repository at the url 'base'.
354
This will use the current default BzrDirFormat unless one is
355
specified, and use whatever
356
repository format that that uses via bzrdir.create_branch and
357
create_repository. If a shared repository is available that is used
360
The created Branch object is returned.
362
:param base: The URL to create the branch at.
363
:param force_new_repo: If True a new repository is always created.
364
:param format: If supplied, the format of branch to create. If not
365
supplied, the default is used.
367
bzrdir = BzrDir.create(base, format)
368
bzrdir._find_or_create_repository(force_new_repo)
369
return bzrdir.create_branch()
371
def determine_repository_policy(self, force_new_repo=False, stack_on=None,
372
stack_on_pwd=None, require_stacking=False):
373
"""Return an object representing a policy to use.
375
This controls whether a new repository is created, and the format of
376
that repository, or some existing shared repository used instead.
378
If stack_on is supplied, will not seek a containing shared repo.
380
:param force_new_repo: If True, require a new repository to be created.
381
:param stack_on: If supplied, the location to stack on. If not
382
supplied, a default_stack_on location may be used.
383
:param stack_on_pwd: If stack_on is relative, the location it is
386
def repository_policy(found_bzrdir):
389
config = found_bzrdir.get_config()
391
stack_on = config.get_default_stack_on()
392
if stack_on is not None:
393
stack_on_pwd = found_bzrdir.user_url
395
# does it have a repository ?
397
repository = found_bzrdir.open_repository()
398
except errors.NoRepositoryPresent:
401
if (found_bzrdir.user_url != self.user_url
402
and not repository.is_shared()):
403
# Don't look higher, can't use a higher shared repo.
411
return UseExistingRepository(repository, stack_on,
412
stack_on_pwd, require_stacking=require_stacking), True
414
return CreateRepository(self, stack_on, stack_on_pwd,
415
require_stacking=require_stacking), True
417
if not force_new_repo:
419
policy = self._find_containing(repository_policy)
420
if policy is not None:
424
return UseExistingRepository(self.open_repository(),
425
stack_on, stack_on_pwd,
426
require_stacking=require_stacking)
427
except errors.NoRepositoryPresent:
429
return CreateRepository(self, stack_on, stack_on_pwd,
430
require_stacking=require_stacking)
432
def _find_or_create_repository(self, force_new_repo):
433
"""Create a new repository if needed, returning the repository."""
434
policy = self.determine_repository_policy(force_new_repo)
435
return policy.acquire_repository()[0]
438
def create_branch_convenience(base, force_new_repo=False,
439
force_new_tree=None, format=None,
440
possible_transports=None):
441
"""Create a new BzrDir, Branch and Repository at the url 'base'.
443
This is a convenience function - it will use an existing repository
444
if possible, can be told explicitly whether to create a working tree or
447
This will use the current default BzrDirFormat unless one is
448
specified, and use whatever
449
repository format that that uses via bzrdir.create_branch and
450
create_repository. If a shared repository is available that is used
451
preferentially. Whatever repository is used, its tree creation policy
454
The created Branch object is returned.
455
If a working tree cannot be made due to base not being a file:// url,
456
no error is raised unless force_new_tree is True, in which case no
457
data is created on disk and NotLocalUrl is raised.
459
:param base: The URL to create the branch at.
460
:param force_new_repo: If True a new repository is always created.
461
:param force_new_tree: If True or False force creation of a tree or
462
prevent such creation respectively.
463
:param format: Override for the bzrdir format to create.
464
:param possible_transports: An optional reusable transports list.
467
# check for non local urls
468
t = get_transport(base, possible_transports)
469
if not isinstance(t, local.LocalTransport):
470
raise errors.NotLocalUrl(base)
471
bzrdir = BzrDir.create(base, format, possible_transports)
472
repo = bzrdir._find_or_create_repository(force_new_repo)
473
result = bzrdir.create_branch()
474
if force_new_tree or (repo.make_working_trees() and
475
force_new_tree is None):
477
bzrdir.create_workingtree()
478
except errors.NotLocalUrl:
483
def create_standalone_workingtree(base, format=None):
484
"""Create a new BzrDir, WorkingTree, Branch and Repository at 'base'.
486
'base' must be a local path or a file:// url.
488
This will use the current default BzrDirFormat unless one is
489
specified, and use whatever
490
repository format that that uses for bzrdirformat.create_workingtree,
491
create_branch and create_repository.
493
:param format: Override for the bzrdir format to create.
494
:return: The WorkingTree object.
496
t = get_transport(base)
497
if not isinstance(t, local.LocalTransport):
498
raise errors.NotLocalUrl(base)
499
bzrdir = BzrDir.create_branch_and_repo(base,
501
format=format).bzrdir
502
return bzrdir.create_workingtree()
504
@deprecated_method(deprecated_in((2, 3, 0)))
505
def generate_backup_name(self, base):
506
return self._available_backup_name(base)
508
def _available_backup_name(self, base):
509
"""Find a non-existing backup file name based on base.
511
See bzrlib.osutils.available_backup_name about race conditions.
513
return osutils.available_backup_name(base, self.root_transport.has)
515
def backup_bzrdir(self):
516
"""Backup this bzr control directory.
518
:return: Tuple with old path name and new path name
521
pb = ui.ui_factory.nested_progress_bar()
523
old_path = self.root_transport.abspath('.bzr')
524
backup_dir = self._available_backup_name('backup.bzr')
525
new_path = self.root_transport.abspath(backup_dir)
526
ui.ui_factory.note('making backup of %s\n to %s'
527
% (old_path, new_path,))
528
self.root_transport.copy_tree('.bzr', backup_dir)
529
return (old_path, new_path)
533
def retire_bzrdir(self, limit=10000):
534
"""Permanently disable the bzrdir.
536
This is done by renaming it to give the user some ability to recover
537
if there was a problem.
539
This will have horrible consequences if anyone has anything locked or
541
:param limit: number of times to retry
546
to_path = '.bzr.retired.%d' % i
547
self.root_transport.rename('.bzr', to_path)
548
note("renamed %s to %s"
549
% (self.root_transport.abspath('.bzr'), to_path))
551
except (errors.TransportError, IOError, errors.PathError):
558
def _find_containing(self, evaluate):
559
"""Find something in a containing control directory.
561
This method will scan containing control dirs, until it finds what
562
it is looking for, decides that it will never find it, or runs out
563
of containing control directories to check.
565
It is used to implement find_repository and
566
determine_repository_policy.
568
:param evaluate: A function returning (value, stop). If stop is True,
569
the value will be returned.
573
result, stop = evaluate(found_bzrdir)
576
next_transport = found_bzrdir.root_transport.clone('..')
577
if (found_bzrdir.user_url == next_transport.base):
578
# top of the file system
580
# find the next containing bzrdir
582
found_bzrdir = BzrDir.open_containing_from_transport(
584
except errors.NotBranchError:
587
def find_repository(self):
588
"""Find the repository that should be used.
590
This does not require a branch as we use it to find the repo for
591
new branches as well as to hook existing branches up to their
594
def usable_repository(found_bzrdir):
595
# does it have a repository ?
597
repository = found_bzrdir.open_repository()
598
except errors.NoRepositoryPresent:
600
if found_bzrdir.user_url == self.user_url:
601
return repository, True
602
elif repository.is_shared():
603
return repository, True
607
found_repo = self._find_containing(usable_repository)
608
if found_repo is None:
609
raise errors.NoRepositoryPresent(self)
612
def _find_creation_modes(self):
613
"""Determine the appropriate modes for files and directories.
615
They're always set to be consistent with the base directory,
616
assuming that this transport allows setting modes.
618
# TODO: Do we need or want an option (maybe a config setting) to turn
619
# this off or override it for particular locations? -- mbp 20080512
620
if self._mode_check_done:
622
self._mode_check_done = True
624
st = self.transport.stat('.')
625
except errors.TransportNotPossible:
626
self._dir_mode = None
627
self._file_mode = None
629
# Check the directory mode, but also make sure the created
630
# directories and files are read-write for this user. This is
631
# mostly a workaround for filesystems which lie about being able to
632
# write to a directory (cygwin & win32)
633
if (st.st_mode & 07777 == 00000):
634
# FTP allows stat but does not return dir/file modes
635
self._dir_mode = None
636
self._file_mode = None
638
self._dir_mode = (st.st_mode & 07777) | 00700
639
# Remove the sticky and execute bits for files
640
self._file_mode = self._dir_mode & ~07111
642
def _get_file_mode(self):
643
"""Return Unix mode for newly created files, or None.
645
if not self._mode_check_done:
646
self._find_creation_modes()
647
return self._file_mode
649
def _get_dir_mode(self):
650
"""Return Unix mode for newly created directories, or None.
652
if not self._mode_check_done:
653
self._find_creation_modes()
654
return self._dir_mode
656
def get_config(self):
657
"""Get configuration for this BzrDir."""
658
return config.BzrDirConfig(self)
660
def _get_config(self):
661
"""By default, no configuration is available."""
664
def __init__(self, _transport, _format):
665
"""Initialize a Bzr control dir object.
667
Only really common logic should reside here, concrete classes should be
668
made with varying behaviours.
670
:param _format: the format that is creating this BzrDir instance.
671
:param _transport: the transport this dir is based at.
673
self._format = _format
674
# these are also under the more standard names of
675
# control_transport and user_transport
676
self.transport = _transport.clone('.bzr')
677
self.root_transport = _transport
678
self._mode_check_done = False
681
def user_transport(self):
682
return self.root_transport
685
def control_transport(self):
686
return self.transport
688
def is_control_filename(self, filename):
689
"""True if filename is the name of a path which is reserved for bzrdir's.
691
:param filename: A filename within the root transport of this bzrdir.
693
This is true IF and ONLY IF the filename is part of the namespace reserved
694
for bzr control dirs. Currently this is the '.bzr' directory in the root
695
of the root_transport.
697
# this might be better on the BzrDirFormat class because it refers to
698
# all the possible bzrdir disk formats.
699
# This method is tested via the workingtree is_control_filename tests-
700
# it was extracted from WorkingTree.is_control_filename. If the method's
701
# contract is extended beyond the current trivial implementation, please
702
# add new tests for it to the appropriate place.
703
return filename == '.bzr' or filename.startswith('.bzr/')
706
def open_unsupported(base):
707
"""Open a branch which is not supported."""
708
return BzrDir.open(base, _unsupported=True)
711
def open(base, _unsupported=False, possible_transports=None):
712
"""Open an existing bzrdir, rooted at 'base' (url).
714
:param _unsupported: a private parameter to the BzrDir class.
716
t = get_transport(base, possible_transports=possible_transports)
717
return BzrDir.open_from_transport(t, _unsupported=_unsupported)
720
def open_from_transport(transport, _unsupported=False,
721
_server_formats=True):
722
"""Open a bzrdir within a particular directory.
724
:param transport: Transport containing the bzrdir.
725
:param _unsupported: private.
727
for hook in BzrDir.hooks['pre_open']:
729
# Keep initial base since 'transport' may be modified while following
731
base = transport.base
732
def find_format(transport):
733
return transport, controldir.ControlDirFormat.find_format(
734
transport, _server_formats=_server_formats)
736
def redirected(transport, e, redirection_notice):
737
redirected_transport = transport._redirected_to(e.source, e.target)
738
if redirected_transport is None:
739
raise errors.NotBranchError(base)
740
note('%s is%s redirected to %s',
741
transport.base, e.permanently, redirected_transport.base)
742
return redirected_transport
745
transport, format = do_catching_redirections(find_format,
748
except errors.TooManyRedirections:
749
raise errors.NotBranchError(base)
751
BzrDir._check_supported(format, _unsupported)
752
return format.open(transport, _found=True)
755
def open_containing(url, possible_transports=None):
756
"""Open an existing branch which contains url.
758
:param url: url to search from.
759
See open_containing_from_transport for more detail.
761
transport = get_transport(url, possible_transports)
762
return BzrDir.open_containing_from_transport(transport)
765
def open_containing_from_transport(a_transport):
766
"""Open an existing branch which contains a_transport.base.
768
This probes for a branch at a_transport, and searches upwards from there.
770
Basically we keep looking up until we find the control directory or
771
run into the root. If there isn't one, raises NotBranchError.
772
If there is one and it is either an unrecognised format or an unsupported
773
format, UnknownFormatError or UnsupportedFormatError are raised.
774
If there is one, it is returned, along with the unused portion of url.
776
:return: The BzrDir that contains the path, and a Unicode path
777
for the rest of the URL.
779
# this gets the normalised url back. I.e. '.' -> the full path.
780
url = a_transport.base
783
result = BzrDir.open_from_transport(a_transport)
784
return result, urlutils.unescape(a_transport.relpath(url))
785
except errors.NotBranchError, e:
788
new_t = a_transport.clone('..')
789
except errors.InvalidURLJoin:
790
# reached the root, whatever that may be
791
raise errors.NotBranchError(path=url)
792
if new_t.base == a_transport.base:
793
# reached the root, whatever that may be
794
raise errors.NotBranchError(path=url)
798
def open_tree_or_branch(klass, location):
799
"""Return the branch and working tree at a location.
801
If there is no tree at the location, tree will be None.
802
If there is no branch at the location, an exception will be
804
:return: (tree, branch)
806
bzrdir = klass.open(location)
807
return bzrdir._get_tree_branch()
810
def open_containing_tree_or_branch(klass, location):
811
"""Return the branch and working tree contained by a location.
813
Returns (tree, branch, relpath).
814
If there is no tree at containing the location, tree will be None.
815
If there is no branch containing the location, an exception will be
817
relpath is the portion of the path that is contained by the branch.
819
bzrdir, relpath = klass.open_containing(location)
820
tree, branch = bzrdir._get_tree_branch()
821
return tree, branch, relpath
824
def open_containing_tree_branch_or_repository(klass, location):
825
"""Return the working tree, branch and repo contained by a location.
827
Returns (tree, branch, repository, relpath).
828
If there is no tree containing the location, tree will be None.
829
If there is no branch containing the location, branch will be None.
830
If there is no repository containing the location, repository will be
832
relpath is the portion of the path that is contained by the innermost
835
If no tree, branch or repository is found, a NotBranchError is raised.
837
bzrdir, relpath = klass.open_containing(location)
839
tree, branch = bzrdir._get_tree_branch()
840
except errors.NotBranchError:
842
repo = bzrdir.find_repository()
843
return None, None, repo, relpath
844
except (errors.NoRepositoryPresent):
845
raise errors.NotBranchError(location)
846
return tree, branch, branch.repository, relpath
848
def _cloning_metadir(self):
849
"""Produce a metadir suitable for cloning with.
851
:returns: (destination_bzrdir_format, source_repository)
853
result_format = self._format.__class__()
856
branch = self.open_branch(ignore_fallbacks=True)
857
source_repository = branch.repository
858
result_format._branch_format = branch._format
859
except errors.NotBranchError:
861
source_repository = self.open_repository()
862
except errors.NoRepositoryPresent:
863
source_repository = None
865
# XXX TODO: This isinstance is here because we have not implemented
866
# the fix recommended in bug # 103195 - to delegate this choice the
868
repo_format = source_repository._format
869
if isinstance(repo_format, remote.RemoteRepositoryFormat):
870
source_repository._ensure_real()
871
repo_format = source_repository._real_repository._format
872
result_format.repository_format = repo_format
874
# TODO: Couldn't we just probe for the format in these cases,
875
# rather than opening the whole tree? It would be a little
876
# faster. mbp 20070401
877
tree = self.open_workingtree(recommend_upgrade=False)
878
except (errors.NoWorkingTree, errors.NotLocalUrl):
879
result_format.workingtree_format = None
881
result_format.workingtree_format = tree._format.__class__()
882
return result_format, source_repository
884
def cloning_metadir(self, require_stacking=False):
885
"""Produce a metadir suitable for cloning or sprouting with.
887
These operations may produce workingtrees (yes, even though they're
888
"cloning" something that doesn't have a tree), so a viable workingtree
889
format must be selected.
891
:require_stacking: If True, non-stackable formats will be upgraded
892
to similar stackable formats.
893
:returns: a BzrDirFormat with all component formats either set
894
appropriately or set to None if that component should not be
897
format, repository = self._cloning_metadir()
898
if format._workingtree_format is None:
900
if repository is None:
901
# No repository either
903
# We have a repository, so set a working tree? (Why? This seems to
904
# contradict the stated return value in the docstring).
905
tree_format = repository._format._matchingbzrdir.workingtree_format
906
format.workingtree_format = tree_format.__class__()
908
format.require_stacking()
912
def create(cls, base, format=None, possible_transports=None):
913
"""Create a new BzrDir at the url 'base'.
915
:param format: If supplied, the format of branch to create. If not
916
supplied, the default is used.
917
:param possible_transports: If supplied, a list of transports that
918
can be reused to share a remote connection.
920
if cls is not BzrDir:
921
raise AssertionError("BzrDir.create always creates the"
922
"default format, not one of %r" % cls)
923
t = get_transport(base, possible_transports)
926
format = controldir.ControlDirFormat.get_default_format()
927
return format.initialize_on_transport(t)
931
class BzrDirHooks(hooks.Hooks):
932
"""Hooks for BzrDir operations."""
935
"""Create the default hooks."""
936
hooks.Hooks.__init__(self)
937
self.create_hook(hooks.HookPoint('pre_open',
938
"Invoked before attempting to open a BzrDir with the transport "
939
"that the open will use.", (1, 14), None))
940
self.create_hook(hooks.HookPoint('post_repo_init',
941
"Invoked after a repository has been initialized. "
942
"post_repo_init is called with a "
943
"bzrlib.bzrdir.RepoInitHookParams.",
946
# install the default hooks
947
BzrDir.hooks = BzrDirHooks()
950
class RepoInitHookParams(object):
951
"""Object holding parameters passed to *_repo_init hooks.
953
There are 4 fields that hooks may wish to access:
955
:ivar repository: Repository created
956
:ivar format: Repository format
957
:ivar bzrdir: The bzrdir for the repository
958
:ivar shared: The repository is shared
961
def __init__(self, repository, format, a_bzrdir, shared):
962
"""Create a group of RepoInitHook parameters.
964
:param repository: Repository created
965
:param format: Repository format
966
:param bzrdir: The bzrdir for the repository
967
:param shared: The repository is shared
969
self.repository = repository
971
self.bzrdir = a_bzrdir
974
def __eq__(self, other):
975
return self.__dict__ == other.__dict__
979
return "<%s for %s>" % (self.__class__.__name__,
982
return "<%s for %s>" % (self.__class__.__name__,
986
class BzrDirPreSplitOut(BzrDir):
987
"""A common class for the all-in-one formats."""
989
def __init__(self, _transport, _format):
990
"""See BzrDir.__init__."""
991
super(BzrDirPreSplitOut, self).__init__(_transport, _format)
992
self._control_files = lockable_files.LockableFiles(
993
self.get_branch_transport(None),
994
self._format._lock_file_name,
995
self._format._lock_class)
997
def break_lock(self):
998
"""Pre-splitout bzrdirs do not suffer from stale locks."""
999
raise NotImplementedError(self.break_lock)
1001
def cloning_metadir(self, require_stacking=False):
1002
"""Produce a metadir suitable for cloning with."""
1003
if require_stacking:
1004
return controldir.format_registry.make_bzrdir('1.6')
1005
return self._format.__class__()
1007
def clone(self, url, revision_id=None, force_new_repo=False,
1008
preserve_stacking=False):
1009
"""See BzrDir.clone().
1011
force_new_repo has no effect, since this family of formats always
1012
require a new repository.
1013
preserve_stacking has no effect, since no source branch using this
1014
family of formats can be stacked, so there is no stacking to preserve.
1016
self._make_tail(url)
1017
result = self._format._initialize_for_clone(url)
1018
self.open_repository().clone(result, revision_id=revision_id)
1019
from_branch = self.open_branch()
1020
from_branch.clone(result, revision_id=revision_id)
1022
tree = self.open_workingtree()
1023
except errors.NotLocalUrl:
1024
# make a new one, this format always has to have one.
1025
result._init_workingtree()
1030
def create_branch(self, name=None):
1031
"""See BzrDir.create_branch."""
1032
return self._format.get_branch_format().initialize(self, name=name)
1034
def destroy_branch(self, name=None):
1035
"""See BzrDir.destroy_branch."""
1036
raise errors.UnsupportedOperation(self.destroy_branch, self)
1038
def create_repository(self, shared=False):
1039
"""See BzrDir.create_repository."""
1041
raise errors.IncompatibleFormat('shared repository', self._format)
1042
return self.open_repository()
1044
def destroy_repository(self):
1045
"""See BzrDir.destroy_repository."""
1046
raise errors.UnsupportedOperation(self.destroy_repository, self)
1048
def create_workingtree(self, revision_id=None, from_branch=None,
1049
accelerator_tree=None, hardlink=False):
1050
"""See BzrDir.create_workingtree."""
1051
# The workingtree is sometimes created when the bzrdir is created,
1052
# but not when cloning.
1054
# this looks buggy but is not -really-
1055
# because this format creates the workingtree when the bzrdir is
1057
# clone and sprout will have set the revision_id
1058
# and that will have set it for us, its only
1059
# specific uses of create_workingtree in isolation
1060
# that can do wonky stuff here, and that only
1061
# happens for creating checkouts, which cannot be
1062
# done on this format anyway. So - acceptable wart.
1064
warning("can't support hardlinked working trees in %r"
1067
result = self.open_workingtree(recommend_upgrade=False)
1068
except errors.NoSuchFile:
1069
result = self._init_workingtree()
1070
if revision_id is not None:
1071
if revision_id == _mod_revision.NULL_REVISION:
1072
result.set_parent_ids([])
1074
result.set_parent_ids([revision_id])
1077
def _init_workingtree(self):
1078
from bzrlib.workingtree import WorkingTreeFormat2
1080
return WorkingTreeFormat2().initialize(self)
1081
except errors.NotLocalUrl:
1082
# Even though we can't access the working tree, we need to
1083
# create its control files.
1084
return WorkingTreeFormat2()._stub_initialize_on_transport(
1085
self.transport, self._control_files._file_mode)
1087
def destroy_workingtree(self):
1088
"""See BzrDir.destroy_workingtree."""
1089
raise errors.UnsupportedOperation(self.destroy_workingtree, self)
1091
def destroy_workingtree_metadata(self):
1092
"""See BzrDir.destroy_workingtree_metadata."""
1093
raise errors.UnsupportedOperation(self.destroy_workingtree_metadata,
1096
def get_branch_transport(self, branch_format, name=None):
1097
"""See BzrDir.get_branch_transport()."""
1098
if name is not None:
1099
raise errors.NoColocatedBranchSupport(self)
1100
if branch_format is None:
1101
return self.transport
1103
branch_format.get_format_string()
1104
except NotImplementedError:
1105
return self.transport
1106
raise errors.IncompatibleFormat(branch_format, self._format)
1108
def get_repository_transport(self, repository_format):
1109
"""See BzrDir.get_repository_transport()."""
1110
if repository_format is None:
1111
return self.transport
1113
repository_format.get_format_string()
1114
except NotImplementedError:
1115
return self.transport
1116
raise errors.IncompatibleFormat(repository_format, self._format)
1118
def get_workingtree_transport(self, workingtree_format):
1119
"""See BzrDir.get_workingtree_transport()."""
1120
if workingtree_format is None:
1121
return self.transport
1123
workingtree_format.get_format_string()
1124
except NotImplementedError:
1125
return self.transport
1126
raise errors.IncompatibleFormat(workingtree_format, self._format)
1128
def needs_format_conversion(self, format=None):
1129
"""See BzrDir.needs_format_conversion()."""
1130
# if the format is not the same as the system default,
1131
# an upgrade is needed.
1133
symbol_versioning.warn(symbol_versioning.deprecated_in((1, 13, 0))
1134
% 'needs_format_conversion(format=None)')
1135
format = BzrDirFormat.get_default_format()
1136
return not isinstance(self._format, format.__class__)
1138
def open_branch(self, name=None, unsupported=False,
1139
ignore_fallbacks=False):
1140
"""See BzrDir.open_branch."""
1141
from bzrlib.branch import BzrBranchFormat4
1142
format = BzrBranchFormat4()
1143
self._check_supported(format, unsupported)
1144
return format.open(self, name, _found=True)
1146
def sprout(self, url, revision_id=None, force_new_repo=False,
1147
possible_transports=None, accelerator_tree=None,
1148
hardlink=False, stacked=False, create_tree_if_local=True,
1149
source_branch=None):
1150
"""See BzrDir.sprout()."""
1151
if source_branch is not None:
1152
my_branch = self.open_branch()
1153
if source_branch.base != my_branch.base:
1154
raise AssertionError(
1155
"source branch %r is not within %r with branch %r" %
1156
(source_branch, self, my_branch))
1158
raise errors.UnstackableBranchFormat(
1159
self._format, self.root_transport.base)
1160
if not create_tree_if_local:
1161
raise errors.MustHaveWorkingTree(
1162
self._format, self.root_transport.base)
1163
from bzrlib.workingtree import WorkingTreeFormat2
1164
self._make_tail(url)
1165
result = self._format._initialize_for_clone(url)
1167
self.open_repository().clone(result, revision_id=revision_id)
1168
except errors.NoRepositoryPresent:
1171
self.open_branch().sprout(result, revision_id=revision_id)
1172
except errors.NotBranchError:
1175
# we always want a working tree
1176
WorkingTreeFormat2().initialize(result,
1177
accelerator_tree=accelerator_tree,
1182
class BzrDir4(BzrDirPreSplitOut):
1183
"""A .bzr version 4 control object.
1185
This is a deprecated format and may be removed after sept 2006.
1188
def create_repository(self, shared=False):
1189
"""See BzrDir.create_repository."""
1190
return self._format.repository_format.initialize(self, shared)
1192
def needs_format_conversion(self, format=None):
1193
"""Format 4 dirs are always in need of conversion."""
1195
symbol_versioning.warn(symbol_versioning.deprecated_in((1, 13, 0))
1196
% 'needs_format_conversion(format=None)')
1199
def open_repository(self):
1200
"""See BzrDir.open_repository."""
1201
from bzrlib.repofmt.weaverepo import RepositoryFormat4
1202
return RepositoryFormat4().open(self, _found=True)
1205
class BzrDir5(BzrDirPreSplitOut):
1206
"""A .bzr version 5 control object.
1208
This is a deprecated format and may be removed after sept 2006.
1211
def has_workingtree(self):
1212
"""See BzrDir.has_workingtree."""
1215
def open_repository(self):
1216
"""See BzrDir.open_repository."""
1217
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1218
return RepositoryFormat5().open(self, _found=True)
1220
def open_workingtree(self, _unsupported=False,
1221
recommend_upgrade=True):
1222
"""See BzrDir.create_workingtree."""
1223
from bzrlib.workingtree import WorkingTreeFormat2
1224
wt_format = WorkingTreeFormat2()
1225
# we don't warn here about upgrades; that ought to be handled for the
1227
return wt_format.open(self, _found=True)
1230
class BzrDir6(BzrDirPreSplitOut):
1231
"""A .bzr version 6 control object.
1233
This is a deprecated format and may be removed after sept 2006.
1236
def has_workingtree(self):
1237
"""See BzrDir.has_workingtree."""
1240
def open_repository(self):
1241
"""See BzrDir.open_repository."""
1242
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1243
return RepositoryFormat6().open(self, _found=True)
1245
def open_workingtree(self, _unsupported=False,
1246
recommend_upgrade=True):
1247
"""See BzrDir.create_workingtree."""
1248
# we don't warn here about upgrades; that ought to be handled for the
1250
from bzrlib.workingtree import WorkingTreeFormat2
1251
return WorkingTreeFormat2().open(self, _found=True)
1254
class BzrDirMeta1(BzrDir):
1255
"""A .bzr meta version 1 control object.
1257
This is the first control object where the
1258
individual aspects are really split out: there are separate repository,
1259
workingtree and branch subdirectories and any subset of the three can be
1260
present within a BzrDir.
1263
def can_convert_format(self):
1264
"""See BzrDir.can_convert_format()."""
1267
def create_branch(self, name=None):
1268
"""See BzrDir.create_branch."""
1269
return self._format.get_branch_format().initialize(self, name=name)
1271
def destroy_branch(self, name=None):
1272
"""See BzrDir.create_branch."""
1273
if name is not None:
1274
raise errors.NoColocatedBranchSupport(self)
1275
self.transport.delete_tree('branch')
1277
def create_repository(self, shared=False):
1278
"""See BzrDir.create_repository."""
1279
return self._format.repository_format.initialize(self, shared)
1281
def destroy_repository(self):
1282
"""See BzrDir.destroy_repository."""
1283
self.transport.delete_tree('repository')
1285
def create_workingtree(self, revision_id=None, from_branch=None,
1286
accelerator_tree=None, hardlink=False):
1287
"""See BzrDir.create_workingtree."""
1288
return self._format.workingtree_format.initialize(
1289
self, revision_id, from_branch=from_branch,
1290
accelerator_tree=accelerator_tree, hardlink=hardlink)
1292
def destroy_workingtree(self):
1293
"""See BzrDir.destroy_workingtree."""
1294
wt = self.open_workingtree(recommend_upgrade=False)
1295
repository = wt.branch.repository
1296
empty = repository.revision_tree(_mod_revision.NULL_REVISION)
1297
# We ignore the conflicts returned by wt.revert since we're about to
1298
# delete the wt metadata anyway, all that should be left here are
1299
# detritus. But see bug #634470 about subtree .bzr dirs.
1300
conflicts = wt.revert(old_tree=empty)
1301
self.destroy_workingtree_metadata()
1303
def destroy_workingtree_metadata(self):
1304
self.transport.delete_tree('checkout')
1306
def find_branch_format(self, name=None):
1307
"""Find the branch 'format' for this bzrdir.
1309
This might be a synthetic object for e.g. RemoteBranch and SVN.
1311
from bzrlib.branch import BranchFormat
1312
return BranchFormat.find_format(self, name=name)
1314
def _get_mkdir_mode(self):
1315
"""Figure out the mode to use when creating a bzrdir subdir."""
1316
temp_control = lockable_files.LockableFiles(self.transport, '',
1317
lockable_files.TransportLock)
1318
return temp_control._dir_mode
1320
def get_branch_reference(self, name=None):
1321
"""See BzrDir.get_branch_reference()."""
1322
from bzrlib.branch import BranchFormat
1323
format = BranchFormat.find_format(self, name=name)
1324
return format.get_reference(self, name=name)
1326
def get_branch_transport(self, branch_format, name=None):
1327
"""See BzrDir.get_branch_transport()."""
1328
if name is not None:
1329
raise errors.NoColocatedBranchSupport(self)
1330
# XXX: this shouldn't implicitly create the directory if it's just
1331
# promising to get a transport -- mbp 20090727
1332
if branch_format is None:
1333
return self.transport.clone('branch')
1335
branch_format.get_format_string()
1336
except NotImplementedError:
1337
raise errors.IncompatibleFormat(branch_format, self._format)
1339
self.transport.mkdir('branch', mode=self._get_mkdir_mode())
1340
except errors.FileExists:
1342
return self.transport.clone('branch')
1344
def get_repository_transport(self, repository_format):
1345
"""See BzrDir.get_repository_transport()."""
1346
if repository_format is None:
1347
return self.transport.clone('repository')
1349
repository_format.get_format_string()
1350
except NotImplementedError:
1351
raise errors.IncompatibleFormat(repository_format, self._format)
1353
self.transport.mkdir('repository', mode=self._get_mkdir_mode())
1354
except errors.FileExists:
1356
return self.transport.clone('repository')
1358
def get_workingtree_transport(self, workingtree_format):
1359
"""See BzrDir.get_workingtree_transport()."""
1360
if workingtree_format is None:
1361
return self.transport.clone('checkout')
1363
workingtree_format.get_format_string()
1364
except NotImplementedError:
1365
raise errors.IncompatibleFormat(workingtree_format, self._format)
1367
self.transport.mkdir('checkout', mode=self._get_mkdir_mode())
1368
except errors.FileExists:
1370
return self.transport.clone('checkout')
1372
def has_workingtree(self):
1373
"""Tell if this bzrdir contains a working tree.
1375
This will still raise an exception if the bzrdir has a workingtree that
1376
is remote & inaccessible.
1378
Note: if you're going to open the working tree, you should just go
1379
ahead and try, and not ask permission first.
1381
from bzrlib.workingtree import WorkingTreeFormat
1383
WorkingTreeFormat.find_format(self)
1384
except errors.NoWorkingTree:
1388
def needs_format_conversion(self, format=None):
1389
"""See BzrDir.needs_format_conversion()."""
1391
symbol_versioning.warn(symbol_versioning.deprecated_in((1, 13, 0))
1392
% 'needs_format_conversion(format=None)')
1394
format = BzrDirFormat.get_default_format()
1395
if not isinstance(self._format, format.__class__):
1396
# it is not a meta dir format, conversion is needed.
1398
# we might want to push this down to the repository?
1400
if not isinstance(self.open_repository()._format,
1401
format.repository_format.__class__):
1402
# the repository needs an upgrade.
1404
except errors.NoRepositoryPresent:
1406
for branch in self.list_branches():
1407
if not isinstance(branch._format,
1408
format.get_branch_format().__class__):
1409
# the branch needs an upgrade.
1412
my_wt = self.open_workingtree(recommend_upgrade=False)
1413
if not isinstance(my_wt._format,
1414
format.workingtree_format.__class__):
1415
# the workingtree needs an upgrade.
1417
except (errors.NoWorkingTree, errors.NotLocalUrl):
1421
def open_branch(self, name=None, unsupported=False,
1422
ignore_fallbacks=False):
1423
"""See BzrDir.open_branch."""
1424
format = self.find_branch_format(name=name)
1425
self._check_supported(format, unsupported)
1426
return format.open(self, name=name,
1427
_found=True, ignore_fallbacks=ignore_fallbacks)
1429
def open_repository(self, unsupported=False):
1430
"""See BzrDir.open_repository."""
1431
from bzrlib.repository import RepositoryFormat
1432
format = RepositoryFormat.find_format(self)
1433
self._check_supported(format, unsupported)
1434
return format.open(self, _found=True)
1436
def open_workingtree(self, unsupported=False,
1437
recommend_upgrade=True):
1438
"""See BzrDir.open_workingtree."""
1439
from bzrlib.workingtree import WorkingTreeFormat
1440
format = WorkingTreeFormat.find_format(self)
1441
self._check_supported(format, unsupported,
1443
basedir=self.root_transport.base)
1444
return format.open(self, _found=True)
1446
def _get_config(self):
1447
return config.TransportConfig(self.transport, 'control.conf')
1450
class BzrProber(controldir.Prober):
1451
"""Prober for formats that use a .bzr/ control directory."""
1454
"""The known .bzr formats."""
1457
def register_bzrdir_format(klass, format):
1458
klass._formats[format.get_format_string()] = format
1461
def unregister_bzrdir_format(klass, format):
1462
del klass._formats[format.get_format_string()]
1465
def probe_transport(klass, transport):
1466
"""Return the .bzrdir style format present in a directory."""
1468
format_string = transport.get_bytes(".bzr/branch-format")
1469
except errors.NoSuchFile:
1470
raise errors.NotBranchError(path=transport.base)
1472
return klass._formats[format_string]
1474
raise errors.UnknownFormatError(format=format_string, kind='bzrdir')
1477
controldir.ControlDirFormat.register_prober(BzrProber)
1480
class RemoteBzrProber(controldir.Prober):
1481
"""Prober for remote servers that provide a Bazaar smart server."""
1484
def probe_transport(klass, transport):
1485
"""Return a RemoteBzrDirFormat object if it looks possible."""
1487
medium = transport.get_smart_medium()
1488
except (NotImplementedError, AttributeError,
1489
errors.TransportNotPossible, errors.NoSmartMedium,
1490
errors.SmartProtocolError):
1491
# no smart server, so not a branch for this format type.
1492
raise errors.NotBranchError(path=transport.base)
1494
# Decline to open it if the server doesn't support our required
1495
# version (3) so that the VFS-based transport will do it.
1496
if medium.should_probe():
1498
server_version = medium.protocol_version()
1499
except errors.SmartProtocolError:
1500
# Apparently there's no usable smart server there, even though
1501
# the medium supports the smart protocol.
1502
raise errors.NotBranchError(path=transport.base)
1503
if server_version != '2':
1504
raise errors.NotBranchError(path=transport.base)
1505
return RemoteBzrDirFormat()
1508
class BzrDirFormat(controldir.ControlDirFormat):
1509
"""ControlDirFormat base class for .bzr/ directories.
1511
Formats are placed in a dict by their format string for reference
1512
during bzrdir opening. These should be subclasses of BzrDirFormat
1515
Once a format is deprecated, just deprecate the initialize and open
1516
methods on the format class. Do not deprecate the object, as the
1517
object will be created every system load.
1520
_lock_file_name = 'branch-lock'
1522
# _lock_class must be set in subclasses to the lock type, typ.
1523
# TransportLock or LockDir
1525
def get_format_string(self):
1526
"""Return the ASCII format string that identifies this format."""
1527
raise NotImplementedError(self.get_format_string)
1529
def initialize_on_transport(self, transport):
1530
"""Initialize a new bzrdir in the base directory of a Transport."""
1532
# can we hand off the request to the smart server rather than using
1534
client_medium = transport.get_smart_medium()
1535
except errors.NoSmartMedium:
1536
return self._initialize_on_transport_vfs(transport)
1538
# Current RPC's only know how to create bzr metadir1 instances, so
1539
# we still delegate to vfs methods if the requested format is not a
1541
if type(self) != BzrDirMetaFormat1:
1542
return self._initialize_on_transport_vfs(transport)
1543
remote_format = RemoteBzrDirFormat()
1544
self._supply_sub_formats_to(remote_format)
1545
return remote_format.initialize_on_transport(transport)
1547
def initialize_on_transport_ex(self, transport, use_existing_dir=False,
1548
create_prefix=False, force_new_repo=False, stacked_on=None,
1549
stack_on_pwd=None, repo_format_name=None, make_working_trees=None,
1550
shared_repo=False, vfs_only=False):
1551
"""Create this format on transport.
1553
The directory to initialize will be created.
1555
:param force_new_repo: Do not use a shared repository for the target,
1556
even if one is available.
1557
:param create_prefix: Create any missing directories leading up to
1559
:param use_existing_dir: Use an existing directory if one exists.
1560
:param stacked_on: A url to stack any created branch on, None to follow
1561
any target stacking policy.
1562
:param stack_on_pwd: If stack_on is relative, the location it is
1564
:param repo_format_name: If non-None, a repository will be
1565
made-or-found. Should none be found, or if force_new_repo is True
1566
the repo_format_name is used to select the format of repository to
1568
:param make_working_trees: Control the setting of make_working_trees
1569
for a new shared repository when one is made. None to use whatever
1570
default the format has.
1571
:param shared_repo: Control whether made repositories are shared or
1573
:param vfs_only: If True do not attempt to use a smart server
1574
:return: repo, bzrdir, require_stacking, repository_policy. repo is
1575
None if none was created or found, bzrdir is always valid.
1576
require_stacking is the result of examining the stacked_on
1577
parameter and any stacking policy found for the target.
1580
# Try to hand off to a smart server
1582
client_medium = transport.get_smart_medium()
1583
except errors.NoSmartMedium:
1586
# TODO: lookup the local format from a server hint.
1587
remote_dir_format = RemoteBzrDirFormat()
1588
remote_dir_format._network_name = self.network_name()
1589
self._supply_sub_formats_to(remote_dir_format)
1590
return remote_dir_format.initialize_on_transport_ex(transport,
1591
use_existing_dir=use_existing_dir, create_prefix=create_prefix,
1592
force_new_repo=force_new_repo, stacked_on=stacked_on,
1593
stack_on_pwd=stack_on_pwd, repo_format_name=repo_format_name,
1594
make_working_trees=make_working_trees, shared_repo=shared_repo)
1595
# XXX: Refactor the create_prefix/no_create_prefix code into a
1596
# common helper function
1597
# The destination may not exist - if so make it according to policy.
1598
def make_directory(transport):
1599
transport.mkdir('.')
1601
def redirected(transport, e, redirection_notice):
1602
note(redirection_notice)
1603
return transport._redirected_to(e.source, e.target)
1605
transport = do_catching_redirections(make_directory, transport,
1607
except errors.FileExists:
1608
if not use_existing_dir:
1610
except errors.NoSuchFile:
1611
if not create_prefix:
1613
transport.create_prefix()
1615
require_stacking = (stacked_on is not None)
1616
# Now the target directory exists, but doesn't have a .bzr
1617
# directory. So we need to create it, along with any work to create
1618
# all of the dependent branches, etc.
1620
result = self.initialize_on_transport(transport)
1621
if repo_format_name:
1623
# use a custom format
1624
result._format.repository_format = \
1625
repository.network_format_registry.get(repo_format_name)
1626
except AttributeError:
1627
# The format didn't permit it to be set.
1629
# A repository is desired, either in-place or shared.
1630
repository_policy = result.determine_repository_policy(
1631
force_new_repo, stacked_on, stack_on_pwd,
1632
require_stacking=require_stacking)
1633
result_repo, is_new_repo = repository_policy.acquire_repository(
1634
make_working_trees, shared_repo)
1635
if not require_stacking and repository_policy._require_stacking:
1636
require_stacking = True
1637
result._format.require_stacking()
1638
result_repo.lock_write()
1641
repository_policy = None
1642
return result_repo, result, require_stacking, repository_policy
1644
def _initialize_on_transport_vfs(self, transport):
1645
"""Initialize a new bzrdir using VFS calls.
1647
:param transport: The transport to create the .bzr directory in.
1650
# Since we are creating a .bzr directory, inherit the
1651
# mode from the root directory
1652
temp_control = lockable_files.LockableFiles(transport,
1653
'', lockable_files.TransportLock)
1654
temp_control._transport.mkdir('.bzr',
1655
# FIXME: RBC 20060121 don't peek under
1657
mode=temp_control._dir_mode)
1658
if sys.platform == 'win32' and isinstance(transport, local.LocalTransport):
1659
win32utils.set_file_attr_hidden(transport._abspath('.bzr'))
1660
file_mode = temp_control._file_mode
1662
bzrdir_transport = transport.clone('.bzr')
1663
utf8_files = [('README',
1664
"This is a Bazaar control directory.\n"
1665
"Do not change any files in this directory.\n"
1666
"See http://bazaar-vcs.org/ for more information about Bazaar.\n"),
1667
('branch-format', self.get_format_string()),
1669
# NB: no need to escape relative paths that are url safe.
1670
control_files = lockable_files.LockableFiles(bzrdir_transport,
1671
self._lock_file_name, self._lock_class)
1672
control_files.create_lock()
1673
control_files.lock_write()
1675
for (filename, content) in utf8_files:
1676
bzrdir_transport.put_bytes(filename, content,
1679
control_files.unlock()
1680
return self.open(transport, _found=True)
1682
def open(self, transport, _found=False):
1683
"""Return an instance of this format for the dir transport points at.
1685
_found is a private parameter, do not use it.
1688
found_format = controldir.ControlDirFormat.find_format(transport)
1689
if not isinstance(found_format, self.__class__):
1690
raise AssertionError("%s was asked to open %s, but it seems to need "
1692
% (self, transport, found_format))
1693
# Allow subclasses - use the found format.
1694
self._supply_sub_formats_to(found_format)
1695
return found_format._open(transport)
1696
return self._open(transport)
1698
def _open(self, transport):
1699
"""Template method helper for opening BzrDirectories.
1701
This performs the actual open and any additional logic or parameter
1704
raise NotImplementedError(self._open)
1707
def register_format(klass, format):
1708
BzrProber.register_bzrdir_format(format)
1709
# bzr native formats have a network name of their format string.
1710
controldir.network_format_registry.register(format.get_format_string(), format.__class__)
1711
controldir.ControlDirFormat.register_format(format)
1713
def _supply_sub_formats_to(self, other_format):
1714
"""Give other_format the same values for sub formats as this has.
1716
This method is expected to be used when parameterising a
1717
RemoteBzrDirFormat instance with the parameters from a
1718
BzrDirMetaFormat1 instance.
1720
:param other_format: other_format is a format which should be
1721
compatible with whatever sub formats are supported by self.
1726
def unregister_format(klass, format):
1727
BzrProber.unregister_bzrdir_format(format)
1728
controldir.ControlDirFormat.unregister_format(format)
1729
controldir.network_format_registry.remove(format.get_format_string())
1732
class BzrDirFormat4(BzrDirFormat):
1733
"""Bzr dir format 4.
1735
This format is a combined format for working tree, branch and repository.
1737
- Format 1 working trees [always]
1738
- Format 4 branches [always]
1739
- Format 4 repositories [always]
1741
This format is deprecated: it indexes texts using a text it which is
1742
removed in format 5; write support for this format has been removed.
1745
_lock_class = lockable_files.TransportLock
1747
def get_format_string(self):
1748
"""See BzrDirFormat.get_format_string()."""
1749
return "Bazaar-NG branch, format 0.0.4\n"
1751
def get_format_description(self):
1752
"""See BzrDirFormat.get_format_description()."""
1753
return "All-in-one format 4"
1755
def get_converter(self, format=None):
1756
"""See BzrDirFormat.get_converter()."""
1757
# there is one and only one upgrade path here.
1758
return ConvertBzrDir4To5()
1760
def initialize_on_transport(self, transport):
1761
"""Format 4 branches cannot be created."""
1762
raise errors.UninitializableFormat(self)
1764
def is_supported(self):
1765
"""Format 4 is not supported.
1767
It is not supported because the model changed from 4 to 5 and the
1768
conversion logic is expensive - so doing it on the fly was not
1773
def network_name(self):
1774
return self.get_format_string()
1776
def _open(self, transport):
1777
"""See BzrDirFormat._open."""
1778
return BzrDir4(transport, self)
1780
def __return_repository_format(self):
1781
"""Circular import protection."""
1782
from bzrlib.repofmt.weaverepo import RepositoryFormat4
1783
return RepositoryFormat4()
1784
repository_format = property(__return_repository_format)
1787
class BzrDirFormatAllInOne(BzrDirFormat):
1788
"""Common class for formats before meta-dirs."""
1790
def initialize_on_transport_ex(self, transport, use_existing_dir=False,
1791
create_prefix=False, force_new_repo=False, stacked_on=None,
1792
stack_on_pwd=None, repo_format_name=None, make_working_trees=None,
1794
"""See BzrDirFormat.initialize_on_transport_ex."""
1795
require_stacking = (stacked_on is not None)
1796
# Format 5 cannot stack, but we've been asked to - actually init
1798
if require_stacking:
1799
format = BzrDirMetaFormat1()
1800
return format.initialize_on_transport_ex(transport,
1801
use_existing_dir=use_existing_dir, create_prefix=create_prefix,
1802
force_new_repo=force_new_repo, stacked_on=stacked_on,
1803
stack_on_pwd=stack_on_pwd, repo_format_name=repo_format_name,
1804
make_working_trees=make_working_trees, shared_repo=shared_repo)
1805
return BzrDirFormat.initialize_on_transport_ex(self, transport,
1806
use_existing_dir=use_existing_dir, create_prefix=create_prefix,
1807
force_new_repo=force_new_repo, stacked_on=stacked_on,
1808
stack_on_pwd=stack_on_pwd, repo_format_name=repo_format_name,
1809
make_working_trees=make_working_trees, shared_repo=shared_repo)
1812
class BzrDirFormat5(BzrDirFormatAllInOne):
1813
"""Bzr control format 5.
1815
This format is a combined format for working tree, branch and repository.
1817
- Format 2 working trees [always]
1818
- Format 4 branches [always]
1819
- Format 5 repositories [always]
1820
Unhashed stores in the repository.
1823
_lock_class = lockable_files.TransportLock
1825
def get_format_string(self):
1826
"""See BzrDirFormat.get_format_string()."""
1827
return "Bazaar-NG branch, format 5\n"
1829
def get_branch_format(self):
1830
from bzrlib import branch
1831
return branch.BzrBranchFormat4()
1833
def get_format_description(self):
1834
"""See BzrDirFormat.get_format_description()."""
1835
return "All-in-one format 5"
1837
def get_converter(self, format=None):
1838
"""See BzrDirFormat.get_converter()."""
1839
# there is one and only one upgrade path here.
1840
return ConvertBzrDir5To6()
1842
def _initialize_for_clone(self, url):
1843
return self.initialize_on_transport(get_transport(url), _cloning=True)
1845
def initialize_on_transport(self, transport, _cloning=False):
1846
"""Format 5 dirs always have working tree, branch and repository.
1848
Except when they are being cloned.
1850
from bzrlib.branch import BzrBranchFormat4
1851
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1852
result = (super(BzrDirFormat5, self).initialize_on_transport(transport))
1853
RepositoryFormat5().initialize(result, _internal=True)
1855
branch = BzrBranchFormat4().initialize(result)
1856
result._init_workingtree()
1859
def network_name(self):
1860
return self.get_format_string()
1862
def _open(self, transport):
1863
"""See BzrDirFormat._open."""
1864
return BzrDir5(transport, self)
1866
def __return_repository_format(self):
1867
"""Circular import protection."""
1868
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1869
return RepositoryFormat5()
1870
repository_format = property(__return_repository_format)
1873
class BzrDirFormat6(BzrDirFormatAllInOne):
1874
"""Bzr control format 6.
1876
This format is a combined format for working tree, branch and repository.
1878
- Format 2 working trees [always]
1879
- Format 4 branches [always]
1880
- Format 6 repositories [always]
1883
_lock_class = lockable_files.TransportLock
1885
def get_format_string(self):
1886
"""See BzrDirFormat.get_format_string()."""
1887
return "Bazaar-NG branch, format 6\n"
1889
def get_format_description(self):
1890
"""See BzrDirFormat.get_format_description()."""
1891
return "All-in-one format 6"
1893
def get_branch_format(self):
1894
from bzrlib import branch
1895
return branch.BzrBranchFormat4()
1897
def get_converter(self, format=None):
1898
"""See BzrDirFormat.get_converter()."""
1899
# there is one and only one upgrade path here.
1900
return ConvertBzrDir6ToMeta()
1902
def _initialize_for_clone(self, url):
1903
return self.initialize_on_transport(get_transport(url), _cloning=True)
1905
def initialize_on_transport(self, transport, _cloning=False):
1906
"""Format 6 dirs always have working tree, branch and repository.
1908
Except when they are being cloned.
1910
from bzrlib.branch import BzrBranchFormat4
1911
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1912
result = super(BzrDirFormat6, self).initialize_on_transport(transport)
1913
RepositoryFormat6().initialize(result, _internal=True)
1915
branch = BzrBranchFormat4().initialize(result)
1916
result._init_workingtree()
1919
def network_name(self):
1920
return self.get_format_string()
1922
def _open(self, transport):
1923
"""See BzrDirFormat._open."""
1924
return BzrDir6(transport, self)
1926
def __return_repository_format(self):
1927
"""Circular import protection."""
1928
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1929
return RepositoryFormat6()
1930
repository_format = property(__return_repository_format)
1933
class BzrDirMetaFormat1(BzrDirFormat):
1934
"""Bzr meta control format 1
1936
This is the first format with split out working tree, branch and repository
1939
- Format 3 working trees [optional]
1940
- Format 5 branches [optional]
1941
- Format 7 repositories [optional]
1944
_lock_class = lockdir.LockDir
1947
self._workingtree_format = None
1948
self._branch_format = None
1949
self._repository_format = None
1951
def __eq__(self, other):
1952
if other.__class__ is not self.__class__:
1954
if other.repository_format != self.repository_format:
1956
if other.workingtree_format != self.workingtree_format:
1960
def __ne__(self, other):
1961
return not self == other
1963
def get_branch_format(self):
1964
if self._branch_format is None:
1965
from bzrlib.branch import BranchFormat
1966
self._branch_format = BranchFormat.get_default_format()
1967
return self._branch_format
1969
def set_branch_format(self, format):
1970
self._branch_format = format
1972
def require_stacking(self, stack_on=None, possible_transports=None,
1974
"""We have a request to stack, try to ensure the formats support it.
1976
:param stack_on: If supplied, it is the URL to a branch that we want to
1977
stack on. Check to see if that format supports stacking before
1980
# Stacking is desired. requested by the target, but does the place it
1981
# points at support stacking? If it doesn't then we should
1982
# not implicitly upgrade. We check this here.
1983
new_repo_format = None
1984
new_branch_format = None
1986
# a bit of state for get_target_branch so that we don't try to open it
1987
# 2 times, for both repo *and* branch
1988
target = [None, False, None] # target_branch, checked, upgrade anyway
1989
def get_target_branch():
1991
# We've checked, don't check again
1993
if stack_on is None:
1994
# No target format, that means we want to force upgrading
1995
target[:] = [None, True, True]
1998
target_dir = BzrDir.open(stack_on,
1999
possible_transports=possible_transports)
2000
except errors.NotBranchError:
2001
# Nothing there, don't change formats
2002
target[:] = [None, True, False]
2004
except errors.JailBreak:
2005
# JailBreak, JFDI and upgrade anyway
2006
target[:] = [None, True, True]
2009
target_branch = target_dir.open_branch()
2010
except errors.NotBranchError:
2011
# No branch, don't upgrade formats
2012
target[:] = [None, True, False]
2014
target[:] = [target_branch, True, False]
2017
if (not _skip_repo and
2018
not self.repository_format.supports_external_lookups):
2019
# We need to upgrade the Repository.
2020
target_branch, _, do_upgrade = get_target_branch()
2021
if target_branch is None:
2022
# We don't have a target branch, should we upgrade anyway?
2024
# stack_on is inaccessible, JFDI.
2025
# TODO: bad monkey, hard-coded formats...
2026
if self.repository_format.rich_root_data:
2027
new_repo_format = pack_repo.RepositoryFormatKnitPack5RichRoot()
2029
new_repo_format = pack_repo.RepositoryFormatKnitPack5()
2031
# If the target already supports stacking, then we know the
2032
# project is already able to use stacking, so auto-upgrade
2034
new_repo_format = target_branch.repository._format
2035
if not new_repo_format.supports_external_lookups:
2036
# target doesn't, source doesn't, so don't auto upgrade
2038
new_repo_format = None
2039
if new_repo_format is not None:
2040
self.repository_format = new_repo_format
2041
note('Source repository format does not support stacking,'
2042
' using format:\n %s',
2043
new_repo_format.get_format_description())
2045
if not self.get_branch_format().supports_stacking():
2046
# We just checked the repo, now lets check if we need to
2047
# upgrade the branch format
2048
target_branch, _, do_upgrade = get_target_branch()
2049
if target_branch is None:
2051
# TODO: bad monkey, hard-coded formats...
2052
new_branch_format = branch.BzrBranchFormat7()
2054
new_branch_format = target_branch._format
2055
if not new_branch_format.supports_stacking():
2056
new_branch_format = None
2057
if new_branch_format is not None:
2058
# Does support stacking, use its format.
2059
self.set_branch_format(new_branch_format)
2060
note('Source branch format does not support stacking,'
2061
' using format:\n %s',
2062
new_branch_format.get_format_description())
2064
def get_converter(self, format=None):
2065
"""See BzrDirFormat.get_converter()."""
2067
format = BzrDirFormat.get_default_format()
2068
if not isinstance(self, format.__class__):
2069
# converting away from metadir is not implemented
2070
raise NotImplementedError(self.get_converter)
2071
return ConvertMetaToMeta(format)
2073
def get_format_string(self):
2074
"""See BzrDirFormat.get_format_string()."""
2075
return "Bazaar-NG meta directory, format 1\n"
2077
def get_format_description(self):
2078
"""See BzrDirFormat.get_format_description()."""
2079
return "Meta directory format 1"
2081
def network_name(self):
2082
return self.get_format_string()
2084
def _open(self, transport):
2085
"""See BzrDirFormat._open."""
2086
# Create a new format instance because otherwise initialisation of new
2087
# metadirs share the global default format object leading to alias
2089
format = BzrDirMetaFormat1()
2090
self._supply_sub_formats_to(format)
2091
return BzrDirMeta1(transport, format)
2093
def __return_repository_format(self):
2094
"""Circular import protection."""
2095
if self._repository_format:
2096
return self._repository_format
2097
from bzrlib.repository import RepositoryFormat
2098
return RepositoryFormat.get_default_format()
2100
def _set_repository_format(self, value):
2101
"""Allow changing the repository format for metadir formats."""
2102
self._repository_format = value
2104
repository_format = property(__return_repository_format,
2105
_set_repository_format)
2107
def _supply_sub_formats_to(self, other_format):
2108
"""Give other_format the same values for sub formats as this has.
2110
This method is expected to be used when parameterising a
2111
RemoteBzrDirFormat instance with the parameters from a
2112
BzrDirMetaFormat1 instance.
2114
:param other_format: other_format is a format which should be
2115
compatible with whatever sub formats are supported by self.
2118
if getattr(self, '_repository_format', None) is not None:
2119
other_format.repository_format = self.repository_format
2120
if self._branch_format is not None:
2121
other_format._branch_format = self._branch_format
2122
if self._workingtree_format is not None:
2123
other_format.workingtree_format = self.workingtree_format
2125
def __get_workingtree_format(self):
2126
if self._workingtree_format is None:
2127
from bzrlib.workingtree import WorkingTreeFormat
2128
self._workingtree_format = WorkingTreeFormat.get_default_format()
2129
return self._workingtree_format
2131
def __set_workingtree_format(self, wt_format):
2132
self._workingtree_format = wt_format
2134
workingtree_format = property(__get_workingtree_format,
2135
__set_workingtree_format)
2138
# Register bzr formats
2139
BzrDirFormat.register_format(BzrDirFormat4())
2140
BzrDirFormat.register_format(BzrDirFormat5())
2141
BzrDirFormat.register_format(BzrDirFormat6())
2142
__default_format = BzrDirMetaFormat1()
2143
BzrDirFormat.register_format(__default_format)
2144
controldir.ControlDirFormat._default_format = __default_format
2147
class Converter(object):
2148
"""Converts a disk format object from one format to another."""
2150
def convert(self, to_convert, pb):
2151
"""Perform the conversion of to_convert, giving feedback via pb.
2153
:param to_convert: The disk object to convert.
2154
:param pb: a progress bar to use for progress information.
2157
def step(self, message):
2158
"""Update the pb by a step."""
2160
self.pb.update(message, self.count, self.total)
2163
class ConvertBzrDir4To5(Converter):
2164
"""Converts format 4 bzr dirs to format 5."""
2167
super(ConvertBzrDir4To5, self).__init__()
2168
self.converted_revs = set()
2169
self.absent_revisions = set()
2173
def convert(self, to_convert, pb):
2174
"""See Converter.convert()."""
2175
self.bzrdir = to_convert
2177
warnings.warn("pb parameter to convert() is deprecated")
2178
self.pb = ui.ui_factory.nested_progress_bar()
2180
ui.ui_factory.note('starting upgrade from format 4 to 5')
2181
if isinstance(self.bzrdir.transport, local.LocalTransport):
2182
self.bzrdir.get_workingtree_transport(None).delete('stat-cache')
2183
self._convert_to_weaves()
2184
return BzrDir.open(self.bzrdir.user_url)
2188
def _convert_to_weaves(self):
2189
ui.ui_factory.note('note: upgrade may be faster if all store files are ungzipped first')
2192
stat = self.bzrdir.transport.stat('weaves')
2193
if not S_ISDIR(stat.st_mode):
2194
self.bzrdir.transport.delete('weaves')
2195
self.bzrdir.transport.mkdir('weaves')
2196
except errors.NoSuchFile:
2197
self.bzrdir.transport.mkdir('weaves')
2198
# deliberately not a WeaveFile as we want to build it up slowly.
2199
self.inv_weave = Weave('inventory')
2200
# holds in-memory weaves for all files
2201
self.text_weaves = {}
2202
self.bzrdir.transport.delete('branch-format')
2203
self.branch = self.bzrdir.open_branch()
2204
self._convert_working_inv()
2205
rev_history = self.branch.revision_history()
2206
# to_read is a stack holding the revisions we still need to process;
2207
# appending to it adds new highest-priority revisions
2208
self.known_revisions = set(rev_history)
2209
self.to_read = rev_history[-1:]
2211
rev_id = self.to_read.pop()
2212
if (rev_id not in self.revisions
2213
and rev_id not in self.absent_revisions):
2214
self._load_one_rev(rev_id)
2216
to_import = self._make_order()
2217
for i, rev_id in enumerate(to_import):
2218
self.pb.update('converting revision', i, len(to_import))
2219
self._convert_one_rev(rev_id)
2221
self._write_all_weaves()
2222
self._write_all_revs()
2223
ui.ui_factory.note('upgraded to weaves:')
2224
ui.ui_factory.note(' %6d revisions and inventories' % len(self.revisions))
2225
ui.ui_factory.note(' %6d revisions not present' % len(self.absent_revisions))
2226
ui.ui_factory.note(' %6d texts' % self.text_count)
2227
self._cleanup_spare_files_after_format4()
2228
self.branch._transport.put_bytes(
2230
BzrDirFormat5().get_format_string(),
2231
mode=self.bzrdir._get_file_mode())
2233
def _cleanup_spare_files_after_format4(self):
2234
# FIXME working tree upgrade foo.
2235
for n in 'merged-patches', 'pending-merged-patches':
2237
## assert os.path.getsize(p) == 0
2238
self.bzrdir.transport.delete(n)
2239
except errors.NoSuchFile:
2241
self.bzrdir.transport.delete_tree('inventory-store')
2242
self.bzrdir.transport.delete_tree('text-store')
2244
def _convert_working_inv(self):
2245
inv = xml4.serializer_v4.read_inventory(
2246
self.branch._transport.get('inventory'))
2247
new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv, working=True)
2248
self.branch._transport.put_bytes('inventory', new_inv_xml,
2249
mode=self.bzrdir._get_file_mode())
2251
def _write_all_weaves(self):
2252
controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)
2253
weave_transport = self.bzrdir.transport.clone('weaves')
2254
weaves = WeaveStore(weave_transport, prefixed=False)
2255
transaction = WriteTransaction()
2259
for file_id, file_weave in self.text_weaves.items():
2260
self.pb.update('writing weave', i, len(self.text_weaves))
2261
weaves._put_weave(file_id, file_weave, transaction)
2263
self.pb.update('inventory', 0, 1)
2264
controlweaves._put_weave('inventory', self.inv_weave, transaction)
2265
self.pb.update('inventory', 1, 1)
2269
def _write_all_revs(self):
2270
"""Write all revisions out in new form."""
2271
self.bzrdir.transport.delete_tree('revision-store')
2272
self.bzrdir.transport.mkdir('revision-store')
2273
revision_transport = self.bzrdir.transport.clone('revision-store')
2275
from bzrlib.xml5 import serializer_v5
2276
from bzrlib.repofmt.weaverepo import RevisionTextStore
2277
revision_store = RevisionTextStore(revision_transport,
2278
serializer_v5, False, versionedfile.PrefixMapper(),
2279
lambda:True, lambda:True)
2281
for i, rev_id in enumerate(self.converted_revs):
2282
self.pb.update('write revision', i, len(self.converted_revs))
2283
text = serializer_v5.write_revision_to_string(
2284
self.revisions[rev_id])
2286
revision_store.add_lines(key, None, osutils.split_lines(text))
2290
def _load_one_rev(self, rev_id):
2291
"""Load a revision object into memory.
2293
Any parents not either loaded or abandoned get queued to be
2295
self.pb.update('loading revision',
2296
len(self.revisions),
2297
len(self.known_revisions))
2298
if not self.branch.repository.has_revision(rev_id):
2300
ui.ui_factory.note('revision {%s} not present in branch; '
2301
'will be converted as a ghost' %
2303
self.absent_revisions.add(rev_id)
2305
rev = self.branch.repository.get_revision(rev_id)
2306
for parent_id in rev.parent_ids:
2307
self.known_revisions.add(parent_id)
2308
self.to_read.append(parent_id)
2309
self.revisions[rev_id] = rev
2311
def _load_old_inventory(self, rev_id):
2312
f = self.branch.repository.inventory_store.get(rev_id)
2314
old_inv_xml = f.read()
2317
inv = xml4.serializer_v4.read_inventory_from_string(old_inv_xml)
2318
inv.revision_id = rev_id
2319
rev = self.revisions[rev_id]
2322
def _load_updated_inventory(self, rev_id):
2323
inv_xml = self.inv_weave.get_text(rev_id)
2324
inv = xml5.serializer_v5.read_inventory_from_string(inv_xml, rev_id)
2327
def _convert_one_rev(self, rev_id):
2328
"""Convert revision and all referenced objects to new format."""
2329
rev = self.revisions[rev_id]
2330
inv = self._load_old_inventory(rev_id)
2331
present_parents = [p for p in rev.parent_ids
2332
if p not in self.absent_revisions]
2333
self._convert_revision_contents(rev, inv, present_parents)
2334
self._store_new_inv(rev, inv, present_parents)
2335
self.converted_revs.add(rev_id)
2337
def _store_new_inv(self, rev, inv, present_parents):
2338
new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
2339
new_inv_sha1 = sha_string(new_inv_xml)
2340
self.inv_weave.add_lines(rev.revision_id,
2342
new_inv_xml.splitlines(True))
2343
rev.inventory_sha1 = new_inv_sha1
2345
def _convert_revision_contents(self, rev, inv, present_parents):
2346
"""Convert all the files within a revision.
2348
Also upgrade the inventory to refer to the text revision ids."""
2349
rev_id = rev.revision_id
2350
mutter('converting texts of revision {%s}',
2352
parent_invs = map(self._load_updated_inventory, present_parents)
2353
entries = inv.iter_entries()
2355
for path, ie in entries:
2356
self._convert_file_version(rev, ie, parent_invs)
2358
def _convert_file_version(self, rev, ie, parent_invs):
2359
"""Convert one version of one file.
2361
The file needs to be added into the weave if it is a merge
2362
of >=2 parents or if it's changed from its parent.
2364
file_id = ie.file_id
2365
rev_id = rev.revision_id
2366
w = self.text_weaves.get(file_id)
2369
self.text_weaves[file_id] = w
2370
text_changed = False
2371
parent_candiate_entries = ie.parent_candidates(parent_invs)
2372
heads = graph.Graph(self).heads(parent_candiate_entries.keys())
2373
# XXX: Note that this is unordered - and this is tolerable because
2374
# the previous code was also unordered.
2375
previous_entries = dict((head, parent_candiate_entries[head]) for head
2377
self.snapshot_ie(previous_entries, ie, w, rev_id)
2379
def get_parent_map(self, revision_ids):
2380
"""See graph.StackedParentsProvider.get_parent_map"""
2381
return dict((revision_id, self.revisions[revision_id])
2382
for revision_id in revision_ids
2383
if revision_id in self.revisions)
2385
def snapshot_ie(self, previous_revisions, ie, w, rev_id):
2386
# TODO: convert this logic, which is ~= snapshot to
2387
# a call to:. This needs the path figured out. rather than a work_tree
2388
# a v4 revision_tree can be given, or something that looks enough like
2389
# one to give the file content to the entry if it needs it.
2390
# and we need something that looks like a weave store for snapshot to
2392
#ie.snapshot(rev, PATH, previous_revisions, REVISION_TREE, InMemoryWeaveStore(self.text_weaves))
2393
if len(previous_revisions) == 1:
2394
previous_ie = previous_revisions.values()[0]
2395
if ie._unchanged(previous_ie):
2396
ie.revision = previous_ie.revision
2399
f = self.branch.repository._text_store.get(ie.text_id)
2401
file_lines = f.readlines()
2404
w.add_lines(rev_id, previous_revisions, file_lines)
2405
self.text_count += 1
2407
w.add_lines(rev_id, previous_revisions, [])
2408
ie.revision = rev_id
2410
def _make_order(self):
2411
"""Return a suitable order for importing revisions.
2413
The order must be such that an revision is imported after all
2414
its (present) parents.
2416
todo = set(self.revisions.keys())
2417
done = self.absent_revisions.copy()
2420
# scan through looking for a revision whose parents
2422
for rev_id in sorted(list(todo)):
2423
rev = self.revisions[rev_id]
2424
parent_ids = set(rev.parent_ids)
2425
if parent_ids.issubset(done):
2426
# can take this one now
2427
order.append(rev_id)
2433
class ConvertBzrDir5To6(Converter):
2434
"""Converts format 5 bzr dirs to format 6."""
2436
def convert(self, to_convert, pb):
2437
"""See Converter.convert()."""
2438
self.bzrdir = to_convert
2439
pb = ui.ui_factory.nested_progress_bar()
2441
ui.ui_factory.note('starting upgrade from format 5 to 6')
2442
self._convert_to_prefixed()
2443
return BzrDir.open(self.bzrdir.user_url)
2447
def _convert_to_prefixed(self):
2448
from bzrlib.store import TransportStore
2449
self.bzrdir.transport.delete('branch-format')
2450
for store_name in ["weaves", "revision-store"]:
2451
ui.ui_factory.note("adding prefixes to %s" % store_name)
2452
store_transport = self.bzrdir.transport.clone(store_name)
2453
store = TransportStore(store_transport, prefixed=True)
2454
for urlfilename in store_transport.list_dir('.'):
2455
filename = urlutils.unescape(urlfilename)
2456
if (filename.endswith(".weave") or
2457
filename.endswith(".gz") or
2458
filename.endswith(".sig")):
2459
file_id, suffix = os.path.splitext(filename)
2463
new_name = store._mapper.map((file_id,)) + suffix
2464
# FIXME keep track of the dirs made RBC 20060121
2466
store_transport.move(filename, new_name)
2467
except errors.NoSuchFile: # catches missing dirs strangely enough
2468
store_transport.mkdir(osutils.dirname(new_name))
2469
store_transport.move(filename, new_name)
2470
self.bzrdir.transport.put_bytes(
2472
BzrDirFormat6().get_format_string(),
2473
mode=self.bzrdir._get_file_mode())
2476
class ConvertBzrDir6ToMeta(Converter):
2477
"""Converts format 6 bzr dirs to metadirs."""
2479
def convert(self, to_convert, pb):
2480
"""See Converter.convert()."""
2481
from bzrlib.repofmt.weaverepo import RepositoryFormat7
2482
from bzrlib.branch import BzrBranchFormat5
2483
self.bzrdir = to_convert
2484
self.pb = ui.ui_factory.nested_progress_bar()
2486
self.total = 20 # the steps we know about
2487
self.garbage_inventories = []
2488
self.dir_mode = self.bzrdir._get_dir_mode()
2489
self.file_mode = self.bzrdir._get_file_mode()
2491
ui.ui_factory.note('starting upgrade from format 6 to metadir')
2492
self.bzrdir.transport.put_bytes(
2494
"Converting to format 6",
2495
mode=self.file_mode)
2496
# its faster to move specific files around than to open and use the apis...
2497
# first off, nuke ancestry.weave, it was never used.
2499
self.step('Removing ancestry.weave')
2500
self.bzrdir.transport.delete('ancestry.weave')
2501
except errors.NoSuchFile:
2503
# find out whats there
2504
self.step('Finding branch files')
2505
last_revision = self.bzrdir.open_branch().last_revision()
2506
bzrcontents = self.bzrdir.transport.list_dir('.')
2507
for name in bzrcontents:
2508
if name.startswith('basis-inventory.'):
2509
self.garbage_inventories.append(name)
2510
# create new directories for repository, working tree and branch
2511
repository_names = [('inventory.weave', True),
2512
('revision-store', True),
2514
self.step('Upgrading repository ')
2515
self.bzrdir.transport.mkdir('repository', mode=self.dir_mode)
2516
self.make_lock('repository')
2517
# we hard code the formats here because we are converting into
2518
# the meta format. The meta format upgrader can take this to a
2519
# future format within each component.
2520
self.put_format('repository', RepositoryFormat7())
2521
for entry in repository_names:
2522
self.move_entry('repository', entry)
2524
self.step('Upgrading branch ')
2525
self.bzrdir.transport.mkdir('branch', mode=self.dir_mode)
2526
self.make_lock('branch')
2527
self.put_format('branch', BzrBranchFormat5())
2528
branch_files = [('revision-history', True),
2529
('branch-name', True),
2531
for entry in branch_files:
2532
self.move_entry('branch', entry)
2534
checkout_files = [('pending-merges', True),
2535
('inventory', True),
2536
('stat-cache', False)]
2537
# If a mandatory checkout file is not present, the branch does not have
2538
# a functional checkout. Do not create a checkout in the converted
2540
for name, mandatory in checkout_files:
2541
if mandatory and name not in bzrcontents:
2542
has_checkout = False
2546
if not has_checkout:
2547
ui.ui_factory.note('No working tree.')
2548
# If some checkout files are there, we may as well get rid of them.
2549
for name, mandatory in checkout_files:
2550
if name in bzrcontents:
2551
self.bzrdir.transport.delete(name)
2553
from bzrlib.workingtree import WorkingTreeFormat3
2554
self.step('Upgrading working tree')
2555
self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
2556
self.make_lock('checkout')
2558
'checkout', WorkingTreeFormat3())
2559
self.bzrdir.transport.delete_multi(
2560
self.garbage_inventories, self.pb)
2561
for entry in checkout_files:
2562
self.move_entry('checkout', entry)
2563
if last_revision is not None:
2564
self.bzrdir.transport.put_bytes(
2565
'checkout/last-revision', last_revision)
2566
self.bzrdir.transport.put_bytes(
2568
BzrDirMetaFormat1().get_format_string(),
2569
mode=self.file_mode)
2571
return BzrDir.open(self.bzrdir.user_url)
2573
def make_lock(self, name):
2574
"""Make a lock for the new control dir name."""
2575
self.step('Make %s lock' % name)
2576
ld = lockdir.LockDir(self.bzrdir.transport,
2578
file_modebits=self.file_mode,
2579
dir_modebits=self.dir_mode)
2582
def move_entry(self, new_dir, entry):
2583
"""Move then entry name into new_dir."""
2585
mandatory = entry[1]
2586
self.step('Moving %s' % name)
2588
self.bzrdir.transport.move(name, '%s/%s' % (new_dir, name))
2589
except errors.NoSuchFile:
2593
def put_format(self, dirname, format):
2594
self.bzrdir.transport.put_bytes('%s/format' % dirname,
2595
format.get_format_string(),
2599
class ConvertMetaToMeta(Converter):
2600
"""Converts the components of metadirs."""
2602
def __init__(self, target_format):
2603
"""Create a metadir to metadir converter.
2605
:param target_format: The final metadir format that is desired.
2607
self.target_format = target_format
2609
def convert(self, to_convert, pb):
2610
"""See Converter.convert()."""
2611
self.bzrdir = to_convert
2612
self.pb = ui.ui_factory.nested_progress_bar()
2615
self.step('checking repository format')
2617
repo = self.bzrdir.open_repository()
2618
except errors.NoRepositoryPresent:
2621
if not isinstance(repo._format, self.target_format.repository_format.__class__):
2622
from bzrlib.repository import CopyConverter
2623
ui.ui_factory.note('starting repository conversion')
2624
converter = CopyConverter(self.target_format.repository_format)
2625
converter.convert(repo, pb)
2626
for branch in self.bzrdir.list_branches():
2627
# TODO: conversions of Branch and Tree should be done by
2628
# InterXFormat lookups/some sort of registry.
2629
# Avoid circular imports
2630
from bzrlib import branch as _mod_branch
2631
old = branch._format.__class__
2632
new = self.target_format.get_branch_format().__class__
2634
if (old == _mod_branch.BzrBranchFormat5 and
2635
new in (_mod_branch.BzrBranchFormat6,
2636
_mod_branch.BzrBranchFormat7,
2637
_mod_branch.BzrBranchFormat8)):
2638
branch_converter = _mod_branch.Converter5to6()
2639
elif (old == _mod_branch.BzrBranchFormat6 and
2640
new in (_mod_branch.BzrBranchFormat7,
2641
_mod_branch.BzrBranchFormat8)):
2642
branch_converter = _mod_branch.Converter6to7()
2643
elif (old == _mod_branch.BzrBranchFormat7 and
2644
new is _mod_branch.BzrBranchFormat8):
2645
branch_converter = _mod_branch.Converter7to8()
2647
raise errors.BadConversionTarget("No converter", new,
2649
branch_converter.convert(branch)
2650
branch = self.bzrdir.open_branch()
2651
old = branch._format.__class__
2653
tree = self.bzrdir.open_workingtree(recommend_upgrade=False)
2654
except (errors.NoWorkingTree, errors.NotLocalUrl):
2657
# TODO: conversions of Branch and Tree should be done by
2658
# InterXFormat lookups
2659
if (isinstance(tree, workingtree.WorkingTree3) and
2660
not isinstance(tree, workingtree_4.DirStateWorkingTree) and
2661
isinstance(self.target_format.workingtree_format,
2662
workingtree_4.DirStateWorkingTreeFormat)):
2663
workingtree_4.Converter3to4().convert(tree)
2664
if (isinstance(tree, workingtree_4.DirStateWorkingTree) and
2665
not isinstance(tree, workingtree_4.WorkingTree5) and
2666
isinstance(self.target_format.workingtree_format,
2667
workingtree_4.WorkingTreeFormat5)):
2668
workingtree_4.Converter4to5().convert(tree)
2669
if (isinstance(tree, workingtree_4.DirStateWorkingTree) and
2670
not isinstance(tree, workingtree_4.WorkingTree6) and
2671
isinstance(self.target_format.workingtree_format,
2672
workingtree_4.WorkingTreeFormat6)):
2673
workingtree_4.Converter4or5to6().convert(tree)
2678
# This is not in remote.py because it's relatively small, and needs to be
2679
# registered. Putting it in remote.py creates a circular import problem.
2680
# we can make it a lazy object if the control formats is turned into something
2682
class RemoteBzrDirFormat(BzrDirMetaFormat1):
2683
"""Format representing bzrdirs accessed via a smart server"""
2685
supports_workingtrees = False
2688
BzrDirMetaFormat1.__init__(self)
2689
# XXX: It's a bit ugly that the network name is here, because we'd
2690
# like to believe that format objects are stateless or at least
2691
# immutable, However, we do at least avoid mutating the name after
2692
# it's returned. See <https://bugs.launchpad.net/bzr/+bug/504102>
2693
self._network_name = None
2696
return "%s(_network_name=%r)" % (self.__class__.__name__,
2699
def get_format_description(self):
2700
if self._network_name:
2701
real_format = controldir.network_format_registry.get(self._network_name)
2702
return 'Remote: ' + real_format.get_format_description()
2703
return 'bzr remote bzrdir'
2705
def get_format_string(self):
2706
raise NotImplementedError(self.get_format_string)
2708
def network_name(self):
2709
if self._network_name:
2710
return self._network_name
2712
raise AssertionError("No network name set.")
2714
def initialize_on_transport(self, transport):
2716
# hand off the request to the smart server
2717
client_medium = transport.get_smart_medium()
2718
except errors.NoSmartMedium:
2719
# TODO: lookup the local format from a server hint.
2720
local_dir_format = BzrDirMetaFormat1()
2721
return local_dir_format.initialize_on_transport(transport)
2722
client = _SmartClient(client_medium)
2723
path = client.remote_path_from_transport(transport)
2725
response = client.call('BzrDirFormat.initialize', path)
2726
except errors.ErrorFromSmartServer, err:
2727
remote._translate_error(err, path=path)
2728
if response[0] != 'ok':
2729
raise errors.SmartProtocolError('unexpected response code %s' % (response,))
2730
format = RemoteBzrDirFormat()
2731
self._supply_sub_formats_to(format)
2732
return remote.RemoteBzrDir(transport, format)
2734
def parse_NoneTrueFalse(self, arg):
2741
raise AssertionError("invalid arg %r" % arg)
2743
def _serialize_NoneTrueFalse(self, arg):
2750
def _serialize_NoneString(self, arg):
2753
def initialize_on_transport_ex(self, transport, use_existing_dir=False,
2754
create_prefix=False, force_new_repo=False, stacked_on=None,
2755
stack_on_pwd=None, repo_format_name=None, make_working_trees=None,
2758
# hand off the request to the smart server
2759
client_medium = transport.get_smart_medium()
2760
except errors.NoSmartMedium:
2763
# Decline to open it if the server doesn't support our required
2764
# version (3) so that the VFS-based transport will do it.
2765
if client_medium.should_probe():
2767
server_version = client_medium.protocol_version()
2768
if server_version != '2':
2772
except errors.SmartProtocolError:
2773
# Apparently there's no usable smart server there, even though
2774
# the medium supports the smart protocol.
2779
client = _SmartClient(client_medium)
2780
path = client.remote_path_from_transport(transport)
2781
if client_medium._is_remote_before((1, 16)):
2784
# TODO: lookup the local format from a server hint.
2785
local_dir_format = BzrDirMetaFormat1()
2786
self._supply_sub_formats_to(local_dir_format)
2787
return local_dir_format.initialize_on_transport_ex(transport,
2788
use_existing_dir=use_existing_dir, create_prefix=create_prefix,
2789
force_new_repo=force_new_repo, stacked_on=stacked_on,
2790
stack_on_pwd=stack_on_pwd, repo_format_name=repo_format_name,
2791
make_working_trees=make_working_trees, shared_repo=shared_repo,
2793
return self._initialize_on_transport_ex_rpc(client, path, transport,
2794
use_existing_dir, create_prefix, force_new_repo, stacked_on,
2795
stack_on_pwd, repo_format_name, make_working_trees, shared_repo)
2797
def _initialize_on_transport_ex_rpc(self, client, path, transport,
2798
use_existing_dir, create_prefix, force_new_repo, stacked_on,
2799
stack_on_pwd, repo_format_name, make_working_trees, shared_repo):
2801
args.append(self._serialize_NoneTrueFalse(use_existing_dir))
2802
args.append(self._serialize_NoneTrueFalse(create_prefix))
2803
args.append(self._serialize_NoneTrueFalse(force_new_repo))
2804
args.append(self._serialize_NoneString(stacked_on))
2805
# stack_on_pwd is often/usually our transport
2808
stack_on_pwd = transport.relpath(stack_on_pwd)
2809
if not stack_on_pwd:
2811
except errors.PathNotChild:
2813
args.append(self._serialize_NoneString(stack_on_pwd))
2814
args.append(self._serialize_NoneString(repo_format_name))
2815
args.append(self._serialize_NoneTrueFalse(make_working_trees))
2816
args.append(self._serialize_NoneTrueFalse(shared_repo))
2817
request_network_name = self._network_name or \
2818
BzrDirFormat.get_default_format().network_name()
2820
response = client.call('BzrDirFormat.initialize_ex_1.16',
2821
request_network_name, path, *args)
2822
except errors.UnknownSmartMethod:
2823
client._medium._remember_remote_is_before((1,16))
2824
local_dir_format = BzrDirMetaFormat1()
2825
self._supply_sub_formats_to(local_dir_format)
2826
return local_dir_format.initialize_on_transport_ex(transport,
2827
use_existing_dir=use_existing_dir, create_prefix=create_prefix,
2828
force_new_repo=force_new_repo, stacked_on=stacked_on,
2829
stack_on_pwd=stack_on_pwd, repo_format_name=repo_format_name,
2830
make_working_trees=make_working_trees, shared_repo=shared_repo,
2832
except errors.ErrorFromSmartServer, err:
2833
remote._translate_error(err, path=path)
2834
repo_path = response[0]
2835
bzrdir_name = response[6]
2836
require_stacking = response[7]
2837
require_stacking = self.parse_NoneTrueFalse(require_stacking)
2838
format = RemoteBzrDirFormat()
2839
format._network_name = bzrdir_name
2840
self._supply_sub_formats_to(format)
2841
bzrdir = remote.RemoteBzrDir(transport, format, _client=client)
2843
repo_format = remote.response_tuple_to_repo_format(response[1:])
2844
if repo_path == '.':
2847
repo_bzrdir_format = RemoteBzrDirFormat()
2848
repo_bzrdir_format._network_name = response[5]
2849
repo_bzr = remote.RemoteBzrDir(transport.clone(repo_path),
2853
final_stack = response[8] or None
2854
final_stack_pwd = response[9] or None
2856
final_stack_pwd = urlutils.join(
2857
transport.base, final_stack_pwd)
2858
remote_repo = remote.RemoteRepository(repo_bzr, repo_format)
2859
if len(response) > 10:
2860
# Updated server verb that locks remotely.
2861
repo_lock_token = response[10] or None
2862
remote_repo.lock_write(repo_lock_token, _skip_rpc=True)
2864
remote_repo.dont_leave_lock_in_place()
2866
remote_repo.lock_write()
2867
policy = UseExistingRepository(remote_repo, final_stack,
2868
final_stack_pwd, require_stacking)
2869
policy.acquire_repository()
2873
bzrdir._format.set_branch_format(self.get_branch_format())
2874
if require_stacking:
2875
# The repo has already been created, but we need to make sure that
2876
# we'll make a stackable branch.
2877
bzrdir._format.require_stacking(_skip_repo=True)
2878
return remote_repo, bzrdir, require_stacking, policy
2880
def _open(self, transport):
2881
return remote.RemoteBzrDir(transport, self)
2883
def __eq__(self, other):
2884
if not isinstance(other, RemoteBzrDirFormat):
2886
return self.get_format_description() == other.get_format_description()
2888
def __return_repository_format(self):
2889
# Always return a RemoteRepositoryFormat object, but if a specific bzr
2890
# repository format has been asked for, tell the RemoteRepositoryFormat
2891
# that it should use that for init() etc.
2892
result = remote.RemoteRepositoryFormat()
2893
custom_format = getattr(self, '_repository_format', None)
2895
if isinstance(custom_format, remote.RemoteRepositoryFormat):
2896
return custom_format
2898
# We will use the custom format to create repositories over the
2899
# wire; expose its details like rich_root_data for code to
2901
result._custom_format = custom_format
2904
def get_branch_format(self):
2905
result = BzrDirMetaFormat1.get_branch_format(self)
2906
if not isinstance(result, remote.RemoteBranchFormat):
2907
new_result = remote.RemoteBranchFormat()
2908
new_result._custom_format = result
2910
self.set_branch_format(new_result)
2914
repository_format = property(__return_repository_format,
2915
BzrDirMetaFormat1._set_repository_format) #.im_func)
2918
controldir.ControlDirFormat.register_server_prober(RemoteBzrProber)
2921
class RepositoryAcquisitionPolicy(object):
2922
"""Abstract base class for repository acquisition policies.
2924
A repository acquisition policy decides how a BzrDir acquires a repository
2925
for a branch that is being created. The most basic policy decision is
2926
whether to create a new repository or use an existing one.
2928
def __init__(self, stack_on, stack_on_pwd, require_stacking):
2931
:param stack_on: A location to stack on
2932
:param stack_on_pwd: If stack_on is relative, the location it is
2934
:param require_stacking: If True, it is a failure to not stack.
2936
self._stack_on = stack_on
2937
self._stack_on_pwd = stack_on_pwd
2938
self._require_stacking = require_stacking
2940
def configure_branch(self, branch):
2941
"""Apply any configuration data from this policy to the branch.
2943
Default implementation sets repository stacking.
2945
if self._stack_on is None:
2947
if self._stack_on_pwd is None:
2948
stack_on = self._stack_on
2951
stack_on = urlutils.rebase_url(self._stack_on,
2954
except errors.InvalidRebaseURLs:
2955
stack_on = self._get_full_stack_on()
2957
branch.set_stacked_on_url(stack_on)
2958
except (errors.UnstackableBranchFormat,
2959
errors.UnstackableRepositoryFormat):
2960
if self._require_stacking:
2963
def requires_stacking(self):
2964
"""Return True if this policy requires stacking."""
2965
return self._stack_on is not None and self._require_stacking
2967
def _get_full_stack_on(self):
2968
"""Get a fully-qualified URL for the stack_on location."""
2969
if self._stack_on is None:
2971
if self._stack_on_pwd is None:
2972
return self._stack_on
2974
return urlutils.join(self._stack_on_pwd, self._stack_on)
2976
def _add_fallback(self, repository, possible_transports=None):
2977
"""Add a fallback to the supplied repository, if stacking is set."""
2978
stack_on = self._get_full_stack_on()
2979
if stack_on is None:
2982
stacked_dir = BzrDir.open(stack_on,
2983
possible_transports=possible_transports)
2984
except errors.JailBreak:
2985
# We keep the stacking details, but we are in the server code so
2986
# actually stacking is not needed.
2989
stacked_repo = stacked_dir.open_branch().repository
2990
except errors.NotBranchError:
2991
stacked_repo = stacked_dir.open_repository()
2993
repository.add_fallback_repository(stacked_repo)
2994
except errors.UnstackableRepositoryFormat:
2995
if self._require_stacking:
2998
self._require_stacking = True
3000
def acquire_repository(self, make_working_trees=None, shared=False):
3001
"""Acquire a repository for this bzrdir.
3003
Implementations may create a new repository or use a pre-exising
3005
:param make_working_trees: If creating a repository, set
3006
make_working_trees to this value (if non-None)
3007
:param shared: If creating a repository, make it shared if True
3008
:return: A repository, is_new_flag (True if the repository was
3011
raise NotImplemented(RepositoryAcquisitionPolicy.acquire_repository)
3014
class CreateRepository(RepositoryAcquisitionPolicy):
3015
"""A policy of creating a new repository"""
3017
def __init__(self, bzrdir, stack_on=None, stack_on_pwd=None,
3018
require_stacking=False):
3021
:param bzrdir: The bzrdir to create the repository on.
3022
:param stack_on: A location to stack on
3023
:param stack_on_pwd: If stack_on is relative, the location it is
3026
RepositoryAcquisitionPolicy.__init__(self, stack_on, stack_on_pwd,
3028
self._bzrdir = bzrdir
3030
def acquire_repository(self, make_working_trees=None, shared=False):
3031
"""Implementation of RepositoryAcquisitionPolicy.acquire_repository
3033
Creates the desired repository in the bzrdir we already have.
3035
stack_on = self._get_full_stack_on()
3037
format = self._bzrdir._format
3038
format.require_stacking(stack_on=stack_on,
3039
possible_transports=[self._bzrdir.root_transport])
3040
if not self._require_stacking:
3041
# We have picked up automatic stacking somewhere.
3042
note('Using default stacking branch %s at %s', self._stack_on,
3044
repository = self._bzrdir.create_repository(shared=shared)
3045
self._add_fallback(repository,
3046
possible_transports=[self._bzrdir.transport])
3047
if make_working_trees is not None:
3048
repository.set_make_working_trees(make_working_trees)
3049
return repository, True
3052
class UseExistingRepository(RepositoryAcquisitionPolicy):
3053
"""A policy of reusing an existing repository"""
3055
def __init__(self, repository, stack_on=None, stack_on_pwd=None,
3056
require_stacking=False):
3059
:param repository: The repository to use.
3060
:param stack_on: A location to stack on
3061
:param stack_on_pwd: If stack_on is relative, the location it is
3064
RepositoryAcquisitionPolicy.__init__(self, stack_on, stack_on_pwd,
3066
self._repository = repository
3068
def acquire_repository(self, make_working_trees=None, shared=False):
3069
"""Implementation of RepositoryAcquisitionPolicy.acquire_repository
3071
Returns an existing repository to use.
3073
self._add_fallback(self._repository,
3074
possible_transports=[self._repository.bzrdir.transport])
3075
return self._repository, False
3078
def register_metadir(registry, key,
3079
repository_format, help, native=True, deprecated=False,
3085
"""Register a metadir subformat.
3087
These all use a BzrDirMetaFormat1 bzrdir, but can be parameterized
3088
by the Repository/Branch/WorkingTreeformats.
3090
:param repository_format: The fully-qualified repository format class
3092
:param branch_format: Fully-qualified branch format class name as
3094
:param tree_format: Fully-qualified tree format class name as
3097
# This should be expanded to support setting WorkingTree and Branch
3098
# formats, once BzrDirMetaFormat1 supports that.
3099
def _load(full_name):
3100
mod_name, factory_name = full_name.rsplit('.', 1)
3102
factory = pyutils.get_named_object(mod_name, factory_name)
3103
except ImportError, e:
3104
raise ImportError('failed to load %s: %s' % (full_name, e))
3105
except AttributeError:
3106
raise AttributeError('no factory %s in module %r'
3107
% (full_name, sys.modules[mod_name]))
3111
bd = BzrDirMetaFormat1()
3112
if branch_format is not None:
3113
bd.set_branch_format(_load(branch_format))
3114
if tree_format is not None:
3115
bd.workingtree_format = _load(tree_format)
3116
if repository_format is not None:
3117
bd.repository_format = _load(repository_format)
3119
registry.register(key, helper, help, native, deprecated, hidden,
3120
experimental, alias)
3122
# The pre-0.8 formats have their repository format network name registered in
3123
# repository.py. MetaDir formats have their repository format network name
3124
# inferred from their disk format string.
3125
controldir.format_registry.register('weave', BzrDirFormat6,
3126
'Pre-0.8 format. Slower than knit and does not'
3127
' support checkouts or shared repositories.',
3130
register_metadir(controldir.format_registry, 'metaweave',
3131
'bzrlib.repofmt.weaverepo.RepositoryFormat7',
3132
'Transitional format in 0.8. Slower than knit.',
3133
branch_format='bzrlib.branch.BzrBranchFormat5',
3134
tree_format='bzrlib.workingtree.WorkingTreeFormat3',
3137
register_metadir(controldir.format_registry, 'knit',
3138
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
3139
'Format using knits. Recommended for interoperation with bzr <= 0.14.',
3140
branch_format='bzrlib.branch.BzrBranchFormat5',
3141
tree_format='bzrlib.workingtree.WorkingTreeFormat3',
3144
register_metadir(controldir.format_registry, 'dirstate',
3145
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
3146
help='New in 0.15: Fast local operations. Compatible with bzr 0.8 and '
3147
'above when accessed over the network.',
3148
branch_format='bzrlib.branch.BzrBranchFormat5',
3149
# this uses bzrlib.workingtree.WorkingTreeFormat4 because importing
3150
# directly from workingtree_4 triggers a circular import.
3151
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3154
register_metadir(controldir.format_registry, 'dirstate-tags',
3155
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
3156
help='New in 0.15: Fast local operations and improved scaling for '
3157
'network operations. Additionally adds support for tags.'
3158
' Incompatible with bzr < 0.15.',
3159
branch_format='bzrlib.branch.BzrBranchFormat6',
3160
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3163
register_metadir(controldir.format_registry, 'rich-root',
3164
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit4',
3165
help='New in 1.0. Better handling of tree roots. Incompatible with'
3167
branch_format='bzrlib.branch.BzrBranchFormat6',
3168
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3171
register_metadir(controldir.format_registry, 'dirstate-with-subtree',
3172
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
3173
help='New in 0.15: Fast local operations and improved scaling for '
3174
'network operations. Additionally adds support for versioning nested '
3175
'bzr branches. Incompatible with bzr < 0.15.',
3176
branch_format='bzrlib.branch.BzrBranchFormat6',
3177
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3181
register_metadir(controldir.format_registry, 'pack-0.92',
3182
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack1',
3183
help='New in 0.92: Pack-based format with data compatible with '
3184
'dirstate-tags format repositories. Interoperates with '
3185
'bzr repositories before 0.92 but cannot be read by bzr < 0.92. '
3187
branch_format='bzrlib.branch.BzrBranchFormat6',
3188
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3190
register_metadir(controldir.format_registry, 'pack-0.92-subtree',
3191
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack3',
3192
help='New in 0.92: Pack-based format with data compatible with '
3193
'dirstate-with-subtree format repositories. Interoperates with '
3194
'bzr repositories before 0.92 but cannot be read by bzr < 0.92. '
3196
branch_format='bzrlib.branch.BzrBranchFormat6',
3197
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3201
register_metadir(controldir.format_registry, 'rich-root-pack',
3202
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack4',
3203
help='New in 1.0: A variant of pack-0.92 that supports rich-root data '
3204
'(needed for bzr-svn and bzr-git).',
3205
branch_format='bzrlib.branch.BzrBranchFormat6',
3206
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3209
register_metadir(controldir.format_registry, '1.6',
3210
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack5',
3211
help='A format that allows a branch to indicate that there is another '
3212
'(stacked) repository that should be used to access data that is '
3213
'not present locally.',
3214
branch_format='bzrlib.branch.BzrBranchFormat7',
3215
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3218
register_metadir(controldir.format_registry, '1.6.1-rich-root',
3219
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack5RichRoot',
3220
help='A variant of 1.6 that supports rich-root data '
3221
'(needed for bzr-svn and bzr-git).',
3222
branch_format='bzrlib.branch.BzrBranchFormat7',
3223
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3226
register_metadir(controldir.format_registry, '1.9',
3227
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack6',
3228
help='A repository format using B+tree indexes. These indexes '
3229
'are smaller in size, have smarter caching and provide faster '
3230
'performance for most operations.',
3231
branch_format='bzrlib.branch.BzrBranchFormat7',
3232
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3235
register_metadir(controldir.format_registry, '1.9-rich-root',
3236
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack6RichRoot',
3237
help='A variant of 1.9 that supports rich-root data '
3238
'(needed for bzr-svn and bzr-git).',
3239
branch_format='bzrlib.branch.BzrBranchFormat7',
3240
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3243
register_metadir(controldir.format_registry, '1.14',
3244
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack6',
3245
help='A working-tree format that supports content filtering.',
3246
branch_format='bzrlib.branch.BzrBranchFormat7',
3247
tree_format='bzrlib.workingtree.WorkingTreeFormat5',
3249
register_metadir(controldir.format_registry, '1.14-rich-root',
3250
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack6RichRoot',
3251
help='A variant of 1.14 that supports rich-root data '
3252
'(needed for bzr-svn and bzr-git).',
3253
branch_format='bzrlib.branch.BzrBranchFormat7',
3254
tree_format='bzrlib.workingtree.WorkingTreeFormat5',
3256
# The following un-numbered 'development' formats should always just be aliases.
3257
register_metadir(controldir.format_registry, 'development-rich-root',
3258
'bzrlib.repofmt.groupcompress_repo.RepositoryFormatCHK1',
3259
help='Current development format. Supports rich roots. Can convert data '
3260
'to and from rich-root-pack (and anything compatible with '
3261
'rich-root-pack) format repositories. Repositories and branches in '
3262
'this format can only be read by bzr.dev. Please read '
3263
'http://doc.bazaar.canonical.com/latest/developers/development-repo.html '
3265
branch_format='bzrlib.branch.BzrBranchFormat7',
3266
tree_format='bzrlib.workingtree.WorkingTreeFormat6',
3271
register_metadir(controldir.format_registry, 'development5-subtree',
3272
'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment2Subtree',
3273
help='Development format, subtree variant. Can convert data to and '
3274
'from pack-0.92-subtree (and anything compatible with '
3275
'pack-0.92-subtree) format repositories. Repositories and branches in '
3276
'this format can only be read by bzr.dev. Please read '
3277
'http://doc.bazaar.canonical.com/latest/developers/development-repo.html '
3279
branch_format='bzrlib.branch.BzrBranchFormat7',
3280
tree_format='bzrlib.workingtree.WorkingTreeFormat6',
3287
register_metadir(controldir.format_registry, 'development-subtree',
3288
'bzrlib.repofmt.groupcompress_repo.RepositoryFormat2aSubtree',
3289
help='Current development format, subtree variant. Can convert data to and '
3290
'from pack-0.92-subtree (and anything compatible with '
3291
'pack-0.92-subtree) format repositories. Repositories and branches in '
3292
'this format can only be read by bzr.dev. Please read '
3293
'http://doc.bazaar.canonical.com/latest/developers/development-repo.html '
3295
branch_format='bzrlib.branch.BzrBranchFormat7',
3296
tree_format='bzrlib.workingtree.WorkingTreeFormat6',
3299
alias=False, # Restore to being an alias when an actual development subtree format is added
3300
# This current non-alias status is simply because we did not introduce a
3301
# chk based subtree format.
3304
# And the development formats above will have aliased one of the following:
3305
register_metadir(controldir.format_registry, 'development6-rich-root',
3306
'bzrlib.repofmt.groupcompress_repo.RepositoryFormatCHK1',
3307
help='pack-1.9 with 255-way hashed CHK inv, group compress, rich roots '
3309
'http://doc.bazaar.canonical.com/latest/developers/development-repo.html '
3311
branch_format='bzrlib.branch.BzrBranchFormat7',
3312
tree_format='bzrlib.workingtree.WorkingTreeFormat6',
3317
register_metadir(controldir.format_registry, 'development7-rich-root',
3318
'bzrlib.repofmt.groupcompress_repo.RepositoryFormatCHK2',
3319
help='pack-1.9 with 255-way hashed CHK inv, bencode revision, group compress, '
3320
'rich roots. Please read '
3321
'http://doc.bazaar.canonical.com/latest/developers/development-repo.html '
3323
branch_format='bzrlib.branch.BzrBranchFormat7',
3324
tree_format='bzrlib.workingtree.WorkingTreeFormat6',
3329
register_metadir(controldir.format_registry, '2a',
3330
'bzrlib.repofmt.groupcompress_repo.RepositoryFormat2a',
3331
help='First format for bzr 2.0 series.\n'
3332
'Uses group-compress storage.\n'
3333
'Provides rich roots which are a one-way transition.\n',
3334
# 'storage in packs, 255-way hashed CHK inventory, bencode revision, group compress, '
3335
# 'rich roots. Supported by bzr 1.16 and later.',
3336
branch_format='bzrlib.branch.BzrBranchFormat7',
3337
tree_format='bzrlib.workingtree.WorkingTreeFormat6',
3341
# The following format should be an alias for the rich root equivalent
3342
# of the default format
3343
register_metadir(controldir.format_registry, 'default-rich-root',
3344
'bzrlib.repofmt.groupcompress_repo.RepositoryFormat2a',
3345
branch_format='bzrlib.branch.BzrBranchFormat7',
3346
tree_format='bzrlib.workingtree.WorkingTreeFormat6',
3351
# The current format that is made on 'bzr init'.
3352
format_name = config.GlobalConfig().get_user_option('default_format')
3353
if format_name is None:
3354
controldir.format_registry.set_default('2a')
3356
controldir.format_registry.set_default(format_name)
3358
# XXX 2010-08-20 JRV: There is still a lot of code relying on
3359
# bzrlib.bzrdir.format_registry existing. When BzrDir.create/BzrDir.open/etc
3360
# get changed to ControlDir.create/ControlDir.open/etc this should be removed.
3361
format_registry = controldir.format_registry