92
88
record_root_entry = True
93
89
# the default CommitBuilder does not manage trees whose root is versioned.
94
90
_versioned_root = False
91
# this commit builder supports the record_entry_contents interface
92
supports_record_entry_contents = True
96
94
def __init__(self, repository, parents, config, timestamp=None,
97
95
timezone=None, committer=None, revprops=None,
96
revision_id=None, lossy=False):
99
97
"""Initiate a CommitBuilder.
101
99
:param repository: Repository to commit to.
102
100
:param parents: Revision ids of the parents of the new revision.
103
:param config: Configuration to use.
104
101
:param timestamp: Optional timestamp recorded for commit.
105
102
:param timezone: Optional timezone for timestamp.
106
103
:param committer: Optional committer to set for commit.
107
104
:param revprops: Optional dictionary of revision properties.
108
105
: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
110
109
self._config = config
112
112
if committer is None:
113
113
self._committer = self._config.username()
114
elif not isinstance(committer, unicode):
115
self._committer = committer.decode() # throw if non-ascii
115
117
self._committer = committer
170
172
self._validate_unicode_text(value,
171
173
'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'
173
210
def commit(self, message):
174
211
"""Make the actual commit.
1558
1591
@needs_read_lock
1559
def search_missing_revision_ids(self, other, revision_id=None, find_ghosts=True):
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):
1560
1595
"""Return the revision ids that other has that this does not.
1562
1597
These are returned in topological order.
1564
1599
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]
1566
1611
return InterRepository.get(other, self).search_missing_revision_ids(
1567
revision_id, find_ghosts)
1612
find_ghosts=find_ghosts, revision_ids=revision_ids,
1613
if_present_ids=if_present_ids)
1570
1616
def open(base):
2013
2059
w = self.inventories
2014
2060
pb = ui.ui_factory.nested_progress_bar()
2016
return self._find_text_key_references_from_xml_inventory_lines(
2062
return self._serializer._find_text_key_references(
2017
2063
w.iter_lines_added_or_present_in_keys(revision_keys, pb=pb))
2021
def _find_text_key_references_from_xml_inventory_lines(self,
2023
"""Core routine for extracting references to texts from inventories.
2025
This performs the translation of xml lines to revision ids.
2027
:param line_iterator: An iterator of lines, origin_version_id
2028
:return: A dictionary mapping text keys ((fileid, revision_id) tuples)
2029
to whether they were referred to by the inventory of the
2030
revision_id that they contain. Note that if that revision_id was
2031
not part of the line_iterator's output then False will be given -
2032
even though it may actually refer to that key.
2034
if not self._serializer.support_altered_by_hack:
2035
raise AssertionError(
2036
"_find_text_key_references_from_xml_inventory_lines only "
2037
"supported for branches which store inventory as unnested xml"
2038
", not on %r" % self)
2041
# this code needs to read every new line in every inventory for the
2042
# inventories [revision_ids]. Seeing a line twice is ok. Seeing a line
2043
# not present in one of those inventories is unnecessary but not
2044
# harmful because we are filtering by the revision id marker in the
2045
# inventory lines : we only select file ids altered in one of those
2046
# revisions. We don't need to see all lines in the inventory because
2047
# only those added in an inventory in rev X can contain a revision=X
2049
unescape_revid_cache = {}
2050
unescape_fileid_cache = {}
2052
# jam 20061218 In a big fetch, this handles hundreds of thousands
2053
# of lines, so it has had a lot of inlining and optimizing done.
2054
# Sorry that it is a little bit messy.
2055
# Move several functions to be local variables, since this is a long
2057
search = self._file_ids_altered_regex.search
2058
unescape = _unescape_xml
2059
setdefault = result.setdefault
2060
for line, line_key in line_iterator:
2061
match = search(line)
2064
# One call to match.group() returning multiple items is quite a
2065
# bit faster than 2 calls to match.group() each returning 1
2066
file_id, revision_id = match.group('file_id', 'revision_id')
2068
# Inlining the cache lookups helps a lot when you make 170,000
2069
# lines and 350k ids, versus 8.4 unique ids.
2070
# Using a cache helps in 2 ways:
2071
# 1) Avoids unnecessary decoding calls
2072
# 2) Re-uses cached strings, which helps in future set and
2074
# (2) is enough that removing encoding entirely along with
2075
# the cache (so we are using plain strings) results in no
2076
# performance improvement.
2078
revision_id = unescape_revid_cache[revision_id]
2080
unescaped = unescape(revision_id)
2081
unescape_revid_cache[revision_id] = unescaped
2082
revision_id = unescaped
2084
# Note that unconditionally unescaping means that we deserialise
2085
# every fileid, which for general 'pull' is not great, but we don't
2086
# really want to have some many fulltexts that this matters anyway.
2089
file_id = unescape_fileid_cache[file_id]
2091
unescaped = unescape(file_id)
2092
unescape_fileid_cache[file_id] = unescaped
2095
key = (file_id, revision_id)
2096
setdefault(key, False)
2097
if revision_id == line_key[-1]:
2101
2067
def _inventory_xml_lines_for_keys(self, keys):
2102
2068
"""Get a line iterator of the sort needed for findind references.
2816
2773
except UnicodeDecodeError:
2817
2774
raise errors.NonAsciiRevisionId(method, self)
2819
def revision_graph_can_have_wrong_parents(self):
2820
"""Is it possible for this repository to have a revision graph with
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.
2823
If True, then this repository must also implement
2824
_find_inconsistent_revision_parents so that check and reconcile can
2825
check for inconsistencies before proceeding with other checks that may
2826
depend on the revision index being consistent.
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).
2828
raise NotImplementedError(self.revision_graph_can_have_wrong_parents)
2831
# remove these delegates a while after bzr 0.15
2832
def __make_delegated(name, from_module):
2833
def _deprecated_repository_forwarder():
2834
symbol_versioning.warn('%s moved to %s in bzr 0.15'
2835
% (name, from_module),
2838
m = __import__(from_module, globals(), locals(), [name])
2840
return getattr(m, name)
2841
except AttributeError:
2842
raise AttributeError('module %s has no name %s'
2844
globals()[name] = _deprecated_repository_forwarder
2847
'AllInOneRepository',
2848
'WeaveMetaDirRepository',
2849
'PreSplitOutRepositoryFormat',
2850
'RepositoryFormat4',
2851
'RepositoryFormat5',
2852
'RepositoryFormat6',
2853
'RepositoryFormat7',
2855
__make_delegated(_name, 'bzrlib.repofmt.weaverepo')
2859
'RepositoryFormatKnit',
2860
'RepositoryFormatKnit1',
2862
__make_delegated(_name, 'bzrlib.repofmt.knitrepo')
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.")
2865
2808
def install_revision(repository, rev, revision_tree):
3271
3223
return self.get_format_string()
3274
# Pre-0.8 formats that don't have a disk format string (because they are
3275
# versioned by the matching control directory). We use the control directories
3276
# disk format string as a key for the network_name because they meet the
3277
# constraints (simple string, unique, immutable).
3278
network_format_registry.register_lazy(
3279
"Bazaar-NG branch, format 5\n",
3280
'bzrlib.repofmt.weaverepo',
3281
'RepositoryFormat5',
3283
network_format_registry.register_lazy(
3284
"Bazaar-NG branch, format 6\n",
3285
'bzrlib.repofmt.weaverepo',
3286
'RepositoryFormat6',
3289
3226
# formats which have no format string are not discoverable or independently
3290
3227
# creatable on disk, so are not registered in format_registry. They're
3291
# all in bzrlib.repofmt.weaverepo now. When an instance of one of these is
3228
# all in bzrlib.repofmt.knitreponow. When an instance of one of these is
3292
3229
# needed, it's constructed directly by the BzrDir. Non-native formats where
3293
3230
# the repository is not separately opened are similar.
3295
3232
format_registry.register_lazy(
3296
'Bazaar-NG Repository format 7',
3297
'bzrlib.repofmt.weaverepo',
3301
format_registry.register_lazy(
3302
3233
'Bazaar-NG Knit Repository Format 1',
3303
3234
'bzrlib.repofmt.knitrepo',
3304
3235
'RepositoryFormatKnit1',
3321
3252
# NOTE: These are experimental in 0.92. Stable in 1.0 and above
3322
3253
format_registry.register_lazy(
3323
3254
'Bazaar pack repository format 1 (needs bzr 0.92)\n',
3324
'bzrlib.repofmt.pack_repo',
3255
'bzrlib.repofmt.knitpack_repo',
3325
3256
'RepositoryFormatKnitPack1',
3327
3258
format_registry.register_lazy(
3328
3259
'Bazaar pack repository format 1 with subtree support (needs bzr 0.92)\n',
3329
'bzrlib.repofmt.pack_repo',
3260
'bzrlib.repofmt.knitpack_repo',
3330
3261
'RepositoryFormatKnitPack3',
3332
3263
format_registry.register_lazy(
3333
3264
'Bazaar pack repository format 1 with rich root (needs bzr 1.0)\n',
3334
'bzrlib.repofmt.pack_repo',
3265
'bzrlib.repofmt.knitpack_repo',
3335
3266
'RepositoryFormatKnitPack4',
3337
3268
format_registry.register_lazy(
3338
3269
'Bazaar RepositoryFormatKnitPack5 (bzr 1.6)\n',
3339
'bzrlib.repofmt.pack_repo',
3270
'bzrlib.repofmt.knitpack_repo',
3340
3271
'RepositoryFormatKnitPack5',
3342
3273
format_registry.register_lazy(
3343
3274
'Bazaar RepositoryFormatKnitPack5RichRoot (bzr 1.6.1)\n',
3344
'bzrlib.repofmt.pack_repo',
3275
'bzrlib.repofmt.knitpack_repo',
3345
3276
'RepositoryFormatKnitPack5RichRoot',
3347
3278
format_registry.register_lazy(
3348
3279
'Bazaar RepositoryFormatKnitPack5RichRoot (bzr 1.6)\n',
3349
'bzrlib.repofmt.pack_repo',
3280
'bzrlib.repofmt.knitpack_repo',
3350
3281
'RepositoryFormatKnitPack5RichRootBroken',
3352
3283
format_registry.register_lazy(
3353
3284
'Bazaar RepositoryFormatKnitPack6 (bzr 1.9)\n',
3354
'bzrlib.repofmt.pack_repo',
3285
'bzrlib.repofmt.knitpack_repo',
3355
3286
'RepositoryFormatKnitPack6',
3357
3288
format_registry.register_lazy(
3358
3289
'Bazaar RepositoryFormatKnitPack6RichRoot (bzr 1.9)\n',
3359
'bzrlib.repofmt.pack_repo',
3290
'bzrlib.repofmt.knitpack_repo',
3360
3291
'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',
3363
3299
# Development formats.
3364
# Obsolete but kept pending a CHK based subtree format.
3300
# Check their docstrings to see if/when they are obsolete.
3365
3301
format_registry.register_lazy(
3366
3302
("Bazaar development format 2 with subtree support "
3367
3303
"(needs bzr.dev from before 1.8)\n"),
3368
'bzrlib.repofmt.pack_repo',
3304
'bzrlib.repofmt.knitpack_repo',
3369
3305
'RepositoryFormatPackDevelopment2Subtree',
3372
# 1.14->1.16 go below here
3373
format_registry.register_lazy(
3374
'Bazaar development format - group compression and chk inventory'
3375
' (needs bzr.dev from 1.14)\n',
3376
'bzrlib.repofmt.groupcompress_repo',
3377
'RepositoryFormatCHK1',
3380
format_registry.register_lazy(
3381
'Bazaar development format - chk repository with bencode revision '
3382
'serialization (needs bzr.dev from 1.16)\n',
3383
'bzrlib.repofmt.groupcompress_repo',
3384
'RepositoryFormatCHK2',
3386
format_registry.register_lazy(
3387
'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
3388
'bzrlib.repofmt.groupcompress_repo',
3389
'RepositoryFormat2a',
3307
format_registry.register_lazy(
3308
'Bazaar development format 8\n',
3309
'bzrlib.repofmt.groupcompress_repo',
3310
'RepositoryFormat2aSubtree',
3500
3424
return searcher.get_result()
3502
3426
@needs_read_lock
3503
def search_missing_revision_ids(self, revision_id=None, find_ghosts=True):
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):
3504
3430
"""Return the revision ids that source has that target does not.
3506
3432
: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.
3508
3441
:param find_ghosts: If True find missing revisions in deep history
3509
3442
rather than just finding the surface difference.
3510
3443
: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]
3512
3456
# stop searching at found target revisions.
3513
if not find_ghosts and revision_id is not None:
3514
return self._walk_to_common_revisions([revision_id])
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)
3515
3461
# generic, possibly worst case, slow code path.
3516
3462
target_ids = set(self.target.all_revision_ids())
3517
if revision_id is not None:
3518
source_ids = self.source.get_ancestry(revision_id)
3519
if source_ids[0] is not None:
3520
raise AssertionError()
3523
source_ids = self.source.all_revision_ids()
3463
source_ids = self._present_source_revisions_for(
3464
revision_ids, if_present_ids)
3524
3465
result_set = set(source_ids).difference(target_ids)
3525
3466
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)
3528
3501
def _same_model(source, target):
3529
3502
"""True if source and target have the same data representation.
3570
3543
return InterRepository._same_model(source, target)
3573
class InterWeaveRepo(InterSameDataRepository):
3574
"""Optimised code paths between Weave based repositories.
3576
This should be in bzrlib/repofmt/weaverepo.py but we have not yet
3577
implemented lazy inter-object optimisation.
3581
def _get_repo_format_to_test(self):
3582
from bzrlib.repofmt import weaverepo
3583
return weaverepo.RepositoryFormat7()
3586
def is_compatible(source, target):
3587
"""Be compatible with known Weave formats.
3589
We don't test for the stores being of specific types because that
3590
could lead to confusing results, and there is no need to be
3593
from bzrlib.repofmt.weaverepo import (
3599
return (isinstance(source._format, (RepositoryFormat5,
3601
RepositoryFormat7)) and
3602
isinstance(target._format, (RepositoryFormat5,
3604
RepositoryFormat7)))
3605
except AttributeError:
3609
def copy_content(self, revision_id=None):
3610
"""See InterRepository.copy_content()."""
3611
# weave specific optimised path:
3613
self.target.set_make_working_trees(self.source.make_working_trees())
3614
except (errors.RepositoryUpgradeRequired, NotImplemented):
3616
# FIXME do not peek!
3617
if self.source._transport.listable():
3618
pb = ui.ui_factory.nested_progress_bar()
3620
self.target.texts.insert_record_stream(
3621
self.source.texts.get_record_stream(
3622
self.source.texts.keys(), 'topological', False))
3623
pb.update('Copying inventory', 0, 1)
3624
self.target.inventories.insert_record_stream(
3625
self.source.inventories.get_record_stream(
3626
self.source.inventories.keys(), 'topological', False))
3627
self.target.signatures.insert_record_stream(
3628
self.source.signatures.get_record_stream(
3629
self.source.signatures.keys(),
3631
self.target.revisions.insert_record_stream(
3632
self.source.revisions.get_record_stream(
3633
self.source.revisions.keys(),
3634
'topological', True))
3638
self.target.fetch(self.source, revision_id=revision_id)
3641
def search_missing_revision_ids(self, revision_id=None, find_ghosts=True):
3642
"""See InterRepository.missing_revision_ids()."""
3643
# we want all revisions to satisfy revision_id in source.
3644
# but we don't want to stat every file here and there.
3645
# we want then, all revisions other needs to satisfy revision_id
3646
# checked, but not those that we have locally.
3647
# so the first thing is to get a subset of the revisions to
3648
# satisfy revision_id in source, and then eliminate those that
3649
# we do already have.
3650
# this is slow on high latency connection to self, but as this
3651
# disk format scales terribly for push anyway due to rewriting
3652
# inventory.weave, this is considered acceptable.
3654
if revision_id is not None:
3655
source_ids = self.source.get_ancestry(revision_id)
3656
if source_ids[0] is not None:
3657
raise AssertionError()
3660
source_ids = self.source._all_possible_ids()
3661
source_ids_set = set(source_ids)
3662
# source_ids is the worst possible case we may need to pull.
3663
# now we want to filter source_ids against what we actually
3664
# have in target, but don't try to check for existence where we know
3665
# we do not have a revision as that would be pointless.
3666
target_ids = set(self.target._all_possible_ids())
3667
possibly_present_revisions = target_ids.intersection(source_ids_set)
3668
actually_present_revisions = set(
3669
self.target._eliminate_revisions_not_present(possibly_present_revisions))
3670
required_revisions = source_ids_set.difference(actually_present_revisions)
3671
if revision_id is not None:
3672
# we used get_ancestry to determine source_ids then we are assured all
3673
# revisions referenced are present as they are installed in topological order.
3674
# and the tip revision was validated by get_ancestry.
3675
result_set = required_revisions
3677
# if we just grabbed the possibly available ids, then
3678
# we only have an estimate of whats available and need to validate
3679
# that against the revision records.
3681
self.source._eliminate_revisions_not_present(required_revisions))
3682
return self.source.revision_ids_to_search_result(result_set)
3685
class InterKnitRepo(InterSameDataRepository):
3686
"""Optimised code paths between Knit based repositories."""
3689
def _get_repo_format_to_test(self):
3690
from bzrlib.repofmt import knitrepo
3691
return knitrepo.RepositoryFormatKnit1()
3694
def is_compatible(source, target):
3695
"""Be compatible with known Knit formats.
3697
We don't test for the stores being of specific types because that
3698
could lead to confusing results, and there is no need to be
3701
from bzrlib.repofmt.knitrepo import RepositoryFormatKnit
3703
are_knits = (isinstance(source._format, RepositoryFormatKnit) and
3704
isinstance(target._format, RepositoryFormatKnit))
3705
except AttributeError:
3707
return are_knits and InterRepository._same_model(source, target)
3710
def search_missing_revision_ids(self, revision_id=None, find_ghosts=True):
3711
"""See InterRepository.missing_revision_ids()."""
3712
if revision_id is not None:
3713
source_ids = self.source.get_ancestry(revision_id)
3714
if source_ids[0] is not None:
3715
raise AssertionError()
3718
source_ids = self.source.all_revision_ids()
3719
source_ids_set = set(source_ids)
3720
# source_ids is the worst possible case we may need to pull.
3721
# now we want to filter source_ids against what we actually
3722
# have in target, but don't try to check for existence where we know
3723
# we do not have a revision as that would be pointless.
3724
target_ids = set(self.target.all_revision_ids())
3725
possibly_present_revisions = target_ids.intersection(source_ids_set)
3726
actually_present_revisions = set(
3727
self.target._eliminate_revisions_not_present(possibly_present_revisions))
3728
required_revisions = source_ids_set.difference(actually_present_revisions)
3729
if revision_id is not None:
3730
# we used get_ancestry to determine source_ids then we are assured all
3731
# revisions referenced are present as they are installed in topological order.
3732
# and the tip revision was validated by get_ancestry.
3733
result_set = required_revisions
3735
# if we just grabbed the possibly available ids, then
3736
# we only have an estimate of whats available and need to validate
3737
# that against the revision records.
3739
self.source._eliminate_revisions_not_present(required_revisions))
3740
return self.source.revision_ids_to_search_result(result_set)
3743
3546
class InterDifferingSerializer(InterRepository):
4283
4039
is_resume = False
4285
4041
# locked_insert_stream performs a commit|suspend.
4286
return self._locked_insert_stream(stream, src_format, is_resume)
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)
4288
4059
self.target_repo.abort_write_group(suppress_errors=True)
4291
4062
self.target_repo.unlock()
4293
def _locked_insert_stream(self, stream, src_format, is_resume):
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')
4294
4082
to_serializer = self.target_repo._format._serializer
4295
4083
src_serializer = src_format._serializer
4296
4084
new_pack = None