82
88
record_root_entry = True
83
89
# the default CommitBuilder does not manage trees whose root is versioned.
84
90
_versioned_root = False
91
# this commit builder supports the record_entry_contents interface
92
supports_record_entry_contents = True
86
94
def __init__(self, repository, parents, config, timestamp=None,
87
95
timezone=None, committer=None, revprops=None,
96
revision_id=None, lossy=False):
89
97
"""Initiate a CommitBuilder.
91
99
:param repository: Repository to commit to.
92
100
:param parents: Revision ids of the parents of the new revision.
93
:param config: Configuration to use.
94
101
:param timestamp: Optional timestamp recorded for commit.
95
102
:param timezone: Optional timezone for timestamp.
96
103
:param committer: Optional committer to set for commit.
97
104
:param revprops: Optional dictionary of revision properties.
98
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
100
109
self._config = config
102
112
if committer is None:
103
113
self._committer = self._config.username()
114
elif not isinstance(committer, unicode):
115
self._committer = committer.decode() # throw if non-ascii
105
117
self._committer = committer
160
172
self._validate_unicode_text(value,
161
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'
163
210
def commit(self, message):
164
211
"""Make the actual commit.
1524
1591
@needs_read_lock
1525
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):
1526
1595
"""Return the revision ids that other has that this does not.
1528
1597
These are returned in topological order.
1530
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]
1532
1611
return InterRepository.get(other, self).search_missing_revision_ids(
1533
revision_id, find_ghosts)
1612
find_ghosts=find_ghosts, revision_ids=revision_ids,
1613
if_present_ids=if_present_ids)
1536
1616
def open(base):
1979
2059
w = self.inventories
1980
2060
pb = ui.ui_factory.nested_progress_bar()
1982
return self._find_text_key_references_from_xml_inventory_lines(
2062
return self._serializer._find_text_key_references(
1983
2063
w.iter_lines_added_or_present_in_keys(revision_keys, pb=pb))
1987
def _find_text_key_references_from_xml_inventory_lines(self,
1989
"""Core routine for extracting references to texts from inventories.
1991
This performs the translation of xml lines to revision ids.
1993
:param line_iterator: An iterator of lines, origin_version_id
1994
:return: A dictionary mapping text keys ((fileid, revision_id) tuples)
1995
to whether they were referred to by the inventory of the
1996
revision_id that they contain. Note that if that revision_id was
1997
not part of the line_iterator's output then False will be given -
1998
even though it may actually refer to that key.
2000
if not self._serializer.support_altered_by_hack:
2001
raise AssertionError(
2002
"_find_text_key_references_from_xml_inventory_lines only "
2003
"supported for branches which store inventory as unnested xml"
2004
", not on %r" % self)
2007
# this code needs to read every new line in every inventory for the
2008
# inventories [revision_ids]. Seeing a line twice is ok. Seeing a line
2009
# not present in one of those inventories is unnecessary but not
2010
# harmful because we are filtering by the revision id marker in the
2011
# inventory lines : we only select file ids altered in one of those
2012
# revisions. We don't need to see all lines in the inventory because
2013
# only those added in an inventory in rev X can contain a revision=X
2015
unescape_revid_cache = {}
2016
unescape_fileid_cache = {}
2018
# jam 20061218 In a big fetch, this handles hundreds of thousands
2019
# of lines, so it has had a lot of inlining and optimizing done.
2020
# Sorry that it is a little bit messy.
2021
# Move several functions to be local variables, since this is a long
2023
search = self._file_ids_altered_regex.search
2024
unescape = _unescape_xml
2025
setdefault = result.setdefault
2026
for line, line_key in line_iterator:
2027
match = search(line)
2030
# One call to match.group() returning multiple items is quite a
2031
# bit faster than 2 calls to match.group() each returning 1
2032
file_id, revision_id = match.group('file_id', 'revision_id')
2034
# Inlining the cache lookups helps a lot when you make 170,000
2035
# lines and 350k ids, versus 8.4 unique ids.
2036
# Using a cache helps in 2 ways:
2037
# 1) Avoids unnecessary decoding calls
2038
# 2) Re-uses cached strings, which helps in future set and
2040
# (2) is enough that removing encoding entirely along with
2041
# the cache (so we are using plain strings) results in no
2042
# performance improvement.
2044
revision_id = unescape_revid_cache[revision_id]
2046
unescaped = unescape(revision_id)
2047
unescape_revid_cache[revision_id] = unescaped
2048
revision_id = unescaped
2050
# Note that unconditionally unescaping means that we deserialise
2051
# every fileid, which for general 'pull' is not great, but we don't
2052
# really want to have some many fulltexts that this matters anyway.
2055
file_id = unescape_fileid_cache[file_id]
2057
unescaped = unescape(file_id)
2058
unescape_fileid_cache[file_id] = unescaped
2061
key = (file_id, revision_id)
2062
setdefault(key, False)
2063
if revision_id == line_key[-1]:
2067
2067
def _inventory_xml_lines_for_keys(self, keys):
2068
2068
"""Get a line iterator of the sort needed for findind references.
2634
2623
result[revision_id] = (_mod_revision.NULL_REVISION,)
2626
def _get_parent_map_no_fallbacks(self, revision_ids):
2627
"""Same as Repository.get_parent_map except doesn't query fallbacks."""
2628
# revisions index works in keys; this just works in revisions
2629
# therefore wrap and unwrap
2632
for revision_id in revision_ids:
2633
if revision_id == _mod_revision.NULL_REVISION:
2634
result[revision_id] = ()
2635
elif revision_id is None:
2636
raise ValueError('get_parent_map(None) is not valid')
2638
query_keys.append((revision_id ,))
2639
vf = self.revisions.without_fallbacks()
2640
for ((revision_id,), parent_keys) in \
2641
vf.get_parent_map(query_keys).iteritems():
2643
result[revision_id] = tuple([parent_revid
2644
for (parent_revid,) in parent_keys])
2646
result[revision_id] = (_mod_revision.NULL_REVISION,)
2637
2649
def _make_parents_provider(self):
2650
if not self._format.supports_external_lookups:
2652
return graph.StackedParentsProvider(_FallbacksList(self))
2654
def _make_parents_provider_with_no_fallbacks(self):
2655
return graph.CallableToParentsProviderAdapter(
2656
self._get_parent_map_no_fallbacks)
2640
2658
@needs_read_lock
2641
2659
def get_known_graph_ancestry(self, revision_ids):
2782
2802
except UnicodeDecodeError:
2783
2803
raise errors.NonAsciiRevisionId(method, self)
2785
def revision_graph_can_have_wrong_parents(self):
2786
"""Is it possible for this repository to have a revision graph with
2805
def _find_inconsistent_revision_parents(self, revisions_iterator=None):
2806
"""Find revisions with different parent lists in the revision object
2807
and in the index graph.
2789
If True, then this repository must also implement
2790
_find_inconsistent_revision_parents so that check and reconcile can
2791
check for inconsistencies before proceeding with other checks that may
2792
depend on the revision index being consistent.
2809
:param revisions_iterator: None, or an iterator of (revid,
2810
Revision-or-None). This iterator controls the revisions checked.
2811
:returns: an iterator yielding tuples of (revison-id, parents-in-index,
2812
parents-in-revision).
2794
raise NotImplementedError(self.revision_graph_can_have_wrong_parents)
2797
# remove these delegates a while after bzr 0.15
2798
def __make_delegated(name, from_module):
2799
def _deprecated_repository_forwarder():
2800
symbol_versioning.warn('%s moved to %s in bzr 0.15'
2801
% (name, from_module),
2804
m = __import__(from_module, globals(), locals(), [name])
2806
return getattr(m, name)
2807
except AttributeError:
2808
raise AttributeError('module %s has no name %s'
2810
globals()[name] = _deprecated_repository_forwarder
2813
'AllInOneRepository',
2814
'WeaveMetaDirRepository',
2815
'PreSplitOutRepositoryFormat',
2816
'RepositoryFormat4',
2817
'RepositoryFormat5',
2818
'RepositoryFormat6',
2819
'RepositoryFormat7',
2821
__make_delegated(_name, 'bzrlib.repofmt.weaverepo')
2825
'RepositoryFormatKnit',
2826
'RepositoryFormatKnit1',
2828
__make_delegated(_name, 'bzrlib.repofmt.knitrepo')
2814
if not self.is_locked():
2815
raise AssertionError()
2817
if revisions_iterator is None:
2818
revisions_iterator = self._iter_revisions(None)
2819
for revid, revision in revisions_iterator:
2820
if revision is None:
2822
parent_map = vf.get_parent_map([(revid,)])
2823
parents_according_to_index = tuple(parent[-1] for parent in
2824
parent_map[(revid,)])
2825
parents_according_to_revision = tuple(revision.parent_ids)
2826
if parents_according_to_index != parents_according_to_revision:
2827
yield (revid, parents_according_to_index,
2828
parents_according_to_revision)
2830
def _check_for_inconsistent_revision_parents(self):
2831
inconsistencies = list(self._find_inconsistent_revision_parents())
2833
raise errors.BzrCheckError(
2834
"Revision knit has inconsistent parents.")
2831
2837
def install_revision(repository, rev, revision_tree):
3237
3252
return self.get_format_string()
3240
# Pre-0.8 formats that don't have a disk format string (because they are
3241
# versioned by the matching control directory). We use the control directories
3242
# disk format string as a key for the network_name because they meet the
3243
# constraints (simple string, unique, immutable).
3244
network_format_registry.register_lazy(
3245
"Bazaar-NG branch, format 5\n",
3246
'bzrlib.repofmt.weaverepo',
3247
'RepositoryFormat5',
3249
network_format_registry.register_lazy(
3250
"Bazaar-NG branch, format 6\n",
3251
'bzrlib.repofmt.weaverepo',
3252
'RepositoryFormat6',
3255
3255
# formats which have no format string are not discoverable or independently
3256
3256
# creatable on disk, so are not registered in format_registry. They're
3257
# all in bzrlib.repofmt.weaverepo now. When an instance of one of these is
3257
# all in bzrlib.repofmt.knitreponow. When an instance of one of these is
3258
3258
# needed, it's constructed directly by the BzrDir. Non-native formats where
3259
3259
# the repository is not separately opened are similar.
3261
3261
format_registry.register_lazy(
3262
'Bazaar-NG Repository format 7',
3263
'bzrlib.repofmt.weaverepo',
3267
format_registry.register_lazy(
3268
3262
'Bazaar-NG Knit Repository Format 1',
3269
3263
'bzrlib.repofmt.knitrepo',
3270
3264
'RepositoryFormatKnit1',
3287
3281
# NOTE: These are experimental in 0.92. Stable in 1.0 and above
3288
3282
format_registry.register_lazy(
3289
3283
'Bazaar pack repository format 1 (needs bzr 0.92)\n',
3290
'bzrlib.repofmt.pack_repo',
3284
'bzrlib.repofmt.knitpack_repo',
3291
3285
'RepositoryFormatKnitPack1',
3293
3287
format_registry.register_lazy(
3294
3288
'Bazaar pack repository format 1 with subtree support (needs bzr 0.92)\n',
3295
'bzrlib.repofmt.pack_repo',
3289
'bzrlib.repofmt.knitpack_repo',
3296
3290
'RepositoryFormatKnitPack3',
3298
3292
format_registry.register_lazy(
3299
3293
'Bazaar pack repository format 1 with rich root (needs bzr 1.0)\n',
3300
'bzrlib.repofmt.pack_repo',
3294
'bzrlib.repofmt.knitpack_repo',
3301
3295
'RepositoryFormatKnitPack4',
3303
3297
format_registry.register_lazy(
3304
3298
'Bazaar RepositoryFormatKnitPack5 (bzr 1.6)\n',
3305
'bzrlib.repofmt.pack_repo',
3299
'bzrlib.repofmt.knitpack_repo',
3306
3300
'RepositoryFormatKnitPack5',
3308
3302
format_registry.register_lazy(
3309
3303
'Bazaar RepositoryFormatKnitPack5RichRoot (bzr 1.6.1)\n',
3310
'bzrlib.repofmt.pack_repo',
3304
'bzrlib.repofmt.knitpack_repo',
3311
3305
'RepositoryFormatKnitPack5RichRoot',
3313
3307
format_registry.register_lazy(
3314
3308
'Bazaar RepositoryFormatKnitPack5RichRoot (bzr 1.6)\n',
3315
'bzrlib.repofmt.pack_repo',
3309
'bzrlib.repofmt.knitpack_repo',
3316
3310
'RepositoryFormatKnitPack5RichRootBroken',
3318
3312
format_registry.register_lazy(
3319
3313
'Bazaar RepositoryFormatKnitPack6 (bzr 1.9)\n',
3320
'bzrlib.repofmt.pack_repo',
3314
'bzrlib.repofmt.knitpack_repo',
3321
3315
'RepositoryFormatKnitPack6',
3323
3317
format_registry.register_lazy(
3324
3318
'Bazaar RepositoryFormatKnitPack6RichRoot (bzr 1.9)\n',
3325
'bzrlib.repofmt.pack_repo',
3319
'bzrlib.repofmt.knitpack_repo',
3326
3320
'RepositoryFormatKnitPack6RichRoot',
3322
format_registry.register_lazy(
3323
'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
3324
'bzrlib.repofmt.groupcompress_repo',
3325
'RepositoryFormat2a',
3329
3328
# Development formats.
3330
# Obsolete but kept pending a CHK based subtree format.
3329
# Check their docstrings to see if/when they are obsolete.
3331
3330
format_registry.register_lazy(
3332
3331
("Bazaar development format 2 with subtree support "
3333
3332
"(needs bzr.dev from before 1.8)\n"),
3334
'bzrlib.repofmt.pack_repo',
3333
'bzrlib.repofmt.knitpack_repo',
3335
3334
'RepositoryFormatPackDevelopment2Subtree',
3338
# 1.14->1.16 go below here
3339
format_registry.register_lazy(
3340
'Bazaar development format - group compression and chk inventory'
3341
' (needs bzr.dev from 1.14)\n',
3342
'bzrlib.repofmt.groupcompress_repo',
3343
'RepositoryFormatCHK1',
3346
format_registry.register_lazy(
3347
'Bazaar development format - chk repository with bencode revision '
3348
'serialization (needs bzr.dev from 1.16)\n',
3349
'bzrlib.repofmt.groupcompress_repo',
3350
'RepositoryFormatCHK2',
3352
format_registry.register_lazy(
3353
'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
3354
'bzrlib.repofmt.groupcompress_repo',
3355
'RepositoryFormat2a',
3336
format_registry.register_lazy(
3337
'Bazaar development format 8\n',
3338
'bzrlib.repofmt.groupcompress_repo',
3339
'RepositoryFormat2aSubtree',
3466
3453
return searcher.get_result()
3468
3455
@needs_read_lock
3469
def search_missing_revision_ids(self, revision_id=None, find_ghosts=True):
3456
def search_missing_revision_ids(self,
3457
revision_id=symbol_versioning.DEPRECATED_PARAMETER,
3458
find_ghosts=True, revision_ids=None, if_present_ids=None):
3470
3459
"""Return the revision ids that source has that target does not.
3472
3461
:param revision_id: only return revision ids included by this
3463
:param revision_ids: return revision ids included by these
3464
revision_ids. NoSuchRevision will be raised if any of these
3465
revisions are not present.
3466
:param if_present_ids: like revision_ids, but will not cause
3467
NoSuchRevision if any of these are absent, instead they will simply
3468
not be in the result. This is useful for e.g. finding revisions
3469
to fetch for tags, which may reference absent revisions.
3474
3470
:param find_ghosts: If True find missing revisions in deep history
3475
3471
rather than just finding the surface difference.
3476
3472
:return: A bzrlib.graph.SearchResult.
3474
if symbol_versioning.deprecated_passed(revision_id):
3475
symbol_versioning.warn(
3476
'search_missing_revision_ids(revision_id=...) was '
3477
'deprecated in 2.4. Use revision_ids=[...] instead.',
3478
DeprecationWarning, stacklevel=2)
3479
if revision_ids is not None:
3480
raise AssertionError(
3481
'revision_ids is mutually exclusive with revision_id')
3482
if revision_id is not None:
3483
revision_ids = [revision_id]
3478
3485
# stop searching at found target revisions.
3479
if not find_ghosts and revision_id is not None:
3480
return self._walk_to_common_revisions([revision_id])
3486
if not find_ghosts and (revision_ids is not None or if_present_ids is
3488
return self._walk_to_common_revisions(revision_ids,
3489
if_present_ids=if_present_ids)
3481
3490
# generic, possibly worst case, slow code path.
3482
3491
target_ids = set(self.target.all_revision_ids())
3483
if revision_id is not None:
3484
source_ids = self.source.get_ancestry(revision_id)
3485
if source_ids[0] is not None:
3486
raise AssertionError()
3489
source_ids = self.source.all_revision_ids()
3492
source_ids = self._present_source_revisions_for(
3493
revision_ids, if_present_ids)
3490
3494
result_set = set(source_ids).difference(target_ids)
3491
3495
return self.source.revision_ids_to_search_result(result_set)
3497
def _present_source_revisions_for(self, revision_ids, if_present_ids=None):
3498
"""Returns set of all revisions in ancestry of revision_ids present in
3501
:param revision_ids: if None, all revisions in source are returned.
3502
:param if_present_ids: like revision_ids, but if any/all of these are
3503
absent no error is raised.
3505
if revision_ids is not None or if_present_ids is not None:
3506
# First, ensure all specified revisions exist. Callers expect
3507
# NoSuchRevision when they pass absent revision_ids here.
3508
if revision_ids is None:
3509
revision_ids = set()
3510
if if_present_ids is None:
3511
if_present_ids = set()
3512
revision_ids = set(revision_ids)
3513
if_present_ids = set(if_present_ids)
3514
all_wanted_ids = revision_ids.union(if_present_ids)
3515
graph = self.source.get_graph()
3516
present_revs = set(graph.get_parent_map(all_wanted_ids))
3517
missing = revision_ids.difference(present_revs)
3519
raise errors.NoSuchRevision(self.source, missing.pop())
3520
found_ids = all_wanted_ids.intersection(present_revs)
3521
source_ids = [rev_id for (rev_id, parents) in
3522
graph.iter_ancestry(found_ids)
3523
if rev_id != _mod_revision.NULL_REVISION
3524
and parents is not None]
3526
source_ids = self.source.all_revision_ids()
3527
return set(source_ids)
3494
3530
def _same_model(source, target):
3495
3531
"""True if source and target have the same data representation.
3536
3572
return InterRepository._same_model(source, target)
3539
class InterWeaveRepo(InterSameDataRepository):
3540
"""Optimised code paths between Weave based repositories.
3542
This should be in bzrlib/repofmt/weaverepo.py but we have not yet
3543
implemented lazy inter-object optimisation.
3547
def _get_repo_format_to_test(self):
3548
from bzrlib.repofmt import weaverepo
3549
return weaverepo.RepositoryFormat7()
3552
def is_compatible(source, target):
3553
"""Be compatible with known Weave formats.
3555
We don't test for the stores being of specific types because that
3556
could lead to confusing results, and there is no need to be
3559
from bzrlib.repofmt.weaverepo import (
3565
return (isinstance(source._format, (RepositoryFormat5,
3567
RepositoryFormat7)) and
3568
isinstance(target._format, (RepositoryFormat5,
3570
RepositoryFormat7)))
3571
except AttributeError:
3575
def copy_content(self, revision_id=None):
3576
"""See InterRepository.copy_content()."""
3577
# weave specific optimised path:
3579
self.target.set_make_working_trees(self.source.make_working_trees())
3580
except (errors.RepositoryUpgradeRequired, NotImplemented):
3582
# FIXME do not peek!
3583
if self.source._transport.listable():
3584
pb = ui.ui_factory.nested_progress_bar()
3586
self.target.texts.insert_record_stream(
3587
self.source.texts.get_record_stream(
3588
self.source.texts.keys(), 'topological', False))
3589
pb.update('Copying inventory', 0, 1)
3590
self.target.inventories.insert_record_stream(
3591
self.source.inventories.get_record_stream(
3592
self.source.inventories.keys(), 'topological', False))
3593
self.target.signatures.insert_record_stream(
3594
self.source.signatures.get_record_stream(
3595
self.source.signatures.keys(),
3597
self.target.revisions.insert_record_stream(
3598
self.source.revisions.get_record_stream(
3599
self.source.revisions.keys(),
3600
'topological', True))
3604
self.target.fetch(self.source, revision_id=revision_id)
3607
def search_missing_revision_ids(self, revision_id=None, find_ghosts=True):
3608
"""See InterRepository.missing_revision_ids()."""
3609
# we want all revisions to satisfy revision_id in source.
3610
# but we don't want to stat every file here and there.
3611
# we want then, all revisions other needs to satisfy revision_id
3612
# checked, but not those that we have locally.
3613
# so the first thing is to get a subset of the revisions to
3614
# satisfy revision_id in source, and then eliminate those that
3615
# we do already have.
3616
# this is slow on high latency connection to self, but as this
3617
# disk format scales terribly for push anyway due to rewriting
3618
# inventory.weave, this is considered acceptable.
3620
if revision_id is not None:
3621
source_ids = self.source.get_ancestry(revision_id)
3622
if source_ids[0] is not None:
3623
raise AssertionError()
3626
source_ids = self.source._all_possible_ids()
3627
source_ids_set = set(source_ids)
3628
# source_ids is the worst possible case we may need to pull.
3629
# now we want to filter source_ids against what we actually
3630
# have in target, but don't try to check for existence where we know
3631
# we do not have a revision as that would be pointless.
3632
target_ids = set(self.target._all_possible_ids())
3633
possibly_present_revisions = target_ids.intersection(source_ids_set)
3634
actually_present_revisions = set(
3635
self.target._eliminate_revisions_not_present(possibly_present_revisions))
3636
required_revisions = source_ids_set.difference(actually_present_revisions)
3637
if revision_id is not None:
3638
# we used get_ancestry to determine source_ids then we are assured all
3639
# revisions referenced are present as they are installed in topological order.
3640
# and the tip revision was validated by get_ancestry.
3641
result_set = required_revisions
3643
# if we just grabbed the possibly available ids, then
3644
# we only have an estimate of whats available and need to validate
3645
# that against the revision records.
3647
self.source._eliminate_revisions_not_present(required_revisions))
3648
return self.source.revision_ids_to_search_result(result_set)
3651
class InterKnitRepo(InterSameDataRepository):
3652
"""Optimised code paths between Knit based repositories."""
3655
def _get_repo_format_to_test(self):
3656
from bzrlib.repofmt import knitrepo
3657
return knitrepo.RepositoryFormatKnit1()
3660
def is_compatible(source, target):
3661
"""Be compatible with known Knit formats.
3663
We don't test for the stores being of specific types because that
3664
could lead to confusing results, and there is no need to be
3667
from bzrlib.repofmt.knitrepo import RepositoryFormatKnit
3669
are_knits = (isinstance(source._format, RepositoryFormatKnit) and
3670
isinstance(target._format, RepositoryFormatKnit))
3671
except AttributeError:
3673
return are_knits and InterRepository._same_model(source, target)
3676
def search_missing_revision_ids(self, revision_id=None, find_ghosts=True):
3677
"""See InterRepository.missing_revision_ids()."""
3678
if revision_id is not None:
3679
source_ids = self.source.get_ancestry(revision_id)
3680
if source_ids[0] is not None:
3681
raise AssertionError()
3684
source_ids = self.source.all_revision_ids()
3685
source_ids_set = set(source_ids)
3686
# source_ids is the worst possible case we may need to pull.
3687
# now we want to filter source_ids against what we actually
3688
# have in target, but don't try to check for existence where we know
3689
# we do not have a revision as that would be pointless.
3690
target_ids = set(self.target.all_revision_ids())
3691
possibly_present_revisions = target_ids.intersection(source_ids_set)
3692
actually_present_revisions = set(
3693
self.target._eliminate_revisions_not_present(possibly_present_revisions))
3694
required_revisions = source_ids_set.difference(actually_present_revisions)
3695
if revision_id is not None:
3696
# we used get_ancestry to determine source_ids then we are assured all
3697
# revisions referenced are present as they are installed in topological order.
3698
# and the tip revision was validated by get_ancestry.
3699
result_set = required_revisions
3701
# if we just grabbed the possibly available ids, then
3702
# we only have an estimate of whats available and need to validate
3703
# that against the revision records.
3705
self.source._eliminate_revisions_not_present(required_revisions))
3706
return self.source.revision_ids_to_search_result(result_set)
3709
3575
class InterDifferingSerializer(InterRepository):
4249
4068
is_resume = False
4251
4070
# locked_insert_stream performs a commit|suspend.
4252
return self._locked_insert_stream(stream, src_format, is_resume)
4071
missing_keys = self.insert_stream_without_locking(stream,
4072
src_format, is_resume)
4074
# suspend the write group and tell the caller what we is
4075
# missing. We know we can suspend or else we would not have
4076
# entered this code path. (All repositories that can handle
4077
# missing keys can handle suspending a write group).
4078
write_group_tokens = self.target_repo.suspend_write_group()
4079
return write_group_tokens, missing_keys
4080
hint = self.target_repo.commit_write_group()
4081
to_serializer = self.target_repo._format._serializer
4082
src_serializer = src_format._serializer
4083
if (to_serializer != src_serializer and
4084
self.target_repo._format.pack_compresses):
4085
self.target_repo.pack(hint=hint)
4254
4088
self.target_repo.abort_write_group(suppress_errors=True)
4257
4091
self.target_repo.unlock()
4259
def _locked_insert_stream(self, stream, src_format, is_resume):
4093
def insert_stream_without_locking(self, stream, src_format,
4095
"""Insert a stream's content into the target repository.
4097
This assumes that you already have a locked repository and an active
4100
:param src_format: a bzr repository format.
4101
:param is_resume: Passed down to get_missing_parent_inventories to
4102
indicate if we should be checking for missing texts at the same
4105
:return: A set of keys that are missing.
4107
if not self.target_repo.is_write_locked():
4108
raise errors.ObjectNotLocked(self)
4109
if not self.target_repo.is_in_write_group():
4110
raise errors.BzrError('you must already be in a write group')
4260
4111
to_serializer = self.target_repo._format._serializer
4261
4112
src_serializer = src_format._serializer
4262
4113
new_pack = None