1
# Copyright (C) 2006-2011 Canonical Ltd
1
# Copyright (C) 2005, 2006 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
11
# GNU General Public License for more details.
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
17
"""BzrDir logic. The BzrDir is the basic control directory used by bzr.
19
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
from __future__ import absolute_import
32
from bzrlib.lazy_import import lazy_import
33
lazy_import(globals(), """
23
from copy import deepcopy
25
from cStringIO import StringIO
26
from unittest import TestSuite
36
branch as _mod_branch,
47
revision as _mod_revision,
48
transport as _mod_transport,
56
from bzrlib.repofmt import knitpack_repo
57
from bzrlib.transport import (
58
do_catching_redirections,
61
from bzrlib.i18n import gettext
64
from bzrlib.trace import (
74
from bzrlib.symbol_versioning import (
80
class BzrDir(controldir.ControlDir):
29
import bzrlib.errors as errors
30
from bzrlib.lockable_files import LockableFiles, TransportLock
31
from bzrlib.lockdir import LockDir
32
from bzrlib.osutils import safe_unicode
33
from bzrlib.osutils import (
40
from bzrlib.store.revision.text import TextRevisionStore
41
from bzrlib.store.text import TextStore
42
from bzrlib.store.versioned import WeaveStore
43
from bzrlib.symbol_versioning import *
44
from bzrlib.trace import mutter
45
from bzrlib.transactions import WriteTransaction
46
from bzrlib.transport import get_transport
47
from bzrlib.transport.local import LocalTransport
48
from bzrlib.weave import Weave
49
from bzrlib.xml4 import serializer_v4
50
from bzrlib.xml5 import serializer_v5
81
54
"""A .bzr control diretory.
83
56
BzrDir instances let you create or open any of the things that can be
84
57
found within .bzr - checkouts, branches and repositories.
87
60
the transport which this bzr dir is rooted at (i.e. file:///.../.bzr/)
89
a transport connected to the directory this bzr was opened from
90
(i.e. the parent directory holding the .bzr directory).
92
Everything in the bzrdir should have the same file permissions.
94
:cvar hooks: An instance of BzrDirHooks.
62
a transport connected to the directory this bzr was opened from.
98
"""Invoke break_lock on the first object in the bzrdir.
100
If there is a tree, the tree is opened and break_lock() called.
101
Otherwise, branch is tried, and finally repository.
65
def can_convert_format(self):
66
"""Return true if this bzrdir is one whose format we can convert from."""
70
def _check_supported(format, allow_unsupported):
71
"""Check whether format is a supported format.
73
If allow_unsupported is True, this is a no-op.
103
# XXX: This seems more like a UI function than something that really
104
# belongs in this class.
106
thing_to_unlock = self.open_workingtree()
107
except (errors.NotLocalUrl, errors.NoWorkingTree):
109
thing_to_unlock = self.open_branch()
110
except errors.NotBranchError:
112
thing_to_unlock = self.open_repository()
113
except errors.NoRepositoryPresent:
115
thing_to_unlock.break_lock()
117
def check_conversion_target(self, target_format):
118
"""Check that a bzrdir as a whole can be converted to a new format."""
119
# The only current restriction is that the repository content can be
120
# fetched compatibly with the target.
121
target_repo_format = target_format.repository_format
123
self.open_repository()._format.check_conversion_target(
125
except errors.NoRepositoryPresent:
126
# No repo, no problem.
129
def clone_on_transport(self, transport, revision_id=None,
130
force_new_repo=False, preserve_stacking=False, stacked_on=None,
131
create_prefix=False, use_existing_dir=True, no_tree=False):
132
"""Clone this bzrdir and its contents to transport verbatim.
134
:param transport: The transport for the location to produce the clone
135
at. If the target directory does not exist, it will be created.
136
:param revision_id: The tip revision-id to use for any branch or
137
working tree. If not None, then the clone operation may tune
75
if not allow_unsupported and not format.is_supported():
76
# see open_downlevel to open legacy branches.
77
raise errors.UnsupportedFormatError(
78
'sorry, format %s not supported' % format,
79
['use a different bzr version',
80
'or remove the .bzr directory'
81
' and "bzr init" again'])
83
def clone(self, url, revision_id=None, basis=None, force_new_repo=False):
84
"""Clone this bzrdir and its contents to url verbatim.
86
If urls last component does not exist, it will be created.
88
if revision_id is not None, then the clone operation may tune
138
89
itself to download less data.
139
:param force_new_repo: Do not use a shared repository for the target,
90
:param force_new_repo: Do not use a shared repository for the target
140
91
even if one is available.
141
:param preserve_stacking: When cloning a stacked branch, stack the
142
new branch on top of the other branch's stacked-on branch.
143
:param create_prefix: Create any missing directories leading up to
145
:param use_existing_dir: Use an existing directory if one exists.
146
:param no_tree: If set to true prevents creation of a working tree.
148
# Overview: put together a broad description of what we want to end up
149
# with; then make as few api calls as possible to do it.
151
# We may want to create a repo/branch/tree, if we do so what format
152
# would we want for each:
153
require_stacking = (stacked_on is not None)
154
format = self.cloning_metadir(require_stacking)
156
# Figure out what objects we want:
94
basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
95
result = self._format.initialize(url)
158
97
local_repo = self.find_repository()
159
98
except errors.NoRepositoryPresent:
162
local_branch = self.open_branch()
163
except errors.NotBranchError:
166
# enable fallbacks when branch is not a branch reference
167
if local_branch.repository.has_same_location(local_repo):
168
local_repo = local_branch.repository
169
if preserve_stacking:
171
stacked_on = local_branch.get_stacked_on_url()
172
except (errors.UnstackableBranchFormat,
173
errors.UnstackableRepositoryFormat,
176
# Bug: We create a metadir without knowing if it can support stacking,
177
# we should look up the policy needs first, or just use it as a hint,
180
make_working_trees = local_repo.make_working_trees() and not no_tree
181
want_shared = local_repo.is_shared()
182
repo_format_name = format.repository_format.network_name()
184
make_working_trees = False
186
repo_format_name = None
188
result_repo, result, require_stacking, repository_policy = \
189
format.initialize_on_transport_ex(transport,
190
use_existing_dir=use_existing_dir, create_prefix=create_prefix,
191
force_new_repo=force_new_repo, stacked_on=stacked_on,
192
stack_on_pwd=self.root_transport.base,
193
repo_format_name=repo_format_name,
194
make_working_trees=make_working_trees, shared_repo=want_shared)
197
# If the result repository is in the same place as the
198
# resulting bzr dir, it will have no content, further if the
199
# result is not stacked then we know all content should be
200
# copied, and finally if we are copying up to a specific
201
# revision_id then we can use the pending-ancestry-result which
202
# does not require traversing all of history to describe it.
203
if (result_repo.user_url == result.user_url
204
and not require_stacking and
205
revision_id is not None):
206
fetch_spec = vf_search.PendingAncestryResult(
207
[revision_id], local_repo)
208
result_repo.fetch(local_repo, fetch_spec=fetch_spec)
101
# may need to copy content in
103
local_repo.clone(result, revision_id=revision_id, basis=basis_repo)
106
result_repo = result.find_repository()
107
# fetch content this dir needs.
109
# XXX FIXME RBC 20060214 need tests for this when the basis
111
result_repo.fetch(basis_repo, revision_id=revision_id)
210
112
result_repo.fetch(local_repo, revision_id=revision_id)
214
if result_repo is not None:
215
raise AssertionError('result_repo not None(%r)' % result_repo)
113
except errors.NoRepositoryPresent:
114
# needed to make one anyway.
115
local_repo.clone(result, revision_id=revision_id, basis=basis_repo)
216
116
# 1 if there is a branch present
217
117
# make sure its content is available in the target repository
219
if local_branch is not None:
220
result_branch = local_branch.clone(result, revision_id=revision_id,
221
repository_policy=repository_policy)
223
# Cheaper to check if the target is not local, than to try making
225
result.root_transport.local_abspath('.')
226
if result_repo is None or result_repo.make_working_trees():
227
self.open_workingtree().clone(result, revision_id=revision_id)
120
self.open_branch().clone(result, revision_id=revision_id)
121
except errors.NotBranchError:
124
self.open_workingtree().clone(result, basis=basis_tree)
228
125
except (errors.NoWorkingTree, errors.NotLocalUrl):
232
# TODO: This should be given a Transport, and should chdir up; otherwise
233
# this will open a new connection.
129
def _get_basis_components(self, basis):
130
"""Retrieve the basis components that are available at basis."""
132
return None, None, None
134
basis_tree = basis.open_workingtree()
135
basis_branch = basis_tree.branch
136
basis_repo = basis_branch.repository
137
except (errors.NoWorkingTree, errors.NotLocalUrl):
140
basis_branch = basis.open_branch()
141
basis_repo = basis_branch.repository
142
except errors.NotBranchError:
145
basis_repo = basis.open_repository()
146
except errors.NoRepositoryPresent:
148
return basis_repo, basis_branch, basis_tree
234
150
def _make_tail(self, url):
235
t = _mod_transport.get_transport(url)
238
def determine_repository_policy(self, force_new_repo=False, stack_on=None,
239
stack_on_pwd=None, require_stacking=False):
240
"""Return an object representing a policy to use.
242
This controls whether a new repository is created, and the format of
243
that repository, or some existing shared repository used instead.
245
If stack_on is supplied, will not seek a containing shared repo.
247
:param force_new_repo: If True, require a new repository to be created.
248
:param stack_on: If supplied, the location to stack on. If not
249
supplied, a default_stack_on location may be used.
250
:param stack_on_pwd: If stack_on is relative, the location it is
253
def repository_policy(found_bzrdir):
256
config = found_bzrdir.get_config()
258
stack_on = config.get_default_stack_on()
259
if stack_on is not None:
260
stack_on_pwd = found_bzrdir.user_url
262
# does it have a repository ?
264
repository = found_bzrdir.open_repository()
265
except errors.NoRepositoryPresent:
268
if (found_bzrdir.user_url != self.user_url
269
and not repository.is_shared()):
270
# Don't look higher, can't use a higher shared repo.
278
return UseExistingRepository(repository, stack_on,
279
stack_on_pwd, require_stacking=require_stacking), True
281
return CreateRepository(self, stack_on, stack_on_pwd,
282
require_stacking=require_stacking), True
284
if not force_new_repo:
286
policy = self._find_containing(repository_policy)
287
if policy is not None:
291
return UseExistingRepository(self.open_repository(),
292
stack_on, stack_on_pwd,
293
require_stacking=require_stacking)
294
except errors.NoRepositoryPresent:
296
return CreateRepository(self, stack_on, stack_on_pwd,
297
require_stacking=require_stacking)
151
segments = url.split('/')
152
if segments and segments[-1] not in ('', '.'):
153
parent = '/'.join(segments[:-1])
154
t = bzrlib.transport.get_transport(parent)
156
t.mkdir(segments[-1])
157
except errors.FileExists:
161
def create(cls, base):
162
"""Create a new BzrDir at the url 'base'.
164
This will call the current default formats initialize with base
165
as the only parameter.
167
If you need a specific format, consider creating an instance
168
of that and calling initialize().
170
if cls is not BzrDir:
171
raise AssertionError("BzrDir.create always creates the default format, "
172
"not one of %r" % cls)
173
segments = base.split('/')
174
if segments and segments[-1] not in ('', '.'):
175
parent = '/'.join(segments[:-1])
176
t = bzrlib.transport.get_transport(parent)
178
t.mkdir(segments[-1])
179
except errors.FileExists:
181
return BzrDirFormat.get_default_format().initialize(safe_unicode(base))
183
def create_branch(self):
184
"""Create a branch in this BzrDir.
186
The bzrdirs format will control what branch format is created.
187
For more control see BranchFormatXX.create(a_bzrdir).
189
raise NotImplementedError(self.create_branch)
192
def create_branch_and_repo(base, force_new_repo=False):
193
"""Create a new BzrDir, Branch and Repository at the url 'base'.
195
This will use the current default BzrDirFormat, and use whatever
196
repository format that that uses via bzrdir.create_branch and
197
create_repository. If a shared repository is available that is used
200
The created Branch object is returned.
202
:param base: The URL to create the branch at.
203
:param force_new_repo: If True a new repository is always created.
205
bzrdir = BzrDir.create(base)
206
bzrdir._find_or_create_repository(force_new_repo)
207
return bzrdir.create_branch()
299
209
def _find_or_create_repository(self, force_new_repo):
300
210
"""Create a new repository if needed, returning the repository."""
301
policy = self.determine_repository_policy(force_new_repo)
302
return policy.acquire_repository()[0]
304
def _find_source_repo(self, add_cleanup, source_branch):
305
"""Find the source branch and repo for a sprout operation.
212
return self.create_repository()
214
return self.find_repository()
215
except errors.NoRepositoryPresent:
216
return self.create_repository()
307
This is helper intended for use by _sprout.
309
:returns: (source_branch, source_repository). Either or both may be
310
None. If not None, they will be read-locked (and their unlock(s)
311
scheduled via the add_cleanup param).
313
if source_branch is not None:
314
add_cleanup(source_branch.lock_read().unlock)
315
return source_branch, source_branch.repository
317
source_branch = self.open_branch()
318
source_repository = source_branch.repository
319
except errors.NotBranchError:
322
source_repository = self.open_repository()
323
except errors.NoRepositoryPresent:
324
source_repository = None
326
add_cleanup(source_repository.lock_read().unlock)
328
add_cleanup(source_branch.lock_read().unlock)
329
return source_branch, source_repository
331
def sprout(self, url, revision_id=None, force_new_repo=False,
332
recurse='down', possible_transports=None,
333
accelerator_tree=None, hardlink=False, stacked=False,
334
source_branch=None, create_tree_if_local=True):
335
"""Create a copy of this controldir prepared for use as a new line of
338
If url's last component does not exist, it will be created.
340
Attributes related to the identity of the source branch like
341
branch nickname will be cleaned, a working tree is created
342
whether one existed before or not; and a local branch is always
345
if revision_id is not None, then the clone operation may tune
346
itself to download less data.
348
:param accelerator_tree: A tree which can be used for retrieving file
349
contents more quickly than the revision tree, i.e. a workingtree.
350
The revision tree will be used for cases where accelerator_tree's
351
content is different.
352
:param hardlink: If true, hard-link files from accelerator_tree,
354
:param stacked: If true, create a stacked branch referring to the
355
location of this control directory.
356
:param create_tree_if_local: If true, a working-tree will be created
357
when working locally.
358
:return: The created control directory
360
operation = cleanup.OperationWithCleanups(self._sprout)
361
return operation.run(url, revision_id=revision_id,
362
force_new_repo=force_new_repo, recurse=recurse,
363
possible_transports=possible_transports,
364
accelerator_tree=accelerator_tree, hardlink=hardlink,
365
stacked=stacked, source_branch=source_branch,
366
create_tree_if_local=create_tree_if_local)
368
def _sprout(self, op, url, revision_id=None, force_new_repo=False,
369
recurse='down', possible_transports=None,
370
accelerator_tree=None, hardlink=False, stacked=False,
371
source_branch=None, create_tree_if_local=True):
372
add_cleanup = op.add_cleanup
373
fetch_spec_factory = fetch.FetchSpecFactory()
374
if revision_id is not None:
375
fetch_spec_factory.add_revision_ids([revision_id])
376
fetch_spec_factory.source_branch_stop_revision_id = revision_id
377
if possible_transports is None:
378
possible_transports = []
380
possible_transports = list(possible_transports) + [
382
target_transport = _mod_transport.get_transport(url,
384
target_transport.ensure_base()
385
cloning_format = self.cloning_metadir(stacked)
386
# Create/update the result branch
388
result = controldir.ControlDir.open_from_transport(target_transport)
389
except errors.NotBranchError:
390
result = cloning_format.initialize_on_transport(target_transport)
391
source_branch, source_repository = self._find_source_repo(
392
add_cleanup, source_branch)
393
fetch_spec_factory.source_branch = source_branch
394
# if a stacked branch wasn't requested, we don't create one
395
# even if the origin was stacked
396
if stacked and source_branch is not None:
397
stacked_branch_url = self.root_transport.base
399
stacked_branch_url = None
400
repository_policy = result.determine_repository_policy(
401
force_new_repo, stacked_branch_url, require_stacking=stacked)
402
result_repo, is_new_repo = repository_policy.acquire_repository(
403
possible_transports=possible_transports)
404
add_cleanup(result_repo.lock_write().unlock)
405
fetch_spec_factory.source_repo = source_repository
406
fetch_spec_factory.target_repo = result_repo
407
if stacked or (len(result_repo._fallback_repositories) != 0):
408
target_repo_kind = fetch.TargetRepoKinds.STACKED
410
target_repo_kind = fetch.TargetRepoKinds.EMPTY
412
target_repo_kind = fetch.TargetRepoKinds.PREEXISTING
413
fetch_spec_factory.target_repo_kind = target_repo_kind
414
if source_repository is not None:
415
fetch_spec = fetch_spec_factory.make_fetch_spec()
416
result_repo.fetch(source_repository, fetch_spec=fetch_spec)
418
if source_branch is None:
419
# this is for sprouting a controldir without a branch; is that
421
# Not especially, but it's part of the contract.
422
result_branch = result.create_branch()
424
result_branch = source_branch.sprout(result,
425
revision_id=revision_id, repository_policy=repository_policy,
426
repository=result_repo)
427
mutter("created new branch %r" % (result_branch,))
429
# Create/update the result working tree
430
if (create_tree_if_local and not result.has_workingtree() and
431
isinstance(target_transport, local.LocalTransport) and
432
(result_repo is None or result_repo.make_working_trees())):
433
wt = result.create_workingtree(accelerator_tree=accelerator_tree,
434
hardlink=hardlink, from_branch=result_branch)
437
if wt.path2id('') is None:
439
wt.set_root_id(self.open_workingtree.get_root_id())
440
except errors.NoWorkingTree:
446
if recurse == 'down':
449
basis = wt.basis_tree()
450
elif result_branch is not None:
451
basis = result_branch.basis_tree()
452
elif source_branch is not None:
453
basis = source_branch.basis_tree()
454
if basis is not None:
455
add_cleanup(basis.lock_read().unlock)
456
subtrees = basis.iter_references()
459
for path, file_id in subtrees:
460
target = urlutils.join(url, urlutils.escape(path))
461
sublocation = source_branch.reference_parent(file_id, path)
462
sublocation.bzrdir.sprout(target,
463
basis.get_reference_revision(file_id, path),
464
force_new_repo=force_new_repo, recurse=recurse,
219
def create_branch_convenience(base, force_new_repo=False, force_new_tree=None):
220
"""Create a new BzrDir, Branch and Repository at the url 'base'.
222
This is a convenience function - it will use an existing repository
223
if possible, can be told explicitly whether to create a working tree or
226
This will use the current default BzrDirFormat, and use whatever
227
repository format that that uses via bzrdir.create_branch and
228
create_repository. If a shared repository is available that is used
229
preferentially. Whatever repository is used, its tree creation policy
232
The created Branch object is returned.
233
If a working tree cannot be made due to base not being a file:// url,
234
no error is raised unless force_new_tree is True, in which case no
235
data is created on disk and NotLocalUrl is raised.
237
:param base: The URL to create the branch at.
238
:param force_new_repo: If True a new repository is always created.
239
:param force_new_tree: If True or False force creation of a tree or
240
prevent such creation respectively.
243
# check for non local urls
244
t = get_transport(safe_unicode(base))
245
if not isinstance(t, LocalTransport):
246
raise errors.NotLocalUrl(base)
247
bzrdir = BzrDir.create(base)
248
repo = bzrdir._find_or_create_repository(force_new_repo)
249
result = bzrdir.create_branch()
250
if force_new_tree or (repo.make_working_trees() and
251
force_new_tree is None):
253
bzrdir.create_workingtree()
254
except errors.NotLocalUrl:
468
def _available_backup_name(self, base):
469
"""Find a non-existing backup file name based on base.
471
See bzrlib.osutils.available_backup_name about race conditions.
473
return osutils.available_backup_name(base, self.root_transport.has)
475
def backup_bzrdir(self):
476
"""Backup this bzr control directory.
478
:return: Tuple with old path name and new path name
481
pb = ui.ui_factory.nested_progress_bar()
483
old_path = self.root_transport.abspath('.bzr')
484
backup_dir = self._available_backup_name('backup.bzr')
485
new_path = self.root_transport.abspath(backup_dir)
486
ui.ui_factory.note(gettext('making backup of {0}\n to {1}').format(
487
urlutils.unescape_for_display(old_path, 'utf-8'),
488
urlutils.unescape_for_display(new_path, 'utf-8')))
489
self.root_transport.copy_tree('.bzr', backup_dir)
490
return (old_path, new_path)
494
def retire_bzrdir(self, limit=10000):
495
"""Permanently disable the bzrdir.
497
This is done by renaming it to give the user some ability to recover
498
if there was a problem.
500
This will have horrible consequences if anyone has anything locked or
502
:param limit: number of times to retry
507
to_path = '.bzr.retired.%d' % i
508
self.root_transport.rename('.bzr', to_path)
509
note(gettext("renamed {0} to {1}").format(
510
self.root_transport.abspath('.bzr'), to_path))
512
except (errors.TransportError, IOError, errors.PathError):
519
def _find_containing(self, evaluate):
520
"""Find something in a containing control directory.
522
This method will scan containing control dirs, until it finds what
523
it is looking for, decides that it will never find it, or runs out
524
of containing control directories to check.
526
It is used to implement find_repository and
527
determine_repository_policy.
529
:param evaluate: A function returning (value, stop). If stop is True,
530
the value will be returned.
534
result, stop = evaluate(found_bzrdir)
537
next_transport = found_bzrdir.root_transport.clone('..')
538
if (found_bzrdir.user_url == next_transport.base):
539
# top of the file system
541
# find the next containing bzrdir
543
found_bzrdir = self.open_containing_from_transport(
545
except errors.NotBranchError:
259
def create_repository(base, shared=False):
260
"""Create a new BzrDir and Repository at the url 'base'.
262
This will use the current default BzrDirFormat, and use whatever
263
repository format that that uses for bzrdirformat.create_repository.
265
;param shared: Create a shared repository rather than a standalone
267
The Repository object is returned.
269
This must be overridden as an instance method in child classes, where
270
it should take no parameters and construct whatever repository format
271
that child class desires.
273
bzrdir = BzrDir.create(base)
274
return bzrdir.create_repository()
277
def create_standalone_workingtree(base):
278
"""Create a new BzrDir, WorkingTree, Branch and Repository at 'base'.
280
'base' must be a local path or a file:// url.
282
This will use the current default BzrDirFormat, and use whatever
283
repository format that that uses for bzrdirformat.create_workingtree,
284
create_branch and create_repository.
286
The WorkingTree object is returned.
288
t = get_transport(safe_unicode(base))
289
if not isinstance(t, LocalTransport):
290
raise errors.NotLocalUrl(base)
291
bzrdir = BzrDir.create_branch_and_repo(safe_unicode(base),
292
force_new_repo=True).bzrdir
293
return bzrdir.create_workingtree()
295
def create_workingtree(self, revision_id=None):
296
"""Create a working tree at this BzrDir.
298
revision_id: create it as of this revision id.
300
raise NotImplementedError(self.create_workingtree)
548
302
def find_repository(self):
549
"""Find the repository that should be used.
303
"""Find the repository that should be used for a_bzrdir.
551
305
This does not require a branch as we use it to find the repo for
552
306
new branches as well as to hook existing branches up to their
555
def usable_repository(found_bzrdir):
556
# does it have a repository ?
310
return self.open_repository()
311
except errors.NoRepositoryPresent:
313
next_transport = self.root_transport.clone('..')
316
found_bzrdir = BzrDir.open_containing_from_transport(
318
except errors.NotBranchError:
319
raise errors.NoRepositoryPresent(self)
558
321
repository = found_bzrdir.open_repository()
559
322
except errors.NoRepositoryPresent:
561
if found_bzrdir.user_url == self.user_url:
562
return repository, True
563
elif repository.is_shared():
564
return repository, True
568
found_repo = self._find_containing(usable_repository)
569
if found_repo is None:
570
raise errors.NoRepositoryPresent(self)
573
def _find_creation_modes(self):
574
"""Determine the appropriate modes for files and directories.
576
They're always set to be consistent with the base directory,
577
assuming that this transport allows setting modes.
579
# TODO: Do we need or want an option (maybe a config setting) to turn
580
# this off or override it for particular locations? -- mbp 20080512
581
if self._mode_check_done:
583
self._mode_check_done = True
585
st = self.transport.stat('.')
586
except errors.TransportNotPossible:
587
self._dir_mode = None
588
self._file_mode = None
590
# Check the directory mode, but also make sure the created
591
# directories and files are read-write for this user. This is
592
# mostly a workaround for filesystems which lie about being able to
593
# write to a directory (cygwin & win32)
594
if (st.st_mode & 07777 == 00000):
595
# FTP allows stat but does not return dir/file modes
596
self._dir_mode = None
597
self._file_mode = None
599
self._dir_mode = (st.st_mode & 07777) | 00700
600
# Remove the sticky and execute bits for files
601
self._file_mode = self._dir_mode & ~07111
603
def _get_file_mode(self):
604
"""Return Unix mode for newly created files, or None.
606
if not self._mode_check_done:
607
self._find_creation_modes()
608
return self._file_mode
610
def _get_dir_mode(self):
611
"""Return Unix mode for newly created directories, or None.
613
if not self._mode_check_done:
614
self._find_creation_modes()
615
return self._dir_mode
617
def get_config(self):
618
"""Get configuration for this BzrDir."""
619
return config.BzrDirConfig(self)
621
def _get_config(self):
622
"""By default, no configuration is available."""
625
def __init__(self, _transport, _format):
626
"""Initialize a Bzr control dir object.
628
Only really common logic should reside here, concrete classes should be
629
made with varying behaviours.
631
:param _format: the format that is creating this BzrDir instance.
632
:param _transport: the transport this dir is based at.
634
self._format = _format
635
# these are also under the more standard names of
636
# control_transport and user_transport
637
self.transport = _transport.clone('.bzr')
638
self.root_transport = _transport
639
self._mode_check_done = False
642
def user_transport(self):
643
return self.root_transport
646
def control_transport(self):
647
return self.transport
649
def is_control_filename(self, filename):
650
"""True if filename is the name of a path which is reserved for bzrdir's.
652
:param filename: A filename within the root transport of this bzrdir.
654
This is true IF and ONLY IF the filename is part of the namespace reserved
655
for bzr control dirs. Currently this is the '.bzr' directory in the root
656
of the root_transport.
658
# this might be better on the BzrDirFormat class because it refers to
659
# all the possible bzrdir disk formats.
660
# This method is tested via the workingtree is_control_filename tests-
661
# it was extracted from WorkingTree.is_control_filename. If the method's
662
# contract is extended beyond the current trivial implementation, please
663
# add new tests for it to the appropriate place.
664
return filename == '.bzr' or filename.startswith('.bzr/')
666
def _cloning_metadir(self):
667
"""Produce a metadir suitable for cloning with.
669
:returns: (destination_bzrdir_format, source_repository)
671
result_format = self._format.__class__()
674
branch = self.open_branch(ignore_fallbacks=True)
675
source_repository = branch.repository
676
result_format._branch_format = branch._format
677
except errors.NotBranchError:
679
source_repository = self.open_repository()
680
except errors.NoRepositoryPresent:
681
source_repository = None
683
# XXX TODO: This isinstance is here because we have not implemented
684
# the fix recommended in bug # 103195 - to delegate this choice the
686
repo_format = source_repository._format
687
if isinstance(repo_format, remote.RemoteRepositoryFormat):
688
source_repository._ensure_real()
689
repo_format = source_repository._real_repository._format
690
result_format.repository_format = repo_format
692
# TODO: Couldn't we just probe for the format in these cases,
693
# rather than opening the whole tree? It would be a little
694
# faster. mbp 20070401
695
tree = self.open_workingtree(recommend_upgrade=False)
696
except (errors.NoWorkingTree, errors.NotLocalUrl):
697
result_format.workingtree_format = None
699
result_format.workingtree_format = tree._format.__class__()
700
return result_format, source_repository
702
def cloning_metadir(self, require_stacking=False):
703
"""Produce a metadir suitable for cloning or sprouting with.
705
These operations may produce workingtrees (yes, even though they're
706
"cloning" something that doesn't have a tree), so a viable workingtree
707
format must be selected.
709
:require_stacking: If True, non-stackable formats will be upgraded
710
to similar stackable formats.
711
:returns: a ControlDirFormat with all component formats either set
712
appropriately or set to None if that component should not be
715
format, repository = self._cloning_metadir()
716
if format._workingtree_format is None:
718
if repository is None:
719
# No repository either
721
# We have a repository, so set a working tree? (Why? This seems to
722
# contradict the stated return value in the docstring).
723
tree_format = repository._format._matchingbzrdir.workingtree_format
724
format.workingtree_format = tree_format.__class__()
726
format.require_stacking()
729
def get_branch_transport(self, branch_format, name=None):
323
next_transport = found_bzrdir.root_transport.clone('..')
325
if ((found_bzrdir.root_transport.base ==
326
self.root_transport.base) or repository.is_shared()):
329
raise errors.NoRepositoryPresent(self)
330
raise errors.NoRepositoryPresent(self)
332
def get_branch_transport(self, branch_format):
730
333
"""Get the transport for use by branch format in this BzrDir.
732
335
Note that bzr dirs that do not support format strings will raise
733
336
IncompatibleFormat if the branch format they are given has
734
a format string, and vice versa.
337
a format string, and vice verca.
736
If branch_format is None, the transport is returned with no
737
checking. If it is not None, then the returned transport is
339
If branch_format is None, the transport is returned with no
340
checking. if it is not None, then the returned transport is
738
341
guaranteed to point to an existing directory ready for use.
740
343
raise NotImplementedError(self.get_branch_transport)
742
345
def get_repository_transport(self, repository_format):
743
346
"""Get the transport for use by repository format in this BzrDir.
745
348
Note that bzr dirs that do not support format strings will raise
746
349
IncompatibleFormat if the repository format they are given has
747
a format string, and vice versa.
350
a format string, and vice verca.
749
If repository_format is None, the transport is returned with no
750
checking. If it is not None, then the returned transport is
352
If repository_format is None, the transport is returned with no
353
checking. if it is not None, then the returned transport is
751
354
guaranteed to point to an existing directory ready for use.
753
356
raise NotImplementedError(self.get_repository_transport)
755
358
def get_workingtree_transport(self, tree_format):
756
359
"""Get the transport for use by workingtree format in this BzrDir.
758
361
Note that bzr dirs that do not support format strings will raise
759
IncompatibleFormat if the workingtree format they are given has a
760
format string, and vice versa.
362
IncompatibleFormat if the workingtree format they are given has
363
a format string, and vice verca.
762
If workingtree_format is None, the transport is returned with no
763
checking. If it is not None, then the returned transport is
365
If workingtree_format is None, the transport is returned with no
366
checking. if it is not None, then the returned transport is
764
367
guaranteed to point to an existing directory ready for use.
766
369
raise NotImplementedError(self.get_workingtree_transport)
769
def create(cls, base, format=None, possible_transports=None):
770
"""Create a new BzrDir at the url 'base'.
772
:param format: If supplied, the format of branch to create. If not
773
supplied, the default is used.
774
:param possible_transports: If supplied, a list of transports that
775
can be reused to share a remote connection.
777
if cls is not BzrDir:
778
raise AssertionError("BzrDir.create always creates the "
779
"default format, not one of %r" % cls)
780
return controldir.ControlDir.create(base, format=format,
781
possible_transports=possible_transports)
784
return "<%s at %r>" % (self.__class__.__name__, self.user_url)
786
def update_feature_flags(self, updated_flags):
787
"""Update the features required by this bzrdir.
789
:param updated_flags: Dictionary mapping feature names to necessities
790
A necessity can be None to indicate the feature should be removed
792
self.control_files.lock_write()
794
self._format._update_feature_flags(updated_flags)
795
self.transport.put_bytes('branch-format', self._format.as_string())
797
self.control_files.unlock()
371
def __init__(self, _transport, _format):
372
"""Initialize a Bzr control dir object.
374
Only really common logic should reside here, concrete classes should be
375
made with varying behaviours.
377
:param _format: the format that is creating this BzrDir instance.
378
:param _transport: the transport this dir is based at.
380
self._format = _format
381
self.transport = _transport.clone('.bzr')
382
self.root_transport = _transport
384
def needs_format_conversion(self, format=None):
385
"""Return true if this bzrdir needs convert_format run on it.
387
For instance, if the repository format is out of date but the
388
branch and working tree are not, this should return True.
390
:param format: Optional parameter indicating a specific desired
391
format we plan to arrive at.
393
raise NotImplementedError(self.needs_format_conversion)
396
def open_unsupported(base):
397
"""Open a branch which is not supported."""
398
return BzrDir.open(base, _unsupported=True)
401
def open(base, _unsupported=False):
402
"""Open an existing bzrdir, rooted at 'base' (url)
404
_unsupported is a private parameter to the BzrDir class.
406
t = get_transport(base)
407
mutter("trying to open %r with transport %r", base, t)
408
format = BzrDirFormat.find_format(t)
409
BzrDir._check_supported(format, _unsupported)
410
return format.open(t, _found=True)
412
def open_branch(self, unsupported=False):
413
"""Open the branch object at this BzrDir if one is present.
415
If unsupported is True, then no longer supported branch formats can
418
TODO: static convenience version of this?
420
raise NotImplementedError(self.open_branch)
423
def open_containing(url):
424
"""Open an existing branch which contains url.
426
:param url: url to search from.
427
See open_containing_from_transport for more detail.
429
return BzrDir.open_containing_from_transport(get_transport(url))
432
def open_containing_from_transport(a_transport):
433
"""Open an existing branch which contains a_transport.base
435
This probes for a branch at a_transport, and searches upwards from there.
437
Basically we keep looking up until we find the control directory or
438
run into the root. If there isn't one, raises NotBranchError.
439
If there is one and it is either an unrecognised format or an unsupported
440
format, UnknownFormatError or UnsupportedFormatError are raised.
441
If there is one, it is returned, along with the unused portion of url.
443
# this gets the normalised url back. I.e. '.' -> the full path.
444
url = a_transport.base
447
format = BzrDirFormat.find_format(a_transport)
448
BzrDir._check_supported(format, False)
449
return format.open(a_transport), a_transport.relpath(url)
450
except errors.NotBranchError, e:
451
mutter('not a branch in: %r %s', a_transport.base, e)
452
new_t = a_transport.clone('..')
453
if new_t.base == a_transport.base:
454
# reached the root, whatever that may be
455
raise errors.NotBranchError(path=url)
458
def open_repository(self, _unsupported=False):
459
"""Open the repository object at this BzrDir if one is present.
461
This will not follow the Branch object pointer - its strictly a direct
462
open facility. Most client code should use open_branch().repository to
465
_unsupported is a private parameter, not part of the api.
466
TODO: static convenience version of this?
468
raise NotImplementedError(self.open_repository)
470
def open_workingtree(self, _unsupported=False):
471
"""Open the workingtree object at this BzrDir if one is present.
473
TODO: static convenience version of this?
475
raise NotImplementedError(self.open_workingtree)
477
def sprout(self, url, revision_id=None, basis=None, force_new_repo=False):
478
"""Create a copy of this bzrdir prepared for use as a new line of
481
If urls last component does not exist, it will be created.
483
Attributes related to the identity of the source branch like
484
branch nickname will be cleaned, a working tree is created
485
whether one existed before or not; and a local branch is always
488
if revision_id is not None, then the clone operation may tune
489
itself to download less data.
492
result = self._format.initialize(url)
493
basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
495
source_branch = self.open_branch()
496
source_repository = source_branch.repository
497
except errors.NotBranchError:
500
source_repository = self.open_repository()
501
except errors.NoRepositoryPresent:
502
# copy the entire basis one if there is one
503
# but there is no repository.
504
source_repository = basis_repo
509
result_repo = result.find_repository()
510
except errors.NoRepositoryPresent:
512
if source_repository is None and result_repo is not None:
514
elif source_repository is None and result_repo is None:
515
# no repo available, make a new one
516
result.create_repository()
517
elif source_repository is not None and result_repo is None:
518
# have soure, and want to make a new target repo
519
source_repository.clone(result,
520
revision_id=revision_id,
523
# fetch needed content into target.
525
# XXX FIXME RBC 20060214 need tests for this when the basis
527
result_repo.fetch(basis_repo, revision_id=revision_id)
528
result_repo.fetch(source_repository, revision_id=revision_id)
529
if source_branch is not None:
530
source_branch.sprout(result, revision_id=revision_id)
532
result.create_branch()
533
result.create_workingtree()
537
class BzrDirPreSplitOut(BzrDir):
538
"""A common class for the all-in-one formats."""
540
def __init__(self, _transport, _format):
541
"""See BzrDir.__init__."""
542
super(BzrDirPreSplitOut, self).__init__(_transport, _format)
543
assert self._format._lock_class == TransportLock
544
assert self._format._lock_file_name == 'branch-lock'
545
self._control_files = LockableFiles(self.get_branch_transport(None),
546
self._format._lock_file_name,
547
self._format._lock_class)
549
def clone(self, url, revision_id=None, basis=None, force_new_repo=False):
550
"""See BzrDir.clone()."""
551
from bzrlib.workingtree import WorkingTreeFormat2
553
result = self._format.initialize(url, _cloning=True)
554
basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
555
self.open_repository().clone(result, revision_id=revision_id, basis=basis_repo)
556
self.open_branch().clone(result, revision_id=revision_id)
558
self.open_workingtree().clone(result, basis=basis_tree)
559
except errors.NotLocalUrl:
560
# make a new one, this format always has to have one.
562
WorkingTreeFormat2().initialize(result)
563
except errors.NotLocalUrl:
564
# but we canot do it for remote trees.
568
def create_branch(self):
569
"""See BzrDir.create_branch."""
570
return self.open_branch()
572
def create_repository(self, shared=False):
573
"""See BzrDir.create_repository."""
575
raise errors.IncompatibleFormat('shared repository', self._format)
576
return self.open_repository()
578
def create_workingtree(self, revision_id=None):
579
"""See BzrDir.create_workingtree."""
580
# this looks buggy but is not -really-
581
# clone and sprout will have set the revision_id
582
# and that will have set it for us, its only
583
# specific uses of create_workingtree in isolation
584
# that can do wonky stuff here, and that only
585
# happens for creating checkouts, which cannot be
586
# done on this format anyway. So - acceptable wart.
587
result = self.open_workingtree()
588
if revision_id is not None:
589
result.set_last_revision(revision_id)
592
def get_branch_transport(self, branch_format):
593
"""See BzrDir.get_branch_transport()."""
594
if branch_format is None:
595
return self.transport
597
branch_format.get_format_string()
598
except NotImplementedError:
599
return self.transport
600
raise errors.IncompatibleFormat(branch_format, self._format)
602
def get_repository_transport(self, repository_format):
603
"""See BzrDir.get_repository_transport()."""
604
if repository_format is None:
605
return self.transport
607
repository_format.get_format_string()
608
except NotImplementedError:
609
return self.transport
610
raise errors.IncompatibleFormat(repository_format, self._format)
612
def get_workingtree_transport(self, workingtree_format):
613
"""See BzrDir.get_workingtree_transport()."""
614
if workingtree_format is None:
615
return self.transport
617
workingtree_format.get_format_string()
618
except NotImplementedError:
619
return self.transport
620
raise errors.IncompatibleFormat(workingtree_format, self._format)
622
def needs_format_conversion(self, format=None):
623
"""See BzrDir.needs_format_conversion()."""
624
# if the format is not the same as the system default,
625
# an upgrade is needed.
627
format = BzrDirFormat.get_default_format()
628
return not isinstance(self._format, format.__class__)
630
def open_branch(self, unsupported=False):
631
"""See BzrDir.open_branch."""
632
from bzrlib.branch import BzrBranchFormat4
633
format = BzrBranchFormat4()
634
self._check_supported(format, unsupported)
635
return format.open(self, _found=True)
637
def sprout(self, url, revision_id=None, basis=None):
638
"""See BzrDir.sprout()."""
639
from bzrlib.workingtree import WorkingTreeFormat2
641
result = self._format.initialize(url, _cloning=True)
642
basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
644
self.open_repository().clone(result, revision_id=revision_id, basis=basis_repo)
645
except errors.NoRepositoryPresent:
648
self.open_branch().sprout(result, revision_id=revision_id)
649
except errors.NotBranchError:
651
# we always want a working tree
652
WorkingTreeFormat2().initialize(result)
656
class BzrDir4(BzrDirPreSplitOut):
657
"""A .bzr version 4 control object.
659
This is a deprecated format and may be removed after sept 2006.
662
def create_repository(self, shared=False):
663
"""See BzrDir.create_repository."""
664
return self._format.repository_format.initialize(self, shared)
666
def needs_format_conversion(self, format=None):
667
"""Format 4 dirs are always in need of conversion."""
670
def open_repository(self):
671
"""See BzrDir.open_repository."""
672
from bzrlib.repository import RepositoryFormat4
673
return RepositoryFormat4().open(self, _found=True)
676
class BzrDir5(BzrDirPreSplitOut):
677
"""A .bzr version 5 control object.
679
This is a deprecated format and may be removed after sept 2006.
682
def open_repository(self):
683
"""See BzrDir.open_repository."""
684
from bzrlib.repository import RepositoryFormat5
685
return RepositoryFormat5().open(self, _found=True)
687
def open_workingtree(self, _unsupported=False):
688
"""See BzrDir.create_workingtree."""
689
from bzrlib.workingtree import WorkingTreeFormat2
690
return WorkingTreeFormat2().open(self, _found=True)
693
class BzrDir6(BzrDirPreSplitOut):
694
"""A .bzr version 6 control object.
696
This is a deprecated format and may be removed after sept 2006.
699
def open_repository(self):
700
"""See BzrDir.open_repository."""
701
from bzrlib.repository import RepositoryFormat6
702
return RepositoryFormat6().open(self, _found=True)
704
def open_workingtree(self, _unsupported=False):
705
"""See BzrDir.create_workingtree."""
706
from bzrlib.workingtree import WorkingTreeFormat2
707
return WorkingTreeFormat2().open(self, _found=True)
800
710
class BzrDirMeta1(BzrDir):
801
711
"""A .bzr meta version 1 control object.
803
This is the first control object where the
713
This is the first control object where the
804
714
individual aspects are really split out: there are separate repository,
805
715
workingtree and branch subdirectories and any subset of the three can be
806
716
present within a BzrDir.
809
def _get_branch_path(self, name):
810
"""Obtain the branch path to use.
812
This uses the API specified branch name first, and then falls back to
813
the branch name specified in the URL. If neither of those is specified,
814
it uses the default branch.
816
:param name: Optional branch name to use
817
:return: Relative path to branch
821
return urlutils.join('branches', name.encode("utf-8"))
823
def _read_branch_list(self):
824
"""Read the branch list.
826
:return: List of utf-8 encoded branch names.
829
f = self.control_transport.get('branch-list')
830
except errors.NoSuchFile:
836
ret.append(name.rstrip("\n"))
841
def _write_branch_list(self, branches):
842
"""Write out the branch list.
844
:param branches: List of utf-8 branch names to write
846
self.transport.put_bytes('branch-list',
847
"".join([name+"\n" for name in branches]))
849
def __init__(self, _transport, _format):
850
super(BzrDirMeta1, self).__init__(_transport, _format)
851
self.control_files = lockable_files.LockableFiles(
852
self.control_transport, self._format._lock_file_name,
853
self._format._lock_class)
855
719
def can_convert_format(self):
856
720
"""See BzrDir.can_convert_format()."""
859
def create_branch(self, name=None, repository=None,
860
append_revisions_only=None):
861
"""See ControlDir.create_branch."""
863
name = self._get_selected_branch()
864
return self._format.get_branch_format().initialize(self, name=name,
865
repository=repository,
866
append_revisions_only=append_revisions_only)
868
def destroy_branch(self, name=None):
869
"""See ControlDir.destroy_branch."""
871
name = self._get_selected_branch()
872
path = self._get_branch_path(name)
874
self.control_files.lock_write()
876
branches = self._read_branch_list()
878
branches.remove(name.encode("utf-8"))
880
raise errors.NotBranchError(name)
881
self._write_branch_list(branches)
883
self.control_files.unlock()
885
self.transport.delete_tree(path)
886
except errors.NoSuchFile:
887
raise errors.NotBranchError(path=urlutils.join(self.transport.base,
723
def create_branch(self):
724
"""See BzrDir.create_branch."""
725
from bzrlib.branch import BranchFormat
726
return BranchFormat.get_default_format().initialize(self)
890
728
def create_repository(self, shared=False):
891
729
"""See BzrDir.create_repository."""
892
730
return self._format.repository_format.initialize(self, shared)
894
def destroy_repository(self):
895
"""See BzrDir.destroy_repository."""
897
self.transport.delete_tree('repository')
898
except errors.NoSuchFile:
899
raise errors.NoRepositoryPresent(self)
901
def create_workingtree(self, revision_id=None, from_branch=None,
902
accelerator_tree=None, hardlink=False):
732
def create_workingtree(self, revision_id=None):
903
733
"""See BzrDir.create_workingtree."""
904
return self._format.workingtree_format.initialize(
905
self, revision_id, from_branch=from_branch,
906
accelerator_tree=accelerator_tree, hardlink=hardlink)
908
def destroy_workingtree(self):
909
"""See BzrDir.destroy_workingtree."""
910
wt = self.open_workingtree(recommend_upgrade=False)
911
repository = wt.branch.repository
912
empty = repository.revision_tree(_mod_revision.NULL_REVISION)
913
# We ignore the conflicts returned by wt.revert since we're about to
914
# delete the wt metadata anyway, all that should be left here are
915
# detritus. But see bug #634470 about subtree .bzr dirs.
916
conflicts = wt.revert(old_tree=empty)
917
self.destroy_workingtree_metadata()
919
def destroy_workingtree_metadata(self):
920
self.transport.delete_tree('checkout')
922
def find_branch_format(self, name=None):
923
"""Find the branch 'format' for this bzrdir.
925
This might be a synthetic object for e.g. RemoteBranch and SVN.
927
from bzrlib.branch import BranchFormatMetadir
928
return BranchFormatMetadir.find_format(self, name=name)
930
def _get_mkdir_mode(self):
931
"""Figure out the mode to use when creating a bzrdir subdir."""
932
temp_control = lockable_files.LockableFiles(self.transport, '',
933
lockable_files.TransportLock)
934
return temp_control._dir_mode
936
def get_branch_reference(self, name=None):
937
"""See BzrDir.get_branch_reference()."""
938
from bzrlib.branch import BranchFormatMetadir
939
format = BranchFormatMetadir.find_format(self, name=name)
940
return format.get_reference(self, name=name)
942
def set_branch_reference(self, target_branch, name=None):
943
format = _mod_branch.BranchReferenceFormat()
944
return format.initialize(self, target_branch=target_branch, name=name)
946
def get_branch_transport(self, branch_format, name=None):
734
from bzrlib.workingtree import WorkingTreeFormat
735
return WorkingTreeFormat.get_default_format().initialize(self, revision_id)
737
def get_branch_transport(self, branch_format):
947
738
"""See BzrDir.get_branch_transport()."""
949
name = self._get_selected_branch()
950
path = self._get_branch_path(name)
951
# XXX: this shouldn't implicitly create the directory if it's just
952
# promising to get a transport -- mbp 20090727
953
739
if branch_format is None:
954
return self.transport.clone(path)
740
return self.transport.clone('branch')
956
742
branch_format.get_format_string()
957
743
except NotImplementedError:
958
744
raise errors.IncompatibleFormat(branch_format, self._format)
960
branches = self._read_branch_list()
961
utf8_name = name.encode("utf-8")
962
if not utf8_name in branches:
963
self.control_files.lock_write()
965
branches = self._read_branch_list()
966
dirname = urlutils.dirname(utf8_name)
967
if dirname != "" and dirname in branches:
968
raise errors.ParentBranchExists(name)
970
b.startswith(utf8_name+"/") for b in branches]
971
if any(child_branches):
972
raise errors.AlreadyBranchError(name)
973
branches.append(utf8_name)
974
self._write_branch_list(branches)
976
self.control_files.unlock()
977
branch_transport = self.transport.clone(path)
978
mode = self._get_mkdir_mode()
979
branch_transport.create_prefix(mode=mode)
981
self.transport.mkdir(path, mode=mode)
746
self.transport.mkdir('branch')
982
747
except errors.FileExists:
984
return self.transport.clone(path)
749
return self.transport.clone('branch')
986
751
def get_repository_transport(self, repository_format):
987
752
"""See BzrDir.get_repository_transport()."""
1052
792
except errors.NoRepositoryPresent:
1054
for branch in self.list_branches():
1055
if not isinstance(branch._format,
1056
format.get_branch_format().__class__):
1057
# the branch needs an upgrade.
1060
my_wt = self.open_workingtree(recommend_upgrade=False)
1061
if not isinstance(my_wt._format,
1062
format.workingtree_format.__class__):
1063
# the workingtree needs an upgrade.
1065
except (errors.NoWorkingTree, errors.NotLocalUrl):
794
# currently there are no other possible conversions for meta1 formats.
1069
def open_branch(self, name=None, unsupported=False,
1070
ignore_fallbacks=False, possible_transports=None):
1071
"""See ControlDir.open_branch."""
1073
name = self._get_selected_branch()
1074
format = self.find_branch_format(name=name)
1075
format.check_support_status(unsupported)
1076
return format.open(self, name=name,
1077
_found=True, ignore_fallbacks=ignore_fallbacks,
1078
possible_transports=possible_transports)
797
def open_branch(self, unsupported=False):
798
"""See BzrDir.open_branch."""
799
from bzrlib.branch import BranchFormat
800
format = BranchFormat.find_format(self)
801
self._check_supported(format, unsupported)
802
return format.open(self, _found=True)
1080
804
def open_repository(self, unsupported=False):
1081
805
"""See BzrDir.open_repository."""
1082
from bzrlib.repository import RepositoryFormatMetaDir
1083
format = RepositoryFormatMetaDir.find_format(self)
1084
format.check_support_status(unsupported)
806
from bzrlib.repository import RepositoryFormat
807
format = RepositoryFormat.find_format(self)
808
self._check_supported(format, unsupported)
1085
809
return format.open(self, _found=True)
1087
def open_workingtree(self, unsupported=False,
1088
recommend_upgrade=True):
811
def open_workingtree(self, unsupported=False):
1089
812
"""See BzrDir.open_workingtree."""
1090
from bzrlib.workingtree import WorkingTreeFormatMetaDir
1091
format = WorkingTreeFormatMetaDir.find_format(self)
1092
format.check_support_status(unsupported, recommend_upgrade,
1093
basedir=self.root_transport.base)
813
from bzrlib.workingtree import WorkingTreeFormat
814
format = WorkingTreeFormat.find_format(self)
815
self._check_supported(format, unsupported)
1094
816
return format.open(self, _found=True)
1096
def _get_config(self):
1097
return config.TransportConfig(self.transport, 'control.conf')
1100
class BzrFormat(object):
1101
"""Base class for all formats of things living in metadirs.
1103
This class manages the format string that is stored in the 'format'
1104
or 'branch-format' file.
1106
All classes for (branch-, repository-, workingtree-) formats that
1107
live in meta directories and have their own 'format' file
1108
(i.e. different from .bzr/branch-format) derive from this class,
1109
as well as the relevant base class for their kind
1110
(BranchFormat, WorkingTreeFormat, RepositoryFormat).
1112
Each format is identified by a "format" or "branch-format" file with a
1113
single line containing the base format name and then an optional list of
1116
Feature flags are supported as of bzr 2.5. Setting feature flags on formats
1117
will render them inaccessible to older versions of bzr.
1119
:ivar features: Dictionary mapping feature names to their necessity
1122
_present_features = set()
1128
def register_feature(cls, name):
1129
"""Register a feature as being present.
1131
:param name: Name of the feature
1134
raise ValueError("spaces are not allowed in feature names")
1135
if name in cls._present_features:
1136
raise errors.FeatureAlreadyRegistered(name)
1137
cls._present_features.add(name)
1140
def unregister_feature(cls, name):
1141
"""Unregister a feature."""
1142
cls._present_features.remove(name)
1144
def check_support_status(self, allow_unsupported, recommend_upgrade=True,
1146
for name, necessity in self.features.iteritems():
1147
if name in self._present_features:
1149
if necessity == "optional":
1150
mutter("ignoring optional missing feature %s", name)
1152
elif necessity == "required":
1153
raise errors.MissingFeature(name)
1155
mutter("treating unknown necessity as require for %s",
1157
raise errors.MissingFeature(name)
1160
def get_format_string(cls):
1161
"""Return the ASCII format string that identifies this format."""
1162
raise NotImplementedError(cls.get_format_string)
1165
def from_string(cls, text):
1166
format_string = cls.get_format_string()
1167
if not text.startswith(format_string):
1168
raise AssertionError("Invalid format header %r for %r" % (text, cls))
1169
lines = text[len(format_string):].splitlines()
1171
for lineno, line in enumerate(lines):
1173
(necessity, feature) = line.split(" ", 1)
1175
raise errors.ParseFormatError(format=cls, lineno=lineno+2,
1176
line=line, text=text)
1177
ret.features[feature] = necessity
1180
def as_string(self):
1181
"""Return the string representation of this format.
1183
lines = [self.get_format_string()]
1184
lines.extend([("%s %s\n" % (item[1], item[0])) for item in
1185
self.features.iteritems()])
1186
return "".join(lines)
1189
def _find_format(klass, registry, kind, format_string):
1191
first_line = format_string[:format_string.index("\n")+1]
1193
first_line = format_string
1195
cls = registry.get(first_line)
1197
raise errors.UnknownFormatError(format=first_line, kind=kind)
1198
return cls.from_string(format_string)
1200
def network_name(self):
1201
"""A simple byte string uniquely identifying this format for RPC calls.
1203
Metadir branch formats use their format string.
1205
return self.as_string()
1207
def __eq__(self, other):
1208
return (self.__class__ is other.__class__ and
1209
self.features == other.features)
1211
def _update_feature_flags(self, updated_flags):
1212
"""Update the feature flags in this format.
1214
:param updated_flags: Updated feature flags
1216
for name, necessity in updated_flags.iteritems():
1217
if necessity is None:
1219
del self.features[name]
1223
self.features[name] = necessity
1226
class BzrProber(controldir.Prober):
1227
"""Prober for formats that use a .bzr/ control directory."""
1229
formats = registry.FormatRegistry(controldir.network_format_registry)
1230
"""The known .bzr formats."""
1233
def probe_transport(klass, transport):
1234
"""Return the .bzrdir style format present in a directory."""
1236
format_string = transport.get_bytes(".bzr/branch-format")
1237
except errors.NoSuchFile:
1238
raise errors.NotBranchError(path=transport.base)
1240
first_line = format_string[:format_string.index("\n")+1]
1242
first_line = format_string
1244
cls = klass.formats.get(first_line)
1246
raise errors.UnknownFormatError(format=first_line, kind='bzrdir')
1247
return cls.from_string(format_string)
1250
def known_formats(cls):
1252
for name, format in cls.formats.iteritems():
1253
if callable(format):
1259
controldir.ControlDirFormat.register_prober(BzrProber)
1262
class RemoteBzrProber(controldir.Prober):
1263
"""Prober for remote servers that provide a Bazaar smart server."""
1266
def probe_transport(klass, transport):
1267
"""Return a RemoteBzrDirFormat object if it looks possible."""
1269
medium = transport.get_smart_medium()
1270
except (NotImplementedError, AttributeError,
1271
errors.TransportNotPossible, errors.NoSmartMedium,
1272
errors.SmartProtocolError):
1273
# no smart server, so not a branch for this format type.
1274
raise errors.NotBranchError(path=transport.base)
1276
# Decline to open it if the server doesn't support our required
1277
# version (3) so that the VFS-based transport will do it.
1278
if medium.should_probe():
1280
server_version = medium.protocol_version()
1281
except errors.SmartProtocolError:
1282
# Apparently there's no usable smart server there, even though
1283
# the medium supports the smart protocol.
1284
raise errors.NotBranchError(path=transport.base)
1285
if server_version != '2':
1286
raise errors.NotBranchError(path=transport.base)
1287
from bzrlib.remote import RemoteBzrDirFormat
1288
return RemoteBzrDirFormat()
1291
def known_formats(cls):
1292
from bzrlib.remote import RemoteBzrDirFormat
1293
return set([RemoteBzrDirFormat()])
1296
class BzrDirFormat(BzrFormat, controldir.ControlDirFormat):
1297
"""ControlDirFormat base class for .bzr/ directories.
1299
Formats are placed in a dict by their format string for reference
819
class BzrDirFormat(object):
820
"""An encapsulation of the initialization and open routines for a format.
822
Formats provide three things:
823
* An initialization routine,
827
Formats are placed in an dict by their format string for reference
1300
828
during bzrdir opening. These should be subclasses of BzrDirFormat
1301
829
for consistency.
1303
831
Once a format is deprecated, just deprecate the initialize and open
1304
methods on the format class. Do not deprecate the object, as the
832
methods on the format class. Do not deprecate the object, as the
1305
833
object will be created every system load.
836
_default_format = None
837
"""The default format used for new .bzr dirs."""
840
"""The known formats."""
1308
842
_lock_file_name = 'branch-lock'
1310
844
# _lock_class must be set in subclasses to the lock type, typ.
1311
845
# TransportLock or LockDir
1313
def initialize_on_transport(self, transport):
1314
"""Initialize a new bzrdir in the base directory of a Transport."""
1316
# can we hand off the request to the smart server rather than using
1318
client_medium = transport.get_smart_medium()
1319
except errors.NoSmartMedium:
1320
return self._initialize_on_transport_vfs(transport)
1322
# Current RPC's only know how to create bzr metadir1 instances, so
1323
# we still delegate to vfs methods if the requested format is not a
1325
if type(self) != BzrDirMetaFormat1:
1326
return self._initialize_on_transport_vfs(transport)
1327
from bzrlib.remote import RemoteBzrDirFormat
1328
remote_format = RemoteBzrDirFormat()
1329
self._supply_sub_formats_to(remote_format)
1330
return remote_format.initialize_on_transport(transport)
1332
def initialize_on_transport_ex(self, transport, use_existing_dir=False,
1333
create_prefix=False, force_new_repo=False, stacked_on=None,
1334
stack_on_pwd=None, repo_format_name=None, make_working_trees=None,
1335
shared_repo=False, vfs_only=False):
1336
"""Create this format on transport.
1338
The directory to initialize will be created.
1340
:param force_new_repo: Do not use a shared repository for the target,
1341
even if one is available.
1342
:param create_prefix: Create any missing directories leading up to
1344
:param use_existing_dir: Use an existing directory if one exists.
1345
:param stacked_on: A url to stack any created branch on, None to follow
1346
any target stacking policy.
1347
:param stack_on_pwd: If stack_on is relative, the location it is
1349
:param repo_format_name: If non-None, a repository will be
1350
made-or-found. Should none be found, or if force_new_repo is True
1351
the repo_format_name is used to select the format of repository to
1353
:param make_working_trees: Control the setting of make_working_trees
1354
for a new shared repository when one is made. None to use whatever
1355
default the format has.
1356
:param shared_repo: Control whether made repositories are shared or
1358
:param vfs_only: If True do not attempt to use a smart server
1359
:return: repo, controldir, require_stacking, repository_policy. repo is
1360
None if none was created or found, bzrdir is always valid.
1361
require_stacking is the result of examining the stacked_on
1362
parameter and any stacking policy found for the target.
1365
# Try to hand off to a smart server
1367
client_medium = transport.get_smart_medium()
1368
except errors.NoSmartMedium:
1371
from bzrlib.remote import RemoteBzrDirFormat
1372
# TODO: lookup the local format from a server hint.
1373
remote_dir_format = RemoteBzrDirFormat()
1374
remote_dir_format._network_name = self.network_name()
1375
self._supply_sub_formats_to(remote_dir_format)
1376
return remote_dir_format.initialize_on_transport_ex(transport,
1377
use_existing_dir=use_existing_dir, create_prefix=create_prefix,
1378
force_new_repo=force_new_repo, stacked_on=stacked_on,
1379
stack_on_pwd=stack_on_pwd, repo_format_name=repo_format_name,
1380
make_working_trees=make_working_trees, shared_repo=shared_repo)
1381
# XXX: Refactor the create_prefix/no_create_prefix code into a
1382
# common helper function
1383
# The destination may not exist - if so make it according to policy.
1384
def make_directory(transport):
1385
transport.mkdir('.')
1387
def redirected(transport, e, redirection_notice):
1388
note(redirection_notice)
1389
return transport._redirected_to(e.source, e.target)
1391
transport = do_catching_redirections(make_directory, transport,
1393
except errors.FileExists:
1394
if not use_existing_dir:
848
def find_format(klass, transport):
849
"""Return the format registered for URL."""
851
format_string = transport.get(".bzr/branch-format").read()
852
return klass._formats[format_string]
1396
853
except errors.NoSuchFile:
1397
if not create_prefix:
1399
transport.create_prefix()
1401
require_stacking = (stacked_on is not None)
1402
# Now the target directory exists, but doesn't have a .bzr
1403
# directory. So we need to create it, along with any work to create
1404
# all of the dependent branches, etc.
1406
result = self.initialize_on_transport(transport)
1407
if repo_format_name:
1409
# use a custom format
1410
result._format.repository_format = \
1411
repository.network_format_registry.get(repo_format_name)
1412
except AttributeError:
1413
# The format didn't permit it to be set.
1415
# A repository is desired, either in-place or shared.
1416
repository_policy = result.determine_repository_policy(
1417
force_new_repo, stacked_on, stack_on_pwd,
1418
require_stacking=require_stacking)
1419
result_repo, is_new_repo = repository_policy.acquire_repository(
1420
make_working_trees, shared_repo)
1421
if not require_stacking and repository_policy._require_stacking:
1422
require_stacking = True
1423
result._format.require_stacking()
1424
result_repo.lock_write()
1427
repository_policy = None
1428
return result_repo, result, require_stacking, repository_policy
1430
def _initialize_on_transport_vfs(self, transport):
1431
"""Initialize a new bzrdir using VFS calls.
1433
:param transport: The transport to create the .bzr directory in.
854
raise errors.NotBranchError(path=transport.base)
856
raise errors.UnknownFormatError(format_string)
859
def get_default_format(klass):
860
"""Return the current default format."""
861
return klass._default_format
863
def get_format_string(self):
864
"""Return the ASCII format string that identifies this format."""
865
raise NotImplementedError(self.get_format_string)
867
def get_converter(self, format=None):
868
"""Return the converter to use to convert bzrdirs needing converts.
870
This returns a bzrlib.bzrdir.Converter object.
872
This should return the best upgrader to step this format towards the
873
current default format. In the case of plugins we can/shouold provide
874
some means for them to extend the range of returnable converters.
876
:param format: Optional format to override the default foramt of the
1436
# Since we are creating a .bzr directory, inherit the
879
raise NotImplementedError(self.get_converter)
881
def initialize(self, url):
882
"""Create a bzr control dir at this url and return an opened copy."""
883
# Since we don't have a .bzr directory, inherit the
1437
884
# mode from the root directory
1438
temp_control = lockable_files.LockableFiles(transport,
1439
'', lockable_files.TransportLock)
1441
temp_control._transport.mkdir('.bzr',
1442
# FIXME: RBC 20060121 don't peek under
1444
mode=temp_control._dir_mode)
1445
except errors.FileExists:
1446
raise errors.AlreadyControlDirError(transport.base)
1447
if sys.platform == 'win32' and isinstance(transport, local.LocalTransport):
1448
win32utils.set_file_attr_hidden(transport._abspath('.bzr'))
885
t = get_transport(url)
886
temp_control = LockableFiles(t, '', TransportLock)
887
temp_control._transport.mkdir('.bzr',
888
# FIXME: RBC 20060121 dont peek under
890
mode=temp_control._dir_mode)
1449
891
file_mode = temp_control._file_mode
1450
892
del temp_control
1451
bzrdir_transport = transport.clone('.bzr')
1452
utf8_files = [('README',
1453
"This is a Bazaar control directory.\n"
1454
"Do not change any files in this directory.\n"
1455
"See http://bazaar.canonical.com/ for more information about Bazaar.\n"),
1456
('branch-format', self.as_string()),
893
mutter('created control directory in ' + t.base)
894
control = t.clone('.bzr')
895
utf8_files = [('README',
896
"This is a Bazaar-NG control directory.\n"
897
"Do not change any files in this directory.\n"),
898
('branch-format', self.get_format_string()),
1458
900
# NB: no need to escape relative paths that are url safe.
1459
control_files = lockable_files.LockableFiles(bzrdir_transport,
1460
self._lock_file_name, self._lock_class)
901
control_files = LockableFiles(control, self._lock_file_name, self._lock_class)
1461
902
control_files.create_lock()
1462
903
control_files.lock_write()
1464
for (filename, content) in utf8_files:
1465
bzrdir_transport.put_bytes(filename, content,
905
for file, content in utf8_files:
906
control_files.put_utf8(file, content)
1468
908
control_files.unlock()
1469
return self.open(transport, _found=True)
909
return self.open(t, _found=True)
911
def is_supported(self):
912
"""Is this format supported?
914
Supported formats must be initializable and openable.
915
Unsupported formats may not support initialization or committing or
916
some other features depending on the reason for not being supported.
1471
920
def open(self, transport, _found=False):
1472
921
"""Return an instance of this format for the dir transport points at.
1474
923
_found is a private parameter, do not use it.
1477
found_format = controldir.ControlDirFormat.find_format(transport)
1478
if not isinstance(found_format, self.__class__):
1479
raise AssertionError("%s was asked to open %s, but it seems to need "
1481
% (self, transport, found_format))
1482
# Allow subclasses - use the found format.
1483
self._supply_sub_formats_to(found_format)
1484
return found_format._open(transport)
926
assert isinstance(BzrDirFormat.find_format(transport),
1485
928
return self._open(transport)
1487
930
def _open(self, transport):
1524
1106
This is the first format with split out working tree, branch and repository
1529
- Format 3 working trees [optional]
1530
- Format 5 branches [optional]
1531
- Format 7 repositories [optional]
1109
- Format 3 working trees [optional]
1110
- Format 5 branches [optional]
1111
- Format 7 repositories [optional]
1534
_lock_class = lockdir.LockDir
1536
fixed_components = False
1538
colocated_branches = True
1541
BzrDirFormat.__init__(self)
1542
self._workingtree_format = None
1543
self._branch_format = None
1544
self._repository_format = None
1546
def __eq__(self, other):
1547
if other.__class__ is not self.__class__:
1549
if other.repository_format != self.repository_format:
1551
if other.workingtree_format != self.workingtree_format:
1553
if other.features != self.features:
1557
def __ne__(self, other):
1558
return not self == other
1560
def get_branch_format(self):
1561
if self._branch_format is None:
1562
from bzrlib.branch import format_registry as branch_format_registry
1563
self._branch_format = branch_format_registry.get_default()
1564
return self._branch_format
1566
def set_branch_format(self, format):
1567
self._branch_format = format
1569
def require_stacking(self, stack_on=None, possible_transports=None,
1571
"""We have a request to stack, try to ensure the formats support it.
1573
:param stack_on: If supplied, it is the URL to a branch that we want to
1574
stack on. Check to see if that format supports stacking before
1577
# Stacking is desired. requested by the target, but does the place it
1578
# points at support stacking? If it doesn't then we should
1579
# not implicitly upgrade. We check this here.
1580
new_repo_format = None
1581
new_branch_format = None
1583
# a bit of state for get_target_branch so that we don't try to open it
1584
# 2 times, for both repo *and* branch
1585
target = [None, False, None] # target_branch, checked, upgrade anyway
1586
def get_target_branch():
1588
# We've checked, don't check again
1590
if stack_on is None:
1591
# No target format, that means we want to force upgrading
1592
target[:] = [None, True, True]
1595
target_dir = BzrDir.open(stack_on,
1596
possible_transports=possible_transports)
1597
except errors.NotBranchError:
1598
# Nothing there, don't change formats
1599
target[:] = [None, True, False]
1601
except errors.JailBreak:
1602
# JailBreak, JFDI and upgrade anyway
1603
target[:] = [None, True, True]
1606
target_branch = target_dir.open_branch()
1607
except errors.NotBranchError:
1608
# No branch, don't upgrade formats
1609
target[:] = [None, True, False]
1611
target[:] = [target_branch, True, False]
1614
if (not _skip_repo and
1615
not self.repository_format.supports_external_lookups):
1616
# We need to upgrade the Repository.
1617
target_branch, _, do_upgrade = get_target_branch()
1618
if target_branch is None:
1619
# We don't have a target branch, should we upgrade anyway?
1621
# stack_on is inaccessible, JFDI.
1622
# TODO: bad monkey, hard-coded formats...
1623
if self.repository_format.rich_root_data:
1624
new_repo_format = knitpack_repo.RepositoryFormatKnitPack5RichRoot()
1626
new_repo_format = knitpack_repo.RepositoryFormatKnitPack5()
1628
# If the target already supports stacking, then we know the
1629
# project is already able to use stacking, so auto-upgrade
1631
new_repo_format = target_branch.repository._format
1632
if not new_repo_format.supports_external_lookups:
1633
# target doesn't, source doesn't, so don't auto upgrade
1635
new_repo_format = None
1636
if new_repo_format is not None:
1637
self.repository_format = new_repo_format
1638
note(gettext('Source repository format does not support stacking,'
1639
' using format:\n %s'),
1640
new_repo_format.get_format_description())
1642
if not self.get_branch_format().supports_stacking():
1643
# We just checked the repo, now lets check if we need to
1644
# upgrade the branch format
1645
target_branch, _, do_upgrade = get_target_branch()
1646
if target_branch is None:
1648
# TODO: bad monkey, hard-coded formats...
1649
from bzrlib.branch import BzrBranchFormat7
1650
new_branch_format = BzrBranchFormat7()
1652
new_branch_format = target_branch._format
1653
if not new_branch_format.supports_stacking():
1654
new_branch_format = None
1655
if new_branch_format is not None:
1656
# Does support stacking, use its format.
1657
self.set_branch_format(new_branch_format)
1658
note(gettext('Source branch format does not support stacking,'
1659
' using format:\n %s'),
1660
new_branch_format.get_format_description())
1114
_lock_class = LockDir
1662
1116
def get_converter(self, format=None):
1663
1117
"""See BzrDirFormat.get_converter()."""
1664
1118
if format is None:
1665
1119
format = BzrDirFormat.get_default_format()
1666
if (type(self) is BzrDirMetaFormat1 and
1667
type(format) is BzrDirMetaFormat1Colo):
1668
return ConvertMetaToColo(format)
1669
if (type(self) is BzrDirMetaFormat1Colo and
1670
type(format) is BzrDirMetaFormat1):
1671
return ConvertMetaToColo(format)
1672
1120
if not isinstance(self, format.__class__):
1673
1121
# converting away from metadir is not implemented
1674
1122
raise NotImplementedError(self.get_converter)
1675
1123
return ConvertMetaToMeta(format)
1678
def get_format_string(cls):
1125
def get_format_string(self):
1679
1126
"""See BzrDirFormat.get_format_string()."""
1680
1127
return "Bazaar-NG meta directory, format 1\n"
1682
def get_format_description(self):
1683
"""See BzrDirFormat.get_format_description()."""
1684
return "Meta directory format 1"
1686
1129
def _open(self, transport):
1687
1130
"""See BzrDirFormat._open."""
1688
# Create a new format instance because otherwise initialisation of new
1689
# metadirs share the global default format object leading to alias
1691
format = BzrDirMetaFormat1()
1692
self._supply_sub_formats_to(format)
1693
return BzrDirMeta1(transport, format)
1131
return BzrDirMeta1(transport, self)
1695
1133
def __return_repository_format(self):
1696
1134
"""Circular import protection."""
1697
if self._repository_format:
1135
if getattr(self, '_repository_format', None):
1698
1136
return self._repository_format
1699
from bzrlib.repository import format_registry
1700
return format_registry.get_default()
1137
from bzrlib.repository import RepositoryFormat
1138
return RepositoryFormat.get_default_format()
1702
def _set_repository_format(self, value):
1703
"""Allow changing the repository format for metadir formats."""
1140
def __set_repository_format(self, value):
1141
"""Allow changint the repository format for metadir formats."""
1704
1142
self._repository_format = value
1706
repository_format = property(__return_repository_format,
1707
_set_repository_format)
1709
def _supply_sub_formats_to(self, other_format):
1710
"""Give other_format the same values for sub formats as this has.
1712
This method is expected to be used when parameterising a
1713
RemoteBzrDirFormat instance with the parameters from a
1714
BzrDirMetaFormat1 instance.
1716
:param other_format: other_format is a format which should be
1717
compatible with whatever sub formats are supported by self.
1720
super(BzrDirMetaFormat1, self)._supply_sub_formats_to(other_format)
1721
if getattr(self, '_repository_format', None) is not None:
1722
other_format.repository_format = self.repository_format
1723
if self._branch_format is not None:
1724
other_format._branch_format = self._branch_format
1725
if self._workingtree_format is not None:
1726
other_format.workingtree_format = self.workingtree_format
1728
def __get_workingtree_format(self):
1729
if self._workingtree_format is None:
1730
from bzrlib.workingtree import (
1731
format_registry as wt_format_registry,
1733
self._workingtree_format = wt_format_registry.get_default()
1734
return self._workingtree_format
1736
def __set_workingtree_format(self, wt_format):
1737
self._workingtree_format = wt_format
1740
return "<%r>" % (self.__class__.__name__,)
1742
workingtree_format = property(__get_workingtree_format,
1743
__set_workingtree_format)
1746
# Register bzr formats
1747
BzrProber.formats.register(BzrDirMetaFormat1.get_format_string(),
1749
controldir.ControlDirFormat._default_format = BzrDirMetaFormat1()
1752
class BzrDirMetaFormat1Colo(BzrDirMetaFormat1):
1753
"""BzrDirMeta1 format with support for colocated branches."""
1755
colocated_branches = True
1758
def get_format_string(cls):
1759
"""See BzrDirFormat.get_format_string()."""
1760
return "Bazaar meta directory, format 1 (with colocated branches)\n"
1762
def get_format_description(self):
1763
"""See BzrDirFormat.get_format_description()."""
1764
return "Meta directory format 1 with support for colocated branches"
1766
def _open(self, transport):
1767
"""See BzrDirFormat._open."""
1768
# Create a new format instance because otherwise initialisation of new
1769
# metadirs share the global default format object leading to alias
1771
format = BzrDirMetaFormat1Colo()
1772
self._supply_sub_formats_to(format)
1773
return BzrDirMeta1(transport, format)
1776
BzrProber.formats.register(BzrDirMetaFormat1Colo.get_format_string(),
1777
BzrDirMetaFormat1Colo)
1780
class ConvertMetaToMeta(controldir.Converter):
1144
repository_format = property(__return_repository_format, __set_repository_format)
1147
BzrDirFormat.register_format(BzrDirFormat4())
1148
BzrDirFormat.register_format(BzrDirFormat5())
1149
BzrDirFormat.register_format(BzrDirMetaFormat1())
1150
__default_format = BzrDirFormat6()
1151
BzrDirFormat.register_format(__default_format)
1152
BzrDirFormat.set_default_format(__default_format)
1155
class BzrDirTestProviderAdapter(object):
1156
"""A tool to generate a suite testing multiple bzrdir formats at once.
1158
This is done by copying the test once for each transport and injecting
1159
the transport_server, transport_readonly_server, and bzrdir_format
1160
classes into each copy. Each copy is also given a new id() to make it
1164
def __init__(self, transport_server, transport_readonly_server, formats):
1165
self._transport_server = transport_server
1166
self._transport_readonly_server = transport_readonly_server
1167
self._formats = formats
1169
def adapt(self, test):
1170
result = TestSuite()
1171
for format in self._formats:
1172
new_test = deepcopy(test)
1173
new_test.transport_server = self._transport_server
1174
new_test.transport_readonly_server = self._transport_readonly_server
1175
new_test.bzrdir_format = format
1176
def make_new_test_id():
1177
new_id = "%s(%s)" % (new_test.id(), format.__class__.__name__)
1178
return lambda: new_id
1179
new_test.id = make_new_test_id()
1180
result.addTest(new_test)
1184
class ScratchDir(BzrDir6):
1185
"""Special test class: a bzrdir that cleans up itself..
1187
>>> d = ScratchDir()
1188
>>> base = d.transport.base
1191
>>> b.transport.__del__()
1196
def __init__(self, files=[], dirs=[], transport=None):
1197
"""Make a test branch.
1199
This creates a temporary directory and runs init-tree in it.
1201
If any files are listed, they are created in the working copy.
1203
if transport is None:
1204
transport = bzrlib.transport.local.ScratchTransport()
1205
# local import for scope restriction
1206
BzrDirFormat6().initialize(transport.base)
1207
super(ScratchDir, self).__init__(transport, BzrDirFormat6())
1208
self.create_repository()
1209
self.create_branch()
1210
self.create_workingtree()
1212
super(ScratchDir, self).__init__(transport, BzrDirFormat6())
1214
# BzrBranch creates a clone to .bzr and then forgets about the
1215
# original transport. A ScratchTransport() deletes itself and
1216
# everything underneath it when it goes away, so we need to
1217
# grab a local copy to prevent that from happening
1218
self._transport = transport
1221
self._transport.mkdir(d)
1224
self._transport.put(f, 'content of %s' % f)
1228
>>> orig = ScratchDir(files=["file1", "file2"])
1229
>>> os.listdir(orig.base)
1230
[u'.bzr', u'file1', u'file2']
1231
>>> clone = orig.clone()
1232
>>> if os.name != 'nt':
1233
... os.path.samefile(orig.base, clone.base)
1235
... orig.base == clone.base
1238
>>> os.listdir(clone.base)
1239
[u'.bzr', u'file1', u'file2']
1241
from shutil import copytree
1242
from bzrlib.osutils import mkdtemp
1245
copytree(self.base, base, symlinks=True)
1247
transport=bzrlib.transport.local.ScratchTransport(base))
1250
class Converter(object):
1251
"""Converts a disk format object from one format to another."""
1253
def convert(self, to_convert, pb):
1254
"""Perform the conversion of to_convert, giving feedback via pb.
1256
:param to_convert: The disk object to convert.
1257
:param pb: a progress bar to use for progress information.
1260
def step(self, message):
1261
"""Update the pb by a step."""
1263
self.pb.update(message, self.count, self.total)
1266
class ConvertBzrDir4To5(Converter):
1267
"""Converts format 4 bzr dirs to format 5."""
1270
super(ConvertBzrDir4To5, self).__init__()
1271
self.converted_revs = set()
1272
self.absent_revisions = set()
1276
def convert(self, to_convert, pb):
1277
"""See Converter.convert()."""
1278
self.bzrdir = to_convert
1280
self.pb.note('starting upgrade from format 4 to 5')
1281
if isinstance(self.bzrdir.transport, LocalTransport):
1282
self.bzrdir.get_workingtree_transport(None).delete('stat-cache')
1283
self._convert_to_weaves()
1284
return BzrDir.open(self.bzrdir.root_transport.base)
1286
def _convert_to_weaves(self):
1287
self.pb.note('note: upgrade may be faster if all store files are ungzipped first')
1290
stat = self.bzrdir.transport.stat('weaves')
1291
if not S_ISDIR(stat.st_mode):
1292
self.bzrdir.transport.delete('weaves')
1293
self.bzrdir.transport.mkdir('weaves')
1294
except errors.NoSuchFile:
1295
self.bzrdir.transport.mkdir('weaves')
1296
# deliberately not a WeaveFile as we want to build it up slowly.
1297
self.inv_weave = Weave('inventory')
1298
# holds in-memory weaves for all files
1299
self.text_weaves = {}
1300
self.bzrdir.transport.delete('branch-format')
1301
self.branch = self.bzrdir.open_branch()
1302
self._convert_working_inv()
1303
rev_history = self.branch.revision_history()
1304
# to_read is a stack holding the revisions we still need to process;
1305
# appending to it adds new highest-priority revisions
1306
self.known_revisions = set(rev_history)
1307
self.to_read = rev_history[-1:]
1309
rev_id = self.to_read.pop()
1310
if (rev_id not in self.revisions
1311
and rev_id not in self.absent_revisions):
1312
self._load_one_rev(rev_id)
1314
to_import = self._make_order()
1315
for i, rev_id in enumerate(to_import):
1316
self.pb.update('converting revision', i, len(to_import))
1317
self._convert_one_rev(rev_id)
1319
self._write_all_weaves()
1320
self._write_all_revs()
1321
self.pb.note('upgraded to weaves:')
1322
self.pb.note(' %6d revisions and inventories', len(self.revisions))
1323
self.pb.note(' %6d revisions not present', len(self.absent_revisions))
1324
self.pb.note(' %6d texts', self.text_count)
1325
self._cleanup_spare_files_after_format4()
1326
self.branch.control_files.put_utf8('branch-format', BzrDirFormat5().get_format_string())
1328
def _cleanup_spare_files_after_format4(self):
1329
# FIXME working tree upgrade foo.
1330
for n in 'merged-patches', 'pending-merged-patches':
1332
## assert os.path.getsize(p) == 0
1333
self.bzrdir.transport.delete(n)
1334
except errors.NoSuchFile:
1336
self.bzrdir.transport.delete_tree('inventory-store')
1337
self.bzrdir.transport.delete_tree('text-store')
1339
def _convert_working_inv(self):
1340
inv = serializer_v4.read_inventory(self.branch.control_files.get('inventory'))
1341
new_inv_xml = serializer_v5.write_inventory_to_string(inv)
1342
# FIXME inventory is a working tree change.
1343
self.branch.control_files.put('inventory', new_inv_xml)
1345
def _write_all_weaves(self):
1346
controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)
1347
weave_transport = self.bzrdir.transport.clone('weaves')
1348
weaves = WeaveStore(weave_transport, prefixed=False)
1349
transaction = WriteTransaction()
1353
for file_id, file_weave in self.text_weaves.items():
1354
self.pb.update('writing weave', i, len(self.text_weaves))
1355
weaves._put_weave(file_id, file_weave, transaction)
1357
self.pb.update('inventory', 0, 1)
1358
controlweaves._put_weave('inventory', self.inv_weave, transaction)
1359
self.pb.update('inventory', 1, 1)
1363
def _write_all_revs(self):
1364
"""Write all revisions out in new form."""
1365
self.bzrdir.transport.delete_tree('revision-store')
1366
self.bzrdir.transport.mkdir('revision-store')
1367
revision_transport = self.bzrdir.transport.clone('revision-store')
1369
_revision_store = TextRevisionStore(TextStore(revision_transport,
1373
transaction = bzrlib.transactions.WriteTransaction()
1374
for i, rev_id in enumerate(self.converted_revs):
1375
self.pb.update('write revision', i, len(self.converted_revs))
1376
_revision_store.add_revision(self.revisions[rev_id], transaction)
1380
def _load_one_rev(self, rev_id):
1381
"""Load a revision object into memory.
1383
Any parents not either loaded or abandoned get queued to be
1385
self.pb.update('loading revision',
1386
len(self.revisions),
1387
len(self.known_revisions))
1388
if not self.branch.repository.has_revision(rev_id):
1390
self.pb.note('revision {%s} not present in branch; '
1391
'will be converted as a ghost',
1393
self.absent_revisions.add(rev_id)
1395
rev = self.branch.repository._revision_store.get_revision(rev_id,
1396
self.branch.repository.get_transaction())
1397
for parent_id in rev.parent_ids:
1398
self.known_revisions.add(parent_id)
1399
self.to_read.append(parent_id)
1400
self.revisions[rev_id] = rev
1402
def _load_old_inventory(self, rev_id):
1403
assert rev_id not in self.converted_revs
1404
old_inv_xml = self.branch.repository.inventory_store.get(rev_id).read()
1405
inv = serializer_v4.read_inventory_from_string(old_inv_xml)
1406
rev = self.revisions[rev_id]
1407
if rev.inventory_sha1:
1408
assert rev.inventory_sha1 == sha_string(old_inv_xml), \
1409
'inventory sha mismatch for {%s}' % rev_id
1412
def _load_updated_inventory(self, rev_id):
1413
assert rev_id in self.converted_revs
1414
inv_xml = self.inv_weave.get_text(rev_id)
1415
inv = serializer_v5.read_inventory_from_string(inv_xml)
1418
def _convert_one_rev(self, rev_id):
1419
"""Convert revision and all referenced objects to new format."""
1420
rev = self.revisions[rev_id]
1421
inv = self._load_old_inventory(rev_id)
1422
present_parents = [p for p in rev.parent_ids
1423
if p not in self.absent_revisions]
1424
self._convert_revision_contents(rev, inv, present_parents)
1425
self._store_new_weave(rev, inv, present_parents)
1426
self.converted_revs.add(rev_id)
1428
def _store_new_weave(self, rev, inv, present_parents):
1429
# the XML is now updated with text versions
1433
if ie.kind == 'root_directory':
1435
assert hasattr(ie, 'revision'), \
1436
'no revision on {%s} in {%s}' % \
1437
(file_id, rev.revision_id)
1438
new_inv_xml = serializer_v5.write_inventory_to_string(inv)
1439
new_inv_sha1 = sha_string(new_inv_xml)
1440
self.inv_weave.add_lines(rev.revision_id,
1442
new_inv_xml.splitlines(True))
1443
rev.inventory_sha1 = new_inv_sha1
1445
def _convert_revision_contents(self, rev, inv, present_parents):
1446
"""Convert all the files within a revision.
1448
Also upgrade the inventory to refer to the text revision ids."""
1449
rev_id = rev.revision_id
1450
mutter('converting texts of revision {%s}',
1452
parent_invs = map(self._load_updated_inventory, present_parents)
1455
self._convert_file_version(rev, ie, parent_invs)
1457
def _convert_file_version(self, rev, ie, parent_invs):
1458
"""Convert one version of one file.
1460
The file needs to be added into the weave if it is a merge
1461
of >=2 parents or if it's changed from its parent.
1463
if ie.kind == 'root_directory':
1465
file_id = ie.file_id
1466
rev_id = rev.revision_id
1467
w = self.text_weaves.get(file_id)
1470
self.text_weaves[file_id] = w
1471
text_changed = False
1472
previous_entries = ie.find_previous_heads(parent_invs, w)
1473
for old_revision in previous_entries:
1474
# if this fails, its a ghost ?
1475
assert old_revision in self.converted_revs
1476
self.snapshot_ie(previous_entries, ie, w, rev_id)
1478
assert getattr(ie, 'revision', None) is not None
1480
def snapshot_ie(self, previous_revisions, ie, w, rev_id):
1481
# TODO: convert this logic, which is ~= snapshot to
1482
# a call to:. This needs the path figured out. rather than a work_tree
1483
# a v4 revision_tree can be given, or something that looks enough like
1484
# one to give the file content to the entry if it needs it.
1485
# and we need something that looks like a weave store for snapshot to
1487
#ie.snapshot(rev, PATH, previous_revisions, REVISION_TREE, InMemoryWeaveStore(self.text_weaves))
1488
if len(previous_revisions) == 1:
1489
previous_ie = previous_revisions.values()[0]
1490
if ie._unchanged(previous_ie):
1491
ie.revision = previous_ie.revision
1494
text = self.branch.repository.text_store.get(ie.text_id)
1495
file_lines = text.readlines()
1496
assert sha_strings(file_lines) == ie.text_sha1
1497
assert sum(map(len, file_lines)) == ie.text_size
1498
w.add_lines(rev_id, previous_revisions, file_lines)
1499
self.text_count += 1
1501
w.add_lines(rev_id, previous_revisions, [])
1502
ie.revision = rev_id
1504
def _make_order(self):
1505
"""Return a suitable order for importing revisions.
1507
The order must be such that an revision is imported after all
1508
its (present) parents.
1510
todo = set(self.revisions.keys())
1511
done = self.absent_revisions.copy()
1514
# scan through looking for a revision whose parents
1516
for rev_id in sorted(list(todo)):
1517
rev = self.revisions[rev_id]
1518
parent_ids = set(rev.parent_ids)
1519
if parent_ids.issubset(done):
1520
# can take this one now
1521
order.append(rev_id)
1527
class ConvertBzrDir5To6(Converter):
1528
"""Converts format 5 bzr dirs to format 6."""
1530
def convert(self, to_convert, pb):
1531
"""See Converter.convert()."""
1532
self.bzrdir = to_convert
1534
self.pb.note('starting upgrade from format 5 to 6')
1535
self._convert_to_prefixed()
1536
return BzrDir.open(self.bzrdir.root_transport.base)
1538
def _convert_to_prefixed(self):
1539
from bzrlib.store import hash_prefix
1540
self.bzrdir.transport.delete('branch-format')
1541
for store_name in ["weaves", "revision-store"]:
1542
self.pb.note("adding prefixes to %s" % store_name)
1543
store_transport = self.bzrdir.transport.clone(store_name)
1544
for filename in store_transport.list_dir('.'):
1545
if (filename.endswith(".weave") or
1546
filename.endswith(".gz") or
1547
filename.endswith(".sig")):
1548
file_id = os.path.splitext(filename)[0]
1551
prefix_dir = hash_prefix(file_id)
1552
# FIXME keep track of the dirs made RBC 20060121
1554
store_transport.move(filename, prefix_dir + '/' + filename)
1555
except errors.NoSuchFile: # catches missing dirs strangely enough
1556
store_transport.mkdir(prefix_dir)
1557
store_transport.move(filename, prefix_dir + '/' + filename)
1558
self.bzrdir._control_files.put_utf8('branch-format', BzrDirFormat6().get_format_string())
1561
class ConvertBzrDir6ToMeta(Converter):
1562
"""Converts format 6 bzr dirs to metadirs."""
1564
def convert(self, to_convert, pb):
1565
"""See Converter.convert()."""
1566
self.bzrdir = to_convert
1569
self.total = 20 # the steps we know about
1570
self.garbage_inventories = []
1572
self.pb.note('starting upgrade from format 6 to metadir')
1573
self.bzrdir._control_files.put_utf8('branch-format', "Converting to format 6")
1574
# its faster to move specific files around than to open and use the apis...
1575
# first off, nuke ancestry.weave, it was never used.
1577
self.step('Removing ancestry.weave')
1578
self.bzrdir.transport.delete('ancestry.weave')
1579
except errors.NoSuchFile:
1581
# find out whats there
1582
self.step('Finding branch files')
1583
last_revision = self.bzrdir.open_workingtree().last_revision()
1584
bzrcontents = self.bzrdir.transport.list_dir('.')
1585
for name in bzrcontents:
1586
if name.startswith('basis-inventory.'):
1587
self.garbage_inventories.append(name)
1588
# create new directories for repository, working tree and branch
1589
self.dir_mode = self.bzrdir._control_files._dir_mode
1590
self.file_mode = self.bzrdir._control_files._file_mode
1591
repository_names = [('inventory.weave', True),
1592
('revision-store', True),
1594
self.step('Upgrading repository ')
1595
self.bzrdir.transport.mkdir('repository', mode=self.dir_mode)
1596
self.make_lock('repository')
1597
# we hard code the formats here because we are converting into
1598
# the meta format. The meta format upgrader can take this to a
1599
# future format within each component.
1600
self.put_format('repository', bzrlib.repository.RepositoryFormat7())
1601
for entry in repository_names:
1602
self.move_entry('repository', entry)
1604
self.step('Upgrading branch ')
1605
self.bzrdir.transport.mkdir('branch', mode=self.dir_mode)
1606
self.make_lock('branch')
1607
self.put_format('branch', bzrlib.branch.BzrBranchFormat5())
1608
branch_files = [('revision-history', True),
1609
('branch-name', True),
1611
for entry in branch_files:
1612
self.move_entry('branch', entry)
1614
self.step('Upgrading working tree')
1615
self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
1616
self.make_lock('checkout')
1617
self.put_format('checkout', bzrlib.workingtree.WorkingTreeFormat3())
1618
self.bzrdir.transport.delete_multi(self.garbage_inventories, self.pb)
1619
checkout_files = [('pending-merges', True),
1620
('inventory', True),
1621
('stat-cache', False)]
1622
for entry in checkout_files:
1623
self.move_entry('checkout', entry)
1624
if last_revision is not None:
1625
self.bzrdir._control_files.put_utf8('checkout/last-revision',
1627
self.bzrdir._control_files.put_utf8('branch-format', BzrDirMetaFormat1().get_format_string())
1628
return BzrDir.open(self.bzrdir.root_transport.base)
1630
def make_lock(self, name):
1631
"""Make a lock for the new control dir name."""
1632
self.step('Make %s lock' % name)
1633
ld = LockDir(self.bzrdir.transport,
1635
file_modebits=self.file_mode,
1636
dir_modebits=self.dir_mode)
1639
def move_entry(self, new_dir, entry):
1640
"""Move then entry name into new_dir."""
1642
mandatory = entry[1]
1643
self.step('Moving %s' % name)
1645
self.bzrdir.transport.move(name, '%s/%s' % (new_dir, name))
1646
except errors.NoSuchFile:
1650
def put_format(self, dirname, format):
1651
self.bzrdir._control_files.put_utf8('%s/format' % dirname, format.get_format_string())
1654
class ConvertMetaToMeta(Converter):
1781
1655
"""Converts the components of metadirs."""
1783
1657
def __init__(self, target_format):
1802
1676
if not isinstance(repo._format, self.target_format.repository_format.__class__):
1803
1677
from bzrlib.repository import CopyConverter
1804
ui.ui_factory.note(gettext('starting repository conversion'))
1678
self.pb.note('starting repository conversion')
1805
1679
converter = CopyConverter(self.target_format.repository_format)
1806
1680
converter.convert(repo, pb)
1807
for branch in self.bzrdir.list_branches():
1808
# TODO: conversions of Branch and Tree should be done by
1809
# InterXFormat lookups/some sort of registry.
1810
# Avoid circular imports
1811
old = branch._format.__class__
1812
new = self.target_format.get_branch_format().__class__
1814
if (old == _mod_branch.BzrBranchFormat5 and
1815
new in (_mod_branch.BzrBranchFormat6,
1816
_mod_branch.BzrBranchFormat7,
1817
_mod_branch.BzrBranchFormat8)):
1818
branch_converter = _mod_branch.Converter5to6()
1819
elif (old == _mod_branch.BzrBranchFormat6 and
1820
new in (_mod_branch.BzrBranchFormat7,
1821
_mod_branch.BzrBranchFormat8)):
1822
branch_converter = _mod_branch.Converter6to7()
1823
elif (old == _mod_branch.BzrBranchFormat7 and
1824
new is _mod_branch.BzrBranchFormat8):
1825
branch_converter = _mod_branch.Converter7to8()
1827
raise errors.BadConversionTarget("No converter", new,
1829
branch_converter.convert(branch)
1830
branch = self.bzrdir.open_branch()
1831
old = branch._format.__class__
1833
tree = self.bzrdir.open_workingtree(recommend_upgrade=False)
1834
except (errors.NoWorkingTree, errors.NotLocalUrl):
1837
# TODO: conversions of Branch and Tree should be done by
1838
# InterXFormat lookups
1839
if (isinstance(tree, workingtree_3.WorkingTree3) and
1840
not isinstance(tree, workingtree_4.DirStateWorkingTree) and
1841
isinstance(self.target_format.workingtree_format,
1842
workingtree_4.DirStateWorkingTreeFormat)):
1843
workingtree_4.Converter3to4().convert(tree)
1844
if (isinstance(tree, workingtree_4.DirStateWorkingTree) and
1845
not isinstance(tree, workingtree_4.WorkingTree5) and
1846
isinstance(self.target_format.workingtree_format,
1847
workingtree_4.WorkingTreeFormat5)):
1848
workingtree_4.Converter4to5().convert(tree)
1849
if (isinstance(tree, workingtree_4.DirStateWorkingTree) and
1850
not isinstance(tree, workingtree_4.WorkingTree6) and
1851
isinstance(self.target_format.workingtree_format,
1852
workingtree_4.WorkingTreeFormat6)):
1853
workingtree_4.Converter4or5to6().convert(tree)
1855
1681
return to_convert
1858
class ConvertMetaToColo(controldir.Converter):
1859
"""Add colocated branch support."""
1861
def __init__(self, target_format):
1862
"""Create a converter.that upgrades a metadir to the colo format.
1864
:param target_format: The final metadir format that is desired.
1866
self.target_format = target_format
1868
def convert(self, to_convert, pb):
1869
"""See Converter.convert()."""
1870
to_convert.transport.put_bytes('branch-format',
1871
self.target_format.as_string())
1872
return BzrDir.open_from_transport(to_convert.root_transport)
1875
class ConvertMetaToColo(controldir.Converter):
1876
"""Convert a 'development-colo' bzrdir to a '2a' bzrdir."""
1878
def __init__(self, target_format):
1879
"""Create a converter that converts a 'development-colo' metadir
1882
:param target_format: The final metadir format that is desired.
1884
self.target_format = target_format
1886
def convert(self, to_convert, pb):
1887
"""See Converter.convert()."""
1888
to_convert.transport.put_bytes('branch-format',
1889
self.target_format.as_string())
1890
return BzrDir.open_from_transport(to_convert.root_transport)
1893
controldir.ControlDirFormat.register_server_prober(RemoteBzrProber)
1896
class RepositoryAcquisitionPolicy(object):
1897
"""Abstract base class for repository acquisition policies.
1899
A repository acquisition policy decides how a BzrDir acquires a repository
1900
for a branch that is being created. The most basic policy decision is
1901
whether to create a new repository or use an existing one.
1903
def __init__(self, stack_on, stack_on_pwd, require_stacking):
1906
:param stack_on: A location to stack on
1907
:param stack_on_pwd: If stack_on is relative, the location it is
1909
:param require_stacking: If True, it is a failure to not stack.
1911
self._stack_on = stack_on
1912
self._stack_on_pwd = stack_on_pwd
1913
self._require_stacking = require_stacking
1915
def configure_branch(self, branch):
1916
"""Apply any configuration data from this policy to the branch.
1918
Default implementation sets repository stacking.
1920
if self._stack_on is None:
1922
if self._stack_on_pwd is None:
1923
stack_on = self._stack_on
1926
stack_on = urlutils.rebase_url(self._stack_on,
1929
except errors.InvalidRebaseURLs:
1930
stack_on = self._get_full_stack_on()
1932
branch.set_stacked_on_url(stack_on)
1933
except (errors.UnstackableBranchFormat,
1934
errors.UnstackableRepositoryFormat):
1935
if self._require_stacking:
1938
def requires_stacking(self):
1939
"""Return True if this policy requires stacking."""
1940
return self._stack_on is not None and self._require_stacking
1942
def _get_full_stack_on(self):
1943
"""Get a fully-qualified URL for the stack_on location."""
1944
if self._stack_on is None:
1946
if self._stack_on_pwd is None:
1947
return self._stack_on
1949
return urlutils.join(self._stack_on_pwd, self._stack_on)
1951
def _add_fallback(self, repository, possible_transports=None):
1952
"""Add a fallback to the supplied repository, if stacking is set."""
1953
stack_on = self._get_full_stack_on()
1954
if stack_on is None:
1957
stacked_dir = BzrDir.open(stack_on,
1958
possible_transports=possible_transports)
1959
except errors.JailBreak:
1960
# We keep the stacking details, but we are in the server code so
1961
# actually stacking is not needed.
1964
stacked_repo = stacked_dir.open_branch().repository
1965
except errors.NotBranchError:
1966
stacked_repo = stacked_dir.open_repository()
1968
repository.add_fallback_repository(stacked_repo)
1969
except errors.UnstackableRepositoryFormat:
1970
if self._require_stacking:
1973
self._require_stacking = True
1975
def acquire_repository(self, make_working_trees=None, shared=False,
1976
possible_transports=None):
1977
"""Acquire a repository for this bzrdir.
1979
Implementations may create a new repository or use a pre-exising
1982
:param make_working_trees: If creating a repository, set
1983
make_working_trees to this value (if non-None)
1984
:param shared: If creating a repository, make it shared if True
1985
:return: A repository, is_new_flag (True if the repository was
1988
raise NotImplementedError(RepositoryAcquisitionPolicy.acquire_repository)
1991
class CreateRepository(RepositoryAcquisitionPolicy):
1992
"""A policy of creating a new repository"""
1994
def __init__(self, bzrdir, stack_on=None, stack_on_pwd=None,
1995
require_stacking=False):
1998
:param bzrdir: The bzrdir to create the repository on.
1999
:param stack_on: A location to stack on
2000
:param stack_on_pwd: If stack_on is relative, the location it is
2003
RepositoryAcquisitionPolicy.__init__(self, stack_on, stack_on_pwd,
2005
self._bzrdir = bzrdir
2007
def acquire_repository(self, make_working_trees=None, shared=False,
2008
possible_transports=None):
2009
"""Implementation of RepositoryAcquisitionPolicy.acquire_repository
2011
Creates the desired repository in the bzrdir we already have.
2013
if possible_transports is None:
2014
possible_transports = []
2016
possible_transports = list(possible_transports)
2017
possible_transports.append(self._bzrdir.root_transport)
2018
stack_on = self._get_full_stack_on()
2020
format = self._bzrdir._format
2021
format.require_stacking(stack_on=stack_on,
2022
possible_transports=possible_transports)
2023
if not self._require_stacking:
2024
# We have picked up automatic stacking somewhere.
2025
note(gettext('Using default stacking branch {0} at {1}').format(
2026
self._stack_on, self._stack_on_pwd))
2027
repository = self._bzrdir.create_repository(shared=shared)
2028
self._add_fallback(repository,
2029
possible_transports=possible_transports)
2030
if make_working_trees is not None:
2031
repository.set_make_working_trees(make_working_trees)
2032
return repository, True
2035
class UseExistingRepository(RepositoryAcquisitionPolicy):
2036
"""A policy of reusing an existing repository"""
2038
def __init__(self, repository, stack_on=None, stack_on_pwd=None,
2039
require_stacking=False):
2042
:param repository: The repository to use.
2043
:param stack_on: A location to stack on
2044
:param stack_on_pwd: If stack_on is relative, the location it is
2047
RepositoryAcquisitionPolicy.__init__(self, stack_on, stack_on_pwd,
2049
self._repository = repository
2051
def acquire_repository(self, make_working_trees=None, shared=False,
2052
possible_transports=None):
2053
"""Implementation of RepositoryAcquisitionPolicy.acquire_repository
2055
Returns an existing repository to use.
2057
if possible_transports is None:
2058
possible_transports = []
2060
possible_transports = list(possible_transports)
2061
possible_transports.append(self._repository.bzrdir.transport)
2062
self._add_fallback(self._repository,
2063
possible_transports=possible_transports)
2064
return self._repository, False
2067
def register_metadir(registry, key,
2068
repository_format, help, native=True, deprecated=False,
2073
alias=False, bzrdir_format=None):
2074
"""Register a metadir subformat.
2076
These all use a meta bzrdir, but can be parameterized by the
2077
Repository/Branch/WorkingTreeformats.
2079
:param repository_format: The fully-qualified repository format class
2081
:param branch_format: Fully-qualified branch format class name as
2083
:param tree_format: Fully-qualified tree format class name as
2086
if bzrdir_format is None:
2087
bzrdir_format = BzrDirMetaFormat1
2088
# This should be expanded to support setting WorkingTree and Branch
2089
# formats, once the API supports that.
2090
def _load(full_name):
2091
mod_name, factory_name = full_name.rsplit('.', 1)
2093
factory = pyutils.get_named_object(mod_name, factory_name)
2094
except ImportError, e:
2095
raise ImportError('failed to load %s: %s' % (full_name, e))
2096
except AttributeError:
2097
raise AttributeError('no factory %s in module %r'
2098
% (full_name, sys.modules[mod_name]))
2102
bd = bzrdir_format()
2103
if branch_format is not None:
2104
bd.set_branch_format(_load(branch_format))
2105
if tree_format is not None:
2106
bd.workingtree_format = _load(tree_format)
2107
if repository_format is not None:
2108
bd.repository_format = _load(repository_format)
2110
registry.register(key, helper, help, native, deprecated, hidden,
2111
experimental, alias)
2113
register_metadir(controldir.format_registry, 'knit',
2114
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2115
'Format using knits. Recommended for interoperation with bzr <= 0.14.',
2116
branch_format='bzrlib.branch.BzrBranchFormat5',
2117
tree_format='bzrlib.workingtree_3.WorkingTreeFormat3',
2120
register_metadir(controldir.format_registry, 'dirstate',
2121
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2122
help='Format using dirstate for working trees. '
2123
'Compatible with bzr 0.8 and '
2124
'above when accessed over the network. Introduced in bzr 0.15.',
2125
branch_format='bzrlib.branch.BzrBranchFormat5',
2126
tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2129
register_metadir(controldir.format_registry, 'dirstate-tags',
2130
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2131
help='Variant of dirstate with support for tags. '
2132
'Introduced in bzr 0.15.',
2133
branch_format='bzrlib.branch.BzrBranchFormat6',
2134
tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2137
register_metadir(controldir.format_registry, 'rich-root',
2138
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit4',
2139
help='Variant of dirstate with better handling of tree roots. '
2140
'Introduced in bzr 1.0',
2141
branch_format='bzrlib.branch.BzrBranchFormat6',
2142
tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2145
register_metadir(controldir.format_registry, 'dirstate-with-subtree',
2146
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
2147
help='Variant of dirstate with support for nested trees. '
2148
'Introduced in 0.15.',
2149
branch_format='bzrlib.branch.BzrBranchFormat6',
2150
tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2154
register_metadir(controldir.format_registry, 'pack-0.92',
2155
'bzrlib.repofmt.knitpack_repo.RepositoryFormatKnitPack1',
2156
help='Pack-based format used in 1.x series. Introduced in 0.92. '
2157
'Interoperates with bzr repositories before 0.92 but cannot be '
2158
'read by bzr < 0.92. '
2160
branch_format='bzrlib.branch.BzrBranchFormat6',
2161
tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2164
register_metadir(controldir.format_registry, 'pack-0.92-subtree',
2165
'bzrlib.repofmt.knitpack_repo.RepositoryFormatKnitPack3',
2166
help='Pack-based format used in 1.x series, with subtree support. '
2167
'Introduced in 0.92. Interoperates with '
2168
'bzr repositories before 0.92 but cannot be read by bzr < 0.92. '
2170
branch_format='bzrlib.branch.BzrBranchFormat6',
2171
tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2176
register_metadir(controldir.format_registry, 'rich-root-pack',
2177
'bzrlib.repofmt.knitpack_repo.RepositoryFormatKnitPack4',
2178
help='A variant of pack-0.92 that supports rich-root data '
2179
'(needed for bzr-svn and bzr-git). Introduced in 1.0.',
2180
branch_format='bzrlib.branch.BzrBranchFormat6',
2181
tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2185
register_metadir(controldir.format_registry, '1.6',
2186
'bzrlib.repofmt.knitpack_repo.RepositoryFormatKnitPack5',
2187
help='A format that allows a branch to indicate that there is another '
2188
'(stacked) repository that should be used to access data that is '
2189
'not present locally.',
2190
branch_format='bzrlib.branch.BzrBranchFormat7',
2191
tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2195
register_metadir(controldir.format_registry, '1.6.1-rich-root',
2196
'bzrlib.repofmt.knitpack_repo.RepositoryFormatKnitPack5RichRoot',
2197
help='A variant of 1.6 that supports rich-root data '
2198
'(needed for bzr-svn and bzr-git).',
2199
branch_format='bzrlib.branch.BzrBranchFormat7',
2200
tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2204
register_metadir(controldir.format_registry, '1.9',
2205
'bzrlib.repofmt.knitpack_repo.RepositoryFormatKnitPack6',
2206
help='A repository format using B+tree indexes. These indexes '
2207
'are smaller in size, have smarter caching and provide faster '
2208
'performance for most operations.',
2209
branch_format='bzrlib.branch.BzrBranchFormat7',
2210
tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2214
register_metadir(controldir.format_registry, '1.9-rich-root',
2215
'bzrlib.repofmt.knitpack_repo.RepositoryFormatKnitPack6RichRoot',
2216
help='A variant of 1.9 that supports rich-root data '
2217
'(needed for bzr-svn and bzr-git).',
2218
branch_format='bzrlib.branch.BzrBranchFormat7',
2219
tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2223
register_metadir(controldir.format_registry, '1.14',
2224
'bzrlib.repofmt.knitpack_repo.RepositoryFormatKnitPack6',
2225
help='A working-tree format that supports content filtering.',
2226
branch_format='bzrlib.branch.BzrBranchFormat7',
2227
tree_format='bzrlib.workingtree_4.WorkingTreeFormat5',
2231
register_metadir(controldir.format_registry, '1.14-rich-root',
2232
'bzrlib.repofmt.knitpack_repo.RepositoryFormatKnitPack6RichRoot',
2233
help='A variant of 1.14 that supports rich-root data '
2234
'(needed for bzr-svn and bzr-git).',
2235
branch_format='bzrlib.branch.BzrBranchFormat7',
2236
tree_format='bzrlib.workingtree_4.WorkingTreeFormat5',
2240
# The following un-numbered 'development' formats should always just be aliases.
2241
register_metadir(controldir.format_registry, 'development-subtree',
2242
'bzrlib.repofmt.groupcompress_repo.RepositoryFormat2aSubtree',
2243
help='Current development format, subtree variant. Can convert data to and '
2244
'from pack-0.92-subtree (and anything compatible with '
2245
'pack-0.92-subtree) format repositories. Repositories and branches in '
2246
'this format can only be read by bzr.dev. Please read '
2247
'http://doc.bazaar.canonical.com/latest/developers/development-repo.html '
2249
branch_format='bzrlib.branch.BzrBranchFormat7',
2250
tree_format='bzrlib.workingtree_4.WorkingTreeFormat6',
2253
alias=False, # Restore to being an alias when an actual development subtree format is added
2254
# This current non-alias status is simply because we did not introduce a
2255
# chk based subtree format.
2257
register_metadir(controldir.format_registry, 'development5-subtree',
2258
'bzrlib.repofmt.knitpack_repo.RepositoryFormatPackDevelopment2Subtree',
2259
help='Development format, subtree variant. Can convert data to and '
2260
'from pack-0.92-subtree (and anything compatible with '
2261
'pack-0.92-subtree) format repositories. Repositories and branches in '
2262
'this format can only be read by bzr.dev. Please read '
2263
'http://doc.bazaar.canonical.com/latest/developers/development-repo.html '
2265
branch_format='bzrlib.branch.BzrBranchFormat7',
2266
tree_format='bzrlib.workingtree_4.WorkingTreeFormat6',
2272
register_metadir(controldir.format_registry, 'development-colo',
2273
'bzrlib.repofmt.groupcompress_repo.RepositoryFormat2a',
2274
help='The 2a format with experimental support for colocated branches.\n',
2275
branch_format='bzrlib.branch.BzrBranchFormat7',
2276
tree_format='bzrlib.workingtree_4.WorkingTreeFormat6',
2278
bzrdir_format=BzrDirMetaFormat1Colo,
2282
# And the development formats above will have aliased one of the following:
2284
# Finally, the current format.
2285
register_metadir(controldir.format_registry, '2a',
2286
'bzrlib.repofmt.groupcompress_repo.RepositoryFormat2a',
2287
help='Format for the bzr 2.0 series.\n'
2288
'Uses group-compress storage.\n'
2289
'Provides rich roots which are a one-way transition.\n',
2290
# 'storage in packs, 255-way hashed CHK inventory, bencode revision, group compress, '
2291
# 'rich roots. Supported by bzr 1.16 and later.',
2292
branch_format='bzrlib.branch.BzrBranchFormat7',
2293
tree_format='bzrlib.workingtree_4.WorkingTreeFormat6',
2297
# The following format should be an alias for the rich root equivalent
2298
# of the default format
2299
register_metadir(controldir.format_registry, 'default-rich-root',
2300
'bzrlib.repofmt.groupcompress_repo.RepositoryFormat2a',
2301
branch_format='bzrlib.branch.BzrBranchFormat7',
2302
tree_format='bzrlib.workingtree_4.WorkingTreeFormat6',
2307
# The current format that is made on 'bzr init'.
2308
format_name = config.GlobalStack().get('default_format')
2309
controldir.format_registry.set_default(format_name)
2311
# XXX 2010-08-20 JRV: There is still a lot of code relying on
2312
# bzrlib.bzrdir.format_registry existing. When BzrDir.create/BzrDir.open/etc
2313
# get changed to ControlDir.create/ControlDir.open/etc this should be removed.
2314
format_registry = controldir.format_registry