760
762
result['size'] = t
765
def get_data_stream(self, revision_ids):
766
raise NotImplementedError(self.get_data_stream)
768
def insert_data_stream(self, stream):
769
"""XXX What does this really do?
771
Is it a substitute for fetch?
772
Should it manage its own write group ?
774
for item_key, bytes in stream:
775
if item_key[0] == 'file':
776
(file_id,) = item_key[1:]
777
knit = self.weave_store.get_weave_or_empty(
778
file_id, self.get_transaction())
779
elif item_key == ('inventory',):
780
knit = self.get_inventory_weave()
781
elif item_key == ('revisions',):
782
knit = self._revision_store.get_revision_file(
783
self.get_transaction())
784
elif item_key == ('signatures',):
785
knit = self._revision_store.get_signature_file(
786
self.get_transaction())
788
raise RepositoryDataStreamError(
789
"Unrecognised data stream key '%s'" % (item_key,))
790
decoded_list = bencode.bdecode(bytes)
791
format = decoded_list.pop(0)
794
for version, options, parents, some_bytes in decoded_list:
795
data_list.append((version, options, len(some_bytes), parents))
796
knit_bytes += some_bytes
797
knit.insert_data_stream(
798
(format, data_list, StringIO(knit_bytes).read))
764
801
def missing_revision_ids(self, other, revision_id=None):
765
802
"""Return the revision ids that other has that this does not.
1537
1576
revision_id.decode('ascii')
1538
1577
except UnicodeDecodeError:
1539
1578
raise errors.NonAsciiRevisionId(method, self)
1580
def revision_graph_can_have_wrong_parents(self):
1581
"""Is it possible for this repository to have a revision graph with
1584
If True, then this repository must also implement
1585
_find_inconsistent_revision_parents so that check and reconcile can
1586
check for inconsistencies before proceeding with other checks that may
1587
depend on the revision index being consistent.
1589
raise NotImplementedError(self.revision_graph_can_have_wrong_parents)
1543
1591
# remove these delegates a while after bzr 0.15
1544
1592
def __make_delegated(name, from_module):
1545
1593
def _deprecated_repository_forwarder():
2421
2469
return f.count_copied, f.failed_revisions
2424
class InterRemoteRepository(InterRepository):
2425
"""Code for converting between RemoteRepository objects.
2427
This just gets an non-remote repository from the RemoteRepository, and calls
2428
InterRepository.get again.
2431
def __init__(self, source, target):
2432
if isinstance(source, remote.RemoteRepository):
2433
source._ensure_real()
2434
real_source = source._real_repository
2436
real_source = source
2437
if isinstance(target, remote.RemoteRepository):
2438
target._ensure_real()
2439
real_target = target._real_repository
2441
real_target = target
2442
self.real_inter = InterRepository.get(real_source, real_target)
2445
def is_compatible(source, target):
2446
if isinstance(source, remote.RemoteRepository):
2472
class InterRemoteToOther(InterRepository):
2474
def __init__(self, source, target):
2475
InterRepository.__init__(self, source, target)
2476
self._real_inter = None
2479
def is_compatible(source, target):
2480
if not isinstance(source, remote.RemoteRepository):
2482
source._ensure_real()
2483
real_source = source._real_repository
2484
# Is source's model compatible with target's model, and are they the
2485
# same format? Currently we can only optimise fetching from an
2486
# identical model & format repo.
2487
assert not isinstance(real_source, remote.RemoteRepository), (
2488
"We don't support remote repos backed by remote repos yet.")
2489
return real_source._format == target._format
2492
def fetch(self, revision_id=None, pb=None):
2493
"""See InterRepository.fetch()."""
2494
from bzrlib.fetch import RemoteToOtherFetcher
2495
mutter("Using fetch logic to copy between %s(remote) and %s(%s)",
2496
self.source, self.target, self.target._format)
2497
# TODO: jam 20070210 This should be an assert, not a translate
2498
revision_id = osutils.safe_revision_id(revision_id)
2499
f = RemoteToOtherFetcher(to_repository=self.target,
2500
from_repository=self.source,
2501
last_revision=revision_id,
2503
return f.count_copied, f.failed_revisions
2506
def _get_repo_format_to_test(self):
2510
class InterOtherToRemote(InterRepository):
2512
def __init__(self, source, target):
2513
InterRepository.__init__(self, source, target)
2514
self._real_inter = None
2517
def is_compatible(source, target):
2448
2518
if isinstance(target, remote.RemoteRepository):
2522
def _ensure_real_inter(self):
2523
if self._real_inter is None:
2524
self.target._ensure_real()
2525
real_target = self.target._real_repository
2526
self._real_inter = InterRepository.get(self.source, real_target)
2452
2528
def copy_content(self, revision_id=None):
2453
self.real_inter.copy_content(revision_id=revision_id)
2529
self._ensure_real_inter()
2530
self._real_inter.copy_content(revision_id=revision_id)
2455
2532
def fetch(self, revision_id=None, pb=None):
2456
self.real_inter.fetch(revision_id=revision_id, pb=pb)
2533
self._ensure_real_inter()
2534
self._real_inter.fetch(revision_id=revision_id, pb=pb)
2459
2537
def _get_repo_format_to_test(self):
2549
2628
if _unescape_re is None:
2550
2629
_unescape_re = re.compile('\&([^;]*);')
2551
2630
return _unescape_re.sub(_unescaper, data)
2633
class _RevisionTextVersionCache(object):
2634
"""A cache of the versionedfile versions for revision and file-id."""
2636
def __init__(self, repository):
2637
self.repository = repository
2638
self.revision_versions = {}
2639
self.revision_parents = {}
2640
self.repo_graph = self.repository.get_graph()
2643
def add_revision_text_versions(self, tree):
2644
"""Cache text version data from the supplied revision tree"""
2646
for path, entry in tree.iter_entries_by_dir():
2647
inv_revisions[entry.file_id] = entry.revision
2648
self.revision_versions[tree.get_revision_id()] = inv_revisions
2649
return inv_revisions
2651
def get_text_version(self, file_id, revision_id):
2652
"""Determine the text version for a given file-id and revision-id"""
2654
inv_revisions = self.revision_versions[revision_id]
2657
tree = self.repository.revision_tree(revision_id)
2658
except errors.RevisionNotPresent:
2659
self.revision_versions[revision_id] = inv_revisions = {}
2661
inv_revisions = self.add_revision_text_versions(tree)
2662
return inv_revisions.get(file_id)
2664
def prepopulate_revs(self, revision_ids):
2665
# Filter out versions that we don't have an inventory for, so that the
2666
# revision_trees() call won't fail.
2667
inv_weave = self.repository.get_inventory_weave()
2668
revs = [r for r in revision_ids if inv_weave.has_version(r)]
2669
# XXX: this loop is very similar to
2670
# bzrlib.fetch.Inter1and2Helper.iter_rev_trees.
2672
for tree in self.repository.revision_trees(revs[:100]):
2673
if tree.inventory.revision_id is None:
2674
tree.inventory.revision_id = tree.get_revision_id()
2675
self.add_revision_text_versions(tree)
2678
def get_parents(self, revision_id):
2680
return self.revision_parents[revision_id]
2682
parents = self.repository.get_parents([revision_id])[0]
2683
self.revision_parents[revision_id] = parents
2686
def heads(self, revision_ids):
2687
revision_ids = tuple(revision_ids)
2689
return self.rev_heads[revision_ids]
2691
heads = self.repo_graph.heads(revision_ids)
2692
self.rev_heads[revision_ids] = heads
2696
class VersionedFileChecker(object):
2698
def __init__(self, planned_revisions, revision_versions, repository):
2699
self.planned_revisions = planned_revisions
2700
self.revision_versions = revision_versions
2701
self.repository = repository
2703
def calculate_file_version_parents(self, revision_id, file_id):
2704
text_revision = self.revision_versions.get_text_version(
2705
file_id, revision_id)
2706
if text_revision is None:
2708
parents_of_text_revision = self.revision_versions.get_parents(
2710
parents_from_inventories = []
2711
for parent in parents_of_text_revision:
2712
if parent == _mod_revision.NULL_REVISION:
2714
introduced_in = self.revision_versions.get_text_version(file_id,
2716
if introduced_in is not None:
2717
parents_from_inventories.append(introduced_in)
2718
heads = set(self.revision_versions.heads(parents_from_inventories))
2720
for parent in parents_from_inventories:
2721
if parent in heads and parent not in new_parents:
2722
new_parents.append(parent)
2723
return tuple(new_parents)
2725
def check_file_version_parents(self, weave, file_id):
2727
for num, revision_id in enumerate(self.planned_revisions):
2728
correct_parents = self.calculate_file_version_parents(
2729
revision_id, file_id)
2730
if correct_parents is None:
2732
text_revision = self.revision_versions.get_text_version(
2733
file_id, revision_id)
2734
knit_parents = tuple(weave.get_parents(text_revision))
2735
if correct_parents != knit_parents:
2736
result[revision_id] = (knit_parents, correct_parents)