96
112
thing_to_unlock.break_lock()
98
def can_convert_format(self):
99
"""Return true if this bzrdir is one whose format we can convert from."""
102
114
def check_conversion_target(self, target_format):
115
"""Check that a bzrdir as a whole can be converted to a new format."""
116
# The only current restriction is that the repository content can be
117
# fetched compatibly with the target.
103
118
target_repo_format = target_format.repository_format
104
source_repo_format = self._format.repository_format
105
source_repo_format.check_conversion_target(target_repo_format)
108
def _check_supported(format, allow_unsupported):
109
"""Check whether format is a supported format.
111
If allow_unsupported is True, this is a no-op.
113
if not allow_unsupported and not format.is_supported():
114
# see open_downlevel to open legacy branches.
115
raise errors.UnsupportedFormatError(format=format)
117
def clone(self, url, revision_id=None, basis=None, force_new_repo=False):
118
"""Clone this bzrdir and its contents to url verbatim.
120
If urls last component does not exist, it will be created.
122
if revision_id is not None, then the clone operation may tune
120
self.open_repository()._format.check_conversion_target(
122
except errors.NoRepositoryPresent:
123
# No repo, no problem.
126
def clone_on_transport(self, transport, revision_id=None,
127
force_new_repo=False, preserve_stacking=False, stacked_on=None,
128
create_prefix=False, use_existing_dir=True, no_tree=False):
129
"""Clone this bzrdir and its contents to transport verbatim.
131
:param transport: The transport for the location to produce the clone
132
at. If the target directory does not exist, it will be created.
133
:param revision_id: The tip revision-id to use for any branch or
134
working tree. If not None, then the clone operation may tune
123
135
itself to download less data.
124
:param force_new_repo: Do not use a shared repository for the target
136
:param force_new_repo: Do not use a shared repository for the target,
125
137
even if one is available.
138
:param preserve_stacking: When cloning a stacked branch, stack the
139
new branch on top of the other branch's stacked-on branch.
140
:param create_prefix: Create any missing directories leading up to
142
:param use_existing_dir: Use an existing directory if one exists.
143
:param no_tree: If set to true prevents creation of a working tree.
128
basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
129
result = self._format.initialize(url)
145
# Overview: put together a broad description of what we want to end up
146
# with; then make as few api calls as possible to do it.
148
# We may want to create a repo/branch/tree, if we do so what format
149
# would we want for each:
150
require_stacking = (stacked_on is not None)
151
format = self.cloning_metadir(require_stacking)
153
# Figure out what objects we want:
131
155
local_repo = self.find_repository()
132
156
except errors.NoRepositoryPresent:
133
157
local_repo = None
159
local_branch = self.open_branch()
160
except errors.NotBranchError:
163
# enable fallbacks when branch is not a branch reference
164
if local_branch.repository.has_same_location(local_repo):
165
local_repo = local_branch.repository
166
if preserve_stacking:
168
stacked_on = local_branch.get_stacked_on_url()
169
except (errors.UnstackableBranchFormat,
170
errors.UnstackableRepositoryFormat,
173
# Bug: We create a metadir without knowing if it can support stacking,
174
# we should look up the policy needs first, or just use it as a hint,
135
# may need to copy content in
137
result_repo = local_repo.clone(
139
revision_id=revision_id,
141
result_repo.set_make_working_trees(local_repo.make_working_trees())
144
result_repo = result.find_repository()
145
# fetch content this dir needs.
147
# XXX FIXME RBC 20060214 need tests for this when the basis
149
result_repo.fetch(basis_repo, revision_id=revision_id)
177
make_working_trees = local_repo.make_working_trees() and not no_tree
178
want_shared = local_repo.is_shared()
179
repo_format_name = format.repository_format.network_name()
181
make_working_trees = False
183
repo_format_name = None
185
result_repo, result, require_stacking, repository_policy = \
186
format.initialize_on_transport_ex(transport,
187
use_existing_dir=use_existing_dir, create_prefix=create_prefix,
188
force_new_repo=force_new_repo, stacked_on=stacked_on,
189
stack_on_pwd=self.root_transport.base,
190
repo_format_name=repo_format_name,
191
make_working_trees=make_working_trees, shared_repo=want_shared)
194
# If the result repository is in the same place as the
195
# resulting bzr dir, it will have no content, further if the
196
# result is not stacked then we know all content should be
197
# copied, and finally if we are copying up to a specific
198
# revision_id then we can use the pending-ancestry-result which
199
# does not require traversing all of history to describe it.
200
if (result_repo.user_url == result.user_url
201
and not require_stacking and
202
revision_id is not None):
203
fetch_spec = graph.PendingAncestryResult(
204
[revision_id], local_repo)
205
result_repo.fetch(local_repo, fetch_spec=fetch_spec)
150
207
result_repo.fetch(local_repo, revision_id=revision_id)
151
except errors.NoRepositoryPresent:
152
# needed to make one anyway.
153
result_repo = local_repo.clone(
155
revision_id=revision_id,
157
result_repo.set_make_working_trees(local_repo.make_working_trees())
211
if result_repo is not None:
212
raise AssertionError('result_repo not None(%r)' % result_repo)
158
213
# 1 if there is a branch present
159
214
# make sure its content is available in the target repository
162
self.open_branch().clone(result, revision_id=revision_id)
163
except errors.NotBranchError:
166
self.open_workingtree().clone(result, basis=basis_tree)
216
if local_branch is not None:
217
result_branch = local_branch.clone(result, revision_id=revision_id,
218
repository_policy=repository_policy)
220
# Cheaper to check if the target is not local, than to try making
222
result.root_transport.local_abspath('.')
223
if result_repo is None or result_repo.make_working_trees():
224
self.open_workingtree().clone(result)
167
225
except (errors.NoWorkingTree, errors.NotLocalUrl):
171
def _get_basis_components(self, basis):
172
"""Retrieve the basis components that are available at basis."""
174
return None, None, None
176
basis_tree = basis.open_workingtree()
177
basis_branch = basis_tree.branch
178
basis_repo = basis_branch.repository
179
except (errors.NoWorkingTree, errors.NotLocalUrl):
182
basis_branch = basis.open_branch()
183
basis_repo = basis_branch.repository
184
except errors.NotBranchError:
187
basis_repo = basis.open_repository()
188
except errors.NoRepositoryPresent:
190
return basis_repo, basis_branch, basis_tree
192
229
# TODO: This should be given a Transport, and should chdir up; otherwise
193
230
# this will open a new connection.
194
231
def _make_tail(self, url):
195
head, tail = urlutils.split(url)
196
if tail and tail != '.':
197
t = get_transport(head)
200
except errors.FileExists:
203
# TODO: Should take a Transport
205
def create(cls, base):
206
"""Create a new BzrDir at the url 'base'.
208
This will call the current default formats initialize with base
209
as the only parameter.
211
If you need a specific format, consider creating an instance
212
of that and calling initialize().
214
if cls is not BzrDir:
215
raise AssertionError("BzrDir.create always creates the default format, "
216
"not one of %r" % cls)
217
head, tail = urlutils.split(base)
218
if tail and tail != '.':
219
t = get_transport(head)
222
except errors.FileExists:
224
return BzrDirFormat.get_default_format().initialize(safe_unicode(base))
226
def create_branch(self):
227
"""Create a branch in this BzrDir.
229
The bzrdirs format will control what branch format is created.
230
For more control see BranchFormatXX.create(a_bzrdir).
232
raise NotImplementedError(self.create_branch)
235
def create_branch_and_repo(base, force_new_repo=False):
232
t = _mod_transport.get_transport(url)
236
def find_bzrdirs(transport, evaluate=None, list_current=None):
237
"""Find bzrdirs recursively from current location.
239
This is intended primarily as a building block for more sophisticated
240
functionality, like finding trees under a directory, or finding
241
branches that use a given repository.
242
:param evaluate: An optional callable that yields recurse, value,
243
where recurse controls whether this bzrdir is recursed into
244
and value is the value to yield. By default, all bzrdirs
245
are recursed into, and the return value is the bzrdir.
246
:param list_current: if supplied, use this function to list the current
247
directory, instead of Transport.list_dir
248
:return: a generator of found bzrdirs, or whatever evaluate returns.
250
if list_current is None:
251
def list_current(transport):
252
return transport.list_dir('')
254
def evaluate(bzrdir):
257
pending = [transport]
258
while len(pending) > 0:
259
current_transport = pending.pop()
262
bzrdir = BzrDir.open_from_transport(current_transport)
263
except (errors.NotBranchError, errors.PermissionDenied):
266
recurse, value = evaluate(bzrdir)
269
subdirs = list_current(current_transport)
270
except (errors.NoSuchFile, errors.PermissionDenied):
273
for subdir in sorted(subdirs, reverse=True):
274
pending.append(current_transport.clone(subdir))
277
def find_branches(transport):
278
"""Find all branches under a transport.
280
This will find all branches below the transport, including branches
281
inside other branches. Where possible, it will use
282
Repository.find_branches.
284
To list all the branches that use a particular Repository, see
285
Repository.find_branches
287
def evaluate(bzrdir):
289
repository = bzrdir.open_repository()
290
except errors.NoRepositoryPresent:
293
return False, ([], repository)
294
return True, (bzrdir.list_branches(), None)
296
for branches, repo in BzrDir.find_bzrdirs(transport,
299
ret.extend(repo.find_branches())
300
if branches is not None:
305
def create_branch_and_repo(base, force_new_repo=False, format=None):
236
306
"""Create a new BzrDir, Branch and Repository at the url 'base'.
238
This will use the current default BzrDirFormat, and use whatever
308
This will use the current default BzrDirFormat unless one is
309
specified, and use whatever
239
310
repository format that that uses via bzrdir.create_branch and
240
311
create_repository. If a shared repository is available that is used
245
316
:param base: The URL to create the branch at.
246
317
:param force_new_repo: If True a new repository is always created.
318
:param format: If supplied, the format of branch to create. If not
319
supplied, the default is used.
248
bzrdir = BzrDir.create(base)
321
bzrdir = BzrDir.create(base, format)
249
322
bzrdir._find_or_create_repository(force_new_repo)
250
323
return bzrdir.create_branch()
325
def determine_repository_policy(self, force_new_repo=False, stack_on=None,
326
stack_on_pwd=None, require_stacking=False):
327
"""Return an object representing a policy to use.
329
This controls whether a new repository is created, and the format of
330
that repository, or some existing shared repository used instead.
332
If stack_on is supplied, will not seek a containing shared repo.
334
:param force_new_repo: If True, require a new repository to be created.
335
:param stack_on: If supplied, the location to stack on. If not
336
supplied, a default_stack_on location may be used.
337
:param stack_on_pwd: If stack_on is relative, the location it is
340
def repository_policy(found_bzrdir):
343
config = found_bzrdir.get_config()
345
stack_on = config.get_default_stack_on()
346
if stack_on is not None:
347
stack_on_pwd = found_bzrdir.user_url
349
# does it have a repository ?
351
repository = found_bzrdir.open_repository()
352
except errors.NoRepositoryPresent:
355
if (found_bzrdir.user_url != self.user_url
356
and not repository.is_shared()):
357
# Don't look higher, can't use a higher shared repo.
365
return UseExistingRepository(repository, stack_on,
366
stack_on_pwd, require_stacking=require_stacking), True
368
return CreateRepository(self, stack_on, stack_on_pwd,
369
require_stacking=require_stacking), True
371
if not force_new_repo:
373
policy = self._find_containing(repository_policy)
374
if policy is not None:
378
return UseExistingRepository(self.open_repository(),
379
stack_on, stack_on_pwd,
380
require_stacking=require_stacking)
381
except errors.NoRepositoryPresent:
383
return CreateRepository(self, stack_on, stack_on_pwd,
384
require_stacking=require_stacking)
252
386
def _find_or_create_repository(self, force_new_repo):
253
387
"""Create a new repository if needed, returning the repository."""
255
return self.create_repository()
388
policy = self.determine_repository_policy(force_new_repo)
389
return policy.acquire_repository()[0]
391
def _find_source_repo(self, add_cleanup, source_branch):
392
"""Find the source branch and repo for a sprout operation.
394
This is helper intended for use by _sprout.
396
:returns: (source_branch, source_repository). Either or both may be
397
None. If not None, they will be read-locked (and their unlock(s)
398
scheduled via the add_cleanup param).
400
if source_branch is not None:
401
add_cleanup(source_branch.lock_read().unlock)
402
return source_branch, source_branch.repository
257
return self.find_repository()
258
except errors.NoRepositoryPresent:
259
return self.create_repository()
404
source_branch = self.open_branch()
405
source_repository = source_branch.repository
406
except errors.NotBranchError:
409
source_repository = self.open_repository()
410
except errors.NoRepositoryPresent:
411
source_repository = None
413
add_cleanup(source_repository.lock_read().unlock)
415
add_cleanup(source_branch.lock_read().unlock)
416
return source_branch, source_repository
418
def sprout(self, url, revision_id=None, force_new_repo=False,
419
recurse='down', possible_transports=None,
420
accelerator_tree=None, hardlink=False, stacked=False,
421
source_branch=None, create_tree_if_local=True):
422
"""Create a copy of this controldir prepared for use as a new line of
425
If url's last component does not exist, it will be created.
427
Attributes related to the identity of the source branch like
428
branch nickname will be cleaned, a working tree is created
429
whether one existed before or not; and a local branch is always
432
if revision_id is not None, then the clone operation may tune
433
itself to download less data.
434
:param accelerator_tree: A tree which can be used for retrieving file
435
contents more quickly than the revision tree, i.e. a workingtree.
436
The revision tree will be used for cases where accelerator_tree's
437
content is different.
438
:param hardlink: If true, hard-link files from accelerator_tree,
440
:param stacked: If true, create a stacked branch referring to the
441
location of this control directory.
442
:param create_tree_if_local: If true, a working-tree will be created
443
when working locally.
445
operation = cleanup.OperationWithCleanups(self._sprout)
446
return operation.run(url, revision_id=revision_id,
447
force_new_repo=force_new_repo, recurse=recurse,
448
possible_transports=possible_transports,
449
accelerator_tree=accelerator_tree, hardlink=hardlink,
450
stacked=stacked, source_branch=source_branch,
451
create_tree_if_local=create_tree_if_local)
453
def _sprout(self, op, url, revision_id=None, force_new_repo=False,
454
recurse='down', possible_transports=None,
455
accelerator_tree=None, hardlink=False, stacked=False,
456
source_branch=None, create_tree_if_local=True):
457
add_cleanup = op.add_cleanup
458
fetch_spec_factory = fetch.FetchSpecFactory()
459
if revision_id is not None:
460
fetch_spec_factory.add_revision_ids([revision_id])
461
fetch_spec_factory.source_branch_stop_revision_id = revision_id
462
target_transport = _mod_transport.get_transport(url,
464
target_transport.ensure_base()
465
cloning_format = self.cloning_metadir(stacked)
466
# Create/update the result branch
467
result = cloning_format.initialize_on_transport(target_transport)
468
source_branch, source_repository = self._find_source_repo(
469
add_cleanup, source_branch)
470
fetch_spec_factory.source_branch = source_branch
471
# if a stacked branch wasn't requested, we don't create one
472
# even if the origin was stacked
473
if stacked and source_branch is not None:
474
stacked_branch_url = self.root_transport.base
476
stacked_branch_url = None
477
repository_policy = result.determine_repository_policy(
478
force_new_repo, stacked_branch_url, require_stacking=stacked)
479
result_repo, is_new_repo = repository_policy.acquire_repository()
480
add_cleanup(result_repo.lock_write().unlock)
481
fetch_spec_factory.source_repo = source_repository
482
fetch_spec_factory.target_repo = result_repo
483
if stacked or (len(result_repo._fallback_repositories) != 0):
484
target_repo_kind = fetch.TargetRepoKinds.STACKED
486
target_repo_kind = fetch.TargetRepoKinds.EMPTY
488
target_repo_kind = fetch.TargetRepoKinds.PREEXISTING
489
fetch_spec_factory.target_repo_kind = target_repo_kind
490
if source_repository is not None:
491
fetch_spec = fetch_spec_factory.make_fetch_spec()
492
result_repo.fetch(source_repository, fetch_spec=fetch_spec)
494
if source_branch is None:
495
# this is for sprouting a controldir without a branch; is that
497
# Not especially, but it's part of the contract.
498
result_branch = result.create_branch()
500
result_branch = source_branch.sprout(result,
501
revision_id=revision_id, repository_policy=repository_policy,
502
repository=result_repo)
503
mutter("created new branch %r" % (result_branch,))
505
# Create/update the result working tree
506
if (create_tree_if_local and
507
isinstance(target_transport, local.LocalTransport) and
508
(result_repo is None or result_repo.make_working_trees())):
509
wt = result.create_workingtree(accelerator_tree=accelerator_tree,
510
hardlink=hardlink, from_branch=result_branch)
513
if wt.path2id('') is None:
515
wt.set_root_id(self.open_workingtree.get_root_id())
516
except errors.NoWorkingTree:
522
if recurse == 'down':
525
basis = wt.basis_tree()
526
elif result_branch is not None:
527
basis = result_branch.basis_tree()
528
elif source_branch is not None:
529
basis = source_branch.basis_tree()
530
if basis is not None:
531
add_cleanup(basis.lock_read().unlock)
532
subtrees = basis.iter_references()
535
for path, file_id in subtrees:
536
target = urlutils.join(url, urlutils.escape(path))
537
sublocation = source_branch.reference_parent(file_id, path)
538
sublocation.bzrdir.sprout(target,
539
basis.get_reference_revision(file_id, path),
540
force_new_repo=force_new_repo, recurse=recurse,
262
547
def create_branch_convenience(base, force_new_repo=False,
263
force_new_tree=None, format=None):
548
force_new_tree=None, format=None,
549
possible_transports=None):
264
550
"""Create a new BzrDir, Branch and Repository at the url 'base'.
266
552
This is a convenience function - it will use an existing repository
267
553
if possible, can be told explicitly whether to create a working tree or
270
This will use the current default BzrDirFormat, and use whatever
556
This will use the current default BzrDirFormat unless one is
557
specified, and use whatever
271
558
repository format that that uses via bzrdir.create_branch and
272
559
create_repository. If a shared repository is available that is used
273
560
preferentially. Whatever repository is used, its tree creation policy
276
563
The created Branch object is returned.
277
564
If a working tree cannot be made due to base not being a file:// url,
278
no error is raised unless force_new_tree is True, in which case no
565
no error is raised unless force_new_tree is True, in which case no
279
566
data is created on disk and NotLocalUrl is raised.
281
568
:param base: The URL to create the branch at.
282
569
:param force_new_repo: If True a new repository is always created.
283
:param force_new_tree: If True or False force creation of a tree or
570
:param force_new_tree: If True or False force creation of a tree or
284
571
prevent such creation respectively.
285
:param format: Override for the for the bzrdir format to create
572
:param format: Override for the bzrdir format to create.
573
:param possible_transports: An optional reusable transports list.
287
575
if force_new_tree:
288
576
# check for non local urls
289
t = get_transport(safe_unicode(base))
290
if not isinstance(t, LocalTransport):
577
t = _mod_transport.get_transport(base, possible_transports)
578
if not isinstance(t, local.LocalTransport):
291
579
raise errors.NotLocalUrl(base)
293
bzrdir = BzrDir.create(base)
295
bzrdir = format.initialize(base)
580
bzrdir = BzrDir.create(base, format, possible_transports)
296
581
repo = bzrdir._find_or_create_repository(force_new_repo)
297
582
result = bzrdir.create_branch()
298
if force_new_tree or (repo.make_working_trees() and
583
if force_new_tree or (repo.make_working_trees() and
299
584
force_new_tree is None):
301
586
bzrdir.create_workingtree()
302
587
except errors.NotLocalUrl:
307
def create_repository(base, shared=False):
308
"""Create a new BzrDir and Repository at the url 'base'.
310
This will use the current default BzrDirFormat, and use whatever
311
repository format that that uses for bzrdirformat.create_repository.
313
:param shared: Create a shared repository rather than a standalone
315
The Repository object is returned.
317
This must be overridden as an instance method in child classes, where
318
it should take no parameters and construct whatever repository format
319
that child class desires.
321
bzrdir = BzrDir.create(base)
322
return bzrdir.create_repository(shared)
325
def create_standalone_workingtree(base):
592
def create_standalone_workingtree(base, format=None):
326
593
"""Create a new BzrDir, WorkingTree, Branch and Repository at 'base'.
328
595
'base' must be a local path or a file:// url.
330
This will use the current default BzrDirFormat, and use whatever
597
This will use the current default BzrDirFormat unless one is
598
specified, and use whatever
331
599
repository format that that uses for bzrdirformat.create_workingtree,
332
600
create_branch and create_repository.
602
:param format: Override for the bzrdir format to create.
334
603
:return: The WorkingTree object.
336
t = get_transport(safe_unicode(base))
337
if not isinstance(t, LocalTransport):
605
t = _mod_transport.get_transport(base)
606
if not isinstance(t, local.LocalTransport):
338
607
raise errors.NotLocalUrl(base)
339
bzrdir = BzrDir.create_branch_and_repo(safe_unicode(base),
340
force_new_repo=True).bzrdir
608
bzrdir = BzrDir.create_branch_and_repo(base,
610
format=format).bzrdir
341
611
return bzrdir.create_workingtree()
343
def create_workingtree(self, revision_id=None):
344
"""Create a working tree at this BzrDir.
346
revision_id: create it as of this revision id.
348
raise NotImplementedError(self.create_workingtree)
350
def destroy_workingtree(self):
351
"""Destroy the working tree at this BzrDir.
353
Formats that do not support this may raise UnsupportedOperation.
355
raise NotImplementedError(self.destroy_workingtree)
357
def destroy_workingtree_metadata(self):
358
"""Destroy the control files for the working tree at this BzrDir.
360
The contents of working tree files are not affected.
361
Formats that do not support this may raise UnsupportedOperation.
363
raise NotImplementedError(self.destroy_workingtree_metadata)
613
@deprecated_method(deprecated_in((2, 3, 0)))
614
def generate_backup_name(self, base):
615
return self._available_backup_name(base)
617
def _available_backup_name(self, base):
618
"""Find a non-existing backup file name based on base.
620
See bzrlib.osutils.available_backup_name about race conditions.
622
return osutils.available_backup_name(base, self.root_transport.has)
624
def backup_bzrdir(self):
625
"""Backup this bzr control directory.
627
:return: Tuple with old path name and new path name
630
pb = ui.ui_factory.nested_progress_bar()
632
old_path = self.root_transport.abspath('.bzr')
633
backup_dir = self._available_backup_name('backup.bzr')
634
new_path = self.root_transport.abspath(backup_dir)
635
ui.ui_factory.note('making backup of %s\n to %s'
636
% (old_path, new_path,))
637
self.root_transport.copy_tree('.bzr', backup_dir)
638
return (old_path, new_path)
642
def retire_bzrdir(self, limit=10000):
643
"""Permanently disable the bzrdir.
645
This is done by renaming it to give the user some ability to recover
646
if there was a problem.
648
This will have horrible consequences if anyone has anything locked or
650
:param limit: number of times to retry
655
to_path = '.bzr.retired.%d' % i
656
self.root_transport.rename('.bzr', to_path)
657
note("renamed %s to %s"
658
% (self.root_transport.abspath('.bzr'), to_path))
660
except (errors.TransportError, IOError, errors.PathError):
667
def _find_containing(self, evaluate):
668
"""Find something in a containing control directory.
670
This method will scan containing control dirs, until it finds what
671
it is looking for, decides that it will never find it, or runs out
672
of containing control directories to check.
674
It is used to implement find_repository and
675
determine_repository_policy.
677
:param evaluate: A function returning (value, stop). If stop is True,
678
the value will be returned.
682
result, stop = evaluate(found_bzrdir)
685
next_transport = found_bzrdir.root_transport.clone('..')
686
if (found_bzrdir.user_url == next_transport.base):
687
# top of the file system
689
# find the next containing bzrdir
691
found_bzrdir = BzrDir.open_containing_from_transport(
693
except errors.NotBranchError:
365
696
def find_repository(self):
366
"""Find the repository that should be used for a_bzrdir.
697
"""Find the repository that should be used.
368
699
This does not require a branch as we use it to find the repo for
369
700
new branches as well as to hook existing branches up to their
373
return self.open_repository()
374
except errors.NoRepositoryPresent:
376
next_transport = self.root_transport.clone('..')
378
# find the next containing bzrdir
380
found_bzrdir = BzrDir.open_containing_from_transport(
382
except errors.NotBranchError:
384
raise errors.NoRepositoryPresent(self)
703
def usable_repository(found_bzrdir):
385
704
# does it have a repository ?
387
706
repository = found_bzrdir.open_repository()
388
707
except errors.NoRepositoryPresent:
389
next_transport = found_bzrdir.root_transport.clone('..')
390
if (found_bzrdir.root_transport.base == next_transport.base):
391
# top of the file system
395
if ((found_bzrdir.root_transport.base ==
396
self.root_transport.base) or repository.is_shared()):
399
raise errors.NoRepositoryPresent(self)
400
raise errors.NoRepositoryPresent(self)
402
def get_branch_transport(self, branch_format):
403
"""Get the transport for use by branch format in this BzrDir.
405
Note that bzr dirs that do not support format strings will raise
406
IncompatibleFormat if the branch format they are given has
407
a format string, and vice versa.
409
If branch_format is None, the transport is returned with no
410
checking. if it is not None, then the returned transport is
411
guaranteed to point to an existing directory ready for use.
413
raise NotImplementedError(self.get_branch_transport)
415
def get_repository_transport(self, repository_format):
416
"""Get the transport for use by repository format in this BzrDir.
418
Note that bzr dirs that do not support format strings will raise
419
IncompatibleFormat if the repository format they are given has
420
a format string, and vice versa.
422
If repository_format is None, the transport is returned with no
423
checking. if it is not None, then the returned transport is
424
guaranteed to point to an existing directory ready for use.
426
raise NotImplementedError(self.get_repository_transport)
428
def get_workingtree_transport(self, tree_format):
429
"""Get the transport for use by workingtree format in this BzrDir.
431
Note that bzr dirs that do not support format strings will raise
432
IncompatibleFormat if the workingtree format they are given has
433
a format string, and vice versa.
435
If workingtree_format is None, the transport is returned with no
436
checking. if it is not None, then the returned transport is
437
guaranteed to point to an existing directory ready for use.
439
raise NotImplementedError(self.get_workingtree_transport)
709
if found_bzrdir.user_url == self.user_url:
710
return repository, True
711
elif repository.is_shared():
712
return repository, True
716
found_repo = self._find_containing(usable_repository)
717
if found_repo is None:
718
raise errors.NoRepositoryPresent(self)
721
def _find_creation_modes(self):
722
"""Determine the appropriate modes for files and directories.
724
They're always set to be consistent with the base directory,
725
assuming that this transport allows setting modes.
727
# TODO: Do we need or want an option (maybe a config setting) to turn
728
# this off or override it for particular locations? -- mbp 20080512
729
if self._mode_check_done:
731
self._mode_check_done = True
733
st = self.transport.stat('.')
734
except errors.TransportNotPossible:
735
self._dir_mode = None
736
self._file_mode = None
738
# Check the directory mode, but also make sure the created
739
# directories and files are read-write for this user. This is
740
# mostly a workaround for filesystems which lie about being able to
741
# write to a directory (cygwin & win32)
742
if (st.st_mode & 07777 == 00000):
743
# FTP allows stat but does not return dir/file modes
744
self._dir_mode = None
745
self._file_mode = None
747
self._dir_mode = (st.st_mode & 07777) | 00700
748
# Remove the sticky and execute bits for files
749
self._file_mode = self._dir_mode & ~07111
751
def _get_file_mode(self):
752
"""Return Unix mode for newly created files, or None.
754
if not self._mode_check_done:
755
self._find_creation_modes()
756
return self._file_mode
758
def _get_dir_mode(self):
759
"""Return Unix mode for newly created directories, or None.
761
if not self._mode_check_done:
762
self._find_creation_modes()
763
return self._dir_mode
765
def get_config(self):
766
"""Get configuration for this BzrDir."""
767
return config.BzrDirConfig(self)
769
def _get_config(self):
770
"""By default, no configuration is available."""
441
773
def __init__(self, _transport, _format):
442
774
"""Initialize a Bzr control dir object.
444
776
Only really common logic should reside here, concrete classes should be
445
777
made with varying behaviours.
448
780
:param _transport: the transport this dir is based at.
450
782
self._format = _format
783
# these are also under the more standard names of
784
# control_transport and user_transport
451
785
self.transport = _transport.clone('.bzr')
452
786
self.root_transport = _transport
787
self._mode_check_done = False
790
def user_transport(self):
791
return self.root_transport
794
def control_transport(self):
795
return self.transport
454
797
def is_control_filename(self, filename):
455
798
"""True if filename is the name of a path which is reserved for bzrdir's.
457
800
:param filename: A filename within the root transport of this bzrdir.
459
802
This is true IF and ONLY IF the filename is part of the namespace reserved
460
803
for bzr control dirs. Currently this is the '.bzr' directory in the root
461
of the root_transport. it is expected that plugins will need to extend
462
this in the future - for instance to make bzr talk with svn working
804
of the root_transport.
465
# this might be better on the BzrDirFormat class because it refers to
466
# all the possible bzrdir disk formats.
467
# This method is tested via the workingtree is_control_filename tests-
468
# it was extracted from WorkingTree.is_control_filename. If the methods
469
# contract is extended beyond the current trivial implementation please
806
# this might be better on the BzrDirFormat class because it refers to
807
# all the possible bzrdir disk formats.
808
# This method is tested via the workingtree is_control_filename tests-
809
# it was extracted from WorkingTree.is_control_filename. If the method's
810
# contract is extended beyond the current trivial implementation, please
470
811
# add new tests for it to the appropriate place.
471
812
return filename == '.bzr' or filename.startswith('.bzr/')
473
def needs_format_conversion(self, format=None):
474
"""Return true if this bzrdir needs convert_format run on it.
476
For instance, if the repository format is out of date but the
477
branch and working tree are not, this should return True.
479
:param format: Optional parameter indicating a specific desired
480
format we plan to arrive at.
482
raise NotImplementedError(self.needs_format_conversion)
485
815
def open_unsupported(base):
486
816
"""Open a branch which is not supported."""
487
817
return BzrDir.open(base, _unsupported=True)
490
def open(base, _unsupported=False):
491
"""Open an existing bzrdir, rooted at 'base' (url)
493
_unsupported is a private parameter to the BzrDir class.
820
def open(base, _unsupported=False, possible_transports=None):
821
"""Open an existing bzrdir, rooted at 'base' (url).
823
:param _unsupported: a private parameter to the BzrDir class.
495
t = get_transport(base)
825
t = _mod_transport.get_transport(base, possible_transports)
496
826
return BzrDir.open_from_transport(t, _unsupported=_unsupported)
499
def open_from_transport(transport, _unsupported=False):
829
def open_from_transport(transport, _unsupported=False,
830
_server_formats=True):
500
831
"""Open a bzrdir within a particular directory.
502
833
:param transport: Transport containing the bzrdir.
503
834
:param _unsupported: private.
505
format = BzrDirFormat.find_format(transport)
506
BzrDir._check_supported(format, _unsupported)
836
for hook in BzrDir.hooks['pre_open']:
838
# Keep initial base since 'transport' may be modified while following
840
base = transport.base
841
def find_format(transport):
842
return transport, controldir.ControlDirFormat.find_format(
843
transport, _server_formats=_server_formats)
845
def redirected(transport, e, redirection_notice):
846
redirected_transport = transport._redirected_to(e.source, e.target)
847
if redirected_transport is None:
848
raise errors.NotBranchError(base)
849
note('%s is%s redirected to %s',
850
transport.base, e.permanently, redirected_transport.base)
851
return redirected_transport
854
transport, format = do_catching_redirections(find_format,
857
except errors.TooManyRedirections:
858
raise errors.NotBranchError(base)
860
format.check_support_status(_unsupported)
507
861
return format.open(transport, _found=True)
509
def open_branch(self, unsupported=False):
510
"""Open the branch object at this BzrDir if one is present.
512
If unsupported is True, then no longer supported branch formats can
515
TODO: static convenience version of this?
517
raise NotImplementedError(self.open_branch)
520
def open_containing(url):
864
def open_containing(url, possible_transports=None):
521
865
"""Open an existing branch which contains url.
523
867
:param url: url to search from.
524
868
See open_containing_from_transport for more detail.
526
return BzrDir.open_containing_from_transport(get_transport(url))
870
transport = _mod_transport.get_transport(url, possible_transports)
871
return BzrDir.open_containing_from_transport(transport)
529
874
def open_containing_from_transport(a_transport):
530
"""Open an existing branch which contains a_transport.base
875
"""Open an existing branch which contains a_transport.base.
532
877
This probes for a branch at a_transport, and searches upwards from there.
534
879
Basically we keep looking up until we find the control directory or
535
880
run into the root. If there isn't one, raises NotBranchError.
536
If there is one and it is either an unrecognised format or an unsupported
881
If there is one and it is either an unrecognised format or an unsupported
537
882
format, UnknownFormatError or UnsupportedFormatError are raised.
538
883
If there is one, it is returned, along with the unused portion of url.
540
:return: The BzrDir that contains the path, and a Unicode path
885
:return: The BzrDir that contains the path, and a Unicode path
541
886
for the rest of the URL.
543
888
# this gets the normalised url back. I.e. '.' -> the full path.
548
893
return result, urlutils.unescape(a_transport.relpath(url))
549
894
except errors.NotBranchError, e:
551
new_t = a_transport.clone('..')
897
new_t = a_transport.clone('..')
898
except errors.InvalidURLJoin:
899
# reached the root, whatever that may be
900
raise errors.NotBranchError(path=url)
552
901
if new_t.base == a_transport.base:
553
902
# reached the root, whatever that may be
554
903
raise errors.NotBranchError(path=url)
555
904
a_transport = new_t
557
def open_repository(self, _unsupported=False):
558
"""Open the repository object at this BzrDir if one is present.
560
This will not follow the Branch object pointer - its strictly a direct
561
open facility. Most client code should use open_branch().repository to
564
_unsupported is a private parameter, not part of the api.
565
TODO: static convenience version of this?
567
raise NotImplementedError(self.open_repository)
569
def open_workingtree(self, _unsupported=False):
570
"""Open the workingtree object at this BzrDir if one is present.
572
TODO: static convenience version of this?
574
raise NotImplementedError(self.open_workingtree)
576
def has_branch(self):
577
"""Tell if this bzrdir contains a branch.
579
Note: if you're going to open the branch, you should just go ahead
580
and try, and not ask permission first. (This method just opens the
581
branch and discards it, and that's somewhat expensive.)
907
def open_tree_or_branch(klass, location):
908
"""Return the branch and working tree at a location.
910
If there is no tree at the location, tree will be None.
911
If there is no branch at the location, an exception will be
913
:return: (tree, branch)
915
bzrdir = klass.open(location)
916
return bzrdir._get_tree_branch()
919
def open_containing_tree_or_branch(klass, location):
920
"""Return the branch and working tree contained by a location.
922
Returns (tree, branch, relpath).
923
If there is no tree at containing the location, tree will be None.
924
If there is no branch containing the location, an exception will be
926
relpath is the portion of the path that is contained by the branch.
928
bzrdir, relpath = klass.open_containing(location)
929
tree, branch = bzrdir._get_tree_branch()
930
return tree, branch, relpath
933
def open_containing_tree_branch_or_repository(klass, location):
934
"""Return the working tree, branch and repo contained by a location.
936
Returns (tree, branch, repository, relpath).
937
If there is no tree containing the location, tree will be None.
938
If there is no branch containing the location, branch will be None.
939
If there is no repository containing the location, repository will be
941
relpath is the portion of the path that is contained by the innermost
944
If no tree, branch or repository is found, a NotBranchError is raised.
946
bzrdir, relpath = klass.open_containing(location)
948
tree, branch = bzrdir._get_tree_branch()
586
949
except errors.NotBranchError:
589
def has_workingtree(self):
590
"""Tell if this bzrdir contains a working tree.
592
This will still raise an exception if the bzrdir has a workingtree that
593
is remote & inaccessible.
595
Note: if you're going to open the working tree, you should just go ahead
596
and try, and not ask permission first. (This method just opens the
597
workingtree and discards it, and that's somewhat expensive.)
951
repo = bzrdir.find_repository()
952
return None, None, repo, relpath
953
except (errors.NoRepositoryPresent):
954
raise errors.NotBranchError(location)
955
return tree, branch, branch.repository, relpath
957
def _cloning_metadir(self):
958
"""Produce a metadir suitable for cloning with.
960
:returns: (destination_bzrdir_format, source_repository)
962
result_format = self._format.__class__()
600
self.open_workingtree()
602
except errors.NoWorkingTree:
605
def cloning_metadir(self, basis=None):
606
"""Produce a metadir suitable for cloning with"""
607
def related_repository(bzrdir):
609
branch = bzrdir.open_branch()
610
return branch.repository
965
branch = self.open_branch(ignore_fallbacks=True)
966
source_repository = branch.repository
967
result_format._branch_format = branch._format
611
968
except errors.NotBranchError:
612
969
source_branch = None
613
return bzrdir.open_repository()
614
result_format = self._format.__class__()
617
source_repository = related_repository(self)
618
except errors.NoRepositoryPresent:
621
source_repository = related_repository(self)
622
result_format.repository_format = source_repository._format
623
except errors.NoRepositoryPresent:
627
def sprout(self, url, revision_id=None, basis=None, force_new_repo=False):
628
"""Create a copy of this bzrdir prepared for use as a new line of
631
If urls last component does not exist, it will be created.
633
Attributes related to the identity of the source branch like
634
branch nickname will be cleaned, a working tree is created
635
whether one existed before or not; and a local branch is always
638
if revision_id is not None, then the clone operation may tune
639
itself to download less data.
642
cloning_format = self.cloning_metadir(basis)
643
result = cloning_format.initialize(url)
644
basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
646
source_branch = self.open_branch()
647
source_repository = source_branch.repository
648
except errors.NotBranchError:
651
970
source_repository = self.open_repository()
652
except errors.NoRepositoryPresent:
653
# copy the entire basis one if there is one
654
# but there is no repository.
655
source_repository = basis_repo
660
result_repo = result.find_repository()
661
except errors.NoRepositoryPresent:
663
if source_repository is None and result_repo is not None:
665
elif source_repository is None and result_repo is None:
666
# no repo available, make a new one
667
result.create_repository()
668
elif source_repository is not None and result_repo is None:
669
# have source, and want to make a new target repo
670
# we don't clone the repo because that preserves attributes
671
# like is_shared(), and we have not yet implemented a
672
# repository sprout().
673
result_repo = result.create_repository()
674
if result_repo is not None:
675
# fetch needed content into target.
677
# XXX FIXME RBC 20060214 need tests for this when the basis
679
result_repo.fetch(basis_repo, revision_id=revision_id)
680
if source_repository is not None:
681
result_repo.fetch(source_repository, revision_id=revision_id)
682
if source_branch is not None:
683
source_branch.sprout(result, revision_id=revision_id)
685
result.create_branch()
686
# TODO: jam 20060426 we probably need a test in here in the
687
# case that the newly sprouted branch is a remote one
688
if result_repo is None or result_repo.make_working_trees():
689
wt = result.create_workingtree()
690
if wt.inventory.root is None:
692
wt.set_root_id(self.open_workingtree.get_root_id())
693
except errors.NoWorkingTree:
698
class BzrDirPreSplitOut(BzrDir):
699
"""A common class for the all-in-one formats."""
701
def __init__(self, _transport, _format):
702
"""See BzrDir.__init__."""
703
super(BzrDirPreSplitOut, self).__init__(_transport, _format)
704
assert self._format._lock_class == lockable_files.TransportLock
705
assert self._format._lock_file_name == 'branch-lock'
706
self._control_files = lockable_files.LockableFiles(
707
self.get_branch_transport(None),
708
self._format._lock_file_name,
709
self._format._lock_class)
711
def break_lock(self):
712
"""Pre-splitout bzrdirs do not suffer from stale locks."""
713
raise NotImplementedError(self.break_lock)
715
def clone(self, url, revision_id=None, basis=None, force_new_repo=False):
716
"""See BzrDir.clone()."""
717
from bzrlib.workingtree import WorkingTreeFormat2
719
result = self._format._initialize_for_clone(url)
720
basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
721
self.open_repository().clone(result, revision_id=revision_id, basis=basis_repo)
722
from_branch = self.open_branch()
723
from_branch.clone(result, revision_id=revision_id)
725
self.open_workingtree().clone(result, basis=basis_tree)
726
except errors.NotLocalUrl:
727
# make a new one, this format always has to have one.
729
WorkingTreeFormat2().initialize(result)
730
except errors.NotLocalUrl:
731
# but we cannot do it for remote trees.
732
to_branch = result.open_branch()
733
WorkingTreeFormat2().stub_initialize_remote(to_branch.control_files)
736
def create_branch(self):
737
"""See BzrDir.create_branch."""
738
return self.open_branch()
740
def create_repository(self, shared=False):
741
"""See BzrDir.create_repository."""
743
raise errors.IncompatibleFormat('shared repository', self._format)
744
return self.open_repository()
746
def create_workingtree(self, revision_id=None):
747
"""See BzrDir.create_workingtree."""
748
# this looks buggy but is not -really-
749
# clone and sprout will have set the revision_id
750
# and that will have set it for us, its only
751
# specific uses of create_workingtree in isolation
752
# that can do wonky stuff here, and that only
753
# happens for creating checkouts, which cannot be
754
# done on this format anyway. So - acceptable wart.
755
result = self.open_workingtree()
756
if revision_id is not None:
757
if revision_id == _mod_revision.NULL_REVISION:
758
result.set_parent_ids([])
760
result.set_parent_ids([revision_id])
763
def destroy_workingtree(self):
764
"""See BzrDir.destroy_workingtree."""
765
raise errors.UnsupportedOperation(self.destroy_workingtree, self)
767
def destroy_workingtree_metadata(self):
768
"""See BzrDir.destroy_workingtree_metadata."""
769
raise errors.UnsupportedOperation(self.destroy_workingtree_metadata,
772
def get_branch_transport(self, branch_format):
773
"""See BzrDir.get_branch_transport()."""
774
if branch_format is None:
775
return self.transport
777
branch_format.get_format_string()
778
except NotImplementedError:
779
return self.transport
780
raise errors.IncompatibleFormat(branch_format, self._format)
971
except errors.NoRepositoryPresent:
972
source_repository = None
974
# XXX TODO: This isinstance is here because we have not implemented
975
# the fix recommended in bug # 103195 - to delegate this choice the
977
repo_format = source_repository._format
978
if isinstance(repo_format, remote.RemoteRepositoryFormat):
979
source_repository._ensure_real()
980
repo_format = source_repository._real_repository._format
981
result_format.repository_format = repo_format
983
# TODO: Couldn't we just probe for the format in these cases,
984
# rather than opening the whole tree? It would be a little
985
# faster. mbp 20070401
986
tree = self.open_workingtree(recommend_upgrade=False)
987
except (errors.NoWorkingTree, errors.NotLocalUrl):
988
result_format.workingtree_format = None
990
result_format.workingtree_format = tree._format.__class__()
991
return result_format, source_repository
993
def cloning_metadir(self, require_stacking=False):
994
"""Produce a metadir suitable for cloning or sprouting with.
996
These operations may produce workingtrees (yes, even though they're
997
"cloning" something that doesn't have a tree), so a viable workingtree
998
format must be selected.
1000
:require_stacking: If True, non-stackable formats will be upgraded
1001
to similar stackable formats.
1002
:returns: a BzrDirFormat with all component formats either set
1003
appropriately or set to None if that component should not be
1006
format, repository = self._cloning_metadir()
1007
if format._workingtree_format is None:
1009
if repository is None:
1010
# No repository either
1012
# We have a repository, so set a working tree? (Why? This seems to
1013
# contradict the stated return value in the docstring).
1014
tree_format = repository._format._matchingbzrdir.workingtree_format
1015
format.workingtree_format = tree_format.__class__()
1016
if require_stacking:
1017
format.require_stacking()
1021
def create(cls, base, format=None, possible_transports=None):
1022
"""Create a new BzrDir at the url 'base'.
1024
:param format: If supplied, the format of branch to create. If not
1025
supplied, the default is used.
1026
:param possible_transports: If supplied, a list of transports that
1027
can be reused to share a remote connection.
1029
if cls is not BzrDir:
1030
raise AssertionError("BzrDir.create always creates the"
1031
"default format, not one of %r" % cls)
1032
t = _mod_transport.get_transport(base, possible_transports)
1035
format = controldir.ControlDirFormat.get_default_format()
1036
return format.initialize_on_transport(t)
1038
def get_branch_transport(self, branch_format, name=None):
1039
"""Get the transport for use by branch format in this BzrDir.
1041
Note that bzr dirs that do not support format strings will raise
1042
IncompatibleFormat if the branch format they are given has
1043
a format string, and vice versa.
1045
If branch_format is None, the transport is returned with no
1046
checking. If it is not None, then the returned transport is
1047
guaranteed to point to an existing directory ready for use.
1049
raise NotImplementedError(self.get_branch_transport)
782
1051
def get_repository_transport(self, repository_format):
783
"""See BzrDir.get_repository_transport()."""
784
if repository_format is None:
785
return self.transport
787
repository_format.get_format_string()
788
except NotImplementedError:
789
return self.transport
790
raise errors.IncompatibleFormat(repository_format, self._format)
792
def get_workingtree_transport(self, workingtree_format):
793
"""See BzrDir.get_workingtree_transport()."""
794
if workingtree_format is None:
795
return self.transport
797
workingtree_format.get_format_string()
798
except NotImplementedError:
799
return self.transport
800
raise errors.IncompatibleFormat(workingtree_format, self._format)
802
def needs_format_conversion(self, format=None):
803
"""See BzrDir.needs_format_conversion()."""
804
# if the format is not the same as the system default,
805
# an upgrade is needed.
807
format = BzrDirFormat.get_default_format()
808
return not isinstance(self._format, format.__class__)
810
def open_branch(self, unsupported=False):
811
"""See BzrDir.open_branch."""
812
from bzrlib.branch import BzrBranchFormat4
813
format = BzrBranchFormat4()
814
self._check_supported(format, unsupported)
815
return format.open(self, _found=True)
817
def sprout(self, url, revision_id=None, basis=None, force_new_repo=False):
818
"""See BzrDir.sprout()."""
819
from bzrlib.workingtree import WorkingTreeFormat2
821
result = self._format._initialize_for_clone(url)
822
basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
824
self.open_repository().clone(result, revision_id=revision_id, basis=basis_repo)
825
except errors.NoRepositoryPresent:
828
self.open_branch().sprout(result, revision_id=revision_id)
829
except errors.NotBranchError:
831
# we always want a working tree
832
WorkingTreeFormat2().initialize(result)
836
class BzrDir4(BzrDirPreSplitOut):
837
"""A .bzr version 4 control object.
839
This is a deprecated format and may be removed after sept 2006.
842
def create_repository(self, shared=False):
843
"""See BzrDir.create_repository."""
844
return self._format.repository_format.initialize(self, shared)
846
def needs_format_conversion(self, format=None):
847
"""Format 4 dirs are always in need of conversion."""
850
def open_repository(self):
851
"""See BzrDir.open_repository."""
852
from bzrlib.repository import RepositoryFormat4
853
return RepositoryFormat4().open(self, _found=True)
856
class BzrDir5(BzrDirPreSplitOut):
857
"""A .bzr version 5 control object.
859
This is a deprecated format and may be removed after sept 2006.
862
def open_repository(self):
863
"""See BzrDir.open_repository."""
864
from bzrlib.repository import RepositoryFormat5
865
return RepositoryFormat5().open(self, _found=True)
867
def open_workingtree(self, _unsupported=False):
868
"""See BzrDir.create_workingtree."""
869
from bzrlib.workingtree import WorkingTreeFormat2
870
return WorkingTreeFormat2().open(self, _found=True)
873
class BzrDir6(BzrDirPreSplitOut):
874
"""A .bzr version 6 control object.
876
This is a deprecated format and may be removed after sept 2006.
879
def open_repository(self):
880
"""See BzrDir.open_repository."""
881
from bzrlib.repository import RepositoryFormat6
882
return RepositoryFormat6().open(self, _found=True)
884
def open_workingtree(self, _unsupported=False):
885
"""See BzrDir.create_workingtree."""
886
from bzrlib.workingtree import WorkingTreeFormat2
887
return WorkingTreeFormat2().open(self, _found=True)
1052
"""Get the transport for use by repository format in this BzrDir.
1054
Note that bzr dirs that do not support format strings will raise
1055
IncompatibleFormat if the repository format they are given has
1056
a format string, and vice versa.
1058
If repository_format is None, the transport is returned with no
1059
checking. If it is not None, then the returned transport is
1060
guaranteed to point to an existing directory ready for use.
1062
raise NotImplementedError(self.get_repository_transport)
1064
def get_workingtree_transport(self, tree_format):
1065
"""Get the transport for use by workingtree format in this BzrDir.
1067
Note that bzr dirs that do not support format strings will raise
1068
IncompatibleFormat if the workingtree format they are given has a
1069
format string, and vice versa.
1071
If workingtree_format is None, the transport is returned with no
1072
checking. If it is not None, then the returned transport is
1073
guaranteed to point to an existing directory ready for use.
1075
raise NotImplementedError(self.get_workingtree_transport)
1078
class BzrDirHooks(hooks.Hooks):
1079
"""Hooks for BzrDir operations."""
1082
"""Create the default hooks."""
1083
hooks.Hooks.__init__(self, "bzrlib.bzrdir", "BzrDir.hooks")
1084
self.add_hook('pre_open',
1085
"Invoked before attempting to open a BzrDir with the transport "
1086
"that the open will use.", (1, 14))
1087
self.add_hook('post_repo_init',
1088
"Invoked after a repository has been initialized. "
1089
"post_repo_init is called with a "
1090
"bzrlib.bzrdir.RepoInitHookParams.",
1093
# install the default hooks
1094
BzrDir.hooks = BzrDirHooks()
1097
class RepoInitHookParams(object):
1098
"""Object holding parameters passed to *_repo_init hooks.
1100
There are 4 fields that hooks may wish to access:
1102
:ivar repository: Repository created
1103
:ivar format: Repository format
1104
:ivar bzrdir: The bzrdir for the repository
1105
:ivar shared: The repository is shared
1108
def __init__(self, repository, format, a_bzrdir, shared):
1109
"""Create a group of RepoInitHook parameters.
1111
:param repository: Repository created
1112
:param format: Repository format
1113
:param bzrdir: The bzrdir for the repository
1114
:param shared: The repository is shared
1116
self.repository = repository
1117
self.format = format
1118
self.bzrdir = a_bzrdir
1119
self.shared = shared
1121
def __eq__(self, other):
1122
return self.__dict__ == other.__dict__
1126
return "<%s for %s>" % (self.__class__.__name__,
1129
return "<%s for %s>" % (self.__class__.__name__,
890
1133
class BzrDirMeta1(BzrDir):
891
1134
"""A .bzr meta version 1 control object.
893
This is the first control object where the
1136
This is the first control object where the
894
1137
individual aspects are really split out: there are separate repository,
895
1138
workingtree and branch subdirectories and any subset of the three can be
896
1139
present within a BzrDir.
989
1276
except errors.NoRepositoryPresent:
991
# currently there are no other possible conversions for meta1 formats.
1278
for branch in self.list_branches():
1279
if not isinstance(branch._format,
1280
format.get_branch_format().__class__):
1281
# the branch needs an upgrade.
1284
my_wt = self.open_workingtree(recommend_upgrade=False)
1285
if not isinstance(my_wt._format,
1286
format.workingtree_format.__class__):
1287
# the workingtree needs an upgrade.
1289
except (errors.NoWorkingTree, errors.NotLocalUrl):
994
def open_branch(self, unsupported=False):
1293
def open_branch(self, name=None, unsupported=False,
1294
ignore_fallbacks=False):
995
1295
"""See BzrDir.open_branch."""
996
from bzrlib.branch import BranchFormat
997
format = BranchFormat.find_format(self)
998
self._check_supported(format, unsupported)
999
return format.open(self, _found=True)
1296
format = self.find_branch_format(name=name)
1297
format.check_support_status(unsupported)
1298
return format.open(self, name=name,
1299
_found=True, ignore_fallbacks=ignore_fallbacks)
1001
1301
def open_repository(self, unsupported=False):
1002
1302
"""See BzrDir.open_repository."""
1003
1303
from bzrlib.repository import RepositoryFormat
1004
1304
format = RepositoryFormat.find_format(self)
1005
self._check_supported(format, unsupported)
1305
format.check_support_status(unsupported)
1006
1306
return format.open(self, _found=True)
1008
def open_workingtree(self, unsupported=False):
1308
def open_workingtree(self, unsupported=False,
1309
recommend_upgrade=True):
1009
1310
"""See BzrDir.open_workingtree."""
1010
1311
from bzrlib.workingtree import WorkingTreeFormat
1011
1312
format = WorkingTreeFormat.find_format(self)
1012
self._check_supported(format, unsupported)
1313
format.check_support_status(unsupported, recommend_upgrade,
1314
basedir=self.root_transport.base)
1013
1315
return format.open(self, _found=True)
1016
class BzrDirFormat(object):
1017
"""An encapsulation of the initialization and open routines for a format.
1019
Formats provide three things:
1020
* An initialization routine,
1024
Formats are placed in an dict by their format string for reference
1317
def _get_config(self):
1318
return config.TransportConfig(self.transport, 'control.conf')
1321
class BzrProber(controldir.Prober):
1322
"""Prober for formats that use a .bzr/ control directory."""
1324
formats = registry.FormatRegistry(controldir.network_format_registry)
1325
"""The known .bzr formats."""
1328
@deprecated_method(deprecated_in((2, 4, 0)))
1329
def register_bzrdir_format(klass, format):
1330
klass.formats.register(format.get_format_string(), format)
1333
@deprecated_method(deprecated_in((2, 4, 0)))
1334
def unregister_bzrdir_format(klass, format):
1335
klass.formats.remove(format.get_format_string())
1338
def probe_transport(klass, transport):
1339
"""Return the .bzrdir style format present in a directory."""
1341
format_string = transport.get_bytes(".bzr/branch-format")
1342
except errors.NoSuchFile:
1343
raise errors.NotBranchError(path=transport.base)
1345
return klass.formats.get(format_string)
1347
raise errors.UnknownFormatError(format=format_string, kind='bzrdir')
1350
def known_formats(cls):
1352
for name, format in cls.formats.iteritems():
1353
if callable(format):
1359
controldir.ControlDirFormat.register_prober(BzrProber)
1362
class RemoteBzrProber(controldir.Prober):
1363
"""Prober for remote servers that provide a Bazaar smart server."""
1366
def probe_transport(klass, transport):
1367
"""Return a RemoteBzrDirFormat object if it looks possible."""
1369
medium = transport.get_smart_medium()
1370
except (NotImplementedError, AttributeError,
1371
errors.TransportNotPossible, errors.NoSmartMedium,
1372
errors.SmartProtocolError):
1373
# no smart server, so not a branch for this format type.
1374
raise errors.NotBranchError(path=transport.base)
1376
# Decline to open it if the server doesn't support our required
1377
# version (3) so that the VFS-based transport will do it.
1378
if medium.should_probe():
1380
server_version = medium.protocol_version()
1381
except errors.SmartProtocolError:
1382
# Apparently there's no usable smart server there, even though
1383
# the medium supports the smart protocol.
1384
raise errors.NotBranchError(path=transport.base)
1385
if server_version != '2':
1386
raise errors.NotBranchError(path=transport.base)
1387
from bzrlib.remote import RemoteBzrDirFormat
1388
return RemoteBzrDirFormat()
1391
def known_formats(cls):
1392
from bzrlib.remote import RemoteBzrDirFormat
1393
return set([RemoteBzrDirFormat()])
1396
class BzrDirFormat(controldir.ControlDirFormat):
1397
"""ControlDirFormat base class for .bzr/ directories.
1399
Formats are placed in a dict by their format string for reference
1025
1400
during bzrdir opening. These should be subclasses of BzrDirFormat
1026
1401
for consistency.
1028
1403
Once a format is deprecated, just deprecate the initialize and open
1029
methods on the format class. Do not deprecate the object, as the
1404
methods on the format class. Do not deprecate the object, as the
1030
1405
object will be created every system load.
1033
_default_format = None
1034
"""The default format used for new .bzr dirs."""
1037
"""The known formats."""
1039
_control_formats = []
1040
"""The registered control formats - .bzr, ....
1042
This is a list of BzrDirFormat objects.
1045
1408
_lock_file_name = 'branch-lock'
1047
1410
# _lock_class must be set in subclasses to the lock type, typ.
1048
1411
# TransportLock or LockDir
1051
def find_format(klass, transport):
1052
"""Return the format present at transport."""
1053
for format in klass._control_formats:
1055
return format.probe_transport(transport)
1056
except errors.NotBranchError:
1057
# this format does not find a control dir here.
1059
raise errors.NotBranchError(path=transport.base)
1062
def probe_transport(klass, transport):
1063
"""Return the .bzrdir style transport present at URL."""
1065
format_string = transport.get(".bzr/branch-format").read()
1066
except errors.NoSuchFile:
1067
raise errors.NotBranchError(path=transport.base)
1070
return klass._formats[format_string]
1072
raise errors.UnknownFormatError(format=format_string)
1075
def get_default_format(klass):
1076
"""Return the current default format."""
1077
return klass._default_format
1079
def get_format_string(self):
1414
def get_format_string(cls):
1080
1415
"""Return the ASCII format string that identifies this format."""
1081
1416
raise NotImplementedError(self.get_format_string)
1083
def get_format_description(self):
1084
"""Return the short description for this format."""
1085
raise NotImplementedError(self.get_format_description)
1087
def get_converter(self, format=None):
1088
"""Return the converter to use to convert bzrdirs needing converts.
1090
This returns a bzrlib.bzrdir.Converter object.
1092
This should return the best upgrader to step this format towards the
1093
current default format. In the case of plugins we can/should provide
1094
some means for them to extend the range of returnable converters.
1096
:param format: Optional format to override the default format of the
1099
raise NotImplementedError(self.get_converter)
1101
def initialize(self, url):
1102
"""Create a bzr control dir at this url and return an opened copy.
1104
Subclasses should typically override initialize_on_transport
1105
instead of this method.
1107
return self.initialize_on_transport(get_transport(url))
1109
1418
def initialize_on_transport(self, transport):
1110
1419
"""Initialize a new bzrdir in the base directory of a Transport."""
1111
# Since we don't have a .bzr directory, inherit the
1421
# can we hand off the request to the smart server rather than using
1423
client_medium = transport.get_smart_medium()
1424
except errors.NoSmartMedium:
1425
return self._initialize_on_transport_vfs(transport)
1427
# Current RPC's only know how to create bzr metadir1 instances, so
1428
# we still delegate to vfs methods if the requested format is not a
1430
if type(self) != BzrDirMetaFormat1:
1431
return self._initialize_on_transport_vfs(transport)
1432
from bzrlib.remote import RemoteBzrDirFormat
1433
remote_format = RemoteBzrDirFormat()
1434
self._supply_sub_formats_to(remote_format)
1435
return remote_format.initialize_on_transport(transport)
1437
def initialize_on_transport_ex(self, transport, use_existing_dir=False,
1438
create_prefix=False, force_new_repo=False, stacked_on=None,
1439
stack_on_pwd=None, repo_format_name=None, make_working_trees=None,
1440
shared_repo=False, vfs_only=False):
1441
"""Create this format on transport.
1443
The directory to initialize will be created.
1445
:param force_new_repo: Do not use a shared repository for the target,
1446
even if one is available.
1447
:param create_prefix: Create any missing directories leading up to
1449
:param use_existing_dir: Use an existing directory if one exists.
1450
:param stacked_on: A url to stack any created branch on, None to follow
1451
any target stacking policy.
1452
:param stack_on_pwd: If stack_on is relative, the location it is
1454
:param repo_format_name: If non-None, a repository will be
1455
made-or-found. Should none be found, or if force_new_repo is True
1456
the repo_format_name is used to select the format of repository to
1458
:param make_working_trees: Control the setting of make_working_trees
1459
for a new shared repository when one is made. None to use whatever
1460
default the format has.
1461
:param shared_repo: Control whether made repositories are shared or
1463
:param vfs_only: If True do not attempt to use a smart server
1464
:return: repo, bzrdir, require_stacking, repository_policy. repo is
1465
None if none was created or found, bzrdir is always valid.
1466
require_stacking is the result of examining the stacked_on
1467
parameter and any stacking policy found for the target.
1470
# Try to hand off to a smart server
1472
client_medium = transport.get_smart_medium()
1473
except errors.NoSmartMedium:
1476
from bzrlib.remote import RemoteBzrDirFormat
1477
# TODO: lookup the local format from a server hint.
1478
remote_dir_format = RemoteBzrDirFormat()
1479
remote_dir_format._network_name = self.network_name()
1480
self._supply_sub_formats_to(remote_dir_format)
1481
return remote_dir_format.initialize_on_transport_ex(transport,
1482
use_existing_dir=use_existing_dir, create_prefix=create_prefix,
1483
force_new_repo=force_new_repo, stacked_on=stacked_on,
1484
stack_on_pwd=stack_on_pwd, repo_format_name=repo_format_name,
1485
make_working_trees=make_working_trees, shared_repo=shared_repo)
1486
# XXX: Refactor the create_prefix/no_create_prefix code into a
1487
# common helper function
1488
# The destination may not exist - if so make it according to policy.
1489
def make_directory(transport):
1490
transport.mkdir('.')
1492
def redirected(transport, e, redirection_notice):
1493
note(redirection_notice)
1494
return transport._redirected_to(e.source, e.target)
1496
transport = do_catching_redirections(make_directory, transport,
1498
except errors.FileExists:
1499
if not use_existing_dir:
1501
except errors.NoSuchFile:
1502
if not create_prefix:
1504
transport.create_prefix()
1506
require_stacking = (stacked_on is not None)
1507
# Now the target directory exists, but doesn't have a .bzr
1508
# directory. So we need to create it, along with any work to create
1509
# all of the dependent branches, etc.
1511
result = self.initialize_on_transport(transport)
1512
if repo_format_name:
1514
# use a custom format
1515
result._format.repository_format = \
1516
repository.network_format_registry.get(repo_format_name)
1517
except AttributeError:
1518
# The format didn't permit it to be set.
1520
# A repository is desired, either in-place or shared.
1521
repository_policy = result.determine_repository_policy(
1522
force_new_repo, stacked_on, stack_on_pwd,
1523
require_stacking=require_stacking)
1524
result_repo, is_new_repo = repository_policy.acquire_repository(
1525
make_working_trees, shared_repo)
1526
if not require_stacking and repository_policy._require_stacking:
1527
require_stacking = True
1528
result._format.require_stacking()
1529
result_repo.lock_write()
1532
repository_policy = None
1533
return result_repo, result, require_stacking, repository_policy
1535
def _initialize_on_transport_vfs(self, transport):
1536
"""Initialize a new bzrdir using VFS calls.
1538
:param transport: The transport to create the .bzr directory in.
1541
# Since we are creating a .bzr directory, inherit the
1112
1542
# mode from the root directory
1113
1543
temp_control = lockable_files.LockableFiles(transport,
1114
1544
'', lockable_files.TransportLock)
1191
1595
raise NotImplementedError(self._open)
1194
def register_format(klass, format):
1195
klass._formats[format.get_format_string()] = format
1198
def register_control_format(klass, format):
1199
"""Register a format that does not use '.bzrdir' for its control dir.
1201
TODO: This should be pulled up into a 'ControlDirFormat' base class
1202
which BzrDirFormat can inherit from, and renamed to register_format
1203
there. It has been done without that for now for simplicity of
1206
klass._control_formats.append(format)
1209
def set_default_format(klass, format):
1210
klass._default_format = format
1213
return self.get_format_string()[:-1]
1216
def unregister_format(klass, format):
1217
assert klass._formats[format.get_format_string()] is format
1218
del klass._formats[format.get_format_string()]
1221
def unregister_control_format(klass, format):
1222
klass._control_formats.remove(format)
1225
# register BzrDirFormat as a control format
1226
BzrDirFormat.register_control_format(BzrDirFormat)
1229
class BzrDirFormat4(BzrDirFormat):
1230
"""Bzr dir format 4.
1232
This format is a combined format for working tree, branch and repository.
1234
- Format 1 working trees [always]
1235
- Format 4 branches [always]
1236
- Format 4 repositories [always]
1238
This format is deprecated: it indexes texts using a text it which is
1239
removed in format 5; write support for this format has been removed.
1242
_lock_class = lockable_files.TransportLock
1244
def get_format_string(self):
1245
"""See BzrDirFormat.get_format_string()."""
1246
return "Bazaar-NG branch, format 0.0.4\n"
1248
def get_format_description(self):
1249
"""See BzrDirFormat.get_format_description()."""
1250
return "All-in-one format 4"
1252
def get_converter(self, format=None):
1253
"""See BzrDirFormat.get_converter()."""
1254
# there is one and only one upgrade path here.
1255
return ConvertBzrDir4To5()
1257
def initialize_on_transport(self, transport):
1258
"""Format 4 branches cannot be created."""
1259
raise errors.UninitializableFormat(self)
1261
def is_supported(self):
1262
"""Format 4 is not supported.
1264
It is not supported because the model changed from 4 to 5 and the
1265
conversion logic is expensive - so doing it on the fly was not
1270
def _open(self, transport):
1271
"""See BzrDirFormat._open."""
1272
return BzrDir4(transport, self)
1274
def __return_repository_format(self):
1275
"""Circular import protection."""
1276
from bzrlib.repository import RepositoryFormat4
1277
return RepositoryFormat4()
1278
repository_format = property(__return_repository_format)
1281
class BzrDirFormat5(BzrDirFormat):
1282
"""Bzr control format 5.
1284
This format is a combined format for working tree, branch and repository.
1286
- Format 2 working trees [always]
1287
- Format 4 branches [always]
1288
- Format 5 repositories [always]
1289
Unhashed stores in the repository.
1292
_lock_class = lockable_files.TransportLock
1294
def get_format_string(self):
1295
"""See BzrDirFormat.get_format_string()."""
1296
return "Bazaar-NG branch, format 5\n"
1298
def get_format_description(self):
1299
"""See BzrDirFormat.get_format_description()."""
1300
return "All-in-one format 5"
1302
def get_converter(self, format=None):
1303
"""See BzrDirFormat.get_converter()."""
1304
# there is one and only one upgrade path here.
1305
return ConvertBzrDir5To6()
1307
def _initialize_for_clone(self, url):
1308
return self.initialize_on_transport(get_transport(url), _cloning=True)
1310
def initialize_on_transport(self, transport, _cloning=False):
1311
"""Format 5 dirs always have working tree, branch and repository.
1313
Except when they are being cloned.
1315
from bzrlib.branch import BzrBranchFormat4
1316
from bzrlib.repository import RepositoryFormat5
1317
from bzrlib.workingtree import WorkingTreeFormat2
1318
result = (super(BzrDirFormat5, self).initialize_on_transport(transport))
1319
RepositoryFormat5().initialize(result, _internal=True)
1321
branch = BzrBranchFormat4().initialize(result)
1323
WorkingTreeFormat2().initialize(result)
1324
except errors.NotLocalUrl:
1325
# Even though we can't access the working tree, we need to
1326
# create its control files.
1327
WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
1330
def _open(self, transport):
1331
"""See BzrDirFormat._open."""
1332
return BzrDir5(transport, self)
1334
def __return_repository_format(self):
1335
"""Circular import protection."""
1336
from bzrlib.repository import RepositoryFormat5
1337
return RepositoryFormat5()
1338
repository_format = property(__return_repository_format)
1341
class BzrDirFormat6(BzrDirFormat):
1342
"""Bzr control format 6.
1344
This format is a combined format for working tree, branch and repository.
1346
- Format 2 working trees [always]
1347
- Format 4 branches [always]
1348
- Format 6 repositories [always]
1351
_lock_class = lockable_files.TransportLock
1353
def get_format_string(self):
1354
"""See BzrDirFormat.get_format_string()."""
1355
return "Bazaar-NG branch, format 6\n"
1357
def get_format_description(self):
1358
"""See BzrDirFormat.get_format_description()."""
1359
return "All-in-one format 6"
1361
def get_converter(self, format=None):
1362
"""See BzrDirFormat.get_converter()."""
1363
# there is one and only one upgrade path here.
1364
return ConvertBzrDir6ToMeta()
1366
def _initialize_for_clone(self, url):
1367
return self.initialize_on_transport(get_transport(url), _cloning=True)
1369
def initialize_on_transport(self, transport, _cloning=False):
1370
"""Format 6 dirs always have working tree, branch and repository.
1372
Except when they are being cloned.
1374
from bzrlib.branch import BzrBranchFormat4
1375
from bzrlib.repository import RepositoryFormat6
1376
from bzrlib.workingtree import WorkingTreeFormat2
1377
result = super(BzrDirFormat6, self).initialize_on_transport(transport)
1378
RepositoryFormat6().initialize(result, _internal=True)
1380
branch = BzrBranchFormat4().initialize(result)
1382
WorkingTreeFormat2().initialize(result)
1383
except errors.NotLocalUrl:
1384
# Even though we can't access the working tree, we need to
1385
# create its control files.
1386
WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
1389
def _open(self, transport):
1390
"""See BzrDirFormat._open."""
1391
return BzrDir6(transport, self)
1393
def __return_repository_format(self):
1394
"""Circular import protection."""
1395
from bzrlib.repository import RepositoryFormat6
1396
return RepositoryFormat6()
1397
repository_format = property(__return_repository_format)
1597
def _supply_sub_formats_to(self, other_format):
1598
"""Give other_format the same values for sub formats as this has.
1600
This method is expected to be used when parameterising a
1601
RemoteBzrDirFormat instance with the parameters from a
1602
BzrDirMetaFormat1 instance.
1604
:param other_format: other_format is a format which should be
1605
compatible with whatever sub formats are supported by self.
1400
1610
class BzrDirMetaFormat1(BzrDirFormat):
1411
1621
_lock_class = lockdir.LockDir
1623
fixed_components = False
1626
self._workingtree_format = None
1627
self._branch_format = None
1628
self._repository_format = None
1630
def __eq__(self, other):
1631
if other.__class__ is not self.__class__:
1633
if other.repository_format != self.repository_format:
1635
if other.workingtree_format != self.workingtree_format:
1639
def __ne__(self, other):
1640
return not self == other
1642
def get_branch_format(self):
1643
if self._branch_format is None:
1644
from bzrlib.branch import format_registry as branch_format_registry
1645
self._branch_format = branch_format_registry.get_default()
1646
return self._branch_format
1648
def set_branch_format(self, format):
1649
self._branch_format = format
1651
def require_stacking(self, stack_on=None, possible_transports=None,
1653
"""We have a request to stack, try to ensure the formats support it.
1655
:param stack_on: If supplied, it is the URL to a branch that we want to
1656
stack on. Check to see if that format supports stacking before
1659
# Stacking is desired. requested by the target, but does the place it
1660
# points at support stacking? If it doesn't then we should
1661
# not implicitly upgrade. We check this here.
1662
new_repo_format = None
1663
new_branch_format = None
1665
# a bit of state for get_target_branch so that we don't try to open it
1666
# 2 times, for both repo *and* branch
1667
target = [None, False, None] # target_branch, checked, upgrade anyway
1668
def get_target_branch():
1670
# We've checked, don't check again
1672
if stack_on is None:
1673
# No target format, that means we want to force upgrading
1674
target[:] = [None, True, True]
1677
target_dir = BzrDir.open(stack_on,
1678
possible_transports=possible_transports)
1679
except errors.NotBranchError:
1680
# Nothing there, don't change formats
1681
target[:] = [None, True, False]
1683
except errors.JailBreak:
1684
# JailBreak, JFDI and upgrade anyway
1685
target[:] = [None, True, True]
1688
target_branch = target_dir.open_branch()
1689
except errors.NotBranchError:
1690
# No branch, don't upgrade formats
1691
target[:] = [None, True, False]
1693
target[:] = [target_branch, True, False]
1696
if (not _skip_repo and
1697
not self.repository_format.supports_external_lookups):
1698
# We need to upgrade the Repository.
1699
target_branch, _, do_upgrade = get_target_branch()
1700
if target_branch is None:
1701
# We don't have a target branch, should we upgrade anyway?
1703
# stack_on is inaccessible, JFDI.
1704
# TODO: bad monkey, hard-coded formats...
1705
if self.repository_format.rich_root_data:
1706
new_repo_format = knitpack_repo.RepositoryFormatKnitPack5RichRoot()
1708
new_repo_format = knitpack_repo.RepositoryFormatKnitPack5()
1710
# If the target already supports stacking, then we know the
1711
# project is already able to use stacking, so auto-upgrade
1713
new_repo_format = target_branch.repository._format
1714
if not new_repo_format.supports_external_lookups:
1715
# target doesn't, source doesn't, so don't auto upgrade
1717
new_repo_format = None
1718
if new_repo_format is not None:
1719
self.repository_format = new_repo_format
1720
note('Source repository format does not support stacking,'
1721
' using format:\n %s',
1722
new_repo_format.get_format_description())
1724
if not self.get_branch_format().supports_stacking():
1725
# We just checked the repo, now lets check if we need to
1726
# upgrade the branch format
1727
target_branch, _, do_upgrade = get_target_branch()
1728
if target_branch is None:
1730
# TODO: bad monkey, hard-coded formats...
1731
from bzrlib.branch import BzrBranchFormat7
1732
new_branch_format = BzrBranchFormat7()
1734
new_branch_format = target_branch._format
1735
if not new_branch_format.supports_stacking():
1736
new_branch_format = None
1737
if new_branch_format is not None:
1738
# Does support stacking, use its format.
1739
self.set_branch_format(new_branch_format)
1740
note('Source branch format does not support stacking,'
1741
' using format:\n %s',
1742
new_branch_format.get_format_description())
1413
1744
def get_converter(self, format=None):
1414
1745
"""See BzrDirFormat.get_converter()."""
1415
1746
if format is None:
1427
1759
"""See BzrDirFormat.get_format_description()."""
1428
1760
return "Meta directory format 1"
1762
def network_name(self):
1763
return self.get_format_string()
1430
1765
def _open(self, transport):
1431
1766
"""See BzrDirFormat._open."""
1432
return BzrDirMeta1(transport, self)
1767
# Create a new format instance because otherwise initialisation of new
1768
# metadirs share the global default format object leading to alias
1770
format = BzrDirMetaFormat1()
1771
self._supply_sub_formats_to(format)
1772
return BzrDirMeta1(transport, format)
1434
1774
def __return_repository_format(self):
1435
1775
"""Circular import protection."""
1436
if getattr(self, '_repository_format', None):
1776
if self._repository_format:
1437
1777
return self._repository_format
1438
from bzrlib.repository import RepositoryFormat
1439
return RepositoryFormat.get_default_format()
1778
from bzrlib.repository import format_registry
1779
return format_registry.get_default()
1441
def __set_repository_format(self, value):
1442
"""Allow changint the repository format for metadir formats."""
1781
def _set_repository_format(self, value):
1782
"""Allow changing the repository format for metadir formats."""
1443
1783
self._repository_format = value
1445
repository_format = property(__return_repository_format, __set_repository_format)
1448
BzrDirFormat.register_format(BzrDirFormat4())
1449
BzrDirFormat.register_format(BzrDirFormat5())
1450
BzrDirFormat.register_format(BzrDirFormat6())
1451
__default_format = BzrDirMetaFormat1()
1452
BzrDirFormat.register_format(__default_format)
1453
BzrDirFormat.set_default_format(__default_format)
1456
class BzrDirTestProviderAdapter(object):
1457
"""A tool to generate a suite testing multiple bzrdir formats at once.
1459
This is done by copying the test once for each transport and injecting
1460
the transport_server, transport_readonly_server, and bzrdir_format
1461
classes into each copy. Each copy is also given a new id() to make it
1465
def __init__(self, transport_server, transport_readonly_server, formats):
1466
self._transport_server = transport_server
1467
self._transport_readonly_server = transport_readonly_server
1468
self._formats = formats
1470
def adapt(self, test):
1471
result = unittest.TestSuite()
1472
for format in self._formats:
1473
new_test = deepcopy(test)
1474
new_test.transport_server = self._transport_server
1475
new_test.transport_readonly_server = self._transport_readonly_server
1476
new_test.bzrdir_format = format
1477
def make_new_test_id():
1478
new_id = "%s(%s)" % (new_test.id(), format.__class__.__name__)
1479
return lambda: new_id
1480
new_test.id = make_new_test_id()
1481
result.addTest(new_test)
1485
class Converter(object):
1486
"""Converts a disk format object from one format to another."""
1488
def convert(self, to_convert, pb):
1489
"""Perform the conversion of to_convert, giving feedback via pb.
1491
:param to_convert: The disk object to convert.
1492
:param pb: a progress bar to use for progress information.
1495
def step(self, message):
1496
"""Update the pb by a step."""
1498
self.pb.update(message, self.count, self.total)
1501
class ConvertBzrDir4To5(Converter):
1502
"""Converts format 4 bzr dirs to format 5."""
1505
super(ConvertBzrDir4To5, self).__init__()
1506
self.converted_revs = set()
1507
self.absent_revisions = set()
1511
def convert(self, to_convert, pb):
1512
"""See Converter.convert()."""
1513
self.bzrdir = to_convert
1515
self.pb.note('starting upgrade from format 4 to 5')
1516
if isinstance(self.bzrdir.transport, LocalTransport):
1517
self.bzrdir.get_workingtree_transport(None).delete('stat-cache')
1518
self._convert_to_weaves()
1519
return BzrDir.open(self.bzrdir.root_transport.base)
1521
def _convert_to_weaves(self):
1522
self.pb.note('note: upgrade may be faster if all store files are ungzipped first')
1525
stat = self.bzrdir.transport.stat('weaves')
1526
if not S_ISDIR(stat.st_mode):
1527
self.bzrdir.transport.delete('weaves')
1528
self.bzrdir.transport.mkdir('weaves')
1529
except errors.NoSuchFile:
1530
self.bzrdir.transport.mkdir('weaves')
1531
# deliberately not a WeaveFile as we want to build it up slowly.
1532
self.inv_weave = Weave('inventory')
1533
# holds in-memory weaves for all files
1534
self.text_weaves = {}
1535
self.bzrdir.transport.delete('branch-format')
1536
self.branch = self.bzrdir.open_branch()
1537
self._convert_working_inv()
1538
rev_history = self.branch.revision_history()
1539
# to_read is a stack holding the revisions we still need to process;
1540
# appending to it adds new highest-priority revisions
1541
self.known_revisions = set(rev_history)
1542
self.to_read = rev_history[-1:]
1544
rev_id = self.to_read.pop()
1545
if (rev_id not in self.revisions
1546
and rev_id not in self.absent_revisions):
1547
self._load_one_rev(rev_id)
1549
to_import = self._make_order()
1550
for i, rev_id in enumerate(to_import):
1551
self.pb.update('converting revision', i, len(to_import))
1552
self._convert_one_rev(rev_id)
1554
self._write_all_weaves()
1555
self._write_all_revs()
1556
self.pb.note('upgraded to weaves:')
1557
self.pb.note(' %6d revisions and inventories', len(self.revisions))
1558
self.pb.note(' %6d revisions not present', len(self.absent_revisions))
1559
self.pb.note(' %6d texts', self.text_count)
1560
self._cleanup_spare_files_after_format4()
1561
self.branch.control_files.put_utf8('branch-format', BzrDirFormat5().get_format_string())
1563
def _cleanup_spare_files_after_format4(self):
1564
# FIXME working tree upgrade foo.
1565
for n in 'merged-patches', 'pending-merged-patches':
1567
## assert os.path.getsize(p) == 0
1568
self.bzrdir.transport.delete(n)
1569
except errors.NoSuchFile:
1571
self.bzrdir.transport.delete_tree('inventory-store')
1572
self.bzrdir.transport.delete_tree('text-store')
1574
def _convert_working_inv(self):
1575
inv = xml4.serializer_v4.read_inventory(
1576
self.branch.control_files.get('inventory'))
1577
new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
1578
# FIXME inventory is a working tree change.
1579
self.branch.control_files.put('inventory', StringIO(new_inv_xml))
1581
def _write_all_weaves(self):
1582
controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)
1583
weave_transport = self.bzrdir.transport.clone('weaves')
1584
weaves = WeaveStore(weave_transport, prefixed=False)
1585
transaction = WriteTransaction()
1589
for file_id, file_weave in self.text_weaves.items():
1590
self.pb.update('writing weave', i, len(self.text_weaves))
1591
weaves._put_weave(file_id, file_weave, transaction)
1593
self.pb.update('inventory', 0, 1)
1594
controlweaves._put_weave('inventory', self.inv_weave, transaction)
1595
self.pb.update('inventory', 1, 1)
1599
def _write_all_revs(self):
1600
"""Write all revisions out in new form."""
1601
self.bzrdir.transport.delete_tree('revision-store')
1602
self.bzrdir.transport.mkdir('revision-store')
1603
revision_transport = self.bzrdir.transport.clone('revision-store')
1605
_revision_store = TextRevisionStore(TextStore(revision_transport,
1609
transaction = WriteTransaction()
1610
for i, rev_id in enumerate(self.converted_revs):
1611
self.pb.update('write revision', i, len(self.converted_revs))
1612
_revision_store.add_revision(self.revisions[rev_id], transaction)
1616
def _load_one_rev(self, rev_id):
1617
"""Load a revision object into memory.
1619
Any parents not either loaded or abandoned get queued to be
1621
self.pb.update('loading revision',
1622
len(self.revisions),
1623
len(self.known_revisions))
1624
if not self.branch.repository.has_revision(rev_id):
1626
self.pb.note('revision {%s} not present in branch; '
1627
'will be converted as a ghost',
1629
self.absent_revisions.add(rev_id)
1631
rev = self.branch.repository._revision_store.get_revision(rev_id,
1632
self.branch.repository.get_transaction())
1633
for parent_id in rev.parent_ids:
1634
self.known_revisions.add(parent_id)
1635
self.to_read.append(parent_id)
1636
self.revisions[rev_id] = rev
1638
def _load_old_inventory(self, rev_id):
1639
assert rev_id not in self.converted_revs
1640
old_inv_xml = self.branch.repository.inventory_store.get(rev_id).read()
1641
inv = xml4.serializer_v4.read_inventory_from_string(old_inv_xml)
1642
inv.revision_id = rev_id
1643
rev = self.revisions[rev_id]
1644
if rev.inventory_sha1:
1645
assert rev.inventory_sha1 == sha_string(old_inv_xml), \
1646
'inventory sha mismatch for {%s}' % rev_id
1649
def _load_updated_inventory(self, rev_id):
1650
assert rev_id in self.converted_revs
1651
inv_xml = self.inv_weave.get_text(rev_id)
1652
inv = xml5.serializer_v5.read_inventory_from_string(inv_xml)
1655
def _convert_one_rev(self, rev_id):
1656
"""Convert revision and all referenced objects to new format."""
1657
rev = self.revisions[rev_id]
1658
inv = self._load_old_inventory(rev_id)
1659
present_parents = [p for p in rev.parent_ids
1660
if p not in self.absent_revisions]
1661
self._convert_revision_contents(rev, inv, present_parents)
1662
self._store_new_weave(rev, inv, present_parents)
1663
self.converted_revs.add(rev_id)
1665
def _store_new_weave(self, rev, inv, present_parents):
1666
# the XML is now updated with text versions
1668
entries = inv.iter_entries()
1670
for path, ie in entries:
1671
assert getattr(ie, 'revision', None) is not None, \
1672
'no revision on {%s} in {%s}' % \
1673
(file_id, rev.revision_id)
1674
new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
1675
new_inv_sha1 = sha_string(new_inv_xml)
1676
self.inv_weave.add_lines(rev.revision_id,
1678
new_inv_xml.splitlines(True))
1679
rev.inventory_sha1 = new_inv_sha1
1681
def _convert_revision_contents(self, rev, inv, present_parents):
1682
"""Convert all the files within a revision.
1684
Also upgrade the inventory to refer to the text revision ids."""
1685
rev_id = rev.revision_id
1686
mutter('converting texts of revision {%s}',
1688
parent_invs = map(self._load_updated_inventory, present_parents)
1689
entries = inv.iter_entries()
1691
for path, ie in entries:
1692
self._convert_file_version(rev, ie, parent_invs)
1694
def _convert_file_version(self, rev, ie, parent_invs):
1695
"""Convert one version of one file.
1697
The file needs to be added into the weave if it is a merge
1698
of >=2 parents or if it's changed from its parent.
1700
file_id = ie.file_id
1701
rev_id = rev.revision_id
1702
w = self.text_weaves.get(file_id)
1705
self.text_weaves[file_id] = w
1706
text_changed = False
1707
previous_entries = ie.find_previous_heads(parent_invs,
1711
for old_revision in previous_entries:
1712
# if this fails, its a ghost ?
1713
assert old_revision in self.converted_revs, \
1714
"Revision {%s} not in converted_revs" % old_revision
1715
self.snapshot_ie(previous_entries, ie, w, rev_id)
1717
assert getattr(ie, 'revision', None) is not None
1719
def snapshot_ie(self, previous_revisions, ie, w, rev_id):
1720
# TODO: convert this logic, which is ~= snapshot to
1721
# a call to:. This needs the path figured out. rather than a work_tree
1722
# a v4 revision_tree can be given, or something that looks enough like
1723
# one to give the file content to the entry if it needs it.
1724
# and we need something that looks like a weave store for snapshot to
1726
#ie.snapshot(rev, PATH, previous_revisions, REVISION_TREE, InMemoryWeaveStore(self.text_weaves))
1727
if len(previous_revisions) == 1:
1728
previous_ie = previous_revisions.values()[0]
1729
if ie._unchanged(previous_ie):
1730
ie.revision = previous_ie.revision
1733
text = self.branch.repository.text_store.get(ie.text_id)
1734
file_lines = text.readlines()
1735
assert sha_strings(file_lines) == ie.text_sha1
1736
assert sum(map(len, file_lines)) == ie.text_size
1737
w.add_lines(rev_id, previous_revisions, file_lines)
1738
self.text_count += 1
1740
w.add_lines(rev_id, previous_revisions, [])
1741
ie.revision = rev_id
1743
def _make_order(self):
1744
"""Return a suitable order for importing revisions.
1746
The order must be such that an revision is imported after all
1747
its (present) parents.
1749
todo = set(self.revisions.keys())
1750
done = self.absent_revisions.copy()
1753
# scan through looking for a revision whose parents
1755
for rev_id in sorted(list(todo)):
1756
rev = self.revisions[rev_id]
1757
parent_ids = set(rev.parent_ids)
1758
if parent_ids.issubset(done):
1759
# can take this one now
1760
order.append(rev_id)
1766
class ConvertBzrDir5To6(Converter):
1767
"""Converts format 5 bzr dirs to format 6."""
1769
def convert(self, to_convert, pb):
1770
"""See Converter.convert()."""
1771
self.bzrdir = to_convert
1773
self.pb.note('starting upgrade from format 5 to 6')
1774
self._convert_to_prefixed()
1775
return BzrDir.open(self.bzrdir.root_transport.base)
1777
def _convert_to_prefixed(self):
1778
from bzrlib.store import TransportStore
1779
self.bzrdir.transport.delete('branch-format')
1780
for store_name in ["weaves", "revision-store"]:
1781
self.pb.note("adding prefixes to %s" % store_name)
1782
store_transport = self.bzrdir.transport.clone(store_name)
1783
store = TransportStore(store_transport, prefixed=True)
1784
for urlfilename in store_transport.list_dir('.'):
1785
filename = urlutils.unescape(urlfilename)
1786
if (filename.endswith(".weave") or
1787
filename.endswith(".gz") or
1788
filename.endswith(".sig")):
1789
file_id = os.path.splitext(filename)[0]
1792
prefix_dir = store.hash_prefix(file_id)
1793
# FIXME keep track of the dirs made RBC 20060121
1795
store_transport.move(filename, prefix_dir + '/' + filename)
1796
except errors.NoSuchFile: # catches missing dirs strangely enough
1797
store_transport.mkdir(prefix_dir)
1798
store_transport.move(filename, prefix_dir + '/' + filename)
1799
self.bzrdir._control_files.put_utf8('branch-format', BzrDirFormat6().get_format_string())
1802
class ConvertBzrDir6ToMeta(Converter):
1803
"""Converts format 6 bzr dirs to metadirs."""
1805
def convert(self, to_convert, pb):
1806
"""See Converter.convert()."""
1807
from bzrlib.branch import BzrBranchFormat5
1808
self.bzrdir = to_convert
1811
self.total = 20 # the steps we know about
1812
self.garbage_inventories = []
1814
self.pb.note('starting upgrade from format 6 to metadir')
1815
self.bzrdir._control_files.put_utf8('branch-format', "Converting to format 6")
1816
# its faster to move specific files around than to open and use the apis...
1817
# first off, nuke ancestry.weave, it was never used.
1819
self.step('Removing ancestry.weave')
1820
self.bzrdir.transport.delete('ancestry.weave')
1821
except errors.NoSuchFile:
1823
# find out whats there
1824
self.step('Finding branch files')
1825
last_revision = self.bzrdir.open_branch().last_revision()
1826
bzrcontents = self.bzrdir.transport.list_dir('.')
1827
for name in bzrcontents:
1828
if name.startswith('basis-inventory.'):
1829
self.garbage_inventories.append(name)
1830
# create new directories for repository, working tree and branch
1831
self.dir_mode = self.bzrdir._control_files._dir_mode
1832
self.file_mode = self.bzrdir._control_files._file_mode
1833
repository_names = [('inventory.weave', True),
1834
('revision-store', True),
1836
self.step('Upgrading repository ')
1837
self.bzrdir.transport.mkdir('repository', mode=self.dir_mode)
1838
self.make_lock('repository')
1839
# we hard code the formats here because we are converting into
1840
# the meta format. The meta format upgrader can take this to a
1841
# future format within each component.
1842
self.put_format('repository', _mod_repository.RepositoryFormat7())
1843
for entry in repository_names:
1844
self.move_entry('repository', entry)
1846
self.step('Upgrading branch ')
1847
self.bzrdir.transport.mkdir('branch', mode=self.dir_mode)
1848
self.make_lock('branch')
1849
self.put_format('branch', BzrBranchFormat5())
1850
branch_files = [('revision-history', True),
1851
('branch-name', True),
1853
for entry in branch_files:
1854
self.move_entry('branch', entry)
1856
checkout_files = [('pending-merges', True),
1857
('inventory', True),
1858
('stat-cache', False)]
1859
# If a mandatory checkout file is not present, the branch does not have
1860
# a functional checkout. Do not create a checkout in the converted
1862
for name, mandatory in checkout_files:
1863
if mandatory and name not in bzrcontents:
1864
has_checkout = False
1868
if not has_checkout:
1869
self.pb.note('No working tree.')
1870
# If some checkout files are there, we may as well get rid of them.
1871
for name, mandatory in checkout_files:
1872
if name in bzrcontents:
1873
self.bzrdir.transport.delete(name)
1875
from bzrlib.workingtree import WorkingTreeFormat3
1876
self.step('Upgrading working tree')
1877
self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
1878
self.make_lock('checkout')
1880
'checkout', WorkingTreeFormat3())
1881
self.bzrdir.transport.delete_multi(
1882
self.garbage_inventories, self.pb)
1883
for entry in checkout_files:
1884
self.move_entry('checkout', entry)
1885
if last_revision is not None:
1886
self.bzrdir._control_files.put_utf8(
1887
'checkout/last-revision', last_revision)
1888
self.bzrdir._control_files.put_utf8(
1889
'branch-format', BzrDirMetaFormat1().get_format_string())
1890
return BzrDir.open(self.bzrdir.root_transport.base)
1892
def make_lock(self, name):
1893
"""Make a lock for the new control dir name."""
1894
self.step('Make %s lock' % name)
1895
ld = lockdir.LockDir(self.bzrdir.transport,
1897
file_modebits=self.file_mode,
1898
dir_modebits=self.dir_mode)
1901
def move_entry(self, new_dir, entry):
1902
"""Move then entry name into new_dir."""
1904
mandatory = entry[1]
1905
self.step('Moving %s' % name)
1907
self.bzrdir.transport.move(name, '%s/%s' % (new_dir, name))
1908
except errors.NoSuchFile:
1912
def put_format(self, dirname, format):
1913
self.bzrdir._control_files.put_utf8('%s/format' % dirname, format.get_format_string())
1916
class ConvertMetaToMeta(Converter):
1785
repository_format = property(__return_repository_format,
1786
_set_repository_format)
1788
def _supply_sub_formats_to(self, other_format):
1789
"""Give other_format the same values for sub formats as this has.
1791
This method is expected to be used when parameterising a
1792
RemoteBzrDirFormat instance with the parameters from a
1793
BzrDirMetaFormat1 instance.
1795
:param other_format: other_format is a format which should be
1796
compatible with whatever sub formats are supported by self.
1799
if getattr(self, '_repository_format', None) is not None:
1800
other_format.repository_format = self.repository_format
1801
if self._branch_format is not None:
1802
other_format._branch_format = self._branch_format
1803
if self._workingtree_format is not None:
1804
other_format.workingtree_format = self.workingtree_format
1806
def __get_workingtree_format(self):
1807
if self._workingtree_format is None:
1808
from bzrlib.workingtree import (
1809
format_registry as wt_format_registry,
1811
self._workingtree_format = wt_format_registry.get_default()
1812
return self._workingtree_format
1814
def __set_workingtree_format(self, wt_format):
1815
self._workingtree_format = wt_format
1817
workingtree_format = property(__get_workingtree_format,
1818
__set_workingtree_format)
1821
# Register bzr formats
1822
BzrProber.formats.register(BzrDirMetaFormat1.get_format_string(),
1824
controldir.ControlDirFormat._default_format = BzrDirMetaFormat1()
1827
class ConvertMetaToMeta(controldir.Converter):
1917
1828
"""Converts the components of metadirs."""
1919
1830
def __init__(self, target_format):
1938
1849
if not isinstance(repo._format, self.target_format.repository_format.__class__):
1939
1850
from bzrlib.repository import CopyConverter
1940
self.pb.note('starting repository conversion')
1851
ui.ui_factory.note('starting repository conversion')
1941
1852
converter = CopyConverter(self.target_format.repository_format)
1942
1853
converter.convert(repo, pb)
1854
for branch in self.bzrdir.list_branches():
1855
# TODO: conversions of Branch and Tree should be done by
1856
# InterXFormat lookups/some sort of registry.
1857
# Avoid circular imports
1858
old = branch._format.__class__
1859
new = self.target_format.get_branch_format().__class__
1861
if (old == _mod_branch.BzrBranchFormat5 and
1862
new in (_mod_branch.BzrBranchFormat6,
1863
_mod_branch.BzrBranchFormat7,
1864
_mod_branch.BzrBranchFormat8)):
1865
branch_converter = _mod_branch.Converter5to6()
1866
elif (old == _mod_branch.BzrBranchFormat6 and
1867
new in (_mod_branch.BzrBranchFormat7,
1868
_mod_branch.BzrBranchFormat8)):
1869
branch_converter = _mod_branch.Converter6to7()
1870
elif (old == _mod_branch.BzrBranchFormat7 and
1871
new is _mod_branch.BzrBranchFormat8):
1872
branch_converter = _mod_branch.Converter7to8()
1874
raise errors.BadConversionTarget("No converter", new,
1876
branch_converter.convert(branch)
1877
branch = self.bzrdir.open_branch()
1878
old = branch._format.__class__
1880
tree = self.bzrdir.open_workingtree(recommend_upgrade=False)
1881
except (errors.NoWorkingTree, errors.NotLocalUrl):
1884
# TODO: conversions of Branch and Tree should be done by
1885
# InterXFormat lookups
1886
if (isinstance(tree, workingtree.WorkingTree3) and
1887
not isinstance(tree, workingtree_4.DirStateWorkingTree) and
1888
isinstance(self.target_format.workingtree_format,
1889
workingtree_4.DirStateWorkingTreeFormat)):
1890
workingtree_4.Converter3to4().convert(tree)
1891
if (isinstance(tree, workingtree_4.DirStateWorkingTree) and
1892
not isinstance(tree, workingtree_4.WorkingTree5) and
1893
isinstance(self.target_format.workingtree_format,
1894
workingtree_4.WorkingTreeFormat5)):
1895
workingtree_4.Converter4to5().convert(tree)
1896
if (isinstance(tree, workingtree_4.DirStateWorkingTree) and
1897
not isinstance(tree, workingtree_4.WorkingTree6) and
1898
isinstance(self.target_format.workingtree_format,
1899
workingtree_4.WorkingTreeFormat6)):
1900
workingtree_4.Converter4or5to6().convert(tree)
1943
1902
return to_convert
1905
controldir.ControlDirFormat.register_server_prober(RemoteBzrProber)
1908
class RepositoryAcquisitionPolicy(object):
1909
"""Abstract base class for repository acquisition policies.
1911
A repository acquisition policy decides how a BzrDir acquires a repository
1912
for a branch that is being created. The most basic policy decision is
1913
whether to create a new repository or use an existing one.
1915
def __init__(self, stack_on, stack_on_pwd, require_stacking):
1918
:param stack_on: A location to stack on
1919
:param stack_on_pwd: If stack_on is relative, the location it is
1921
:param require_stacking: If True, it is a failure to not stack.
1923
self._stack_on = stack_on
1924
self._stack_on_pwd = stack_on_pwd
1925
self._require_stacking = require_stacking
1927
def configure_branch(self, branch):
1928
"""Apply any configuration data from this policy to the branch.
1930
Default implementation sets repository stacking.
1932
if self._stack_on is None:
1934
if self._stack_on_pwd is None:
1935
stack_on = self._stack_on
1938
stack_on = urlutils.rebase_url(self._stack_on,
1941
except errors.InvalidRebaseURLs:
1942
stack_on = self._get_full_stack_on()
1944
branch.set_stacked_on_url(stack_on)
1945
except (errors.UnstackableBranchFormat,
1946
errors.UnstackableRepositoryFormat):
1947
if self._require_stacking:
1950
def requires_stacking(self):
1951
"""Return True if this policy requires stacking."""
1952
return self._stack_on is not None and self._require_stacking
1954
def _get_full_stack_on(self):
1955
"""Get a fully-qualified URL for the stack_on location."""
1956
if self._stack_on is None:
1958
if self._stack_on_pwd is None:
1959
return self._stack_on
1961
return urlutils.join(self._stack_on_pwd, self._stack_on)
1963
def _add_fallback(self, repository, possible_transports=None):
1964
"""Add a fallback to the supplied repository, if stacking is set."""
1965
stack_on = self._get_full_stack_on()
1966
if stack_on is None:
1969
stacked_dir = BzrDir.open(stack_on,
1970
possible_transports=possible_transports)
1971
except errors.JailBreak:
1972
# We keep the stacking details, but we are in the server code so
1973
# actually stacking is not needed.
1976
stacked_repo = stacked_dir.open_branch().repository
1977
except errors.NotBranchError:
1978
stacked_repo = stacked_dir.open_repository()
1980
repository.add_fallback_repository(stacked_repo)
1981
except errors.UnstackableRepositoryFormat:
1982
if self._require_stacking:
1985
self._require_stacking = True
1987
def acquire_repository(self, make_working_trees=None, shared=False):
1988
"""Acquire a repository for this bzrdir.
1990
Implementations may create a new repository or use a pre-exising
1992
:param make_working_trees: If creating a repository, set
1993
make_working_trees to this value (if non-None)
1994
:param shared: If creating a repository, make it shared if True
1995
:return: A repository, is_new_flag (True if the repository was
1998
raise NotImplemented(RepositoryAcquisitionPolicy.acquire_repository)
2001
class CreateRepository(RepositoryAcquisitionPolicy):
2002
"""A policy of creating a new repository"""
2004
def __init__(self, bzrdir, stack_on=None, stack_on_pwd=None,
2005
require_stacking=False):
2008
:param bzrdir: The bzrdir to create the repository on.
2009
:param stack_on: A location to stack on
2010
:param stack_on_pwd: If stack_on is relative, the location it is
2013
RepositoryAcquisitionPolicy.__init__(self, stack_on, stack_on_pwd,
2015
self._bzrdir = bzrdir
2017
def acquire_repository(self, make_working_trees=None, shared=False):
2018
"""Implementation of RepositoryAcquisitionPolicy.acquire_repository
2020
Creates the desired repository in the bzrdir we already have.
2022
stack_on = self._get_full_stack_on()
2024
format = self._bzrdir._format
2025
format.require_stacking(stack_on=stack_on,
2026
possible_transports=[self._bzrdir.root_transport])
2027
if not self._require_stacking:
2028
# We have picked up automatic stacking somewhere.
2029
note('Using default stacking branch %s at %s', self._stack_on,
2031
repository = self._bzrdir.create_repository(shared=shared)
2032
self._add_fallback(repository,
2033
possible_transports=[self._bzrdir.transport])
2034
if make_working_trees is not None:
2035
repository.set_make_working_trees(make_working_trees)
2036
return repository, True
2039
class UseExistingRepository(RepositoryAcquisitionPolicy):
2040
"""A policy of reusing an existing repository"""
2042
def __init__(self, repository, stack_on=None, stack_on_pwd=None,
2043
require_stacking=False):
2046
:param repository: The repository to use.
2047
:param stack_on: A location to stack on
2048
:param stack_on_pwd: If stack_on is relative, the location it is
2051
RepositoryAcquisitionPolicy.__init__(self, stack_on, stack_on_pwd,
2053
self._repository = repository
2055
def acquire_repository(self, make_working_trees=None, shared=False):
2056
"""Implementation of RepositoryAcquisitionPolicy.acquire_repository
2058
Returns an existing repository to use.
2060
self._add_fallback(self._repository,
2061
possible_transports=[self._repository.bzrdir.transport])
2062
return self._repository, False
2065
def register_metadir(registry, key,
2066
repository_format, help, native=True, deprecated=False,
2072
"""Register a metadir subformat.
2074
These all use a BzrDirMetaFormat1 bzrdir, but can be parameterized
2075
by the Repository/Branch/WorkingTreeformats.
2077
:param repository_format: The fully-qualified repository format class
2079
:param branch_format: Fully-qualified branch format class name as
2081
:param tree_format: Fully-qualified tree format class name as
2084
# This should be expanded to support setting WorkingTree and Branch
2085
# formats, once BzrDirMetaFormat1 supports that.
2086
def _load(full_name):
2087
mod_name, factory_name = full_name.rsplit('.', 1)
2089
factory = pyutils.get_named_object(mod_name, factory_name)
2090
except ImportError, e:
2091
raise ImportError('failed to load %s: %s' % (full_name, e))
2092
except AttributeError:
2093
raise AttributeError('no factory %s in module %r'
2094
% (full_name, sys.modules[mod_name]))
2098
bd = BzrDirMetaFormat1()
2099
if branch_format is not None:
2100
bd.set_branch_format(_load(branch_format))
2101
if tree_format is not None:
2102
bd.workingtree_format = _load(tree_format)
2103
if repository_format is not None:
2104
bd.repository_format = _load(repository_format)
2106
registry.register(key, helper, help, native, deprecated, hidden,
2107
experimental, alias)
2109
register_metadir(controldir.format_registry, 'knit',
2110
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2111
'Format using knits. Recommended for interoperation with bzr <= 0.14.',
2112
branch_format='bzrlib.branch.BzrBranchFormat5',
2113
tree_format='bzrlib.workingtree.WorkingTreeFormat3',
2116
register_metadir(controldir.format_registry, 'dirstate',
2117
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2118
help='New in 0.15: Fast local operations. Compatible with bzr 0.8 and '
2119
'above when accessed over the network.',
2120
branch_format='bzrlib.branch.BzrBranchFormat5',
2121
tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2124
register_metadir(controldir.format_registry, 'dirstate-tags',
2125
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2126
help='New in 0.15: Fast local operations and improved scaling for '
2127
'network operations. Additionally adds support for tags.'
2128
' Incompatible with bzr < 0.15.',
2129
branch_format='bzrlib.branch.BzrBranchFormat6',
2130
tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2133
register_metadir(controldir.format_registry, 'rich-root',
2134
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit4',
2135
help='New in 1.0. Better handling of tree roots. Incompatible with'
2137
branch_format='bzrlib.branch.BzrBranchFormat6',
2138
tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2141
register_metadir(controldir.format_registry, 'dirstate-with-subtree',
2142
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
2143
help='New in 0.15: Fast local operations and improved scaling for '
2144
'network operations. Additionally adds support for versioning nested '
2145
'bzr branches. Incompatible with bzr < 0.15.',
2146
branch_format='bzrlib.branch.BzrBranchFormat6',
2147
tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2151
register_metadir(controldir.format_registry, 'pack-0.92',
2152
'bzrlib.repofmt.knitpack_repo.RepositoryFormatKnitPack1',
2153
help='New in 0.92: Pack-based format with data compatible with '
2154
'dirstate-tags format repositories. Interoperates with '
2155
'bzr repositories before 0.92 but cannot be read by bzr < 0.92. '
2157
branch_format='bzrlib.branch.BzrBranchFormat6',
2158
tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2160
register_metadir(controldir.format_registry, 'pack-0.92-subtree',
2161
'bzrlib.repofmt.knitpack_repo.RepositoryFormatKnitPack3',
2162
help='New in 0.92: Pack-based format with data compatible with '
2163
'dirstate-with-subtree format repositories. Interoperates with '
2164
'bzr repositories before 0.92 but cannot be read by bzr < 0.92. '
2166
branch_format='bzrlib.branch.BzrBranchFormat6',
2167
tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2171
register_metadir(controldir.format_registry, 'rich-root-pack',
2172
'bzrlib.repofmt.knitpack_repo.RepositoryFormatKnitPack4',
2173
help='New in 1.0: A variant of pack-0.92 that supports rich-root data '
2174
'(needed for bzr-svn and bzr-git).',
2175
branch_format='bzrlib.branch.BzrBranchFormat6',
2176
tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2179
register_metadir(controldir.format_registry, '1.6',
2180
'bzrlib.repofmt.knitpack_repo.RepositoryFormatKnitPack5',
2181
help='A format that allows a branch to indicate that there is another '
2182
'(stacked) repository that should be used to access data that is '
2183
'not present locally.',
2184
branch_format='bzrlib.branch.BzrBranchFormat7',
2185
tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2188
register_metadir(controldir.format_registry, '1.6.1-rich-root',
2189
'bzrlib.repofmt.knitpack_repo.RepositoryFormatKnitPack5RichRoot',
2190
help='A variant of 1.6 that supports rich-root data '
2191
'(needed for bzr-svn and bzr-git).',
2192
branch_format='bzrlib.branch.BzrBranchFormat7',
2193
tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2196
register_metadir(controldir.format_registry, '1.9',
2197
'bzrlib.repofmt.knitpack_repo.RepositoryFormatKnitPack6',
2198
help='A repository format using B+tree indexes. These indexes '
2199
'are smaller in size, have smarter caching and provide faster '
2200
'performance for most operations.',
2201
branch_format='bzrlib.branch.BzrBranchFormat7',
2202
tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2205
register_metadir(controldir.format_registry, '1.9-rich-root',
2206
'bzrlib.repofmt.knitpack_repo.RepositoryFormatKnitPack6RichRoot',
2207
help='A variant of 1.9 that supports rich-root data '
2208
'(needed for bzr-svn and bzr-git).',
2209
branch_format='bzrlib.branch.BzrBranchFormat7',
2210
tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2213
register_metadir(controldir.format_registry, '1.14',
2214
'bzrlib.repofmt.knitpack_repo.RepositoryFormatKnitPack6',
2215
help='A working-tree format that supports content filtering.',
2216
branch_format='bzrlib.branch.BzrBranchFormat7',
2217
tree_format='bzrlib.workingtree_4.WorkingTreeFormat5',
2219
register_metadir(controldir.format_registry, '1.14-rich-root',
2220
'bzrlib.repofmt.knitpack_repo.RepositoryFormatKnitPack6RichRoot',
2221
help='A variant of 1.14 that supports rich-root data '
2222
'(needed for bzr-svn and bzr-git).',
2223
branch_format='bzrlib.branch.BzrBranchFormat7',
2224
tree_format='bzrlib.workingtree_4.WorkingTreeFormat5',
2226
# The following un-numbered 'development' formats should always just be aliases.
2227
register_metadir(controldir.format_registry, 'development-subtree',
2228
'bzrlib.repofmt.groupcompress_repo.RepositoryFormat2aSubtree',
2229
help='Current development format, subtree variant. Can convert data to and '
2230
'from pack-0.92-subtree (and anything compatible with '
2231
'pack-0.92-subtree) format repositories. Repositories and branches in '
2232
'this format can only be read by bzr.dev. Please read '
2233
'http://doc.bazaar.canonical.com/latest/developers/development-repo.html '
2235
branch_format='bzrlib.branch.BzrBranchFormat7',
2236
tree_format='bzrlib.workingtree_4.WorkingTreeFormat6',
2239
alias=False, # Restore to being an alias when an actual development subtree format is added
2240
# This current non-alias status is simply because we did not introduce a
2241
# chk based subtree format.
2243
register_metadir(controldir.format_registry, 'development5-subtree',
2244
'bzrlib.repofmt.knitpack_repo.RepositoryFormatPackDevelopment2Subtree',
2245
help='Development format, subtree variant. Can convert data to and '
2246
'from pack-0.92-subtree (and anything compatible with '
2247
'pack-0.92-subtree) format repositories. Repositories and branches in '
2248
'this format can only be read by bzr.dev. Please read '
2249
'http://doc.bazaar.canonical.com/latest/developers/development-repo.html '
2251
branch_format='bzrlib.branch.BzrBranchFormat7',
2252
tree_format='bzrlib.workingtree_4.WorkingTreeFormat6',
2258
# And the development formats above will have aliased one of the following:
2260
# Finally, the current format.
2261
register_metadir(controldir.format_registry, '2a',
2262
'bzrlib.repofmt.groupcompress_repo.RepositoryFormat2a',
2263
help='First format for bzr 2.0 series.\n'
2264
'Uses group-compress storage.\n'
2265
'Provides rich roots which are a one-way transition.\n',
2266
# 'storage in packs, 255-way hashed CHK inventory, bencode revision, group compress, '
2267
# 'rich roots. Supported by bzr 1.16 and later.',
2268
branch_format='bzrlib.branch.BzrBranchFormat7',
2269
tree_format='bzrlib.workingtree_4.WorkingTreeFormat6',
2273
# The following format should be an alias for the rich root equivalent
2274
# of the default format
2275
register_metadir(controldir.format_registry, 'default-rich-root',
2276
'bzrlib.repofmt.groupcompress_repo.RepositoryFormat2a',
2277
branch_format='bzrlib.branch.BzrBranchFormat7',
2278
tree_format='bzrlib.workingtree_4.WorkingTreeFormat6',
2283
# The current format that is made on 'bzr init'.
2284
format_name = config.GlobalConfig().get_user_option('default_format')
2285
if format_name is None:
2286
controldir.format_registry.set_default('2a')
2288
controldir.format_registry.set_default(format_name)
2290
# XXX 2010-08-20 JRV: There is still a lot of code relying on
2291
# bzrlib.bzrdir.format_registry existing. When BzrDir.create/BzrDir.open/etc
2292
# get changed to ControlDir.create/ControlDir.open/etc this should be removed.
2293
format_registry = controldir.format_registry