~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

  • Committer: John Arbash Meinel
  • Date: 2009-07-08 14:37:25 UTC
  • mfrom: (4516 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4517.
  • Revision ID: john@arbash-meinel.com-20090708143725-sc9sjy3mz4cxwxzz
Merge bzr.dev 4516

Show diffs side-by-side

added added

removed removed

Lines of Context:
35
35
        symbol_versioning,
36
36
        transport,
37
37
        tsort,
38
 
        ui,
39
38
        urlutils,
40
39
        )
41
40
from bzrlib.config import BranchConfig, TransportConfig
91
90
        self._revision_history_cache = None
92
91
        self._revision_id_to_revno_cache = None
93
92
        self._partial_revision_id_to_revno_cache = {}
 
93
        self._partial_revision_history_cache = []
94
94
        self._last_revision_info_cache = None
95
95
        self._merge_sorted_revisions_cache = None
96
96
        self._open_hook()
101
101
    def _open_hook(self):
102
102
        """Called by init to allow simpler extension of the base class."""
103
103
 
104
 
    def _activate_fallback_location(self, url, lock_style):
 
104
    def _activate_fallback_location(self, url):
105
105
        """Activate the branch/repository from url as a fallback repository."""
106
106
        repo = self._get_fallback_repository(url)
107
 
        if lock_style == 'write':
108
 
            repo.lock_write()
109
 
        elif lock_style == 'read':
110
 
            repo.lock_read()
 
107
        if repo.has_same_location(self.repository):
 
108
            raise errors.UnstackableLocationError(self.base, url)
111
109
        self.repository.add_fallback_repository(repo)
112
110
 
113
111
    def break_lock(self):
129
127
            raise errors.UnstackableRepositoryFormat(self.repository._format,
130
128
                self.repository.base)
131
129
 
 
130
    def _extend_partial_history(self, stop_index=None, stop_revision=None):
 
131
        """Extend the partial history to include a given index
 
132
 
 
133
        If a stop_index is supplied, stop when that index has been reached.
 
134
        If a stop_revision is supplied, stop when that revision is
 
135
        encountered.  Otherwise, stop when the beginning of history is
 
136
        reached.
 
137
 
 
138
        :param stop_index: The index which should be present.  When it is
 
139
            present, history extension will stop.
 
140
        :param stop_revision: The revision id which should be present.  When
 
141
            it is encountered, history extension will stop.
 
142
        """
 
143
        if len(self._partial_revision_history_cache) == 0:
 
144
            self._partial_revision_history_cache = [self.last_revision()]
 
145
        repository._iter_for_revno(
 
146
            self.repository, self._partial_revision_history_cache,
 
147
            stop_index=stop_index, stop_revision=stop_revision)
 
148
        if self._partial_revision_history_cache[-1] == _mod_revision.NULL_REVISION:
 
149
            self._partial_revision_history_cache.pop()
 
150
 
132
151
    @staticmethod
133
152
    def open(base, _unsupported=False, possible_transports=None):
134
153
        """Open the branch rooted at base.
502
521
        """
503
522
        raise errors.UpgradeRequired(self.base)
504
523
 
 
524
    def set_append_revisions_only(self, enabled):
 
525
        if not self._format.supports_set_append_revisions_only():
 
526
            raise errors.UpgradeRequired(self.base)
 
527
        if enabled:
 
528
            value = 'True'
 
529
        else:
 
530
            value = 'False'
 
531
        self.get_config().set_user_option('append_revisions_only', value,
 
532
            warn_masked=True)
 
533
 
505
534
    def set_reference_info(self, file_id, tree_path, branch_location):
506
535
        """Set the branch location to use for a tree reference."""
507
536
        raise errors.UnsupportedOperation(self.set_reference_info, self)
656
685
                self.repository.fetch(source_repository, revision_id,
657
686
                    find_ghosts=True)
658
687
        else:
659
 
            self._activate_fallback_location(url, 'write')
 
688
            self._activate_fallback_location(url)
660
689
        # write this out after the repository is stacked to avoid setting a
661
690
        # stacked config that doesn't work.
662
691
        self._set_config_location('stacked_on_location', url)
702
731
        self._revision_id_to_revno_cache = None
703
732
        self._last_revision_info_cache = None
704
733
        self._merge_sorted_revisions_cache = None
 
734
        self._partial_revision_history_cache = []
 
735
        self._partial_revision_id_to_revno_cache = {}
705
736
 
706
737
    def _gen_revision_history(self):
707
738
        """Return sequence of revision hashes on to this branch.
746
777
        """Older format branches cannot bind or unbind."""
747
778
        raise errors.UpgradeRequired(self.base)
748
779
 
749
 
    def set_append_revisions_only(self, enabled):
750
 
        """Older format branches are never restricted to append-only"""
751
 
        raise errors.UpgradeRequired(self.base)
752
 
 
753
780
    def last_revision(self):
754
781
        """Return last revision id, or NULL_REVISION."""
755
782
        return self.last_revision_info()[1]
835
862
        except ValueError:
836
863
            raise errors.NoSuchRevision(self, revision_id)
837
864
 
 
865
    @needs_read_lock
838
866
    def get_rev_id(self, revno, history=None):
839
867
        """Find the revision id of the specified revno."""
840
868
        if revno == 0:
841
869
            return _mod_revision.NULL_REVISION
842
 
        if history is None:
843
 
            history = self.revision_history()
844
 
        if revno <= 0 or revno > len(history):
 
870
        last_revno, last_revid = self.last_revision_info()
 
871
        if revno == last_revno:
 
872
            return last_revid
 
873
        if revno <= 0 or revno > last_revno:
845
874
            raise errors.NoSuchRevision(self, revno)
846
 
        return history[revno - 1]
 
875
        distance_from_last = last_revno - revno
 
876
        if len(self._partial_revision_history_cache) <= distance_from_last:
 
877
            self._extend_partial_history(distance_from_last)
 
878
        return self._partial_revision_history_cache[distance_from_last]
847
879
 
848
880
    @needs_write_lock
849
881
    def pull(self, source, overwrite=False, stop_revision=None,
932
964
            location = None
933
965
        return location
934
966
 
 
967
    def get_child_submit_format(self):
 
968
        """Return the preferred format of submissions to this branch."""
 
969
        return self.get_config().get_user_option("child_submit_format")
 
970
 
935
971
    def get_submit_branch(self):
936
972
        """Return the submit location of the branch.
937
973
 
1085
1121
        source_revno, source_revision_id = self.last_revision_info()
1086
1122
        if revision_id is None:
1087
1123
            revno, revision_id = source_revno, source_revision_id
1088
 
        elif source_revision_id == revision_id:
1089
 
            # we know the revno without needing to walk all of history
1090
 
            revno = source_revno
1091
1124
        else:
1092
 
            # To figure out the revno for a random revision, we need to build
1093
 
            # the revision history, and count its length.
1094
 
            # We don't care about the order, just how long it is.
1095
 
            # Alternatively, we could start at the current location, and count
1096
 
            # backwards. But there is no guarantee that we will find it since
1097
 
            # it may be a merged revision.
1098
 
            revno = len(list(self.repository.iter_reverse_revision_history(
1099
 
                                                                revision_id)))
 
1125
            graph = self.repository.get_graph()
 
1126
            try:
 
1127
                revno = graph.find_distance_to_null(revision_id, 
 
1128
                    [(source_revision_id, source_revno)])
 
1129
            except errors.GhostRevisionsHaveNoRevno:
 
1130
                # Default to 1, if we can't find anything else
 
1131
                revno = 1
1100
1132
        destination.set_last_revision_info(revno, revision_id)
1101
1133
 
1102
1134
    @needs_read_lock
1147
1179
 
1148
1180
        :return: A BranchCheckResult.
1149
1181
        """
 
1182
        ret = BranchCheckResult(self)
1150
1183
        mainline_parent_id = None
1151
1184
        last_revno, last_revision_id = self.last_revision_info()
1152
 
        real_rev_history = list(self.repository.iter_reverse_revision_history(
1153
 
                                last_revision_id))
 
1185
        real_rev_history = []
 
1186
        try:
 
1187
            for revid in self.repository.iter_reverse_revision_history(
 
1188
                last_revision_id):
 
1189
                real_rev_history.append(revid)
 
1190
        except errors.RevisionNotPresent:
 
1191
            ret.ghosts_in_mainline = True
 
1192
        else:
 
1193
            ret.ghosts_in_mainline = False
1154
1194
        real_rev_history.reverse()
1155
1195
        if len(real_rev_history) != last_revno:
1156
1196
            raise errors.BzrCheckError('revno does not match len(mainline)'
1172
1212
                                        "parents of {%s}"
1173
1213
                                        % (mainline_parent_id, revision_id))
1174
1214
            mainline_parent_id = revision_id
1175
 
        return BranchCheckResult(self)
 
1215
        return ret
1176
1216
 
1177
1217
    def _get_checkout_format(self):
1178
1218
        """Return the most suitable metadir for a checkout of this branch.
1345
1385
    _formats = {}
1346
1386
    """The known formats."""
1347
1387
 
 
1388
    can_set_append_revisions_only = True
 
1389
 
1348
1390
    def __eq__(self, other):
1349
1391
        return self.__class__ is other.__class__
1350
1392
 
1503
1545
    def set_default_format(klass, format):
1504
1546
        klass._default_format = format
1505
1547
 
 
1548
    def supports_set_append_revisions_only(self):
 
1549
        """True if this format supports set_append_revisions_only."""
 
1550
        return False
 
1551
 
1506
1552
    def supports_stacking(self):
1507
1553
        """True if this format records a stacked-on branch."""
1508
1554
        return False
1790
1836
        """See bzrlib.branch.BranchFormat.make_tags()."""
1791
1837
        return BasicTags(branch)
1792
1838
 
 
1839
    def supports_set_append_revisions_only(self):
 
1840
        return True
1793
1841
 
1794
1842
 
1795
1843
class BzrBranchFormat8(BranchFormatMetadir):
1824
1872
        """See bzrlib.branch.BranchFormat.make_tags()."""
1825
1873
        return BasicTags(branch)
1826
1874
 
 
1875
    def supports_set_append_revisions_only(self):
 
1876
        return True
 
1877
 
1827
1878
    def supports_stacking(self):
1828
1879
        return True
1829
1880
 
1858
1909
        """See BranchFormat.get_format_description()."""
1859
1910
        return "Branch format 7"
1860
1911
 
 
1912
    def supports_set_append_revisions_only(self):
 
1913
        return True
 
1914
 
1861
1915
    supports_reference_locations = False
1862
1916
 
1863
1917
 
2366
2420
                    raise AssertionError(
2367
2421
                        "'transform_fallback_location' hook %s returned "
2368
2422
                        "None, not a URL." % hook_name)
2369
 
            self._activate_fallback_location(url, None)
 
2423
            self._activate_fallback_location(url)
2370
2424
 
2371
2425
    def __init__(self, *args, **kwargs):
2372
2426
        self._ignore_fallbacks = kwargs.get('ignore_fallbacks', False)
2373
2427
        super(BzrBranch8, self).__init__(*args, **kwargs)
2374
2428
        self._last_revision_info_cache = None
2375
 
        self._partial_revision_history_cache = []
2376
2429
        self._reference_info = None
2377
2430
 
2378
2431
    def _clear_cached_state(self):
2379
2432
        super(BzrBranch8, self)._clear_cached_state()
2380
2433
        self._last_revision_info_cache = None
2381
 
        self._partial_revision_history_cache = []
2382
2434
        self._reference_info = None
2383
2435
 
2384
2436
    def _last_revision_info(self):
2440
2492
        self._extend_partial_history(stop_index=last_revno-1)
2441
2493
        return list(reversed(self._partial_revision_history_cache))
2442
2494
 
2443
 
    def _extend_partial_history(self, stop_index=None, stop_revision=None):
2444
 
        """Extend the partial history to include a given index
2445
 
 
2446
 
        If a stop_index is supplied, stop when that index has been reached.
2447
 
        If a stop_revision is supplied, stop when that revision is
2448
 
        encountered.  Otherwise, stop when the beginning of history is
2449
 
        reached.
2450
 
 
2451
 
        :param stop_index: The index which should be present.  When it is
2452
 
            present, history extension will stop.
2453
 
        :param revision_id: The revision id which should be present.  When
2454
 
            it is encountered, history extension will stop.
2455
 
        """
2456
 
        repo = self.repository
2457
 
        if len(self._partial_revision_history_cache) == 0:
2458
 
            iterator = repo.iter_reverse_revision_history(self.last_revision())
2459
 
        else:
2460
 
            start_revision = self._partial_revision_history_cache[-1]
2461
 
            iterator = repo.iter_reverse_revision_history(start_revision)
2462
 
            #skip the last revision in the list
2463
 
            next_revision = iterator.next()
2464
 
        for revision_id in iterator:
2465
 
            self._partial_revision_history_cache.append(revision_id)
2466
 
            if (stop_index is not None and
2467
 
                len(self._partial_revision_history_cache) > stop_index):
2468
 
                break
2469
 
            if revision_id == stop_revision:
2470
 
                break
2471
 
 
2472
2495
    def _write_revision_history(self, history):
2473
2496
        """Factored out of set_revision_history.
2474
2497
 
2617
2640
            raise errors.NotStacked(self)
2618
2641
        return stacked_url
2619
2642
 
2620
 
    def set_append_revisions_only(self, enabled):
2621
 
        if enabled:
2622
 
            value = 'True'
2623
 
        else:
2624
 
            value = 'False'
2625
 
        self.get_config().set_user_option('append_revisions_only', value,
2626
 
            warn_masked=True)
2627
 
 
2628
2643
    def _get_append_revisions_only(self):
2629
2644
        value = self.get_config().get_user_option('append_revisions_only')
2630
2645
        return value == 'True'
2780
2795
 
2781
2796
    def __init__(self, branch):
2782
2797
        self.branch = branch
 
2798
        self.ghosts_in_mainline = False
2783
2799
 
2784
2800
    def report_results(self, verbose):
2785
2801
        """Report the check results via trace.note.
2790
2806
        note('checked branch %s format %s',
2791
2807
             self.branch.base,
2792
2808
             self.branch._format)
 
2809
        if self.ghosts_in_mainline:
 
2810
            note('branch contains ghosts in mainline')
2793
2811
 
2794
2812
 
2795
2813
class Converter5to6(object):
2890
2908
    @staticmethod
2891
2909
    def _get_branch_formats_to_test():
2892
2910
        """Return a tuple with the Branch formats to use when testing."""
2893
 
        raise NotImplementedError(self._get_branch_formats_to_test)
 
2911
        raise NotImplementedError(InterBranch._get_branch_formats_to_test)
2894
2912
 
2895
2913
    def pull(self, overwrite=False, stop_revision=None,
2896
2914
             possible_transports=None, local=False):
3051
3069
                _override_hook_source_branch=_override_hook_source_branch)
3052
3070
        finally:
3053
3071
            self.source.unlock()
3054
 
        return result
3055
3072
 
3056
3073
    def _push_with_bound_branches(self, overwrite, stop_revision,
3057
3074
            _override_hook_source_branch=None):