~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/repository.py

Merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
495
495
        attempted.
496
496
        """
497
497
 
498
 
    @needs_write_lock
499
498
    def add_inventory(self, revision_id, inv, parents):
500
499
        """Add the inventory inv to the repository as revision_id.
501
500
        
526
525
        return inv_vf.add_lines(revision_id, final_parents, lines,
527
526
            check_content=check_content)[0]
528
527
 
529
 
    @needs_write_lock
530
528
    def add_revision(self, revision_id, rev, inv=None, config=None):
531
529
        """Add rev to the revision store as revision_id.
532
530
 
813
811
    def get_data_stream(self, revision_ids):
814
812
        raise NotImplementedError(self.get_data_stream)
815
813
 
 
814
    def get_data_stream_for_search(self, search_result):
 
815
        """Get a data stream that can be inserted to a repository.
 
816
 
 
817
        :param search_result: A bzrlib.graph.SearchResult selecting the
 
818
            revisions to get.
 
819
        :return: A data stream that can be inserted into a repository using
 
820
            insert_data_stream.
 
821
        """
 
822
        raise NotImplementedError(self.get_data_stream_for_search)
 
823
 
816
824
    def insert_data_stream(self, stream):
817
825
        """XXX What does this really do? 
818
826
        
833
841
                knit = self._revision_store.get_signature_file(
834
842
                    self.get_transaction())
835
843
            else:
836
 
                raise RepositoryDataStreamError(
 
844
                raise errors.RepositoryDataStreamError(
837
845
                    "Unrecognised data stream key '%s'" % (item_key,))
838
846
            decoded_list = bencode.bdecode(bytes)
839
847
            format = decoded_list.pop(0)
852
860
                (format, data_list, reader_func))
853
861
 
854
862
    @needs_read_lock
 
863
    def search_missing_revision_ids(self, other, revision_id=None, find_ghosts=True):
 
864
        """Return the revision ids that other has that this does not.
 
865
        
 
866
        These are returned in topological order.
 
867
 
 
868
        revision_id: only return revision ids included by revision_id.
 
869
        """
 
870
        return InterRepository.get(other, self).search_missing_revision_ids(
 
871
            revision_id, find_ghosts)
 
872
 
 
873
    @deprecated_method(symbol_versioning.one_two)
 
874
    @needs_read_lock
855
875
    def missing_revision_ids(self, other, revision_id=None, find_ghosts=True):
856
876
        """Return the revision ids that other has that this does not.
857
877
        
859
879
 
860
880
        revision_id: only return revision ids included by revision_id.
861
881
        """
862
 
        return InterRepository.get(other, self).missing_revision_ids(
863
 
            revision_id, find_ghosts)
 
882
        keys =  self.search_missing_revision_ids(
 
883
            other, revision_id, find_ghosts).get_keys()
 
884
        other.lock_read()
 
885
        try:
 
886
            parents = other.get_graph().get_parent_map(keys)
 
887
        finally:
 
888
            other.unlock()
 
889
        return tsort.topo_sort(parents)
864
890
 
865
891
    @staticmethod
866
892
    def open(base):
1752
1778
        """Return the graph walker for this repository format"""
1753
1779
        parents_provider = self._make_parents_provider()
1754
1780
        if (other_repository is not None and
1755
 
            other_repository.bzrdir.transport.base !=
1756
 
            self.bzrdir.transport.base):
 
1781
            not self.has_same_location(other_repository)):
1757
1782
            parents_provider = graph._StackedParentsProvider(
1758
1783
                [parents_provider, other_repository._make_parents_provider()])
1759
1784
        return graph.Graph(parents_provider)
1762
1787
        """Return an object suitable for checking versioned files."""
1763
1788
        return _VersionedFileChecker(self)
1764
1789
 
 
1790
    def revision_ids_to_search_result(self, result_set):
 
1791
        """Convert a set of revision ids to a graph SearchResult."""
 
1792
        result_parents = set()
 
1793
        for parents in self.get_graph().get_parent_map(
 
1794
            result_set).itervalues():
 
1795
            result_parents.update(parents)
 
1796
        included_keys = result_set.intersection(result_parents)
 
1797
        start_keys = result_set.difference(included_keys)
 
1798
        exclude_keys = result_parents.difference(result_set)
 
1799
        result = graph.SearchResult(start_keys, exclude_keys,
 
1800
            len(result_set), result_set)
 
1801
        return result
 
1802
 
1765
1803
    @needs_write_lock
1766
1804
    def set_make_working_trees(self, new_value):
1767
1805
        """Set the policy flag for making working trees when creating branches.
1848
1886
        depend on the revision index being consistent.
1849
1887
        """
1850
1888
        raise NotImplementedError(self.revision_graph_can_have_wrong_parents)
1851
 
        
 
1889
 
 
1890
 
1852
1891
# remove these delegates a while after bzr 0.15
1853
1892
def __make_delegated(name, from_module):
1854
1893
    def _deprecated_repository_forwarder():
2051
2090
    # Set to True or False in derived classes. True indicates that the format
2052
2091
    # supports ghosts gracefully.
2053
2092
    supports_ghosts = None
 
2093
    # Can this repository be given external locations to lookup additional
 
2094
    # data. Set to True or False in derived classes.
 
2095
    supports_external_lookups = None
2054
2096
 
2055
2097
    def __str__(self):
2056
2098
        return "<%s>" % self.__class__.__name__
2077
2119
        except errors.NoSuchFile:
2078
2120
            raise errors.NoRepositoryPresent(a_bzrdir)
2079
2121
        except KeyError:
2080
 
            raise errors.UnknownFormatError(format=format_string)
 
2122
            raise errors.UnknownFormatError(format=format_string,
 
2123
                                            kind='repository')
2081
2124
 
2082
2125
    @classmethod
2083
2126
    def register_format(klass, format):
2195
2238
 
2196
2239
    rich_root_data = False
2197
2240
    supports_tree_reference = False
 
2241
    supports_external_lookups = False
2198
2242
    _matchingbzrdir = bzrdir.BzrDirMetaFormat1()
2199
2243
 
2200
2244
    def __init__(self):
2259
2303
 
2260
2304
# Pack-based formats. There is one format for pre-subtrees, and one for
2261
2305
# post-subtrees to allow ease of testing.
2262
 
# NOTE: These are experimental in 0.92.
 
2306
# NOTE: These are experimental in 0.92. Stable in 1.0 and above
2263
2307
format_registry.register_lazy(
2264
2308
    'Bazaar pack repository format 1 (needs bzr 0.92)\n',
2265
2309
    'bzrlib.repofmt.pack_repo',
2275
2319
    'bzrlib.repofmt.pack_repo',
2276
2320
    'RepositoryFormatKnitPack4',
2277
2321
    )
 
2322
# Development formats. 
 
2323
# 1.2->1.3
 
2324
# development 0 - stub to introduce development versioning scheme.
 
2325
format_registry.register_lazy(
 
2326
    "Bazaar development format 0 (needs bzr.dev from before 1.3)\n",
 
2327
    'bzrlib.repofmt.pack_repo',
 
2328
    'RepositoryFormatPackDevelopment0',
 
2329
    )
 
2330
format_registry.register_lazy(
 
2331
    ("Bazaar development format 0 with subtree support "
 
2332
        "(needs bzr.dev from before 1.3)\n"),
 
2333
    'bzrlib.repofmt.pack_repo',
 
2334
    'RepositoryFormatPackDevelopment0Subtree',
 
2335
    )
 
2336
# 1.3->1.4 go below here
2278
2337
 
2279
2338
 
2280
2339
class InterRepository(InterObject):
2337
2396
            # we don't care about other ghosts as we can't fetch them and
2338
2397
            # haven't been asked to.
2339
2398
            next_revs = set(next_revs)
2340
 
            next_revs.difference_update(null_set)
2341
 
            have_revs = self.target.has_revisions(next_revs)
 
2399
            # we always have NULL_REVISION present.
 
2400
            have_revs = self.target.has_revisions(next_revs).union(null_set)
2342
2401
            missing_revs.update(next_revs - have_revs)
2343
2402
            searcher.stop_searching_any(have_revs)
2344
 
        return missing_revs
 
2403
        return searcher.get_result()
2345
2404
   
 
2405
    @deprecated_method(symbol_versioning.one_two)
2346
2406
    @needs_read_lock
2347
2407
    def missing_revision_ids(self, revision_id=None, find_ghosts=True):
2348
2408
        """Return the revision ids that source has that target does not.
2354
2414
        :param find_ghosts: If True find missing revisions in deep history
2355
2415
            rather than just finding the surface difference.
2356
2416
        """
 
2417
        return list(self.search_missing_revision_ids(
 
2418
            revision_id, find_ghosts).get_keys())
 
2419
 
 
2420
    @needs_read_lock
 
2421
    def search_missing_revision_ids(self, revision_id=None, find_ghosts=True):
 
2422
        """Return the revision ids that source has that target does not.
 
2423
        
 
2424
        :param revision_id: only return revision ids included by this
 
2425
                            revision_id.
 
2426
        :param find_ghosts: If True find missing revisions in deep history
 
2427
            rather than just finding the surface difference.
 
2428
        :return: A bzrlib.graph.SearchResult.
 
2429
        """
2357
2430
        # stop searching at found target revisions.
2358
2431
        if not find_ghosts and revision_id is not None:
2359
2432
            return self._walk_to_common_revisions([revision_id])
2366
2439
        else:
2367
2440
            source_ids = self.source.all_revision_ids()
2368
2441
        result_set = set(source_ids).difference(target_ids)
2369
 
        # this may look like a no-op: its not. It preserves the ordering
2370
 
        # other_ids had while only returning the members from other_ids
2371
 
        # that we've decided we need.
2372
 
        return [rev_id for rev_id in source_ids if rev_id in result_set]
 
2442
        return self.source.revision_ids_to_search_result(result_set)
2373
2443
 
2374
2444
    @staticmethod
2375
2445
    def _same_model(source, target):
2516
2586
        return f.count_copied, f.failed_revisions
2517
2587
 
2518
2588
    @needs_read_lock
2519
 
    def missing_revision_ids(self, revision_id=None, find_ghosts=True):
 
2589
    def search_missing_revision_ids(self, revision_id=None, find_ghosts=True):
2520
2590
        """See InterRepository.missing_revision_ids()."""
2521
2591
        # we want all revisions to satisfy revision_id in source.
2522
2592
        # but we don't want to stat every file here and there.
2542
2612
        # we do not have a revision as that would be pointless.
2543
2613
        target_ids = set(self.target._all_possible_ids())
2544
2614
        possibly_present_revisions = target_ids.intersection(source_ids_set)
2545
 
        actually_present_revisions = set(self.target._eliminate_revisions_not_present(possibly_present_revisions))
 
2615
        actually_present_revisions = set(
 
2616
            self.target._eliminate_revisions_not_present(possibly_present_revisions))
2546
2617
        required_revisions = source_ids_set.difference(actually_present_revisions)
2547
 
        required_topo_revisions = [rev_id for rev_id in source_ids if rev_id in required_revisions]
2548
2618
        if revision_id is not None:
2549
2619
            # we used get_ancestry to determine source_ids then we are assured all
2550
2620
            # revisions referenced are present as they are installed in topological order.
2551
2621
            # and the tip revision was validated by get_ancestry.
2552
 
            return required_topo_revisions
 
2622
            result_set = required_revisions
2553
2623
        else:
2554
2624
            # if we just grabbed the possibly available ids, then 
2555
2625
            # we only have an estimate of whats available and need to validate
2556
2626
            # that against the revision records.
2557
 
            return self.source._eliminate_revisions_not_present(required_topo_revisions)
 
2627
            result_set = set(
 
2628
                self.source._eliminate_revisions_not_present(required_revisions))
 
2629
        return self.source.revision_ids_to_search_result(result_set)
2558
2630
 
2559
2631
 
2560
2632
class InterKnitRepo(InterSameDataRepository):
2594
2666
        return f.count_copied, f.failed_revisions
2595
2667
 
2596
2668
    @needs_read_lock
2597
 
    def missing_revision_ids(self, revision_id=None, find_ghosts=True):
 
2669
    def search_missing_revision_ids(self, revision_id=None, find_ghosts=True):
2598
2670
        """See InterRepository.missing_revision_ids()."""
2599
2671
        if revision_id is not None:
2600
2672
            source_ids = self.source.get_ancestry(revision_id)
2609
2681
        # we do not have a revision as that would be pointless.
2610
2682
        target_ids = set(self.target.all_revision_ids())
2611
2683
        possibly_present_revisions = target_ids.intersection(source_ids_set)
2612
 
        actually_present_revisions = set(self.target._eliminate_revisions_not_present(possibly_present_revisions))
 
2684
        actually_present_revisions = set(
 
2685
            self.target._eliminate_revisions_not_present(possibly_present_revisions))
2613
2686
        required_revisions = source_ids_set.difference(actually_present_revisions)
2614
 
        required_topo_revisions = [rev_id for rev_id in source_ids if rev_id in required_revisions]
2615
2687
        if revision_id is not None:
2616
2688
            # we used get_ancestry to determine source_ids then we are assured all
2617
2689
            # revisions referenced are present as they are installed in topological order.
2618
2690
            # and the tip revision was validated by get_ancestry.
2619
 
            return required_topo_revisions
 
2691
            result_set = required_revisions
2620
2692
        else:
2621
2693
            # if we just grabbed the possibly available ids, then 
2622
2694
            # we only have an estimate of whats available and need to validate
2623
2695
            # that against the revision records.
2624
 
            return self.source._eliminate_revisions_not_present(required_topo_revisions)
 
2696
            result_set = set(
 
2697
                self.source._eliminate_revisions_not_present(required_revisions))
 
2698
        return self.source.revision_ids_to_search_result(result_set)
2625
2699
 
2626
2700
 
2627
2701
class InterPackRepo(InterSameDataRepository):
2674
2748
            return (0, [])
2675
2749
        else:
2676
2750
            try:
2677
 
                revision_ids = self.missing_revision_ids(revision_id,
2678
 
                    find_ghosts=find_ghosts)
 
2751
                revision_ids = self.search_missing_revision_ids(revision_id,
 
2752
                    find_ghosts=find_ghosts).get_keys()
2679
2753
            except errors.NoSuchRevision:
2680
2754
                raise errors.InstallFailed([revision_id])
2681
2755
        packs = self.source._pack_collection.all_packs()
2692
2766
            return (0, [])
2693
2767
 
2694
2768
    @needs_read_lock
2695
 
    def missing_revision_ids(self, revision_id=None, find_ghosts=True):
 
2769
    def search_missing_revision_ids(self, revision_id=None, find_ghosts=True):
2696
2770
        """See InterRepository.missing_revision_ids().
2697
2771
        
2698
2772
        :param find_ghosts: Find ghosts throughout the ancestry of
2711
2785
        # have in target, but don't try to check for existence where we know
2712
2786
        # we do not have a revision as that would be pointless.
2713
2787
        target_ids = set(self.target.all_revision_ids())
2714
 
        return [r for r in source_ids if (r not in target_ids)]
 
2788
        result_set = set(source_ids).difference(target_ids)
 
2789
        return self.source.revision_ids_to_search_result(result_set)
2715
2790
 
2716
2791
 
2717
2792
class InterModel1and2(InterRepository):
2771
2846
        try:
2772
2847
            from bzrlib.repofmt.knitrepo import (RepositoryFormatKnit1,
2773
2848
                RepositoryFormatKnit3)
2774
 
            from bzrlib.repofmt.pack_repo import (RepositoryFormatKnitPack1,
2775
 
                RepositoryFormatKnitPack3)
2776
 
            return (isinstance(source._format,
2777
 
                    (RepositoryFormatKnit1, RepositoryFormatKnitPack1)) and
2778
 
                isinstance(target._format,
2779
 
                    (RepositoryFormatKnit3, RepositoryFormatKnitPack3))
2780
 
                )
 
2849
            from bzrlib.repofmt.pack_repo import (
 
2850
                RepositoryFormatKnitPack1,
 
2851
                RepositoryFormatKnitPack3,
 
2852
                RepositoryFormatPackDevelopment0,
 
2853
                RepositoryFormatPackDevelopment0Subtree,
 
2854
                )
 
2855
            nosubtrees = (
 
2856
                RepositoryFormatKnit1,
 
2857
                RepositoryFormatKnitPack1,
 
2858
                RepositoryFormatPackDevelopment0,
 
2859
                )
 
2860
            subtrees = (
 
2861
                RepositoryFormatKnit3,
 
2862
                RepositoryFormatKnitPack3,
 
2863
                RepositoryFormatPackDevelopment0Subtree,
 
2864
                )
 
2865
            return (isinstance(source._format, nosubtrees) and
 
2866
                isinstance(target._format, subtrees))
2781
2867
        except AttributeError:
2782
2868
            return False
2783
2869
 
2816
2902
    @needs_write_lock
2817
2903
    def fetch(self, revision_id=None, pb=None, find_ghosts=False):
2818
2904
        """See InterRepository.fetch()."""
2819
 
        revision_ids = self.target.missing_revision_ids(self.source,
2820
 
            revision_id, find_ghosts=find_ghosts)
 
2905
        revision_ids = self.target.search_missing_revision_ids(self.source,
 
2906
            revision_id, find_ghosts=find_ghosts).get_keys()
 
2907
        revision_ids = tsort.topo_sort(
 
2908
            self.source.get_graph().get_parent_map(revision_ids))
2821
2909
        def revisions_iterator():
2822
2910
            for current_revision_id in revision_ids:
2823
2911
                revision = self.source.get_revision(current_revision_id)