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, in zip(mpdiffs, ordered_keys):
358
sha1 = sha1s[item_key]
359
parents = [key[-1] for key in parent_map[item_key]]
385
360
text = ''.join(mpdiff.to_patch())
361
# Infer file id records as appropriate.
362
if len(item_key) == 2:
363
file_id = item_key[0]
386
366
self.bundle.add_multiparent_record(text, sha1, parents, repo_kind,
387
revision_id, file_id)
367
item_key[-1], file_id)
390
370
class BundleInfoV4(object):
500
480
if self._info is not None:
501
481
raise AssertionError()
502
482
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)
483
if (pending_file_records and
484
(repo_kind, file_id) != ('file', current_file)):
485
# Flush the data for a single file - prevents memory
486
# spiking due to buffering all files in memory.
487
self._install_mp_records_keys(self._repository.texts,
488
pending_file_records)
507
489
current_file = None
508
current_versionedfile = None
509
pending_file_records = []
490
del pending_file_records[:]
510
491
if len(pending_inventory_records) > 0 and repo_kind != 'inventory':
511
self._install_inventory_records(inventory_vf,
512
pending_inventory_records)
492
self._install_inventory_records(pending_inventory_records)
513
493
pending_inventory_records = []
514
494
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,
495
pending_inventory_records.append(((revision_id,), metadata, bytes))
520
496
if repo_kind == 'revision':
521
497
target_revision = revision_id
522
498
self._install_revision(revision_id, metadata, bytes)
524
500
self._install_signature(revision_id, metadata, bytes)
525
501
if repo_kind == 'file':
526
502
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)
503
pending_file_records.append(((file_id, revision_id), metadata, bytes))
504
self._install_mp_records_keys(self._repository.texts, pending_file_records)
536
505
return target_revision
538
507
def _handle_info(self, info):
553
522
records if r not in versionedfile]
554
523
versionedfile.add_mpdiffs(vf_records)
556
def _install_inventory_records(self, vf, records):
525
def _install_mp_records_keys(self, versionedfile, records):
526
d_func = multiparent.MultiParent.from_patch
528
for key, meta, text in records:
529
# Adapt to tuple interface: A length two key is a file_id,
530
# revision_id pair, a length 1 key is a
531
# revision/signature/inventory. We need to do this because
532
# the metadata extraction from the bundle has not yet been updated
533
# to use the consistent tuple interface itself.
538
parents = [prefix + (parent,) for parent in meta['parents']]
539
vf_records.append((key, parents, meta['sha1'], d_func(text)))
540
versionedfile.add_mpdiffs(vf_records)
542
def _install_inventory_records(self, records):
557
543
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:
544
return self._install_mp_records_keys(self._repository.inventories,
546
for key, metadata, bytes in records:
547
revision_id = key[-1]
560
548
parent_ids = metadata['parents']
561
549
parents = [self._repository.get_inventory(p)
562
550
for p in parent_ids]
579
567
def _handle_root(self, target_inv, parent_ids):
580
568
revision_id = target_inv.revision_id
581
569
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, [])
570
text_key = (target_inv.root.file_id, revision_id)
571
parent_keys = [(target_inv.root.file_id, parent) for
572
parent in parent_ids]
573
self._repository.texts.add_lines(text_key, parent_keys, [])
587
574
elif not self._repository.supports_rich_root():
588
575
if target_inv.root.revision != revision_id:
589
576
raise errors.IncompatibleRevision(repr(self._repository))
592
578
def _install_revision(self, revision_id, metadata, text):
593
579
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)
581
revision = self._source_serializer.read_revision_from_string(text)
582
self._repository.add_revision(revision.revision_id, revision)
601
584
def _install_signature(self, revision_id, metadata, text):
602
585
transaction = self._repository.get_transaction()
603
if self._repository._revision_store.has_signature(revision_id,
586
if self._repository.has_signature_for_revision_id(revision_id):
606
self._repository._revision_store.add_revision_signature_text(
607
revision_id, text, transaction)
588
self._repository.add_signature_text(revision_id, text)