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)
179
def has_revisions(self, revision_ids):
180
"""See Repository.has_revisions()."""
182
transaction = self.get_transaction()
183
for revision_id in revision_ids:
184
if self._revision_store.has_revision_id(revision_id, transaction):
185
result.add(revision_id)
176
189
def is_shared(self):
177
190
"""AllInOne repositories cannot be shared."""
187
200
:param new_value: True to restore the default, False to disable making
190
raise errors.RepositoryUpgradeRequired(self.user_url)
203
raise NotImplementedError(self.set_make_working_trees)
192
205
def make_working_trees(self):
193
206
"""Returns the policy for making working trees on new branches."""
197
class WeaveMetaDirRepository(MetaDirVersionedFileRepository):
209
def revision_graph_can_have_wrong_parents(self):
210
# XXX: This is an old format that we don't support full checking on, so
211
# just claim that checking for this inconsistency is not required.
215
class WeaveMetaDirRepository(MetaDirRepository):
198
216
"""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
218
_serializer = xml5.serializer_v5
205
221
def _all_possible_ids(self):
206
222
"""Return all the possible revisions that we could find."""
207
223
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()]
224
mutter_callsite(3, "_all_possible_ids scales with size of history.")
225
return self.get_inventory_weave().versions()
213
228
def _all_revision_ids(self):
214
"""Returns a list of all the revision ids in the repository.
229
"""Returns a list of all the revision ids in the repository.
216
These are in as much topological order as the underlying store can
231
These are in as much topological order as the underlying store can
217
232
present: for weaves ghosts may lead to a lack of correctness until
218
233
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')
235
if self._revision_store.text_store.listable():
236
return self._revision_store.all_revision_ids(self.get_transaction())
237
result = self._all_possible_ids()
238
# TODO: jam 20070210 Ensure that _all_possible_ids returns non-unicode
239
# ids. (It should, since _revision_store's API should change to
240
# return utf8 revision_ids)
241
return self._eliminate_revisions_not_present(result)
243
def _check_revision_parents(self, revision, inventory):
244
"""Private to Repository and Fetch.
246
This checks the parentage of revision in an inventory weave for
247
consistency and is only applicable to inventory-weave-for-ancestry
248
using repository formats & fetchers.
250
weave_parents = inventory.get_parents(revision.revision_id)
251
weave_names = inventory.versions()
252
for parent_id in revision.parent_ids:
253
if parent_id in weave_names:
254
# this parent must not be a ghost.
255
if not parent_id in weave_parents:
257
raise errors.CorruptRepository(self)
240
259
def get_commit_builder(self, branch, parents, config, timestamp=None,
241
260
timezone=None, committer=None, revprops=None,
242
revision_id=None, lossy=False):
243
262
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)
263
result = WeaveCommitBuilder(self, parents, config, timestamp, timezone,
264
committer, revprops, revision_id)
246
265
self.start_write_group()
250
269
def get_revision(self, revision_id):
251
270
"""Return the Revision object for a named revision"""
271
# TODO: jam 20070210 get_revision_reconcile should do this for us
252
272
r = self.get_revision_reconcile(revision_id)
273
# weave corruption can lead to absent revision markers that should be
275
# the following test is reasonably cheap (it needs a single weave read)
276
# and the weave is cached in read transactions. In write transactions
277
# it is not cached but typically we only read a small number of
278
# revisions. For knits when they are introduced we will probably want
279
# to ensure that caching write transactions are in use.
280
inv = self.get_inventory_weave()
281
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):
285
def get_revision_graph(self, revision_id=None):
286
"""Return a dictionary containing the revision graph.
288
:param revision_id: The revision_id to get a graph from. If None, then
289
the entire revision graph is returned. This is a deprecated mode of
290
operation and will be removed in the future.
291
:return: a dictionary of revision_id->revision_parents_list.
293
if 'evil' in debug.debug_flags:
295
"get_revision_graph scales with size of history.")
296
# special case NULL_REVISION
297
if revision_id == _mod_revision.NULL_REVISION:
299
a_weave = self.get_inventory_weave()
300
all_revisions = self._eliminate_revisions_not_present(
302
entire_graph = dict([(node, tuple(a_weave.get_parents(node))) for
303
node in all_revisions])
304
if revision_id is None:
306
elif revision_id not in entire_graph:
307
raise errors.NoSuchRevision(self, revision_id)
309
# add what can be reached from revision_id
311
pending = set([revision_id])
312
while len(pending) > 0:
314
result[node] = entire_graph[node]
315
for revision_id in result[node]:
316
if revision_id not in result:
317
pending.add(revision_id)
320
def has_revisions(self, revision_ids):
321
"""See Repository.has_revisions()."""
323
transaction = self.get_transaction()
324
for revision_id in revision_ids:
325
if self._revision_store.has_revision_id(revision_id, transaction):
326
result.add(revision_id)
329
def revision_graph_can_have_wrong_parents(self):
330
# XXX: This is an old format that we don't support full checking on, so
331
# just claim that checking for this inconsistency is not required.
335
class PreSplitOutRepositoryFormat(RepositoryFormat):
268
336
"""Base class for the pre split out repository formats."""
270
338
rich_root_data = False
271
339
supports_tree_reference = False
272
340
supports_ghosts = False
273
341
supports_external_lookups = False
274
supports_chks = False
275
supports_nesting_repositories = True
276
_fetch_order = 'topological'
277
_fetch_reconcile = True
279
supports_leaving_lock = False
280
# XXX: This is an old format that we don't support full checking on, so
281
# just claim that checking for this inconsistency is not required.
282
revision_graph_can_have_wrong_parents = False
284
343
def initialize(self, a_bzrdir, shared=False, _internal=False):
285
344
"""Create a weave repository."""
544
581
weavefile.write_weave_v5(weave.Weave(), sio)
545
582
empty_weave = sio.getvalue()
547
trace.mutter('creating repository in %s.', a_bzrdir.transport.base)
584
mutter('creating repository in %s.', a_bzrdir.transport.base)
548
585
dirs = ['revision-store', 'weaves']
549
files = [('inventory.weave', StringIO(empty_weave)),
586
files = [('inventory.weave', StringIO(empty_weave)),
551
588
utf8_files = [('format', self.get_format_string())]
553
590
self._upload_blank_content(a_bzrdir, dirs, files, utf8_files, shared)
554
591
return self.open(a_bzrdir=a_bzrdir, _found=True)
556
593
def open(self, a_bzrdir, _found=False, _override_transport=None):
557
594
"""See RepositoryFormat.open().
559
596
:param _override_transport: INTERNAL USE ONLY. Allows opening the
560
597
repository at a slightly different url
561
598
than normal. I.e. during 'upgrade'.
564
601
format = RepositoryFormat.find_format(a_bzrdir)
602
assert format.__class__ == self.__class__
565
603
if _override_transport is not None:
566
604
repo_transport = _override_transport
568
606
repo_transport = a_bzrdir.get_repository_transport(None)
569
607
control_files = lockable_files.LockableFiles(repo_transport,
570
608
'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())]
609
text_store = self._get_text_store(repo_transport, control_files)
610
control_store = self._get_control_store(repo_transport, control_files)
611
_revision_store = self._get_revision_store(repo_transport, control_files)
612
return WeaveMetaDirRepository(_format=self,
614
control_files=control_files,
615
_revision_store=_revision_store,
616
control_store=control_store,
617
text_store=text_store)
620
class WeaveCommitBuilder(CommitBuilder):
621
"""A builder for weave based repos that don't support ghosts."""
623
def _add_text_to_weave(self, file_id, new_lines, parents, nostore_sha):
624
versionedfile = self.repository.weave_store.get_weave_or_empty(
625
file_id, self.repository.get_transaction())
626
result = versionedfile.add_lines(
627
self._new_revision_id, parents, new_lines,
628
nostore_sha=nostore_sha)[0:2]
629
versionedfile.clear_cache()
633
_legacy_formats = [RepositoryFormat4(),