88
96
record_root_entry = True
89
97
# the default CommitBuilder does not manage trees whose root is versioned.
90
98
_versioned_root = False
91
# this commit builder supports the record_entry_contents interface
92
supports_record_entry_contents = True
94
100
def __init__(self, repository, parents, config, timestamp=None,
95
101
timezone=None, committer=None, revprops=None,
96
revision_id=None, lossy=False):
97
103
"""Initiate a CommitBuilder.
99
105
:param repository: Repository to commit to.
100
106
:param parents: Revision ids of the parents of the new revision.
107
:param config: Configuration to use.
101
108
:param timestamp: Optional timestamp recorded for commit.
102
109
:param timezone: Optional timezone for timestamp.
103
110
:param committer: Optional committer to set for commit.
104
111
:param revprops: Optional dictionary of revision properties.
105
112
:param revision_id: Optional revision id.
106
:param lossy: Whether to discard data that can not be natively
107
represented, when pushing to a foreign VCS
109
114
self._config = config
112
116
if committer is None:
113
117
self._committer = self._config.username()
114
elif not isinstance(committer, unicode):
115
self._committer = committer.decode() # throw if non-ascii
117
119
self._committer = committer
172
174
self._validate_unicode_text(value,
173
175
'revision property (%s)' % (key,))
175
def _ensure_fallback_inventories(self):
176
"""Ensure that appropriate inventories are available.
178
This only applies to repositories that are stacked, and is about
179
enusring the stacking invariants. Namely, that for any revision that is
180
present, we either have all of the file content, or we have the parent
181
inventory and the delta file content.
183
if not self.repository._fallback_repositories:
185
if not self.repository._format.supports_chks:
186
raise errors.BzrError("Cannot commit directly to a stacked branch"
187
" in pre-2a formats. See "
188
"https://bugs.launchpad.net/bzr/+bug/375013 for details.")
189
# This is a stacked repo, we need to make sure we have the parent
190
# inventories for the parents.
191
parent_keys = [(p,) for p in self.parents]
192
parent_map = self.repository.inventories._index.get_parent_map(parent_keys)
193
missing_parent_keys = set([pk for pk in parent_keys
194
if pk not in parent_map])
195
fallback_repos = list(reversed(self.repository._fallback_repositories))
196
missing_keys = [('inventories', pk[0])
197
for pk in missing_parent_keys]
199
while missing_keys and fallback_repos:
200
fallback_repo = fallback_repos.pop()
201
source = fallback_repo._get_source(self.repository._format)
202
sink = self.repository._get_sink()
203
stream = source.get_stream_for_missing_keys(missing_keys)
204
missing_keys = sink.insert_stream_without_locking(stream,
205
self.repository._format)
207
raise errors.BzrError('Unable to fill in parent inventories for a'
210
177
def commit(self, message):
211
178
"""Make the actual commit.
1591
1561
@needs_read_lock
1592
def search_missing_revision_ids(self, other,
1593
revision_id=symbol_versioning.DEPRECATED_PARAMETER,
1594
find_ghosts=True, revision_ids=None, if_present_ids=None):
1562
def search_missing_revision_ids(self, other, revision_id=None, find_ghosts=True):
1595
1563
"""Return the revision ids that other has that this does not.
1597
1565
These are returned in topological order.
1599
1567
revision_id: only return revision ids included by revision_id.
1601
if symbol_versioning.deprecated_passed(revision_id):
1602
symbol_versioning.warn(
1603
'search_missing_revision_ids(revision_id=...) was '
1604
'deprecated in 2.4. Use revision_ids=[...] instead.',
1605
DeprecationWarning, stacklevel=3)
1606
if revision_ids is not None:
1607
raise AssertionError(
1608
'revision_ids is mutually exclusive with revision_id')
1609
if revision_id is not None:
1610
revision_ids = [revision_id]
1611
1569
return InterRepository.get(other, self).search_missing_revision_ids(
1612
find_ghosts=find_ghosts, revision_ids=revision_ids,
1613
if_present_ids=if_present_ids)
1570
revision_id, find_ghosts)
1616
1573
def open(base):
2059
2016
w = self.inventories
2060
2017
pb = ui.ui_factory.nested_progress_bar()
2062
return self._serializer._find_text_key_references(
2019
return self._find_text_key_references_from_xml_inventory_lines(
2063
2020
w.iter_lines_added_or_present_in_keys(revision_keys, pb=pb))
2024
def _find_text_key_references_from_xml_inventory_lines(self,
2026
"""Core routine for extracting references to texts from inventories.
2028
This performs the translation of xml lines to revision ids.
2030
:param line_iterator: An iterator of lines, origin_version_id
2031
:return: A dictionary mapping text keys ((fileid, revision_id) tuples)
2032
to whether they were referred to by the inventory of the
2033
revision_id that they contain. Note that if that revision_id was
2034
not part of the line_iterator's output then False will be given -
2035
even though it may actually refer to that key.
2037
if not self._serializer.support_altered_by_hack:
2038
raise AssertionError(
2039
"_find_text_key_references_from_xml_inventory_lines only "
2040
"supported for branches which store inventory as unnested xml"
2041
", not on %r" % self)
2044
# this code needs to read every new line in every inventory for the
2045
# inventories [revision_ids]. Seeing a line twice is ok. Seeing a line
2046
# not present in one of those inventories is unnecessary but not
2047
# harmful because we are filtering by the revision id marker in the
2048
# inventory lines : we only select file ids altered in one of those
2049
# revisions. We don't need to see all lines in the inventory because
2050
# only those added in an inventory in rev X can contain a revision=X
2052
unescape_revid_cache = {}
2053
unescape_fileid_cache = {}
2055
# jam 20061218 In a big fetch, this handles hundreds of thousands
2056
# of lines, so it has had a lot of inlining and optimizing done.
2057
# Sorry that it is a little bit messy.
2058
# Move several functions to be local variables, since this is a long
2060
search = self._file_ids_altered_regex.search
2061
unescape = _unescape_xml
2062
setdefault = result.setdefault
2063
for line, line_key in line_iterator:
2064
match = search(line)
2067
# One call to match.group() returning multiple items is quite a
2068
# bit faster than 2 calls to match.group() each returning 1
2069
file_id, revision_id = match.group('file_id', 'revision_id')
2071
# Inlining the cache lookups helps a lot when you make 170,000
2072
# lines and 350k ids, versus 8.4 unique ids.
2073
# Using a cache helps in 2 ways:
2074
# 1) Avoids unnecessary decoding calls
2075
# 2) Re-uses cached strings, which helps in future set and
2077
# (2) is enough that removing encoding entirely along with
2078
# the cache (so we are using plain strings) results in no
2079
# performance improvement.
2081
revision_id = unescape_revid_cache[revision_id]
2083
unescaped = unescape(revision_id)
2084
unescape_revid_cache[revision_id] = unescaped
2085
revision_id = unescaped
2087
# Note that unconditionally unescaping means that we deserialise
2088
# every fileid, which for general 'pull' is not great, but we don't
2089
# really want to have some many fulltexts that this matters anyway.
2092
file_id = unescape_fileid_cache[file_id]
2094
unescaped = unescape(file_id)
2095
unescape_fileid_cache[file_id] = unescaped
2098
key = (file_id, revision_id)
2099
setdefault(key, False)
2100
if revision_id == line_key[-1]:
2067
2104
def _inventory_xml_lines_for_keys(self, keys):
2068
2105
"""Get a line iterator of the sort needed for findind references.
2773
2808
except UnicodeDecodeError:
2774
2809
raise errors.NonAsciiRevisionId(method, self)
2776
def _find_inconsistent_revision_parents(self, revisions_iterator=None):
2777
"""Find revisions with different parent lists in the revision object
2778
and in the index graph.
2811
def revision_graph_can_have_wrong_parents(self):
2812
"""Is it possible for this repository to have a revision graph with
2780
:param revisions_iterator: None, or an iterator of (revid,
2781
Revision-or-None). This iterator controls the revisions checked.
2782
:returns: an iterator yielding tuples of (revison-id, parents-in-index,
2783
parents-in-revision).
2815
If True, then this repository must also implement
2816
_find_inconsistent_revision_parents so that check and reconcile can
2817
check for inconsistencies before proceeding with other checks that may
2818
depend on the revision index being consistent.
2785
if not self.is_locked():
2786
raise AssertionError()
2788
if revisions_iterator is None:
2789
revisions_iterator = self._iter_revisions(None)
2790
for revid, revision in revisions_iterator:
2791
if revision is None:
2793
parent_map = vf.get_parent_map([(revid,)])
2794
parents_according_to_index = tuple(parent[-1] for parent in
2795
parent_map[(revid,)])
2796
parents_according_to_revision = tuple(revision.parent_ids)
2797
if parents_according_to_index != parents_according_to_revision:
2798
yield (revid, parents_according_to_index,
2799
parents_according_to_revision)
2801
def _check_for_inconsistent_revision_parents(self):
2802
inconsistencies = list(self._find_inconsistent_revision_parents())
2804
raise errors.BzrCheckError(
2805
"Revision knit has inconsistent parents.")
2820
raise NotImplementedError(self.revision_graph_can_have_wrong_parents)
2823
# remove these delegates a while after bzr 0.15
2824
def __make_delegated(name, from_module):
2825
def _deprecated_repository_forwarder():
2826
symbol_versioning.warn('%s moved to %s in bzr 0.15'
2827
% (name, from_module),
2831
return pyutils.get_named_object(from_module, name)
2832
except AttributeError:
2833
raise AttributeError('module %s has no name %s'
2834
% (sys.modules[from_module], name))
2835
globals()[name] = _deprecated_repository_forwarder
2838
'AllInOneRepository',
2839
'WeaveMetaDirRepository',
2840
'PreSplitOutRepositoryFormat',
2841
'RepositoryFormat4',
2842
'RepositoryFormat5',
2843
'RepositoryFormat6',
2844
'RepositoryFormat7',
2846
__make_delegated(_name, 'bzrlib.repofmt.weaverepo')
2850
'RepositoryFormatKnit',
2851
'RepositoryFormatKnit1',
2853
__make_delegated(_name, 'bzrlib.repofmt.knitrepo')
2808
2856
def install_revision(repository, rev, revision_tree):
3223
3262
return self.get_format_string()
3265
# Pre-0.8 formats that don't have a disk format string (because they are
3266
# versioned by the matching control directory). We use the control directories
3267
# disk format string as a key for the network_name because they meet the
3268
# constraints (simple string, unique, immutable).
3269
network_format_registry.register_lazy(
3270
"Bazaar-NG branch, format 5\n",
3271
'bzrlib.repofmt.weaverepo',
3272
'RepositoryFormat5',
3274
network_format_registry.register_lazy(
3275
"Bazaar-NG branch, format 6\n",
3276
'bzrlib.repofmt.weaverepo',
3277
'RepositoryFormat6',
3226
3280
# formats which have no format string are not discoverable or independently
3227
3281
# creatable on disk, so are not registered in format_registry. They're
3228
# all in bzrlib.repofmt.knitreponow. When an instance of one of these is
3282
# all in bzrlib.repofmt.weaverepo now. When an instance of one of these is
3229
3283
# needed, it's constructed directly by the BzrDir. Non-native formats where
3230
3284
# the repository is not separately opened are similar.
3232
3286
format_registry.register_lazy(
3287
'Bazaar-NG Repository format 7',
3288
'bzrlib.repofmt.weaverepo',
3292
format_registry.register_lazy(
3233
3293
'Bazaar-NG Knit Repository Format 1',
3234
3294
'bzrlib.repofmt.knitrepo',
3235
3295
'RepositoryFormatKnit1',
3252
3312
# NOTE: These are experimental in 0.92. Stable in 1.0 and above
3253
3313
format_registry.register_lazy(
3254
3314
'Bazaar pack repository format 1 (needs bzr 0.92)\n',
3255
'bzrlib.repofmt.knitpack_repo',
3315
'bzrlib.repofmt.pack_repo',
3256
3316
'RepositoryFormatKnitPack1',
3258
3318
format_registry.register_lazy(
3259
3319
'Bazaar pack repository format 1 with subtree support (needs bzr 0.92)\n',
3260
'bzrlib.repofmt.knitpack_repo',
3320
'bzrlib.repofmt.pack_repo',
3261
3321
'RepositoryFormatKnitPack3',
3263
3323
format_registry.register_lazy(
3264
3324
'Bazaar pack repository format 1 with rich root (needs bzr 1.0)\n',
3265
'bzrlib.repofmt.knitpack_repo',
3325
'bzrlib.repofmt.pack_repo',
3266
3326
'RepositoryFormatKnitPack4',
3268
3328
format_registry.register_lazy(
3269
3329
'Bazaar RepositoryFormatKnitPack5 (bzr 1.6)\n',
3270
'bzrlib.repofmt.knitpack_repo',
3330
'bzrlib.repofmt.pack_repo',
3271
3331
'RepositoryFormatKnitPack5',
3273
3333
format_registry.register_lazy(
3274
3334
'Bazaar RepositoryFormatKnitPack5RichRoot (bzr 1.6.1)\n',
3275
'bzrlib.repofmt.knitpack_repo',
3335
'bzrlib.repofmt.pack_repo',
3276
3336
'RepositoryFormatKnitPack5RichRoot',
3278
3338
format_registry.register_lazy(
3279
3339
'Bazaar RepositoryFormatKnitPack5RichRoot (bzr 1.6)\n',
3280
'bzrlib.repofmt.knitpack_repo',
3340
'bzrlib.repofmt.pack_repo',
3281
3341
'RepositoryFormatKnitPack5RichRootBroken',
3283
3343
format_registry.register_lazy(
3284
3344
'Bazaar RepositoryFormatKnitPack6 (bzr 1.9)\n',
3285
'bzrlib.repofmt.knitpack_repo',
3345
'bzrlib.repofmt.pack_repo',
3286
3346
'RepositoryFormatKnitPack6',
3288
3348
format_registry.register_lazy(
3289
3349
'Bazaar RepositoryFormatKnitPack6RichRoot (bzr 1.9)\n',
3290
'bzrlib.repofmt.knitpack_repo',
3350
'bzrlib.repofmt.pack_repo',
3291
3351
'RepositoryFormatKnitPack6RichRoot',
3293
format_registry.register_lazy(
3294
'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
3295
'bzrlib.repofmt.groupcompress_repo',
3296
'RepositoryFormat2a',
3299
3354
# Development formats.
3300
# Check their docstrings to see if/when they are obsolete.
3355
# Obsolete but kept pending a CHK based subtree format.
3301
3356
format_registry.register_lazy(
3302
3357
("Bazaar development format 2 with subtree support "
3303
3358
"(needs bzr.dev from before 1.8)\n"),
3304
'bzrlib.repofmt.knitpack_repo',
3359
'bzrlib.repofmt.pack_repo',
3305
3360
'RepositoryFormatPackDevelopment2Subtree',
3363
# 1.14->1.16 go below here
3364
format_registry.register_lazy(
3365
'Bazaar development format - group compression and chk inventory'
3366
' (needs bzr.dev from 1.14)\n',
3367
'bzrlib.repofmt.groupcompress_repo',
3368
'RepositoryFormatCHK1',
3371
format_registry.register_lazy(
3372
'Bazaar development format - chk repository with bencode revision '
3373
'serialization (needs bzr.dev from 1.16)\n',
3374
'bzrlib.repofmt.groupcompress_repo',
3375
'RepositoryFormatCHK2',
3377
format_registry.register_lazy(
3378
'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
3379
'bzrlib.repofmt.groupcompress_repo',
3380
'RepositoryFormat2a',
3307
3382
format_registry.register_lazy(
3308
3383
'Bazaar development format 8\n',
3309
3384
'bzrlib.repofmt.groupcompress_repo',
3424
3496
return searcher.get_result()
3426
3498
@needs_read_lock
3427
def search_missing_revision_ids(self,
3428
revision_id=symbol_versioning.DEPRECATED_PARAMETER,
3429
find_ghosts=True, revision_ids=None, if_present_ids=None):
3499
def search_missing_revision_ids(self, revision_id=None, find_ghosts=True):
3430
3500
"""Return the revision ids that source has that target does not.
3432
3502
:param revision_id: only return revision ids included by this
3434
:param revision_ids: return revision ids included by these
3435
revision_ids. NoSuchRevision will be raised if any of these
3436
revisions are not present.
3437
:param if_present_ids: like revision_ids, but will not cause
3438
NoSuchRevision if any of these are absent, instead they will simply
3439
not be in the result. This is useful for e.g. finding revisions
3440
to fetch for tags, which may reference absent revisions.
3441
3504
:param find_ghosts: If True find missing revisions in deep history
3442
3505
rather than just finding the surface difference.
3443
3506
:return: A bzrlib.graph.SearchResult.
3445
if symbol_versioning.deprecated_passed(revision_id):
3446
symbol_versioning.warn(
3447
'search_missing_revision_ids(revision_id=...) was '
3448
'deprecated in 2.4. Use revision_ids=[...] instead.',
3449
DeprecationWarning, stacklevel=2)
3450
if revision_ids is not None:
3451
raise AssertionError(
3452
'revision_ids is mutually exclusive with revision_id')
3453
if revision_id is not None:
3454
revision_ids = [revision_id]
3456
3508
# stop searching at found target revisions.
3457
if not find_ghosts and (revision_ids is not None or if_present_ids is
3459
return self._walk_to_common_revisions(revision_ids,
3460
if_present_ids=if_present_ids)
3509
if not find_ghosts and revision_id is not None:
3510
return self._walk_to_common_revisions([revision_id])
3461
3511
# generic, possibly worst case, slow code path.
3462
3512
target_ids = set(self.target.all_revision_ids())
3463
source_ids = self._present_source_revisions_for(
3464
revision_ids, if_present_ids)
3513
if revision_id is not None:
3514
source_ids = self.source.get_ancestry(revision_id)
3515
if source_ids[0] is not None:
3516
raise AssertionError()
3519
source_ids = self.source.all_revision_ids()
3465
3520
result_set = set(source_ids).difference(target_ids)
3466
3521
return self.source.revision_ids_to_search_result(result_set)
3468
def _present_source_revisions_for(self, revision_ids, if_present_ids=None):
3469
"""Returns set of all revisions in ancestry of revision_ids present in
3472
:param revision_ids: if None, all revisions in source are returned.
3473
:param if_present_ids: like revision_ids, but if any/all of these are
3474
absent no error is raised.
3476
if revision_ids is not None or if_present_ids is not None:
3477
# First, ensure all specified revisions exist. Callers expect
3478
# NoSuchRevision when they pass absent revision_ids here.
3479
if revision_ids is None:
3480
revision_ids = set()
3481
if if_present_ids is None:
3482
if_present_ids = set()
3483
revision_ids = set(revision_ids)
3484
if_present_ids = set(if_present_ids)
3485
all_wanted_ids = revision_ids.union(if_present_ids)
3486
graph = self.source.get_graph()
3487
present_revs = set(graph.get_parent_map(all_wanted_ids))
3488
missing = revision_ids.difference(present_revs)
3490
raise errors.NoSuchRevision(self.source, missing.pop())
3491
found_ids = all_wanted_ids.intersection(present_revs)
3492
source_ids = [rev_id for (rev_id, parents) in
3493
graph.iter_ancestry(found_ids)
3494
if rev_id != _mod_revision.NULL_REVISION
3495
and parents is not None]
3497
source_ids = self.source.all_revision_ids()
3498
return set(source_ids)
3501
3524
def _same_model(source, target):
3502
3525
"""True if source and target have the same data representation.
3543
3566
return InterRepository._same_model(source, target)
3569
class InterWeaveRepo(InterSameDataRepository):
3570
"""Optimised code paths between Weave based repositories.
3572
This should be in bzrlib/repofmt/weaverepo.py but we have not yet
3573
implemented lazy inter-object optimisation.
3577
def _get_repo_format_to_test(self):
3578
from bzrlib.repofmt import weaverepo
3579
return weaverepo.RepositoryFormat7()
3582
def is_compatible(source, target):
3583
"""Be compatible with known Weave formats.
3585
We don't test for the stores being of specific types because that
3586
could lead to confusing results, and there is no need to be
3589
from bzrlib.repofmt.weaverepo import (
3595
return (isinstance(source._format, (RepositoryFormat5,
3597
RepositoryFormat7)) and
3598
isinstance(target._format, (RepositoryFormat5,
3600
RepositoryFormat7)))
3601
except AttributeError:
3605
def copy_content(self, revision_id=None):
3606
"""See InterRepository.copy_content()."""
3607
# weave specific optimised path:
3609
self.target.set_make_working_trees(self.source.make_working_trees())
3610
except (errors.RepositoryUpgradeRequired, NotImplemented):
3612
# FIXME do not peek!
3613
if self.source._transport.listable():
3614
pb = ui.ui_factory.nested_progress_bar()
3616
self.target.texts.insert_record_stream(
3617
self.source.texts.get_record_stream(
3618
self.source.texts.keys(), 'topological', False))
3619
pb.update('Copying inventory', 0, 1)
3620
self.target.inventories.insert_record_stream(
3621
self.source.inventories.get_record_stream(
3622
self.source.inventories.keys(), 'topological', False))
3623
self.target.signatures.insert_record_stream(
3624
self.source.signatures.get_record_stream(
3625
self.source.signatures.keys(),
3627
self.target.revisions.insert_record_stream(
3628
self.source.revisions.get_record_stream(
3629
self.source.revisions.keys(),
3630
'topological', True))
3634
self.target.fetch(self.source, revision_id=revision_id)
3637
def search_missing_revision_ids(self, revision_id=None, find_ghosts=True):
3638
"""See InterRepository.missing_revision_ids()."""
3639
# we want all revisions to satisfy revision_id in source.
3640
# but we don't want to stat every file here and there.
3641
# we want then, all revisions other needs to satisfy revision_id
3642
# checked, but not those that we have locally.
3643
# so the first thing is to get a subset of the revisions to
3644
# satisfy revision_id in source, and then eliminate those that
3645
# we do already have.
3646
# this is slow on high latency connection to self, but as this
3647
# disk format scales terribly for push anyway due to rewriting
3648
# inventory.weave, this is considered acceptable.
3650
if revision_id is not None:
3651
source_ids = self.source.get_ancestry(revision_id)
3652
if source_ids[0] is not None:
3653
raise AssertionError()
3656
source_ids = self.source._all_possible_ids()
3657
source_ids_set = set(source_ids)
3658
# source_ids is the worst possible case we may need to pull.
3659
# now we want to filter source_ids against what we actually
3660
# have in target, but don't try to check for existence where we know
3661
# we do not have a revision as that would be pointless.
3662
target_ids = set(self.target._all_possible_ids())
3663
possibly_present_revisions = target_ids.intersection(source_ids_set)
3664
actually_present_revisions = set(
3665
self.target._eliminate_revisions_not_present(possibly_present_revisions))
3666
required_revisions = source_ids_set.difference(actually_present_revisions)
3667
if revision_id is not None:
3668
# we used get_ancestry to determine source_ids then we are assured all
3669
# revisions referenced are present as they are installed in topological order.
3670
# and the tip revision was validated by get_ancestry.
3671
result_set = required_revisions
3673
# if we just grabbed the possibly available ids, then
3674
# we only have an estimate of whats available and need to validate
3675
# that against the revision records.
3677
self.source._eliminate_revisions_not_present(required_revisions))
3678
return self.source.revision_ids_to_search_result(result_set)
3681
class InterKnitRepo(InterSameDataRepository):
3682
"""Optimised code paths between Knit based repositories."""
3685
def _get_repo_format_to_test(self):
3686
from bzrlib.repofmt import knitrepo
3687
return knitrepo.RepositoryFormatKnit1()
3690
def is_compatible(source, target):
3691
"""Be compatible with known Knit formats.
3693
We don't test for the stores being of specific types because that
3694
could lead to confusing results, and there is no need to be
3697
from bzrlib.repofmt.knitrepo import RepositoryFormatKnit
3699
are_knits = (isinstance(source._format, RepositoryFormatKnit) and
3700
isinstance(target._format, RepositoryFormatKnit))
3701
except AttributeError:
3703
return are_knits and InterRepository._same_model(source, target)
3706
def search_missing_revision_ids(self, revision_id=None, find_ghosts=True):
3707
"""See InterRepository.missing_revision_ids()."""
3708
if revision_id is not None:
3709
source_ids = self.source.get_ancestry(revision_id)
3710
if source_ids[0] is not None:
3711
raise AssertionError()
3714
source_ids = self.source.all_revision_ids()
3715
source_ids_set = set(source_ids)
3716
# source_ids is the worst possible case we may need to pull.
3717
# now we want to filter source_ids against what we actually
3718
# have in target, but don't try to check for existence where we know
3719
# we do not have a revision as that would be pointless.
3720
target_ids = set(self.target.all_revision_ids())
3721
possibly_present_revisions = target_ids.intersection(source_ids_set)
3722
actually_present_revisions = set(
3723
self.target._eliminate_revisions_not_present(possibly_present_revisions))
3724
required_revisions = source_ids_set.difference(actually_present_revisions)
3725
if revision_id is not None:
3726
# we used get_ancestry to determine source_ids then we are assured all
3727
# revisions referenced are present as they are installed in topological order.
3728
# and the tip revision was validated by get_ancestry.
3729
result_set = required_revisions
3731
# if we just grabbed the possibly available ids, then
3732
# we only have an estimate of whats available and need to validate
3733
# that against the revision records.
3735
self.source._eliminate_revisions_not_present(required_revisions))
3736
return self.source.revision_ids_to_search_result(result_set)
3546
3739
class InterDifferingSerializer(InterRepository):
4039
4272
is_resume = False
4041
4274
# locked_insert_stream performs a commit|suspend.
4042
missing_keys = self.insert_stream_without_locking(stream,
4043
src_format, is_resume)
4045
# suspend the write group and tell the caller what we is
4046
# missing. We know we can suspend or else we would not have
4047
# entered this code path. (All repositories that can handle
4048
# missing keys can handle suspending a write group).
4049
write_group_tokens = self.target_repo.suspend_write_group()
4050
return write_group_tokens, missing_keys
4051
hint = self.target_repo.commit_write_group()
4052
to_serializer = self.target_repo._format._serializer
4053
src_serializer = src_format._serializer
4054
if (to_serializer != src_serializer and
4055
self.target_repo._format.pack_compresses):
4056
self.target_repo.pack(hint=hint)
4275
return self._locked_insert_stream(stream, src_format,
4059
4278
self.target_repo.abort_write_group(suppress_errors=True)
4062
4281
self.target_repo.unlock()
4064
def insert_stream_without_locking(self, stream, src_format,
4066
"""Insert a stream's content into the target repository.
4068
This assumes that you already have a locked repository and an active
4071
:param src_format: a bzr repository format.
4072
:param is_resume: Passed down to get_missing_parent_inventories to
4073
indicate if we should be checking for missing texts at the same
4076
:return: A set of keys that are missing.
4078
if not self.target_repo.is_write_locked():
4079
raise errors.ObjectNotLocked(self)
4080
if not self.target_repo.is_in_write_group():
4081
raise errors.BzrError('you must already be in a write group')
4283
def _locked_insert_stream(self, stream, src_format, is_resume):
4082
4284
to_serializer = self.target_repo._format._serializer
4083
4285
src_serializer = src_format._serializer
4084
4286
new_pack = None