81
113
thing_to_unlock.break_lock()
83
def can_convert_format(self):
84
"""Return true if this bzrdir is one whose format we can convert from."""
88
def _check_supported(format, allow_unsupported):
89
"""Check whether format is a supported format.
91
If allow_unsupported is True, this is a no-op.
93
if not allow_unsupported and not format.is_supported():
94
# see open_downlevel to open legacy branches.
95
raise errors.UnsupportedFormatError(
96
'sorry, format %s not supported' % format,
97
['use a different bzr version',
98
'or remove the .bzr directory'
99
' and "bzr init" again'])
101
def clone(self, url, revision_id=None, basis=None, force_new_repo=False):
102
"""Clone this bzrdir and its contents to url verbatim.
104
If urls last component does not exist, it will be created.
106
if revision_id is not None, then the clone operation may tune
115
def check_conversion_target(self, target_format):
116
"""Check that a bzrdir as a whole can be converted to a new format."""
117
# The only current restriction is that the repository content can be
118
# fetched compatibly with the target.
119
target_repo_format = target_format.repository_format
121
self.open_repository()._format.check_conversion_target(
123
except errors.NoRepositoryPresent:
124
# No repo, no problem.
127
def clone_on_transport(self, transport, revision_id=None,
128
force_new_repo=False, preserve_stacking=False, stacked_on=None,
129
create_prefix=False, use_existing_dir=True, no_tree=False):
130
"""Clone this bzrdir and its contents to transport verbatim.
132
:param transport: The transport for the location to produce the clone
133
at. If the target directory does not exist, it will be created.
134
:param revision_id: The tip revision-id to use for any branch or
135
working tree. If not None, then the clone operation may tune
107
136
itself to download less data.
108
:param force_new_repo: Do not use a shared repository for the target
137
:param force_new_repo: Do not use a shared repository for the target,
109
138
even if one is available.
139
:param preserve_stacking: When cloning a stacked branch, stack the
140
new branch on top of the other branch's stacked-on branch.
141
:param create_prefix: Create any missing directories leading up to
143
:param use_existing_dir: Use an existing directory if one exists.
144
:param no_tree: If set to true prevents creation of a working tree.
112
basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
113
result = self._format.initialize(url)
146
# Overview: put together a broad description of what we want to end up
147
# with; then make as few api calls as possible to do it.
149
# We may want to create a repo/branch/tree, if we do so what format
150
# would we want for each:
151
require_stacking = (stacked_on is not None)
152
format = self.cloning_metadir(require_stacking)
154
# Figure out what objects we want:
115
156
local_repo = self.find_repository()
116
157
except errors.NoRepositoryPresent:
117
158
local_repo = None
160
local_branch = self.open_branch()
161
except errors.NotBranchError:
164
# enable fallbacks when branch is not a branch reference
165
if local_branch.repository.has_same_location(local_repo):
166
local_repo = local_branch.repository
167
if preserve_stacking:
169
stacked_on = local_branch.get_stacked_on_url()
170
except (errors.UnstackableBranchFormat,
171
errors.UnstackableRepositoryFormat,
174
# Bug: We create a metadir without knowing if it can support stacking,
175
# we should look up the policy needs first, or just use it as a hint,
119
# may need to copy content in
121
result_repo = local_repo.clone(
123
revision_id=revision_id,
125
result_repo.set_make_working_trees(local_repo.make_working_trees())
128
result_repo = result.find_repository()
129
# fetch content this dir needs.
131
# XXX FIXME RBC 20060214 need tests for this when the basis
133
result_repo.fetch(basis_repo, revision_id=revision_id)
178
make_working_trees = local_repo.make_working_trees() and not no_tree
179
want_shared = local_repo.is_shared()
180
repo_format_name = format.repository_format.network_name()
182
make_working_trees = False
184
repo_format_name = None
186
result_repo, result, require_stacking, repository_policy = \
187
format.initialize_on_transport_ex(transport,
188
use_existing_dir=use_existing_dir, create_prefix=create_prefix,
189
force_new_repo=force_new_repo, stacked_on=stacked_on,
190
stack_on_pwd=self.root_transport.base,
191
repo_format_name=repo_format_name,
192
make_working_trees=make_working_trees, shared_repo=want_shared)
195
# If the result repository is in the same place as the
196
# resulting bzr dir, it will have no content, further if the
197
# result is not stacked then we know all content should be
198
# copied, and finally if we are copying up to a specific
199
# revision_id then we can use the pending-ancestry-result which
200
# does not require traversing all of history to describe it.
201
if (result_repo.user_url == result.user_url
202
and not require_stacking and
203
revision_id is not None):
204
fetch_spec = graph.PendingAncestryResult(
205
[revision_id], local_repo)
206
result_repo.fetch(local_repo, fetch_spec=fetch_spec)
134
208
result_repo.fetch(local_repo, revision_id=revision_id)
135
except errors.NoRepositoryPresent:
136
# needed to make one anyway.
137
result_repo = local_repo.clone(
139
revision_id=revision_id,
141
result_repo.set_make_working_trees(local_repo.make_working_trees())
212
if result_repo is not None:
213
raise AssertionError('result_repo not None(%r)' % result_repo)
142
214
# 1 if there is a branch present
143
215
# make sure its content is available in the target repository
146
self.open_branch().clone(result, revision_id=revision_id)
147
except errors.NotBranchError:
150
self.open_workingtree().clone(result, basis=basis_tree)
217
if local_branch is not None:
218
result_branch = local_branch.clone(result, revision_id=revision_id,
219
repository_policy=repository_policy)
221
# Cheaper to check if the target is not local, than to try making
223
result.root_transport.local_abspath('.')
224
if result_repo is None or result_repo.make_working_trees():
225
self.open_workingtree().clone(result)
151
226
except (errors.NoWorkingTree, errors.NotLocalUrl):
155
def _get_basis_components(self, basis):
156
"""Retrieve the basis components that are available at basis."""
158
return None, None, None
160
basis_tree = basis.open_workingtree()
161
basis_branch = basis_tree.branch
162
basis_repo = basis_branch.repository
163
except (errors.NoWorkingTree, errors.NotLocalUrl):
166
basis_branch = basis.open_branch()
167
basis_repo = basis_branch.repository
168
except errors.NotBranchError:
171
basis_repo = basis.open_repository()
172
except errors.NoRepositoryPresent:
174
return basis_repo, basis_branch, basis_tree
176
230
# TODO: This should be given a Transport, and should chdir up; otherwise
177
231
# this will open a new connection.
178
232
def _make_tail(self, url):
179
head, tail = urlutils.split(url)
180
if tail and tail != '.':
181
t = bzrlib.transport.get_transport(head)
184
except errors.FileExists:
187
# TODO: Should take a Transport
189
def create(cls, base):
190
"""Create a new BzrDir at the url 'base'.
192
This will call the current default formats initialize with base
193
as the only parameter.
195
If you need a specific format, consider creating an instance
196
of that and calling initialize().
198
if cls is not BzrDir:
199
raise AssertionError("BzrDir.create always creates the default format, "
200
"not one of %r" % cls)
201
head, tail = urlutils.split(base)
202
if tail and tail != '.':
203
t = bzrlib.transport.get_transport(head)
206
except errors.FileExists:
208
return BzrDirFormat.get_default_format().initialize(safe_unicode(base))
210
def create_branch(self):
211
"""Create a branch in this BzrDir.
213
The bzrdirs format will control what branch format is created.
214
For more control see BranchFormatXX.create(a_bzrdir).
216
raise NotImplementedError(self.create_branch)
219
def create_branch_and_repo(base, force_new_repo=False):
233
t = _mod_transport.get_transport(url)
237
def find_bzrdirs(transport, evaluate=None, list_current=None):
238
"""Find bzrdirs recursively from current location.
240
This is intended primarily as a building block for more sophisticated
241
functionality, like finding trees under a directory, or finding
242
branches that use a given repository.
244
:param evaluate: An optional callable that yields recurse, value,
245
where recurse controls whether this bzrdir is recursed into
246
and value is the value to yield. By default, all bzrdirs
247
are recursed into, and the return value is the bzrdir.
248
:param list_current: if supplied, use this function to list the current
249
directory, instead of Transport.list_dir
250
:return: a generator of found bzrdirs, or whatever evaluate returns.
252
if list_current is None:
253
def list_current(transport):
254
return transport.list_dir('')
256
def evaluate(bzrdir):
259
pending = [transport]
260
while len(pending) > 0:
261
current_transport = pending.pop()
264
bzrdir = BzrDir.open_from_transport(current_transport)
265
except (errors.NotBranchError, errors.PermissionDenied):
268
recurse, value = evaluate(bzrdir)
271
subdirs = list_current(current_transport)
272
except (errors.NoSuchFile, errors.PermissionDenied):
275
for subdir in sorted(subdirs, reverse=True):
276
pending.append(current_transport.clone(subdir))
279
def find_branches(transport):
280
"""Find all branches under a transport.
282
This will find all branches below the transport, including branches
283
inside other branches. Where possible, it will use
284
Repository.find_branches.
286
To list all the branches that use a particular Repository, see
287
Repository.find_branches
289
def evaluate(bzrdir):
291
repository = bzrdir.open_repository()
292
except errors.NoRepositoryPresent:
295
return False, ([], repository)
296
return True, (bzrdir.list_branches(), None)
298
for branches, repo in BzrDir.find_bzrdirs(transport,
301
ret.extend(repo.find_branches())
302
if branches is not None:
307
def create_branch_and_repo(base, force_new_repo=False, format=None):
220
308
"""Create a new BzrDir, Branch and Repository at the url 'base'.
222
This will use the current default BzrDirFormat, and use whatever
310
This will use the current default BzrDirFormat unless one is
311
specified, and use whatever
223
312
repository format that that uses via bzrdir.create_branch and
224
313
create_repository. If a shared repository is available that is used
229
318
:param base: The URL to create the branch at.
230
319
:param force_new_repo: If True a new repository is always created.
320
:param format: If supplied, the format of branch to create. If not
321
supplied, the default is used.
232
bzrdir = BzrDir.create(base)
323
bzrdir = BzrDir.create(base, format)
233
324
bzrdir._find_or_create_repository(force_new_repo)
234
325
return bzrdir.create_branch()
327
def determine_repository_policy(self, force_new_repo=False, stack_on=None,
328
stack_on_pwd=None, require_stacking=False):
329
"""Return an object representing a policy to use.
331
This controls whether a new repository is created, and the format of
332
that repository, or some existing shared repository used instead.
334
If stack_on is supplied, will not seek a containing shared repo.
336
:param force_new_repo: If True, require a new repository to be created.
337
:param stack_on: If supplied, the location to stack on. If not
338
supplied, a default_stack_on location may be used.
339
:param stack_on_pwd: If stack_on is relative, the location it is
342
def repository_policy(found_bzrdir):
345
config = found_bzrdir.get_config()
347
stack_on = config.get_default_stack_on()
348
if stack_on is not None:
349
stack_on_pwd = found_bzrdir.user_url
351
# does it have a repository ?
353
repository = found_bzrdir.open_repository()
354
except errors.NoRepositoryPresent:
357
if (found_bzrdir.user_url != self.user_url
358
and not repository.is_shared()):
359
# Don't look higher, can't use a higher shared repo.
367
return UseExistingRepository(repository, stack_on,
368
stack_on_pwd, require_stacking=require_stacking), True
370
return CreateRepository(self, stack_on, stack_on_pwd,
371
require_stacking=require_stacking), True
373
if not force_new_repo:
375
policy = self._find_containing(repository_policy)
376
if policy is not None:
380
return UseExistingRepository(self.open_repository(),
381
stack_on, stack_on_pwd,
382
require_stacking=require_stacking)
383
except errors.NoRepositoryPresent:
385
return CreateRepository(self, stack_on, stack_on_pwd,
386
require_stacking=require_stacking)
236
388
def _find_or_create_repository(self, force_new_repo):
237
389
"""Create a new repository if needed, returning the repository."""
239
return self.create_repository()
390
policy = self.determine_repository_policy(force_new_repo)
391
return policy.acquire_repository()[0]
393
def _find_source_repo(self, add_cleanup, source_branch):
394
"""Find the source branch and repo for a sprout operation.
396
This is helper intended for use by _sprout.
398
:returns: (source_branch, source_repository). Either or both may be
399
None. If not None, they will be read-locked (and their unlock(s)
400
scheduled via the add_cleanup param).
402
if source_branch is not None:
403
add_cleanup(source_branch.lock_read().unlock)
404
return source_branch, source_branch.repository
241
return self.find_repository()
242
except errors.NoRepositoryPresent:
243
return self.create_repository()
406
source_branch = self.open_branch()
407
source_repository = source_branch.repository
408
except errors.NotBranchError:
411
source_repository = self.open_repository()
412
except errors.NoRepositoryPresent:
413
source_repository = None
415
add_cleanup(source_repository.lock_read().unlock)
417
add_cleanup(source_branch.lock_read().unlock)
418
return source_branch, source_repository
420
def sprout(self, url, revision_id=None, force_new_repo=False,
421
recurse='down', possible_transports=None,
422
accelerator_tree=None, hardlink=False, stacked=False,
423
source_branch=None, create_tree_if_local=True):
424
"""Create a copy of this controldir prepared for use as a new line of
427
If url's last component does not exist, it will be created.
429
Attributes related to the identity of the source branch like
430
branch nickname will be cleaned, a working tree is created
431
whether one existed before or not; and a local branch is always
434
if revision_id is not None, then the clone operation may tune
435
itself to download less data.
437
:param accelerator_tree: A tree which can be used for retrieving file
438
contents more quickly than the revision tree, i.e. a workingtree.
439
The revision tree will be used for cases where accelerator_tree's
440
content is different.
441
:param hardlink: If true, hard-link files from accelerator_tree,
443
:param stacked: If true, create a stacked branch referring to the
444
location of this control directory.
445
:param create_tree_if_local: If true, a working-tree will be created
446
when working locally.
448
operation = cleanup.OperationWithCleanups(self._sprout)
449
return operation.run(url, revision_id=revision_id,
450
force_new_repo=force_new_repo, recurse=recurse,
451
possible_transports=possible_transports,
452
accelerator_tree=accelerator_tree, hardlink=hardlink,
453
stacked=stacked, source_branch=source_branch,
454
create_tree_if_local=create_tree_if_local)
456
def _sprout(self, op, url, revision_id=None, force_new_repo=False,
457
recurse='down', possible_transports=None,
458
accelerator_tree=None, hardlink=False, stacked=False,
459
source_branch=None, create_tree_if_local=True):
460
add_cleanup = op.add_cleanup
461
fetch_spec_factory = fetch.FetchSpecFactory()
462
if revision_id is not None:
463
fetch_spec_factory.add_revision_ids([revision_id])
464
fetch_spec_factory.source_branch_stop_revision_id = revision_id
465
target_transport = _mod_transport.get_transport(url,
467
target_transport.ensure_base()
468
cloning_format = self.cloning_metadir(stacked)
469
# Create/update the result branch
470
result = cloning_format.initialize_on_transport(target_transport)
471
source_branch, source_repository = self._find_source_repo(
472
add_cleanup, source_branch)
473
fetch_spec_factory.source_branch = source_branch
474
# if a stacked branch wasn't requested, we don't create one
475
# even if the origin was stacked
476
if stacked and source_branch is not None:
477
stacked_branch_url = self.root_transport.base
479
stacked_branch_url = None
480
repository_policy = result.determine_repository_policy(
481
force_new_repo, stacked_branch_url, require_stacking=stacked)
482
result_repo, is_new_repo = repository_policy.acquire_repository()
483
add_cleanup(result_repo.lock_write().unlock)
484
fetch_spec_factory.source_repo = source_repository
485
fetch_spec_factory.target_repo = result_repo
486
if stacked or (len(result_repo._fallback_repositories) != 0):
487
target_repo_kind = fetch.TargetRepoKinds.STACKED
489
target_repo_kind = fetch.TargetRepoKinds.EMPTY
491
target_repo_kind = fetch.TargetRepoKinds.PREEXISTING
492
fetch_spec_factory.target_repo_kind = target_repo_kind
493
if source_repository is not None:
494
fetch_spec = fetch_spec_factory.make_fetch_spec()
495
result_repo.fetch(source_repository, fetch_spec=fetch_spec)
497
if source_branch is None:
498
# this is for sprouting a controldir without a branch; is that
500
# Not especially, but it's part of the contract.
501
result_branch = result.create_branch()
503
result_branch = source_branch.sprout(result,
504
revision_id=revision_id, repository_policy=repository_policy,
505
repository=result_repo)
506
mutter("created new branch %r" % (result_branch,))
508
# Create/update the result working tree
509
if (create_tree_if_local and
510
isinstance(target_transport, local.LocalTransport) and
511
(result_repo is None or result_repo.make_working_trees())):
512
wt = result.create_workingtree(accelerator_tree=accelerator_tree,
513
hardlink=hardlink, from_branch=result_branch)
516
if wt.path2id('') is None:
518
wt.set_root_id(self.open_workingtree.get_root_id())
519
except errors.NoWorkingTree:
525
if recurse == 'down':
528
basis = wt.basis_tree()
529
elif result_branch is not None:
530
basis = result_branch.basis_tree()
531
elif source_branch is not None:
532
basis = source_branch.basis_tree()
533
if basis is not None:
534
add_cleanup(basis.lock_read().unlock)
535
subtrees = basis.iter_references()
538
for path, file_id in subtrees:
539
target = urlutils.join(url, urlutils.escape(path))
540
sublocation = source_branch.reference_parent(file_id, path)
541
sublocation.bzrdir.sprout(target,
542
basis.get_reference_revision(file_id, path),
543
force_new_repo=force_new_repo, recurse=recurse,
246
548
def create_branch_convenience(base, force_new_repo=False,
247
force_new_tree=None, format=None):
549
force_new_tree=None, format=None,
550
possible_transports=None):
248
551
"""Create a new BzrDir, Branch and Repository at the url 'base'.
250
553
This is a convenience function - it will use an existing repository
251
554
if possible, can be told explicitly whether to create a working tree or
254
This will use the current default BzrDirFormat, and use whatever
557
This will use the current default BzrDirFormat unless one is
558
specified, and use whatever
255
559
repository format that that uses via bzrdir.create_branch and
256
560
create_repository. If a shared repository is available that is used
257
561
preferentially. Whatever repository is used, its tree creation policy
260
564
The created Branch object is returned.
261
565
If a working tree cannot be made due to base not being a file:// url,
262
no error is raised unless force_new_tree is True, in which case no
566
no error is raised unless force_new_tree is True, in which case no
263
567
data is created on disk and NotLocalUrl is raised.
265
569
:param base: The URL to create the branch at.
266
570
:param force_new_repo: If True a new repository is always created.
267
:param force_new_tree: If True or False force creation of a tree or
571
:param force_new_tree: If True or False force creation of a tree or
268
572
prevent such creation respectively.
269
:param format: Override for the for the bzrdir format to create
573
:param format: Override for the bzrdir format to create.
574
:param possible_transports: An optional reusable transports list.
271
576
if force_new_tree:
272
577
# check for non local urls
273
t = get_transport(safe_unicode(base))
274
if not isinstance(t, LocalTransport):
578
t = _mod_transport.get_transport(base, possible_transports)
579
if not isinstance(t, local.LocalTransport):
275
580
raise errors.NotLocalUrl(base)
277
bzrdir = BzrDir.create(base)
279
bzrdir = format.initialize(base)
581
bzrdir = BzrDir.create(base, format, possible_transports)
280
582
repo = bzrdir._find_or_create_repository(force_new_repo)
281
583
result = bzrdir.create_branch()
282
if force_new_tree or (repo.make_working_trees() and
584
if force_new_tree or (repo.make_working_trees() and
283
585
force_new_tree is None):
285
587
bzrdir.create_workingtree()
286
588
except errors.NotLocalUrl:
291
def create_repository(base, shared=False):
292
"""Create a new BzrDir and Repository at the url 'base'.
294
This will use the current default BzrDirFormat, and use whatever
295
repository format that that uses for bzrdirformat.create_repository.
297
;param shared: Create a shared repository rather than a standalone
299
The Repository object is returned.
301
This must be overridden as an instance method in child classes, where
302
it should take no parameters and construct whatever repository format
303
that child class desires.
305
bzrdir = BzrDir.create(base)
306
return bzrdir.create_repository()
309
def create_standalone_workingtree(base):
593
def create_standalone_workingtree(base, format=None):
310
594
"""Create a new BzrDir, WorkingTree, Branch and Repository at 'base'.
312
596
'base' must be a local path or a file:// url.
314
This will use the current default BzrDirFormat, and use whatever
598
This will use the current default BzrDirFormat unless one is
599
specified, and use whatever
315
600
repository format that that uses for bzrdirformat.create_workingtree,
316
601
create_branch and create_repository.
318
The WorkingTree object is returned.
603
:param format: Override for the bzrdir format to create.
604
:return: The WorkingTree object.
320
t = get_transport(safe_unicode(base))
321
if not isinstance(t, LocalTransport):
606
t = _mod_transport.get_transport(base)
607
if not isinstance(t, local.LocalTransport):
322
608
raise errors.NotLocalUrl(base)
323
bzrdir = BzrDir.create_branch_and_repo(safe_unicode(base),
324
force_new_repo=True).bzrdir
609
bzrdir = BzrDir.create_branch_and_repo(base,
611
format=format).bzrdir
325
612
return bzrdir.create_workingtree()
327
def create_workingtree(self, revision_id=None):
328
"""Create a working tree at this BzrDir.
330
revision_id: create it as of this revision id.
332
raise NotImplementedError(self.create_workingtree)
614
@deprecated_method(deprecated_in((2, 3, 0)))
615
def generate_backup_name(self, base):
616
return self._available_backup_name(base)
618
def _available_backup_name(self, base):
619
"""Find a non-existing backup file name based on base.
621
See bzrlib.osutils.available_backup_name about race conditions.
623
return osutils.available_backup_name(base, self.root_transport.has)
625
def backup_bzrdir(self):
626
"""Backup this bzr control directory.
628
:return: Tuple with old path name and new path name
631
pb = ui.ui_factory.nested_progress_bar()
633
old_path = self.root_transport.abspath('.bzr')
634
backup_dir = self._available_backup_name('backup.bzr')
635
new_path = self.root_transport.abspath(backup_dir)
636
ui.ui_factory.note(gettext('making backup of {0}\n to {1}').format(
637
urlutils.unescape_for_display(old_path, 'utf-8'),
638
urlutils.unescape_for_display(new_path, 'utf-8')))
639
self.root_transport.copy_tree('.bzr', backup_dir)
640
return (old_path, new_path)
644
def retire_bzrdir(self, limit=10000):
645
"""Permanently disable the bzrdir.
647
This is done by renaming it to give the user some ability to recover
648
if there was a problem.
650
This will have horrible consequences if anyone has anything locked or
652
:param limit: number of times to retry
657
to_path = '.bzr.retired.%d' % i
658
self.root_transport.rename('.bzr', to_path)
659
note(gettext("renamed {0} to {1}").format(
660
self.root_transport.abspath('.bzr'), to_path))
662
except (errors.TransportError, IOError, errors.PathError):
669
def _find_containing(self, evaluate):
670
"""Find something in a containing control directory.
672
This method will scan containing control dirs, until it finds what
673
it is looking for, decides that it will never find it, or runs out
674
of containing control directories to check.
676
It is used to implement find_repository and
677
determine_repository_policy.
679
:param evaluate: A function returning (value, stop). If stop is True,
680
the value will be returned.
684
result, stop = evaluate(found_bzrdir)
687
next_transport = found_bzrdir.root_transport.clone('..')
688
if (found_bzrdir.user_url == next_transport.base):
689
# top of the file system
691
# find the next containing bzrdir
693
found_bzrdir = BzrDir.open_containing_from_transport(
695
except errors.NotBranchError:
334
698
def find_repository(self):
335
"""Find the repository that should be used for a_bzrdir.
699
"""Find the repository that should be used.
337
701
This does not require a branch as we use it to find the repo for
338
702
new branches as well as to hook existing branches up to their
342
return self.open_repository()
343
except errors.NoRepositoryPresent:
345
next_transport = self.root_transport.clone('..')
347
# find the next containing bzrdir
349
found_bzrdir = BzrDir.open_containing_from_transport(
351
except errors.NotBranchError:
353
raise errors.NoRepositoryPresent(self)
705
def usable_repository(found_bzrdir):
354
706
# does it have a repository ?
356
708
repository = found_bzrdir.open_repository()
357
709
except errors.NoRepositoryPresent:
358
next_transport = found_bzrdir.root_transport.clone('..')
359
if (found_bzrdir.root_transport.base == next_transport.base):
360
# top of the file system
364
if ((found_bzrdir.root_transport.base ==
365
self.root_transport.base) or repository.is_shared()):
368
raise errors.NoRepositoryPresent(self)
369
raise errors.NoRepositoryPresent(self)
371
def get_branch_transport(self, branch_format):
372
"""Get the transport for use by branch format in this BzrDir.
374
Note that bzr dirs that do not support format strings will raise
375
IncompatibleFormat if the branch format they are given has
376
a format string, and vice verca.
378
If branch_format is None, the transport is returned with no
379
checking. if it is not None, then the returned transport is
380
guaranteed to point to an existing directory ready for use.
382
raise NotImplementedError(self.get_branch_transport)
384
def get_repository_transport(self, repository_format):
385
"""Get the transport for use by repository format in this BzrDir.
387
Note that bzr dirs that do not support format strings will raise
388
IncompatibleFormat if the repository format they are given has
389
a format string, and vice verca.
391
If repository_format is None, the transport is returned with no
392
checking. if it is not None, then the returned transport is
393
guaranteed to point to an existing directory ready for use.
395
raise NotImplementedError(self.get_repository_transport)
397
def get_workingtree_transport(self, tree_format):
398
"""Get the transport for use by workingtree format in this BzrDir.
400
Note that bzr dirs that do not support format strings will raise
401
IncompatibleFormat if the workingtree format they are given has
402
a format string, and vice verca.
404
If workingtree_format is None, the transport is returned with no
405
checking. if it is not None, then the returned transport is
406
guaranteed to point to an existing directory ready for use.
408
raise NotImplementedError(self.get_workingtree_transport)
711
if found_bzrdir.user_url == self.user_url:
712
return repository, True
713
elif repository.is_shared():
714
return repository, True
718
found_repo = self._find_containing(usable_repository)
719
if found_repo is None:
720
raise errors.NoRepositoryPresent(self)
723
def _find_creation_modes(self):
724
"""Determine the appropriate modes for files and directories.
726
They're always set to be consistent with the base directory,
727
assuming that this transport allows setting modes.
729
# TODO: Do we need or want an option (maybe a config setting) to turn
730
# this off or override it for particular locations? -- mbp 20080512
731
if self._mode_check_done:
733
self._mode_check_done = True
735
st = self.transport.stat('.')
736
except errors.TransportNotPossible:
737
self._dir_mode = None
738
self._file_mode = None
740
# Check the directory mode, but also make sure the created
741
# directories and files are read-write for this user. This is
742
# mostly a workaround for filesystems which lie about being able to
743
# write to a directory (cygwin & win32)
744
if (st.st_mode & 07777 == 00000):
745
# FTP allows stat but does not return dir/file modes
746
self._dir_mode = None
747
self._file_mode = None
749
self._dir_mode = (st.st_mode & 07777) | 00700
750
# Remove the sticky and execute bits for files
751
self._file_mode = self._dir_mode & ~07111
753
def _get_file_mode(self):
754
"""Return Unix mode for newly created files, or None.
756
if not self._mode_check_done:
757
self._find_creation_modes()
758
return self._file_mode
760
def _get_dir_mode(self):
761
"""Return Unix mode for newly created directories, or None.
763
if not self._mode_check_done:
764
self._find_creation_modes()
765
return self._dir_mode
767
def get_config(self):
768
"""Get configuration for this BzrDir."""
769
return config.BzrDirConfig(self)
771
def _get_config(self):
772
"""By default, no configuration is available."""
410
775
def __init__(self, _transport, _format):
411
776
"""Initialize a Bzr control dir object.
413
778
Only really common logic should reside here, concrete classes should be
414
779
made with varying behaviours.
417
782
:param _transport: the transport this dir is based at.
419
784
self._format = _format
785
# these are also under the more standard names of
786
# control_transport and user_transport
420
787
self.transport = _transport.clone('.bzr')
421
788
self.root_transport = _transport
789
self._mode_check_done = False
792
def user_transport(self):
793
return self.root_transport
796
def control_transport(self):
797
return self.transport
423
799
def is_control_filename(self, filename):
424
800
"""True if filename is the name of a path which is reserved for bzrdir's.
426
802
:param filename: A filename within the root transport of this bzrdir.
428
804
This is true IF and ONLY IF the filename is part of the namespace reserved
429
805
for bzr control dirs. Currently this is the '.bzr' directory in the root
430
of the root_transport. it is expected that plugins will need to extend
431
this in the future - for instance to make bzr talk with svn working
806
of the root_transport.
434
# this might be better on the BzrDirFormat class because it refers to
435
# all the possible bzrdir disk formats.
436
# This method is tested via the workingtree is_control_filename tests-
437
# it was extractd from WorkingTree.is_control_filename. If the methods
438
# contract is extended beyond the current trivial implementation please
808
# this might be better on the BzrDirFormat class because it refers to
809
# all the possible bzrdir disk formats.
810
# This method is tested via the workingtree is_control_filename tests-
811
# it was extracted from WorkingTree.is_control_filename. If the method's
812
# contract is extended beyond the current trivial implementation, please
439
813
# add new tests for it to the appropriate place.
440
814
return filename == '.bzr' or filename.startswith('.bzr/')
442
def needs_format_conversion(self, format=None):
443
"""Return true if this bzrdir needs convert_format run on it.
445
For instance, if the repository format is out of date but the
446
branch and working tree are not, this should return True.
448
:param format: Optional parameter indicating a specific desired
449
format we plan to arrive at.
451
raise NotImplementedError(self.needs_format_conversion)
454
817
def open_unsupported(base):
455
818
"""Open a branch which is not supported."""
456
819
return BzrDir.open(base, _unsupported=True)
459
def open(base, _unsupported=False):
460
"""Open an existing bzrdir, rooted at 'base' (url)
462
_unsupported is a private parameter to the BzrDir class.
464
t = get_transport(base)
465
mutter("trying to open %r with transport %r", base, t)
466
format = BzrDirFormat.find_format(t)
467
BzrDir._check_supported(format, _unsupported)
468
return format.open(t, _found=True)
470
def open_branch(self, unsupported=False):
471
"""Open the branch object at this BzrDir if one is present.
473
If unsupported is True, then no longer supported branch formats can
476
TODO: static convenience version of this?
478
raise NotImplementedError(self.open_branch)
481
def open_containing(url):
822
def open(base, _unsupported=False, possible_transports=None):
823
"""Open an existing bzrdir, rooted at 'base' (url).
825
:param _unsupported: a private parameter to the BzrDir class.
827
t = _mod_transport.get_transport(base, possible_transports)
828
return BzrDir.open_from_transport(t, _unsupported=_unsupported)
831
def open_from_transport(transport, _unsupported=False,
832
_server_formats=True):
833
"""Open a bzrdir within a particular directory.
835
:param transport: Transport containing the bzrdir.
836
:param _unsupported: private.
838
for hook in BzrDir.hooks['pre_open']:
840
# Keep initial base since 'transport' may be modified while following
842
base = transport.base
843
def find_format(transport):
844
return transport, controldir.ControlDirFormat.find_format(
845
transport, _server_formats=_server_formats)
847
def redirected(transport, e, redirection_notice):
848
redirected_transport = transport._redirected_to(e.source, e.target)
849
if redirected_transport is None:
850
raise errors.NotBranchError(base)
851
note(gettext('{0} is{1} redirected to {2}').format(
852
transport.base, e.permanently, redirected_transport.base))
853
return redirected_transport
856
transport, format = do_catching_redirections(find_format,
859
except errors.TooManyRedirections:
860
raise errors.NotBranchError(base)
862
format.check_support_status(_unsupported)
863
return format.open(transport, _found=True)
866
def open_containing(url, possible_transports=None):
482
867
"""Open an existing branch which contains url.
484
869
:param url: url to search from.
485
871
See open_containing_from_transport for more detail.
487
return BzrDir.open_containing_from_transport(get_transport(url))
873
transport = _mod_transport.get_transport(url, possible_transports)
874
return BzrDir.open_containing_from_transport(transport)
490
877
def open_containing_from_transport(a_transport):
491
"""Open an existing branch which contains a_transport.base
878
"""Open an existing branch which contains a_transport.base.
493
880
This probes for a branch at a_transport, and searches upwards from there.
495
882
Basically we keep looking up until we find the control directory or
496
883
run into the root. If there isn't one, raises NotBranchError.
497
If there is one and it is either an unrecognised format or an unsupported
884
If there is one and it is either an unrecognised format or an unsupported
498
885
format, UnknownFormatError or UnsupportedFormatError are raised.
499
886
If there is one, it is returned, along with the unused portion of url.
501
:return: The BzrDir that contains the path, and a Unicode path
888
:return: The BzrDir that contains the path, and a Unicode path
502
889
for the rest of the URL.
504
891
# this gets the normalised url back. I.e. '.' -> the full path.
505
892
url = a_transport.base
508
format = BzrDirFormat.find_format(a_transport)
509
BzrDir._check_supported(format, False)
510
return format.open(a_transport), urlutils.unescape(a_transport.relpath(url))
895
result = BzrDir.open_from_transport(a_transport)
896
return result, urlutils.unescape(a_transport.relpath(url))
511
897
except errors.NotBranchError, e:
512
## mutter('not a branch in: %r %s', a_transport.base, e)
514
new_t = a_transport.clone('..')
900
new_t = a_transport.clone('..')
901
except errors.InvalidURLJoin:
902
# reached the root, whatever that may be
903
raise errors.NotBranchError(path=url)
515
904
if new_t.base == a_transport.base:
516
905
# reached the root, whatever that may be
517
906
raise errors.NotBranchError(path=url)
518
907
a_transport = new_t
520
def open_repository(self, _unsupported=False):
521
"""Open the repository object at this BzrDir if one is present.
523
This will not follow the Branch object pointer - its strictly a direct
524
open facility. Most client code should use open_branch().repository to
527
_unsupported is a private parameter, not part of the api.
528
TODO: static convenience version of this?
530
raise NotImplementedError(self.open_repository)
532
def open_workingtree(self, _unsupported=False):
533
"""Open the workingtree object at this BzrDir if one is present.
535
TODO: static convenience version of this?
537
raise NotImplementedError(self.open_workingtree)
539
def has_branch(self):
540
"""Tell if this bzrdir contains a branch.
542
Note: if you're going to open the branch, you should just go ahead
543
and try, and not ask permission first. (This method just opens the
544
branch and discards it, and that's somewhat expensive.)
549
except errors.NotBranchError:
552
def has_workingtree(self):
553
"""Tell if this bzrdir contains a working tree.
555
This will still raise an exception if the bzrdir has a workingtree that
556
is remote & inaccessible.
558
Note: if you're going to open the working tree, you should just go ahead
559
and try, and not ask permission first. (This method just opens the
560
workingtree and discards it, and that's somewhat expensive.)
563
self.open_workingtree()
565
except errors.NoWorkingTree:
568
def sprout(self, url, revision_id=None, basis=None, force_new_repo=False):
569
"""Create a copy of this bzrdir prepared for use as a new line of
572
If urls last component does not exist, it will be created.
574
Attributes related to the identity of the source branch like
575
branch nickname will be cleaned, a working tree is created
576
whether one existed before or not; and a local branch is always
579
if revision_id is not None, then the clone operation may tune
580
itself to download less data.
583
result = self._format.initialize(url)
584
basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
586
source_branch = self.open_branch()
587
source_repository = source_branch.repository
588
except errors.NotBranchError:
910
def open_tree_or_branch(klass, location):
911
"""Return the branch and working tree at a location.
913
If there is no tree at the location, tree will be None.
914
If there is no branch at the location, an exception will be
916
:return: (tree, branch)
918
bzrdir = klass.open(location)
919
return bzrdir._get_tree_branch()
922
def open_containing_tree_or_branch(klass, location):
923
"""Return the branch and working tree contained by a location.
925
Returns (tree, branch, relpath).
926
If there is no tree at containing the location, tree will be None.
927
If there is no branch containing the location, an exception will be
929
relpath is the portion of the path that is contained by the branch.
931
bzrdir, relpath = klass.open_containing(location)
932
tree, branch = bzrdir._get_tree_branch()
933
return tree, branch, relpath
936
def open_containing_tree_branch_or_repository(klass, location):
937
"""Return the working tree, branch and repo contained by a location.
939
Returns (tree, branch, repository, relpath).
940
If there is no tree containing the location, tree will be None.
941
If there is no branch containing the location, branch will be None.
942
If there is no repository containing the location, repository will be
944
relpath is the portion of the path that is contained by the innermost
947
If no tree, branch or repository is found, a NotBranchError is raised.
949
bzrdir, relpath = klass.open_containing(location)
951
tree, branch = bzrdir._get_tree_branch()
952
except errors.NotBranchError:
954
repo = bzrdir.find_repository()
955
return None, None, repo, relpath
956
except (errors.NoRepositoryPresent):
957
raise errors.NotBranchError(location)
958
return tree, branch, branch.repository, relpath
960
def _cloning_metadir(self):
961
"""Produce a metadir suitable for cloning with.
963
:returns: (destination_bzrdir_format, source_repository)
965
result_format = self._format.__class__()
968
branch = self.open_branch(ignore_fallbacks=True)
969
source_repository = branch.repository
970
result_format._branch_format = branch._format
971
except errors.NotBranchError:
591
973
source_repository = self.open_repository()
592
except errors.NoRepositoryPresent:
593
# copy the entire basis one if there is one
594
# but there is no repository.
595
source_repository = basis_repo
600
result_repo = result.find_repository()
601
except errors.NoRepositoryPresent:
603
if source_repository is None and result_repo is not None:
605
elif source_repository is None and result_repo is None:
606
# no repo available, make a new one
607
result.create_repository()
608
elif source_repository is not None and result_repo is None:
609
# have source, and want to make a new target repo
610
# we dont clone the repo because that preserves attributes
611
# like is_shared(), and we have not yet implemented a
612
# repository sprout().
613
result_repo = result.create_repository()
614
if result_repo is not None:
615
# fetch needed content into target.
617
# XXX FIXME RBC 20060214 need tests for this when the basis
619
result_repo.fetch(basis_repo, revision_id=revision_id)
620
result_repo.fetch(source_repository, revision_id=revision_id)
621
if source_branch is not None:
622
source_branch.sprout(result, revision_id=revision_id)
624
result.create_branch()
625
# TODO: jam 20060426 we probably need a test in here in the
626
# case that the newly sprouted branch is a remote one
627
if result_repo is None or result_repo.make_working_trees():
628
result.create_workingtree()
632
class BzrDirPreSplitOut(BzrDir):
633
"""A common class for the all-in-one formats."""
635
def __init__(self, _transport, _format):
636
"""See BzrDir.__init__."""
637
super(BzrDirPreSplitOut, self).__init__(_transport, _format)
638
assert self._format._lock_class == TransportLock
639
assert self._format._lock_file_name == 'branch-lock'
640
self._control_files = LockableFiles(self.get_branch_transport(None),
641
self._format._lock_file_name,
642
self._format._lock_class)
644
def break_lock(self):
645
"""Pre-splitout bzrdirs do not suffer from stale locks."""
646
raise NotImplementedError(self.break_lock)
648
def clone(self, url, revision_id=None, basis=None, force_new_repo=False):
649
"""See BzrDir.clone()."""
650
from bzrlib.workingtree import WorkingTreeFormat2
652
result = self._format._initialize_for_clone(url)
653
basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
654
self.open_repository().clone(result, revision_id=revision_id, basis=basis_repo)
655
from_branch = self.open_branch()
656
from_branch.clone(result, revision_id=revision_id)
658
self.open_workingtree().clone(result, basis=basis_tree)
659
except errors.NotLocalUrl:
660
# make a new one, this format always has to have one.
662
WorkingTreeFormat2().initialize(result)
663
except errors.NotLocalUrl:
664
# but we cannot do it for remote trees.
665
to_branch = result.open_branch()
666
WorkingTreeFormat2().stub_initialize_remote(to_branch.control_files)
669
def create_branch(self):
670
"""See BzrDir.create_branch."""
671
return self.open_branch()
673
def create_repository(self, shared=False):
674
"""See BzrDir.create_repository."""
676
raise errors.IncompatibleFormat('shared repository', self._format)
677
return self.open_repository()
679
def create_workingtree(self, revision_id=None):
680
"""See BzrDir.create_workingtree."""
681
# this looks buggy but is not -really-
682
# clone and sprout will have set the revision_id
683
# and that will have set it for us, its only
684
# specific uses of create_workingtree in isolation
685
# that can do wonky stuff here, and that only
686
# happens for creating checkouts, which cannot be
687
# done on this format anyway. So - acceptable wart.
688
result = self.open_workingtree()
689
if revision_id is not None:
690
result.set_last_revision(revision_id)
693
def get_branch_transport(self, branch_format):
694
"""See BzrDir.get_branch_transport()."""
695
if branch_format is None:
696
return self.transport
698
branch_format.get_format_string()
699
except NotImplementedError:
700
return self.transport
701
raise errors.IncompatibleFormat(branch_format, self._format)
974
except errors.NoRepositoryPresent:
975
source_repository = None
977
# XXX TODO: This isinstance is here because we have not implemented
978
# the fix recommended in bug # 103195 - to delegate this choice the
980
repo_format = source_repository._format
981
if isinstance(repo_format, remote.RemoteRepositoryFormat):
982
source_repository._ensure_real()
983
repo_format = source_repository._real_repository._format
984
result_format.repository_format = repo_format
986
# TODO: Couldn't we just probe for the format in these cases,
987
# rather than opening the whole tree? It would be a little
988
# faster. mbp 20070401
989
tree = self.open_workingtree(recommend_upgrade=False)
990
except (errors.NoWorkingTree, errors.NotLocalUrl):
991
result_format.workingtree_format = None
993
result_format.workingtree_format = tree._format.__class__()
994
return result_format, source_repository
996
def cloning_metadir(self, require_stacking=False):
997
"""Produce a metadir suitable for cloning or sprouting with.
999
These operations may produce workingtrees (yes, even though they're
1000
"cloning" something that doesn't have a tree), so a viable workingtree
1001
format must be selected.
1003
:require_stacking: If True, non-stackable formats will be upgraded
1004
to similar stackable formats.
1005
:returns: a BzrDirFormat with all component formats either set
1006
appropriately or set to None if that component should not be
1009
format, repository = self._cloning_metadir()
1010
if format._workingtree_format is None:
1012
if repository is None:
1013
# No repository either
1015
# We have a repository, so set a working tree? (Why? This seems to
1016
# contradict the stated return value in the docstring).
1017
tree_format = repository._format._matchingbzrdir.workingtree_format
1018
format.workingtree_format = tree_format.__class__()
1019
if require_stacking:
1020
format.require_stacking()
1024
def create(cls, base, format=None, possible_transports=None):
1025
"""Create a new BzrDir at the url 'base'.
1027
:param format: If supplied, the format of branch to create. If not
1028
supplied, the default is used.
1029
:param possible_transports: If supplied, a list of transports that
1030
can be reused to share a remote connection.
1032
if cls is not BzrDir:
1033
raise AssertionError("BzrDir.create always creates the"
1034
"default format, not one of %r" % cls)
1035
t = _mod_transport.get_transport(base, possible_transports)
1038
format = controldir.ControlDirFormat.get_default_format()
1039
return format.initialize_on_transport(t)
1041
def get_branch_transport(self, branch_format, name=None):
1042
"""Get the transport for use by branch format in this BzrDir.
1044
Note that bzr dirs that do not support format strings will raise
1045
IncompatibleFormat if the branch format they are given has
1046
a format string, and vice versa.
1048
If branch_format is None, the transport is returned with no
1049
checking. If it is not None, then the returned transport is
1050
guaranteed to point to an existing directory ready for use.
1052
raise NotImplementedError(self.get_branch_transport)
703
1054
def get_repository_transport(self, repository_format):
704
"""See BzrDir.get_repository_transport()."""
705
if repository_format is None:
706
return self.transport
708
repository_format.get_format_string()
709
except NotImplementedError:
710
return self.transport
711
raise errors.IncompatibleFormat(repository_format, self._format)
713
def get_workingtree_transport(self, workingtree_format):
714
"""See BzrDir.get_workingtree_transport()."""
715
if workingtree_format is None:
716
return self.transport
718
workingtree_format.get_format_string()
719
except NotImplementedError:
720
return self.transport
721
raise errors.IncompatibleFormat(workingtree_format, self._format)
723
def needs_format_conversion(self, format=None):
724
"""See BzrDir.needs_format_conversion()."""
725
# if the format is not the same as the system default,
726
# an upgrade is needed.
728
format = BzrDirFormat.get_default_format()
729
return not isinstance(self._format, format.__class__)
731
def open_branch(self, unsupported=False):
732
"""See BzrDir.open_branch."""
733
from bzrlib.branch import BzrBranchFormat4
734
format = BzrBranchFormat4()
735
self._check_supported(format, unsupported)
736
return format.open(self, _found=True)
738
def sprout(self, url, revision_id=None, basis=None):
739
"""See BzrDir.sprout()."""
740
from bzrlib.workingtree import WorkingTreeFormat2
742
result = self._format._initialize_for_clone(url)
743
basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
745
self.open_repository().clone(result, revision_id=revision_id, basis=basis_repo)
746
except errors.NoRepositoryPresent:
749
self.open_branch().sprout(result, revision_id=revision_id)
750
except errors.NotBranchError:
752
# we always want a working tree
753
WorkingTreeFormat2().initialize(result)
757
class BzrDir4(BzrDirPreSplitOut):
758
"""A .bzr version 4 control object.
760
This is a deprecated format and may be removed after sept 2006.
763
def create_repository(self, shared=False):
764
"""See BzrDir.create_repository."""
765
return self._format.repository_format.initialize(self, shared)
767
def needs_format_conversion(self, format=None):
768
"""Format 4 dirs are always in need of conversion."""
771
def open_repository(self):
772
"""See BzrDir.open_repository."""
773
from bzrlib.repository import RepositoryFormat4
774
return RepositoryFormat4().open(self, _found=True)
777
class BzrDir5(BzrDirPreSplitOut):
778
"""A .bzr version 5 control object.
780
This is a deprecated format and may be removed after sept 2006.
783
def open_repository(self):
784
"""See BzrDir.open_repository."""
785
from bzrlib.repository import RepositoryFormat5
786
return RepositoryFormat5().open(self, _found=True)
788
def open_workingtree(self, _unsupported=False):
789
"""See BzrDir.create_workingtree."""
790
from bzrlib.workingtree import WorkingTreeFormat2
791
return WorkingTreeFormat2().open(self, _found=True)
794
class BzrDir6(BzrDirPreSplitOut):
795
"""A .bzr version 6 control object.
797
This is a deprecated format and may be removed after sept 2006.
800
def open_repository(self):
801
"""See BzrDir.open_repository."""
802
from bzrlib.repository import RepositoryFormat6
803
return RepositoryFormat6().open(self, _found=True)
805
def open_workingtree(self, _unsupported=False):
806
"""See BzrDir.create_workingtree."""
807
from bzrlib.workingtree import WorkingTreeFormat2
808
return WorkingTreeFormat2().open(self, _found=True)
1055
"""Get the transport for use by repository format in this BzrDir.
1057
Note that bzr dirs that do not support format strings will raise
1058
IncompatibleFormat if the repository format they are given has
1059
a format string, and vice versa.
1061
If repository_format is None, the transport is returned with no
1062
checking. If it is not None, then the returned transport is
1063
guaranteed to point to an existing directory ready for use.
1065
raise NotImplementedError(self.get_repository_transport)
1067
def get_workingtree_transport(self, tree_format):
1068
"""Get the transport for use by workingtree format in this BzrDir.
1070
Note that bzr dirs that do not support format strings will raise
1071
IncompatibleFormat if the workingtree format they are given has a
1072
format string, and vice versa.
1074
If workingtree_format is None, the transport is returned with no
1075
checking. If it is not None, then the returned transport is
1076
guaranteed to point to an existing directory ready for use.
1078
raise NotImplementedError(self.get_workingtree_transport)
1081
class BzrDirHooks(hooks.Hooks):
1082
"""Hooks for BzrDir operations."""
1085
"""Create the default hooks."""
1086
hooks.Hooks.__init__(self, "bzrlib.bzrdir", "BzrDir.hooks")
1087
self.add_hook('pre_open',
1088
"Invoked before attempting to open a BzrDir with the transport "
1089
"that the open will use.", (1, 14))
1090
self.add_hook('post_repo_init',
1091
"Invoked after a repository has been initialized. "
1092
"post_repo_init is called with a "
1093
"bzrlib.bzrdir.RepoInitHookParams.",
1096
# install the default hooks
1097
BzrDir.hooks = BzrDirHooks()
1100
class RepoInitHookParams(object):
1101
"""Object holding parameters passed to `*_repo_init` hooks.
1103
There are 4 fields that hooks may wish to access:
1105
:ivar repository: Repository created
1106
:ivar format: Repository format
1107
:ivar bzrdir: The bzrdir for the repository
1108
:ivar shared: The repository is shared
1111
def __init__(self, repository, format, a_bzrdir, shared):
1112
"""Create a group of RepoInitHook parameters.
1114
:param repository: Repository created
1115
:param format: Repository format
1116
:param bzrdir: The bzrdir for the repository
1117
:param shared: The repository is shared
1119
self.repository = repository
1120
self.format = format
1121
self.bzrdir = a_bzrdir
1122
self.shared = shared
1124
def __eq__(self, other):
1125
return self.__dict__ == other.__dict__
1129
return "<%s for %s>" % (self.__class__.__name__,
1132
return "<%s for %s>" % (self.__class__.__name__,
811
1136
class BzrDirMeta1(BzrDir):
812
1137
"""A .bzr meta version 1 control object.
814
This is the first control object where the
1139
This is the first control object where the
815
1140
individual aspects are really split out: there are separate repository,
816
1141
workingtree and branch subdirectories and any subset of the three can be
817
1142
present within a BzrDir.
898
1281
except errors.NoRepositoryPresent:
900
# currently there are no other possible conversions for meta1 formats.
1283
for branch in self.list_branches():
1284
if not isinstance(branch._format,
1285
format.get_branch_format().__class__):
1286
# the branch needs an upgrade.
1289
my_wt = self.open_workingtree(recommend_upgrade=False)
1290
if not isinstance(my_wt._format,
1291
format.workingtree_format.__class__):
1292
# the workingtree needs an upgrade.
1294
except (errors.NoWorkingTree, errors.NotLocalUrl):
903
def open_branch(self, unsupported=False):
1298
def open_branch(self, name=None, unsupported=False,
1299
ignore_fallbacks=False):
904
1300
"""See BzrDir.open_branch."""
905
from bzrlib.branch import BranchFormat
906
format = BranchFormat.find_format(self)
907
self._check_supported(format, unsupported)
908
return format.open(self, _found=True)
1301
format = self.find_branch_format(name=name)
1302
format.check_support_status(unsupported)
1303
return format.open(self, name=name,
1304
_found=True, ignore_fallbacks=ignore_fallbacks)
910
1306
def open_repository(self, unsupported=False):
911
1307
"""See BzrDir.open_repository."""
912
1308
from bzrlib.repository import RepositoryFormat
913
1309
format = RepositoryFormat.find_format(self)
914
self._check_supported(format, unsupported)
1310
format.check_support_status(unsupported)
915
1311
return format.open(self, _found=True)
917
def open_workingtree(self, unsupported=False):
1313
def open_workingtree(self, unsupported=False,
1314
recommend_upgrade=True):
918
1315
"""See BzrDir.open_workingtree."""
919
1316
from bzrlib.workingtree import WorkingTreeFormat
920
1317
format = WorkingTreeFormat.find_format(self)
921
self._check_supported(format, unsupported)
1318
format.check_support_status(unsupported, recommend_upgrade,
1319
basedir=self.root_transport.base)
922
1320
return format.open(self, _found=True)
925
class BzrDirFormat(object):
926
"""An encapsulation of the initialization and open routines for a format.
928
Formats provide three things:
929
* An initialization routine,
933
Formats are placed in an dict by their format string for reference
1322
def _get_config(self):
1323
return config.TransportConfig(self.transport, 'control.conf')
1326
class BzrProber(controldir.Prober):
1327
"""Prober for formats that use a .bzr/ control directory."""
1329
formats = registry.FormatRegistry(controldir.network_format_registry)
1330
"""The known .bzr formats."""
1333
@deprecated_method(deprecated_in((2, 4, 0)))
1334
def register_bzrdir_format(klass, format):
1335
klass.formats.register(format.get_format_string(), format)
1338
@deprecated_method(deprecated_in((2, 4, 0)))
1339
def unregister_bzrdir_format(klass, format):
1340
klass.formats.remove(format.get_format_string())
1343
def probe_transport(klass, transport):
1344
"""Return the .bzrdir style format present in a directory."""
1346
format_string = transport.get_bytes(".bzr/branch-format")
1347
except errors.NoSuchFile:
1348
raise errors.NotBranchError(path=transport.base)
1350
return klass.formats.get(format_string)
1352
raise errors.UnknownFormatError(format=format_string, kind='bzrdir')
1355
def known_formats(cls):
1357
for name, format in cls.formats.iteritems():
1358
if callable(format):
1364
controldir.ControlDirFormat.register_prober(BzrProber)
1367
class RemoteBzrProber(controldir.Prober):
1368
"""Prober for remote servers that provide a Bazaar smart server."""
1371
def probe_transport(klass, transport):
1372
"""Return a RemoteBzrDirFormat object if it looks possible."""
1374
medium = transport.get_smart_medium()
1375
except (NotImplementedError, AttributeError,
1376
errors.TransportNotPossible, errors.NoSmartMedium,
1377
errors.SmartProtocolError):
1378
# no smart server, so not a branch for this format type.
1379
raise errors.NotBranchError(path=transport.base)
1381
# Decline to open it if the server doesn't support our required
1382
# version (3) so that the VFS-based transport will do it.
1383
if medium.should_probe():
1385
server_version = medium.protocol_version()
1386
except errors.SmartProtocolError:
1387
# Apparently there's no usable smart server there, even though
1388
# the medium supports the smart protocol.
1389
raise errors.NotBranchError(path=transport.base)
1390
if server_version != '2':
1391
raise errors.NotBranchError(path=transport.base)
1392
from bzrlib.remote import RemoteBzrDirFormat
1393
return RemoteBzrDirFormat()
1396
def known_formats(cls):
1397
from bzrlib.remote import RemoteBzrDirFormat
1398
return set([RemoteBzrDirFormat()])
1401
class BzrDirFormat(controldir.ControlDirFormat):
1402
"""ControlDirFormat base class for .bzr/ directories.
1404
Formats are placed in a dict by their format string for reference
934
1405
during bzrdir opening. These should be subclasses of BzrDirFormat
935
1406
for consistency.
937
1408
Once a format is deprecated, just deprecate the initialize and open
938
methods on the format class. Do not deprecate the object, as the
1409
methods on the format class. Do not deprecate the object, as the
939
1410
object will be created every system load.
942
_default_format = None
943
"""The default format used for new .bzr dirs."""
946
"""The known formats."""
948
1413
_lock_file_name = 'branch-lock'
950
1415
# _lock_class must be set in subclasses to the lock type, typ.
951
1416
# TransportLock or LockDir
954
def find_format(klass, transport):
955
"""Return the format registered for URL."""
957
format_string = transport.get(".bzr/branch-format").read()
958
return klass._formats[format_string]
959
except errors.NoSuchFile:
960
raise errors.NotBranchError(path=transport.base)
962
raise errors.UnknownFormatError(format_string)
965
def get_default_format(klass):
966
"""Return the current default format."""
967
return klass._default_format
969
def get_format_string(self):
1419
def get_format_string(cls):
970
1420
"""Return the ASCII format string that identifies this format."""
971
raise NotImplementedError(self.get_format_string)
973
def get_format_description(self):
974
"""Return the short description for this format."""
975
raise NotImplementedError(self.get_format_description)
977
def get_converter(self, format=None):
978
"""Return the converter to use to convert bzrdirs needing converts.
980
This returns a bzrlib.bzrdir.Converter object.
982
This should return the best upgrader to step this format towards the
983
current default format. In the case of plugins we can/shouold provide
984
some means for them to extend the range of returnable converters.
986
:param format: Optional format to override the default foramt of the
989
raise NotImplementedError(self.get_converter)
991
def initialize(self, url):
992
"""Create a bzr control dir at this url and return an opened copy.
994
Subclasses should typically override initialize_on_transport
995
instead of this method.
997
return self.initialize_on_transport(get_transport(url))
1421
raise NotImplementedError(cls.get_format_string)
999
1423
def initialize_on_transport(self, transport):
1000
1424
"""Initialize a new bzrdir in the base directory of a Transport."""
1001
# Since we don'transport have a .bzr directory, inherit the
1426
# can we hand off the request to the smart server rather than using
1428
client_medium = transport.get_smart_medium()
1429
except errors.NoSmartMedium:
1430
return self._initialize_on_transport_vfs(transport)
1432
# Current RPC's only know how to create bzr metadir1 instances, so
1433
# we still delegate to vfs methods if the requested format is not a
1435
if type(self) != BzrDirMetaFormat1:
1436
return self._initialize_on_transport_vfs(transport)
1437
from bzrlib.remote import RemoteBzrDirFormat
1438
remote_format = RemoteBzrDirFormat()
1439
self._supply_sub_formats_to(remote_format)
1440
return remote_format.initialize_on_transport(transport)
1442
def initialize_on_transport_ex(self, transport, use_existing_dir=False,
1443
create_prefix=False, force_new_repo=False, stacked_on=None,
1444
stack_on_pwd=None, repo_format_name=None, make_working_trees=None,
1445
shared_repo=False, vfs_only=False):
1446
"""Create this format on transport.
1448
The directory to initialize will be created.
1450
:param force_new_repo: Do not use a shared repository for the target,
1451
even if one is available.
1452
:param create_prefix: Create any missing directories leading up to
1454
:param use_existing_dir: Use an existing directory if one exists.
1455
:param stacked_on: A url to stack any created branch on, None to follow
1456
any target stacking policy.
1457
:param stack_on_pwd: If stack_on is relative, the location it is
1459
:param repo_format_name: If non-None, a repository will be
1460
made-or-found. Should none be found, or if force_new_repo is True
1461
the repo_format_name is used to select the format of repository to
1463
:param make_working_trees: Control the setting of make_working_trees
1464
for a new shared repository when one is made. None to use whatever
1465
default the format has.
1466
:param shared_repo: Control whether made repositories are shared or
1468
:param vfs_only: If True do not attempt to use a smart server
1469
:return: repo, bzrdir, require_stacking, repository_policy. repo is
1470
None if none was created or found, bzrdir is always valid.
1471
require_stacking is the result of examining the stacked_on
1472
parameter and any stacking policy found for the target.
1475
# Try to hand off to a smart server
1477
client_medium = transport.get_smart_medium()
1478
except errors.NoSmartMedium:
1481
from bzrlib.remote import RemoteBzrDirFormat
1482
# TODO: lookup the local format from a server hint.
1483
remote_dir_format = RemoteBzrDirFormat()
1484
remote_dir_format._network_name = self.network_name()
1485
self._supply_sub_formats_to(remote_dir_format)
1486
return remote_dir_format.initialize_on_transport_ex(transport,
1487
use_existing_dir=use_existing_dir, create_prefix=create_prefix,
1488
force_new_repo=force_new_repo, stacked_on=stacked_on,
1489
stack_on_pwd=stack_on_pwd, repo_format_name=repo_format_name,
1490
make_working_trees=make_working_trees, shared_repo=shared_repo)
1491
# XXX: Refactor the create_prefix/no_create_prefix code into a
1492
# common helper function
1493
# The destination may not exist - if so make it according to policy.
1494
def make_directory(transport):
1495
transport.mkdir('.')
1497
def redirected(transport, e, redirection_notice):
1498
note(redirection_notice)
1499
return transport._redirected_to(e.source, e.target)
1501
transport = do_catching_redirections(make_directory, transport,
1503
except errors.FileExists:
1504
if not use_existing_dir:
1506
except errors.NoSuchFile:
1507
if not create_prefix:
1509
transport.create_prefix()
1511
require_stacking = (stacked_on is not None)
1512
# Now the target directory exists, but doesn't have a .bzr
1513
# directory. So we need to create it, along with any work to create
1514
# all of the dependent branches, etc.
1516
result = self.initialize_on_transport(transport)
1517
if repo_format_name:
1519
# use a custom format
1520
result._format.repository_format = \
1521
repository.network_format_registry.get(repo_format_name)
1522
except AttributeError:
1523
# The format didn't permit it to be set.
1525
# A repository is desired, either in-place or shared.
1526
repository_policy = result.determine_repository_policy(
1527
force_new_repo, stacked_on, stack_on_pwd,
1528
require_stacking=require_stacking)
1529
result_repo, is_new_repo = repository_policy.acquire_repository(
1530
make_working_trees, shared_repo)
1531
if not require_stacking and repository_policy._require_stacking:
1532
require_stacking = True
1533
result._format.require_stacking()
1534
result_repo.lock_write()
1537
repository_policy = None
1538
return result_repo, result, require_stacking, repository_policy
1540
def _initialize_on_transport_vfs(self, transport):
1541
"""Initialize a new bzrdir using VFS calls.
1543
:param transport: The transport to create the .bzr directory in.
1546
# Since we are creating a .bzr directory, inherit the
1002
1547
# mode from the root directory
1003
temp_control = LockableFiles(transport, '', TransportLock)
1548
temp_control = lockable_files.LockableFiles(transport,
1549
'', lockable_files.TransportLock)
1004
1550
temp_control._transport.mkdir('.bzr',
1005
# FIXME: RBC 20060121 dont peek under
1551
# FIXME: RBC 20060121 don't peek under
1007
1553
mode=temp_control._dir_mode)
1554
if sys.platform == 'win32' and isinstance(transport, local.LocalTransport):
1555
win32utils.set_file_attr_hidden(transport._abspath('.bzr'))
1008
1556
file_mode = temp_control._file_mode
1009
1557
del temp_control
1010
mutter('created control directory in ' + transport.base)
1011
control = transport.clone('.bzr')
1012
utf8_files = [('README',
1013
"This is a Bazaar-NG control directory.\n"
1014
"Do not change any files in this directory.\n"),
1558
bzrdir_transport = transport.clone('.bzr')
1559
utf8_files = [('README',
1560
"This is a Bazaar control directory.\n"
1561
"Do not change any files in this directory.\n"
1562
"See http://bazaar.canonical.com/ for more information about Bazaar.\n"),
1015
1563
('branch-format', self.get_format_string()),
1017
1565
# NB: no need to escape relative paths that are url safe.
1018
control_files = LockableFiles(control, self._lock_file_name,
1566
control_files = lockable_files.LockableFiles(bzrdir_transport,
1567
self._lock_file_name, self._lock_class)
1020
1568
control_files.create_lock()
1021
1569
control_files.lock_write()
1023
for file, content in utf8_files:
1024
control_files.put_utf8(file, content)
1571
for (filename, content) in utf8_files:
1572
bzrdir_transport.put_bytes(filename, content,
1026
1575
control_files.unlock()
1027
1576
return self.open(transport, _found=True)
1029
def is_supported(self):
1030
"""Is this format supported?
1032
Supported formats must be initializable and openable.
1033
Unsupported formats may not support initialization or committing or
1034
some other features depending on the reason for not being supported.
1038
1578
def open(self, transport, _found=False):
1039
1579
"""Return an instance of this format for the dir transport points at.
1041
1581
_found is a private parameter, do not use it.
1044
assert isinstance(BzrDirFormat.find_format(transport),
1584
found_format = controldir.ControlDirFormat.find_format(transport)
1585
if not isinstance(found_format, self.__class__):
1586
raise AssertionError("%s was asked to open %s, but it seems to need "
1588
% (self, transport, found_format))
1589
# Allow subclasses - use the found format.
1590
self._supply_sub_formats_to(found_format)
1591
return found_format._open(transport)
1046
1592
return self._open(transport)
1048
1594
def _open(self, transport):
1054
1600
raise NotImplementedError(self._open)
1057
def register_format(klass, format):
1058
klass._formats[format.get_format_string()] = format
1061
def set_default_format(klass, format):
1062
klass._default_format = format
1065
return self.get_format_string()[:-1]
1068
def unregister_format(klass, format):
1069
assert klass._formats[format.get_format_string()] is format
1070
del klass._formats[format.get_format_string()]
1073
class BzrDirFormat4(BzrDirFormat):
1074
"""Bzr dir format 4.
1076
This format is a combined format for working tree, branch and repository.
1078
- Format 1 working trees [always]
1079
- Format 4 branches [always]
1080
- Format 4 repositories [always]
1082
This format is deprecated: it indexes texts using a text it which is
1083
removed in format 5; write support for this format has been removed.
1086
_lock_class = TransportLock
1088
def get_format_string(self):
1089
"""See BzrDirFormat.get_format_string()."""
1090
return "Bazaar-NG branch, format 0.0.4\n"
1092
def get_format_description(self):
1093
"""See BzrDirFormat.get_format_description()."""
1094
return "All-in-one format 4"
1096
def get_converter(self, format=None):
1097
"""See BzrDirFormat.get_converter()."""
1098
# there is one and only one upgrade path here.
1099
return ConvertBzrDir4To5()
1101
def initialize_on_transport(self, transport):
1102
"""Format 4 branches cannot be created."""
1103
raise errors.UninitializableFormat(self)
1105
def is_supported(self):
1106
"""Format 4 is not supported.
1108
It is not supported because the model changed from 4 to 5 and the
1109
conversion logic is expensive - so doing it on the fly was not
1114
def _open(self, transport):
1115
"""See BzrDirFormat._open."""
1116
return BzrDir4(transport, self)
1118
def __return_repository_format(self):
1119
"""Circular import protection."""
1120
from bzrlib.repository import RepositoryFormat4
1121
return RepositoryFormat4(self)
1122
repository_format = property(__return_repository_format)
1125
class BzrDirFormat5(BzrDirFormat):
1126
"""Bzr control format 5.
1128
This format is a combined format for working tree, branch and repository.
1130
- Format 2 working trees [always]
1131
- Format 4 branches [always]
1132
- Format 5 repositories [always]
1133
Unhashed stores in the repository.
1136
_lock_class = TransportLock
1138
def get_format_string(self):
1139
"""See BzrDirFormat.get_format_string()."""
1140
return "Bazaar-NG branch, format 5\n"
1142
def get_format_description(self):
1143
"""See BzrDirFormat.get_format_description()."""
1144
return "All-in-one format 5"
1146
def get_converter(self, format=None):
1147
"""See BzrDirFormat.get_converter()."""
1148
# there is one and only one upgrade path here.
1149
return ConvertBzrDir5To6()
1151
def _initialize_for_clone(self, url):
1152
return self.initialize_on_transport(get_transport(url), _cloning=True)
1154
def initialize_on_transport(self, transport, _cloning=False):
1155
"""Format 5 dirs always have working tree, branch and repository.
1157
Except when they are being cloned.
1159
from bzrlib.branch import BzrBranchFormat4
1160
from bzrlib.repository import RepositoryFormat5
1161
from bzrlib.workingtree import WorkingTreeFormat2
1162
result = (super(BzrDirFormat5, self).initialize_on_transport(transport))
1163
RepositoryFormat5().initialize(result, _internal=True)
1165
BzrBranchFormat4().initialize(result)
1166
WorkingTreeFormat2().initialize(result)
1169
def _open(self, transport):
1170
"""See BzrDirFormat._open."""
1171
return BzrDir5(transport, self)
1173
def __return_repository_format(self):
1174
"""Circular import protection."""
1175
from bzrlib.repository import RepositoryFormat5
1176
return RepositoryFormat5(self)
1177
repository_format = property(__return_repository_format)
1180
class BzrDirFormat6(BzrDirFormat):
1181
"""Bzr control format 6.
1183
This format is a combined format for working tree, branch and repository.
1185
- Format 2 working trees [always]
1186
- Format 4 branches [always]
1187
- Format 6 repositories [always]
1190
_lock_class = TransportLock
1192
def get_format_string(self):
1193
"""See BzrDirFormat.get_format_string()."""
1194
return "Bazaar-NG branch, format 6\n"
1196
def get_format_description(self):
1197
"""See BzrDirFormat.get_format_description()."""
1198
return "All-in-one format 6"
1200
def get_converter(self, format=None):
1201
"""See BzrDirFormat.get_converter()."""
1202
# there is one and only one upgrade path here.
1203
return ConvertBzrDir6ToMeta()
1205
def _initialize_for_clone(self, url):
1206
return self.initialize_on_transport(get_transport(url), _cloning=True)
1208
def initialize_on_transport(self, transport, _cloning=False):
1209
"""Format 6 dirs always have working tree, branch and repository.
1211
Except when they are being cloned.
1213
from bzrlib.branch import BzrBranchFormat4
1214
from bzrlib.repository import RepositoryFormat6
1215
from bzrlib.workingtree import WorkingTreeFormat2
1216
result = super(BzrDirFormat6, self).initialize_on_transport(transport)
1217
RepositoryFormat6().initialize(result, _internal=True)
1219
BzrBranchFormat4().initialize(result)
1221
WorkingTreeFormat2().initialize(result)
1222
except errors.NotLocalUrl:
1223
# emulate pre-check behaviour for working tree and silently
1228
def _open(self, transport):
1229
"""See BzrDirFormat._open."""
1230
return BzrDir6(transport, self)
1232
def __return_repository_format(self):
1233
"""Circular import protection."""
1234
from bzrlib.repository import RepositoryFormat6
1235
return RepositoryFormat6(self)
1236
repository_format = property(__return_repository_format)
1602
def _supply_sub_formats_to(self, other_format):
1603
"""Give other_format the same values for sub formats as this has.
1605
This method is expected to be used when parameterising a
1606
RemoteBzrDirFormat instance with the parameters from a
1607
BzrDirMetaFormat1 instance.
1609
:param other_format: other_format is a format which should be
1610
compatible with whatever sub formats are supported by self.
1239
1615
class BzrDirMetaFormat1(BzrDirFormat):
1266
1766
"""See BzrDirFormat.get_format_description()."""
1267
1767
return "Meta directory format 1"
1769
def network_name(self):
1770
return self.get_format_string()
1269
1772
def _open(self, transport):
1270
1773
"""See BzrDirFormat._open."""
1271
return BzrDirMeta1(transport, self)
1774
# Create a new format instance because otherwise initialisation of new
1775
# metadirs share the global default format object leading to alias
1777
format = BzrDirMetaFormat1()
1778
self._supply_sub_formats_to(format)
1779
return BzrDirMeta1(transport, format)
1273
1781
def __return_repository_format(self):
1274
1782
"""Circular import protection."""
1275
if getattr(self, '_repository_format', None):
1783
if self._repository_format:
1276
1784
return self._repository_format
1277
from bzrlib.repository import RepositoryFormat
1278
return RepositoryFormat.get_default_format()
1785
from bzrlib.repository import format_registry
1786
return format_registry.get_default()
1280
def __set_repository_format(self, value):
1281
"""Allow changint the repository format for metadir formats."""
1788
def _set_repository_format(self, value):
1789
"""Allow changing the repository format for metadir formats."""
1282
1790
self._repository_format = value
1284
repository_format = property(__return_repository_format, __set_repository_format)
1287
BzrDirFormat.register_format(BzrDirFormat4())
1288
BzrDirFormat.register_format(BzrDirFormat5())
1289
BzrDirFormat.register_format(BzrDirFormat6())
1290
__default_format = BzrDirMetaFormat1()
1291
BzrDirFormat.register_format(__default_format)
1292
BzrDirFormat.set_default_format(__default_format)
1295
class BzrDirTestProviderAdapter(object):
1296
"""A tool to generate a suite testing multiple bzrdir formats at once.
1298
This is done by copying the test once for each transport and injecting
1299
the transport_server, transport_readonly_server, and bzrdir_format
1300
classes into each copy. Each copy is also given a new id() to make it
1304
def __init__(self, transport_server, transport_readonly_server, formats):
1305
self._transport_server = transport_server
1306
self._transport_readonly_server = transport_readonly_server
1307
self._formats = formats
1309
def adapt(self, test):
1310
result = TestSuite()
1311
for format in self._formats:
1312
new_test = deepcopy(test)
1313
new_test.transport_server = self._transport_server
1314
new_test.transport_readonly_server = self._transport_readonly_server
1315
new_test.bzrdir_format = format
1316
def make_new_test_id():
1317
new_id = "%s(%s)" % (new_test.id(), format.__class__.__name__)
1318
return lambda: new_id
1319
new_test.id = make_new_test_id()
1320
result.addTest(new_test)
1324
class ScratchDir(BzrDir6):
1325
"""Special test class: a bzrdir that cleans up itself..
1327
>>> d = ScratchDir()
1328
>>> base = d.transport.base
1331
>>> b.transport.__del__()
1336
def __init__(self, files=[], dirs=[], transport=None):
1337
"""Make a test branch.
1339
This creates a temporary directory and runs init-tree in it.
1341
If any files are listed, they are created in the working copy.
1343
if transport is None:
1344
transport = bzrlib.transport.local.ScratchTransport()
1345
# local import for scope restriction
1346
BzrDirFormat6().initialize(transport.base)
1347
super(ScratchDir, self).__init__(transport, BzrDirFormat6())
1348
self.create_repository()
1349
self.create_branch()
1350
self.create_workingtree()
1352
super(ScratchDir, self).__init__(transport, BzrDirFormat6())
1354
# BzrBranch creates a clone to .bzr and then forgets about the
1355
# original transport. A ScratchTransport() deletes itself and
1356
# everything underneath it when it goes away, so we need to
1357
# grab a local copy to prevent that from happening
1358
self._transport = transport
1361
self._transport.mkdir(d)
1364
self._transport.put(f, 'content of %s' % f)
1368
>>> orig = ScratchDir(files=["file1", "file2"])
1369
>>> os.listdir(orig.base)
1370
[u'.bzr', u'file1', u'file2']
1371
>>> clone = orig.clone()
1372
>>> if os.name != 'nt':
1373
... os.path.samefile(orig.base, clone.base)
1375
... orig.base == clone.base
1378
>>> os.listdir(clone.base)
1379
[u'.bzr', u'file1', u'file2']
1381
from shutil import copytree
1382
from bzrlib.osutils import mkdtemp
1385
copytree(self.base, base, symlinks=True)
1387
transport=bzrlib.transport.local.ScratchTransport(base))
1390
class Converter(object):
1391
"""Converts a disk format object from one format to another."""
1393
def convert(self, to_convert, pb):
1394
"""Perform the conversion of to_convert, giving feedback via pb.
1396
:param to_convert: The disk object to convert.
1397
:param pb: a progress bar to use for progress information.
1400
def step(self, message):
1401
"""Update the pb by a step."""
1403
self.pb.update(message, self.count, self.total)
1406
class ConvertBzrDir4To5(Converter):
1407
"""Converts format 4 bzr dirs to format 5."""
1410
super(ConvertBzrDir4To5, self).__init__()
1411
self.converted_revs = set()
1412
self.absent_revisions = set()
1416
def convert(self, to_convert, pb):
1417
"""See Converter.convert()."""
1418
self.bzrdir = to_convert
1420
self.pb.note('starting upgrade from format 4 to 5')
1421
if isinstance(self.bzrdir.transport, LocalTransport):
1422
self.bzrdir.get_workingtree_transport(None).delete('stat-cache')
1423
self._convert_to_weaves()
1424
return BzrDir.open(self.bzrdir.root_transport.base)
1426
def _convert_to_weaves(self):
1427
self.pb.note('note: upgrade may be faster if all store files are ungzipped first')
1430
stat = self.bzrdir.transport.stat('weaves')
1431
if not S_ISDIR(stat.st_mode):
1432
self.bzrdir.transport.delete('weaves')
1433
self.bzrdir.transport.mkdir('weaves')
1434
except errors.NoSuchFile:
1435
self.bzrdir.transport.mkdir('weaves')
1436
# deliberately not a WeaveFile as we want to build it up slowly.
1437
self.inv_weave = Weave('inventory')
1438
# holds in-memory weaves for all files
1439
self.text_weaves = {}
1440
self.bzrdir.transport.delete('branch-format')
1441
self.branch = self.bzrdir.open_branch()
1442
self._convert_working_inv()
1443
rev_history = self.branch.revision_history()
1444
# to_read is a stack holding the revisions we still need to process;
1445
# appending to it adds new highest-priority revisions
1446
self.known_revisions = set(rev_history)
1447
self.to_read = rev_history[-1:]
1449
rev_id = self.to_read.pop()
1450
if (rev_id not in self.revisions
1451
and rev_id not in self.absent_revisions):
1452
self._load_one_rev(rev_id)
1454
to_import = self._make_order()
1455
for i, rev_id in enumerate(to_import):
1456
self.pb.update('converting revision', i, len(to_import))
1457
self._convert_one_rev(rev_id)
1459
self._write_all_weaves()
1460
self._write_all_revs()
1461
self.pb.note('upgraded to weaves:')
1462
self.pb.note(' %6d revisions and inventories', len(self.revisions))
1463
self.pb.note(' %6d revisions not present', len(self.absent_revisions))
1464
self.pb.note(' %6d texts', self.text_count)
1465
self._cleanup_spare_files_after_format4()
1466
self.branch.control_files.put_utf8('branch-format', BzrDirFormat5().get_format_string())
1468
def _cleanup_spare_files_after_format4(self):
1469
# FIXME working tree upgrade foo.
1470
for n in 'merged-patches', 'pending-merged-patches':
1472
## assert os.path.getsize(p) == 0
1473
self.bzrdir.transport.delete(n)
1474
except errors.NoSuchFile:
1476
self.bzrdir.transport.delete_tree('inventory-store')
1477
self.bzrdir.transport.delete_tree('text-store')
1479
def _convert_working_inv(self):
1480
inv = serializer_v4.read_inventory(self.branch.control_files.get('inventory'))
1481
new_inv_xml = bzrlib.xml5.serializer_v5.write_inventory_to_string(inv)
1482
# FIXME inventory is a working tree change.
1483
self.branch.control_files.put('inventory', new_inv_xml)
1485
def _write_all_weaves(self):
1486
controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)
1487
weave_transport = self.bzrdir.transport.clone('weaves')
1488
weaves = WeaveStore(weave_transport, prefixed=False)
1489
transaction = WriteTransaction()
1493
for file_id, file_weave in self.text_weaves.items():
1494
self.pb.update('writing weave', i, len(self.text_weaves))
1495
weaves._put_weave(file_id, file_weave, transaction)
1497
self.pb.update('inventory', 0, 1)
1498
controlweaves._put_weave('inventory', self.inv_weave, transaction)
1499
self.pb.update('inventory', 1, 1)
1503
def _write_all_revs(self):
1504
"""Write all revisions out in new form."""
1505
self.bzrdir.transport.delete_tree('revision-store')
1506
self.bzrdir.transport.mkdir('revision-store')
1507
revision_transport = self.bzrdir.transport.clone('revision-store')
1509
_revision_store = TextRevisionStore(TextStore(revision_transport,
1513
transaction = bzrlib.transactions.WriteTransaction()
1514
for i, rev_id in enumerate(self.converted_revs):
1515
self.pb.update('write revision', i, len(self.converted_revs))
1516
_revision_store.add_revision(self.revisions[rev_id], transaction)
1520
def _load_one_rev(self, rev_id):
1521
"""Load a revision object into memory.
1523
Any parents not either loaded or abandoned get queued to be
1525
self.pb.update('loading revision',
1526
len(self.revisions),
1527
len(self.known_revisions))
1528
if not self.branch.repository.has_revision(rev_id):
1530
self.pb.note('revision {%s} not present in branch; '
1531
'will be converted as a ghost',
1533
self.absent_revisions.add(rev_id)
1535
rev = self.branch.repository._revision_store.get_revision(rev_id,
1536
self.branch.repository.get_transaction())
1537
for parent_id in rev.parent_ids:
1538
self.known_revisions.add(parent_id)
1539
self.to_read.append(parent_id)
1540
self.revisions[rev_id] = rev
1542
def _load_old_inventory(self, rev_id):
1543
assert rev_id not in self.converted_revs
1544
old_inv_xml = self.branch.repository.inventory_store.get(rev_id).read()
1545
inv = serializer_v4.read_inventory_from_string(old_inv_xml)
1546
rev = self.revisions[rev_id]
1547
if rev.inventory_sha1:
1548
assert rev.inventory_sha1 == sha_string(old_inv_xml), \
1549
'inventory sha mismatch for {%s}' % rev_id
1552
def _load_updated_inventory(self, rev_id):
1553
assert rev_id in self.converted_revs
1554
inv_xml = self.inv_weave.get_text(rev_id)
1555
inv = bzrlib.xml5.serializer_v5.read_inventory_from_string(inv_xml)
1558
def _convert_one_rev(self, rev_id):
1559
"""Convert revision and all referenced objects to new format."""
1560
rev = self.revisions[rev_id]
1561
inv = self._load_old_inventory(rev_id)
1562
present_parents = [p for p in rev.parent_ids
1563
if p not in self.absent_revisions]
1564
self._convert_revision_contents(rev, inv, present_parents)
1565
self._store_new_weave(rev, inv, present_parents)
1566
self.converted_revs.add(rev_id)
1568
def _store_new_weave(self, rev, inv, present_parents):
1569
# the XML is now updated with text versions
1573
if ie.kind == 'root_directory':
1575
assert hasattr(ie, 'revision'), \
1576
'no revision on {%s} in {%s}' % \
1577
(file_id, rev.revision_id)
1578
new_inv_xml = bzrlib.xml5.serializer_v5.write_inventory_to_string(inv)
1579
new_inv_sha1 = sha_string(new_inv_xml)
1580
self.inv_weave.add_lines(rev.revision_id,
1582
new_inv_xml.splitlines(True))
1583
rev.inventory_sha1 = new_inv_sha1
1585
def _convert_revision_contents(self, rev, inv, present_parents):
1586
"""Convert all the files within a revision.
1588
Also upgrade the inventory to refer to the text revision ids."""
1589
rev_id = rev.revision_id
1590
mutter('converting texts of revision {%s}',
1592
parent_invs = map(self._load_updated_inventory, present_parents)
1595
self._convert_file_version(rev, ie, parent_invs)
1597
def _convert_file_version(self, rev, ie, parent_invs):
1598
"""Convert one version of one file.
1600
The file needs to be added into the weave if it is a merge
1601
of >=2 parents or if it's changed from its parent.
1603
if ie.kind == 'root_directory':
1605
file_id = ie.file_id
1606
rev_id = rev.revision_id
1607
w = self.text_weaves.get(file_id)
1610
self.text_weaves[file_id] = w
1611
text_changed = False
1612
previous_entries = ie.find_previous_heads(parent_invs,
1616
for old_revision in previous_entries:
1617
# if this fails, its a ghost ?
1618
assert old_revision in self.converted_revs
1619
self.snapshot_ie(previous_entries, ie, w, rev_id)
1621
assert getattr(ie, 'revision', None) is not None
1623
def snapshot_ie(self, previous_revisions, ie, w, rev_id):
1624
# TODO: convert this logic, which is ~= snapshot to
1625
# a call to:. This needs the path figured out. rather than a work_tree
1626
# a v4 revision_tree can be given, or something that looks enough like
1627
# one to give the file content to the entry if it needs it.
1628
# and we need something that looks like a weave store for snapshot to
1630
#ie.snapshot(rev, PATH, previous_revisions, REVISION_TREE, InMemoryWeaveStore(self.text_weaves))
1631
if len(previous_revisions) == 1:
1632
previous_ie = previous_revisions.values()[0]
1633
if ie._unchanged(previous_ie):
1634
ie.revision = previous_ie.revision
1637
text = self.branch.repository.text_store.get(ie.text_id)
1638
file_lines = text.readlines()
1639
assert sha_strings(file_lines) == ie.text_sha1
1640
assert sum(map(len, file_lines)) == ie.text_size
1641
w.add_lines(rev_id, previous_revisions, file_lines)
1642
self.text_count += 1
1644
w.add_lines(rev_id, previous_revisions, [])
1645
ie.revision = rev_id
1647
def _make_order(self):
1648
"""Return a suitable order for importing revisions.
1650
The order must be such that an revision is imported after all
1651
its (present) parents.
1653
todo = set(self.revisions.keys())
1654
done = self.absent_revisions.copy()
1657
# scan through looking for a revision whose parents
1659
for rev_id in sorted(list(todo)):
1660
rev = self.revisions[rev_id]
1661
parent_ids = set(rev.parent_ids)
1662
if parent_ids.issubset(done):
1663
# can take this one now
1664
order.append(rev_id)
1670
class ConvertBzrDir5To6(Converter):
1671
"""Converts format 5 bzr dirs to format 6."""
1673
def convert(self, to_convert, pb):
1674
"""See Converter.convert()."""
1675
self.bzrdir = to_convert
1677
self.pb.note('starting upgrade from format 5 to 6')
1678
self._convert_to_prefixed()
1679
return BzrDir.open(self.bzrdir.root_transport.base)
1681
def _convert_to_prefixed(self):
1682
from bzrlib.store import TransportStore
1683
self.bzrdir.transport.delete('branch-format')
1684
for store_name in ["weaves", "revision-store"]:
1685
self.pb.note("adding prefixes to %s" % store_name)
1686
store_transport = self.bzrdir.transport.clone(store_name)
1687
store = TransportStore(store_transport, prefixed=True)
1688
for urlfilename in store_transport.list_dir('.'):
1689
filename = urlutils.unescape(urlfilename)
1690
if (filename.endswith(".weave") or
1691
filename.endswith(".gz") or
1692
filename.endswith(".sig")):
1693
file_id = os.path.splitext(filename)[0]
1696
prefix_dir = store.hash_prefix(file_id)
1697
# FIXME keep track of the dirs made RBC 20060121
1699
store_transport.move(filename, prefix_dir + '/' + filename)
1700
except errors.NoSuchFile: # catches missing dirs strangely enough
1701
store_transport.mkdir(prefix_dir)
1702
store_transport.move(filename, prefix_dir + '/' + filename)
1703
self.bzrdir._control_files.put_utf8('branch-format', BzrDirFormat6().get_format_string())
1706
class ConvertBzrDir6ToMeta(Converter):
1707
"""Converts format 6 bzr dirs to metadirs."""
1709
def convert(self, to_convert, pb):
1710
"""See Converter.convert()."""
1711
self.bzrdir = to_convert
1714
self.total = 20 # the steps we know about
1715
self.garbage_inventories = []
1717
self.pb.note('starting upgrade from format 6 to metadir')
1718
self.bzrdir._control_files.put_utf8('branch-format', "Converting to format 6")
1719
# its faster to move specific files around than to open and use the apis...
1720
# first off, nuke ancestry.weave, it was never used.
1722
self.step('Removing ancestry.weave')
1723
self.bzrdir.transport.delete('ancestry.weave')
1724
except errors.NoSuchFile:
1726
# find out whats there
1727
self.step('Finding branch files')
1728
last_revision = self.bzrdir.open_branch().last_revision()
1729
bzrcontents = self.bzrdir.transport.list_dir('.')
1730
for name in bzrcontents:
1731
if name.startswith('basis-inventory.'):
1732
self.garbage_inventories.append(name)
1733
# create new directories for repository, working tree and branch
1734
self.dir_mode = self.bzrdir._control_files._dir_mode
1735
self.file_mode = self.bzrdir._control_files._file_mode
1736
repository_names = [('inventory.weave', True),
1737
('revision-store', True),
1739
self.step('Upgrading repository ')
1740
self.bzrdir.transport.mkdir('repository', mode=self.dir_mode)
1741
self.make_lock('repository')
1742
# we hard code the formats here because we are converting into
1743
# the meta format. The meta format upgrader can take this to a
1744
# future format within each component.
1745
self.put_format('repository', bzrlib.repository.RepositoryFormat7())
1746
for entry in repository_names:
1747
self.move_entry('repository', entry)
1749
self.step('Upgrading branch ')
1750
self.bzrdir.transport.mkdir('branch', mode=self.dir_mode)
1751
self.make_lock('branch')
1752
self.put_format('branch', bzrlib.branch.BzrBranchFormat5())
1753
branch_files = [('revision-history', True),
1754
('branch-name', True),
1756
for entry in branch_files:
1757
self.move_entry('branch', entry)
1759
self.step('Upgrading working tree')
1760
self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
1761
self.make_lock('checkout')
1762
self.put_format('checkout', bzrlib.workingtree.WorkingTreeFormat3())
1763
self.bzrdir.transport.delete_multi(self.garbage_inventories, self.pb)
1764
checkout_files = [('pending-merges', True),
1765
('inventory', True),
1766
('stat-cache', False)]
1767
for entry in checkout_files:
1768
self.move_entry('checkout', entry)
1769
if last_revision is not None:
1770
self.bzrdir._control_files.put_utf8('checkout/last-revision',
1772
self.bzrdir._control_files.put_utf8('branch-format', BzrDirMetaFormat1().get_format_string())
1773
return BzrDir.open(self.bzrdir.root_transport.base)
1775
def make_lock(self, name):
1776
"""Make a lock for the new control dir name."""
1777
self.step('Make %s lock' % name)
1778
ld = LockDir(self.bzrdir.transport,
1780
file_modebits=self.file_mode,
1781
dir_modebits=self.dir_mode)
1784
def move_entry(self, new_dir, entry):
1785
"""Move then entry name into new_dir."""
1787
mandatory = entry[1]
1788
self.step('Moving %s' % name)
1790
self.bzrdir.transport.move(name, '%s/%s' % (new_dir, name))
1791
except errors.NoSuchFile:
1795
def put_format(self, dirname, format):
1796
self.bzrdir._control_files.put_utf8('%s/format' % dirname, format.get_format_string())
1799
class ConvertMetaToMeta(Converter):
1792
repository_format = property(__return_repository_format,
1793
_set_repository_format)
1795
def _supply_sub_formats_to(self, other_format):
1796
"""Give other_format the same values for sub formats as this has.
1798
This method is expected to be used when parameterising a
1799
RemoteBzrDirFormat instance with the parameters from a
1800
BzrDirMetaFormat1 instance.
1802
:param other_format: other_format is a format which should be
1803
compatible with whatever sub formats are supported by self.
1806
if getattr(self, '_repository_format', None) is not None:
1807
other_format.repository_format = self.repository_format
1808
if self._branch_format is not None:
1809
other_format._branch_format = self._branch_format
1810
if self._workingtree_format is not None:
1811
other_format.workingtree_format = self.workingtree_format
1813
def __get_workingtree_format(self):
1814
if self._workingtree_format is None:
1815
from bzrlib.workingtree import (
1816
format_registry as wt_format_registry,
1818
self._workingtree_format = wt_format_registry.get_default()
1819
return self._workingtree_format
1821
def __set_workingtree_format(self, wt_format):
1822
self._workingtree_format = wt_format
1824
workingtree_format = property(__get_workingtree_format,
1825
__set_workingtree_format)
1828
# Register bzr formats
1829
BzrProber.formats.register(BzrDirMetaFormat1.get_format_string(),
1831
controldir.ControlDirFormat._default_format = BzrDirMetaFormat1()
1834
class ConvertMetaToMeta(controldir.Converter):
1800
1835
"""Converts the components of metadirs."""
1802
1837
def __init__(self, target_format):
1821
1856
if not isinstance(repo._format, self.target_format.repository_format.__class__):
1822
1857
from bzrlib.repository import CopyConverter
1823
self.pb.note('starting repository conversion')
1858
ui.ui_factory.note(gettext('starting repository conversion'))
1824
1859
converter = CopyConverter(self.target_format.repository_format)
1825
1860
converter.convert(repo, pb)
1861
for branch in self.bzrdir.list_branches():
1862
# TODO: conversions of Branch and Tree should be done by
1863
# InterXFormat lookups/some sort of registry.
1864
# Avoid circular imports
1865
old = branch._format.__class__
1866
new = self.target_format.get_branch_format().__class__
1868
if (old == _mod_branch.BzrBranchFormat5 and
1869
new in (_mod_branch.BzrBranchFormat6,
1870
_mod_branch.BzrBranchFormat7,
1871
_mod_branch.BzrBranchFormat8)):
1872
branch_converter = _mod_branch.Converter5to6()
1873
elif (old == _mod_branch.BzrBranchFormat6 and
1874
new in (_mod_branch.BzrBranchFormat7,
1875
_mod_branch.BzrBranchFormat8)):
1876
branch_converter = _mod_branch.Converter6to7()
1877
elif (old == _mod_branch.BzrBranchFormat7 and
1878
new is _mod_branch.BzrBranchFormat8):
1879
branch_converter = _mod_branch.Converter7to8()
1881
raise errors.BadConversionTarget("No converter", new,
1883
branch_converter.convert(branch)
1884
branch = self.bzrdir.open_branch()
1885
old = branch._format.__class__
1887
tree = self.bzrdir.open_workingtree(recommend_upgrade=False)
1888
except (errors.NoWorkingTree, errors.NotLocalUrl):
1891
# TODO: conversions of Branch and Tree should be done by
1892
# InterXFormat lookups
1893
if (isinstance(tree, workingtree_3.WorkingTree3) and
1894
not isinstance(tree, workingtree_4.DirStateWorkingTree) and
1895
isinstance(self.target_format.workingtree_format,
1896
workingtree_4.DirStateWorkingTreeFormat)):
1897
workingtree_4.Converter3to4().convert(tree)
1898
if (isinstance(tree, workingtree_4.DirStateWorkingTree) and
1899
not isinstance(tree, workingtree_4.WorkingTree5) and
1900
isinstance(self.target_format.workingtree_format,
1901
workingtree_4.WorkingTreeFormat5)):
1902
workingtree_4.Converter4to5().convert(tree)
1903
if (isinstance(tree, workingtree_4.DirStateWorkingTree) and
1904
not isinstance(tree, workingtree_4.WorkingTree6) and
1905
isinstance(self.target_format.workingtree_format,
1906
workingtree_4.WorkingTreeFormat6)):
1907
workingtree_4.Converter4or5to6().convert(tree)
1826
1909
return to_convert
1912
controldir.ControlDirFormat.register_server_prober(RemoteBzrProber)
1915
class RepositoryAcquisitionPolicy(object):
1916
"""Abstract base class for repository acquisition policies.
1918
A repository acquisition policy decides how a BzrDir acquires a repository
1919
for a branch that is being created. The most basic policy decision is
1920
whether to create a new repository or use an existing one.
1922
def __init__(self, stack_on, stack_on_pwd, require_stacking):
1925
:param stack_on: A location to stack on
1926
:param stack_on_pwd: If stack_on is relative, the location it is
1928
:param require_stacking: If True, it is a failure to not stack.
1930
self._stack_on = stack_on
1931
self._stack_on_pwd = stack_on_pwd
1932
self._require_stacking = require_stacking
1934
def configure_branch(self, branch):
1935
"""Apply any configuration data from this policy to the branch.
1937
Default implementation sets repository stacking.
1939
if self._stack_on is None:
1941
if self._stack_on_pwd is None:
1942
stack_on = self._stack_on
1945
stack_on = urlutils.rebase_url(self._stack_on,
1948
except errors.InvalidRebaseURLs:
1949
stack_on = self._get_full_stack_on()
1951
branch.set_stacked_on_url(stack_on)
1952
except (errors.UnstackableBranchFormat,
1953
errors.UnstackableRepositoryFormat):
1954
if self._require_stacking:
1957
def requires_stacking(self):
1958
"""Return True if this policy requires stacking."""
1959
return self._stack_on is not None and self._require_stacking
1961
def _get_full_stack_on(self):
1962
"""Get a fully-qualified URL for the stack_on location."""
1963
if self._stack_on is None:
1965
if self._stack_on_pwd is None:
1966
return self._stack_on
1968
return urlutils.join(self._stack_on_pwd, self._stack_on)
1970
def _add_fallback(self, repository, possible_transports=None):
1971
"""Add a fallback to the supplied repository, if stacking is set."""
1972
stack_on = self._get_full_stack_on()
1973
if stack_on is None:
1976
stacked_dir = BzrDir.open(stack_on,
1977
possible_transports=possible_transports)
1978
except errors.JailBreak:
1979
# We keep the stacking details, but we are in the server code so
1980
# actually stacking is not needed.
1983
stacked_repo = stacked_dir.open_branch().repository
1984
except errors.NotBranchError:
1985
stacked_repo = stacked_dir.open_repository()
1987
repository.add_fallback_repository(stacked_repo)
1988
except errors.UnstackableRepositoryFormat:
1989
if self._require_stacking:
1992
self._require_stacking = True
1994
def acquire_repository(self, make_working_trees=None, shared=False):
1995
"""Acquire a repository for this bzrdir.
1997
Implementations may create a new repository or use a pre-exising
2000
:param make_working_trees: If creating a repository, set
2001
make_working_trees to this value (if non-None)
2002
:param shared: If creating a repository, make it shared if True
2003
:return: A repository, is_new_flag (True if the repository was
2006
raise NotImplemented(RepositoryAcquisitionPolicy.acquire_repository)
2009
class CreateRepository(RepositoryAcquisitionPolicy):
2010
"""A policy of creating a new repository"""
2012
def __init__(self, bzrdir, stack_on=None, stack_on_pwd=None,
2013
require_stacking=False):
2016
:param bzrdir: The bzrdir to create the repository on.
2017
:param stack_on: A location to stack on
2018
:param stack_on_pwd: If stack_on is relative, the location it is
2021
RepositoryAcquisitionPolicy.__init__(self, stack_on, stack_on_pwd,
2023
self._bzrdir = bzrdir
2025
def acquire_repository(self, make_working_trees=None, shared=False):
2026
"""Implementation of RepositoryAcquisitionPolicy.acquire_repository
2028
Creates the desired repository in the bzrdir we already have.
2030
stack_on = self._get_full_stack_on()
2032
format = self._bzrdir._format
2033
format.require_stacking(stack_on=stack_on,
2034
possible_transports=[self._bzrdir.root_transport])
2035
if not self._require_stacking:
2036
# We have picked up automatic stacking somewhere.
2037
note(gettext('Using default stacking branch {0} at {1}').format(
2038
self._stack_on, self._stack_on_pwd))
2039
repository = self._bzrdir.create_repository(shared=shared)
2040
self._add_fallback(repository,
2041
possible_transports=[self._bzrdir.transport])
2042
if make_working_trees is not None:
2043
repository.set_make_working_trees(make_working_trees)
2044
return repository, True
2047
class UseExistingRepository(RepositoryAcquisitionPolicy):
2048
"""A policy of reusing an existing repository"""
2050
def __init__(self, repository, stack_on=None, stack_on_pwd=None,
2051
require_stacking=False):
2054
:param repository: The repository to use.
2055
:param stack_on: A location to stack on
2056
:param stack_on_pwd: If stack_on is relative, the location it is
2059
RepositoryAcquisitionPolicy.__init__(self, stack_on, stack_on_pwd,
2061
self._repository = repository
2063
def acquire_repository(self, make_working_trees=None, shared=False):
2064
"""Implementation of RepositoryAcquisitionPolicy.acquire_repository
2066
Returns an existing repository to use.
2068
self._add_fallback(self._repository,
2069
possible_transports=[self._repository.bzrdir.transport])
2070
return self._repository, False
2073
def register_metadir(registry, key,
2074
repository_format, help, native=True, deprecated=False,
2080
"""Register a metadir subformat.
2082
These all use a BzrDirMetaFormat1 bzrdir, but can be parameterized
2083
by the Repository/Branch/WorkingTreeformats.
2085
:param repository_format: The fully-qualified repository format class
2087
:param branch_format: Fully-qualified branch format class name as
2089
:param tree_format: Fully-qualified tree format class name as
2092
# This should be expanded to support setting WorkingTree and Branch
2093
# formats, once BzrDirMetaFormat1 supports that.
2094
def _load(full_name):
2095
mod_name, factory_name = full_name.rsplit('.', 1)
2097
factory = pyutils.get_named_object(mod_name, factory_name)
2098
except ImportError, e:
2099
raise ImportError('failed to load %s: %s' % (full_name, e))
2100
except AttributeError:
2101
raise AttributeError('no factory %s in module %r'
2102
% (full_name, sys.modules[mod_name]))
2106
bd = BzrDirMetaFormat1()
2107
if branch_format is not None:
2108
bd.set_branch_format(_load(branch_format))
2109
if tree_format is not None:
2110
bd.workingtree_format = _load(tree_format)
2111
if repository_format is not None:
2112
bd.repository_format = _load(repository_format)
2114
registry.register(key, helper, help, native, deprecated, hidden,
2115
experimental, alias)
2117
register_metadir(controldir.format_registry, 'knit',
2118
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2119
'Format using knits. Recommended for interoperation with bzr <= 0.14.',
2120
branch_format='bzrlib.branch.BzrBranchFormat5',
2121
tree_format='bzrlib.workingtree_3.WorkingTreeFormat3',
2124
register_metadir(controldir.format_registry, 'dirstate',
2125
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2126
help='New in 0.15: Fast local operations. Compatible with bzr 0.8 and '
2127
'above when accessed over the network.',
2128
branch_format='bzrlib.branch.BzrBranchFormat5',
2129
tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2132
register_metadir(controldir.format_registry, 'dirstate-tags',
2133
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2134
help='New in 0.15: Fast local operations and improved scaling for '
2135
'network operations. Additionally adds support for tags.'
2136
' Incompatible with bzr < 0.15.',
2137
branch_format='bzrlib.branch.BzrBranchFormat6',
2138
tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2141
register_metadir(controldir.format_registry, 'rich-root',
2142
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit4',
2143
help='New in 1.0. Better handling of tree roots. Incompatible with'
2145
branch_format='bzrlib.branch.BzrBranchFormat6',
2146
tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2149
register_metadir(controldir.format_registry, 'dirstate-with-subtree',
2150
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
2151
help='New in 0.15: Fast local operations and improved scaling for '
2152
'network operations. Additionally adds support for versioning nested '
2153
'bzr branches. Incompatible with bzr < 0.15.',
2154
branch_format='bzrlib.branch.BzrBranchFormat6',
2155
tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2159
register_metadir(controldir.format_registry, 'pack-0.92',
2160
'bzrlib.repofmt.knitpack_repo.RepositoryFormatKnitPack1',
2161
help='New in 0.92: Pack-based format with data compatible with '
2162
'dirstate-tags format repositories. Interoperates with '
2163
'bzr repositories before 0.92 but cannot be read by bzr < 0.92. '
2165
branch_format='bzrlib.branch.BzrBranchFormat6',
2166
tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2168
register_metadir(controldir.format_registry, 'pack-0.92-subtree',
2169
'bzrlib.repofmt.knitpack_repo.RepositoryFormatKnitPack3',
2170
help='New in 0.92: Pack-based format with data compatible with '
2171
'dirstate-with-subtree format repositories. Interoperates with '
2172
'bzr repositories before 0.92 but cannot be read by bzr < 0.92. '
2174
branch_format='bzrlib.branch.BzrBranchFormat6',
2175
tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2179
register_metadir(controldir.format_registry, 'rich-root-pack',
2180
'bzrlib.repofmt.knitpack_repo.RepositoryFormatKnitPack4',
2181
help='New in 1.0: A variant of pack-0.92 that supports rich-root data '
2182
'(needed for bzr-svn and bzr-git).',
2183
branch_format='bzrlib.branch.BzrBranchFormat6',
2184
tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2187
register_metadir(controldir.format_registry, '1.6',
2188
'bzrlib.repofmt.knitpack_repo.RepositoryFormatKnitPack5',
2189
help='A format that allows a branch to indicate that there is another '
2190
'(stacked) repository that should be used to access data that is '
2191
'not present locally.',
2192
branch_format='bzrlib.branch.BzrBranchFormat7',
2193
tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2196
register_metadir(controldir.format_registry, '1.6.1-rich-root',
2197
'bzrlib.repofmt.knitpack_repo.RepositoryFormatKnitPack5RichRoot',
2198
help='A variant of 1.6 that supports rich-root data '
2199
'(needed for bzr-svn and bzr-git).',
2200
branch_format='bzrlib.branch.BzrBranchFormat7',
2201
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',
2213
register_metadir(controldir.format_registry, '1.9-rich-root',
2214
'bzrlib.repofmt.knitpack_repo.RepositoryFormatKnitPack6RichRoot',
2215
help='A variant of 1.9 that supports rich-root data '
2216
'(needed for bzr-svn and bzr-git).',
2217
branch_format='bzrlib.branch.BzrBranchFormat7',
2218
tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2221
register_metadir(controldir.format_registry, '1.14',
2222
'bzrlib.repofmt.knitpack_repo.RepositoryFormatKnitPack6',
2223
help='A working-tree format that supports content filtering.',
2224
branch_format='bzrlib.branch.BzrBranchFormat7',
2225
tree_format='bzrlib.workingtree_4.WorkingTreeFormat5',
2227
register_metadir(controldir.format_registry, '1.14-rich-root',
2228
'bzrlib.repofmt.knitpack_repo.RepositoryFormatKnitPack6RichRoot',
2229
help='A variant of 1.14 that supports rich-root data '
2230
'(needed for bzr-svn and bzr-git).',
2231
branch_format='bzrlib.branch.BzrBranchFormat7',
2232
tree_format='bzrlib.workingtree_4.WorkingTreeFormat5',
2234
# The following un-numbered 'development' formats should always just be aliases.
2235
register_metadir(controldir.format_registry, 'development-subtree',
2236
'bzrlib.repofmt.groupcompress_repo.RepositoryFormat2aSubtree',
2237
help='Current development format, subtree variant. Can convert data to and '
2238
'from pack-0.92-subtree (and anything compatible with '
2239
'pack-0.92-subtree) format repositories. Repositories and branches in '
2240
'this format can only be read by bzr.dev. Please read '
2241
'http://doc.bazaar.canonical.com/latest/developers/development-repo.html '
2243
branch_format='bzrlib.branch.BzrBranchFormat7',
2244
tree_format='bzrlib.workingtree_4.WorkingTreeFormat6',
2247
alias=False, # Restore to being an alias when an actual development subtree format is added
2248
# This current non-alias status is simply because we did not introduce a
2249
# chk based subtree format.
2251
register_metadir(controldir.format_registry, 'development5-subtree',
2252
'bzrlib.repofmt.knitpack_repo.RepositoryFormatPackDevelopment2Subtree',
2253
help='Development format, subtree variant. Can convert data to and '
2254
'from pack-0.92-subtree (and anything compatible with '
2255
'pack-0.92-subtree) format repositories. Repositories and branches in '
2256
'this format can only be read by bzr.dev. Please read '
2257
'http://doc.bazaar.canonical.com/latest/developers/development-repo.html '
2259
branch_format='bzrlib.branch.BzrBranchFormat7',
2260
tree_format='bzrlib.workingtree_4.WorkingTreeFormat6',
2266
# And the development formats above will have aliased one of the following:
2268
# Finally, the current format.
2269
register_metadir(controldir.format_registry, '2a',
2270
'bzrlib.repofmt.groupcompress_repo.RepositoryFormat2a',
2271
help='First format for bzr 2.0 series.\n'
2272
'Uses group-compress storage.\n'
2273
'Provides rich roots which are a one-way transition.\n',
2274
# 'storage in packs, 255-way hashed CHK inventory, bencode revision, group compress, '
2275
# 'rich roots. Supported by bzr 1.16 and later.',
2276
branch_format='bzrlib.branch.BzrBranchFormat7',
2277
tree_format='bzrlib.workingtree_4.WorkingTreeFormat6',
2281
# The following format should be an alias for the rich root equivalent
2282
# of the default format
2283
register_metadir(controldir.format_registry, 'default-rich-root',
2284
'bzrlib.repofmt.groupcompress_repo.RepositoryFormat2a',
2285
branch_format='bzrlib.branch.BzrBranchFormat7',
2286
tree_format='bzrlib.workingtree_4.WorkingTreeFormat6',
2291
# The current format that is made on 'bzr init'.
2292
format_name = config.GlobalStack().get('default_format')
2293
controldir.format_registry.set_default(format_name)
2295
# XXX 2010-08-20 JRV: There is still a lot of code relying on
2296
# bzrlib.bzrdir.format_registry existing. When BzrDir.create/BzrDir.open/etc
2297
# get changed to ControlDir.create/ControlDir.open/etc this should be removed.
2298
format_registry = controldir.format_registry