~amanica/bzr/320119-log_exclusive_lower_bound

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

  • Committer: John Arbash Meinel
  • Date: 2009-07-29 21:35:05 UTC
  • mfrom: (4511.1.65 +trunk)
  • mto: (4511.1.66 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4533.
  • Revision ID: john@arbash-meinel.com-20090729213505-tkqsvy1zfpocu75w
Merge bzr.dev 4576 in prep for NEWS

Show diffs side-by-side

added added

removed removed

Lines of Context:
91
91
        self._revision_history_cache = None
92
92
        self._revision_id_to_revno_cache = None
93
93
        self._partial_revision_id_to_revno_cache = {}
 
94
        self._partial_revision_history_cache = []
94
95
        self._last_revision_info_cache = None
95
96
        self._merge_sorted_revisions_cache = None
96
97
        self._open_hook()
104
105
    def _activate_fallback_location(self, url):
105
106
        """Activate the branch/repository from url as a fallback repository."""
106
107
        repo = self._get_fallback_repository(url)
 
108
        if repo.has_same_location(self.repository):
 
109
            raise errors.UnstackableLocationError(self.base, url)
107
110
        self.repository.add_fallback_repository(repo)
108
111
 
109
112
    def break_lock(self):
125
128
            raise errors.UnstackableRepositoryFormat(self.repository._format,
126
129
                self.repository.base)
127
130
 
 
131
    def _extend_partial_history(self, stop_index=None, stop_revision=None):
 
132
        """Extend the partial history to include a given index
 
133
 
 
134
        If a stop_index is supplied, stop when that index has been reached.
 
135
        If a stop_revision is supplied, stop when that revision is
 
136
        encountered.  Otherwise, stop when the beginning of history is
 
137
        reached.
 
138
 
 
139
        :param stop_index: The index which should be present.  When it is
 
140
            present, history extension will stop.
 
141
        :param stop_revision: The revision id which should be present.  When
 
142
            it is encountered, history extension will stop.
 
143
        """
 
144
        if len(self._partial_revision_history_cache) == 0:
 
145
            self._partial_revision_history_cache = [self.last_revision()]
 
146
        repository._iter_for_revno(
 
147
            self.repository, self._partial_revision_history_cache,
 
148
            stop_index=stop_index, stop_revision=stop_revision)
 
149
        if self._partial_revision_history_cache[-1] == _mod_revision.NULL_REVISION:
 
150
            self._partial_revision_history_cache.pop()
 
151
 
128
152
    @staticmethod
129
153
    def open(base, _unsupported=False, possible_transports=None):
130
154
        """Open the branch rooted at base.
498
522
        """
499
523
        raise errors.UpgradeRequired(self.base)
500
524
 
 
525
    def set_append_revisions_only(self, enabled):
 
526
        if not self._format.supports_set_append_revisions_only():
 
527
            raise errors.UpgradeRequired(self.base)
 
528
        if enabled:
 
529
            value = 'True'
 
530
        else:
 
531
            value = 'False'
 
532
        self.get_config().set_user_option('append_revisions_only', value,
 
533
            warn_masked=True)
 
534
 
501
535
    def set_reference_info(self, file_id, tree_path, branch_location):
502
536
        """Set the branch location to use for a tree reference."""
503
537
        raise errors.UnsupportedOperation(self.set_reference_info, self)
629
663
        """
630
664
        if not self._format.supports_stacking():
631
665
            raise errors.UnstackableBranchFormat(self._format, self.base)
 
666
        # XXX: Changing from one fallback repository to another does not check
 
667
        # that all the data you need is present in the new fallback.
 
668
        # Possibly it should.
632
669
        self._check_stackable_repo()
633
670
        if not url:
634
671
            try:
636
673
            except (errors.NotStacked, errors.UnstackableBranchFormat,
637
674
                errors.UnstackableRepositoryFormat):
638
675
                return
639
 
            url = ''
640
 
            # XXX: Lock correctness - should unlock our old repo if we were
641
 
            # locked.
642
 
            # repositories don't offer an interface to remove fallback
643
 
            # repositories today; take the conceptually simpler option and just
644
 
            # reopen it.
645
 
            self.repository = self.bzrdir.find_repository()
646
 
            self.repository.lock_write()
647
 
            # for every revision reference the branch has, ensure it is pulled
648
 
            # in.
649
 
            source_repository = self._get_fallback_repository(old_url)
650
 
            for revision_id in chain([self.last_revision()],
651
 
                self.tags.get_reverse_tag_dict()):
652
 
                self.repository.fetch(source_repository, revision_id,
653
 
                    find_ghosts=True)
 
676
            self._unstack()
654
677
        else:
655
678
            self._activate_fallback_location(url)
656
679
        # write this out after the repository is stacked to avoid setting a
657
680
        # stacked config that doesn't work.
658
681
        self._set_config_location('stacked_on_location', url)
659
682
 
 
683
    def _unstack(self):
 
684
        """Change a branch to be unstacked, copying data as needed.
 
685
        
 
686
        Don't call this directly, use set_stacked_on_url(None).
 
687
        """
 
688
        pb = ui.ui_factory.nested_progress_bar()
 
689
        try:
 
690
            pb.update("Unstacking")
 
691
            # The basic approach here is to fetch the tip of the branch,
 
692
            # including all available ghosts, from the existing stacked
 
693
            # repository into a new repository object without the fallbacks. 
 
694
            #
 
695
            # XXX: See <https://launchpad.net/bugs/397286> - this may not be
 
696
            # correct for CHKMap repostiories
 
697
            old_repository = self.repository
 
698
            if len(old_repository._fallback_repositories) != 1:
 
699
                raise AssertionError("can't cope with fallback repositories "
 
700
                    "of %r" % (self.repository,))
 
701
            # unlock it, including unlocking the fallback
 
702
            old_repository.unlock()
 
703
            old_repository.lock_read()
 
704
            try:
 
705
                # Repositories don't offer an interface to remove fallback
 
706
                # repositories today; take the conceptually simpler option and just
 
707
                # reopen it.  We reopen it starting from the URL so that we
 
708
                # get a separate connection for RemoteRepositories and can
 
709
                # stream from one of them to the other.  This does mean doing
 
710
                # separate SSH connection setup, but unstacking is not a
 
711
                # common operation so it's tolerable.
 
712
                new_bzrdir = bzrdir.BzrDir.open(self.bzrdir.root_transport.base)
 
713
                new_repository = new_bzrdir.find_repository()
 
714
                self.repository = new_repository
 
715
                if self.repository._fallback_repositories:
 
716
                    raise AssertionError("didn't expect %r to have "
 
717
                        "fallback_repositories"
 
718
                        % (self.repository,))
 
719
                # this is not paired with an unlock because it's just restoring
 
720
                # the previous state; the lock's released when set_stacked_on_url
 
721
                # returns
 
722
                self.repository.lock_write()
 
723
                # XXX: If you unstack a branch while it has a working tree
 
724
                # with a pending merge, the pending-merged revisions will no
 
725
                # longer be present.  You can (probably) revert and remerge.
 
726
                #
 
727
                # XXX: This only fetches up to the tip of the repository; it
 
728
                # doesn't bring across any tags.  That's fairly consistent
 
729
                # with how branch works, but perhaps not ideal.
 
730
                self.repository.fetch(old_repository,
 
731
                    revision_id=self.last_revision(),
 
732
                    find_ghosts=True)
 
733
            finally:
 
734
                old_repository.unlock()
 
735
        finally:
 
736
            pb.finished()
660
737
 
661
738
    def _set_tags_bytes(self, bytes):
662
739
        """Mirror method for _get_tags_bytes.
698
775
        self._revision_id_to_revno_cache = None
699
776
        self._last_revision_info_cache = None
700
777
        self._merge_sorted_revisions_cache = None
 
778
        self._partial_revision_history_cache = []
 
779
        self._partial_revision_id_to_revno_cache = {}
701
780
 
702
781
    def _gen_revision_history(self):
703
782
        """Return sequence of revision hashes on to this branch.
742
821
        """Older format branches cannot bind or unbind."""
743
822
        raise errors.UpgradeRequired(self.base)
744
823
 
745
 
    def set_append_revisions_only(self, enabled):
746
 
        """Older format branches are never restricted to append-only"""
747
 
        raise errors.UpgradeRequired(self.base)
748
 
 
749
824
    def last_revision(self):
750
825
        """Return last revision id, or NULL_REVISION."""
751
826
        return self.last_revision_info()[1]
831
906
        except ValueError:
832
907
            raise errors.NoSuchRevision(self, revision_id)
833
908
 
 
909
    @needs_read_lock
834
910
    def get_rev_id(self, revno, history=None):
835
911
        """Find the revision id of the specified revno."""
836
912
        if revno == 0:
837
913
            return _mod_revision.NULL_REVISION
838
 
        if history is None:
839
 
            history = self.revision_history()
840
 
        if revno <= 0 or revno > len(history):
 
914
        last_revno, last_revid = self.last_revision_info()
 
915
        if revno == last_revno:
 
916
            return last_revid
 
917
        if revno <= 0 or revno > last_revno:
841
918
            raise errors.NoSuchRevision(self, revno)
842
 
        return history[revno - 1]
 
919
        distance_from_last = last_revno - revno
 
920
        if len(self._partial_revision_history_cache) <= distance_from_last:
 
921
            self._extend_partial_history(distance_from_last)
 
922
        return self._partial_revision_history_cache[distance_from_last]
843
923
 
844
924
    @needs_write_lock
845
925
    def pull(self, source, overwrite=False, stop_revision=None,
1349
1429
    _formats = {}
1350
1430
    """The known formats."""
1351
1431
 
 
1432
    can_set_append_revisions_only = True
 
1433
 
1352
1434
    def __eq__(self, other):
1353
1435
        return self.__class__ is other.__class__
1354
1436
 
1507
1589
    def set_default_format(klass, format):
1508
1590
        klass._default_format = format
1509
1591
 
 
1592
    def supports_set_append_revisions_only(self):
 
1593
        """True if this format supports set_append_revisions_only."""
 
1594
        return False
 
1595
 
1510
1596
    def supports_stacking(self):
1511
1597
        """True if this format records a stacked-on branch."""
1512
1598
        return False
1794
1880
        """See bzrlib.branch.BranchFormat.make_tags()."""
1795
1881
        return BasicTags(branch)
1796
1882
 
 
1883
    def supports_set_append_revisions_only(self):
 
1884
        return True
1797
1885
 
1798
1886
 
1799
1887
class BzrBranchFormat8(BranchFormatMetadir):
1828
1916
        """See bzrlib.branch.BranchFormat.make_tags()."""
1829
1917
        return BasicTags(branch)
1830
1918
 
 
1919
    def supports_set_append_revisions_only(self):
 
1920
        return True
 
1921
 
1831
1922
    def supports_stacking(self):
1832
1923
        return True
1833
1924
 
1862
1953
        """See BranchFormat.get_format_description()."""
1863
1954
        return "Branch format 7"
1864
1955
 
 
1956
    def supports_set_append_revisions_only(self):
 
1957
        return True
 
1958
 
1865
1959
    supports_reference_locations = False
1866
1960
 
1867
1961
 
2376
2470
        self._ignore_fallbacks = kwargs.get('ignore_fallbacks', False)
2377
2471
        super(BzrBranch8, self).__init__(*args, **kwargs)
2378
2472
        self._last_revision_info_cache = None
2379
 
        self._partial_revision_history_cache = []
2380
2473
        self._reference_info = None
2381
2474
 
2382
2475
    def _clear_cached_state(self):
2383
2476
        super(BzrBranch8, self)._clear_cached_state()
2384
2477
        self._last_revision_info_cache = None
2385
 
        self._partial_revision_history_cache = []
2386
2478
        self._reference_info = None
2387
2479
 
2388
2480
    def _last_revision_info(self):
2444
2536
        self._extend_partial_history(stop_index=last_revno-1)
2445
2537
        return list(reversed(self._partial_revision_history_cache))
2446
2538
 
2447
 
    def _extend_partial_history(self, stop_index=None, stop_revision=None):
2448
 
        """Extend the partial history to include a given index
2449
 
 
2450
 
        If a stop_index is supplied, stop when that index has been reached.
2451
 
        If a stop_revision is supplied, stop when that revision is
2452
 
        encountered.  Otherwise, stop when the beginning of history is
2453
 
        reached.
2454
 
 
2455
 
        :param stop_index: The index which should be present.  When it is
2456
 
            present, history extension will stop.
2457
 
        :param revision_id: The revision id which should be present.  When
2458
 
            it is encountered, history extension will stop.
2459
 
        """
2460
 
        repo = self.repository
2461
 
        if len(self._partial_revision_history_cache) == 0:
2462
 
            iterator = repo.iter_reverse_revision_history(self.last_revision())
2463
 
        else:
2464
 
            start_revision = self._partial_revision_history_cache[-1]
2465
 
            iterator = repo.iter_reverse_revision_history(start_revision)
2466
 
            #skip the last revision in the list
2467
 
            next_revision = iterator.next()
2468
 
        for revision_id in iterator:
2469
 
            self._partial_revision_history_cache.append(revision_id)
2470
 
            if (stop_index is not None and
2471
 
                len(self._partial_revision_history_cache) > stop_index):
2472
 
                break
2473
 
            if revision_id == stop_revision:
2474
 
                break
2475
 
 
2476
2539
    def _write_revision_history(self, history):
2477
2540
        """Factored out of set_revision_history.
2478
2541
 
2621
2684
            raise errors.NotStacked(self)
2622
2685
        return stacked_url
2623
2686
 
2624
 
    def set_append_revisions_only(self, enabled):
2625
 
        if enabled:
2626
 
            value = 'True'
2627
 
        else:
2628
 
            value = 'False'
2629
 
        self.get_config().set_user_option('append_revisions_only', value,
2630
 
            warn_masked=True)
2631
 
 
2632
2687
    def _get_append_revisions_only(self):
2633
2688
        value = self.get_config().get_user_option('append_revisions_only')
2634
2689
        return value == 'True'
2897
2952
    @staticmethod
2898
2953
    def _get_branch_formats_to_test():
2899
2954
        """Return a tuple with the Branch formats to use when testing."""
2900
 
        raise NotImplementedError(self._get_branch_formats_to_test)
 
2955
        raise NotImplementedError(InterBranch._get_branch_formats_to_test)
2901
2956
 
2902
2957
    def pull(self, overwrite=False, stop_revision=None,
2903
2958
             possible_transports=None, local=False):
3058
3113
                _override_hook_source_branch=_override_hook_source_branch)
3059
3114
        finally:
3060
3115
            self.source.unlock()
3061
 
        return result
3062
3116
 
3063
3117
    def _push_with_bound_branches(self, overwrite, stop_revision,
3064
3118
            _override_hook_source_branch=None):