112
90
thing_to_unlock.break_lock()
92
def can_convert_format(self):
93
"""Return true if this bzrdir is one whose format we can convert from."""
114
96
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.
118
97
target_repo_format = target_format.repository_format
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
98
source_repo_format = self._format.repository_format
99
source_repo_format.check_conversion_target(target_repo_format)
102
def _check_supported(format, allow_unsupported):
103
"""Check whether format is a supported format.
105
If allow_unsupported is True, this is a no-op.
107
if not allow_unsupported and not format.is_supported():
108
# see open_downlevel to open legacy branches.
109
raise errors.UnsupportedFormatError(format=format)
111
def clone(self, url, revision_id=None, basis=None, force_new_repo=False):
112
"""Clone this bzrdir and its contents to url verbatim.
114
If urls last component does not exist, it will be created.
116
if revision_id is not None, then the clone operation may tune
135
117
itself to download less data.
136
:param force_new_repo: Do not use a shared repository for the target,
118
:param force_new_repo: Do not use a shared repository for the target
137
119
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.
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:
122
basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
123
result = self._format.initialize(url)
155
125
local_repo = self.find_repository()
156
126
except errors.NoRepositoryPresent:
157
127
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,
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)
129
# may need to copy content in
131
result_repo = local_repo.clone(
133
revision_id=revision_id,
135
result_repo.set_make_working_trees(local_repo.make_working_trees())
138
result_repo = result.find_repository()
139
# fetch content this dir needs.
141
# XXX FIXME RBC 20060214 need tests for this when the basis
143
result_repo.fetch(basis_repo, revision_id=revision_id)
207
144
result_repo.fetch(local_repo, revision_id=revision_id)
211
if result_repo is not None:
212
raise AssertionError('result_repo not None(%r)' % result_repo)
145
except errors.NoRepositoryPresent:
146
# needed to make one anyway.
147
result_repo = local_repo.clone(
149
revision_id=revision_id,
151
result_repo.set_make_working_trees(local_repo.make_working_trees())
213
152
# 1 if there is a branch present
214
153
# make sure its content is available in the target repository
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)
156
self.open_branch().clone(result, revision_id=revision_id)
157
except errors.NotBranchError:
160
self.open_workingtree().clone(result, basis=basis_tree)
225
161
except (errors.NoWorkingTree, errors.NotLocalUrl):
165
def _get_basis_components(self, basis):
166
"""Retrieve the basis components that are available at basis."""
168
return None, None, None
170
basis_tree = basis.open_workingtree()
171
basis_branch = basis_tree.branch
172
basis_repo = basis_branch.repository
173
except (errors.NoWorkingTree, errors.NotLocalUrl):
176
basis_branch = basis.open_branch()
177
basis_repo = basis_branch.repository
178
except errors.NotBranchError:
181
basis_repo = basis.open_repository()
182
except errors.NoRepositoryPresent:
184
return basis_repo, basis_branch, basis_tree
229
186
# TODO: This should be given a Transport, and should chdir up; otherwise
230
187
# this will open a new connection.
231
188
def _make_tail(self, url):
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):
189
head, tail = urlutils.split(url)
190
if tail and tail != '.':
191
t = bzrlib.transport.get_transport(head)
194
except errors.FileExists:
197
# TODO: Should take a Transport
199
def create(cls, base):
200
"""Create a new BzrDir at the url 'base'.
202
This will call the current default formats initialize with base
203
as the only parameter.
205
If you need a specific format, consider creating an instance
206
of that and calling initialize().
208
if cls is not BzrDir:
209
raise AssertionError("BzrDir.create always creates the default format, "
210
"not one of %r" % cls)
211
head, tail = urlutils.split(base)
212
if tail and tail != '.':
213
t = bzrlib.transport.get_transport(head)
216
except errors.FileExists:
218
return BzrDirFormat.get_default_format().initialize(safe_unicode(base))
220
def create_branch(self):
221
"""Create a branch in this BzrDir.
223
The bzrdirs format will control what branch format is created.
224
For more control see BranchFormatXX.create(a_bzrdir).
226
raise NotImplementedError(self.create_branch)
229
def create_branch_and_repo(base, force_new_repo=False):
306
230
"""Create a new BzrDir, Branch and Repository at the url 'base'.
308
This will use the current default BzrDirFormat unless one is
309
specified, and use whatever
232
This will use the current default BzrDirFormat, and use whatever
310
233
repository format that that uses via bzrdir.create_branch and
311
234
create_repository. If a shared repository is available that is used
316
239
:param base: The URL to create the branch at.
317
240
: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.
321
bzrdir = BzrDir.create(base, format)
242
bzrdir = BzrDir.create(base)
322
243
bzrdir._find_or_create_repository(force_new_repo)
323
244
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)
386
246
def _find_or_create_repository(self, force_new_repo):
387
247
"""Create a new repository if needed, returning the 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.
249
return self.create_repository()
251
return self.find_repository()
252
except errors.NoRepositoryPresent:
253
return self.create_repository()
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
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,
547
256
def create_branch_convenience(base, force_new_repo=False,
548
force_new_tree=None, format=None,
549
possible_transports=None):
257
force_new_tree=None, format=None):
550
258
"""Create a new BzrDir, Branch and Repository at the url 'base'.
552
260
This is a convenience function - it will use an existing repository
553
261
if possible, can be told explicitly whether to create a working tree or
556
This will use the current default BzrDirFormat unless one is
557
specified, and use whatever
264
This will use the current default BzrDirFormat, and use whatever
558
265
repository format that that uses via bzrdir.create_branch and
559
266
create_repository. If a shared repository is available that is used
560
267
preferentially. Whatever repository is used, its tree creation policy
563
270
The created Branch object is returned.
564
271
If a working tree cannot be made due to base not being a file:// url,
565
no error is raised unless force_new_tree is True, in which case no
272
no error is raised unless force_new_tree is True, in which case no
566
273
data is created on disk and NotLocalUrl is raised.
568
275
:param base: The URL to create the branch at.
569
276
:param force_new_repo: If True a new repository is always created.
570
:param force_new_tree: If True or False force creation of a tree or
277
:param force_new_tree: If True or False force creation of a tree or
571
278
prevent such creation respectively.
572
:param format: Override for the bzrdir format to create.
573
:param possible_transports: An optional reusable transports list.
279
:param format: Override for the for the bzrdir format to create
575
281
if force_new_tree:
576
282
# check for non local urls
577
t = _mod_transport.get_transport(base, possible_transports)
578
if not isinstance(t, local.LocalTransport):
283
t = get_transport(safe_unicode(base))
284
if not isinstance(t, LocalTransport):
579
285
raise errors.NotLocalUrl(base)
580
bzrdir = BzrDir.create(base, format, possible_transports)
287
bzrdir = BzrDir.create(base)
289
bzrdir = format.initialize(base)
581
290
repo = bzrdir._find_or_create_repository(force_new_repo)
582
291
result = bzrdir.create_branch()
583
if force_new_tree or (repo.make_working_trees() and
292
if force_new_tree or (repo.make_working_trees() and
584
293
force_new_tree is None):
586
295
bzrdir.create_workingtree()
587
296
except errors.NotLocalUrl:
592
def create_standalone_workingtree(base, format=None):
301
def create_repository(base, shared=False):
302
"""Create a new BzrDir and Repository at the url 'base'.
304
This will use the current default BzrDirFormat, and use whatever
305
repository format that that uses for bzrdirformat.create_repository.
307
:param shared: Create a shared repository rather than a standalone
309
The Repository object is returned.
311
This must be overridden as an instance method in child classes, where
312
it should take no parameters and construct whatever repository format
313
that child class desires.
315
bzrdir = BzrDir.create(base)
316
return bzrdir.create_repository(shared)
319
def create_standalone_workingtree(base):
593
320
"""Create a new BzrDir, WorkingTree, Branch and Repository at 'base'.
595
322
'base' must be a local path or a file:// url.
597
This will use the current default BzrDirFormat unless one is
598
specified, and use whatever
324
This will use the current default BzrDirFormat, and use whatever
599
325
repository format that that uses for bzrdirformat.create_workingtree,
600
326
create_branch and create_repository.
602
:param format: Override for the bzrdir format to create.
603
328
:return: The WorkingTree object.
605
t = _mod_transport.get_transport(base)
606
if not isinstance(t, local.LocalTransport):
330
t = get_transport(safe_unicode(base))
331
if not isinstance(t, LocalTransport):
607
332
raise errors.NotLocalUrl(base)
608
bzrdir = BzrDir.create_branch_and_repo(base,
610
format=format).bzrdir
333
bzrdir = BzrDir.create_branch_and_repo(safe_unicode(base),
334
force_new_repo=True).bzrdir
611
335
return bzrdir.create_workingtree()
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()
337
def create_workingtree(self, revision_id=None):
338
"""Create a working tree at this BzrDir.
340
revision_id: create it as of this revision id.
342
raise NotImplementedError(self.create_workingtree)
344
def find_repository(self):
345
"""Find the repository that should be used for a_bzrdir.
347
This does not require a branch as we use it to find the repo for
348
new branches as well as to hook existing branches up to their
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
352
return self.open_repository()
353
except errors.NoRepositoryPresent:
355
next_transport = self.root_transport.clone('..')
689
357
# find the next containing bzrdir
691
359
found_bzrdir = BzrDir.open_containing_from_transport(
692
360
next_transport)[0]
693
361
except errors.NotBranchError:
696
def find_repository(self):
697
"""Find the repository that should be used.
699
This does not require a branch as we use it to find the repo for
700
new branches as well as to hook existing branches up to their
703
def usable_repository(found_bzrdir):
363
raise errors.NoRepositoryPresent(self)
704
364
# does it have a repository ?
706
366
repository = found_bzrdir.open_repository()
707
367
except errors.NoRepositoryPresent:
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."""
368
next_transport = found_bzrdir.root_transport.clone('..')
369
if (found_bzrdir.root_transport.base == next_transport.base):
370
# top of the file system
374
if ((found_bzrdir.root_transport.base ==
375
self.root_transport.base) or repository.is_shared()):
378
raise errors.NoRepositoryPresent(self)
379
raise errors.NoRepositoryPresent(self)
381
def get_branch_transport(self, branch_format):
382
"""Get the transport for use by branch format in this BzrDir.
384
Note that bzr dirs that do not support format strings will raise
385
IncompatibleFormat if the branch format they are given has
386
a format string, and vice versa.
388
If branch_format is None, the transport is returned with no
389
checking. if it is not None, then the returned transport is
390
guaranteed to point to an existing directory ready for use.
392
raise NotImplementedError(self.get_branch_transport)
394
def get_repository_transport(self, repository_format):
395
"""Get the transport for use by repository format in this BzrDir.
397
Note that bzr dirs that do not support format strings will raise
398
IncompatibleFormat if the repository format they are given has
399
a format string, and vice versa.
401
If repository_format is None, the transport is returned with no
402
checking. if it is not None, then the returned transport is
403
guaranteed to point to an existing directory ready for use.
405
raise NotImplementedError(self.get_repository_transport)
407
def get_workingtree_transport(self, tree_format):
408
"""Get the transport for use by workingtree format in this BzrDir.
410
Note that bzr dirs that do not support format strings will raise
411
IncompatibleFormat if the workingtree format they are given has
412
a format string, and vice versa.
414
If workingtree_format is None, the transport is returned with no
415
checking. if it is not None, then the returned transport is
416
guaranteed to point to an existing directory ready for use.
418
raise NotImplementedError(self.get_workingtree_transport)
773
420
def __init__(self, _transport, _format):
774
421
"""Initialize a Bzr control dir object.
776
423
Only really common logic should reside here, concrete classes should be
777
424
made with varying behaviours.
780
427
:param _transport: the transport this dir is based at.
782
429
self._format = _format
783
# these are also under the more standard names of
784
# control_transport and user_transport
785
430
self.transport = _transport.clone('.bzr')
786
431
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
797
433
def is_control_filename(self, filename):
798
434
"""True if filename is the name of a path which is reserved for bzrdir's.
800
436
:param filename: A filename within the root transport of this bzrdir.
802
438
This is true IF and ONLY IF the filename is part of the namespace reserved
803
439
for bzr control dirs. Currently this is the '.bzr' directory in the root
804
of the root_transport.
440
of the root_transport. it is expected that plugins will need to extend
441
this in the future - for instance to make bzr talk with svn working
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
444
# this might be better on the BzrDirFormat class because it refers to
445
# all the possible bzrdir disk formats.
446
# This method is tested via the workingtree is_control_filename tests-
447
# it was extracted from WorkingTree.is_control_filename. If the methods
448
# contract is extended beyond the current trivial implementation please
811
449
# add new tests for it to the appropriate place.
812
450
return filename == '.bzr' or filename.startswith('.bzr/')
452
def needs_format_conversion(self, format=None):
453
"""Return true if this bzrdir needs convert_format run on it.
455
For instance, if the repository format is out of date but the
456
branch and working tree are not, this should return True.
458
:param format: Optional parameter indicating a specific desired
459
format we plan to arrive at.
461
raise NotImplementedError(self.needs_format_conversion)
815
464
def open_unsupported(base):
816
465
"""Open a branch which is not supported."""
817
466
return BzrDir.open(base, _unsupported=True)
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.
469
def open(base, _unsupported=False):
470
"""Open an existing bzrdir, rooted at 'base' (url)
472
_unsupported is a private parameter to the BzrDir class.
825
t = _mod_transport.get_transport(base, possible_transports)
474
t = get_transport(base)
826
475
return BzrDir.open_from_transport(t, _unsupported=_unsupported)
829
def open_from_transport(transport, _unsupported=False,
830
_server_formats=True):
478
def open_from_transport(transport, _unsupported=False):
831
479
"""Open a bzrdir within a particular directory.
833
481
:param transport: Transport containing the bzrdir.
834
482
:param _unsupported: private.
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)
484
format = BzrDirFormat.find_format(transport)
485
BzrDir._check_supported(format, _unsupported)
861
486
return format.open(transport, _found=True)
488
def open_branch(self, unsupported=False):
489
"""Open the branch object at this BzrDir if one is present.
491
If unsupported is True, then no longer supported branch formats can
494
TODO: static convenience version of this?
496
raise NotImplementedError(self.open_branch)
864
def open_containing(url, possible_transports=None):
499
def open_containing(url):
865
500
"""Open an existing branch which contains url.
867
502
:param url: url to search from.
868
503
See open_containing_from_transport for more detail.
870
transport = _mod_transport.get_transport(url, possible_transports)
871
return BzrDir.open_containing_from_transport(transport)
505
return BzrDir.open_containing_from_transport(get_transport(url))
874
508
def open_containing_from_transport(a_transport):
875
"""Open an existing branch which contains a_transport.base.
509
"""Open an existing branch which contains a_transport.base
877
511
This probes for a branch at a_transport, and searches upwards from there.
879
513
Basically we keep looking up until we find the control directory or
880
514
run into the root. If there isn't one, raises NotBranchError.
881
If there is one and it is either an unrecognised format or an unsupported
515
If there is one and it is either an unrecognised format or an unsupported
882
516
format, UnknownFormatError or UnsupportedFormatError are raised.
883
517
If there is one, it is returned, along with the unused portion of url.
885
:return: The BzrDir that contains the path, and a Unicode path
519
:return: The BzrDir that contains the path, and a Unicode path
886
520
for the rest of the URL.
888
522
# this gets the normalised url back. I.e. '.' -> the full path.
893
527
return result, urlutils.unescape(a_transport.relpath(url))
894
528
except errors.NotBranchError, e:
897
new_t = a_transport.clone('..')
898
except errors.InvalidURLJoin:
899
# reached the root, whatever that may be
900
raise errors.NotBranchError(path=url)
530
new_t = a_transport.clone('..')
901
531
if new_t.base == a_transport.base:
902
532
# reached the root, whatever that may be
903
533
raise errors.NotBranchError(path=url)
904
534
a_transport = new_t
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)
536
def open_repository(self, _unsupported=False):
537
"""Open the repository object at this BzrDir if one is present.
539
This will not follow the Branch object pointer - its strictly a direct
540
open facility. Most client code should use open_branch().repository to
543
_unsupported is a private parameter, not part of the api.
544
TODO: static convenience version of this?
546
raise NotImplementedError(self.open_repository)
548
def open_workingtree(self, _unsupported=False):
549
"""Open the workingtree object at this BzrDir if one is present.
551
TODO: static convenience version of this?
553
raise NotImplementedError(self.open_workingtree)
555
def has_branch(self):
556
"""Tell if this bzrdir contains a branch.
558
Note: if you're going to open the branch, you should just go ahead
559
and try, and not ask permission first. (This method just opens the
560
branch and discards it, and that's somewhat expensive.)
948
tree, branch = bzrdir._get_tree_branch()
949
565
except errors.NotBranchError:
568
def has_workingtree(self):
569
"""Tell if this bzrdir contains a working tree.
571
This will still raise an exception if the bzrdir has a workingtree that
572
is remote & inaccessible.
574
Note: if you're going to open the working tree, you should just go ahead
575
and try, and not ask permission first. (This method just opens the
576
workingtree and discards it, and that's somewhat expensive.)
579
self.open_workingtree()
581
except errors.NoWorkingTree:
584
def cloning_metadir(self, basis=None):
585
"""Produce a metadir suitable for cloning with"""
586
def related_repository(bzrdir):
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)
588
branch = bzrdir.open_branch()
589
return branch.repository
590
except errors.NotBranchError:
592
return bzrdir.open_repository()
962
593
result_format = self._format.__class__()
965
branch = self.open_branch(ignore_fallbacks=True)
966
source_repository = branch.repository
967
result_format._branch_format = branch._format
968
except errors.NotBranchError:
596
source_repository = related_repository(self)
597
except errors.NoRepositoryPresent:
600
source_repository = related_repository(self)
601
result_format.repository_format = source_repository._format
602
except errors.NoRepositoryPresent:
606
def sprout(self, url, revision_id=None, basis=None, force_new_repo=False):
607
"""Create a copy of this bzrdir prepared for use as a new line of
610
If urls last component does not exist, it will be created.
612
Attributes related to the identity of the source branch like
613
branch nickname will be cleaned, a working tree is created
614
whether one existed before or not; and a local branch is always
617
if revision_id is not None, then the clone operation may tune
618
itself to download less data.
621
cloning_format = self.cloning_metadir(basis)
622
result = cloning_format.initialize(url)
623
basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
625
source_branch = self.open_branch()
626
source_repository = source_branch.repository
627
except errors.NotBranchError:
970
630
source_repository = self.open_repository()
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)
631
except errors.NoRepositoryPresent:
632
# copy the entire basis one if there is one
633
# but there is no repository.
634
source_repository = basis_repo
639
result_repo = result.find_repository()
640
except errors.NoRepositoryPresent:
642
if source_repository is None and result_repo is not None:
644
elif source_repository is None and result_repo is None:
645
# no repo available, make a new one
646
result.create_repository()
647
elif source_repository is not None and result_repo is None:
648
# have source, and want to make a new target repo
649
# we don't clone the repo because that preserves attributes
650
# like is_shared(), and we have not yet implemented a
651
# repository sprout().
652
result_repo = result.create_repository()
653
if result_repo is not None:
654
# fetch needed content into target.
656
# XXX FIXME RBC 20060214 need tests for this when the basis
658
result_repo.fetch(basis_repo, revision_id=revision_id)
659
if source_repository is not None:
660
result_repo.fetch(source_repository, revision_id=revision_id)
661
if source_branch is not None:
662
source_branch.sprout(result, revision_id=revision_id)
664
result.create_branch()
665
# TODO: jam 20060426 we probably need a test in here in the
666
# case that the newly sprouted branch is a remote one
667
if result_repo is None or result_repo.make_working_trees():
668
result.create_workingtree()
672
class BzrDirPreSplitOut(BzrDir):
673
"""A common class for the all-in-one formats."""
675
def __init__(self, _transport, _format):
676
"""See BzrDir.__init__."""
677
super(BzrDirPreSplitOut, self).__init__(_transport, _format)
678
assert self._format._lock_class == TransportLock
679
assert self._format._lock_file_name == 'branch-lock'
680
self._control_files = LockableFiles(self.get_branch_transport(None),
681
self._format._lock_file_name,
682
self._format._lock_class)
684
def break_lock(self):
685
"""Pre-splitout bzrdirs do not suffer from stale locks."""
686
raise NotImplementedError(self.break_lock)
688
def clone(self, url, revision_id=None, basis=None, force_new_repo=False):
689
"""See BzrDir.clone()."""
690
from bzrlib.workingtree import WorkingTreeFormat2
692
result = self._format._initialize_for_clone(url)
693
basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
694
self.open_repository().clone(result, revision_id=revision_id, basis=basis_repo)
695
from_branch = self.open_branch()
696
from_branch.clone(result, revision_id=revision_id)
698
self.open_workingtree().clone(result, basis=basis_tree)
699
except errors.NotLocalUrl:
700
# make a new one, this format always has to have one.
702
WorkingTreeFormat2().initialize(result)
703
except errors.NotLocalUrl:
704
# but we cannot do it for remote trees.
705
to_branch = result.open_branch()
706
WorkingTreeFormat2().stub_initialize_remote(to_branch.control_files)
709
def create_branch(self):
710
"""See BzrDir.create_branch."""
711
return self.open_branch()
713
def create_repository(self, shared=False):
714
"""See BzrDir.create_repository."""
716
raise errors.IncompatibleFormat('shared repository', self._format)
717
return self.open_repository()
719
def create_workingtree(self, revision_id=None):
720
"""See BzrDir.create_workingtree."""
721
# this looks buggy but is not -really-
722
# clone and sprout will have set the revision_id
723
# and that will have set it for us, its only
724
# specific uses of create_workingtree in isolation
725
# that can do wonky stuff here, and that only
726
# happens for creating checkouts, which cannot be
727
# done on this format anyway. So - acceptable wart.
728
result = self.open_workingtree()
729
if revision_id is not None:
730
if revision_id == bzrlib.revision.NULL_REVISION:
731
result.set_parent_ids([])
733
result.set_parent_ids([revision_id])
736
def get_branch_transport(self, branch_format):
737
"""See BzrDir.get_branch_transport()."""
738
if branch_format is None:
739
return self.transport
741
branch_format.get_format_string()
742
except NotImplementedError:
743
return self.transport
744
raise errors.IncompatibleFormat(branch_format, self._format)
746
def get_repository_transport(self, repository_format):
747
"""See BzrDir.get_repository_transport()."""
748
if repository_format is None:
749
return self.transport
751
repository_format.get_format_string()
752
except NotImplementedError:
753
return self.transport
754
raise errors.IncompatibleFormat(repository_format, self._format)
756
def get_workingtree_transport(self, workingtree_format):
757
"""See BzrDir.get_workingtree_transport()."""
758
if workingtree_format is None:
759
return self.transport
761
workingtree_format.get_format_string()
762
except NotImplementedError:
763
return self.transport
764
raise errors.IncompatibleFormat(workingtree_format, self._format)
766
def needs_format_conversion(self, format=None):
767
"""See BzrDir.needs_format_conversion()."""
768
# if the format is not the same as the system default,
769
# an upgrade is needed.
1034
770
if format is None:
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)
1051
def get_repository_transport(self, repository_format):
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__,
771
format = BzrDirFormat.get_default_format()
772
return not isinstance(self._format, format.__class__)
774
def open_branch(self, unsupported=False):
775
"""See BzrDir.open_branch."""
776
from bzrlib.branch import BzrBranchFormat4
777
format = BzrBranchFormat4()
778
self._check_supported(format, unsupported)
779
return format.open(self, _found=True)
781
def sprout(self, url, revision_id=None, basis=None, force_new_repo=False):
782
"""See BzrDir.sprout()."""
783
from bzrlib.workingtree import WorkingTreeFormat2
785
result = self._format._initialize_for_clone(url)
786
basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
788
self.open_repository().clone(result, revision_id=revision_id, basis=basis_repo)
789
except errors.NoRepositoryPresent:
792
self.open_branch().sprout(result, revision_id=revision_id)
793
except errors.NotBranchError:
795
# we always want a working tree
796
WorkingTreeFormat2().initialize(result)
800
class BzrDir4(BzrDirPreSplitOut):
801
"""A .bzr version 4 control object.
803
This is a deprecated format and may be removed after sept 2006.
806
def create_repository(self, shared=False):
807
"""See BzrDir.create_repository."""
808
return self._format.repository_format.initialize(self, shared)
810
def needs_format_conversion(self, format=None):
811
"""Format 4 dirs are always in need of conversion."""
814
def open_repository(self):
815
"""See BzrDir.open_repository."""
816
from bzrlib.repository import RepositoryFormat4
817
return RepositoryFormat4().open(self, _found=True)
820
class BzrDir5(BzrDirPreSplitOut):
821
"""A .bzr version 5 control object.
823
This is a deprecated format and may be removed after sept 2006.
826
def open_repository(self):
827
"""See BzrDir.open_repository."""
828
from bzrlib.repository import RepositoryFormat5
829
return RepositoryFormat5().open(self, _found=True)
831
def open_workingtree(self, _unsupported=False):
832
"""See BzrDir.create_workingtree."""
833
from bzrlib.workingtree import WorkingTreeFormat2
834
return WorkingTreeFormat2().open(self, _found=True)
837
class BzrDir6(BzrDirPreSplitOut):
838
"""A .bzr version 6 control object.
840
This is a deprecated format and may be removed after sept 2006.
843
def open_repository(self):
844
"""See BzrDir.open_repository."""
845
from bzrlib.repository import RepositoryFormat6
846
return RepositoryFormat6().open(self, _found=True)
848
def open_workingtree(self, _unsupported=False):
849
"""See BzrDir.create_workingtree."""
850
from bzrlib.workingtree import WorkingTreeFormat2
851
return WorkingTreeFormat2().open(self, _found=True)
1133
854
class BzrDirMeta1(BzrDir):
1134
855
"""A .bzr meta version 1 control object.
1136
This is the first control object where the
857
This is the first control object where the
1137
858
individual aspects are really split out: there are separate repository,
1138
859
workingtree and branch subdirectories and any subset of the three can be
1139
860
present within a BzrDir.
1276
941
except errors.NoRepositoryPresent:
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):
943
# currently there are no other possible conversions for meta1 formats.
1293
def open_branch(self, name=None, unsupported=False,
1294
ignore_fallbacks=False):
946
def open_branch(self, unsupported=False):
1295
947
"""See BzrDir.open_branch."""
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)
948
from bzrlib.branch import BranchFormat
949
format = BranchFormat.find_format(self)
950
self._check_supported(format, unsupported)
951
return format.open(self, _found=True)
1301
953
def open_repository(self, unsupported=False):
1302
954
"""See BzrDir.open_repository."""
1303
955
from bzrlib.repository import RepositoryFormat
1304
956
format = RepositoryFormat.find_format(self)
1305
format.check_support_status(unsupported)
957
self._check_supported(format, unsupported)
1306
958
return format.open(self, _found=True)
1308
def open_workingtree(self, unsupported=False,
1309
recommend_upgrade=True):
960
def open_workingtree(self, unsupported=False):
1310
961
"""See BzrDir.open_workingtree."""
1311
962
from bzrlib.workingtree import WorkingTreeFormat
1312
963
format = WorkingTreeFormat.find_format(self)
1313
format.check_support_status(unsupported, recommend_upgrade,
1314
basedir=self.root_transport.base)
964
self._check_supported(format, unsupported)
1315
965
return format.open(self, _found=True)
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
968
class BzrDirFormat(object):
969
"""An encapsulation of the initialization and open routines for a format.
971
Formats provide three things:
972
* An initialization routine,
976
Formats are placed in an dict by their format string for reference
1400
977
during bzrdir opening. These should be subclasses of BzrDirFormat
1401
978
for consistency.
1403
980
Once a format is deprecated, just deprecate the initialize and open
1404
methods on the format class. Do not deprecate the object, as the
981
methods on the format class. Do not deprecate the object, as the
1405
982
object will be created every system load.
985
_default_format = None
986
"""The default format used for new .bzr dirs."""
989
"""The known formats."""
991
_control_formats = []
992
"""The registered control formats - .bzr, ....
994
This is a list of BzrDirFormat objects.
1408
997
_lock_file_name = 'branch-lock'
1410
999
# _lock_class must be set in subclasses to the lock type, typ.
1411
1000
# TransportLock or LockDir
1414
def get_format_string(cls):
1003
def find_format(klass, transport):
1004
"""Return the format present at transport."""
1005
for format in klass._control_formats:
1007
return format.probe_transport(transport)
1008
except errors.NotBranchError:
1009
# this format does not find a control dir here.
1011
raise errors.NotBranchError(path=transport.base)
1014
def probe_transport(klass, transport):
1015
"""Return the .bzrdir style transport present at URL."""
1017
format_string = transport.get(".bzr/branch-format").read()
1018
except errors.NoSuchFile:
1019
raise errors.NotBranchError(path=transport.base)
1022
return klass._formats[format_string]
1024
raise errors.UnknownFormatError(format=format_string)
1027
def get_default_format(klass):
1028
"""Return the current default format."""
1029
return klass._default_format
1031
def get_format_string(self):
1415
1032
"""Return the ASCII format string that identifies this format."""
1416
1033
raise NotImplementedError(self.get_format_string)
1035
def get_format_description(self):
1036
"""Return the short description for this format."""
1037
raise NotImplementedError(self.get_format_description)
1039
def get_converter(self, format=None):
1040
"""Return the converter to use to convert bzrdirs needing converts.
1042
This returns a bzrlib.bzrdir.Converter object.
1044
This should return the best upgrader to step this format towards the
1045
current default format. In the case of plugins we can/should provide
1046
some means for them to extend the range of returnable converters.
1048
:param format: Optional format to override the default format of the
1051
raise NotImplementedError(self.get_converter)
1053
def initialize(self, url):
1054
"""Create a bzr control dir at this url and return an opened copy.
1056
Subclasses should typically override initialize_on_transport
1057
instead of this method.
1059
return self.initialize_on_transport(get_transport(url))
1418
1061
def initialize_on_transport(self, transport):
1419
1062
"""Initialize a new bzrdir in the base directory of a Transport."""
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
1063
# Since we don't have a .bzr directory, inherit the
1542
1064
# mode from the root directory
1543
temp_control = lockable_files.LockableFiles(transport,
1544
'', lockable_files.TransportLock)
1065
temp_control = LockableFiles(transport, '', TransportLock)
1545
1066
temp_control._transport.mkdir('.bzr',
1546
1067
# FIXME: RBC 20060121 don't peek under
1548
1069
mode=temp_control._dir_mode)
1549
if sys.platform == 'win32' and isinstance(transport, local.LocalTransport):
1550
win32utils.set_file_attr_hidden(transport._abspath('.bzr'))
1551
1070
file_mode = temp_control._file_mode
1552
1071
del temp_control
1553
bzrdir_transport = transport.clone('.bzr')
1554
utf8_files = [('README',
1555
"This is a Bazaar control directory.\n"
1556
"Do not change any files in this directory.\n"
1557
"See http://bazaar.canonical.com/ for more information about Bazaar.\n"),
1072
mutter('created control directory in ' + transport.base)
1073
control = transport.clone('.bzr')
1074
utf8_files = [('README',
1075
"This is a Bazaar-NG control directory.\n"
1076
"Do not change any files in this directory.\n"),
1558
1077
('branch-format', self.get_format_string()),
1560
1079
# NB: no need to escape relative paths that are url safe.
1561
control_files = lockable_files.LockableFiles(bzrdir_transport,
1562
self._lock_file_name, self._lock_class)
1080
control_files = LockableFiles(control, self._lock_file_name,
1563
1082
control_files.create_lock()
1564
1083
control_files.lock_write()
1566
for (filename, content) in utf8_files:
1567
bzrdir_transport.put_bytes(filename, content,
1085
for file, content in utf8_files:
1086
control_files.put_utf8(file, content)
1570
1088
control_files.unlock()
1571
1089
return self.open(transport, _found=True)
1091
def is_supported(self):
1092
"""Is this format supported?
1094
Supported formats must be initializable and openable.
1095
Unsupported formats may not support initialization or committing or
1096
some other features depending on the reason for not being supported.
1100
def same_model(self, target_format):
1101
return (self.repository_format.rich_root_data ==
1102
target_format.rich_root_data)
1105
def known_formats(klass):
1106
"""Return all the known formats.
1108
Concrete formats should override _known_formats.
1110
# There is double indirection here to make sure that control
1111
# formats used by more than one dir format will only be probed
1112
# once. This can otherwise be quite expensive for remote connections.
1114
for format in klass._control_formats:
1115
result.update(format._known_formats())
1119
def _known_formats(klass):
1120
"""Return the known format instances for this control format."""
1121
return set(klass._formats.values())
1573
1123
def open(self, transport, _found=False):
1574
1124
"""Return an instance of this format for the dir transport points at.
1576
1126
_found is a private parameter, do not use it.
1579
found_format = controldir.ControlDirFormat.find_format(transport)
1580
if not isinstance(found_format, self.__class__):
1581
raise AssertionError("%s was asked to open %s, but it seems to need "
1583
% (self, transport, found_format))
1584
# Allow subclasses - use the found format.
1585
self._supply_sub_formats_to(found_format)
1586
return found_format._open(transport)
1129
assert isinstance(BzrDirFormat.find_format(transport),
1587
1131
return self._open(transport)
1589
1133
def _open(self, transport):
1595
1139
raise NotImplementedError(self._open)
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.
1142
def register_format(klass, format):
1143
klass._formats[format.get_format_string()] = format
1146
def register_control_format(klass, format):
1147
"""Register a format that does not use '.bzrdir' for its control dir.
1149
TODO: This should be pulled up into a 'ControlDirFormat' base class
1150
which BzrDirFormat can inherit from, and renamed to register_format
1151
there. It has been done without that for now for simplicity of
1154
klass._control_formats.append(format)
1157
def set_default_format(klass, format):
1158
klass._default_format = format
1161
return self.get_format_string()[:-1]
1164
def unregister_format(klass, format):
1165
assert klass._formats[format.get_format_string()] is format
1166
del klass._formats[format.get_format_string()]
1169
def unregister_control_format(klass, format):
1170
klass._control_formats.remove(format)
1173
# register BzrDirFormat as a control format
1174
BzrDirFormat.register_control_format(BzrDirFormat)
1177
class BzrDirFormat4(BzrDirFormat):
1178
"""Bzr dir format 4.
1180
This format is a combined format for working tree, branch and repository.
1182
- Format 1 working trees [always]
1183
- Format 4 branches [always]
1184
- Format 4 repositories [always]
1186
This format is deprecated: it indexes texts using a text it which is
1187
removed in format 5; write support for this format has been removed.
1190
_lock_class = TransportLock
1192
def get_format_string(self):
1193
"""See BzrDirFormat.get_format_string()."""
1194
return "Bazaar-NG branch, format 0.0.4\n"
1196
def get_format_description(self):
1197
"""See BzrDirFormat.get_format_description()."""
1198
return "All-in-one format 4"
1200
def get_converter(self, format=None):
1201
"""See BzrDirFormat.get_converter()."""
1202
# there is one and only one upgrade path here.
1203
return ConvertBzrDir4To5()
1205
def initialize_on_transport(self, transport):
1206
"""Format 4 branches cannot be created."""
1207
raise errors.UninitializableFormat(self)
1209
def is_supported(self):
1210
"""Format 4 is not supported.
1212
It is not supported because the model changed from 4 to 5 and the
1213
conversion logic is expensive - so doing it on the fly was not
1218
def _open(self, transport):
1219
"""See BzrDirFormat._open."""
1220
return BzrDir4(transport, self)
1222
def __return_repository_format(self):
1223
"""Circular import protection."""
1224
from bzrlib.repository import RepositoryFormat4
1225
return RepositoryFormat4()
1226
repository_format = property(__return_repository_format)
1229
class BzrDirFormat5(BzrDirFormat):
1230
"""Bzr control format 5.
1232
This format is a combined format for working tree, branch and repository.
1234
- Format 2 working trees [always]
1235
- Format 4 branches [always]
1236
- Format 5 repositories [always]
1237
Unhashed stores in the repository.
1240
_lock_class = TransportLock
1242
def get_format_string(self):
1243
"""See BzrDirFormat.get_format_string()."""
1244
return "Bazaar-NG branch, format 5\n"
1246
def get_format_description(self):
1247
"""See BzrDirFormat.get_format_description()."""
1248
return "All-in-one format 5"
1250
def get_converter(self, format=None):
1251
"""See BzrDirFormat.get_converter()."""
1252
# there is one and only one upgrade path here.
1253
return ConvertBzrDir5To6()
1255
def _initialize_for_clone(self, url):
1256
return self.initialize_on_transport(get_transport(url), _cloning=True)
1258
def initialize_on_transport(self, transport, _cloning=False):
1259
"""Format 5 dirs always have working tree, branch and repository.
1261
Except when they are being cloned.
1263
from bzrlib.branch import BzrBranchFormat4
1264
from bzrlib.repository import RepositoryFormat5
1265
from bzrlib.workingtree import WorkingTreeFormat2
1266
result = (super(BzrDirFormat5, self).initialize_on_transport(transport))
1267
RepositoryFormat5().initialize(result, _internal=True)
1269
branch = BzrBranchFormat4().initialize(result)
1271
WorkingTreeFormat2().initialize(result)
1272
except errors.NotLocalUrl:
1273
# Even though we can't access the working tree, we need to
1274
# create its control files.
1275
WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
1278
def _open(self, transport):
1279
"""See BzrDirFormat._open."""
1280
return BzrDir5(transport, self)
1282
def __return_repository_format(self):
1283
"""Circular import protection."""
1284
from bzrlib.repository import RepositoryFormat5
1285
return RepositoryFormat5()
1286
repository_format = property(__return_repository_format)
1289
class BzrDirFormat6(BzrDirFormat):
1290
"""Bzr control format 6.
1292
This format is a combined format for working tree, branch and repository.
1294
- Format 2 working trees [always]
1295
- Format 4 branches [always]
1296
- Format 6 repositories [always]
1299
_lock_class = TransportLock
1301
def get_format_string(self):
1302
"""See BzrDirFormat.get_format_string()."""
1303
return "Bazaar-NG branch, format 6\n"
1305
def get_format_description(self):
1306
"""See BzrDirFormat.get_format_description()."""
1307
return "All-in-one format 6"
1309
def get_converter(self, format=None):
1310
"""See BzrDirFormat.get_converter()."""
1311
# there is one and only one upgrade path here.
1312
return ConvertBzrDir6ToMeta()
1314
def _initialize_for_clone(self, url):
1315
return self.initialize_on_transport(get_transport(url), _cloning=True)
1317
def initialize_on_transport(self, transport, _cloning=False):
1318
"""Format 6 dirs always have working tree, branch and repository.
1320
Except when they are being cloned.
1322
from bzrlib.branch import BzrBranchFormat4
1323
from bzrlib.repository import RepositoryFormat6
1324
from bzrlib.workingtree import WorkingTreeFormat2
1325
result = super(BzrDirFormat6, self).initialize_on_transport(transport)
1326
RepositoryFormat6().initialize(result, _internal=True)
1328
branch = BzrBranchFormat4().initialize(result)
1330
WorkingTreeFormat2().initialize(result)
1331
except errors.NotLocalUrl:
1332
# Even though we can't access the working tree, we need to
1333
# create its control files.
1334
WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
1337
def _open(self, transport):
1338
"""See BzrDirFormat._open."""
1339
return BzrDir6(transport, self)
1341
def __return_repository_format(self):
1342
"""Circular import protection."""
1343
from bzrlib.repository import RepositoryFormat6
1344
return RepositoryFormat6()
1345
repository_format = property(__return_repository_format)
1610
1348
class BzrDirMetaFormat1(BzrDirFormat):
1618
1356
- Format 7 repositories [optional]
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())
1359
_lock_class = LockDir
1744
1361
def get_converter(self, format=None):
1745
1362
"""See BzrDirFormat.get_converter()."""
1759
1375
"""See BzrDirFormat.get_format_description()."""
1760
1376
return "Meta directory format 1"
1762
def network_name(self):
1763
return self.get_format_string()
1765
1378
def _open(self, transport):
1766
1379
"""See BzrDirFormat._open."""
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)
1380
return BzrDirMeta1(transport, self)
1774
1382
def __return_repository_format(self):
1775
1383
"""Circular import protection."""
1776
if self._repository_format:
1384
if getattr(self, '_repository_format', None):
1777
1385
return self._repository_format
1778
from bzrlib.repository import format_registry
1779
return format_registry.get_default()
1386
from bzrlib.repository import RepositoryFormat
1387
return RepositoryFormat.get_default_format()
1781
def _set_repository_format(self, value):
1782
"""Allow changing the repository format for metadir formats."""
1389
def __set_repository_format(self, value):
1390
"""Allow changint the repository format for metadir formats."""
1783
1391
self._repository_format = value
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):
1393
repository_format = property(__return_repository_format, __set_repository_format)
1396
BzrDirFormat.register_format(BzrDirFormat4())
1397
BzrDirFormat.register_format(BzrDirFormat5())
1398
BzrDirFormat.register_format(BzrDirFormat6())
1399
__default_format = BzrDirMetaFormat1()
1400
BzrDirFormat.register_format(__default_format)
1401
BzrDirFormat.set_default_format(__default_format)
1404
class BzrDirTestProviderAdapter(object):
1405
"""A tool to generate a suite testing multiple bzrdir formats at once.
1407
This is done by copying the test once for each transport and injecting
1408
the transport_server, transport_readonly_server, and bzrdir_format
1409
classes into each copy. Each copy is also given a new id() to make it
1413
def __init__(self, transport_server, transport_readonly_server, formats):
1414
self._transport_server = transport_server
1415
self._transport_readonly_server = transport_readonly_server
1416
self._formats = formats
1418
def adapt(self, test):
1419
result = TestSuite()
1420
for format in self._formats:
1421
new_test = deepcopy(test)
1422
new_test.transport_server = self._transport_server
1423
new_test.transport_readonly_server = self._transport_readonly_server
1424
new_test.bzrdir_format = format
1425
def make_new_test_id():
1426
new_id = "%s(%s)" % (new_test.id(), format.__class__.__name__)
1427
return lambda: new_id
1428
new_test.id = make_new_test_id()
1429
result.addTest(new_test)
1433
class Converter(object):
1434
"""Converts a disk format object from one format to another."""
1436
def convert(self, to_convert, pb):
1437
"""Perform the conversion of to_convert, giving feedback via pb.
1439
:param to_convert: The disk object to convert.
1440
:param pb: a progress bar to use for progress information.
1443
def step(self, message):
1444
"""Update the pb by a step."""
1446
self.pb.update(message, self.count, self.total)
1449
class ConvertBzrDir4To5(Converter):
1450
"""Converts format 4 bzr dirs to format 5."""
1453
super(ConvertBzrDir4To5, self).__init__()
1454
self.converted_revs = set()
1455
self.absent_revisions = set()
1459
def convert(self, to_convert, pb):
1460
"""See Converter.convert()."""
1461
self.bzrdir = to_convert
1463
self.pb.note('starting upgrade from format 4 to 5')
1464
if isinstance(self.bzrdir.transport, LocalTransport):
1465
self.bzrdir.get_workingtree_transport(None).delete('stat-cache')
1466
self._convert_to_weaves()
1467
return BzrDir.open(self.bzrdir.root_transport.base)
1469
def _convert_to_weaves(self):
1470
self.pb.note('note: upgrade may be faster if all store files are ungzipped first')
1473
stat = self.bzrdir.transport.stat('weaves')
1474
if not S_ISDIR(stat.st_mode):
1475
self.bzrdir.transport.delete('weaves')
1476
self.bzrdir.transport.mkdir('weaves')
1477
except errors.NoSuchFile:
1478
self.bzrdir.transport.mkdir('weaves')
1479
# deliberately not a WeaveFile as we want to build it up slowly.
1480
self.inv_weave = Weave('inventory')
1481
# holds in-memory weaves for all files
1482
self.text_weaves = {}
1483
self.bzrdir.transport.delete('branch-format')
1484
self.branch = self.bzrdir.open_branch()
1485
self._convert_working_inv()
1486
rev_history = self.branch.revision_history()
1487
# to_read is a stack holding the revisions we still need to process;
1488
# appending to it adds new highest-priority revisions
1489
self.known_revisions = set(rev_history)
1490
self.to_read = rev_history[-1:]
1492
rev_id = self.to_read.pop()
1493
if (rev_id not in self.revisions
1494
and rev_id not in self.absent_revisions):
1495
self._load_one_rev(rev_id)
1497
to_import = self._make_order()
1498
for i, rev_id in enumerate(to_import):
1499
self.pb.update('converting revision', i, len(to_import))
1500
self._convert_one_rev(rev_id)
1502
self._write_all_weaves()
1503
self._write_all_revs()
1504
self.pb.note('upgraded to weaves:')
1505
self.pb.note(' %6d revisions and inventories', len(self.revisions))
1506
self.pb.note(' %6d revisions not present', len(self.absent_revisions))
1507
self.pb.note(' %6d texts', self.text_count)
1508
self._cleanup_spare_files_after_format4()
1509
self.branch.control_files.put_utf8('branch-format', BzrDirFormat5().get_format_string())
1511
def _cleanup_spare_files_after_format4(self):
1512
# FIXME working tree upgrade foo.
1513
for n in 'merged-patches', 'pending-merged-patches':
1515
## assert os.path.getsize(p) == 0
1516
self.bzrdir.transport.delete(n)
1517
except errors.NoSuchFile:
1519
self.bzrdir.transport.delete_tree('inventory-store')
1520
self.bzrdir.transport.delete_tree('text-store')
1522
def _convert_working_inv(self):
1523
inv = serializer_v4.read_inventory(self.branch.control_files.get('inventory'))
1524
new_inv_xml = bzrlib.xml5.serializer_v5.write_inventory_to_string(inv)
1525
# FIXME inventory is a working tree change.
1526
self.branch.control_files.put('inventory', StringIO(new_inv_xml))
1528
def _write_all_weaves(self):
1529
controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)
1530
weave_transport = self.bzrdir.transport.clone('weaves')
1531
weaves = WeaveStore(weave_transport, prefixed=False)
1532
transaction = WriteTransaction()
1536
for file_id, file_weave in self.text_weaves.items():
1537
self.pb.update('writing weave', i, len(self.text_weaves))
1538
weaves._put_weave(file_id, file_weave, transaction)
1540
self.pb.update('inventory', 0, 1)
1541
controlweaves._put_weave('inventory', self.inv_weave, transaction)
1542
self.pb.update('inventory', 1, 1)
1546
def _write_all_revs(self):
1547
"""Write all revisions out in new form."""
1548
self.bzrdir.transport.delete_tree('revision-store')
1549
self.bzrdir.transport.mkdir('revision-store')
1550
revision_transport = self.bzrdir.transport.clone('revision-store')
1552
_revision_store = TextRevisionStore(TextStore(revision_transport,
1556
transaction = bzrlib.transactions.WriteTransaction()
1557
for i, rev_id in enumerate(self.converted_revs):
1558
self.pb.update('write revision', i, len(self.converted_revs))
1559
_revision_store.add_revision(self.revisions[rev_id], transaction)
1563
def _load_one_rev(self, rev_id):
1564
"""Load a revision object into memory.
1566
Any parents not either loaded or abandoned get queued to be
1568
self.pb.update('loading revision',
1569
len(self.revisions),
1570
len(self.known_revisions))
1571
if not self.branch.repository.has_revision(rev_id):
1573
self.pb.note('revision {%s} not present in branch; '
1574
'will be converted as a ghost',
1576
self.absent_revisions.add(rev_id)
1578
rev = self.branch.repository._revision_store.get_revision(rev_id,
1579
self.branch.repository.get_transaction())
1580
for parent_id in rev.parent_ids:
1581
self.known_revisions.add(parent_id)
1582
self.to_read.append(parent_id)
1583
self.revisions[rev_id] = rev
1585
def _load_old_inventory(self, rev_id):
1586
assert rev_id not in self.converted_revs
1587
old_inv_xml = self.branch.repository.inventory_store.get(rev_id).read()
1588
inv = serializer_v4.read_inventory_from_string(old_inv_xml)
1589
inv.revision_id = rev_id
1590
rev = self.revisions[rev_id]
1591
if rev.inventory_sha1:
1592
assert rev.inventory_sha1 == sha_string(old_inv_xml), \
1593
'inventory sha mismatch for {%s}' % rev_id
1596
def _load_updated_inventory(self, rev_id):
1597
assert rev_id in self.converted_revs
1598
inv_xml = self.inv_weave.get_text(rev_id)
1599
inv = bzrlib.xml5.serializer_v5.read_inventory_from_string(inv_xml)
1602
def _convert_one_rev(self, rev_id):
1603
"""Convert revision and all referenced objects to new format."""
1604
rev = self.revisions[rev_id]
1605
inv = self._load_old_inventory(rev_id)
1606
present_parents = [p for p in rev.parent_ids
1607
if p not in self.absent_revisions]
1608
self._convert_revision_contents(rev, inv, present_parents)
1609
self._store_new_weave(rev, inv, present_parents)
1610
self.converted_revs.add(rev_id)
1612
def _store_new_weave(self, rev, inv, present_parents):
1613
# the XML is now updated with text versions
1615
entries = inv.iter_entries()
1617
for path, ie in entries:
1618
assert getattr(ie, 'revision', None) is not None, \
1619
'no revision on {%s} in {%s}' % \
1620
(file_id, rev.revision_id)
1621
new_inv_xml = bzrlib.xml5.serializer_v5.write_inventory_to_string(inv)
1622
new_inv_sha1 = sha_string(new_inv_xml)
1623
self.inv_weave.add_lines(rev.revision_id,
1625
new_inv_xml.splitlines(True))
1626
rev.inventory_sha1 = new_inv_sha1
1628
def _convert_revision_contents(self, rev, inv, present_parents):
1629
"""Convert all the files within a revision.
1631
Also upgrade the inventory to refer to the text revision ids."""
1632
rev_id = rev.revision_id
1633
mutter('converting texts of revision {%s}',
1635
parent_invs = map(self._load_updated_inventory, present_parents)
1636
entries = inv.iter_entries()
1638
for path, ie in entries:
1639
self._convert_file_version(rev, ie, parent_invs)
1641
def _convert_file_version(self, rev, ie, parent_invs):
1642
"""Convert one version of one file.
1644
The file needs to be added into the weave if it is a merge
1645
of >=2 parents or if it's changed from its parent.
1647
file_id = ie.file_id
1648
rev_id = rev.revision_id
1649
w = self.text_weaves.get(file_id)
1652
self.text_weaves[file_id] = w
1653
text_changed = False
1654
previous_entries = ie.find_previous_heads(parent_invs,
1658
for old_revision in previous_entries:
1659
# if this fails, its a ghost ?
1660
assert old_revision in self.converted_revs
1661
self.snapshot_ie(previous_entries, ie, w, rev_id)
1663
assert getattr(ie, 'revision', None) is not None
1665
def snapshot_ie(self, previous_revisions, ie, w, rev_id):
1666
# TODO: convert this logic, which is ~= snapshot to
1667
# a call to:. This needs the path figured out. rather than a work_tree
1668
# a v4 revision_tree can be given, or something that looks enough like
1669
# one to give the file content to the entry if it needs it.
1670
# and we need something that looks like a weave store for snapshot to
1672
#ie.snapshot(rev, PATH, previous_revisions, REVISION_TREE, InMemoryWeaveStore(self.text_weaves))
1673
if len(previous_revisions) == 1:
1674
previous_ie = previous_revisions.values()[0]
1675
if ie._unchanged(previous_ie):
1676
ie.revision = previous_ie.revision
1679
text = self.branch.repository.text_store.get(ie.text_id)
1680
file_lines = text.readlines()
1681
assert sha_strings(file_lines) == ie.text_sha1
1682
assert sum(map(len, file_lines)) == ie.text_size
1683
w.add_lines(rev_id, previous_revisions, file_lines)
1684
self.text_count += 1
1686
w.add_lines(rev_id, previous_revisions, [])
1687
ie.revision = rev_id
1689
def _make_order(self):
1690
"""Return a suitable order for importing revisions.
1692
The order must be such that an revision is imported after all
1693
its (present) parents.
1695
todo = set(self.revisions.keys())
1696
done = self.absent_revisions.copy()
1699
# scan through looking for a revision whose parents
1701
for rev_id in sorted(list(todo)):
1702
rev = self.revisions[rev_id]
1703
parent_ids = set(rev.parent_ids)
1704
if parent_ids.issubset(done):
1705
# can take this one now
1706
order.append(rev_id)
1712
class ConvertBzrDir5To6(Converter):
1713
"""Converts format 5 bzr dirs to format 6."""
1715
def convert(self, to_convert, pb):
1716
"""See Converter.convert()."""
1717
self.bzrdir = to_convert
1719
self.pb.note('starting upgrade from format 5 to 6')
1720
self._convert_to_prefixed()
1721
return BzrDir.open(self.bzrdir.root_transport.base)
1723
def _convert_to_prefixed(self):
1724
from bzrlib.store import TransportStore
1725
self.bzrdir.transport.delete('branch-format')
1726
for store_name in ["weaves", "revision-store"]:
1727
self.pb.note("adding prefixes to %s" % store_name)
1728
store_transport = self.bzrdir.transport.clone(store_name)
1729
store = TransportStore(store_transport, prefixed=True)
1730
for urlfilename in store_transport.list_dir('.'):
1731
filename = urlutils.unescape(urlfilename)
1732
if (filename.endswith(".weave") or
1733
filename.endswith(".gz") or
1734
filename.endswith(".sig")):
1735
file_id = os.path.splitext(filename)[0]
1738
prefix_dir = store.hash_prefix(file_id)
1739
# FIXME keep track of the dirs made RBC 20060121
1741
store_transport.move(filename, prefix_dir + '/' + filename)
1742
except errors.NoSuchFile: # catches missing dirs strangely enough
1743
store_transport.mkdir(prefix_dir)
1744
store_transport.move(filename, prefix_dir + '/' + filename)
1745
self.bzrdir._control_files.put_utf8('branch-format', BzrDirFormat6().get_format_string())
1748
class ConvertBzrDir6ToMeta(Converter):
1749
"""Converts format 6 bzr dirs to metadirs."""
1751
def convert(self, to_convert, pb):
1752
"""See Converter.convert()."""
1753
self.bzrdir = to_convert
1756
self.total = 20 # the steps we know about
1757
self.garbage_inventories = []
1759
self.pb.note('starting upgrade from format 6 to metadir')
1760
self.bzrdir._control_files.put_utf8('branch-format', "Converting to format 6")
1761
# its faster to move specific files around than to open and use the apis...
1762
# first off, nuke ancestry.weave, it was never used.
1764
self.step('Removing ancestry.weave')
1765
self.bzrdir.transport.delete('ancestry.weave')
1766
except errors.NoSuchFile:
1768
# find out whats there
1769
self.step('Finding branch files')
1770
last_revision = self.bzrdir.open_branch().last_revision()
1771
bzrcontents = self.bzrdir.transport.list_dir('.')
1772
for name in bzrcontents:
1773
if name.startswith('basis-inventory.'):
1774
self.garbage_inventories.append(name)
1775
# create new directories for repository, working tree and branch
1776
self.dir_mode = self.bzrdir._control_files._dir_mode
1777
self.file_mode = self.bzrdir._control_files._file_mode
1778
repository_names = [('inventory.weave', True),
1779
('revision-store', True),
1781
self.step('Upgrading repository ')
1782
self.bzrdir.transport.mkdir('repository', mode=self.dir_mode)
1783
self.make_lock('repository')
1784
# we hard code the formats here because we are converting into
1785
# the meta format. The meta format upgrader can take this to a
1786
# future format within each component.
1787
self.put_format('repository', bzrlib.repository.RepositoryFormat7())
1788
for entry in repository_names:
1789
self.move_entry('repository', entry)
1791
self.step('Upgrading branch ')
1792
self.bzrdir.transport.mkdir('branch', mode=self.dir_mode)
1793
self.make_lock('branch')
1794
self.put_format('branch', bzrlib.branch.BzrBranchFormat5())
1795
branch_files = [('revision-history', True),
1796
('branch-name', True),
1798
for entry in branch_files:
1799
self.move_entry('branch', entry)
1801
checkout_files = [('pending-merges', True),
1802
('inventory', True),
1803
('stat-cache', False)]
1804
# If a mandatory checkout file is not present, the branch does not have
1805
# a functional checkout. Do not create a checkout in the converted
1807
for name, mandatory in checkout_files:
1808
if mandatory and name not in bzrcontents:
1809
has_checkout = False
1813
if not has_checkout:
1814
self.pb.note('No working tree.')
1815
# If some checkout files are there, we may as well get rid of them.
1816
for name, mandatory in checkout_files:
1817
if name in bzrcontents:
1818
self.bzrdir.transport.delete(name)
1820
self.step('Upgrading working tree')
1821
self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
1822
self.make_lock('checkout')
1824
'checkout', bzrlib.workingtree.WorkingTreeFormat3())
1825
self.bzrdir.transport.delete_multi(
1826
self.garbage_inventories, self.pb)
1827
for entry in checkout_files:
1828
self.move_entry('checkout', entry)
1829
if last_revision is not None:
1830
self.bzrdir._control_files.put_utf8(
1831
'checkout/last-revision', last_revision)
1832
self.bzrdir._control_files.put_utf8(
1833
'branch-format', BzrDirMetaFormat1().get_format_string())
1834
return BzrDir.open(self.bzrdir.root_transport.base)
1836
def make_lock(self, name):
1837
"""Make a lock for the new control dir name."""
1838
self.step('Make %s lock' % name)
1839
ld = LockDir(self.bzrdir.transport,
1841
file_modebits=self.file_mode,
1842
dir_modebits=self.dir_mode)
1845
def move_entry(self, new_dir, entry):
1846
"""Move then entry name into new_dir."""
1848
mandatory = entry[1]
1849
self.step('Moving %s' % name)
1851
self.bzrdir.transport.move(name, '%s/%s' % (new_dir, name))
1852
except errors.NoSuchFile:
1856
def put_format(self, dirname, format):
1857
self.bzrdir._control_files.put_utf8('%s/format' % dirname, format.get_format_string())
1860
class ConvertMetaToMeta(Converter):
1828
1861
"""Converts the components of metadirs."""
1830
1863
def __init__(self, target_format):
1849
1882
if not isinstance(repo._format, self.target_format.repository_format.__class__):
1850
1883
from bzrlib.repository import CopyConverter
1851
ui.ui_factory.note('starting repository conversion')
1884
self.pb.note('starting repository conversion')
1852
1885
converter = CopyConverter(self.target_format.repository_format)
1853
1886
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_3.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)
1902
1887
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_3.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