176
175
self._validate_unicode_text(value,
177
176
'revision property (%s)' % (key,))
178
def _ensure_fallback_inventories(self):
179
"""Ensure that appropriate inventories are available.
181
This only applies to repositories that are stacked, and is about
182
enusring the stacking invariants. Namely, that for any revision that is
183
present, we either have all of the file content, or we have the parent
184
inventory and the delta file content.
186
if not self.repository._fallback_repositories:
188
if not self.repository._format.supports_chks:
189
raise errors.BzrError("Cannot commit directly to a stacked branch"
190
" in pre-2a formats. See "
191
"https://bugs.launchpad.net/bzr/+bug/375013 for details.")
192
# This is a stacked repo, we need to make sure we have the parent
193
# inventories for the parents.
194
parent_keys = [(p,) for p in self.parents]
195
parent_map = self.repository.inventories._index.get_parent_map(parent_keys)
196
missing_parent_keys = set([pk for pk in parent_keys
197
if pk not in parent_map])
198
fallback_repos = list(reversed(self.repository._fallback_repositories))
199
missing_keys = [('inventories', pk[0])
200
for pk in missing_parent_keys]
202
while missing_keys and fallback_repos:
203
fallback_repo = fallback_repos.pop()
204
source = fallback_repo._get_source(self.repository._format)
205
sink = self.repository._get_sink()
206
stream = source.get_stream_for_missing_keys(missing_keys)
207
missing_keys = sink.insert_stream_without_locking(stream,
208
self.repository._format)
210
raise errors.BzrError('Unable to fill in parent inventories for a'
179
213
def commit(self, message):
180
214
"""Make the actual commit.
1563
1598
@needs_read_lock
1564
def search_missing_revision_ids(self, other, revision_id=None, find_ghosts=True):
1599
def search_missing_revision_ids(self, other,
1600
revision_id=symbol_versioning.DEPRECATED_PARAMETER,
1601
find_ghosts=True, revision_ids=None, if_present_ids=None):
1565
1602
"""Return the revision ids that other has that this does not.
1567
1604
These are returned in topological order.
1569
1606
revision_id: only return revision ids included by revision_id.
1608
if symbol_versioning.deprecated_passed(revision_id):
1609
symbol_versioning.warn(
1610
'search_missing_revision_ids(revision_id=...) was '
1611
'deprecated in 2.3. Use revision_ids=[...] instead.',
1612
DeprecationWarning, stacklevel=3)
1613
if revision_ids is not None:
1614
raise AssertionError(
1615
'revision_ids is mutually exclusive with revision_id')
1616
if revision_id is not None:
1617
revision_ids = [revision_id]
1571
1618
return InterRepository.get(other, self).search_missing_revision_ids(
1572
revision_id, find_ghosts)
1619
find_ghosts=find_ghosts, revision_ids=revision_ids,
1620
if_present_ids=if_present_ids)
1575
1623
def open(base):
3352
3370
'bzrlib.repofmt.pack_repo',
3353
3371
'RepositoryFormatKnitPack6RichRoot',
3373
format_registry.register_lazy(
3374
'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
3375
'bzrlib.repofmt.groupcompress_repo',
3376
'RepositoryFormat2a',
3356
3379
# Development formats.
3357
# Obsolete but kept pending a CHK based subtree format.
3380
# Check their docstrings to see if/when they are obsolete.
3358
3381
format_registry.register_lazy(
3359
3382
("Bazaar development format 2 with subtree support "
3360
3383
"(needs bzr.dev from before 1.8)\n"),
3361
3384
'bzrlib.repofmt.pack_repo',
3362
3385
'RepositoryFormatPackDevelopment2Subtree',
3365
# 1.14->1.16 go below here
3366
format_registry.register_lazy(
3367
'Bazaar development format - group compression and chk inventory'
3368
' (needs bzr.dev from 1.14)\n',
3369
'bzrlib.repofmt.groupcompress_repo',
3370
'RepositoryFormatCHK1',
3373
format_registry.register_lazy(
3374
'Bazaar development format - chk repository with bencode revision '
3375
'serialization (needs bzr.dev from 1.16)\n',
3376
'bzrlib.repofmt.groupcompress_repo',
3377
'RepositoryFormatCHK2',
3379
format_registry.register_lazy(
3380
'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
3381
'bzrlib.repofmt.groupcompress_repo',
3382
'RepositoryFormat2a',
3384
3387
format_registry.register_lazy(
3385
3388
'Bazaar development format 8\n',
3386
3389
'bzrlib.repofmt.groupcompress_repo',
3498
3505
return searcher.get_result()
3500
3507
@needs_read_lock
3501
def search_missing_revision_ids(self, revision_id=None, find_ghosts=True):
3508
def search_missing_revision_ids(self,
3509
revision_id=symbol_versioning.DEPRECATED_PARAMETER,
3510
find_ghosts=True, revision_ids=None, if_present_ids=None):
3502
3511
"""Return the revision ids that source has that target does not.
3504
3513
:param revision_id: only return revision ids included by this
3515
:param revision_ids: return revision ids included by these
3516
revision_ids. NoSuchRevision will be raised if any of these
3517
revisions are not present.
3518
:param if_present_ids: like revision_ids, but will not cause
3519
NoSuchRevision if any of these are absent, instead they will simply
3520
not be in the result. This is useful for e.g. finding revisions
3521
to fetch for tags, which may reference absent revisions.
3506
3522
:param find_ghosts: If True find missing revisions in deep history
3507
3523
rather than just finding the surface difference.
3508
3524
:return: A bzrlib.graph.SearchResult.
3526
if symbol_versioning.deprecated_passed(revision_id):
3527
symbol_versioning.warn(
3528
'search_missing_revision_ids(revision_id=...) was '
3529
'deprecated in 2.3. Use revision_ids=[...] instead.',
3530
DeprecationWarning, stacklevel=2)
3531
if revision_ids is not None:
3532
raise AssertionError(
3533
'revision_ids is mutually exclusive with revision_id')
3534
if revision_id is not None:
3535
revision_ids = [revision_id]
3510
3537
# stop searching at found target revisions.
3511
if not find_ghosts and revision_id is not None:
3512
return self._walk_to_common_revisions([revision_id])
3538
if not find_ghosts and (revision_ids is not None or if_present_ids is
3540
return self._walk_to_common_revisions(revision_ids,
3541
if_present_ids=if_present_ids)
3513
3542
# generic, possibly worst case, slow code path.
3514
3543
target_ids = set(self.target.all_revision_ids())
3515
if revision_id is not None:
3516
source_ids = self.source.get_ancestry(revision_id)
3517
if source_ids[0] is not None:
3518
raise AssertionError()
3521
source_ids = self.source.all_revision_ids()
3544
source_ids = self._present_source_revisions_for(
3545
revision_ids, if_present_ids)
3522
3546
result_set = set(source_ids).difference(target_ids)
3523
3547
return self.source.revision_ids_to_search_result(result_set)
3549
def _present_source_revisions_for(self, revision_ids, if_present_ids=None):
3550
"""Returns set of all revisions in ancestry of revision_ids present in
3553
:param revision_ids: if None, all revisions in source are returned.
3554
:param if_present_ids: like revision_ids, but if any/all of these are
3555
absent no error is raised.
3557
if revision_ids is not None or if_present_ids is not None:
3558
# First, ensure all specified revisions exist. Callers expect
3559
# NoSuchRevision when they pass absent revision_ids here.
3560
if revision_ids is None:
3561
revision_ids = set()
3562
if if_present_ids is None:
3563
if_present_ids = set()
3564
revision_ids = set(revision_ids)
3565
if_present_ids = set(if_present_ids)
3566
all_wanted_ids = revision_ids.union(if_present_ids)
3567
graph = self.source.get_graph()
3568
present_revs = set(graph.get_parent_map(all_wanted_ids))
3569
missing = revision_ids.difference(present_revs)
3571
raise errors.NoSuchRevision(self.source, missing.pop())
3572
found_ids = all_wanted_ids.intersection(present_revs)
3573
source_ids = [rev_id for (rev_id, parents) in
3574
graph.iter_ancestry(found_ids)
3575
if rev_id != _mod_revision.NULL_REVISION
3576
and parents is not None]
3578
source_ids = self.source.all_revision_ids()
3579
return set(source_ids)
3526
3582
def _same_model(source, target):
3527
3583
"""True if source and target have the same data representation.
3568
3624
return InterRepository._same_model(source, target)
3571
class InterWeaveRepo(InterSameDataRepository):
3572
"""Optimised code paths between Weave based repositories.
3574
This should be in bzrlib/repofmt/weaverepo.py but we have not yet
3575
implemented lazy inter-object optimisation.
3579
def _get_repo_format_to_test(self):
3580
from bzrlib.repofmt import weaverepo
3581
return weaverepo.RepositoryFormat7()
3584
def is_compatible(source, target):
3585
"""Be compatible with known Weave formats.
3587
We don't test for the stores being of specific types because that
3588
could lead to confusing results, and there is no need to be
3591
from bzrlib.repofmt.weaverepo import (
3597
return (isinstance(source._format, (RepositoryFormat5,
3599
RepositoryFormat7)) and
3600
isinstance(target._format, (RepositoryFormat5,
3602
RepositoryFormat7)))
3603
except AttributeError:
3607
def copy_content(self, revision_id=None):
3608
"""See InterRepository.copy_content()."""
3609
# weave specific optimised path:
3611
self.target.set_make_working_trees(self.source.make_working_trees())
3612
except (errors.RepositoryUpgradeRequired, NotImplemented):
3614
# FIXME do not peek!
3615
if self.source._transport.listable():
3616
pb = ui.ui_factory.nested_progress_bar()
3618
self.target.texts.insert_record_stream(
3619
self.source.texts.get_record_stream(
3620
self.source.texts.keys(), 'topological', False))
3621
pb.update('Copying inventory', 0, 1)
3622
self.target.inventories.insert_record_stream(
3623
self.source.inventories.get_record_stream(
3624
self.source.inventories.keys(), 'topological', False))
3625
self.target.signatures.insert_record_stream(
3626
self.source.signatures.get_record_stream(
3627
self.source.signatures.keys(),
3629
self.target.revisions.insert_record_stream(
3630
self.source.revisions.get_record_stream(
3631
self.source.revisions.keys(),
3632
'topological', True))
3636
self.target.fetch(self.source, revision_id=revision_id)
3639
def search_missing_revision_ids(self, revision_id=None, find_ghosts=True):
3640
"""See InterRepository.missing_revision_ids()."""
3641
# we want all revisions to satisfy revision_id in source.
3642
# but we don't want to stat every file here and there.
3643
# we want then, all revisions other needs to satisfy revision_id
3644
# checked, but not those that we have locally.
3645
# so the first thing is to get a subset of the revisions to
3646
# satisfy revision_id in source, and then eliminate those that
3647
# we do already have.
3648
# this is slow on high latency connection to self, but as this
3649
# disk format scales terribly for push anyway due to rewriting
3650
# inventory.weave, this is considered acceptable.
3652
if revision_id is not None:
3653
source_ids = self.source.get_ancestry(revision_id)
3654
if source_ids[0] is not None:
3655
raise AssertionError()
3658
source_ids = self.source._all_possible_ids()
3659
source_ids_set = set(source_ids)
3660
# source_ids is the worst possible case we may need to pull.
3661
# now we want to filter source_ids against what we actually
3662
# have in target, but don't try to check for existence where we know
3663
# we do not have a revision as that would be pointless.
3664
target_ids = set(self.target._all_possible_ids())
3665
possibly_present_revisions = target_ids.intersection(source_ids_set)
3666
actually_present_revisions = set(
3667
self.target._eliminate_revisions_not_present(possibly_present_revisions))
3668
required_revisions = source_ids_set.difference(actually_present_revisions)
3669
if revision_id is not None:
3670
# we used get_ancestry to determine source_ids then we are assured all
3671
# revisions referenced are present as they are installed in topological order.
3672
# and the tip revision was validated by get_ancestry.
3673
result_set = required_revisions
3675
# if we just grabbed the possibly available ids, then
3676
# we only have an estimate of whats available and need to validate
3677
# that against the revision records.
3679
self.source._eliminate_revisions_not_present(required_revisions))
3680
return self.source.revision_ids_to_search_result(result_set)
3683
class InterKnitRepo(InterSameDataRepository):
3684
"""Optimised code paths between Knit based repositories."""
3687
def _get_repo_format_to_test(self):
3688
from bzrlib.repofmt import knitrepo
3689
return knitrepo.RepositoryFormatKnit1()
3692
def is_compatible(source, target):
3693
"""Be compatible with known Knit formats.
3695
We don't test for the stores being of specific types because that
3696
could lead to confusing results, and there is no need to be
3699
from bzrlib.repofmt.knitrepo import RepositoryFormatKnit
3701
are_knits = (isinstance(source._format, RepositoryFormatKnit) and
3702
isinstance(target._format, RepositoryFormatKnit))
3703
except AttributeError:
3705
return are_knits and InterRepository._same_model(source, target)
3708
def search_missing_revision_ids(self, revision_id=None, find_ghosts=True):
3709
"""See InterRepository.missing_revision_ids()."""
3710
if revision_id is not None:
3711
source_ids = self.source.get_ancestry(revision_id)
3712
if source_ids[0] is not None:
3713
raise AssertionError()
3716
source_ids = self.source.all_revision_ids()
3717
source_ids_set = set(source_ids)
3718
# source_ids is the worst possible case we may need to pull.
3719
# now we want to filter source_ids against what we actually
3720
# have in target, but don't try to check for existence where we know
3721
# we do not have a revision as that would be pointless.
3722
target_ids = set(self.target.all_revision_ids())
3723
possibly_present_revisions = target_ids.intersection(source_ids_set)
3724
actually_present_revisions = set(
3725
self.target._eliminate_revisions_not_present(possibly_present_revisions))
3726
required_revisions = source_ids_set.difference(actually_present_revisions)
3727
if revision_id is not None:
3728
# we used get_ancestry to determine source_ids then we are assured all
3729
# revisions referenced are present as they are installed in topological order.
3730
# and the tip revision was validated by get_ancestry.
3731
result_set = required_revisions
3733
# if we just grabbed the possibly available ids, then
3734
# we only have an estimate of whats available and need to validate
3735
# that against the revision records.
3737
self.source._eliminate_revisions_not_present(required_revisions))
3738
return self.source.revision_ids_to_search_result(result_set)
3741
3627
class InterDifferingSerializer(InterRepository):
4274
4168
is_resume = False
4276
4170
# locked_insert_stream performs a commit|suspend.
4277
return self._locked_insert_stream(stream, src_format,
4171
missing_keys = self.insert_stream_without_locking(stream,
4172
src_format, is_resume)
4174
# suspend the write group and tell the caller what we is
4175
# missing. We know we can suspend or else we would not have
4176
# entered this code path. (All repositories that can handle
4177
# missing keys can handle suspending a write group).
4178
write_group_tokens = self.target_repo.suspend_write_group()
4179
return write_group_tokens, missing_keys
4180
hint = self.target_repo.commit_write_group()
4181
to_serializer = self.target_repo._format._serializer
4182
src_serializer = src_format._serializer
4183
if (to_serializer != src_serializer and
4184
self.target_repo._format.pack_compresses):
4185
self.target_repo.pack(hint=hint)
4280
4188
self.target_repo.abort_write_group(suppress_errors=True)
4283
4191
self.target_repo.unlock()
4285
def _locked_insert_stream(self, stream, src_format, is_resume):
4193
def insert_stream_without_locking(self, stream, src_format,
4195
"""Insert a stream's content into the target repository.
4197
This assumes that you already have a locked repository and an active
4200
:param src_format: a bzr repository format.
4201
:param is_resume: Passed down to get_missing_parent_inventories to
4202
indicate if we should be checking for missing texts at the same
4205
:return: A set of keys that are missing.
4207
if not self.target_repo.is_write_locked():
4208
raise errors.ObjectNotLocked(self)
4209
if not self.target_repo.is_in_write_group():
4210
raise errors.BzrError('you must already be in a write group')
4286
4211
to_serializer = self.target_repo._format._serializer
4287
4212
src_serializer = src_format._serializer
4288
4213
new_pack = None