/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/vf_repository.py

  • Committer: Jelmer Vernooij
  • Date: 2011-05-18 10:24:05 UTC
  • mfrom: (5889 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5903.
  • Revision ID: jelmer@samba.org-20110518102405-isallt5uet1afh4f
merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
from bzrlib.lazy_import import lazy_import
21
21
lazy_import(globals(), """
22
22
from bzrlib import (
 
23
    check,
23
24
    debug,
24
25
    fetch as _mod_fetch,
25
26
    fifo_cache,
31
32
    revision as _mod_revision,
32
33
    serializer as _mod_serializer,
33
34
    static_tuple,
 
35
    symbol_versioning,
34
36
    tsort,
35
37
    ui,
36
38
    versionedfile,
104
106
        super(VersionedFileCommitBuilder, self).__init__(repository,
105
107
            parents, config, timestamp, timezone, committer, revprops,
106
108
            revision_id, lossy)
 
109
        try:
 
110
            basis_id = self.parents[0]
 
111
        except IndexError:
 
112
            basis_id = _mod_revision.NULL_REVISION
 
113
        self.basis_delta_revision = basis_id
107
114
        self.new_inventory = Inventory(None)
108
115
        self._basis_delta = []
109
116
        self.__heads = graph.HeadsCache(repository.get_graph()).heads
123
130
        builder.record_delete().
124
131
        """
125
132
        self._recording_deletes = True
126
 
        try:
127
 
            basis_id = self.parents[0]
128
 
        except IndexError:
129
 
            basis_id = _mod_revision.NULL_REVISION
130
 
        self.basis_delta_revision = basis_id
131
133
 
132
134
    def any_changes(self):
133
135
        """Return True if any entries were changed.
536
538
        else:
537
539
            raise NotImplementedError('unknown kind')
538
540
        ie.revision = self._new_revision_id
539
 
        self._any_changes = True
 
541
        # The initial commit adds a root directory, but this in itself is not
 
542
        # a worthwhile commit.
 
543
        if (self.basis_delta_revision != _mod_revision.NULL_REVISION or
 
544
            path != ""):
 
545
            self._any_changes = True
540
546
        return self._get_delta(ie, basis_inv, path), True, fingerprint
541
547
 
542
548
    def record_iter_changes(self, tree, basis_revision_id, iter_changes,
798
804
            if new_path == '':
799
805
                seen_root = True
800
806
        self.new_inventory = None
801
 
        if len(inv_delta):
 
807
        # The initial commit adds a root directory, but this in itself is not
 
808
        # a worthwhile commit.
 
809
        if ((len(inv_delta) > 0 and basis_revision_id != _mod_revision.NULL_REVISION) or
 
810
            (len(inv_delta) > 1 and basis_revision_id == _mod_revision.NULL_REVISION)):
802
811
            # This should perhaps be guarded by a check that the basis we
803
812
            # commit against is the basis for the commit and if not do a delta
804
813
            # against the basis.
1204
1213
            # result['size'] = t
1205
1214
        return result
1206
1215
 
1207
 
 
1208
1216
    def get_commit_builder(self, branch, parents, config, timestamp=None,
1209
1217
                           timezone=None, committer=None, revprops=None,
1210
1218
                           revision_id=None, lossy=False):
1815
1823
        known_graph = self.revisions.get_known_graph_ancestry(revision_keys)
1816
1824
        return graph.GraphThunkIdsToKeys(known_graph)
1817
1825
 
 
1826
    @needs_read_lock
 
1827
    def get_file_graph(self):
 
1828
        """Return the graph walker for text revisions."""
 
1829
        return graph.Graph(self.texts)
 
1830
 
1818
1831
    def _get_versioned_file_checker(self, text_key_references=None,
1819
1832
        ancestors=None):
1820
1833
        """Return an object suitable for checking versioned files.
1850
1863
            raise errors.NoSuchRevision(self, revision_id)
1851
1864
        return record.get_bytes_as('fulltext')
1852
1865
 
 
1866
    @needs_read_lock
 
1867
    def _check(self, revision_ids, callback_refs, check_repo):
 
1868
        result = check.VersionedFileCheck(self, check_repo=check_repo)
 
1869
        result.check(callback_refs)
 
1870
        return result
 
1871
 
1853
1872
    def _find_inconsistent_revision_parents(self, revisions_iterator=None):
1854
1873
        """Find revisions with different parent lists in the revision object
1855
1874
        and in the index graph.
2446
2465
        return wrong_parents, unused_keys
2447
2466
 
2448
2467
 
2449
 
class InterDifferingSerializer(InterRepository):
 
2468
class InterVersionedFileRepository(InterRepository):
 
2469
 
 
2470
    _walk_to_common_revisions_batch_size = 50
 
2471
 
 
2472
    @needs_write_lock
 
2473
    def fetch(self, revision_id=None, find_ghosts=False,
 
2474
            fetch_spec=None):
 
2475
        """Fetch the content required to construct revision_id.
 
2476
 
 
2477
        The content is copied from self.source to self.target.
 
2478
 
 
2479
        :param revision_id: if None all content is copied, if NULL_REVISION no
 
2480
                            content is copied.
 
2481
        :return: None.
 
2482
        """
 
2483
        ui.ui_factory.warn_experimental_format_fetch(self)
 
2484
        from bzrlib.fetch import RepoFetcher
 
2485
        # See <https://launchpad.net/bugs/456077> asking for a warning here
 
2486
        if self.source._format.network_name() != self.target._format.network_name():
 
2487
            ui.ui_factory.show_user_warning('cross_format_fetch',
 
2488
                from_format=self.source._format,
 
2489
                to_format=self.target._format)
 
2490
        f = RepoFetcher(to_repository=self.target,
 
2491
                               from_repository=self.source,
 
2492
                               last_revision=revision_id,
 
2493
                               fetch_spec=fetch_spec,
 
2494
                               find_ghosts=find_ghosts)
 
2495
 
 
2496
    def _walk_to_common_revisions(self, revision_ids, if_present_ids=None):
 
2497
        """Walk out from revision_ids in source to revisions target has.
 
2498
 
 
2499
        :param revision_ids: The start point for the search.
 
2500
        :return: A set of revision ids.
 
2501
        """
 
2502
        target_graph = self.target.get_graph()
 
2503
        revision_ids = frozenset(revision_ids)
 
2504
        if if_present_ids:
 
2505
            all_wanted_revs = revision_ids.union(if_present_ids)
 
2506
        else:
 
2507
            all_wanted_revs = revision_ids
 
2508
        missing_revs = set()
 
2509
        source_graph = self.source.get_graph()
 
2510
        # ensure we don't pay silly lookup costs.
 
2511
        searcher = source_graph._make_breadth_first_searcher(all_wanted_revs)
 
2512
        null_set = frozenset([_mod_revision.NULL_REVISION])
 
2513
        searcher_exhausted = False
 
2514
        while True:
 
2515
            next_revs = set()
 
2516
            ghosts = set()
 
2517
            # Iterate the searcher until we have enough next_revs
 
2518
            while len(next_revs) < self._walk_to_common_revisions_batch_size:
 
2519
                try:
 
2520
                    next_revs_part, ghosts_part = searcher.next_with_ghosts()
 
2521
                    next_revs.update(next_revs_part)
 
2522
                    ghosts.update(ghosts_part)
 
2523
                except StopIteration:
 
2524
                    searcher_exhausted = True
 
2525
                    break
 
2526
            # If there are ghosts in the source graph, and the caller asked for
 
2527
            # them, make sure that they are present in the target.
 
2528
            # We don't care about other ghosts as we can't fetch them and
 
2529
            # haven't been asked to.
 
2530
            ghosts_to_check = set(revision_ids.intersection(ghosts))
 
2531
            revs_to_get = set(next_revs).union(ghosts_to_check)
 
2532
            if revs_to_get:
 
2533
                have_revs = set(target_graph.get_parent_map(revs_to_get))
 
2534
                # we always have NULL_REVISION present.
 
2535
                have_revs = have_revs.union(null_set)
 
2536
                # Check if the target is missing any ghosts we need.
 
2537
                ghosts_to_check.difference_update(have_revs)
 
2538
                if ghosts_to_check:
 
2539
                    # One of the caller's revision_ids is a ghost in both the
 
2540
                    # source and the target.
 
2541
                    raise errors.NoSuchRevision(
 
2542
                        self.source, ghosts_to_check.pop())
 
2543
                missing_revs.update(next_revs - have_revs)
 
2544
                # Because we may have walked past the original stop point, make
 
2545
                # sure everything is stopped
 
2546
                stop_revs = searcher.find_seen_ancestors(have_revs)
 
2547
                searcher.stop_searching_any(stop_revs)
 
2548
            if searcher_exhausted:
 
2549
                break
 
2550
        return searcher.get_result()
 
2551
 
 
2552
    @needs_read_lock
 
2553
    def search_missing_revision_ids(self,
 
2554
            revision_id=symbol_versioning.DEPRECATED_PARAMETER,
 
2555
            find_ghosts=True, revision_ids=None, if_present_ids=None,
 
2556
            limit=None):
 
2557
        """Return the revision ids that source has that target does not.
 
2558
 
 
2559
        :param revision_id: only return revision ids included by this
 
2560
            revision_id.
 
2561
        :param revision_ids: return revision ids included by these
 
2562
            revision_ids.  NoSuchRevision will be raised if any of these
 
2563
            revisions are not present.
 
2564
        :param if_present_ids: like revision_ids, but will not cause
 
2565
            NoSuchRevision if any of these are absent, instead they will simply
 
2566
            not be in the result.  This is useful for e.g. finding revisions
 
2567
            to fetch for tags, which may reference absent revisions.
 
2568
        :param find_ghosts: If True find missing revisions in deep history
 
2569
            rather than just finding the surface difference.
 
2570
        :return: A bzrlib.graph.SearchResult.
 
2571
        """
 
2572
        if symbol_versioning.deprecated_passed(revision_id):
 
2573
            symbol_versioning.warn(
 
2574
                'search_missing_revision_ids(revision_id=...) was '
 
2575
                'deprecated in 2.4.  Use revision_ids=[...] instead.',
 
2576
                DeprecationWarning, stacklevel=2)
 
2577
            if revision_ids is not None:
 
2578
                raise AssertionError(
 
2579
                    'revision_ids is mutually exclusive with revision_id')
 
2580
            if revision_id is not None:
 
2581
                revision_ids = [revision_id]
 
2582
        del revision_id
 
2583
        # stop searching at found target revisions.
 
2584
        if not find_ghosts and (revision_ids is not None or if_present_ids is
 
2585
                not None):
 
2586
            result = self._walk_to_common_revisions(revision_ids,
 
2587
                    if_present_ids=if_present_ids)
 
2588
            result_set = result.get_keys()
 
2589
        else:
 
2590
            # generic, possibly worst case, slow code path.
 
2591
            target_ids = set(self.target.all_revision_ids())
 
2592
            source_ids = self._present_source_revisions_for(
 
2593
                revision_ids, if_present_ids)
 
2594
            result_set = set(source_ids).difference(target_ids)
 
2595
        if limit is not None:
 
2596
            graph = self.source.get_graph()
 
2597
            topo_ordered = list(graph.iter_topo_order(result_set))
 
2598
            result_set = set(topo_ordered[:limit])
 
2599
        return self.source.revision_ids_to_search_result(result_set)
 
2600
 
 
2601
    def _present_source_revisions_for(self, revision_ids, if_present_ids=None):
 
2602
        """Returns set of all revisions in ancestry of revision_ids present in
 
2603
        the source repo.
 
2604
 
 
2605
        :param revision_ids: if None, all revisions in source are returned.
 
2606
        :param if_present_ids: like revision_ids, but if any/all of these are
 
2607
            absent no error is raised.
 
2608
        """
 
2609
        if revision_ids is not None or if_present_ids is not None:
 
2610
            # First, ensure all specified revisions exist.  Callers expect
 
2611
            # NoSuchRevision when they pass absent revision_ids here.
 
2612
            if revision_ids is None:
 
2613
                revision_ids = set()
 
2614
            if if_present_ids is None:
 
2615
                if_present_ids = set()
 
2616
            revision_ids = set(revision_ids)
 
2617
            if_present_ids = set(if_present_ids)
 
2618
            all_wanted_ids = revision_ids.union(if_present_ids)
 
2619
            graph = self.source.get_graph()
 
2620
            present_revs = set(graph.get_parent_map(all_wanted_ids))
 
2621
            missing = revision_ids.difference(present_revs)
 
2622
            if missing:
 
2623
                raise errors.NoSuchRevision(self.source, missing.pop())
 
2624
            found_ids = all_wanted_ids.intersection(present_revs)
 
2625
            source_ids = [rev_id for (rev_id, parents) in
 
2626
                          graph.iter_ancestry(found_ids)
 
2627
                          if rev_id != _mod_revision.NULL_REVISION
 
2628
                          and parents is not None]
 
2629
        else:
 
2630
            source_ids = self.source.all_revision_ids()
 
2631
        return set(source_ids)
 
2632
 
 
2633
    @classmethod
 
2634
    def _get_repo_format_to_test(self):
 
2635
        return None
 
2636
 
 
2637
    @classmethod
 
2638
    def is_compatible(cls, source, target):
 
2639
        # The default implementation is compatible with everything
 
2640
        return (source._format.supports_full_versioned_files and
 
2641
                target._format.supports_full_versioned_files)
 
2642
 
 
2643
 
 
2644
class InterDifferingSerializer(InterVersionedFileRepository):
2450
2645
 
2451
2646
    @classmethod
2452
2647
    def _get_repo_format_to_test(self):
2788
2983
        return basis_id, basis_tree
2789
2984
 
2790
2985
 
2791
 
class InterSameDataRepository(InterRepository):
 
2986
class InterSameDataRepository(InterVersionedFileRepository):
2792
2987
    """Code for converting between repositories that represent the same data.
2793
2988
 
2794
2989
    Data format and model must match for this to work.
2812
3007
            target._format.supports_full_versioned_files)
2813
3008
 
2814
3009
 
 
3010
InterRepository.register_optimiser(InterVersionedFileRepository)
2815
3011
InterRepository.register_optimiser(InterDifferingSerializer)
2816
3012
InterRepository.register_optimiser(InterSameDataRepository)
2817
3013