170
172
pb = bzrlib.ui.ui_factory.nested_progress_bar()
171
173
if knit_kind == "file":
172
self._fetch_weave_text(file_id, revisions)
174
# Accumulate file texts
175
text_keys.extend([(file_id, revision) for revision in
173
177
elif knit_kind == "inventory":
178
# Now copy the file texts.
179
to_texts = self.to_repository.texts
180
from_texts = self.from_repository.texts
181
to_texts.insert_record_stream(from_texts.get_record_stream(
182
text_keys, 'topological', False))
183
# Cause an error if a text occurs after we have done the
174
186
# Before we process the inventory we generate the root
175
187
# texts (if necessary) so that the inventories references
177
189
self._generate_root_texts(revs)
178
190
# NB: This currently reopens the inventory weave in source;
179
# using a full get_data_stream instead would avoid this.
191
# using a single stream interface instead would avoid this.
180
192
self._fetch_inventory_weave(revs, pb)
181
193
elif knit_kind == "signatures":
182
194
# Nothing to do here; this will be taken care of when
208
220
return self.to_repository.search_missing_revision_ids(
209
221
self.from_repository, self._last_revision,
210
222
find_ghosts=self.find_ghosts)
211
except errors.NoSuchRevision:
223
except errors.NoSuchRevision, e:
212
224
raise InstallFailed([self._last_revision])
214
def _fetch_weave_text(self, file_id, required_versions):
215
to_weave = self.to_weaves.get_weave_or_empty(file_id,
216
self.to_repository.get_transaction())
217
from_weave = self.from_weaves.get_weave(file_id,
218
self.from_repository.get_transaction())
219
# Fetch all the texts.
220
to_weave.insert_record_stream(from_weave.get_record_stream(
221
required_versions, 'topological', False))
223
226
def _fetch_inventory_weave(self, revs, pb):
224
227
pb.update("fetch inventory", 0, 2)
225
to_weave = self.to_repository.get_inventory_weave()
228
to_weave = self.to_repository.inventories
226
229
child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
228
231
# just merge, this is optimisable and its means we don't
229
232
# copy unreferenced data such as not-needed inventories.
230
233
pb.update("fetch inventory", 1, 3)
231
from_weave = self.from_repository.get_inventory_weave()
234
from_weave = self.from_repository.inventories
232
235
pb.update("fetch inventory", 2, 3)
233
236
# we fetch only the referenced inventories because we do not
234
237
# know for unselected inventories whether all their required
235
238
# texts are present in the other repository - it could be
237
to_weave.insert_record_stream(from_weave.get_record_stream(revs,
240
to_weave.insert_record_stream(from_weave.get_record_stream(
241
[(rev_id,) for rev_id in revs],
238
242
'topological', False))
240
244
child_pb.finished()
259
263
def _fetch_revision_texts(self, revs, pb):
260
264
"""Fetch revision object texts"""
261
to_txn = self.to_transaction = self.to_repository.get_transaction()
263
266
total = len(revs)
264
to_store = self.to_repository._revision_store
266
268
pb.update('copying revisions', count, total)
268
270
sig_text = self.from_repository.get_signature_text(rev)
269
to_store.add_revision_signature_text(rev, sig_text, to_txn)
271
self.to_repository.add_signature_text(rev, sig_text)
270
272
except errors.NoSuchRevision:
273
self._copy_revision(rev, to_txn)
275
self._copy_revision(rev)
275
277
# fixup inventory if needed:
276
278
# this is expensive because we have no inverse index to current ghosts.
279
281
# FIXME: repository should inform if this is needed.
280
282
self.to_repository.reconcile()
282
def _copy_revision(self, rev, to_txn):
283
to_store = self.to_repository._revision_store
284
to_store.add_revision(self.from_repository.get_revision(rev), to_txn)
284
def _copy_revision(self, rev_id):
285
rev = self.from_repository.get_revision(rev_id)
286
self.to_repository.add_revision(rev_id, rev)
287
289
class KnitRepoFetcher(RepoFetcher):
295
297
def _fetch_revision_texts(self, revs, pb):
296
298
# may need to be a InterRevisionStore call here.
297
from_transaction = self.from_repository.get_transaction()
298
to_transaction = self.to_repository.get_transaction()
299
to_sf = self.to_repository._revision_store.get_signature_file(
301
from_sf = self.from_repository._revision_store.get_signature_file(
299
to_sf = self.to_repository.signatures
300
from_sf = self.from_repository.signatures
303
301
# A missing signature is just skipped.
304
to_sf.insert_record_stream(filter_absent(from_sf.get_record_stream(revs,
302
to_sf.insert_record_stream(filter_absent(from_sf.get_record_stream(
303
[(rev_id,) for rev_id in revs],
305
304
'unordered', False)))
306
self._fetch_just_revision_texts(revs, from_transaction, to_transaction)
305
self._fetch_just_revision_texts(revs)
308
def _fetch_just_revision_texts(self, version_ids, from_transaction,
310
to_rf = self.to_repository._revision_store.get_revision_file(
312
from_rf = self.from_repository._revision_store.get_revision_file(
314
to_rf.insert_record_stream(from_rf.get_record_stream(version_ids,
307
def _fetch_just_revision_texts(self, version_ids):
308
to_rf = self.to_repository.revisions
309
from_rf = self.from_repository.revisions
310
to_rf.insert_record_stream(from_rf.get_record_stream(
311
[(rev_id,) for rev_id in version_ids],
315
312
'topological', False))
375
372
:param revs: the revisions to include
377
to_store = self.target.weave_store
374
to_texts = self.target.texts
378
375
graph = self.source.get_graph()
379
376
parent_map = graph.get_parent_map(revs)
380
revision_root, planned_versions = self._find_root_ids(
377
rev_order = topo_sort(parent_map)
378
rev_id_to_root_id, root_id_to_rev_ids = self._find_root_ids(
381
379
revs, parent_map, graph)
382
for root_id, versions in planned_versions.iteritems():
383
versionedfile = to_store.get_weave_or_empty(root_id,
384
self.target.get_transaction())
386
for revision_id in versions:
387
if revision_id in versionedfile:
389
parents = parent_map[revision_id]
380
root_id_order = [(rev_id_to_root_id[rev_id], rev_id) for rev_id in
382
# Guaranteed stable, this groups all the file id operations together
383
# retaining topological order within the revisions of a file id.
384
# File id splits and joins would invalidate this, but they don't exist
385
# yet, and are unlikely to in non-rich-root environments anyway.
386
root_id_order.sort(key=operator.itemgetter(0))
387
# Create a record stream containing the roots to create.
389
for key in root_id_order:
390
root_id, rev_id = key
391
rev_parents = parent_map[rev_id]
390
392
# We drop revision parents with different file-ids, because
391
# a version cannot have a version with another file-id as its
393
# that represents a rename of the root to a different location
394
# - its not actually a parent for us. (We could look for that
395
# file id in the revision tree at considerably more expense,
396
# but for now this is sufficient (and reconcile will catch and
397
# correct this anyway).
393
398
# When a parent revision is a ghost, we guess that its root id
395
parents = tuple(p for p in parents if p != NULL_REVISION
396
and revision_root.get(p, root_id) == root_id)
397
result = versionedfile.add_lines_with_ghosts(
398
revision_id, parents, [], parent_texts)
399
parent_texts[revision_id] = result[2]
399
# was unchanged (rather than trimming it from the parent list).
400
parent_keys = tuple((root_id, parent) for parent in rev_parents
401
if parent != NULL_REVISION and
402
rev_id_to_root_id.get(parent, root_id) == root_id)
403
yield FulltextContentFactory(key, parent_keys, None, '')
404
to_texts.insert_record_stream(yield_roots())
401
406
def regenerate_inventory(self, revs):
402
407
"""Generate a new inventory versionedfile in target, convertin data.
449
454
def _fetch_inventory_weave(self, revs, pb):
450
455
self.helper.regenerate_inventory(revs)
452
def _fetch_just_revision_texts(self, version_ids, from_transaction,
457
def _fetch_just_revision_texts(self, version_ids):
454
458
self.helper.fetch_revisions(version_ids)
457
class RemoteToOtherFetcher(GenericRepoFetcher):
459
def _fetch_everything_for_search(self, search, pp):
460
data_stream = self.from_repository.get_data_stream_for_search(search)
461
self.count_copied += self.to_repository.insert_data_stream(data_stream)