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)
306
texts = self.repository.texts
308
for file_id, revision_ids in \
309
self.repository.fileids_altered_by_revision_ids(
310
self.revision_ids).iteritems():
311
revision_ids = list(revision_ids)
312
for revision_id in revision_ids:
313
text_keys.append((file_id, revision_id))
314
self.add_mp_records_keys('file', texts, text_keys)
341
316
def write_revisions(self):
342
317
"""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))
318
inv_vf = self.repository.inventories
319
revision_order = [key[-1] for key in multiparent.topo_iter_keys(inv_vf,
345
321
if self.target is not None and self.target in self.revision_ids:
346
322
revision_order.remove(self.target)
347
323
revision_order.append(self.target)
348
self.add_mp_records('inventory', None, inv_vf, revision_order)
324
self.add_mp_records_keys('inventory', inv_vf, [(revid,) for revid in revision_order])
349
325
parent_map = self.repository.get_parent_map(revision_order)
350
326
for revision_id in revision_order:
351
327
parents = parent_map.get(revision_id, None)
374
350
base = parents[0]
375
351
return base, target
377
def add_mp_records(self, repo_kind, file_id, vf, revision_ids):
353
def add_mp_records_keys(self, repo_kind, vf, keys):
378
354
"""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]
355
ordered_keys = list(multiparent.topo_iter_keys(vf, keys))
356
mpdiffs = vf.make_mpdiffs(ordered_keys)
357
sha1s = vf.get_sha1s(ordered_keys)
358
parent_map = vf.get_parent_map(ordered_keys)
359
for mpdiff, item_key, sha1, in zip(mpdiffs, ordered_keys, sha1s):
360
parents = [key[-1] for key in parent_map[item_key]]
385
361
text = ''.join(mpdiff.to_patch())
362
# Infer file id records as appropriate.
363
if len(item_key) == 2:
364
file_id = item_key[0]
386
367
self.bundle.add_multiparent_record(text, sha1, parents, repo_kind,
387
revision_id, file_id)
368
item_key[-1], file_id)
390
371
class BundleInfoV4(object):
500
481
if self._info is not None:
501
482
raise AssertionError()
502
483
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)
484
if (pending_file_records and
485
(repo_kind, file_id) != ('file', current_file)):
486
# Flush the data for a single file - prevents memory
487
# spiking due to buffering all files in memory.
488
self._install_mp_records_keys(self._repository.texts,
489
pending_file_records)
507
490
current_file = None
508
current_versionedfile = None
509
pending_file_records = []
491
del pending_file_records[:]
510
492
if len(pending_inventory_records) > 0 and repo_kind != 'inventory':
511
self._install_inventory_records(inventory_vf,
512
pending_inventory_records)
493
self._install_inventory_records(pending_inventory_records)
513
494
pending_inventory_records = []
514
495
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,
496
pending_inventory_records.append(((revision_id,), metadata, bytes))
520
497
if repo_kind == 'revision':
521
498
target_revision = revision_id
522
499
self._install_revision(revision_id, metadata, bytes)
524
501
self._install_signature(revision_id, metadata, bytes)
525
502
if repo_kind == 'file':
526
503
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)
504
pending_file_records.append(((file_id, revision_id), metadata, bytes))
505
self._install_mp_records_keys(self._repository.texts, pending_file_records)
536
506
return target_revision
538
508
def _handle_info(self, info):
553
523
records if r not in versionedfile]
554
524
versionedfile.add_mpdiffs(vf_records)
556
def _install_inventory_records(self, vf, records):
526
def _install_mp_records_keys(self, versionedfile, records):
527
d_func = multiparent.MultiParent.from_patch
529
for key, meta, text in records:
530
# Adapt to tuple interface:
535
parents = [prefix + (parent,) for parent in meta['parents']]
536
vf_records.append((key, parents, meta['sha1'], d_func(text)))
537
versionedfile.add_mpdiffs(vf_records)
539
def _install_inventory_records(self, records):
557
540
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:
541
return self._install_mp_records_keys(self._repository.inventories,
543
for key, metadata, bytes in records:
544
revision_id = key[-1]
560
545
parent_ids = metadata['parents']
561
546
parents = [self._repository.get_inventory(p)
562
547
for p in parent_ids]
579
564
def _handle_root(self, target_inv, parent_ids):
580
565
revision_id = target_inv.revision_id
581
566
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, [])
567
text_key = (target_inv.root.file_id, revision_id)
568
parent_keys = [(target_inv.root.file_id, parent) for
569
parent in parent_ids]
570
self._repository.texts.add_lines(text_key, parent_keys, [])
587
571
elif not self._repository.supports_rich_root():
588
572
if target_inv.root.revision != revision_id:
589
573
raise errors.IncompatibleRevision(repr(self._repository))
592
575
def _install_revision(self, revision_id, metadata, text):
593
576
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)
578
revision = self._source_serializer.read_revision_from_string(text)
579
self._repository.add_revision(revision.revision_id, revision)
601
581
def _install_signature(self, revision_id, metadata, text):
602
582
transaction = self._repository.get_transaction()
603
if self._repository._revision_store.has_signature(revision_id,
583
if self._repository.has_signature_for_revision_id(revision_id):
606
self._repository._revision_store.add_revision_signature_text(
607
revision_id, text, transaction)
585
self._repository.add_signature_text(revision_id, text)