25
from cStringIO import StringIO
28
from bzrlib.lazy_import import lazy_import
29
lazy_import(globals(), """
23
from StringIO import StringIO
32
revision as _mod_revision,
52
37
from bzrlib.decorators import needs_read_lock, needs_write_lock
53
38
from bzrlib.repository import (
41
MetaDirRepositoryFormat,
57
45
from bzrlib.store.text import TextStore
58
from bzrlib.versionedfile import (
60
FulltextContentFactory,
63
from bzrlib.vf_repository import (
64
InterSameDataRepository,
65
VersionedFileCommitBuilder,
66
VersionedFileRepository,
67
VersionedFileRepositoryFormat,
68
MetaDirVersionedFileRepository,
69
MetaDirVersionedFileRepositoryFormat,
72
from bzrlib.plugins.weave_fmt import bzrdir as weave_bzrdir
75
class AllInOneRepository(VersionedFileRepository):
46
from bzrlib.trace import mutter
49
class AllInOneRepository(Repository):
76
50
"""Legacy support - the repository behaviour for all-in-one branches."""
79
def _serializer(self):
80
return xml5.serializer_v5
82
def _escape(self, file_or_path):
83
if not isinstance(file_or_path, basestring):
84
file_or_path = '/'.join(file_or_path)
85
if file_or_path == '':
87
return urlutils.escape(osutils.safe_unicode(file_or_path))
89
def __init__(self, _format, a_bzrdir):
52
_serializer = xml5.serializer_v5
54
def __init__(self, _format, a_bzrdir, _revision_store, control_store, text_store):
90
55
# we reuse one control files instance.
91
dir_mode = a_bzrdir._get_dir_mode()
92
file_mode = a_bzrdir._get_file_mode()
56
dir_mode = a_bzrdir._control_files._dir_mode
57
file_mode = a_bzrdir._control_files._file_mode
94
59
def get_store(name, compressed=True, prefixed=False):
95
60
# FIXME: This approach of assuming stores are all entirely compressed
96
# or entirely uncompressed is tidy, but breaks upgrade from
97
# some existing branches where there's a mixture; we probably
61
# or entirely uncompressed is tidy, but breaks upgrade from
62
# some existing branches where there's a mixture; we probably
98
63
# still want the option to look for both.
99
relpath = self._escape(name)
100
store = TextStore(a_bzrdir.transport.clone(relpath),
64
relpath = a_bzrdir._control_files._escape(name)
65
store = TextStore(a_bzrdir._control_files._transport.clone(relpath),
101
66
prefixed=prefixed, compressed=compressed,
102
67
dir_mode=dir_mode,
103
68
file_mode=file_mode)
106
71
# not broken out yet because the controlweaves|inventory_store
107
# and texts bits are still different.
72
# and text_store | weave_store bits are still different.
108
73
if isinstance(_format, RepositoryFormat4):
109
# cannot remove these - there is still no consistent api
74
# cannot remove these - there is still no consistent api
110
75
# which allows access to this old info.
111
76
self.inventory_store = get_store('inventory-store')
112
self._text_store = get_store('text-store')
113
super(AllInOneRepository, self).__init__(_format, a_bzrdir, a_bzrdir._control_files)
77
text_store = get_store('text-store')
78
super(AllInOneRepository, self).__init__(_format, a_bzrdir, a_bzrdir._control_files, _revision_store, control_store, text_store)
116
81
def _all_possible_ids(self):
117
82
"""Return all the possible revisions that we could find."""
118
83
if 'evil' in debug.debug_flags:
119
trace.mutter_callsite(
120
3, "_all_possible_ids scales with size of history.")
121
return [key[-1] for key in self.inventories.keys()]
84
mutter_callsite(3, "_all_possible_ids scales with size of history.")
85
return self.get_inventory_weave().versions()
124
88
def _all_revision_ids(self):
125
"""Returns a list of all the revision ids in the repository.
89
"""Returns a list of all the revision ids in the repository.
127
These are in as much topological order as the underlying store can
91
These are in as much topological order as the underlying store can
128
92
present: for weaves ghosts may lead to a lack of correctness until
129
93
the reweave updates the parents list.
131
return [key[-1] for key in self.revisions.keys()]
133
def _activate_new_inventory(self):
134
"""Put a replacement inventory.new into use as inventories."""
135
# Copy the content across
136
t = self.bzrdir._control_files._transport
137
t.copy('inventory.new.weave', 'inventory.weave')
138
# delete the temp inventory
139
t.delete('inventory.new.weave')
140
# Check we can parse the new weave properly as a sanity check
141
self.inventories.keys()
143
def _backup_inventory(self):
144
t = self.bzrdir._control_files._transport
145
t.copy('inventory.weave', 'inventory.backup.weave')
147
def _temp_inventories(self):
148
t = self.bzrdir._control_files._transport
149
return self._format._get_inventories(t, self, 'inventory.new')
95
if self._revision_store.text_store.listable():
96
return self._revision_store.all_revision_ids(self.get_transaction())
97
result = self._all_possible_ids()
98
# TODO: jam 20070210 Ensure that _all_possible_ids returns non-unicode
99
# ids. (It should, since _revision_store's API should change to
100
# return utf8 revision_ids)
101
return self._eliminate_revisions_not_present(result)
103
def _check_revision_parents(self, revision, inventory):
104
"""Private to Repository and Fetch.
106
This checks the parentage of revision in an inventory weave for
107
consistency and is only applicable to inventory-weave-for-ancestry
108
using repository formats & fetchers.
110
weave_parents = inventory.get_parents(revision.revision_id)
111
weave_names = inventory.versions()
112
for parent_id in revision.parent_ids:
113
if parent_id in weave_names:
114
# this parent must not be a ghost.
115
if not parent_id in weave_parents:
117
raise errors.CorruptRepository(self)
151
119
def get_commit_builder(self, branch, parents, config, timestamp=None,
152
120
timezone=None, committer=None, revprops=None,
153
revision_id=None, lossy=False):
154
122
self._check_ascii_revisionid(revision_id, self.get_commit_builder)
155
result = VersionedFileCommitBuilder(self, parents, config, timestamp,
156
timezone, committer, revprops, revision_id, lossy=lossy)
123
result = WeaveCommitBuilder(self, parents, config, timestamp, timezone,
124
committer, revprops, revision_id)
157
125
self.start_write_group()
161
129
def get_revisions(self, revision_ids):
162
130
revs = self._get_revisions(revision_ids)
131
# weave corruption can lead to absent revision markers that should be
133
# the following test is reasonably cheap (it needs a single weave read)
134
# and the weave is cached in read transactions. In write transactions
135
# it is not cached but typically we only read a small number of
136
# revisions. For knits when they are introduced we will probably want
137
# to ensure that caching write transactions are in use.
138
inv = self.get_inventory_weave()
140
self._check_revision_parents(rev, inv)
165
def _inventory_add_lines(self, revision_id, parents, lines,
167
"""Store lines in inv_vf and return the sha1 of the inventory."""
168
present_parents = self.get_graph().get_parent_map(parents)
170
for parent in parents:
171
if parent in present_parents:
172
final_parents.append((parent,))
173
return self.inventories.add_lines((revision_id,), final_parents, lines,
174
check_content=check_content)[0]
144
def get_revision_graph(self, revision_id=None):
145
"""Return a dictionary containing the revision graph.
147
:param revision_id: The revision_id to get a graph from. If None, then
148
the entire revision graph is returned. This is a deprecated mode of
149
operation and will be removed in the future.
150
:return: a dictionary of revision_id->revision_parents_list.
152
if 'evil' in debug.debug_flags:
154
"get_revision_graph scales with size of history.")
155
# special case NULL_REVISION
156
if revision_id == _mod_revision.NULL_REVISION:
158
a_weave = self.get_inventory_weave()
159
all_revisions = self._eliminate_revisions_not_present(
161
entire_graph = dict([(node, tuple(a_weave.get_parents(node))) for
162
node in all_revisions])
163
if revision_id is None:
165
elif revision_id not in entire_graph:
166
raise errors.NoSuchRevision(self, revision_id)
168
# add what can be reached from revision_id
170
pending = set([revision_id])
171
while len(pending) > 0:
173
result[node] = entire_graph[node]
174
for revision_id in result[node]:
175
if revision_id not in result:
176
pending.add(revision_id)
176
180
def is_shared(self):
177
181
"""AllInOne repositories cannot be shared."""
187
191
:param new_value: True to restore the default, False to disable making
190
raise errors.RepositoryUpgradeRequired(self.user_url)
194
raise NotImplementedError(self.set_make_working_trees)
192
196
def make_working_trees(self):
193
197
"""Returns the policy for making working trees on new branches."""
197
class WeaveMetaDirRepository(MetaDirVersionedFileRepository):
200
def revision_graph_can_have_wrong_parents(self):
201
# XXX: This is an old format that we don't support full checking on, so
202
# just claim that checking for this inconsistency is not required.
206
class WeaveMetaDirRepository(MetaDirRepository):
198
207
"""A subclass of MetaDirRepository to set weave specific policy."""
200
def __init__(self, _format, a_bzrdir, control_files):
201
super(WeaveMetaDirRepository, self).__init__(_format, a_bzrdir, control_files)
202
self._serializer = _format._serializer
209
_serializer = xml5.serializer_v5
205
212
def _all_possible_ids(self):
206
213
"""Return all the possible revisions that we could find."""
207
214
if 'evil' in debug.debug_flags:
208
trace.mutter_callsite(
209
3, "_all_possible_ids scales with size of history.")
210
return [key[-1] for key in self.inventories.keys()]
215
mutter_callsite(3, "_all_possible_ids scales with size of history.")
216
return self.get_inventory_weave().versions()
213
219
def _all_revision_ids(self):
214
"""Returns a list of all the revision ids in the repository.
220
"""Returns a list of all the revision ids in the repository.
216
These are in as much topological order as the underlying store can
222
These are in as much topological order as the underlying store can
217
223
present: for weaves ghosts may lead to a lack of correctness until
218
224
the reweave updates the parents list.
220
return [key[-1] for key in self.revisions.keys()]
222
def _activate_new_inventory(self):
223
"""Put a replacement inventory.new into use as inventories."""
224
# Copy the content across
226
t.copy('inventory.new.weave', 'inventory.weave')
227
# delete the temp inventory
228
t.delete('inventory.new.weave')
229
# Check we can parse the new weave properly as a sanity check
230
self.inventories.keys()
232
def _backup_inventory(self):
234
t.copy('inventory.weave', 'inventory.backup.weave')
236
def _temp_inventories(self):
238
return self._format._get_inventories(t, self, 'inventory.new')
226
if self._revision_store.text_store.listable():
227
return self._revision_store.all_revision_ids(self.get_transaction())
228
result = self._all_possible_ids()
229
# TODO: jam 20070210 Ensure that _all_possible_ids returns non-unicode
230
# ids. (It should, since _revision_store's API should change to
231
# return utf8 revision_ids)
232
return self._eliminate_revisions_not_present(result)
234
def _check_revision_parents(self, revision, inventory):
235
"""Private to Repository and Fetch.
237
This checks the parentage of revision in an inventory weave for
238
consistency and is only applicable to inventory-weave-for-ancestry
239
using repository formats & fetchers.
241
weave_parents = inventory.get_parents(revision.revision_id)
242
weave_names = inventory.versions()
243
for parent_id in revision.parent_ids:
244
if parent_id in weave_names:
245
# this parent must not be a ghost.
246
if not parent_id in weave_parents:
248
raise errors.CorruptRepository(self)
240
250
def get_commit_builder(self, branch, parents, config, timestamp=None,
241
251
timezone=None, committer=None, revprops=None,
242
revision_id=None, lossy=False):
243
253
self._check_ascii_revisionid(revision_id, self.get_commit_builder)
244
result = VersionedFileCommitBuilder(self, parents, config, timestamp,
245
timezone, committer, revprops, revision_id, lossy=lossy)
254
result = WeaveCommitBuilder(self, parents, config, timestamp, timezone,
255
committer, revprops, revision_id)
246
256
self.start_write_group()
250
260
def get_revision(self, revision_id):
251
261
"""Return the Revision object for a named revision"""
262
# TODO: jam 20070210 get_revision_reconcile should do this for us
252
263
r = self.get_revision_reconcile(revision_id)
264
# weave corruption can lead to absent revision markers that should be
266
# the following test is reasonably cheap (it needs a single weave read)
267
# and the weave is cached in read transactions. In write transactions
268
# it is not cached but typically we only read a small number of
269
# revisions. For knits when they are introduced we will probably want
270
# to ensure that caching write transactions are in use.
271
inv = self.get_inventory_weave()
272
self._check_revision_parents(r, inv)
255
def _inventory_add_lines(self, revision_id, parents, lines,
257
"""Store lines in inv_vf and return the sha1 of the inventory."""
258
present_parents = self.get_graph().get_parent_map(parents)
260
for parent in parents:
261
if parent in present_parents:
262
final_parents.append((parent,))
263
return self.inventories.add_lines((revision_id,), final_parents, lines,
264
check_content=check_content)[0]
267
class PreSplitOutRepositoryFormat(VersionedFileRepositoryFormat):
276
def get_revision_graph(self, revision_id=None):
277
"""Return a dictionary containing the revision graph.
279
:param revision_id: The revision_id to get a graph from. If None, then
280
the entire revision graph is returned. This is a deprecated mode of
281
operation and will be removed in the future.
282
:return: a dictionary of revision_id->revision_parents_list.
284
if 'evil' in debug.debug_flags:
286
"get_revision_graph scales with size of history.")
287
# special case NULL_REVISION
288
if revision_id == _mod_revision.NULL_REVISION:
290
a_weave = self.get_inventory_weave()
291
all_revisions = self._eliminate_revisions_not_present(
293
entire_graph = dict([(node, tuple(a_weave.get_parents(node))) for
294
node in all_revisions])
295
if revision_id is None:
297
elif revision_id not in entire_graph:
298
raise errors.NoSuchRevision(self, revision_id)
300
# add what can be reached from revision_id
302
pending = set([revision_id])
303
while len(pending) > 0:
305
result[node] = entire_graph[node]
306
for revision_id in result[node]:
307
if revision_id not in result:
308
pending.add(revision_id)
311
def revision_graph_can_have_wrong_parents(self):
312
# XXX: This is an old format that we don't support full checking on, so
313
# just claim that checking for this inconsistency is not required.
317
class PreSplitOutRepositoryFormat(RepositoryFormat):
268
318
"""Base class for the pre split out repository formats."""
270
320
rich_root_data = False
271
321
supports_tree_reference = False
272
322
supports_ghosts = False
273
supports_external_lookups = False
274
supports_chks = False
275
_fetch_order = 'topological'
276
_fetch_reconcile = True
278
supports_leaving_lock = False
279
# XXX: This is an old format that we don't support full checking on, so
280
# just claim that checking for this inconsistency is not required.
281
revision_graph_can_have_wrong_parents = False
283
324
def initialize(self, a_bzrdir, shared=False, _internal=False):
284
325
"""Create a weave repository."""
544
562
weavefile.write_weave_v5(weave.Weave(), sio)
545
563
empty_weave = sio.getvalue()
547
trace.mutter('creating repository in %s.', a_bzrdir.transport.base)
565
mutter('creating repository in %s.', a_bzrdir.transport.base)
548
566
dirs = ['revision-store', 'weaves']
549
files = [('inventory.weave', StringIO(empty_weave)),
567
files = [('inventory.weave', StringIO(empty_weave)),
551
569
utf8_files = [('format', self.get_format_string())]
553
571
self._upload_blank_content(a_bzrdir, dirs, files, utf8_files, shared)
554
572
return self.open(a_bzrdir=a_bzrdir, _found=True)
556
574
def open(self, a_bzrdir, _found=False, _override_transport=None):
557
575
"""See RepositoryFormat.open().
559
577
:param _override_transport: INTERNAL USE ONLY. Allows opening the
560
578
repository at a slightly different url
561
579
than normal. I.e. during 'upgrade'.
564
582
format = RepositoryFormat.find_format(a_bzrdir)
583
assert format.__class__ == self.__class__
565
584
if _override_transport is not None:
566
585
repo_transport = _override_transport
568
587
repo_transport = a_bzrdir.get_repository_transport(None)
569
588
control_files = lockable_files.LockableFiles(repo_transport,
570
589
'lock', lockdir.LockDir)
571
result = WeaveMetaDirRepository(_format=self, a_bzrdir=a_bzrdir,
572
control_files=control_files)
573
result.revisions = self._get_revisions(repo_transport, result)
574
result.signatures = self._get_signatures(repo_transport, result)
575
result.inventories = self._get_inventories(repo_transport, result)
576
result.texts = self._get_texts(repo_transport, result)
577
result.chk_bytes = None
578
result._transport = repo_transport
581
def is_deprecated(self):
585
class TextVersionedFiles(VersionedFiles):
586
"""Just-a-bunch-of-files based VersionedFile stores."""
588
def __init__(self, transport, compressed, mapper, is_locked, can_write):
589
self._compressed = compressed
590
self._transport = transport
591
self._mapper = mapper
596
self._is_locked = is_locked
597
self._can_write = can_write
599
def add_lines(self, key, parents, lines):
600
"""Add a revision to the store."""
601
if not self._is_locked():
602
raise errors.ObjectNotLocked(self)
603
if not self._can_write():
604
raise errors.ReadOnlyError(self)
606
raise ValueError('bad idea to put / in %r' % (key,))
607
text = ''.join(lines)
609
text = tuned_gzip.bytes_to_gzip(text)
610
path = self._map(key)
611
self._transport.put_bytes_non_atomic(path, text, create_parent_dir=True)
613
def insert_record_stream(self, stream):
615
for record in stream:
616
# Raise an error when a record is missing.
617
if record.storage_kind == 'absent':
618
raise errors.RevisionNotPresent([record.key[0]], self)
619
# adapt to non-tuple interface
620
if record.storage_kind == 'fulltext':
621
self.add_lines(record.key, None,
622
osutils.split_lines(record.get_bytes_as('fulltext')))
624
adapter_key = record.storage_kind, 'fulltext'
626
adapter = adapters[adapter_key]
628
adapter_factory = adapter_registry.get(adapter_key)
629
adapter = adapter_factory(self)
630
adapters[adapter_key] = adapter
631
lines = osutils.split_lines(adapter.get_bytes(
632
record, record.get_bytes_as(record.storage_kind)))
634
self.add_lines(record.key, None, lines)
635
except errors.RevisionAlreadyPresent:
638
def _load_text(self, key):
639
if not self._is_locked():
640
raise errors.ObjectNotLocked(self)
641
path = self._map(key)
643
text = self._transport.get_bytes(path)
644
compressed = self._compressed
645
except errors.NoSuchFile:
647
# try without the .gz
650
text = self._transport.get_bytes(path)
652
except errors.NoSuchFile:
657
text = gzip.GzipFile(mode='rb', fileobj=StringIO(text)).read()
661
return self._mapper.map(key) + self._ext
664
class RevisionTextStore(TextVersionedFiles):
665
"""Legacy thunk for format 4 repositories."""
667
def __init__(self, transport, serializer, compressed, mapper, is_locked,
669
"""Create a RevisionTextStore at transport with serializer."""
670
TextVersionedFiles.__init__(self, transport, compressed, mapper,
671
is_locked, can_write)
672
self._serializer = serializer
674
def _load_text_parents(self, key):
675
text = self._load_text(key)
678
parents = self._serializer.read_revision_from_string(text).parent_ids
679
return text, tuple((parent,) for parent in parents)
681
def get_parent_map(self, keys):
684
parents = self._load_text_parents(key)[1]
687
result[key] = parents
690
def get_known_graph_ancestry(self, keys):
691
"""Get a KnownGraph instance with the ancestry of keys."""
693
parent_map = self.get_parent_map(keys)
694
kg = _mod_graph.KnownGraph(parent_map)
697
def get_record_stream(self, keys, sort_order, include_delta_closure):
699
text, parents = self._load_text_parents(key)
701
yield AbsentContentFactory(key)
703
yield FulltextContentFactory(key, parents, None, text)
706
if not self._is_locked():
707
raise errors.ObjectNotLocked(self)
709
for quoted_relpath in self._transport.iter_files_recursive():
710
relpath = urllib.unquote(quoted_relpath)
711
path, ext = os.path.splitext(relpath)
714
if not relpath.endswith('.sig'):
715
relpaths.add(relpath)
716
paths = list(relpaths)
717
return set([self._mapper.unmap(path) for path in paths])
720
class SignatureTextStore(TextVersionedFiles):
721
"""Legacy thunk for format 4-7 repositories."""
723
def __init__(self, transport, compressed, mapper, is_locked, can_write):
724
TextVersionedFiles.__init__(self, transport, compressed, mapper,
725
is_locked, can_write)
726
self._ext = '.sig' + self._ext
728
def get_parent_map(self, keys):
731
text = self._load_text(key)
737
def get_record_stream(self, keys, sort_order, include_delta_closure):
739
text = self._load_text(key)
741
yield AbsentContentFactory(key)
743
yield FulltextContentFactory(key, None, None, text)
746
if not self._is_locked():
747
raise errors.ObjectNotLocked(self)
749
for quoted_relpath in self._transport.iter_files_recursive():
750
relpath = urllib.unquote(quoted_relpath)
751
path, ext = os.path.splitext(relpath)
754
if not relpath.endswith('.sig'):
756
relpaths.add(relpath[:-4])
757
paths = list(relpaths)
758
return set([self._mapper.unmap(path) for path in paths])
761
class InterWeaveRepo(InterSameDataRepository):
762
"""Optimised code paths between Weave based repositories.
766
def _get_repo_format_to_test(self):
767
return RepositoryFormat7()
770
def is_compatible(source, target):
771
"""Be compatible with known Weave formats.
773
We don't test for the stores being of specific types because that
774
could lead to confusing results, and there is no need to be
778
return (isinstance(source._format, (RepositoryFormat5,
780
RepositoryFormat7)) and
781
isinstance(target._format, (RepositoryFormat5,
784
except AttributeError:
788
def copy_content(self, revision_id=None):
789
"""See InterRepository.copy_content()."""
790
# weave specific optimised path:
792
self.target.set_make_working_trees(self.source.make_working_trees())
793
except (errors.RepositoryUpgradeRequired, NotImplemented):
796
if self.source._transport.listable():
797
pb = ui.ui_factory.nested_progress_bar()
799
self.target.texts.insert_record_stream(
800
self.source.texts.get_record_stream(
801
self.source.texts.keys(), 'topological', False))
802
pb.update('Copying inventory', 0, 1)
803
self.target.inventories.insert_record_stream(
804
self.source.inventories.get_record_stream(
805
self.source.inventories.keys(), 'topological', False))
806
self.target.signatures.insert_record_stream(
807
self.source.signatures.get_record_stream(
808
self.source.signatures.keys(),
810
self.target.revisions.insert_record_stream(
811
self.source.revisions.get_record_stream(
812
self.source.revisions.keys(),
813
'topological', True))
817
self.target.fetch(self.source, revision_id=revision_id)
820
def search_missing_revision_ids(self,
821
revision_id=symbol_versioning.DEPRECATED_PARAMETER,
822
find_ghosts=True, revision_ids=None, if_present_ids=None,
824
"""See InterRepository.search_missing_revision_ids()."""
825
# we want all revisions to satisfy revision_id in source.
826
# but we don't want to stat every file here and there.
827
# we want then, all revisions other needs to satisfy revision_id
828
# checked, but not those that we have locally.
829
# so the first thing is to get a subset of the revisions to
830
# satisfy revision_id in source, and then eliminate those that
831
# we do already have.
832
# this is slow on high latency connection to self, but as this
833
# disk format scales terribly for push anyway due to rewriting
834
# inventory.weave, this is considered acceptable.
836
if symbol_versioning.deprecated_passed(revision_id):
837
symbol_versioning.warn(
838
'search_missing_revision_ids(revision_id=...) was '
839
'deprecated in 2.4. Use revision_ids=[...] instead.',
840
DeprecationWarning, stacklevel=2)
841
if revision_ids is not None:
842
raise AssertionError(
843
'revision_ids is mutually exclusive with revision_id')
844
if revision_id is not None:
845
revision_ids = [revision_id]
847
source_ids_set = self._present_source_revisions_for(
848
revision_ids, if_present_ids)
849
# source_ids is the worst possible case we may need to pull.
850
# now we want to filter source_ids against what we actually
851
# have in target, but don't try to check for existence where we know
852
# we do not have a revision as that would be pointless.
853
target_ids = set(self.target._all_possible_ids())
854
possibly_present_revisions = target_ids.intersection(source_ids_set)
855
actually_present_revisions = set(
856
self.target._eliminate_revisions_not_present(possibly_present_revisions))
857
required_revisions = source_ids_set.difference(actually_present_revisions)
858
if revision_ids is not None:
859
# we used get_ancestry to determine source_ids then we are assured all
860
# revisions referenced are present as they are installed in topological order.
861
# and the tip revision was validated by get_ancestry.
862
result_set = required_revisions
864
# if we just grabbed the possibly available ids, then
865
# we only have an estimate of whats available and need to validate
866
# that against the revision records.
868
self.source._eliminate_revisions_not_present(required_revisions))
869
if limit is not None:
870
topo_ordered = self.get_graph().iter_topo_order(result_set)
871
result_set = set(itertools.islice(topo_ordered, limit))
872
return self.source.revision_ids_to_search_result(result_set)
875
InterRepository.register_optimiser(InterWeaveRepo)
878
def get_extra_interrepo_test_combinations():
879
from bzrlib.repofmt import knitrepo
880
return [(InterRepository, RepositoryFormat5(),
881
knitrepo.RepositoryFormatKnit3())]
590
text_store = self._get_text_store(repo_transport, control_files)
591
control_store = self._get_control_store(repo_transport, control_files)
592
_revision_store = self._get_revision_store(repo_transport, control_files)
593
return WeaveMetaDirRepository(_format=self,
595
control_files=control_files,
596
_revision_store=_revision_store,
597
control_store=control_store,
598
text_store=text_store)
601
class WeaveCommitBuilder(CommitBuilder):
602
"""A builder for weave based repos that don't support ghosts."""
604
def _add_text_to_weave(self, file_id, new_lines, parents, nostore_sha):
605
versionedfile = self.repository.weave_store.get_weave_or_empty(
606
file_id, self.repository.get_transaction())
607
result = versionedfile.add_lines(
608
self._new_revision_id, parents, new_lines,
609
nostore_sha=nostore_sha)[0:2]
610
versionedfile.clear_cache()
614
_legacy_formats = [RepositoryFormat4(),