~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

  • Committer: Jelmer Vernooij
  • Date: 2011-04-19 17:14:47 UTC
  • mto: This revision was merged to the branch mainline in revision 5842.
  • Revision ID: jelmer@samba.org-20110419171447-iucjejqkyb6fwbwk
Split out full history branch code.

Show diffs side-by-side

added added

removed removed

Lines of Context:
751
751
        """Print `file` to stdout."""
752
752
        raise NotImplementedError(self.print_file)
753
753
 
 
754
    @deprecated_method(deprecated_in((2, 4, 0)))
 
755
    @needs_write_lock
754
756
    def set_revision_history(self, rev_history):
755
 
        raise NotImplementedError(self.set_revision_history)
 
757
        """See Branch.set_revision_history."""
 
758
        if len(rev_history) == 0:
 
759
            revid = _mod_revision.NULL_REVISION
 
760
        else:
 
761
            revid = rev_history[-1]
 
762
        self.set_last_revision_info(len(rev_history), revid)
 
763
        self._cache_revision_history(rev_history)
 
764
 
 
765
    @needs_write_lock
 
766
    def set_last_revision_info(self, revno, revision_id):
 
767
        revision_id = _mod_revision.ensure_null(revision_id)
 
768
        old_revno, old_revid = self.last_revision_info()
 
769
        if self._get_append_revisions_only():
 
770
            self._check_history_violation(revision_id)
 
771
        self._run_pre_change_branch_tip_hooks(revno, revision_id)
 
772
        self._write_last_revision_info(revno, revision_id)
 
773
        self._clear_cached_state()
 
774
        self._last_revision_info_cache = revno, revision_id
 
775
        self._run_post_change_branch_tip_hooks(old_revno, old_revid)
756
776
 
757
777
    @needs_write_lock
758
778
    def set_parent(self, url):
988
1008
        :return: A tuple (revno, revision_id).
989
1009
        """
990
1010
        if self._last_revision_info_cache is None:
991
 
            self._last_revision_info_cache = self._last_revision_info()
 
1011
            self._last_revision_info_cache = self._read_last_revision_info()
992
1012
        return self._last_revision_info_cache
993
1013
 
994
 
    def _last_revision_info(self):
995
 
        rh = self.revision_history()
996
 
        revno = len(rh)
997
 
        if revno:
998
 
            return (revno, rh[-1])
999
 
        else:
1000
 
            return (0, _mod_revision.NULL_REVISION)
 
1014
    def _read_last_revision_info(self):
 
1015
        raise NotImplementedError(self._last_revision_info)
1001
1016
 
1002
1017
    def update_revisions(self, other, stop_revision=None, overwrite=False,
1003
1018
                         graph=None, fetch_tags=True):
2502
2517
        """See Branch.print_file."""
2503
2518
        return self.repository.print_file(file, revision_id)
2504
2519
 
2505
 
    @deprecated_method(deprecated_in((2, 4, 0)))
2506
 
    @needs_write_lock
2507
 
    def set_revision_history(self, rev_history):
2508
 
        """See Branch.set_revision_history."""
2509
 
        self._set_revision_history(rev_history)
2510
 
 
2511
 
    def _set_revision_history(self, rev_history):
2512
 
        if 'evil' in debug.debug_flags:
2513
 
            mutter_callsite(3, "set_revision_history scales with history.")
2514
 
        check_not_reserved_id = _mod_revision.check_not_reserved_id
2515
 
        for rev_id in rev_history:
2516
 
            check_not_reserved_id(rev_id)
2517
 
        if Branch.hooks['post_change_branch_tip']:
2518
 
            # Don't calculate the last_revision_info() if there are no hooks
2519
 
            # that will use it.
2520
 
            old_revno, old_revid = self.last_revision_info()
2521
 
        if len(rev_history) == 0:
2522
 
            revid = _mod_revision.NULL_REVISION
2523
 
        else:
2524
 
            revid = rev_history[-1]
2525
 
        self._run_pre_change_branch_tip_hooks(len(rev_history), revid)
2526
 
        self._write_revision_history(rev_history)
2527
 
        self._clear_cached_state()
2528
 
        self._cache_revision_history(rev_history)
2529
 
        for hook in Branch.hooks['set_rh']:
2530
 
            hook(self, rev_history)
2531
 
        if Branch.hooks['post_change_branch_tip']:
2532
 
            self._run_post_change_branch_tip_hooks(old_revno, old_revid)
2533
 
 
2534
 
    def _synchronize_history(self, destination, revision_id):
2535
 
        """Synchronize last revision and revision history between branches.
2536
 
 
2537
 
        This version is most efficient when the destination is also a
2538
 
        BzrBranch5, but works for BzrBranch6 as long as the revision
2539
 
        history is the true lefthand parent history, and all of the revisions
2540
 
        are in the destination's repository.  If not, set_revision_history
2541
 
        will fail.
2542
 
 
2543
 
        :param destination: The branch to copy the history into
2544
 
        :param revision_id: The revision-id to truncate history at.  May
2545
 
          be None to copy complete history.
2546
 
        """
2547
 
        if not isinstance(destination._format, BzrBranchFormat5):
2548
 
            super(BzrBranch, self)._synchronize_history(
2549
 
                destination, revision_id)
2550
 
            return
2551
 
        if revision_id == _mod_revision.NULL_REVISION:
2552
 
            new_history = []
2553
 
        else:
2554
 
            new_history = self.revision_history()
2555
 
        if revision_id is not None and new_history != []:
2556
 
            try:
2557
 
                new_history = new_history[:new_history.index(revision_id) + 1]
2558
 
            except ValueError:
2559
 
                rev = self.repository.get_revision(revision_id)
2560
 
                new_history = rev.get_history(self.repository)[1:]
2561
 
        destination._set_revision_history(new_history)
2562
 
 
2563
2520
    @needs_write_lock
2564
2521
    def set_last_revision_info(self, revno, revision_id):
2565
2522
        """Set the last revision of this branch.
2572
2529
        configured to check constraints on history, in which case this may not
2573
2530
        be permitted.
2574
2531
        """
2575
 
        revision_id = _mod_revision.ensure_null(revision_id)
2576
 
        # this old format stores the full history, but this api doesn't
2577
 
        # provide it, so we must generate, and might as well check it's
2578
 
        # correct
2579
 
        history = self._lefthand_history(revision_id)
2580
 
        if len(history) != revno:
2581
 
            raise AssertionError('%d != %d' % (len(history), revno))
2582
 
        self._set_revision_history(history)
 
2532
        raise NotImplementedError(self.set_last_revision_info)
2583
2533
 
2584
2534
    @needs_write_lock
2585
2535
    def generate_revision_history(self, revision_id, last_rev=None,
2645
2595
            self._transport.put_bytes('parent', url + '\n',
2646
2596
                mode=self.bzrdir._get_file_mode())
2647
2597
 
2648
 
 
2649
 
class FullHistoryBzrBranch(BzrBranch):
2650
 
 
2651
 
    def _write_revision_history(self, history):
2652
 
        """Factored out of set_revision_history.
2653
 
 
2654
 
        This performs the actual writing to disk.
2655
 
        It is intended to be called by BzrBranch5.set_revision_history."""
2656
 
        self._transport.put_bytes(
2657
 
            'revision-history', '\n'.join(history),
2658
 
            mode=self.bzrdir._get_file_mode())
2659
 
 
2660
 
    def _gen_revision_history(self):
2661
 
        history = self._transport.get_bytes('revision-history').split('\n')
2662
 
        if history[-1:] == ['']:
2663
 
            # There shouldn't be a trailing newline, but just in case.
2664
 
            history.pop()
2665
 
        return history
2666
 
 
2667
 
 
2668
 
class BzrBranch5(FullHistoryBzrBranch):
2669
 
    """A format 5 branch. This supports new features over plain branches.
2670
 
 
2671
 
    It has support for a master_branch which is the data for bound branches.
2672
 
    """
 
2598
    @needs_write_lock
 
2599
    def unbind(self):
 
2600
        """If bound, unbind"""
 
2601
        return self.set_bound_location(None)
 
2602
 
 
2603
    @needs_write_lock
 
2604
    def bind(self, other):
 
2605
        """Bind this branch to the branch other.
 
2606
 
 
2607
        This does not push or pull data between the branches, though it does
 
2608
        check for divergence to raise an error when the branches are not
 
2609
        either the same, or one a prefix of the other. That behaviour may not
 
2610
        be useful, so that check may be removed in future.
 
2611
 
 
2612
        :param other: The branch to bind to
 
2613
        :type other: Branch
 
2614
        """
 
2615
        # TODO: jam 20051230 Consider checking if the target is bound
 
2616
        #       It is debatable whether you should be able to bind to
 
2617
        #       a branch which is itself bound.
 
2618
        #       Committing is obviously forbidden,
 
2619
        #       but binding itself may not be.
 
2620
        #       Since we *have* to check at commit time, we don't
 
2621
        #       *need* to check here
 
2622
 
 
2623
        # we want to raise diverged if:
 
2624
        # last_rev is not in the other_last_rev history, AND
 
2625
        # other_last_rev is not in our history, and do it without pulling
 
2626
        # history around
 
2627
        self.set_bound_location(other.base)
2673
2628
 
2674
2629
    def get_bound_location(self):
2675
2630
        try:
2717
2672
            return True
2718
2673
 
2719
2674
    @needs_write_lock
2720
 
    def bind(self, other):
2721
 
        """Bind this branch to the branch other.
2722
 
 
2723
 
        This does not push or pull data between the branches, though it does
2724
 
        check for divergence to raise an error when the branches are not
2725
 
        either the same, or one a prefix of the other. That behaviour may not
2726
 
        be useful, so that check may be removed in future.
2727
 
 
2728
 
        :param other: The branch to bind to
2729
 
        :type other: Branch
2730
 
        """
2731
 
        # TODO: jam 20051230 Consider checking if the target is bound
2732
 
        #       It is debatable whether you should be able to bind to
2733
 
        #       a branch which is itself bound.
2734
 
        #       Committing is obviously forbidden,
2735
 
        #       but binding itself may not be.
2736
 
        #       Since we *have* to check at commit time, we don't
2737
 
        #       *need* to check here
2738
 
 
2739
 
        # we want to raise diverged if:
2740
 
        # last_rev is not in the other_last_rev history, AND
2741
 
        # other_last_rev is not in our history, and do it without pulling
2742
 
        # history around
2743
 
        self.set_bound_location(other.base)
2744
 
 
2745
 
    @needs_write_lock
2746
 
    def unbind(self):
2747
 
        """If bound, unbind"""
2748
 
        return self.set_bound_location(None)
2749
 
 
2750
 
    @needs_write_lock
2751
2675
    def update(self, possible_transports=None):
2752
2676
        """Synchronise this branch with the master branch if any.
2753
2677
 
2764
2688
            return old_tip
2765
2689
        return None
2766
2690
 
2767
 
 
2768
 
class BzrBranch8(BzrBranch5):
 
2691
    def _read_last_revision_info(self):
 
2692
        revision_string = self._transport.get_bytes('last-revision')
 
2693
        revno, revision_id = revision_string.rstrip('\n').split(' ', 1)
 
2694
        revision_id = cache_utf8.get_cached_utf8(revision_id)
 
2695
        revno = int(revno)
 
2696
        return revno, revision_id
 
2697
 
 
2698
    def _write_last_revision_info(self, revno, revision_id):
 
2699
        """Simply write out the revision id, with no checks.
 
2700
 
 
2701
        Use set_last_revision_info to perform this safely.
 
2702
 
 
2703
        Does not update the revision_history cache.
 
2704
        """
 
2705
        revision_id = _mod_revision.ensure_null(revision_id)
 
2706
        out_string = '%d %s\n' % (revno, revision_id)
 
2707
        self._transport.put_bytes('last-revision', out_string,
 
2708
            mode=self.bzrdir._get_file_mode())
 
2709
 
 
2710
 
 
2711
class FullHistoryBzrBranch(BzrBranch):
 
2712
    """Bzr branch which contains the full revision history."""
 
2713
 
 
2714
    @needs_write_lock
 
2715
    def set_last_revision_info(self, revno, revision_id):
 
2716
        revision_id = _mod_revision.ensure_null(revision_id)
 
2717
        # this old format stores the full history, but this api doesn't
 
2718
        # provide it, so we must generate, and might as well check it's
 
2719
        # correct
 
2720
        history = self._lefthand_history(revision_id)
 
2721
        if len(history) != revno:
 
2722
            raise AssertionError('%d != %d' % (len(history), revno))
 
2723
        self._set_revision_history(history)
 
2724
 
 
2725
    def _read_last_revision_info(self):
 
2726
        rh = self.revision_history()
 
2727
        revno = len(rh)
 
2728
        if revno:
 
2729
            return (revno, rh[-1])
 
2730
        else:
 
2731
            return (0, _mod_revision.NULL_REVISION)
 
2732
 
 
2733
    @deprecated_method(deprecated_in((2, 4, 0)))
 
2734
    @needs_write_lock
 
2735
    def set_revision_history(self, rev_history):
 
2736
        """See Branch.set_revision_history."""
 
2737
        self._set_revision_history(rev_history)
 
2738
 
 
2739
    def _set_revision_history(self, rev_history):
 
2740
        if 'evil' in debug.debug_flags:
 
2741
            mutter_callsite(3, "set_revision_history scales with history.")
 
2742
        check_not_reserved_id = _mod_revision.check_not_reserved_id
 
2743
        for rev_id in rev_history:
 
2744
            check_not_reserved_id(rev_id)
 
2745
        if Branch.hooks['post_change_branch_tip']:
 
2746
            # Don't calculate the last_revision_info() if there are no hooks
 
2747
            # that will use it.
 
2748
            old_revno, old_revid = self.last_revision_info()
 
2749
        if len(rev_history) == 0:
 
2750
            revid = _mod_revision.NULL_REVISION
 
2751
        else:
 
2752
            revid = rev_history[-1]
 
2753
        self._run_pre_change_branch_tip_hooks(len(rev_history), revid)
 
2754
        self._write_revision_history(rev_history)
 
2755
        self._clear_cached_state()
 
2756
        self._cache_revision_history(rev_history)
 
2757
        for hook in Branch.hooks['set_rh']:
 
2758
            hook(self, rev_history)
 
2759
        if Branch.hooks['post_change_branch_tip']:
 
2760
            self._run_post_change_branch_tip_hooks(old_revno, old_revid)
 
2761
 
 
2762
    def _write_revision_history(self, history):
 
2763
        """Factored out of set_revision_history.
 
2764
 
 
2765
        This performs the actual writing to disk.
 
2766
        It is intended to be called by set_revision_history."""
 
2767
        self._transport.put_bytes(
 
2768
            'revision-history', '\n'.join(history),
 
2769
            mode=self.bzrdir._get_file_mode())
 
2770
 
 
2771
    def _gen_revision_history(self):
 
2772
        history = self._transport.get_bytes('revision-history').split('\n')
 
2773
        if history[-1:] == ['']:
 
2774
            # There shouldn't be a trailing newline, but just in case.
 
2775
            history.pop()
 
2776
        return history
 
2777
 
 
2778
    def _synchronize_history(self, destination, revision_id):
 
2779
        if not isinstance(destination._format, FullHistoryBzrBranch):
 
2780
            super(BzrBranch, self)._synchronize_history(
 
2781
                destination, revision_id)
 
2782
            return
 
2783
        if revision_id == _mod_revision.NULL_REVISION:
 
2784
            new_history = []
 
2785
        else:
 
2786
            new_history = self.revision_history()
 
2787
        if revision_id is not None and new_history != []:
 
2788
            try:
 
2789
                new_history = new_history[:new_history.index(revision_id) + 1]
 
2790
            except ValueError:
 
2791
                rev = self.repository.get_revision(revision_id)
 
2792
                new_history = rev.get_history(self.repository)[1:]
 
2793
        destination._set_revision_history(new_history)
 
2794
 
 
2795
 
 
2796
class BzrBranch5(FullHistoryBzrBranch):
 
2797
    """A format 5 branch. This supports new features over plain branches.
 
2798
 
 
2799
    It has support for a master_branch which is the data for bound branches.
 
2800
    """
 
2801
 
 
2802
 
 
2803
class BzrBranch8(BzrBranch):
2769
2804
    """A branch that stores tree-reference locations."""
2770
2805
 
2771
2806
    def _open_hook(self):
2797
2832
        self._last_revision_info_cache = None
2798
2833
        self._reference_info = None
2799
2834
 
2800
 
    def _last_revision_info(self):
2801
 
        revision_string = self._transport.get_bytes('last-revision')
2802
 
        revno, revision_id = revision_string.rstrip('\n').split(' ', 1)
2803
 
        revision_id = cache_utf8.get_cached_utf8(revision_id)
2804
 
        revno = int(revno)
2805
 
        return revno, revision_id
2806
 
 
2807
 
    def _write_last_revision_info(self, revno, revision_id):
2808
 
        """Simply write out the revision id, with no checks.
2809
 
 
2810
 
        Use set_last_revision_info to perform this safely.
2811
 
 
2812
 
        Does not update the revision_history cache.
2813
 
        Intended to be called by set_last_revision_info and
2814
 
        _write_revision_history.
2815
 
        """
2816
 
        revision_id = _mod_revision.ensure_null(revision_id)
2817
 
        out_string = '%d %s\n' % (revno, revision_id)
2818
 
        self._transport.put_bytes('last-revision', out_string,
2819
 
            mode=self.bzrdir._get_file_mode())
2820
 
 
2821
 
    @needs_write_lock
2822
 
    def set_last_revision_info(self, revno, revision_id):
2823
 
        revision_id = _mod_revision.ensure_null(revision_id)
2824
 
        old_revno, old_revid = self.last_revision_info()
2825
 
        if self._get_append_revisions_only():
2826
 
            self._check_history_violation(revision_id)
2827
 
        self._run_pre_change_branch_tip_hooks(revno, revision_id)
2828
 
        self._write_last_revision_info(revno, revision_id)
2829
 
        self._clear_cached_state()
2830
 
        self._last_revision_info_cache = revno, revision_id
2831
 
        self._run_post_change_branch_tip_hooks(old_revno, old_revid)
2832
 
 
2833
 
    def _synchronize_history(self, destination, revision_id):
2834
 
        """Synchronize last revision and revision history between branches.
2835
 
 
2836
 
        :see: Branch._synchronize_history
2837
 
        """
2838
 
        # XXX: The base Branch has a fast implementation of this method based
2839
 
        # on set_last_revision_info, but BzrBranch/BzrBranch5 have a slower one
2840
 
        # that uses set_revision_history.  This class inherits from BzrBranch5,
2841
 
        # but wants the fast implementation, so it calls
2842
 
        # Branch._synchronize_history directly.
2843
 
        Branch._synchronize_history(self, destination, revision_id)
2844
 
 
2845
2835
    def _check_history_violation(self, revision_id):
2846
2836
        last_revision = _mod_revision.ensure_null(self.last_revision())
2847
2837
        if _mod_revision.is_null(last_revision):