~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/vf_repository.py

  • Committer: Jelmer Vernooij
  • Date: 2011-05-16 13:39:39 UTC
  • mto: (5923.1.1 trunk)
  • mto: This revision was merged to the branch mainline in revision 5925.
  • Revision ID: jelmer@samba.org-20110516133939-8u1pc9utas3uw1lt
Require a unicode prompt to be passed into all methods that prompt.

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
 
20
20
from bzrlib.lazy_import import lazy_import
21
21
lazy_import(globals(), """
22
 
import itertools
23
 
 
24
22
from bzrlib import (
25
23
    check,
26
24
    debug,
34
32
    revision as _mod_revision,
35
33
    serializer as _mod_serializer,
36
34
    static_tuple,
37
 
    symbol_versioning,
38
35
    tsort,
39
36
    ui,
40
37
    versionedfile,
78
75
    """Base class for all repository formats that are VersionedFiles-based."""
79
76
 
80
77
    supports_full_versioned_files = True
81
 
    supports_versioned_directories = True
82
78
 
83
79
    # Should commit add an inventory, or an inventory delta to the repository.
84
80
    _commit_inv_deltas = True
279
275
 
280
276
    def _get_delta(self, ie, basis_inv, path):
281
277
        """Get a delta against the basis inventory for ie."""
282
 
        if not basis_inv.has_id(ie.file_id):
 
278
        if ie.file_id not in basis_inv:
283
279
            # add
284
280
            result = (None, path, ie.file_id, ie)
285
281
            self._basis_delta.append(result)
398
394
                # this masks when a change may have occurred against the basis.
399
395
                # To match this we always issue a delta, because the revision
400
396
                # of the root will always be changing.
401
 
                if basis_inv.has_id(ie.file_id):
 
397
                if ie.file_id in basis_inv:
402
398
                    delta = (basis_inv.id2path(ie.file_id), path,
403
399
                        ie.file_id, ie)
404
400
                else:
423
419
        head_set = self._heads(ie.file_id, parent_candiate_entries.keys())
424
420
        heads = []
425
421
        for inv in parent_invs:
426
 
            if inv.has_id(ie.file_id):
 
422
            if ie.file_id in inv:
427
423
                old_rev = inv[ie.file_id].revision
428
424
                if old_rev in head_set:
429
425
                    heads.append(inv[ie.file_id].revision)
1428
1424
            the revision key from each parsed line will be looked up in the
1429
1425
            revision_keys filter.
1430
1426
        :return: a dictionary mapping altered file-ids to an iterable of
1431
 
            revision_ids. Each altered file-ids has the exact revision_ids that
1432
 
            altered it listed explicitly.
 
1427
        revision_ids. Each altered file-ids has the exact revision_ids that
 
1428
        altered it listed explicitly.
1433
1429
        """
1434
1430
        seen = set(self._serializer._find_text_key_references(
1435
1431
                line_iterator).iterkeys())
1464
1460
        :param _inv_weave: The inventory weave from this repository or None.
1465
1461
            If None, the inventory weave will be opened automatically.
1466
1462
        :return: a dictionary mapping altered file-ids to an iterable of
1467
 
            revision_ids. Each altered file-ids has the exact revision_ids that
1468
 
            altered it listed explicitly.
 
1463
        revision_ids. Each altered file-ids has the exact revision_ids that
 
1464
        altered it listed explicitly.
1469
1465
        """
1470
1466
        selected_keys = set((revid,) for revid in revision_ids)
1471
1467
        w = _inv_weave or self.inventories
2468
2464
        return wrong_parents, unused_keys
2469
2465
 
2470
2466
 
2471
 
class InterVersionedFileRepository(InterRepository):
2472
 
 
2473
 
    _walk_to_common_revisions_batch_size = 50
2474
 
 
2475
 
    @needs_write_lock
2476
 
    def fetch(self, revision_id=None, find_ghosts=False,
2477
 
            fetch_spec=None):
2478
 
        """Fetch the content required to construct revision_id.
2479
 
 
2480
 
        The content is copied from self.source to self.target.
2481
 
 
2482
 
        :param revision_id: if None all content is copied, if NULL_REVISION no
2483
 
                            content is copied.
2484
 
        :return: None.
2485
 
        """
2486
 
        ui.ui_factory.warn_experimental_format_fetch(self)
2487
 
        from bzrlib.fetch import RepoFetcher
2488
 
        # See <https://launchpad.net/bugs/456077> asking for a warning here
2489
 
        if self.source._format.network_name() != self.target._format.network_name():
2490
 
            ui.ui_factory.show_user_warning('cross_format_fetch',
2491
 
                from_format=self.source._format,
2492
 
                to_format=self.target._format)
2493
 
        f = RepoFetcher(to_repository=self.target,
2494
 
                               from_repository=self.source,
2495
 
                               last_revision=revision_id,
2496
 
                               fetch_spec=fetch_spec,
2497
 
                               find_ghosts=find_ghosts)
2498
 
 
2499
 
    def _walk_to_common_revisions(self, revision_ids, if_present_ids=None):
2500
 
        """Walk out from revision_ids in source to revisions target has.
2501
 
 
2502
 
        :param revision_ids: The start point for the search.
2503
 
        :return: A set of revision ids.
2504
 
        """
2505
 
        target_graph = self.target.get_graph()
2506
 
        revision_ids = frozenset(revision_ids)
2507
 
        if if_present_ids:
2508
 
            all_wanted_revs = revision_ids.union(if_present_ids)
2509
 
        else:
2510
 
            all_wanted_revs = revision_ids
2511
 
        missing_revs = set()
2512
 
        source_graph = self.source.get_graph()
2513
 
        # ensure we don't pay silly lookup costs.
2514
 
        searcher = source_graph._make_breadth_first_searcher(all_wanted_revs)
2515
 
        null_set = frozenset([_mod_revision.NULL_REVISION])
2516
 
        searcher_exhausted = False
2517
 
        while True:
2518
 
            next_revs = set()
2519
 
            ghosts = set()
2520
 
            # Iterate the searcher until we have enough next_revs
2521
 
            while len(next_revs) < self._walk_to_common_revisions_batch_size:
2522
 
                try:
2523
 
                    next_revs_part, ghosts_part = searcher.next_with_ghosts()
2524
 
                    next_revs.update(next_revs_part)
2525
 
                    ghosts.update(ghosts_part)
2526
 
                except StopIteration:
2527
 
                    searcher_exhausted = True
2528
 
                    break
2529
 
            # If there are ghosts in the source graph, and the caller asked for
2530
 
            # them, make sure that they are present in the target.
2531
 
            # We don't care about other ghosts as we can't fetch them and
2532
 
            # haven't been asked to.
2533
 
            ghosts_to_check = set(revision_ids.intersection(ghosts))
2534
 
            revs_to_get = set(next_revs).union(ghosts_to_check)
2535
 
            if revs_to_get:
2536
 
                have_revs = set(target_graph.get_parent_map(revs_to_get))
2537
 
                # we always have NULL_REVISION present.
2538
 
                have_revs = have_revs.union(null_set)
2539
 
                # Check if the target is missing any ghosts we need.
2540
 
                ghosts_to_check.difference_update(have_revs)
2541
 
                if ghosts_to_check:
2542
 
                    # One of the caller's revision_ids is a ghost in both the
2543
 
                    # source and the target.
2544
 
                    raise errors.NoSuchRevision(
2545
 
                        self.source, ghosts_to_check.pop())
2546
 
                missing_revs.update(next_revs - have_revs)
2547
 
                # Because we may have walked past the original stop point, make
2548
 
                # sure everything is stopped
2549
 
                stop_revs = searcher.find_seen_ancestors(have_revs)
2550
 
                searcher.stop_searching_any(stop_revs)
2551
 
            if searcher_exhausted:
2552
 
                break
2553
 
        return searcher.get_result()
2554
 
 
2555
 
    @needs_read_lock
2556
 
    def search_missing_revision_ids(self,
2557
 
            revision_id=symbol_versioning.DEPRECATED_PARAMETER,
2558
 
            find_ghosts=True, revision_ids=None, if_present_ids=None,
2559
 
            limit=None):
2560
 
        """Return the revision ids that source has that target does not.
2561
 
 
2562
 
        :param revision_id: only return revision ids included by this
2563
 
            revision_id.
2564
 
        :param revision_ids: return revision ids included by these
2565
 
            revision_ids.  NoSuchRevision will be raised if any of these
2566
 
            revisions are not present.
2567
 
        :param if_present_ids: like revision_ids, but will not cause
2568
 
            NoSuchRevision if any of these are absent, instead they will simply
2569
 
            not be in the result.  This is useful for e.g. finding revisions
2570
 
            to fetch for tags, which may reference absent revisions.
2571
 
        :param find_ghosts: If True find missing revisions in deep history
2572
 
            rather than just finding the surface difference.
2573
 
        :return: A bzrlib.graph.SearchResult.
2574
 
        """
2575
 
        if symbol_versioning.deprecated_passed(revision_id):
2576
 
            symbol_versioning.warn(
2577
 
                'search_missing_revision_ids(revision_id=...) was '
2578
 
                'deprecated in 2.4.  Use revision_ids=[...] instead.',
2579
 
                DeprecationWarning, stacklevel=2)
2580
 
            if revision_ids is not None:
2581
 
                raise AssertionError(
2582
 
                    'revision_ids is mutually exclusive with revision_id')
2583
 
            if revision_id is not None:
2584
 
                revision_ids = [revision_id]
2585
 
        del revision_id
2586
 
        # stop searching at found target revisions.
2587
 
        if not find_ghosts and (revision_ids is not None or if_present_ids is
2588
 
                not None):
2589
 
            result = self._walk_to_common_revisions(revision_ids,
2590
 
                    if_present_ids=if_present_ids)
2591
 
            if limit is None:
2592
 
                return result
2593
 
            result_set = result.get_keys()
2594
 
        else:
2595
 
            # generic, possibly worst case, slow code path.
2596
 
            target_ids = set(self.target.all_revision_ids())
2597
 
            source_ids = self._present_source_revisions_for(
2598
 
                revision_ids, if_present_ids)
2599
 
            result_set = set(source_ids).difference(target_ids)
2600
 
        if limit is not None:
2601
 
            topo_ordered = self.source.get_graph().iter_topo_order(result_set)
2602
 
            result_set = set(itertools.islice(topo_ordered, limit))
2603
 
        return self.source.revision_ids_to_search_result(result_set)
2604
 
 
2605
 
    def _present_source_revisions_for(self, revision_ids, if_present_ids=None):
2606
 
        """Returns set of all revisions in ancestry of revision_ids present in
2607
 
        the source repo.
2608
 
 
2609
 
        :param revision_ids: if None, all revisions in source are returned.
2610
 
        :param if_present_ids: like revision_ids, but if any/all of these are
2611
 
            absent no error is raised.
2612
 
        """
2613
 
        if revision_ids is not None or if_present_ids is not None:
2614
 
            # First, ensure all specified revisions exist.  Callers expect
2615
 
            # NoSuchRevision when they pass absent revision_ids here.
2616
 
            if revision_ids is None:
2617
 
                revision_ids = set()
2618
 
            if if_present_ids is None:
2619
 
                if_present_ids = set()
2620
 
            revision_ids = set(revision_ids)
2621
 
            if_present_ids = set(if_present_ids)
2622
 
            all_wanted_ids = revision_ids.union(if_present_ids)
2623
 
            graph = self.source.get_graph()
2624
 
            present_revs = set(graph.get_parent_map(all_wanted_ids))
2625
 
            missing = revision_ids.difference(present_revs)
2626
 
            if missing:
2627
 
                raise errors.NoSuchRevision(self.source, missing.pop())
2628
 
            found_ids = all_wanted_ids.intersection(present_revs)
2629
 
            source_ids = [rev_id for (rev_id, parents) in
2630
 
                          graph.iter_ancestry(found_ids)
2631
 
                          if rev_id != _mod_revision.NULL_REVISION
2632
 
                          and parents is not None]
2633
 
        else:
2634
 
            source_ids = self.source.all_revision_ids()
2635
 
        return set(source_ids)
2636
 
 
2637
 
    @classmethod
2638
 
    def _get_repo_format_to_test(self):
2639
 
        return None
2640
 
 
2641
 
    @classmethod
2642
 
    def is_compatible(cls, source, target):
2643
 
        # The default implementation is compatible with everything
2644
 
        return (source._format.supports_full_versioned_files and
2645
 
                target._format.supports_full_versioned_files)
2646
 
 
2647
 
 
2648
 
class InterDifferingSerializer(InterVersionedFileRepository):
 
2467
class InterDifferingSerializer(InterRepository):
2649
2468
 
2650
2469
    @classmethod
2651
2470
    def _get_repo_format_to_test(self):
2987
2806
        return basis_id, basis_tree
2988
2807
 
2989
2808
 
2990
 
class InterSameDataRepository(InterVersionedFileRepository):
 
2809
class InterSameDataRepository(InterRepository):
2991
2810
    """Code for converting between repositories that represent the same data.
2992
2811
 
2993
2812
    Data format and model must match for this to work.
3011
2830
            target._format.supports_full_versioned_files)
3012
2831
 
3013
2832
 
3014
 
InterRepository.register_optimiser(InterVersionedFileRepository)
3015
2833
InterRepository.register_optimiser(InterDifferingSerializer)
3016
2834
InterRepository.register_optimiser(InterSameDataRepository)
3017
2835
 
3071
2889
        # the parents inserted are not those commit would do - in particular
3072
2890
        # they are not filtered by heads(). RBC, AB
3073
2891
        for revision, tree in parent_trees.iteritems():
3074
 
            if not tree.has_id(ie.file_id):
 
2892
            if ie.file_id not in tree:
3075
2893
                continue
3076
2894
            parent_id = tree.get_file_revision(ie.file_id)
3077
2895
            if parent_id in text_parents: