1
# Copyright (C) 2005, 2006, 2007, 2008, 2009 Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
"""BzrDir logic. The BzrDir is the basic control directory used by bzr.
19
At format 7 this was split out into Branch, Repository and Checkout control
22
Note: This module has a lot of ``open`` functions/methods that return
23
references to in-memory objects. As a rule, there are no matching ``close``
24
methods. To free any associated resources, simply stop referencing the
28
# TODO: Move old formats into a plugin to make this file smaller.
33
from bzrlib.lazy_import import lazy_import
34
lazy_import(globals(), """
35
from stat import S_ISDIR
47
revision as _mod_revision,
57
from bzrlib.osutils import (
60
from bzrlib.smart.client import _SmartClient
61
from bzrlib.store.versioned import WeaveStore
62
from bzrlib.transactions import WriteTransaction
63
from bzrlib.transport import (
64
do_catching_redirections,
67
remote as remote_transport,
69
from bzrlib.weave import Weave
72
from bzrlib.trace import (
85
"""A .bzr control diretory.
87
BzrDir instances let you create or open any of the things that can be
88
found within .bzr - checkouts, branches and repositories.
91
the transport which this bzr dir is rooted at (i.e. file:///.../.bzr/)
93
a transport connected to the directory this bzr was opened from
94
(i.e. the parent directory holding the .bzr directory).
96
Everything in the bzrdir should have the same file permissions.
98
:cvar hooks: An instance of BzrDirHooks.
101
def break_lock(self):
102
"""Invoke break_lock on the first object in the bzrdir.
104
If there is a tree, the tree is opened and break_lock() called.
105
Otherwise, branch is tried, and finally repository.
107
# XXX: This seems more like a UI function than something that really
108
# belongs in this class.
110
thing_to_unlock = self.open_workingtree()
111
except (errors.NotLocalUrl, errors.NoWorkingTree):
113
thing_to_unlock = self.open_branch()
114
except errors.NotBranchError:
116
thing_to_unlock = self.open_repository()
117
except errors.NoRepositoryPresent:
119
thing_to_unlock.break_lock()
121
def can_convert_format(self):
122
"""Return true if this bzrdir is one whose format we can convert from."""
125
def check_conversion_target(self, target_format):
126
target_repo_format = target_format.repository_format
127
source_repo_format = self._format.repository_format
128
source_repo_format.check_conversion_target(target_repo_format)
131
def _check_supported(format, allow_unsupported,
132
recommend_upgrade=True,
134
"""Give an error or warning on old formats.
136
:param format: may be any kind of format - workingtree, branch,
139
:param allow_unsupported: If true, allow opening
140
formats that are strongly deprecated, and which may
141
have limited functionality.
143
:param recommend_upgrade: If true (default), warn
144
the user through the ui object that they may wish
145
to upgrade the object.
147
# TODO: perhaps move this into a base Format class; it's not BzrDir
148
# specific. mbp 20070323
149
if not allow_unsupported and not format.is_supported():
150
# see open_downlevel to open legacy branches.
151
raise errors.UnsupportedFormatError(format=format)
152
if recommend_upgrade \
153
and getattr(format, 'upgrade_recommended', False):
154
ui.ui_factory.recommend_upgrade(
155
format.get_format_description(),
158
def clone(self, url, revision_id=None, force_new_repo=False,
159
preserve_stacking=False):
160
"""Clone this bzrdir and its contents to url verbatim.
162
:param url: The url create the clone at. If url's last component does
163
not exist, it will be created.
164
:param revision_id: The tip revision-id to use for any branch or
165
working tree. If not None, then the clone operation may tune
166
itself to download less data.
167
:param force_new_repo: Do not use a shared repository for the target
168
even if one is available.
169
:param preserve_stacking: When cloning a stacked branch, stack the
170
new branch on top of the other branch's stacked-on branch.
172
return self.clone_on_transport(get_transport(url),
173
revision_id=revision_id,
174
force_new_repo=force_new_repo,
175
preserve_stacking=preserve_stacking)
177
def clone_on_transport(self, transport, revision_id=None,
178
force_new_repo=False, preserve_stacking=False,
180
"""Clone this bzrdir and its contents to transport verbatim.
182
:param transport: The transport for the location to produce the clone
183
at. If the target directory does not exist, it will be created.
184
:param revision_id: The tip revision-id to use for any branch or
185
working tree. If not None, then the clone operation may tune
186
itself to download less data.
187
:param force_new_repo: Do not use a shared repository for the target,
188
even if one is available.
189
:param preserve_stacking: When cloning a stacked branch, stack the
190
new branch on top of the other branch's stacked-on branch.
192
transport.ensure_base()
193
require_stacking = (stacked_on is not None)
194
format = self.cloning_metadir(require_stacking)
195
result = format.initialize_on_transport(transport)
196
repository_policy = None
198
local_repo = self.find_repository()
199
except errors.NoRepositoryPresent:
202
local_branch = self.open_branch()
203
except errors.NotBranchError:
206
# enable fallbacks when branch is not a branch reference
207
if local_branch.repository.has_same_location(local_repo):
208
local_repo = local_branch.repository
209
if preserve_stacking:
211
stacked_on = local_branch.get_stacked_on_url()
212
except (errors.UnstackableBranchFormat,
213
errors.UnstackableRepositoryFormat,
218
# may need to copy content in
219
repository_policy = result.determine_repository_policy(
220
force_new_repo, stacked_on, self.root_transport.base,
221
require_stacking=require_stacking)
222
make_working_trees = local_repo.make_working_trees()
223
result_repo, is_new_repo = repository_policy.acquire_repository(
224
make_working_trees, local_repo.is_shared())
225
if not require_stacking and repository_policy._require_stacking:
226
require_stacking = True
227
result._format.require_stacking()
228
if is_new_repo and not require_stacking and revision_id is not None:
229
fetch_spec = graph.PendingAncestryResult(
230
[revision_id], local_repo)
231
result_repo.fetch(local_repo, fetch_spec=fetch_spec)
233
result_repo.fetch(local_repo, revision_id=revision_id)
236
# 1 if there is a branch present
237
# make sure its content is available in the target repository
239
if local_branch is not None:
240
result_branch = local_branch.clone(result, revision_id=revision_id,
241
repository_policy=repository_policy)
243
# Cheaper to check if the target is not local, than to try making
245
result.root_transport.local_abspath('.')
246
if result_repo is None or result_repo.make_working_trees():
247
self.open_workingtree().clone(result)
248
except (errors.NoWorkingTree, errors.NotLocalUrl):
252
# TODO: This should be given a Transport, and should chdir up; otherwise
253
# this will open a new connection.
254
def _make_tail(self, url):
255
t = get_transport(url)
259
def create(cls, base, format=None, possible_transports=None):
260
"""Create a new BzrDir at the url 'base'.
262
:param format: If supplied, the format of branch to create. If not
263
supplied, the default is used.
264
:param possible_transports: If supplied, a list of transports that
265
can be reused to share a remote connection.
267
if cls is not BzrDir:
268
raise AssertionError("BzrDir.create always creates the default"
269
" format, not one of %r" % cls)
270
t = get_transport(base, possible_transports)
273
format = BzrDirFormat.get_default_format()
274
return format.initialize_on_transport(t)
277
def find_bzrdirs(transport, evaluate=None, list_current=None):
278
"""Find bzrdirs recursively from current location.
280
This is intended primarily as a building block for more sophisticated
281
functionality, like finding trees under a directory, or finding
282
branches that use a given repository.
283
:param evaluate: An optional callable that yields recurse, value,
284
where recurse controls whether this bzrdir is recursed into
285
and value is the value to yield. By default, all bzrdirs
286
are recursed into, and the return value is the bzrdir.
287
:param list_current: if supplied, use this function to list the current
288
directory, instead of Transport.list_dir
289
:return: a generator of found bzrdirs, or whatever evaluate returns.
291
if list_current is None:
292
def list_current(transport):
293
return transport.list_dir('')
295
def evaluate(bzrdir):
298
pending = [transport]
299
while len(pending) > 0:
300
current_transport = pending.pop()
303
bzrdir = BzrDir.open_from_transport(current_transport)
304
except errors.NotBranchError:
307
recurse, value = evaluate(bzrdir)
310
subdirs = list_current(current_transport)
311
except errors.NoSuchFile:
314
for subdir in sorted(subdirs, reverse=True):
315
pending.append(current_transport.clone(subdir))
318
def find_branches(transport):
319
"""Find all branches under a transport.
321
This will find all branches below the transport, including branches
322
inside other branches. Where possible, it will use
323
Repository.find_branches.
325
To list all the branches that use a particular Repository, see
326
Repository.find_branches
328
def evaluate(bzrdir):
330
repository = bzrdir.open_repository()
331
except errors.NoRepositoryPresent:
334
return False, (None, repository)
336
branch = bzrdir.open_branch()
337
except errors.NotBranchError:
338
return True, (None, None)
340
return True, (branch, None)
342
for branch, repo in BzrDir.find_bzrdirs(transport, evaluate=evaluate):
344
branches.extend(repo.find_branches())
345
if branch is not None:
346
branches.append(branch)
349
def destroy_repository(self):
350
"""Destroy the repository in this BzrDir"""
351
raise NotImplementedError(self.destroy_repository)
353
def create_branch(self):
354
"""Create a branch in this BzrDir.
356
The bzrdir's format will control what branch format is created.
357
For more control see BranchFormatXX.create(a_bzrdir).
359
raise NotImplementedError(self.create_branch)
361
def destroy_branch(self):
362
"""Destroy the branch in this BzrDir"""
363
raise NotImplementedError(self.destroy_branch)
366
def create_branch_and_repo(base, force_new_repo=False, format=None):
367
"""Create a new BzrDir, Branch and Repository at the url 'base'.
369
This will use the current default BzrDirFormat unless one is
370
specified, and use whatever
371
repository format that that uses via bzrdir.create_branch and
372
create_repository. If a shared repository is available that is used
375
The created Branch object is returned.
377
:param base: The URL to create the branch at.
378
:param force_new_repo: If True a new repository is always created.
379
:param format: If supplied, the format of branch to create. If not
380
supplied, the default is used.
382
bzrdir = BzrDir.create(base, format)
383
bzrdir._find_or_create_repository(force_new_repo)
384
return bzrdir.create_branch()
386
def determine_repository_policy(self, force_new_repo=False, stack_on=None,
387
stack_on_pwd=None, require_stacking=False):
388
"""Return an object representing a policy to use.
390
This controls whether a new repository is created, or a shared
391
repository used instead.
393
If stack_on is supplied, will not seek a containing shared repo.
395
:param force_new_repo: If True, require a new repository to be created.
396
:param stack_on: If supplied, the location to stack on. If not
397
supplied, a default_stack_on location may be used.
398
:param stack_on_pwd: If stack_on is relative, the location it is
401
def repository_policy(found_bzrdir):
404
config = found_bzrdir.get_config()
406
if config is not None:
407
stack_on = config.get_default_stack_on()
408
if stack_on is not None:
409
stack_on_pwd = found_bzrdir.root_transport.base
411
note('Using default stacking branch %s at %s', stack_on,
413
# does it have a repository ?
415
repository = found_bzrdir.open_repository()
416
except errors.NoRepositoryPresent:
419
if ((found_bzrdir.root_transport.base !=
420
self.root_transport.base) and not repository.is_shared()):
427
return UseExistingRepository(repository, stack_on,
428
stack_on_pwd, require_stacking=require_stacking), True
430
return CreateRepository(self, stack_on, stack_on_pwd,
431
require_stacking=require_stacking), True
433
if not force_new_repo:
435
policy = self._find_containing(repository_policy)
436
if policy is not None:
440
return UseExistingRepository(self.open_repository(),
441
stack_on, stack_on_pwd,
442
require_stacking=require_stacking)
443
except errors.NoRepositoryPresent:
445
return CreateRepository(self, stack_on, stack_on_pwd,
446
require_stacking=require_stacking)
448
def _find_or_create_repository(self, force_new_repo):
449
"""Create a new repository if needed, returning the repository."""
450
policy = self.determine_repository_policy(force_new_repo)
451
return policy.acquire_repository()[0]
454
def create_branch_convenience(base, force_new_repo=False,
455
force_new_tree=None, format=None,
456
possible_transports=None):
457
"""Create a new BzrDir, Branch and Repository at the url 'base'.
459
This is a convenience function - it will use an existing repository
460
if possible, can be told explicitly whether to create a working tree or
463
This will use the current default BzrDirFormat unless one is
464
specified, and use whatever
465
repository format that that uses via bzrdir.create_branch and
466
create_repository. If a shared repository is available that is used
467
preferentially. Whatever repository is used, its tree creation policy
470
The created Branch object is returned.
471
If a working tree cannot be made due to base not being a file:// url,
472
no error is raised unless force_new_tree is True, in which case no
473
data is created on disk and NotLocalUrl is raised.
475
:param base: The URL to create the branch at.
476
:param force_new_repo: If True a new repository is always created.
477
:param force_new_tree: If True or False force creation of a tree or
478
prevent such creation respectively.
479
:param format: Override for the bzrdir format to create.
480
:param possible_transports: An optional reusable transports list.
483
# check for non local urls
484
t = get_transport(base, possible_transports)
485
if not isinstance(t, local.LocalTransport):
486
raise errors.NotLocalUrl(base)
487
bzrdir = BzrDir.create(base, format, possible_transports)
488
repo = bzrdir._find_or_create_repository(force_new_repo)
489
result = bzrdir.create_branch()
490
if force_new_tree or (repo.make_working_trees() and
491
force_new_tree is None):
493
bzrdir.create_workingtree()
494
except errors.NotLocalUrl:
499
def create_standalone_workingtree(base, format=None):
500
"""Create a new BzrDir, WorkingTree, Branch and Repository at 'base'.
502
'base' must be a local path or a file:// url.
504
This will use the current default BzrDirFormat unless one is
505
specified, and use whatever
506
repository format that that uses for bzrdirformat.create_workingtree,
507
create_branch and create_repository.
509
:param format: Override for the bzrdir format to create.
510
:return: The WorkingTree object.
512
t = get_transport(base)
513
if not isinstance(t, local.LocalTransport):
514
raise errors.NotLocalUrl(base)
515
bzrdir = BzrDir.create_branch_and_repo(base,
517
format=format).bzrdir
518
return bzrdir.create_workingtree()
520
def create_workingtree(self, revision_id=None, from_branch=None,
521
accelerator_tree=None, hardlink=False):
522
"""Create a working tree at this BzrDir.
524
:param revision_id: create it as of this revision id.
525
:param from_branch: override bzrdir branch (for lightweight checkouts)
526
:param accelerator_tree: A tree which can be used for retrieving file
527
contents more quickly than the revision tree, i.e. a workingtree.
528
The revision tree will be used for cases where accelerator_tree's
529
content is different.
531
raise NotImplementedError(self.create_workingtree)
533
def backup_bzrdir(self):
534
"""Backup this bzr control directory.
536
:return: Tuple with old path name and new path name
538
pb = ui.ui_factory.nested_progress_bar()
540
# FIXME: bug 300001 -- the backup fails if the backup directory
541
# already exists, but it should instead either remove it or make
542
# a new backup directory.
544
# FIXME: bug 262450 -- the backup directory should have the same
545
# permissions as the .bzr directory (probably a bug in copy_tree)
546
old_path = self.root_transport.abspath('.bzr')
547
new_path = self.root_transport.abspath('backup.bzr')
548
pb.note('making backup of %s' % (old_path,))
549
pb.note(' to %s' % (new_path,))
550
self.root_transport.copy_tree('.bzr', 'backup.bzr')
551
return (old_path, new_path)
555
def retire_bzrdir(self, limit=10000):
556
"""Permanently disable the bzrdir.
558
This is done by renaming it to give the user some ability to recover
559
if there was a problem.
561
This will have horrible consequences if anyone has anything locked or
563
:param limit: number of times to retry
568
to_path = '.bzr.retired.%d' % i
569
self.root_transport.rename('.bzr', to_path)
570
note("renamed %s to %s"
571
% (self.root_transport.abspath('.bzr'), to_path))
573
except (errors.TransportError, IOError, errors.PathError):
580
def destroy_workingtree(self):
581
"""Destroy the working tree at this BzrDir.
583
Formats that do not support this may raise UnsupportedOperation.
585
raise NotImplementedError(self.destroy_workingtree)
587
def destroy_workingtree_metadata(self):
588
"""Destroy the control files for the working tree at this BzrDir.
590
The contents of working tree files are not affected.
591
Formats that do not support this may raise UnsupportedOperation.
593
raise NotImplementedError(self.destroy_workingtree_metadata)
595
def _find_containing(self, evaluate):
596
"""Find something in a containing control directory.
598
This method will scan containing control dirs, until it finds what
599
it is looking for, decides that it will never find it, or runs out
600
of containing control directories to check.
602
It is used to implement find_repository and
603
determine_repository_policy.
605
:param evaluate: A function returning (value, stop). If stop is True,
606
the value will be returned.
610
result, stop = evaluate(found_bzrdir)
613
next_transport = found_bzrdir.root_transport.clone('..')
614
if (found_bzrdir.root_transport.base == next_transport.base):
615
# top of the file system
617
# find the next containing bzrdir
619
found_bzrdir = BzrDir.open_containing_from_transport(
621
except errors.NotBranchError:
624
def find_repository(self):
625
"""Find the repository that should be used.
627
This does not require a branch as we use it to find the repo for
628
new branches as well as to hook existing branches up to their
631
def usable_repository(found_bzrdir):
632
# does it have a repository ?
634
repository = found_bzrdir.open_repository()
635
except errors.NoRepositoryPresent:
637
if found_bzrdir.root_transport.base == self.root_transport.base:
638
return repository, True
639
elif repository.is_shared():
640
return repository, True
644
found_repo = self._find_containing(usable_repository)
645
if found_repo is None:
646
raise errors.NoRepositoryPresent(self)
649
def get_branch_reference(self):
650
"""Return the referenced URL for the branch in this bzrdir.
652
:raises NotBranchError: If there is no Branch.
653
:return: The URL the branch in this bzrdir references if it is a
654
reference branch, or None for regular branches.
658
def get_branch_transport(self, branch_format):
659
"""Get the transport for use by branch format in this BzrDir.
661
Note that bzr dirs that do not support format strings will raise
662
IncompatibleFormat if the branch format they are given has
663
a format string, and vice versa.
665
If branch_format is None, the transport is returned with no
666
checking. If it is not None, then the returned transport is
667
guaranteed to point to an existing directory ready for use.
669
raise NotImplementedError(self.get_branch_transport)
671
def _find_creation_modes(self):
672
"""Determine the appropriate modes for files and directories.
674
They're always set to be consistent with the base directory,
675
assuming that this transport allows setting modes.
677
# TODO: Do we need or want an option (maybe a config setting) to turn
678
# this off or override it for particular locations? -- mbp 20080512
679
if self._mode_check_done:
681
self._mode_check_done = True
683
st = self.transport.stat('.')
684
except errors.TransportNotPossible:
685
self._dir_mode = None
686
self._file_mode = None
688
# Check the directory mode, but also make sure the created
689
# directories and files are read-write for this user. This is
690
# mostly a workaround for filesystems which lie about being able to
691
# write to a directory (cygwin & win32)
692
if (st.st_mode & 07777 == 00000):
693
# FTP allows stat but does not return dir/file modes
694
self._dir_mode = None
695
self._file_mode = None
697
self._dir_mode = (st.st_mode & 07777) | 00700
698
# Remove the sticky and execute bits for files
699
self._file_mode = self._dir_mode & ~07111
701
def _get_file_mode(self):
702
"""Return Unix mode for newly created files, or None.
704
if not self._mode_check_done:
705
self._find_creation_modes()
706
return self._file_mode
708
def _get_dir_mode(self):
709
"""Return Unix mode for newly created directories, or None.
711
if not self._mode_check_done:
712
self._find_creation_modes()
713
return self._dir_mode
715
def get_repository_transport(self, repository_format):
716
"""Get the transport for use by repository format in this BzrDir.
718
Note that bzr dirs that do not support format strings will raise
719
IncompatibleFormat if the repository format they are given has
720
a format string, and vice versa.
722
If repository_format is None, the transport is returned with no
723
checking. If it is not None, then the returned transport is
724
guaranteed to point to an existing directory ready for use.
726
raise NotImplementedError(self.get_repository_transport)
728
def get_workingtree_transport(self, tree_format):
729
"""Get the transport for use by workingtree format in this BzrDir.
731
Note that bzr dirs that do not support format strings will raise
732
IncompatibleFormat if the workingtree format they are given has a
733
format string, and vice versa.
735
If workingtree_format is None, the transport is returned with no
736
checking. If it is not None, then the returned transport is
737
guaranteed to point to an existing directory ready for use.
739
raise NotImplementedError(self.get_workingtree_transport)
741
def get_config(self):
742
if getattr(self, '_get_config', None) is None:
744
return self._get_config()
746
def __init__(self, _transport, _format):
747
"""Initialize a Bzr control dir object.
749
Only really common logic should reside here, concrete classes should be
750
made with varying behaviours.
752
:param _format: the format that is creating this BzrDir instance.
753
:param _transport: the transport this dir is based at.
755
self._format = _format
756
self.transport = _transport.clone('.bzr')
757
self.root_transport = _transport
758
self._mode_check_done = False
760
def is_control_filename(self, filename):
761
"""True if filename is the name of a path which is reserved for bzrdir's.
763
:param filename: A filename within the root transport of this bzrdir.
765
This is true IF and ONLY IF the filename is part of the namespace reserved
766
for bzr control dirs. Currently this is the '.bzr' directory in the root
767
of the root_transport. it is expected that plugins will need to extend
768
this in the future - for instance to make bzr talk with svn working
771
# this might be better on the BzrDirFormat class because it refers to
772
# all the possible bzrdir disk formats.
773
# This method is tested via the workingtree is_control_filename tests-
774
# it was extracted from WorkingTree.is_control_filename. If the method's
775
# contract is extended beyond the current trivial implementation, please
776
# add new tests for it to the appropriate place.
777
return filename == '.bzr' or filename.startswith('.bzr/')
779
def needs_format_conversion(self, format=None):
780
"""Return true if this bzrdir needs convert_format run on it.
782
For instance, if the repository format is out of date but the
783
branch and working tree are not, this should return True.
785
:param format: Optional parameter indicating a specific desired
786
format we plan to arrive at.
788
raise NotImplementedError(self.needs_format_conversion)
791
def open_unsupported(base):
792
"""Open a branch which is not supported."""
793
return BzrDir.open(base, _unsupported=True)
796
def open(base, _unsupported=False, possible_transports=None):
797
"""Open an existing bzrdir, rooted at 'base' (url).
799
:param _unsupported: a private parameter to the BzrDir class.
801
t = get_transport(base, possible_transports=possible_transports)
802
return BzrDir.open_from_transport(t, _unsupported=_unsupported)
805
def open_from_transport(transport, _unsupported=False,
806
_server_formats=True):
807
"""Open a bzrdir within a particular directory.
809
:param transport: Transport containing the bzrdir.
810
:param _unsupported: private.
812
for hook in BzrDir.hooks['pre_open']:
814
# Keep initial base since 'transport' may be modified while following
816
base = transport.base
817
def find_format(transport):
818
return transport, BzrDirFormat.find_format(
819
transport, _server_formats=_server_formats)
821
def redirected(transport, e, redirection_notice):
822
redirected_transport = transport._redirected_to(e.source, e.target)
823
if redirected_transport is None:
824
raise errors.NotBranchError(base)
825
note('%s is%s redirected to %s',
826
transport.base, e.permanently, redirected_transport.base)
827
return redirected_transport
830
transport, format = do_catching_redirections(find_format,
833
except errors.TooManyRedirections:
834
raise errors.NotBranchError(base)
836
BzrDir._check_supported(format, _unsupported)
837
return format.open(transport, _found=True)
839
def open_branch(self, unsupported=False):
840
"""Open the branch object at this BzrDir if one is present.
842
If unsupported is True, then no longer supported branch formats can
845
TODO: static convenience version of this?
847
raise NotImplementedError(self.open_branch)
850
def open_containing(url, possible_transports=None):
851
"""Open an existing branch which contains url.
853
:param url: url to search from.
854
See open_containing_from_transport for more detail.
856
transport = get_transport(url, possible_transports)
857
return BzrDir.open_containing_from_transport(transport)
860
def open_containing_from_transport(a_transport):
861
"""Open an existing branch which contains a_transport.base.
863
This probes for a branch at a_transport, and searches upwards from there.
865
Basically we keep looking up until we find the control directory or
866
run into the root. If there isn't one, raises NotBranchError.
867
If there is one and it is either an unrecognised format or an unsupported
868
format, UnknownFormatError or UnsupportedFormatError are raised.
869
If there is one, it is returned, along with the unused portion of url.
871
:return: The BzrDir that contains the path, and a Unicode path
872
for the rest of the URL.
874
# this gets the normalised url back. I.e. '.' -> the full path.
875
url = a_transport.base
878
result = BzrDir.open_from_transport(a_transport)
879
return result, urlutils.unescape(a_transport.relpath(url))
880
except errors.NotBranchError, e:
883
new_t = a_transport.clone('..')
884
except errors.InvalidURLJoin:
885
# reached the root, whatever that may be
886
raise errors.NotBranchError(path=url)
887
if new_t.base == a_transport.base:
888
# reached the root, whatever that may be
889
raise errors.NotBranchError(path=url)
892
def _get_tree_branch(self):
893
"""Return the branch and tree, if any, for this bzrdir.
895
Return None for tree if not present or inaccessible.
896
Raise NotBranchError if no branch is present.
897
:return: (tree, branch)
900
tree = self.open_workingtree()
901
except (errors.NoWorkingTree, errors.NotLocalUrl):
903
branch = self.open_branch()
909
def open_tree_or_branch(klass, location):
910
"""Return the branch and working tree at a location.
912
If there is no tree at the location, tree will be None.
913
If there is no branch at the location, an exception will be
915
:return: (tree, branch)
917
bzrdir = klass.open(location)
918
return bzrdir._get_tree_branch()
921
def open_containing_tree_or_branch(klass, location):
922
"""Return the branch and working tree contained by a location.
924
Returns (tree, branch, relpath).
925
If there is no tree at containing the location, tree will be None.
926
If there is no branch containing the location, an exception will be
928
relpath is the portion of the path that is contained by the branch.
930
bzrdir, relpath = klass.open_containing(location)
931
tree, branch = bzrdir._get_tree_branch()
932
return tree, branch, relpath
935
def open_containing_tree_branch_or_repository(klass, location):
936
"""Return the working tree, branch and repo contained by a location.
938
Returns (tree, branch, repository, relpath).
939
If there is no tree containing the location, tree will be None.
940
If there is no branch containing the location, branch will be None.
941
If there is no repository containing the location, repository will be
943
relpath is the portion of the path that is contained by the innermost
946
If no tree, branch or repository is found, a NotBranchError is raised.
948
bzrdir, relpath = klass.open_containing(location)
950
tree, branch = bzrdir._get_tree_branch()
951
except errors.NotBranchError:
953
repo = bzrdir.find_repository()
954
return None, None, repo, relpath
955
except (errors.NoRepositoryPresent):
956
raise errors.NotBranchError(location)
957
return tree, branch, branch.repository, relpath
959
def open_repository(self, _unsupported=False):
960
"""Open the repository object at this BzrDir if one is present.
962
This will not follow the Branch object pointer - it's strictly a direct
963
open facility. Most client code should use open_branch().repository to
966
:param _unsupported: a private parameter, not part of the api.
967
TODO: static convenience version of this?
969
raise NotImplementedError(self.open_repository)
971
def open_workingtree(self, _unsupported=False,
972
recommend_upgrade=True, from_branch=None):
973
"""Open the workingtree object at this BzrDir if one is present.
975
:param recommend_upgrade: Optional keyword parameter, when True (the
976
default), emit through the ui module a recommendation that the user
977
upgrade the working tree when the workingtree being opened is old
978
(but still fully supported).
979
:param from_branch: override bzrdir branch (for lightweight checkouts)
981
raise NotImplementedError(self.open_workingtree)
983
def has_branch(self):
984
"""Tell if this bzrdir contains a branch.
986
Note: if you're going to open the branch, you should just go ahead
987
and try, and not ask permission first. (This method just opens the
988
branch and discards it, and that's somewhat expensive.)
993
except errors.NotBranchError:
996
def has_workingtree(self):
997
"""Tell if this bzrdir contains a working tree.
999
This will still raise an exception if the bzrdir has a workingtree that
1000
is remote & inaccessible.
1002
Note: if you're going to open the working tree, you should just go ahead
1003
and try, and not ask permission first. (This method just opens the
1004
workingtree and discards it, and that's somewhat expensive.)
1007
self.open_workingtree(recommend_upgrade=False)
1009
except errors.NoWorkingTree:
1012
def _cloning_metadir(self):
1013
"""Produce a metadir suitable for cloning with.
1015
:returns: (destination_bzrdir_format, source_repository)
1017
result_format = self._format.__class__()
1020
branch = self.open_branch()
1021
source_repository = branch.repository
1022
result_format._branch_format = branch._format
1023
except errors.NotBranchError:
1024
source_branch = None
1025
source_repository = self.open_repository()
1026
except errors.NoRepositoryPresent:
1027
source_repository = None
1029
# XXX TODO: This isinstance is here because we have not implemented
1030
# the fix recommended in bug # 103195 - to delegate this choice the
1031
# repository itself.
1032
repo_format = source_repository._format
1033
if isinstance(repo_format, remote.RemoteRepositoryFormat):
1034
source_repository._ensure_real()
1035
repo_format = source_repository._real_repository._format
1036
result_format.repository_format = repo_format
1038
# TODO: Couldn't we just probe for the format in these cases,
1039
# rather than opening the whole tree? It would be a little
1040
# faster. mbp 20070401
1041
tree = self.open_workingtree(recommend_upgrade=False)
1042
except (errors.NoWorkingTree, errors.NotLocalUrl):
1043
result_format.workingtree_format = None
1045
result_format.workingtree_format = tree._format.__class__()
1046
return result_format, source_repository
1048
def cloning_metadir(self, require_stacking=False):
1049
"""Produce a metadir suitable for cloning or sprouting with.
1051
These operations may produce workingtrees (yes, even though they're
1052
"cloning" something that doesn't have a tree), so a viable workingtree
1053
format must be selected.
1055
:require_stacking: If True, non-stackable formats will be upgraded
1056
to similar stackable formats.
1057
:returns: a BzrDirFormat with all component formats either set
1058
appropriately or set to None if that component should not be
1061
format, repository = self._cloning_metadir()
1062
if format._workingtree_format is None:
1063
if repository is None:
1065
tree_format = repository._format._matchingbzrdir.workingtree_format
1066
format.workingtree_format = tree_format.__class__()
1067
if require_stacking:
1068
format.require_stacking()
1071
def checkout_metadir(self):
1072
return self.cloning_metadir()
1074
def sprout(self, url, revision_id=None, force_new_repo=False,
1075
recurse='down', possible_transports=None,
1076
accelerator_tree=None, hardlink=False, stacked=False,
1077
source_branch=None, create_tree_if_local=True):
1078
"""Create a copy of this bzrdir prepared for use as a new line of
1081
If url's last component does not exist, it will be created.
1083
Attributes related to the identity of the source branch like
1084
branch nickname will be cleaned, a working tree is created
1085
whether one existed before or not; and a local branch is always
1088
if revision_id is not None, then the clone operation may tune
1089
itself to download less data.
1090
:param accelerator_tree: A tree which can be used for retrieving file
1091
contents more quickly than the revision tree, i.e. a workingtree.
1092
The revision tree will be used for cases where accelerator_tree's
1093
content is different.
1094
:param hardlink: If true, hard-link files from accelerator_tree,
1096
:param stacked: If true, create a stacked branch referring to the
1097
location of this control directory.
1098
:param create_tree_if_local: If true, a working-tree will be created
1099
when working locally.
1101
target_transport = get_transport(url, possible_transports)
1102
target_transport.ensure_base()
1103
cloning_format = self.cloning_metadir(stacked)
1104
# Create/update the result branch
1105
result = cloning_format.initialize_on_transport(target_transport)
1106
# if a stacked branch wasn't requested, we don't create one
1107
# even if the origin was stacked
1108
stacked_branch_url = None
1109
if source_branch is not None:
1111
stacked_branch_url = self.root_transport.base
1112
source_repository = source_branch.repository
1115
source_branch = self.open_branch()
1116
source_repository = source_branch.repository
1118
stacked_branch_url = self.root_transport.base
1119
except errors.NotBranchError:
1120
source_branch = None
1122
source_repository = self.open_repository()
1123
except errors.NoRepositoryPresent:
1124
source_repository = None
1125
repository_policy = result.determine_repository_policy(
1126
force_new_repo, stacked_branch_url, require_stacking=stacked)
1127
result_repo, is_new_repo = repository_policy.acquire_repository()
1128
if is_new_repo and revision_id is not None and not stacked:
1129
fetch_spec = graph.PendingAncestryResult(
1130
[revision_id], source_repository)
1133
if source_repository is not None:
1134
# Fetch while stacked to prevent unstacked fetch from
1136
if fetch_spec is None:
1137
result_repo.fetch(source_repository, revision_id=revision_id)
1139
result_repo.fetch(source_repository, fetch_spec=fetch_spec)
1141
if source_branch is None:
1142
# this is for sprouting a bzrdir without a branch; is that
1144
# Not especially, but it's part of the contract.
1145
result_branch = result.create_branch()
1147
result_branch = source_branch.sprout(result,
1148
revision_id=revision_id, repository_policy=repository_policy)
1149
mutter("created new branch %r" % (result_branch,))
1151
# Create/update the result working tree
1152
if (create_tree_if_local and
1153
isinstance(target_transport, local.LocalTransport) and
1154
(result_repo is None or result_repo.make_working_trees())):
1155
wt = result.create_workingtree(accelerator_tree=accelerator_tree,
1159
if wt.path2id('') is None:
1161
wt.set_root_id(self.open_workingtree.get_root_id())
1162
except errors.NoWorkingTree:
1168
if recurse == 'down':
1170
basis = wt.basis_tree()
1172
subtrees = basis.iter_references()
1173
elif result_branch is not None:
1174
basis = result_branch.basis_tree()
1176
subtrees = basis.iter_references()
1177
elif source_branch is not None:
1178
basis = source_branch.basis_tree()
1180
subtrees = basis.iter_references()
1185
for path, file_id in subtrees:
1186
target = urlutils.join(url, urlutils.escape(path))
1187
sublocation = source_branch.reference_parent(file_id, path)
1188
sublocation.bzrdir.sprout(target,
1189
basis.get_reference_revision(file_id, path),
1190
force_new_repo=force_new_repo, recurse=recurse,
1193
if basis is not None:
1198
class BzrDirHooks(hooks.Hooks):
1199
"""Hooks for BzrDir operations."""
1202
"""Create the default hooks."""
1203
hooks.Hooks.__init__(self)
1204
self.create_hook(hooks.HookPoint('pre_open',
1205
"Invoked before attempting to open a BzrDir with the transport "
1206
"that the open will use.", (1, 14), None))
1208
# install the default hooks
1209
BzrDir.hooks = BzrDirHooks()
1212
class BzrDirPreSplitOut(BzrDir):
1213
"""A common class for the all-in-one formats."""
1215
def __init__(self, _transport, _format):
1216
"""See BzrDir.__init__."""
1217
super(BzrDirPreSplitOut, self).__init__(_transport, _format)
1218
self._control_files = lockable_files.LockableFiles(
1219
self.get_branch_transport(None),
1220
self._format._lock_file_name,
1221
self._format._lock_class)
1223
def break_lock(self):
1224
"""Pre-splitout bzrdirs do not suffer from stale locks."""
1225
raise NotImplementedError(self.break_lock)
1227
def cloning_metadir(self, require_stacking=False):
1228
"""Produce a metadir suitable for cloning with."""
1229
if require_stacking:
1230
return format_registry.make_bzrdir('1.6')
1231
return self._format.__class__()
1233
def clone(self, url, revision_id=None, force_new_repo=False,
1234
preserve_stacking=False):
1235
"""See BzrDir.clone().
1237
force_new_repo has no effect, since this family of formats always
1238
require a new repository.
1239
preserve_stacking has no effect, since no source branch using this
1240
family of formats can be stacked, so there is no stacking to preserve.
1242
self._make_tail(url)
1243
result = self._format._initialize_for_clone(url)
1244
self.open_repository().clone(result, revision_id=revision_id)
1245
from_branch = self.open_branch()
1246
from_branch.clone(result, revision_id=revision_id)
1248
tree = self.open_workingtree()
1249
except errors.NotLocalUrl:
1250
# make a new one, this format always has to have one.
1251
result._init_workingtree()
1256
def create_branch(self):
1257
"""See BzrDir.create_branch."""
1258
return self._format.get_branch_format().initialize(self)
1260
def destroy_branch(self):
1261
"""See BzrDir.destroy_branch."""
1262
raise errors.UnsupportedOperation(self.destroy_branch, self)
1264
def create_repository(self, shared=False):
1265
"""See BzrDir.create_repository."""
1267
raise errors.IncompatibleFormat('shared repository', self._format)
1268
return self.open_repository()
1270
def destroy_repository(self):
1271
"""See BzrDir.destroy_repository."""
1272
raise errors.UnsupportedOperation(self.destroy_repository, self)
1274
def create_workingtree(self, revision_id=None, from_branch=None,
1275
accelerator_tree=None, hardlink=False):
1276
"""See BzrDir.create_workingtree."""
1277
# The workingtree is sometimes created when the bzrdir is created,
1278
# but not when cloning.
1280
# this looks buggy but is not -really-
1281
# because this format creates the workingtree when the bzrdir is
1283
# clone and sprout will have set the revision_id
1284
# and that will have set it for us, its only
1285
# specific uses of create_workingtree in isolation
1286
# that can do wonky stuff here, and that only
1287
# happens for creating checkouts, which cannot be
1288
# done on this format anyway. So - acceptable wart.
1290
result = self.open_workingtree(recommend_upgrade=False)
1291
except errors.NoSuchFile:
1292
result = self._init_workingtree()
1293
if revision_id is not None:
1294
if revision_id == _mod_revision.NULL_REVISION:
1295
result.set_parent_ids([])
1297
result.set_parent_ids([revision_id])
1300
def _init_workingtree(self):
1301
from bzrlib.workingtree import WorkingTreeFormat2
1303
return WorkingTreeFormat2().initialize(self)
1304
except errors.NotLocalUrl:
1305
# Even though we can't access the working tree, we need to
1306
# create its control files.
1307
return WorkingTreeFormat2()._stub_initialize_on_transport(
1308
self.transport, self._control_files._file_mode)
1310
def destroy_workingtree(self):
1311
"""See BzrDir.destroy_workingtree."""
1312
raise errors.UnsupportedOperation(self.destroy_workingtree, self)
1314
def destroy_workingtree_metadata(self):
1315
"""See BzrDir.destroy_workingtree_metadata."""
1316
raise errors.UnsupportedOperation(self.destroy_workingtree_metadata,
1319
def get_branch_transport(self, branch_format):
1320
"""See BzrDir.get_branch_transport()."""
1321
if branch_format is None:
1322
return self.transport
1324
branch_format.get_format_string()
1325
except NotImplementedError:
1326
return self.transport
1327
raise errors.IncompatibleFormat(branch_format, self._format)
1329
def get_repository_transport(self, repository_format):
1330
"""See BzrDir.get_repository_transport()."""
1331
if repository_format is None:
1332
return self.transport
1334
repository_format.get_format_string()
1335
except NotImplementedError:
1336
return self.transport
1337
raise errors.IncompatibleFormat(repository_format, self._format)
1339
def get_workingtree_transport(self, workingtree_format):
1340
"""See BzrDir.get_workingtree_transport()."""
1341
if workingtree_format is None:
1342
return self.transport
1344
workingtree_format.get_format_string()
1345
except NotImplementedError:
1346
return self.transport
1347
raise errors.IncompatibleFormat(workingtree_format, self._format)
1349
def needs_format_conversion(self, format=None):
1350
"""See BzrDir.needs_format_conversion()."""
1351
# if the format is not the same as the system default,
1352
# an upgrade is needed.
1354
symbol_versioning.warn(symbol_versioning.deprecated_in((1, 13, 0))
1355
% 'needs_format_conversion(format=None)')
1356
format = BzrDirFormat.get_default_format()
1357
return not isinstance(self._format, format.__class__)
1359
def open_branch(self, unsupported=False):
1360
"""See BzrDir.open_branch."""
1361
from bzrlib.branch import BzrBranchFormat4
1362
format = BzrBranchFormat4()
1363
self._check_supported(format, unsupported)
1364
return format.open(self, _found=True)
1366
def sprout(self, url, revision_id=None, force_new_repo=False,
1367
possible_transports=None, accelerator_tree=None,
1368
hardlink=False, stacked=False, create_tree_if_local=True,
1369
source_branch=None):
1370
"""See BzrDir.sprout()."""
1371
if source_branch is not None:
1372
my_branch = self.open_branch()
1373
if source_branch.base != my_branch.base:
1374
raise AssertionError(
1375
"source branch %r is not within %r with branch %r" %
1376
(source_branch, self, my_branch))
1378
raise errors.UnstackableBranchFormat(
1379
self._format, self.root_transport.base)
1380
if not create_tree_if_local:
1381
raise errors.MustHaveWorkingTree(
1382
self._format, self.root_transport.base)
1383
from bzrlib.workingtree import WorkingTreeFormat2
1384
self._make_tail(url)
1385
result = self._format._initialize_for_clone(url)
1387
self.open_repository().clone(result, revision_id=revision_id)
1388
except errors.NoRepositoryPresent:
1391
self.open_branch().sprout(result, revision_id=revision_id)
1392
except errors.NotBranchError:
1395
# we always want a working tree
1396
WorkingTreeFormat2().initialize(result,
1397
accelerator_tree=accelerator_tree,
1402
class BzrDir4(BzrDirPreSplitOut):
1403
"""A .bzr version 4 control object.
1405
This is a deprecated format and may be removed after sept 2006.
1408
def create_repository(self, shared=False):
1409
"""See BzrDir.create_repository."""
1410
return self._format.repository_format.initialize(self, shared)
1412
def needs_format_conversion(self, format=None):
1413
"""Format 4 dirs are always in need of conversion."""
1415
symbol_versioning.warn(symbol_versioning.deprecated_in((1, 13, 0))
1416
% 'needs_format_conversion(format=None)')
1419
def open_repository(self):
1420
"""See BzrDir.open_repository."""
1421
from bzrlib.repofmt.weaverepo import RepositoryFormat4
1422
return RepositoryFormat4().open(self, _found=True)
1425
class BzrDir5(BzrDirPreSplitOut):
1426
"""A .bzr version 5 control object.
1428
This is a deprecated format and may be removed after sept 2006.
1431
def open_repository(self):
1432
"""See BzrDir.open_repository."""
1433
from bzrlib.repofmt.weaverepo import RepositoryFormat5
1434
return RepositoryFormat5().open(self, _found=True)
1436
def open_workingtree(self, _unsupported=False,
1437
recommend_upgrade=True):
1438
"""See BzrDir.create_workingtree."""
1439
from bzrlib.workingtree import WorkingTreeFormat2
1440
wt_format = WorkingTreeFormat2()
1441
# we don't warn here about upgrades; that ought to be handled for the
1443
return wt_format.open(self, _found=True)
1446
class BzrDir6(BzrDirPreSplitOut):
1447
"""A .bzr version 6 control object.
1449
This is a deprecated format and may be removed after sept 2006.
1452
def open_repository(self):
1453
"""See BzrDir.open_repository."""
1454
from bzrlib.repofmt.weaverepo import RepositoryFormat6
1455
return RepositoryFormat6().open(self, _found=True)
1457
def open_workingtree(self, _unsupported=False,
1458
recommend_upgrade=True):
1459
"""See BzrDir.create_workingtree."""
1460
# we don't warn here about upgrades; that ought to be handled for the
1462
from bzrlib.workingtree import WorkingTreeFormat2
1463
return WorkingTreeFormat2().open(self, _found=True)
1466
class BzrDirMeta1(BzrDir):
1467
"""A .bzr meta version 1 control object.
1469
This is the first control object where the
1470
individual aspects are really split out: there are separate repository,
1471
workingtree and branch subdirectories and any subset of the three can be
1472
present within a BzrDir.
1475
def can_convert_format(self):
1476
"""See BzrDir.can_convert_format()."""
1479
def create_branch(self):
1480
"""See BzrDir.create_branch."""
1481
return self._format.get_branch_format().initialize(self)
1483
def destroy_branch(self):
1484
"""See BzrDir.create_branch."""
1485
self.transport.delete_tree('branch')
1487
def create_repository(self, shared=False):
1488
"""See BzrDir.create_repository."""
1489
return self._format.repository_format.initialize(self, shared)
1491
def destroy_repository(self):
1492
"""See BzrDir.destroy_repository."""
1493
self.transport.delete_tree('repository')
1495
def create_workingtree(self, revision_id=None, from_branch=None,
1496
accelerator_tree=None, hardlink=False):
1497
"""See BzrDir.create_workingtree."""
1498
return self._format.workingtree_format.initialize(
1499
self, revision_id, from_branch=from_branch,
1500
accelerator_tree=accelerator_tree, hardlink=hardlink)
1502
def destroy_workingtree(self):
1503
"""See BzrDir.destroy_workingtree."""
1504
wt = self.open_workingtree(recommend_upgrade=False)
1505
repository = wt.branch.repository
1506
empty = repository.revision_tree(_mod_revision.NULL_REVISION)
1507
wt.revert(old_tree=empty)
1508
self.destroy_workingtree_metadata()
1510
def destroy_workingtree_metadata(self):
1511
self.transport.delete_tree('checkout')
1513
def find_branch_format(self):
1514
"""Find the branch 'format' for this bzrdir.
1516
This might be a synthetic object for e.g. RemoteBranch and SVN.
1518
from bzrlib.branch import BranchFormat
1519
return BranchFormat.find_format(self)
1521
def _get_mkdir_mode(self):
1522
"""Figure out the mode to use when creating a bzrdir subdir."""
1523
temp_control = lockable_files.LockableFiles(self.transport, '',
1524
lockable_files.TransportLock)
1525
return temp_control._dir_mode
1527
def get_branch_reference(self):
1528
"""See BzrDir.get_branch_reference()."""
1529
from bzrlib.branch import BranchFormat
1530
format = BranchFormat.find_format(self)
1531
return format.get_reference(self)
1533
def get_branch_transport(self, branch_format):
1534
"""See BzrDir.get_branch_transport()."""
1535
if branch_format is None:
1536
return self.transport.clone('branch')
1538
branch_format.get_format_string()
1539
except NotImplementedError:
1540
raise errors.IncompatibleFormat(branch_format, self._format)
1542
self.transport.mkdir('branch', mode=self._get_mkdir_mode())
1543
except errors.FileExists:
1545
return self.transport.clone('branch')
1547
def get_repository_transport(self, repository_format):
1548
"""See BzrDir.get_repository_transport()."""
1549
if repository_format is None:
1550
return self.transport.clone('repository')
1552
repository_format.get_format_string()
1553
except NotImplementedError:
1554
raise errors.IncompatibleFormat(repository_format, self._format)
1556
self.transport.mkdir('repository', mode=self._get_mkdir_mode())
1557
except errors.FileExists:
1559
return self.transport.clone('repository')
1561
def get_workingtree_transport(self, workingtree_format):
1562
"""See BzrDir.get_workingtree_transport()."""
1563
if workingtree_format is None:
1564
return self.transport.clone('checkout')
1566
workingtree_format.get_format_string()
1567
except NotImplementedError:
1568
raise errors.IncompatibleFormat(workingtree_format, self._format)
1570
self.transport.mkdir('checkout', mode=self._get_mkdir_mode())
1571
except errors.FileExists:
1573
return self.transport.clone('checkout')
1575
def needs_format_conversion(self, format=None):
1576
"""See BzrDir.needs_format_conversion()."""
1578
symbol_versioning.warn(symbol_versioning.deprecated_in((1, 13, 0))
1579
% 'needs_format_conversion(format=None)')
1581
format = BzrDirFormat.get_default_format()
1582
if not isinstance(self._format, format.__class__):
1583
# it is not a meta dir format, conversion is needed.
1585
# we might want to push this down to the repository?
1587
if not isinstance(self.open_repository()._format,
1588
format.repository_format.__class__):
1589
# the repository needs an upgrade.
1591
except errors.NoRepositoryPresent:
1594
if not isinstance(self.open_branch()._format,
1595
format.get_branch_format().__class__):
1596
# the branch needs an upgrade.
1598
except errors.NotBranchError:
1601
my_wt = self.open_workingtree(recommend_upgrade=False)
1602
if not isinstance(my_wt._format,
1603
format.workingtree_format.__class__):
1604
# the workingtree needs an upgrade.
1606
except (errors.NoWorkingTree, errors.NotLocalUrl):
1610
def open_branch(self, unsupported=False):
1611
"""See BzrDir.open_branch."""
1612
format = self.find_branch_format()
1613
self._check_supported(format, unsupported)
1614
return format.open(self, _found=True)
1616
def open_repository(self, unsupported=False):
1617
"""See BzrDir.open_repository."""
1618
from bzrlib.repository import RepositoryFormat
1619
format = RepositoryFormat.find_format(self)
1620
self._check_supported(format, unsupported)
1621
return format.open(self, _found=True)
1623
def open_workingtree(self, unsupported=False,
1624
recommend_upgrade=True):
1625
"""See BzrDir.open_workingtree."""
1626
from bzrlib.workingtree import WorkingTreeFormat
1627
format = WorkingTreeFormat.find_format(self)
1628
self._check_supported(format, unsupported,
1630
basedir=self.root_transport.base)
1631
return format.open(self, _found=True)
1633
def _get_config(self):
1634
return config.BzrDirConfig(self.transport)
1637
class BzrDirFormat(object):
1638
"""An encapsulation of the initialization and open routines for a format.
1640
Formats provide three things:
1641
* An initialization routine,
1645
Formats are placed in a dict by their format string for reference
1646
during bzrdir opening. These should be subclasses of BzrDirFormat
1649
Once a format is deprecated, just deprecate the initialize and open
1650
methods on the format class. Do not deprecate the object, as the
1651
object will be created every system load.
1654
_default_format = None
1655
"""The default format used for new .bzr dirs."""
1658
"""The known formats."""
1660
_control_formats = []
1661
"""The registered control formats - .bzr, ....
1663
This is a list of BzrDirFormat objects.
1666
_control_server_formats = []
1667
"""The registered control server formats, e.g. RemoteBzrDirs.
1669
This is a list of BzrDirFormat objects.
1672
_lock_file_name = 'branch-lock'
1674
# _lock_class must be set in subclasses to the lock type, typ.
1675
# TransportLock or LockDir
1678
def find_format(klass, transport, _server_formats=True):
1679
"""Return the format present at transport."""
1681
formats = klass._control_server_formats + klass._control_formats
1683
formats = klass._control_formats
1684
for format in formats:
1686
return format.probe_transport(transport)
1687
except errors.NotBranchError:
1688
# this format does not find a control dir here.
1690
raise errors.NotBranchError(path=transport.base)
1693
def probe_transport(klass, transport):
1694
"""Return the .bzrdir style format present in a directory."""
1696
format_string = transport.get(".bzr/branch-format").read()
1697
except errors.NoSuchFile:
1698
raise errors.NotBranchError(path=transport.base)
1701
return klass._formats[format_string]
1703
raise errors.UnknownFormatError(format=format_string, kind='bzrdir')
1706
def get_default_format(klass):
1707
"""Return the current default format."""
1708
return klass._default_format
1710
def get_format_string(self):
1711
"""Return the ASCII format string that identifies this format."""
1712
raise NotImplementedError(self.get_format_string)
1714
def get_format_description(self):
1715
"""Return the short description for this format."""
1716
raise NotImplementedError(self.get_format_description)
1718
def get_converter(self, format=None):
1719
"""Return the converter to use to convert bzrdirs needing converts.
1721
This returns a bzrlib.bzrdir.Converter object.
1723
This should return the best upgrader to step this format towards the
1724
current default format. In the case of plugins we can/should provide
1725
some means for them to extend the range of returnable converters.
1727
:param format: Optional format to override the default format of the
1730
raise NotImplementedError(self.get_converter)
1732
def initialize(self, url, possible_transports=None):
1733
"""Create a bzr control dir at this url and return an opened copy.
1735
Subclasses should typically override initialize_on_transport
1736
instead of this method.
1738
return self.initialize_on_transport(get_transport(url,
1739
possible_transports))
1741
def initialize_on_transport(self, transport):
1742
"""Initialize a new bzrdir in the base directory of a Transport."""
1744
# can we hand off the request to the smart server rather than using
1746
client_medium = transport.get_smart_medium()
1747
except errors.NoSmartMedium:
1748
return self._initialize_on_transport_vfs(transport)
1750
# Current RPC's only know how to create bzr metadir1 instances, so
1751
# we still delegate to vfs methods if the requested format is not a
1753
if type(self) != BzrDirMetaFormat1:
1754
return self._initialize_on_transport_vfs(transport)
1755
remote_format = RemoteBzrDirFormat()
1756
self._supply_sub_formats_to(remote_format)
1757
return remote_format.initialize_on_transport(transport)
1759
def _initialize_on_transport_vfs(self, transport):
1760
"""Initialize a new bzrdir using VFS calls.
1762
:param transport: The transport to create the .bzr directory in.
1765
# Since we are creating a .bzr directory, inherit the
1766
# mode from the root directory
1767
temp_control = lockable_files.LockableFiles(transport,
1768
'', lockable_files.TransportLock)
1769
temp_control._transport.mkdir('.bzr',
1770
# FIXME: RBC 20060121 don't peek under
1772
mode=temp_control._dir_mode)
1773
if sys.platform == 'win32' and isinstance(transport, local.LocalTransport):
1774
win32utils.set_file_attr_hidden(transport._abspath('.bzr'))
1775
file_mode = temp_control._file_mode
1777
bzrdir_transport = transport.clone('.bzr')
1778
utf8_files = [('README',
1779
"This is a Bazaar control directory.\n"
1780
"Do not change any files in this directory.\n"
1781
"See http://bazaar-vcs.org/ for more information about Bazaar.\n"),
1782
('branch-format', self.get_format_string()),
1784
# NB: no need to escape relative paths that are url safe.
1785
control_files = lockable_files.LockableFiles(bzrdir_transport,
1786
self._lock_file_name, self._lock_class)
1787
control_files.create_lock()
1788
control_files.lock_write()
1790
for (filename, content) in utf8_files:
1791
bzrdir_transport.put_bytes(filename, content,
1794
control_files.unlock()
1795
return self.open(transport, _found=True)
1797
def is_supported(self):
1798
"""Is this format supported?
1800
Supported formats must be initializable and openable.
1801
Unsupported formats may not support initialization or committing or
1802
some other features depending on the reason for not being supported.
1806
def network_name(self):
1807
"""A simple byte string uniquely identifying this format for RPC calls.
1809
Bzr control formats use thir disk format string to identify the format
1810
over the wire. Its possible that other control formats have more
1811
complex detection requirements, so we permit them to use any unique and
1812
immutable string they desire.
1814
raise NotImplementedError(self.network_name)
1816
def same_model(self, target_format):
1817
return (self.repository_format.rich_root_data ==
1818
target_format.rich_root_data)
1821
def known_formats(klass):
1822
"""Return all the known formats.
1824
Concrete formats should override _known_formats.
1826
# There is double indirection here to make sure that control
1827
# formats used by more than one dir format will only be probed
1828
# once. This can otherwise be quite expensive for remote connections.
1830
for format in klass._control_formats:
1831
result.update(format._known_formats())
1835
def _known_formats(klass):
1836
"""Return the known format instances for this control format."""
1837
return set(klass._formats.values())
1839
def open(self, transport, _found=False):
1840
"""Return an instance of this format for the dir transport points at.
1842
_found is a private parameter, do not use it.
1845
found_format = BzrDirFormat.find_format(transport)
1846
if not isinstance(found_format, self.__class__):
1847
raise AssertionError("%s was asked to open %s, but it seems to need "
1849
% (self, transport, found_format))
1850
# Allow subclasses - use the found format.
1851
self._supply_sub_formats_to(found_format)
1852
return found_format._open(transport)
1853
return self._open(transport)
1855
def _open(self, transport):
1856
"""Template method helper for opening BzrDirectories.
1858
This performs the actual open and any additional logic or parameter
1861
raise NotImplementedError(self._open)
1864
def register_format(klass, format):
1865
klass._formats[format.get_format_string()] = format
1866
# bzr native formats have a network name of their format string.
1867
network_format_registry.register(format.get_format_string(), format.__class__)
1870
def register_control_format(klass, format):
1871
"""Register a format that does not use '.bzr' for its control dir.
1873
TODO: This should be pulled up into a 'ControlDirFormat' base class
1874
which BzrDirFormat can inherit from, and renamed to register_format
1875
there. It has been done without that for now for simplicity of
1878
klass._control_formats.append(format)
1881
def register_control_server_format(klass, format):
1882
"""Register a control format for client-server environments.
1884
These formats will be tried before ones registered with
1885
register_control_format. This gives implementations that decide to the
1886
chance to grab it before anything looks at the contents of the format
1889
klass._control_server_formats.append(format)
1892
def _set_default_format(klass, format):
1893
"""Set default format (for testing behavior of defaults only)"""
1894
klass._default_format = format
1898
return self.get_format_description().rstrip()
1900
def _supply_sub_formats_to(self, other_format):
1901
"""Give other_format the same values for sub formats as this has.
1903
This method is expected to be used when parameterising a
1904
RemoteBzrDirFormat instance with the parameters from a
1905
BzrDirMetaFormat1 instance.
1907
:param other_format: other_format is a format which should be
1908
compatible with whatever sub formats are supported by self.
1913
def unregister_format(klass, format):
1914
del klass._formats[format.get_format_string()]
1917
def unregister_control_format(klass, format):
1918
klass._control_formats.remove(format)
1921
class BzrDirFormat4(BzrDirFormat):
1922
"""Bzr dir format 4.
1924
This format is a combined format for working tree, branch and repository.
1926
- Format 1 working trees [always]
1927
- Format 4 branches [always]
1928
- Format 4 repositories [always]
1930
This format is deprecated: it indexes texts using a text it which is
1931
removed in format 5; write support for this format has been removed.
1934
_lock_class = lockable_files.TransportLock
1936
def get_format_string(self):
1937
"""See BzrDirFormat.get_format_string()."""
1938
return "Bazaar-NG branch, format 0.0.4\n"
1940
def get_format_description(self):
1941
"""See BzrDirFormat.get_format_description()."""
1942
return "All-in-one format 4"
1944
def get_converter(self, format=None):
1945
"""See BzrDirFormat.get_converter()."""
1946
# there is one and only one upgrade path here.
1947
return ConvertBzrDir4To5()
1949
def initialize_on_transport(self, transport):
1950
"""Format 4 branches cannot be created."""
1951
raise errors.UninitializableFormat(self)
1953
def is_supported(self):
1954
"""Format 4 is not supported.
1956
It is not supported because the model changed from 4 to 5 and the
1957
conversion logic is expensive - so doing it on the fly was not
1962
def network_name(self):
1963
return self.get_format_string()
1965
def _open(self, transport):
1966
"""See BzrDirFormat._open."""
1967
return BzrDir4(transport, self)
1969
def __return_repository_format(self):
1970
"""Circular import protection."""
1971
from bzrlib.repofmt.weaverepo import RepositoryFormat4
1972
return RepositoryFormat4()
1973
repository_format = property(__return_repository_format)
1976
class BzrDirFormat5(BzrDirFormat):
1977
"""Bzr control format 5.
1979
This format is a combined format for working tree, branch and repository.
1981
- Format 2 working trees [always]
1982
- Format 4 branches [always]
1983
- Format 5 repositories [always]
1984
Unhashed stores in the repository.
1987
_lock_class = lockable_files.TransportLock
1989
def get_format_string(self):
1990
"""See BzrDirFormat.get_format_string()."""
1991
return "Bazaar-NG branch, format 5\n"
1993
def get_branch_format(self):
1994
from bzrlib import branch
1995
return branch.BzrBranchFormat4()
1997
def get_format_description(self):
1998
"""See BzrDirFormat.get_format_description()."""
1999
return "All-in-one format 5"
2001
def get_converter(self, format=None):
2002
"""See BzrDirFormat.get_converter()."""
2003
# there is one and only one upgrade path here.
2004
return ConvertBzrDir5To6()
2006
def _initialize_for_clone(self, url):
2007
return self.initialize_on_transport(get_transport(url), _cloning=True)
2009
def initialize_on_transport(self, transport, _cloning=False):
2010
"""Format 5 dirs always have working tree, branch and repository.
2012
Except when they are being cloned.
2014
from bzrlib.branch import BzrBranchFormat4
2015
from bzrlib.repofmt.weaverepo import RepositoryFormat5
2016
result = (super(BzrDirFormat5, self).initialize_on_transport(transport))
2017
RepositoryFormat5().initialize(result, _internal=True)
2019
branch = BzrBranchFormat4().initialize(result)
2020
result._init_workingtree()
2023
def network_name(self):
2024
return self.get_format_string()
2026
def _open(self, transport):
2027
"""See BzrDirFormat._open."""
2028
return BzrDir5(transport, self)
2030
def __return_repository_format(self):
2031
"""Circular import protection."""
2032
from bzrlib.repofmt.weaverepo import RepositoryFormat5
2033
return RepositoryFormat5()
2034
repository_format = property(__return_repository_format)
2037
class BzrDirFormat6(BzrDirFormat):
2038
"""Bzr control format 6.
2040
This format is a combined format for working tree, branch and repository.
2042
- Format 2 working trees [always]
2043
- Format 4 branches [always]
2044
- Format 6 repositories [always]
2047
_lock_class = lockable_files.TransportLock
2049
def get_format_string(self):
2050
"""See BzrDirFormat.get_format_string()."""
2051
return "Bazaar-NG branch, format 6\n"
2053
def get_format_description(self):
2054
"""See BzrDirFormat.get_format_description()."""
2055
return "All-in-one format 6"
2057
def get_branch_format(self):
2058
from bzrlib import branch
2059
return branch.BzrBranchFormat4()
2061
def get_converter(self, format=None):
2062
"""See BzrDirFormat.get_converter()."""
2063
# there is one and only one upgrade path here.
2064
return ConvertBzrDir6ToMeta()
2066
def _initialize_for_clone(self, url):
2067
return self.initialize_on_transport(get_transport(url), _cloning=True)
2069
def initialize_on_transport(self, transport, _cloning=False):
2070
"""Format 6 dirs always have working tree, branch and repository.
2072
Except when they are being cloned.
2074
from bzrlib.branch import BzrBranchFormat4
2075
from bzrlib.repofmt.weaverepo import RepositoryFormat6
2076
result = super(BzrDirFormat6, self).initialize_on_transport(transport)
2077
RepositoryFormat6().initialize(result, _internal=True)
2079
branch = BzrBranchFormat4().initialize(result)
2080
result._init_workingtree()
2083
def network_name(self):
2084
return self.get_format_string()
2086
def _open(self, transport):
2087
"""See BzrDirFormat._open."""
2088
return BzrDir6(transport, self)
2090
def __return_repository_format(self):
2091
"""Circular import protection."""
2092
from bzrlib.repofmt.weaverepo import RepositoryFormat6
2093
return RepositoryFormat6()
2094
repository_format = property(__return_repository_format)
2097
class BzrDirMetaFormat1(BzrDirFormat):
2098
"""Bzr meta control format 1
2100
This is the first format with split out working tree, branch and repository
2103
- Format 3 working trees [optional]
2104
- Format 5 branches [optional]
2105
- Format 7 repositories [optional]
2108
_lock_class = lockdir.LockDir
2111
self._workingtree_format = None
2112
self._branch_format = None
2113
self._repository_format = None
2115
def __eq__(self, other):
2116
if other.__class__ is not self.__class__:
2118
if other.repository_format != self.repository_format:
2120
if other.workingtree_format != self.workingtree_format:
2124
def __ne__(self, other):
2125
return not self == other
2127
def get_branch_format(self):
2128
if self._branch_format is None:
2129
from bzrlib.branch import BranchFormat
2130
self._branch_format = BranchFormat.get_default_format()
2131
return self._branch_format
2133
def set_branch_format(self, format):
2134
self._branch_format = format
2136
def require_stacking(self):
2137
if not self.get_branch_format().supports_stacking():
2138
# We need to make a stacked branch, but the default format for the
2139
# target doesn't support stacking. So force a branch that *can*
2141
from bzrlib.branch import BzrBranchFormat7
2142
branch_format = BzrBranchFormat7()
2143
self.set_branch_format(branch_format)
2144
mutter("using %r for stacking" % (branch_format,))
2145
from bzrlib.repofmt import pack_repo
2146
if self.repository_format.rich_root_data:
2147
bzrdir_format_name = '1.6.1-rich-root'
2148
repo_format = pack_repo.RepositoryFormatKnitPack5RichRoot()
2150
bzrdir_format_name = '1.6'
2151
repo_format = pack_repo.RepositoryFormatKnitPack5()
2152
note('Source format does not support stacking, using format:'
2154
bzrdir_format_name, repo_format.get_format_description())
2155
self.repository_format = repo_format
2157
def get_converter(self, format=None):
2158
"""See BzrDirFormat.get_converter()."""
2160
format = BzrDirFormat.get_default_format()
2161
if not isinstance(self, format.__class__):
2162
# converting away from metadir is not implemented
2163
raise NotImplementedError(self.get_converter)
2164
return ConvertMetaToMeta(format)
2166
def get_format_string(self):
2167
"""See BzrDirFormat.get_format_string()."""
2168
return "Bazaar-NG meta directory, format 1\n"
2170
def get_format_description(self):
2171
"""See BzrDirFormat.get_format_description()."""
2172
return "Meta directory format 1"
2174
def network_name(self):
2175
return self.get_format_string()
2177
def _open(self, transport):
2178
"""See BzrDirFormat._open."""
2179
return BzrDirMeta1(transport, self)
2181
def __return_repository_format(self):
2182
"""Circular import protection."""
2183
if self._repository_format:
2184
return self._repository_format
2185
from bzrlib.repository import RepositoryFormat
2186
return RepositoryFormat.get_default_format()
2188
def _set_repository_format(self, value):
2189
"""Allow changing the repository format for metadir formats."""
2190
self._repository_format = value
2192
repository_format = property(__return_repository_format,
2193
_set_repository_format)
2195
def _supply_sub_formats_to(self, other_format):
2196
"""Give other_format the same values for sub formats as this has.
2198
This method is expected to be used when parameterising a
2199
RemoteBzrDirFormat instance with the parameters from a
2200
BzrDirMetaFormat1 instance.
2202
:param other_format: other_format is a format which should be
2203
compatible with whatever sub formats are supported by self.
2206
if getattr(self, '_repository_format', None) is not None:
2207
other_format.repository_format = self.repository_format
2208
if self._branch_format is not None:
2209
other_format._branch_format = self._branch_format
2210
if self._workingtree_format is not None:
2211
other_format.workingtree_format = self.workingtree_format
2213
def __get_workingtree_format(self):
2214
if self._workingtree_format is None:
2215
from bzrlib.workingtree import WorkingTreeFormat
2216
self._workingtree_format = WorkingTreeFormat.get_default_format()
2217
return self._workingtree_format
2219
def __set_workingtree_format(self, wt_format):
2220
self._workingtree_format = wt_format
2222
workingtree_format = property(__get_workingtree_format,
2223
__set_workingtree_format)
2226
network_format_registry = registry.FormatRegistry()
2227
"""Registry of formats indexed by their network name.
2229
The network name for a BzrDirFormat is an identifier that can be used when
2230
referring to formats with smart server operations. See
2231
BzrDirFormat.network_name() for more detail.
2235
# Register bzr control format
2236
BzrDirFormat.register_control_format(BzrDirFormat)
2238
# Register bzr formats
2239
BzrDirFormat.register_format(BzrDirFormat4())
2240
BzrDirFormat.register_format(BzrDirFormat5())
2241
BzrDirFormat.register_format(BzrDirFormat6())
2242
__default_format = BzrDirMetaFormat1()
2243
BzrDirFormat.register_format(__default_format)
2244
BzrDirFormat._default_format = __default_format
2247
class Converter(object):
2248
"""Converts a disk format object from one format to another."""
2250
def convert(self, to_convert, pb):
2251
"""Perform the conversion of to_convert, giving feedback via pb.
2253
:param to_convert: The disk object to convert.
2254
:param pb: a progress bar to use for progress information.
2257
def step(self, message):
2258
"""Update the pb by a step."""
2260
self.pb.update(message, self.count, self.total)
2263
class ConvertBzrDir4To5(Converter):
2264
"""Converts format 4 bzr dirs to format 5."""
2267
super(ConvertBzrDir4To5, self).__init__()
2268
self.converted_revs = set()
2269
self.absent_revisions = set()
2273
def convert(self, to_convert, pb):
2274
"""See Converter.convert()."""
2275
self.bzrdir = to_convert
2277
self.pb.note('starting upgrade from format 4 to 5')
2278
if isinstance(self.bzrdir.transport, local.LocalTransport):
2279
self.bzrdir.get_workingtree_transport(None).delete('stat-cache')
2280
self._convert_to_weaves()
2281
return BzrDir.open(self.bzrdir.root_transport.base)
2283
def _convert_to_weaves(self):
2284
self.pb.note('note: upgrade may be faster if all store files are ungzipped first')
2287
stat = self.bzrdir.transport.stat('weaves')
2288
if not S_ISDIR(stat.st_mode):
2289
self.bzrdir.transport.delete('weaves')
2290
self.bzrdir.transport.mkdir('weaves')
2291
except errors.NoSuchFile:
2292
self.bzrdir.transport.mkdir('weaves')
2293
# deliberately not a WeaveFile as we want to build it up slowly.
2294
self.inv_weave = Weave('inventory')
2295
# holds in-memory weaves for all files
2296
self.text_weaves = {}
2297
self.bzrdir.transport.delete('branch-format')
2298
self.branch = self.bzrdir.open_branch()
2299
self._convert_working_inv()
2300
rev_history = self.branch.revision_history()
2301
# to_read is a stack holding the revisions we still need to process;
2302
# appending to it adds new highest-priority revisions
2303
self.known_revisions = set(rev_history)
2304
self.to_read = rev_history[-1:]
2306
rev_id = self.to_read.pop()
2307
if (rev_id not in self.revisions
2308
and rev_id not in self.absent_revisions):
2309
self._load_one_rev(rev_id)
2311
to_import = self._make_order()
2312
for i, rev_id in enumerate(to_import):
2313
self.pb.update('converting revision', i, len(to_import))
2314
self._convert_one_rev(rev_id)
2316
self._write_all_weaves()
2317
self._write_all_revs()
2318
self.pb.note('upgraded to weaves:')
2319
self.pb.note(' %6d revisions and inventories', len(self.revisions))
2320
self.pb.note(' %6d revisions not present', len(self.absent_revisions))
2321
self.pb.note(' %6d texts', self.text_count)
2322
self._cleanup_spare_files_after_format4()
2323
self.branch._transport.put_bytes(
2325
BzrDirFormat5().get_format_string(),
2326
mode=self.bzrdir._get_file_mode())
2328
def _cleanup_spare_files_after_format4(self):
2329
# FIXME working tree upgrade foo.
2330
for n in 'merged-patches', 'pending-merged-patches':
2332
## assert os.path.getsize(p) == 0
2333
self.bzrdir.transport.delete(n)
2334
except errors.NoSuchFile:
2336
self.bzrdir.transport.delete_tree('inventory-store')
2337
self.bzrdir.transport.delete_tree('text-store')
2339
def _convert_working_inv(self):
2340
inv = xml4.serializer_v4.read_inventory(
2341
self.branch._transport.get('inventory'))
2342
new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv, working=True)
2343
self.branch._transport.put_bytes('inventory', new_inv_xml,
2344
mode=self.bzrdir._get_file_mode())
2346
def _write_all_weaves(self):
2347
controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)
2348
weave_transport = self.bzrdir.transport.clone('weaves')
2349
weaves = WeaveStore(weave_transport, prefixed=False)
2350
transaction = WriteTransaction()
2354
for file_id, file_weave in self.text_weaves.items():
2355
self.pb.update('writing weave', i, len(self.text_weaves))
2356
weaves._put_weave(file_id, file_weave, transaction)
2358
self.pb.update('inventory', 0, 1)
2359
controlweaves._put_weave('inventory', self.inv_weave, transaction)
2360
self.pb.update('inventory', 1, 1)
2364
def _write_all_revs(self):
2365
"""Write all revisions out in new form."""
2366
self.bzrdir.transport.delete_tree('revision-store')
2367
self.bzrdir.transport.mkdir('revision-store')
2368
revision_transport = self.bzrdir.transport.clone('revision-store')
2370
from bzrlib.xml5 import serializer_v5
2371
from bzrlib.repofmt.weaverepo import RevisionTextStore
2372
revision_store = RevisionTextStore(revision_transport,
2373
serializer_v5, False, versionedfile.PrefixMapper(),
2374
lambda:True, lambda:True)
2376
for i, rev_id in enumerate(self.converted_revs):
2377
self.pb.update('write revision', i, len(self.converted_revs))
2378
text = serializer_v5.write_revision_to_string(
2379
self.revisions[rev_id])
2381
revision_store.add_lines(key, None, osutils.split_lines(text))
2385
def _load_one_rev(self, rev_id):
2386
"""Load a revision object into memory.
2388
Any parents not either loaded or abandoned get queued to be
2390
self.pb.update('loading revision',
2391
len(self.revisions),
2392
len(self.known_revisions))
2393
if not self.branch.repository.has_revision(rev_id):
2395
self.pb.note('revision {%s} not present in branch; '
2396
'will be converted as a ghost',
2398
self.absent_revisions.add(rev_id)
2400
rev = self.branch.repository.get_revision(rev_id)
2401
for parent_id in rev.parent_ids:
2402
self.known_revisions.add(parent_id)
2403
self.to_read.append(parent_id)
2404
self.revisions[rev_id] = rev
2406
def _load_old_inventory(self, rev_id):
2407
old_inv_xml = self.branch.repository.inventory_store.get(rev_id).read()
2408
inv = xml4.serializer_v4.read_inventory_from_string(old_inv_xml)
2409
inv.revision_id = rev_id
2410
rev = self.revisions[rev_id]
2413
def _load_updated_inventory(self, rev_id):
2414
inv_xml = self.inv_weave.get_text(rev_id)
2415
inv = xml5.serializer_v5.read_inventory_from_string(inv_xml, rev_id)
2418
def _convert_one_rev(self, rev_id):
2419
"""Convert revision and all referenced objects to new format."""
2420
rev = self.revisions[rev_id]
2421
inv = self._load_old_inventory(rev_id)
2422
present_parents = [p for p in rev.parent_ids
2423
if p not in self.absent_revisions]
2424
self._convert_revision_contents(rev, inv, present_parents)
2425
self._store_new_inv(rev, inv, present_parents)
2426
self.converted_revs.add(rev_id)
2428
def _store_new_inv(self, rev, inv, present_parents):
2429
new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
2430
new_inv_sha1 = sha_string(new_inv_xml)
2431
self.inv_weave.add_lines(rev.revision_id,
2433
new_inv_xml.splitlines(True))
2434
rev.inventory_sha1 = new_inv_sha1
2436
def _convert_revision_contents(self, rev, inv, present_parents):
2437
"""Convert all the files within a revision.
2439
Also upgrade the inventory to refer to the text revision ids."""
2440
rev_id = rev.revision_id
2441
mutter('converting texts of revision {%s}',
2443
parent_invs = map(self._load_updated_inventory, present_parents)
2444
entries = inv.iter_entries()
2446
for path, ie in entries:
2447
self._convert_file_version(rev, ie, parent_invs)
2449
def _convert_file_version(self, rev, ie, parent_invs):
2450
"""Convert one version of one file.
2452
The file needs to be added into the weave if it is a merge
2453
of >=2 parents or if it's changed from its parent.
2455
file_id = ie.file_id
2456
rev_id = rev.revision_id
2457
w = self.text_weaves.get(file_id)
2460
self.text_weaves[file_id] = w
2461
text_changed = False
2462
parent_candiate_entries = ie.parent_candidates(parent_invs)
2463
heads = graph.Graph(self).heads(parent_candiate_entries.keys())
2464
# XXX: Note that this is unordered - and this is tolerable because
2465
# the previous code was also unordered.
2466
previous_entries = dict((head, parent_candiate_entries[head]) for head
2468
self.snapshot_ie(previous_entries, ie, w, rev_id)
2471
@symbol_versioning.deprecated_method(symbol_versioning.one_one)
2472
def get_parents(self, revision_ids):
2473
for revision_id in revision_ids:
2474
yield self.revisions[revision_id].parent_ids
2476
def get_parent_map(self, revision_ids):
2477
"""See graph._StackedParentsProvider.get_parent_map"""
2478
return dict((revision_id, self.revisions[revision_id])
2479
for revision_id in revision_ids
2480
if revision_id in self.revisions)
2482
def snapshot_ie(self, previous_revisions, ie, w, rev_id):
2483
# TODO: convert this logic, which is ~= snapshot to
2484
# a call to:. This needs the path figured out. rather than a work_tree
2485
# a v4 revision_tree can be given, or something that looks enough like
2486
# one to give the file content to the entry if it needs it.
2487
# and we need something that looks like a weave store for snapshot to
2489
#ie.snapshot(rev, PATH, previous_revisions, REVISION_TREE, InMemoryWeaveStore(self.text_weaves))
2490
if len(previous_revisions) == 1:
2491
previous_ie = previous_revisions.values()[0]
2492
if ie._unchanged(previous_ie):
2493
ie.revision = previous_ie.revision
2496
text = self.branch.repository._text_store.get(ie.text_id)
2497
file_lines = text.readlines()
2498
w.add_lines(rev_id, previous_revisions, file_lines)
2499
self.text_count += 1
2501
w.add_lines(rev_id, previous_revisions, [])
2502
ie.revision = rev_id
2504
def _make_order(self):
2505
"""Return a suitable order for importing revisions.
2507
The order must be such that an revision is imported after all
2508
its (present) parents.
2510
todo = set(self.revisions.keys())
2511
done = self.absent_revisions.copy()
2514
# scan through looking for a revision whose parents
2516
for rev_id in sorted(list(todo)):
2517
rev = self.revisions[rev_id]
2518
parent_ids = set(rev.parent_ids)
2519
if parent_ids.issubset(done):
2520
# can take this one now
2521
order.append(rev_id)
2527
class ConvertBzrDir5To6(Converter):
2528
"""Converts format 5 bzr dirs to format 6."""
2530
def convert(self, to_convert, pb):
2531
"""See Converter.convert()."""
2532
self.bzrdir = to_convert
2534
self.pb.note('starting upgrade from format 5 to 6')
2535
self._convert_to_prefixed()
2536
return BzrDir.open(self.bzrdir.root_transport.base)
2538
def _convert_to_prefixed(self):
2539
from bzrlib.store import TransportStore
2540
self.bzrdir.transport.delete('branch-format')
2541
for store_name in ["weaves", "revision-store"]:
2542
self.pb.note("adding prefixes to %s" % store_name)
2543
store_transport = self.bzrdir.transport.clone(store_name)
2544
store = TransportStore(store_transport, prefixed=True)
2545
for urlfilename in store_transport.list_dir('.'):
2546
filename = urlutils.unescape(urlfilename)
2547
if (filename.endswith(".weave") or
2548
filename.endswith(".gz") or
2549
filename.endswith(".sig")):
2550
file_id, suffix = os.path.splitext(filename)
2554
new_name = store._mapper.map((file_id,)) + suffix
2555
# FIXME keep track of the dirs made RBC 20060121
2557
store_transport.move(filename, new_name)
2558
except errors.NoSuchFile: # catches missing dirs strangely enough
2559
store_transport.mkdir(osutils.dirname(new_name))
2560
store_transport.move(filename, new_name)
2561
self.bzrdir.transport.put_bytes(
2563
BzrDirFormat6().get_format_string(),
2564
mode=self.bzrdir._get_file_mode())
2567
class ConvertBzrDir6ToMeta(Converter):
2568
"""Converts format 6 bzr dirs to metadirs."""
2570
def convert(self, to_convert, pb):
2571
"""See Converter.convert()."""
2572
from bzrlib.repofmt.weaverepo import RepositoryFormat7
2573
from bzrlib.branch import BzrBranchFormat5
2574
self.bzrdir = to_convert
2577
self.total = 20 # the steps we know about
2578
self.garbage_inventories = []
2579
self.dir_mode = self.bzrdir._get_dir_mode()
2580
self.file_mode = self.bzrdir._get_file_mode()
2582
self.pb.note('starting upgrade from format 6 to metadir')
2583
self.bzrdir.transport.put_bytes(
2585
"Converting to format 6",
2586
mode=self.file_mode)
2587
# its faster to move specific files around than to open and use the apis...
2588
# first off, nuke ancestry.weave, it was never used.
2590
self.step('Removing ancestry.weave')
2591
self.bzrdir.transport.delete('ancestry.weave')
2592
except errors.NoSuchFile:
2594
# find out whats there
2595
self.step('Finding branch files')
2596
last_revision = self.bzrdir.open_branch().last_revision()
2597
bzrcontents = self.bzrdir.transport.list_dir('.')
2598
for name in bzrcontents:
2599
if name.startswith('basis-inventory.'):
2600
self.garbage_inventories.append(name)
2601
# create new directories for repository, working tree and branch
2602
repository_names = [('inventory.weave', True),
2603
('revision-store', True),
2605
self.step('Upgrading repository ')
2606
self.bzrdir.transport.mkdir('repository', mode=self.dir_mode)
2607
self.make_lock('repository')
2608
# we hard code the formats here because we are converting into
2609
# the meta format. The meta format upgrader can take this to a
2610
# future format within each component.
2611
self.put_format('repository', RepositoryFormat7())
2612
for entry in repository_names:
2613
self.move_entry('repository', entry)
2615
self.step('Upgrading branch ')
2616
self.bzrdir.transport.mkdir('branch', mode=self.dir_mode)
2617
self.make_lock('branch')
2618
self.put_format('branch', BzrBranchFormat5())
2619
branch_files = [('revision-history', True),
2620
('branch-name', True),
2622
for entry in branch_files:
2623
self.move_entry('branch', entry)
2625
checkout_files = [('pending-merges', True),
2626
('inventory', True),
2627
('stat-cache', False)]
2628
# If a mandatory checkout file is not present, the branch does not have
2629
# a functional checkout. Do not create a checkout in the converted
2631
for name, mandatory in checkout_files:
2632
if mandatory and name not in bzrcontents:
2633
has_checkout = False
2637
if not has_checkout:
2638
self.pb.note('No working tree.')
2639
# If some checkout files are there, we may as well get rid of them.
2640
for name, mandatory in checkout_files:
2641
if name in bzrcontents:
2642
self.bzrdir.transport.delete(name)
2644
from bzrlib.workingtree import WorkingTreeFormat3
2645
self.step('Upgrading working tree')
2646
self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
2647
self.make_lock('checkout')
2649
'checkout', WorkingTreeFormat3())
2650
self.bzrdir.transport.delete_multi(
2651
self.garbage_inventories, self.pb)
2652
for entry in checkout_files:
2653
self.move_entry('checkout', entry)
2654
if last_revision is not None:
2655
self.bzrdir.transport.put_bytes(
2656
'checkout/last-revision', last_revision)
2657
self.bzrdir.transport.put_bytes(
2659
BzrDirMetaFormat1().get_format_string(),
2660
mode=self.file_mode)
2661
return BzrDir.open(self.bzrdir.root_transport.base)
2663
def make_lock(self, name):
2664
"""Make a lock for the new control dir name."""
2665
self.step('Make %s lock' % name)
2666
ld = lockdir.LockDir(self.bzrdir.transport,
2668
file_modebits=self.file_mode,
2669
dir_modebits=self.dir_mode)
2672
def move_entry(self, new_dir, entry):
2673
"""Move then entry name into new_dir."""
2675
mandatory = entry[1]
2676
self.step('Moving %s' % name)
2678
self.bzrdir.transport.move(name, '%s/%s' % (new_dir, name))
2679
except errors.NoSuchFile:
2683
def put_format(self, dirname, format):
2684
self.bzrdir.transport.put_bytes('%s/format' % dirname,
2685
format.get_format_string(),
2689
class ConvertMetaToMeta(Converter):
2690
"""Converts the components of metadirs."""
2692
def __init__(self, target_format):
2693
"""Create a metadir to metadir converter.
2695
:param target_format: The final metadir format that is desired.
2697
self.target_format = target_format
2699
def convert(self, to_convert, pb):
2700
"""See Converter.convert()."""
2701
self.bzrdir = to_convert
2705
self.step('checking repository format')
2707
repo = self.bzrdir.open_repository()
2708
except errors.NoRepositoryPresent:
2711
if not isinstance(repo._format, self.target_format.repository_format.__class__):
2712
from bzrlib.repository import CopyConverter
2713
self.pb.note('starting repository conversion')
2714
converter = CopyConverter(self.target_format.repository_format)
2715
converter.convert(repo, pb)
2717
branch = self.bzrdir.open_branch()
2718
except errors.NotBranchError:
2721
# TODO: conversions of Branch and Tree should be done by
2722
# InterXFormat lookups/some sort of registry.
2723
# Avoid circular imports
2724
from bzrlib import branch as _mod_branch
2725
old = branch._format.__class__
2726
new = self.target_format.get_branch_format().__class__
2728
if (old == _mod_branch.BzrBranchFormat5 and
2729
new in (_mod_branch.BzrBranchFormat6,
2730
_mod_branch.BzrBranchFormat7)):
2731
branch_converter = _mod_branch.Converter5to6()
2732
elif (old == _mod_branch.BzrBranchFormat6 and
2733
new == _mod_branch.BzrBranchFormat7):
2734
branch_converter = _mod_branch.Converter6to7()
2736
raise errors.BadConversionTarget("No converter", new)
2737
branch_converter.convert(branch)
2738
branch = self.bzrdir.open_branch()
2739
old = branch._format.__class__
2741
tree = self.bzrdir.open_workingtree(recommend_upgrade=False)
2742
except (errors.NoWorkingTree, errors.NotLocalUrl):
2745
# TODO: conversions of Branch and Tree should be done by
2746
# InterXFormat lookups
2747
if (isinstance(tree, workingtree.WorkingTree3) and
2748
not isinstance(tree, workingtree_4.DirStateWorkingTree) and
2749
isinstance(self.target_format.workingtree_format,
2750
workingtree_4.DirStateWorkingTreeFormat)):
2751
workingtree_4.Converter3to4().convert(tree)
2752
if (isinstance(tree, workingtree_4.DirStateWorkingTree) and
2753
not isinstance(tree, workingtree_4.WorkingTree5) and
2754
isinstance(self.target_format.workingtree_format,
2755
workingtree_4.WorkingTreeFormat5)):
2756
workingtree_4.Converter4to5().convert(tree)
2760
# This is not in remote.py because it's small, and needs to be registered.
2761
# Putting it in remote.py creates a circular import problem.
2762
# we can make it a lazy object if the control formats is turned into something
2764
class RemoteBzrDirFormat(BzrDirMetaFormat1):
2765
"""Format representing bzrdirs accessed via a smart server"""
2768
BzrDirMetaFormat1.__init__(self)
2769
self._network_name = None
2771
def get_format_description(self):
2772
return 'bzr remote bzrdir'
2774
def get_format_string(self):
2775
raise NotImplementedError(self.get_format_string)
2777
def network_name(self):
2778
if self._network_name:
2779
return self._network_name
2781
raise AssertionError("No network name set.")
2784
def probe_transport(klass, transport):
2785
"""Return a RemoteBzrDirFormat object if it looks possible."""
2787
medium = transport.get_smart_medium()
2788
except (NotImplementedError, AttributeError,
2789
errors.TransportNotPossible, errors.NoSmartMedium,
2790
errors.SmartProtocolError):
2791
# no smart server, so not a branch for this format type.
2792
raise errors.NotBranchError(path=transport.base)
2794
# Decline to open it if the server doesn't support our required
2795
# version (3) so that the VFS-based transport will do it.
2796
if medium.should_probe():
2798
server_version = medium.protocol_version()
2799
except errors.SmartProtocolError:
2800
# Apparently there's no usable smart server there, even though
2801
# the medium supports the smart protocol.
2802
raise errors.NotBranchError(path=transport.base)
2803
if server_version != '2':
2804
raise errors.NotBranchError(path=transport.base)
2807
def initialize_on_transport(self, transport):
2809
# hand off the request to the smart server
2810
client_medium = transport.get_smart_medium()
2811
except errors.NoSmartMedium:
2812
# TODO: lookup the local format from a server hint.
2813
local_dir_format = BzrDirMetaFormat1()
2814
return local_dir_format.initialize_on_transport(transport)
2815
client = _SmartClient(client_medium)
2816
path = client.remote_path_from_transport(transport)
2817
response = client.call('BzrDirFormat.initialize', path)
2818
if response[0] != 'ok':
2819
raise errors.SmartProtocolError('unexpected response code %s' % (response,))
2820
format = RemoteBzrDirFormat()
2821
self._supply_sub_formats_to(format)
2822
return remote.RemoteBzrDir(transport, format)
2824
def _open(self, transport):
2825
return remote.RemoteBzrDir(transport, self)
2827
def __eq__(self, other):
2828
if not isinstance(other, RemoteBzrDirFormat):
2830
return self.get_format_description() == other.get_format_description()
2832
def __return_repository_format(self):
2833
# Always return a RemoteRepositoryFormat object, but if a specific bzr
2834
# repository format has been asked for, tell the RemoteRepositoryFormat
2835
# that it should use that for init() etc.
2836
result = remote.RemoteRepositoryFormat()
2837
custom_format = getattr(self, '_repository_format', None)
2839
# We will use the custom format to create repositories over the
2840
# wire; expose its details like rich_root_data for code to query
2841
if isinstance(custom_format, remote.RemoteRepositoryFormat):
2842
result._custom_format = custom_format._custom_format
2844
result._custom_format = custom_format
2847
def get_branch_format(self):
2848
result = BzrDirMetaFormat1.get_branch_format(self)
2849
if not isinstance(result, remote.RemoteBranchFormat):
2850
new_result = remote.RemoteBranchFormat()
2851
new_result._custom_format = result
2853
self.set_branch_format(new_result)
2857
repository_format = property(__return_repository_format,
2858
BzrDirMetaFormat1._set_repository_format) #.im_func)
2861
BzrDirFormat.register_control_server_format(RemoteBzrDirFormat)
2864
class BzrDirFormatInfo(object):
2866
def __init__(self, native, deprecated, hidden, experimental):
2867
self.deprecated = deprecated
2868
self.native = native
2869
self.hidden = hidden
2870
self.experimental = experimental
2873
class BzrDirFormatRegistry(registry.Registry):
2874
"""Registry of user-selectable BzrDir subformats.
2876
Differs from BzrDirFormat._control_formats in that it provides sub-formats,
2877
e.g. BzrDirMeta1 with weave repository. Also, it's more user-oriented.
2881
"""Create a BzrDirFormatRegistry."""
2882
self._aliases = set()
2883
self._registration_order = list()
2884
super(BzrDirFormatRegistry, self).__init__()
2887
"""Return a set of the format names which are aliases."""
2888
return frozenset(self._aliases)
2890
def register_metadir(self, key,
2891
repository_format, help, native=True, deprecated=False,
2897
"""Register a metadir subformat.
2899
These all use a BzrDirMetaFormat1 bzrdir, but can be parameterized
2900
by the Repository/Branch/WorkingTreeformats.
2902
:param repository_format: The fully-qualified repository format class
2904
:param branch_format: Fully-qualified branch format class name as
2906
:param tree_format: Fully-qualified tree format class name as
2909
# This should be expanded to support setting WorkingTree and Branch
2910
# formats, once BzrDirMetaFormat1 supports that.
2911
def _load(full_name):
2912
mod_name, factory_name = full_name.rsplit('.', 1)
2914
mod = __import__(mod_name, globals(), locals(),
2916
except ImportError, e:
2917
raise ImportError('failed to load %s: %s' % (full_name, e))
2919
factory = getattr(mod, factory_name)
2920
except AttributeError:
2921
raise AttributeError('no factory %s in module %r'
2926
bd = BzrDirMetaFormat1()
2927
if branch_format is not None:
2928
bd.set_branch_format(_load(branch_format))
2929
if tree_format is not None:
2930
bd.workingtree_format = _load(tree_format)
2931
if repository_format is not None:
2932
bd.repository_format = _load(repository_format)
2934
self.register(key, helper, help, native, deprecated, hidden,
2935
experimental, alias)
2937
def register(self, key, factory, help, native=True, deprecated=False,
2938
hidden=False, experimental=False, alias=False):
2939
"""Register a BzrDirFormat factory.
2941
The factory must be a callable that takes one parameter: the key.
2942
It must produce an instance of the BzrDirFormat when called.
2944
This function mainly exists to prevent the info object from being
2947
registry.Registry.register(self, key, factory, help,
2948
BzrDirFormatInfo(native, deprecated, hidden, experimental))
2950
self._aliases.add(key)
2951
self._registration_order.append(key)
2953
def register_lazy(self, key, module_name, member_name, help, native=True,
2954
deprecated=False, hidden=False, experimental=False, alias=False):
2955
registry.Registry.register_lazy(self, key, module_name, member_name,
2956
help, BzrDirFormatInfo(native, deprecated, hidden, experimental))
2958
self._aliases.add(key)
2959
self._registration_order.append(key)
2961
def set_default(self, key):
2962
"""Set the 'default' key to be a clone of the supplied key.
2964
This method must be called once and only once.
2966
registry.Registry.register(self, 'default', self.get(key),
2967
self.get_help(key), info=self.get_info(key))
2968
self._aliases.add('default')
2970
def set_default_repository(self, key):
2971
"""Set the FormatRegistry default and Repository default.
2973
This is a transitional method while Repository.set_default_format
2976
if 'default' in self:
2977
self.remove('default')
2978
self.set_default(key)
2979
format = self.get('default')()
2981
def make_bzrdir(self, key):
2982
return self.get(key)()
2984
def help_topic(self, topic):
2986
default_realkey = None
2987
default_help = self.get_help('default')
2989
for key in self._registration_order:
2990
if key == 'default':
2992
help = self.get_help(key)
2993
if help == default_help:
2994
default_realkey = key
2996
help_pairs.append((key, help))
2998
def wrapped(key, help, info):
3000
help = '(native) ' + help
3001
return ':%s:\n%s\n\n' % (key,
3002
textwrap.fill(help, initial_indent=' ',
3003
subsequent_indent=' '))
3004
if default_realkey is not None:
3005
output += wrapped(default_realkey, '(default) %s' % default_help,
3006
self.get_info('default'))
3007
deprecated_pairs = []
3008
experimental_pairs = []
3009
for key, help in help_pairs:
3010
info = self.get_info(key)
3013
elif info.deprecated:
3014
deprecated_pairs.append((key, help))
3015
elif info.experimental:
3016
experimental_pairs.append((key, help))
3018
output += wrapped(key, help, info)
3019
output += "\nSee ``bzr help formats`` for more about storage formats."
3021
if len(experimental_pairs) > 0:
3022
other_output += "Experimental formats are shown below.\n\n"
3023
for key, help in experimental_pairs:
3024
info = self.get_info(key)
3025
other_output += wrapped(key, help, info)
3028
"No experimental formats are available.\n\n"
3029
if len(deprecated_pairs) > 0:
3030
other_output += "\nDeprecated formats are shown below.\n\n"
3031
for key, help in deprecated_pairs:
3032
info = self.get_info(key)
3033
other_output += wrapped(key, help, info)
3036
"\nNo deprecated formats are available.\n\n"
3038
"\nSee ``bzr help formats`` for more about storage formats."
3040
if topic == 'other-formats':
3046
class RepositoryAcquisitionPolicy(object):
3047
"""Abstract base class for repository acquisition policies.
3049
A repository acquisition policy decides how a BzrDir acquires a repository
3050
for a branch that is being created. The most basic policy decision is
3051
whether to create a new repository or use an existing one.
3053
def __init__(self, stack_on, stack_on_pwd, require_stacking):
3056
:param stack_on: A location to stack on
3057
:param stack_on_pwd: If stack_on is relative, the location it is
3059
:param require_stacking: If True, it is a failure to not stack.
3061
self._stack_on = stack_on
3062
self._stack_on_pwd = stack_on_pwd
3063
self._require_stacking = require_stacking
3065
def configure_branch(self, branch):
3066
"""Apply any configuration data from this policy to the branch.
3068
Default implementation sets repository stacking.
3070
if self._stack_on is None:
3072
if self._stack_on_pwd is None:
3073
stack_on = self._stack_on
3076
stack_on = urlutils.rebase_url(self._stack_on,
3078
branch.bzrdir.root_transport.base)
3079
except errors.InvalidRebaseURLs:
3080
stack_on = self._get_full_stack_on()
3082
branch.set_stacked_on_url(stack_on)
3083
except (errors.UnstackableBranchFormat,
3084
errors.UnstackableRepositoryFormat):
3085
if self._require_stacking:
3088
def _get_full_stack_on(self):
3089
"""Get a fully-qualified URL for the stack_on location."""
3090
if self._stack_on is None:
3092
if self._stack_on_pwd is None:
3093
return self._stack_on
3095
return urlutils.join(self._stack_on_pwd, self._stack_on)
3097
def _add_fallback(self, repository, possible_transports=None):
3098
"""Add a fallback to the supplied repository, if stacking is set."""
3099
stack_on = self._get_full_stack_on()
3100
if stack_on is None:
3102
stacked_dir = BzrDir.open(stack_on,
3103
possible_transports=possible_transports)
3105
stacked_repo = stacked_dir.open_branch().repository
3106
except errors.NotBranchError:
3107
stacked_repo = stacked_dir.open_repository()
3109
repository.add_fallback_repository(stacked_repo)
3110
except errors.UnstackableRepositoryFormat:
3111
if self._require_stacking:
3114
self._require_stacking = True
3116
def acquire_repository(self, make_working_trees=None, shared=False):
3117
"""Acquire a repository for this bzrdir.
3119
Implementations may create a new repository or use a pre-exising
3121
:param make_working_trees: If creating a repository, set
3122
make_working_trees to this value (if non-None)
3123
:param shared: If creating a repository, make it shared if True
3124
:return: A repository, is_new_flag (True if the repository was
3127
raise NotImplemented(RepositoryAcquisitionPolicy.acquire_repository)
3130
class CreateRepository(RepositoryAcquisitionPolicy):
3131
"""A policy of creating a new repository"""
3133
def __init__(self, bzrdir, stack_on=None, stack_on_pwd=None,
3134
require_stacking=False):
3137
:param bzrdir: The bzrdir to create the repository on.
3138
:param stack_on: A location to stack on
3139
:param stack_on_pwd: If stack_on is relative, the location it is
3142
RepositoryAcquisitionPolicy.__init__(self, stack_on, stack_on_pwd,
3144
self._bzrdir = bzrdir
3146
def acquire_repository(self, make_working_trees=None, shared=False):
3147
"""Implementation of RepositoryAcquisitionPolicy.acquire_repository
3149
Creates the desired repository in the bzrdir we already have.
3151
repository = self._bzrdir.create_repository(shared=shared)
3152
self._add_fallback(repository,
3153
possible_transports=[self._bzrdir.transport])
3154
if make_working_trees is not None:
3155
repository.set_make_working_trees(make_working_trees)
3156
return repository, True
3159
class UseExistingRepository(RepositoryAcquisitionPolicy):
3160
"""A policy of reusing an existing repository"""
3162
def __init__(self, repository, stack_on=None, stack_on_pwd=None,
3163
require_stacking=False):
3166
:param repository: The repository to use.
3167
:param stack_on: A location to stack on
3168
:param stack_on_pwd: If stack_on is relative, the location it is
3171
RepositoryAcquisitionPolicy.__init__(self, stack_on, stack_on_pwd,
3173
self._repository = repository
3175
def acquire_repository(self, make_working_trees=None, shared=False):
3176
"""Implementation of RepositoryAcquisitionPolicy.acquire_repository
3178
Returns an existing repository to use.
3180
self._add_fallback(self._repository,
3181
possible_transports=[self._repository.bzrdir.transport])
3182
return self._repository, False
3185
# Please register new formats after old formats so that formats
3186
# appear in chronological order and format descriptions can build
3188
format_registry = BzrDirFormatRegistry()
3189
# The pre-0.8 formats have their repository format network name registered in
3190
# repository.py. MetaDir formats have their repository format network name
3191
# inferred from their disk format string.
3192
format_registry.register('weave', BzrDirFormat6,
3193
'Pre-0.8 format. Slower than knit and does not'
3194
' support checkouts or shared repositories.',
3196
format_registry.register_metadir('metaweave',
3197
'bzrlib.repofmt.weaverepo.RepositoryFormat7',
3198
'Transitional format in 0.8. Slower than knit.',
3199
branch_format='bzrlib.branch.BzrBranchFormat5',
3200
tree_format='bzrlib.workingtree.WorkingTreeFormat3',
3202
format_registry.register_metadir('knit',
3203
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
3204
'Format using knits. Recommended for interoperation with bzr <= 0.14.',
3205
branch_format='bzrlib.branch.BzrBranchFormat5',
3206
tree_format='bzrlib.workingtree.WorkingTreeFormat3',
3208
format_registry.register_metadir('dirstate',
3209
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
3210
help='New in 0.15: Fast local operations. Compatible with bzr 0.8 and '
3211
'above when accessed over the network.',
3212
branch_format='bzrlib.branch.BzrBranchFormat5',
3213
# this uses bzrlib.workingtree.WorkingTreeFormat4 because importing
3214
# directly from workingtree_4 triggers a circular import.
3215
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3217
format_registry.register_metadir('dirstate-tags',
3218
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
3219
help='New in 0.15: Fast local operations and improved scaling for '
3220
'network operations. Additionally adds support for tags.'
3221
' Incompatible with bzr < 0.15.',
3222
branch_format='bzrlib.branch.BzrBranchFormat6',
3223
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3225
format_registry.register_metadir('rich-root',
3226
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit4',
3227
help='New in 1.0. Better handling of tree roots. Incompatible with'
3229
branch_format='bzrlib.branch.BzrBranchFormat6',
3230
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3232
format_registry.register_metadir('dirstate-with-subtree',
3233
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
3234
help='New in 0.15: Fast local operations and improved scaling for '
3235
'network operations. Additionally adds support for versioning nested '
3236
'bzr branches. Incompatible with bzr < 0.15.',
3237
branch_format='bzrlib.branch.BzrBranchFormat6',
3238
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3242
format_registry.register_metadir('pack-0.92',
3243
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack1',
3244
help='New in 0.92: Pack-based format with data compatible with '
3245
'dirstate-tags format repositories. Interoperates with '
3246
'bzr repositories before 0.92 but cannot be read by bzr < 0.92. '
3247
'Previously called knitpack-experimental. '
3248
'For more information, see '
3249
'http://doc.bazaar-vcs.org/latest/developers/packrepo.html.',
3250
branch_format='bzrlib.branch.BzrBranchFormat6',
3251
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3253
format_registry.register_metadir('pack-0.92-subtree',
3254
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack3',
3255
help='New in 0.92: Pack-based format with data compatible with '
3256
'dirstate-with-subtree format repositories. Interoperates with '
3257
'bzr repositories before 0.92 but cannot be read by bzr < 0.92. '
3258
'Previously called knitpack-experimental. '
3259
'For more information, see '
3260
'http://doc.bazaar-vcs.org/latest/developers/packrepo.html.',
3261
branch_format='bzrlib.branch.BzrBranchFormat6',
3262
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3266
format_registry.register_metadir('rich-root-pack',
3267
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack4',
3268
help='New in 1.0: A variant of pack-0.92 that supports rich-root data '
3269
'(needed for bzr-svn and bzr-git).',
3270
branch_format='bzrlib.branch.BzrBranchFormat6',
3271
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3273
format_registry.register_metadir('1.6',
3274
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack5',
3275
help='A format that allows a branch to indicate that there is another '
3276
'(stacked) repository that should be used to access data that is '
3277
'not present locally.',
3278
branch_format='bzrlib.branch.BzrBranchFormat7',
3279
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3281
format_registry.register_metadir('1.6.1-rich-root',
3282
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack5RichRoot',
3283
help='A variant of 1.6 that supports rich-root data '
3284
'(needed for bzr-svn and bzr-git).',
3285
branch_format='bzrlib.branch.BzrBranchFormat7',
3286
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3288
format_registry.register_metadir('1.9',
3289
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack6',
3290
help='A repository format using B+tree indexes. These indexes '
3291
'are smaller in size, have smarter caching and provide faster '
3292
'performance for most operations.',
3293
branch_format='bzrlib.branch.BzrBranchFormat7',
3294
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3296
format_registry.register_metadir('1.9-rich-root',
3297
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack6RichRoot',
3298
help='A variant of 1.9 that supports rich-root data '
3299
'(needed for bzr-svn and bzr-git).',
3300
branch_format='bzrlib.branch.BzrBranchFormat7',
3301
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3303
format_registry.register_metadir('development-wt5',
3304
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack6',
3305
help='A working-tree format that supports views and content filtering.',
3306
branch_format='bzrlib.branch.BzrBranchFormat7',
3307
tree_format='bzrlib.workingtree.WorkingTreeFormat5',
3310
format_registry.register_metadir('development-wt5-rich-root',
3311
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack6RichRoot',
3312
help='A variant of development-wt5 that supports rich-root data '
3313
'(needed for bzr-svn and bzr-git).',
3314
branch_format='bzrlib.branch.BzrBranchFormat7',
3315
tree_format='bzrlib.workingtree.WorkingTreeFormat5',
3318
# The following two formats should always just be aliases.
3319
format_registry.register_metadir('development',
3320
'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment2',
3321
help='Current development format. Can convert data to and from pack-0.92 '
3322
'(and anything compatible with pack-0.92) format repositories. '
3323
'Repositories and branches in this format can only be read by bzr.dev. '
3325
'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
3327
branch_format='bzrlib.branch.BzrBranchFormat7',
3328
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3332
format_registry.register_metadir('development-subtree',
3333
'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment2Subtree',
3334
help='Current development format, subtree variant. Can convert data to and '
3335
'from pack-0.92-subtree (and anything compatible with '
3336
'pack-0.92-subtree) format repositories. Repositories and branches in '
3337
'this format can only be read by bzr.dev. Please read '
3338
'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
3340
branch_format='bzrlib.branch.BzrBranchFormat7',
3341
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3345
# And the development formats above will have aliased one of the following:
3346
format_registry.register_metadir('development2',
3347
'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment2',
3348
help='1.6.1 with B+Tree based index. '
3350
'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
3352
branch_format='bzrlib.branch.BzrBranchFormat7',
3353
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3357
format_registry.register_metadir('development2-subtree',
3358
'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment2Subtree',
3359
help='1.6.1-subtree with B+Tree based index. '
3361
'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
3363
branch_format='bzrlib.branch.BzrBranchFormat7',
3364
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3368
# The following format should be an alias for the rich root equivalent
3369
# of the default format
3370
format_registry.register_metadir('default-rich-root',
3371
'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack4',
3372
help='Default format, rich root variant. (needed for bzr-svn and bzr-git).',
3373
branch_format='bzrlib.branch.BzrBranchFormat6',
3374
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3377
# The current format that is made on 'bzr init'.
3378
format_registry.set_default('pack-0.92')