296
301
self.bundle.add_info_record(serializer=serializer_format,
297
302
supports_rich_root=supports_rich_root)
299
def iter_file_revisions(self):
300
"""Iterate through all relevant revisions of all files.
302
This is the correct implementation, but is not compatible with bzr.dev,
303
because certain old revisions were not converted correctly, and have
304
the wrong "revision" marker in inventories.
306
transaction = self.repository.get_transaction()
307
altered = self.repository.fileids_altered_by_revision_ids(
309
for file_id, file_revision_ids in altered.iteritems():
310
vf = self.repository.weave_store.get_weave(file_id, transaction)
311
yield vf, file_id, file_revision_ids
313
def iter_file_revisions_aggressive(self):
314
"""Iterate through all relevant revisions of all files.
316
This uses the standard iter_file_revisions to determine what revisions
317
are referred to by inventories, but then uses the versionedfile to
318
determine what the build-dependencies of each required revision.
320
All build dependencies which are not ancestors of the base revision
323
for vf, file_id, file_revision_ids in self.iter_file_revisions():
324
new_revision_ids = set()
325
pending = list(file_revision_ids)
326
while len(pending) > 0:
327
revision_id = pending.pop()
328
if revision_id in new_revision_ids:
330
if revision_id in self.base_ancestry:
332
new_revision_ids.add(revision_id)
333
pending.extend(vf.get_parent_map([revision_id])[revision_id])
334
yield vf, file_id, new_revision_ids
336
304
def write_files(self):
337
305
"""Write bundle records for all revisions of all files"""
338
for vf, file_id, revision_ids in self.iter_file_revisions():
339
self.add_mp_records('file', file_id, vf, revision_ids)
307
altered_fileids = self.repository.fileids_altered_by_revision_ids(
309
for file_id, revision_ids in altered_fileids.iteritems():
310
for revision_id in revision_ids:
311
text_keys.append((file_id, revision_id))
312
self._add_mp_records_keys('file', self.repository.texts, text_keys)
341
314
def write_revisions(self):
342
315
"""Write bundle records for all revisions and signatures"""
343
inv_vf = self.repository.get_inventory_weave()
344
revision_order = list(multiparent.topo_iter(inv_vf, self.revision_ids))
316
inv_vf = self.repository.inventories
317
revision_order = [key[-1] for key in multiparent.topo_iter_keys(inv_vf,
345
319
if self.target is not None and self.target in self.revision_ids:
346
320
revision_order.remove(self.target)
347
321
revision_order.append(self.target)
348
self.add_mp_records('inventory', None, inv_vf, revision_order)
322
self._add_mp_records_keys('inventory', inv_vf, [(revid,) for revid in revision_order])
349
323
parent_map = self.repository.get_parent_map(revision_order)
350
324
for revision_id in revision_order:
351
325
parents = parent_map.get(revision_id, None)
374
348
base = parents[0]
375
349
return base, target
377
def add_mp_records(self, repo_kind, file_id, vf, revision_ids):
351
def _add_mp_records_keys(self, repo_kind, vf, keys):
378
352
"""Add multi-parent diff records to a bundle"""
379
revision_ids = list(multiparent.topo_iter(vf, revision_ids))
380
mpdiffs = vf.make_mpdiffs(revision_ids)
381
sha1s = vf.get_sha1s(revision_ids)
382
parent_map = vf.get_parent_map(revision_ids)
383
for mpdiff, revision_id, sha1, in zip(mpdiffs, revision_ids, sha1s):
384
parents = parent_map[revision_id]
353
ordered_keys = list(multiparent.topo_iter_keys(vf, keys))
354
mpdiffs = vf.make_mpdiffs(ordered_keys)
355
sha1s = vf.get_sha1s(ordered_keys)
356
parent_map = vf.get_parent_map(ordered_keys)
357
for mpdiff, item_key, sha1, in zip(mpdiffs, ordered_keys, sha1s):
358
parents = [key[-1] for key in parent_map[item_key]]
385
359
text = ''.join(mpdiff.to_patch())
360
# Infer file id records as appropriate.
361
if len(item_key) == 2:
362
file_id = item_key[0]
386
365
self.bundle.add_multiparent_record(text, sha1, parents, repo_kind,
387
revision_id, file_id)
366
item_key[-1], file_id)
390
369
class BundleInfoV4(object):
500
479
if self._info is not None:
501
480
raise AssertionError()
502
481
self._handle_info(metadata)
503
if (repo_kind, file_id) != ('file', current_file):
504
if len(pending_file_records) > 0:
505
self._install_mp_records(current_versionedfile,
506
pending_file_records)
482
if (pending_file_records and
483
(repo_kind, file_id) != ('file', current_file)):
484
# Flush the data for a single file - prevents memory
485
# spiking due to buffering all files in memory.
486
self._install_mp_records_keys(self._repository.texts,
487
pending_file_records)
507
488
current_file = None
508
current_versionedfile = None
509
pending_file_records = []
489
del pending_file_records[:]
510
490
if len(pending_inventory_records) > 0 and repo_kind != 'inventory':
511
self._install_inventory_records(inventory_vf,
512
pending_inventory_records)
491
self._install_inventory_records(pending_inventory_records)
513
492
pending_inventory_records = []
514
493
if repo_kind == 'inventory':
515
if inventory_vf is None:
516
inventory_vf = self._repository.get_inventory_weave()
517
if revision_id not in inventory_vf:
518
pending_inventory_records.append((revision_id, metadata,
494
pending_inventory_records.append(((revision_id,), metadata, bytes))
520
495
if repo_kind == 'revision':
521
496
target_revision = revision_id
522
497
self._install_revision(revision_id, metadata, bytes)
524
499
self._install_signature(revision_id, metadata, bytes)
525
500
if repo_kind == 'file':
526
501
current_file = file_id
527
if current_versionedfile is None:
528
current_versionedfile = \
529
self._repository.weave_store.get_weave_or_empty(
530
file_id, self._repository.get_transaction())
531
pending_file_records = []
532
if revision_id in current_versionedfile:
534
pending_file_records.append((revision_id, metadata, bytes))
535
self._install_mp_records(current_versionedfile, pending_file_records)
502
pending_file_records.append(((file_id, revision_id), metadata, bytes))
503
self._install_mp_records_keys(self._repository.texts, pending_file_records)
536
504
return target_revision
538
506
def _handle_info(self, info):
553
521
records if r not in versionedfile]
554
522
versionedfile.add_mpdiffs(vf_records)
556
def _install_inventory_records(self, vf, records):
524
def _install_mp_records_keys(self, versionedfile, records):
525
d_func = multiparent.MultiParent.from_patch
527
for key, meta, text in records:
528
# Adapt to tuple interface: A length two key is a file_id,
529
# revision_id pair, a length 1 key is a
530
# revision/signature/inventory. We need to do this because
531
# the metadata extraction from the bundle has not yet been updated
532
# to use the consistent tuple interface itself.
537
parents = [prefix + (parent,) for parent in meta['parents']]
538
vf_records.append((key, parents, meta['sha1'], d_func(text)))
539
versionedfile.add_mpdiffs(vf_records)
541
def _install_inventory_records(self, records):
557
542
if self._info['serializer'] == self._repository._serializer.format_num:
558
return self._install_mp_records(vf, records)
559
for revision_id, metadata, bytes in records:
543
return self._install_mp_records_keys(self._repository.inventories,
545
for key, metadata, bytes in records:
546
revision_id = key[-1]
560
547
parent_ids = metadata['parents']
561
548
parents = [self._repository.get_inventory(p)
562
549
for p in parent_ids]
579
566
def _handle_root(self, target_inv, parent_ids):
580
567
revision_id = target_inv.revision_id
581
568
if self.update_root:
582
target_inv.root.revision = revision_id
583
store = self._repository.weave_store
584
transaction = self._repository.get_transaction()
585
vf = store.get_weave_or_empty(target_inv.root.file_id, transaction)
586
vf.add_lines(revision_id, parent_ids, [])
569
text_key = (target_inv.root.file_id, revision_id)
570
parent_keys = [(target_inv.root.file_id, parent) for
571
parent in parent_ids]
572
self._repository.texts.add_lines(text_key, parent_keys, [])
587
573
elif not self._repository.supports_rich_root():
588
574
if target_inv.root.revision != revision_id:
589
575
raise errors.IncompatibleRevision(repr(self._repository))
592
577
def _install_revision(self, revision_id, metadata, text):
593
578
if self._repository.has_revision(revision_id):
595
if self._info['serializer'] == self._repository._serializer.format_num:
596
self._repository._add_revision_text(revision_id, text)
598
revision = self._source_serializer.read_revision_from_string(text)
599
self._repository.add_revision(revision.revision_id, revision)
580
revision = self._source_serializer.read_revision_from_string(text)
581
self._repository.add_revision(revision.revision_id, revision)
601
583
def _install_signature(self, revision_id, metadata, text):
602
584
transaction = self._repository.get_transaction()
603
if self._repository._revision_store.has_signature(revision_id,
585
if self._repository.has_signature_for_revision_id(revision_id):
606
self._repository._revision_store.add_revision_signature_text(
607
revision_id, text, transaction)
587
self._repository.add_signature_text(revision_id, text)