~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

  • Committer: John Ferlito
  • Date: 2009-05-25 10:59:42 UTC
  • mto: (4665.4.1 ppa-doc)
  • mto: This revision was merged to the branch mainline in revision 4693.
  • Revision ID: johnf@inodes.org-20090525105942-5xkcbe37m1u5lp5z
Update packaging scripts to make deployment a bit easier
Update documentation for deploying to PPA

Show diffs side-by-side

added added

removed removed

Lines of Context:
46
46
    )
47
47
""")
48
48
 
49
 
from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises
 
49
from bzrlib.decorators import needs_read_lock, needs_write_lock
50
50
from bzrlib.hooks import HookPoint, Hooks
51
51
from bzrlib.inter import InterObject
52
 
from bzrlib.lock import _RelockDebugMixin
53
52
from bzrlib import registry
54
53
from bzrlib.symbol_versioning import (
55
54
    deprecated_in,
92
91
        self._revision_history_cache = None
93
92
        self._revision_id_to_revno_cache = None
94
93
        self._partial_revision_id_to_revno_cache = {}
95
 
        self._partial_revision_history_cache = []
96
94
        self._last_revision_info_cache = None
97
95
        self._merge_sorted_revisions_cache = None
98
96
        self._open_hook()
103
101
    def _open_hook(self):
104
102
        """Called by init to allow simpler extension of the base class."""
105
103
 
106
 
    def _activate_fallback_location(self, url):
 
104
    def _activate_fallback_location(self, url, lock_style):
107
105
        """Activate the branch/repository from url as a fallback repository."""
108
106
        repo = self._get_fallback_repository(url)
109
 
        if repo.has_same_location(self.repository):
110
 
            raise errors.UnstackableLocationError(self.base, url)
 
107
        if lock_style == 'write':
 
108
            repo.lock_write()
 
109
        elif lock_style == 'read':
 
110
            repo.lock_read()
111
111
        self.repository.add_fallback_repository(repo)
112
112
 
113
113
    def break_lock(self):
129
129
            raise errors.UnstackableRepositoryFormat(self.repository._format,
130
130
                self.repository.base)
131
131
 
132
 
    def _extend_partial_history(self, stop_index=None, stop_revision=None):
133
 
        """Extend the partial history to include a given index
134
 
 
135
 
        If a stop_index is supplied, stop when that index has been reached.
136
 
        If a stop_revision is supplied, stop when that revision is
137
 
        encountered.  Otherwise, stop when the beginning of history is
138
 
        reached.
139
 
 
140
 
        :param stop_index: The index which should be present.  When it is
141
 
            present, history extension will stop.
142
 
        :param stop_revision: The revision id which should be present.  When
143
 
            it is encountered, history extension will stop.
144
 
        """
145
 
        if len(self._partial_revision_history_cache) == 0:
146
 
            self._partial_revision_history_cache = [self.last_revision()]
147
 
        repository._iter_for_revno(
148
 
            self.repository, self._partial_revision_history_cache,
149
 
            stop_index=stop_index, stop_revision=stop_revision)
150
 
        if self._partial_revision_history_cache[-1] == _mod_revision.NULL_REVISION:
151
 
            self._partial_revision_history_cache.pop()
152
 
 
153
 
    def _get_check_refs(self):
154
 
        """Get the references needed for check().
155
 
 
156
 
        See bzrlib.check.
157
 
        """
158
 
        revid = self.last_revision()
159
 
        return [('revision-existence', revid), ('lefthand-distance', revid)]
160
 
 
161
132
    @staticmethod
162
133
    def open(base, _unsupported=False, possible_transports=None):
163
134
        """Open the branch rooted at base.
447
418
        # start_revision_id.
448
419
        if self._merge_sorted_revisions_cache is None:
449
420
            last_revision = self.last_revision()
450
 
            last_key = (last_revision,)
451
 
            known_graph = self.repository.revisions.get_known_graph_ancestry(
452
 
                [last_key])
453
 
            self._merge_sorted_revisions_cache = known_graph.merge_sort(
454
 
                last_key)
 
421
            graph = self.repository.get_graph()
 
422
            parent_map = dict(((key, value) for key, value in
 
423
                     graph.iter_ancestry([last_revision]) if value is not None))
 
424
            revision_graph = repository._strip_NULL_ghosts(parent_map)
 
425
            revs = tsort.merge_sort(revision_graph, last_revision, None,
 
426
                generate_revno=True)
 
427
            # Drop the sequence # before caching
 
428
            self._merge_sorted_revisions_cache = [r[1:] for r in revs]
 
429
 
455
430
        filtered = self._filter_merge_sorted_revisions(
456
431
            self._merge_sorted_revisions_cache, start_revision_id,
457
432
            stop_revision_id, stop_rule)
467
442
        """Iterate over an inclusive range of sorted revisions."""
468
443
        rev_iter = iter(merge_sorted_revisions)
469
444
        if start_revision_id is not None:
470
 
            for node in rev_iter:
471
 
                rev_id = node.key[-1]
 
445
            for rev_id, depth, revno, end_of_merge in rev_iter:
472
446
                if rev_id != start_revision_id:
473
447
                    continue
474
448
                else:
475
449
                    # The decision to include the start or not
476
450
                    # depends on the stop_rule if a stop is provided
477
 
                    # so pop this node back into the iterator
478
 
                    rev_iter = chain(iter([node]), rev_iter)
 
451
                    rev_iter = chain(
 
452
                        iter([(rev_id, depth, revno, end_of_merge)]),
 
453
                        rev_iter)
479
454
                    break
480
455
        if stop_revision_id is None:
481
 
            # Yield everything
482
 
            for node in rev_iter:
483
 
                rev_id = node.key[-1]
484
 
                yield (rev_id, node.merge_depth, node.revno,
485
 
                       node.end_of_merge)
 
456
            for rev_id, depth, revno, end_of_merge in rev_iter:
 
457
                yield rev_id, depth, revno, end_of_merge
486
458
        elif stop_rule == 'exclude':
487
 
            for node in rev_iter:
488
 
                rev_id = node.key[-1]
 
459
            for rev_id, depth, revno, end_of_merge in rev_iter:
489
460
                if rev_id == stop_revision_id:
490
461
                    return
491
 
                yield (rev_id, node.merge_depth, node.revno,
492
 
                       node.end_of_merge)
 
462
                yield rev_id, depth, revno, end_of_merge
493
463
        elif stop_rule == 'include':
494
 
            for node in rev_iter:
495
 
                rev_id = node.key[-1]
496
 
                yield (rev_id, node.merge_depth, node.revno,
497
 
                       node.end_of_merge)
 
464
            for rev_id, depth, revno, end_of_merge in rev_iter:
 
465
                yield rev_id, depth, revno, end_of_merge
498
466
                if rev_id == stop_revision_id:
499
467
                    return
500
468
        elif stop_rule == 'with-merges':
503
471
                left_parent = stop_rev.parent_ids[0]
504
472
            else:
505
473
                left_parent = _mod_revision.NULL_REVISION
506
 
            # left_parent is the actual revision we want to stop logging at,
507
 
            # since we want to show the merged revisions after the stop_rev too
508
 
            reached_stop_revision_id = False
509
 
            revision_id_whitelist = []
510
 
            for node in rev_iter:
511
 
                rev_id = node.key[-1]
 
474
            for rev_id, depth, revno, end_of_merge in rev_iter:
512
475
                if rev_id == left_parent:
513
 
                    # reached the left parent after the stop_revision
514
476
                    return
515
 
                if (not reached_stop_revision_id or
516
 
                        rev_id in revision_id_whitelist):
517
 
                    yield (rev_id, node.merge_depth, node.revno,
518
 
                       node.end_of_merge)
519
 
                    if reached_stop_revision_id or rev_id == stop_revision_id:
520
 
                        # only do the merged revs of rev_id from now on
521
 
                        rev = self.repository.get_revision(rev_id)
522
 
                        if rev.parent_ids:
523
 
                            reached_stop_revision_id = True
524
 
                            revision_id_whitelist.extend(rev.parent_ids)
 
477
                yield rev_id, depth, revno, end_of_merge
525
478
        else:
526
479
            raise ValueError('invalid stop_rule %r' % stop_rule)
527
480
 
549
502
        """
550
503
        raise errors.UpgradeRequired(self.base)
551
504
 
552
 
    def set_append_revisions_only(self, enabled):
553
 
        if not self._format.supports_set_append_revisions_only():
554
 
            raise errors.UpgradeRequired(self.base)
555
 
        if enabled:
556
 
            value = 'True'
557
 
        else:
558
 
            value = 'False'
559
 
        self.get_config().set_user_option('append_revisions_only', value,
560
 
            warn_masked=True)
561
 
 
562
505
    def set_reference_info(self, file_id, tree_path, branch_location):
563
506
        """Set the branch location to use for a tree reference."""
564
507
        raise errors.UnsupportedOperation(self.set_reference_info, self)
690
633
        """
691
634
        if not self._format.supports_stacking():
692
635
            raise errors.UnstackableBranchFormat(self._format, self.base)
693
 
        # XXX: Changing from one fallback repository to another does not check
694
 
        # that all the data you need is present in the new fallback.
695
 
        # Possibly it should.
696
636
        self._check_stackable_repo()
697
637
        if not url:
698
638
            try:
700
640
            except (errors.NotStacked, errors.UnstackableBranchFormat,
701
641
                errors.UnstackableRepositoryFormat):
702
642
                return
703
 
            self._unstack()
 
643
            url = ''
 
644
            # XXX: Lock correctness - should unlock our old repo if we were
 
645
            # locked.
 
646
            # repositories don't offer an interface to remove fallback
 
647
            # repositories today; take the conceptually simpler option and just
 
648
            # reopen it.
 
649
            self.repository = self.bzrdir.find_repository()
 
650
            self.repository.lock_write()
 
651
            # for every revision reference the branch has, ensure it is pulled
 
652
            # in.
 
653
            source_repository = self._get_fallback_repository(old_url)
 
654
            for revision_id in chain([self.last_revision()],
 
655
                self.tags.get_reverse_tag_dict()):
 
656
                self.repository.fetch(source_repository, revision_id,
 
657
                    find_ghosts=True)
704
658
        else:
705
 
            self._activate_fallback_location(url)
 
659
            self._activate_fallback_location(url, 'write')
706
660
        # write this out after the repository is stacked to avoid setting a
707
661
        # stacked config that doesn't work.
708
662
        self._set_config_location('stacked_on_location', url)
709
663
 
710
 
    def _unstack(self):
711
 
        """Change a branch to be unstacked, copying data as needed.
712
 
        
713
 
        Don't call this directly, use set_stacked_on_url(None).
714
 
        """
715
 
        pb = ui.ui_factory.nested_progress_bar()
716
 
        try:
717
 
            pb.update("Unstacking")
718
 
            # The basic approach here is to fetch the tip of the branch,
719
 
            # including all available ghosts, from the existing stacked
720
 
            # repository into a new repository object without the fallbacks. 
721
 
            #
722
 
            # XXX: See <https://launchpad.net/bugs/397286> - this may not be
723
 
            # correct for CHKMap repostiories
724
 
            old_repository = self.repository
725
 
            if len(old_repository._fallback_repositories) != 1:
726
 
                raise AssertionError("can't cope with fallback repositories "
727
 
                    "of %r" % (self.repository,))
728
 
            # unlock it, including unlocking the fallback
729
 
            old_repository.unlock()
730
 
            old_repository.lock_read()
731
 
            try:
732
 
                # Repositories don't offer an interface to remove fallback
733
 
                # repositories today; take the conceptually simpler option and just
734
 
                # reopen it.  We reopen it starting from the URL so that we
735
 
                # get a separate connection for RemoteRepositories and can
736
 
                # stream from one of them to the other.  This does mean doing
737
 
                # separate SSH connection setup, but unstacking is not a
738
 
                # common operation so it's tolerable.
739
 
                new_bzrdir = bzrdir.BzrDir.open(self.bzrdir.root_transport.base)
740
 
                new_repository = new_bzrdir.find_repository()
741
 
                self.repository = new_repository
742
 
                if self.repository._fallback_repositories:
743
 
                    raise AssertionError("didn't expect %r to have "
744
 
                        "fallback_repositories"
745
 
                        % (self.repository,))
746
 
                # this is not paired with an unlock because it's just restoring
747
 
                # the previous state; the lock's released when set_stacked_on_url
748
 
                # returns
749
 
                self.repository.lock_write()
750
 
                # XXX: If you unstack a branch while it has a working tree
751
 
                # with a pending merge, the pending-merged revisions will no
752
 
                # longer be present.  You can (probably) revert and remerge.
753
 
                #
754
 
                # XXX: This only fetches up to the tip of the repository; it
755
 
                # doesn't bring across any tags.  That's fairly consistent
756
 
                # with how branch works, but perhaps not ideal.
757
 
                self.repository.fetch(old_repository,
758
 
                    revision_id=self.last_revision(),
759
 
                    find_ghosts=True)
760
 
            finally:
761
 
                old_repository.unlock()
762
 
        finally:
763
 
            pb.finished()
764
664
 
765
665
    def _set_tags_bytes(self, bytes):
766
666
        """Mirror method for _get_tags_bytes.
802
702
        self._revision_id_to_revno_cache = None
803
703
        self._last_revision_info_cache = None
804
704
        self._merge_sorted_revisions_cache = None
805
 
        self._partial_revision_history_cache = []
806
 
        self._partial_revision_id_to_revno_cache = {}
807
705
 
808
706
    def _gen_revision_history(self):
809
707
        """Return sequence of revision hashes on to this branch.
848
746
        """Older format branches cannot bind or unbind."""
849
747
        raise errors.UpgradeRequired(self.base)
850
748
 
 
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
 
851
753
    def last_revision(self):
852
754
        """Return last revision id, or NULL_REVISION."""
853
755
        return self.last_revision_info()[1]
933
835
        except ValueError:
934
836
            raise errors.NoSuchRevision(self, revision_id)
935
837
 
936
 
    @needs_read_lock
937
838
    def get_rev_id(self, revno, history=None):
938
839
        """Find the revision id of the specified revno."""
939
840
        if revno == 0:
940
841
            return _mod_revision.NULL_REVISION
941
 
        last_revno, last_revid = self.last_revision_info()
942
 
        if revno == last_revno:
943
 
            return last_revid
944
 
        if revno <= 0 or revno > last_revno:
 
842
        if history is None:
 
843
            history = self.revision_history()
 
844
        if revno <= 0 or revno > len(history):
945
845
            raise errors.NoSuchRevision(self, revno)
946
 
        distance_from_last = last_revno - revno
947
 
        if len(self._partial_revision_history_cache) <= distance_from_last:
948
 
            self._extend_partial_history(distance_from_last)
949
 
        return self._partial_revision_history_cache[distance_from_last]
 
846
        return history[revno - 1]
950
847
 
951
848
    @needs_write_lock
952
849
    def pull(self, source, overwrite=False, stop_revision=None,
1035
932
            location = None
1036
933
        return location
1037
934
 
1038
 
    def get_child_submit_format(self):
1039
 
        """Return the preferred format of submissions to this branch."""
1040
 
        return self.get_config().get_user_option("child_submit_format")
1041
 
 
1042
935
    def get_submit_branch(self):
1043
936
        """Return the submit location of the branch.
1044
937
 
1103
996
        params = ChangeBranchTipParams(
1104
997
            self, old_revno, new_revno, old_revid, new_revid)
1105
998
        for hook in hooks:
1106
 
            hook(params)
 
999
            try:
 
1000
                hook(params)
 
1001
            except errors.TipChangeRejected:
 
1002
                raise
 
1003
            except Exception:
 
1004
                exc_info = sys.exc_info()
 
1005
                hook_name = Branch.hooks.get_hook_name(hook)
 
1006
                raise errors.HookFailed(
 
1007
                    'pre_change_branch_tip', hook_name, exc_info)
1107
1008
 
1108
1009
    @needs_write_lock
1109
1010
    def update(self):
1158
1059
        revision_id: if not None, the revision history in the new branch will
1159
1060
                     be truncated to end with revision_id.
1160
1061
        """
1161
 
        if (repository_policy is not None and
1162
 
            repository_policy.requires_stacking()):
1163
 
            to_bzrdir._format.require_stacking(_skip_repo=True)
1164
1062
        result = to_bzrdir.create_branch()
1165
1063
        result.lock_write()
1166
1064
        try:
1187
1085
        source_revno, source_revision_id = self.last_revision_info()
1188
1086
        if revision_id is None:
1189
1087
            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
1190
1091
        else:
1191
 
            graph = self.repository.get_graph()
1192
 
            try:
1193
 
                revno = graph.find_distance_to_null(revision_id, 
1194
 
                    [(source_revision_id, source_revno)])
1195
 
            except errors.GhostRevisionsHaveNoRevno:
1196
 
                # Default to 1, if we can't find anything else
1197
 
                revno = 1
 
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)))
1198
1100
        destination.set_last_revision_info(revno, revision_id)
1199
1101
 
1200
1102
    @needs_read_lock
1234
1136
        target._set_all_reference_info(target_reference_dict)
1235
1137
 
1236
1138
    @needs_read_lock
1237
 
    def check(self, refs):
 
1139
    def check(self):
1238
1140
        """Check consistency of the branch.
1239
1141
 
1240
1142
        In particular this checks that revisions given in the revision-history
1243
1145
 
1244
1146
        Callers will typically also want to check the repository.
1245
1147
 
1246
 
        :param refs: Calculated refs for this branch as specified by
1247
 
            branch._get_check_refs()
1248
1148
        :return: A BranchCheckResult.
1249
1149
        """
1250
 
        result = BranchCheckResult(self)
 
1150
        mainline_parent_id = None
1251
1151
        last_revno, last_revision_id = self.last_revision_info()
1252
 
        actual_revno = refs[('lefthand-distance', last_revision_id)]
1253
 
        if actual_revno != last_revno:
1254
 
            result.errors.append(errors.BzrCheckError(
1255
 
                'revno does not match len(mainline) %s != %s' % (
1256
 
                last_revno, actual_revno)))
1257
 
        # TODO: We should probably also check that self.revision_history
1258
 
        # matches the repository for older branch formats.
1259
 
        # If looking for the code that cross-checks repository parents against
1260
 
        # the iter_reverse_revision_history output, that is now a repository
1261
 
        # specific check.
1262
 
        return result
 
1152
        real_rev_history = list(self.repository.iter_reverse_revision_history(
 
1153
                                last_revision_id))
 
1154
        real_rev_history.reverse()
 
1155
        if len(real_rev_history) != last_revno:
 
1156
            raise errors.BzrCheckError('revno does not match len(mainline)'
 
1157
                ' %s != %s' % (last_revno, len(real_rev_history)))
 
1158
        # TODO: We should probably also check that real_rev_history actually
 
1159
        #       matches self.revision_history()
 
1160
        for revision_id in real_rev_history:
 
1161
            try:
 
1162
                revision = self.repository.get_revision(revision_id)
 
1163
            except errors.NoSuchRevision, e:
 
1164
                raise errors.BzrCheckError("mainline revision {%s} not in repository"
 
1165
                            % revision_id)
 
1166
            # In general the first entry on the revision history has no parents.
 
1167
            # But it's not illegal for it to have parents listed; this can happen
 
1168
            # in imports from Arch when the parents weren't reachable.
 
1169
            if mainline_parent_id is not None:
 
1170
                if mainline_parent_id not in revision.parent_ids:
 
1171
                    raise errors.BzrCheckError("previous revision {%s} not listed among "
 
1172
                                        "parents of {%s}"
 
1173
                                        % (mainline_parent_id, revision_id))
 
1174
            mainline_parent_id = revision_id
 
1175
        return BranchCheckResult(self)
1263
1176
 
1264
1177
    def _get_checkout_format(self):
1265
1178
        """Return the most suitable metadir for a checkout of this branch.
1290
1203
        # clone call. Or something. 20090224 RBC/spiv.
1291
1204
        if revision_id is None:
1292
1205
            revision_id = self.last_revision()
1293
 
        dir_to = self.bzrdir.clone_on_transport(to_transport,
1294
 
            revision_id=revision_id, stacked_on=stacked_on,
1295
 
            create_prefix=create_prefix, use_existing_dir=use_existing_dir)
 
1206
        try:
 
1207
            dir_to = self.bzrdir.clone_on_transport(to_transport,
 
1208
                revision_id=revision_id, stacked_on=stacked_on,
 
1209
                create_prefix=create_prefix, use_existing_dir=use_existing_dir)
 
1210
        except errors.FileExists:
 
1211
            if not use_existing_dir:
 
1212
                raise
 
1213
        except errors.NoSuchFile:
 
1214
            if not create_prefix:
 
1215
                raise
1296
1216
        return dir_to.open_branch()
1297
1217
 
1298
1218
    def create_checkout(self, to_location, revision_id=None,
1425
1345
    _formats = {}
1426
1346
    """The known formats."""
1427
1347
 
1428
 
    can_set_append_revisions_only = True
1429
 
 
1430
1348
    def __eq__(self, other):
1431
1349
        return self.__class__ is other.__class__
1432
1350
 
1438
1356
        """Return the format for the branch object in a_bzrdir."""
1439
1357
        try:
1440
1358
            transport = a_bzrdir.get_branch_transport(None)
1441
 
            format_string = transport.get_bytes("format")
 
1359
            format_string = transport.get("format").read()
1442
1360
            return klass._formats[format_string]
1443
1361
        except errors.NoSuchFile:
1444
 
            raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)
 
1362
            raise errors.NotBranchError(path=transport.base)
1445
1363
        except KeyError:
1446
1364
            raise errors.UnknownFormatError(format=format_string, kind='branch')
1447
1365
 
1585
1503
    def set_default_format(klass, format):
1586
1504
        klass._default_format = format
1587
1505
 
1588
 
    def supports_set_append_revisions_only(self):
1589
 
        """True if this format supports set_append_revisions_only."""
1590
 
        return False
1591
 
 
1592
1506
    def supports_stacking(self):
1593
1507
        """True if this format records a stacked-on branch."""
1594
1508
        return False
1796
1710
                              _repository=a_bzrdir.find_repository(),
1797
1711
                              ignore_fallbacks=ignore_fallbacks)
1798
1712
        except errors.NoSuchFile:
1799
 
            raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)
 
1713
            raise errors.NotBranchError(path=transport.base)
1800
1714
 
1801
1715
    def __init__(self):
1802
1716
        super(BranchFormatMetadir, self).__init__()
1876
1790
        """See bzrlib.branch.BranchFormat.make_tags()."""
1877
1791
        return BasicTags(branch)
1878
1792
 
1879
 
    def supports_set_append_revisions_only(self):
1880
 
        return True
1881
1793
 
1882
1794
 
1883
1795
class BzrBranchFormat8(BranchFormatMetadir):
1912
1824
        """See bzrlib.branch.BranchFormat.make_tags()."""
1913
1825
        return BasicTags(branch)
1914
1826
 
1915
 
    def supports_set_append_revisions_only(self):
1916
 
        return True
1917
 
 
1918
1827
    def supports_stacking(self):
1919
1828
        return True
1920
1829
 
1949
1858
        """See BranchFormat.get_format_description()."""
1950
1859
        return "Branch format 7"
1951
1860
 
1952
 
    def supports_set_append_revisions_only(self):
1953
 
        return True
1954
 
 
1955
1861
    supports_reference_locations = False
1956
1862
 
1957
1863
 
1977
1883
    def get_reference(self, a_bzrdir):
1978
1884
        """See BranchFormat.get_reference()."""
1979
1885
        transport = a_bzrdir.get_branch_transport(None)
1980
 
        return transport.get_bytes('location')
 
1886
        return transport.get('location').read()
1981
1887
 
1982
1888
    def set_reference(self, a_bzrdir, to_branch):
1983
1889
        """See BranchFormat.set_reference()."""
2071
1977
BranchFormat.register_format(__format6)
2072
1978
BranchFormat.register_format(__format7)
2073
1979
BranchFormat.register_format(__format8)
2074
 
BranchFormat.set_default_format(__format7)
 
1980
BranchFormat.set_default_format(__format6)
2075
1981
_legacy_formats = [BzrBranchFormat4(),
2076
1982
    ]
2077
1983
network_format_registry.register(
2078
1984
    _legacy_formats[0].network_name(), _legacy_formats[0].__class__)
2079
1985
 
2080
1986
 
2081
 
class BzrBranch(Branch, _RelockDebugMixin):
 
1987
class BzrBranch(Branch):
2082
1988
    """A branch stored in the actual filesystem.
2083
1989
 
2084
1990
    Note that it's "local" in the context of the filesystem; it doesn't
2130
2036
        return self.control_files.is_locked()
2131
2037
 
2132
2038
    def lock_write(self, token=None):
2133
 
        if not self.is_locked():
2134
 
            self._note_lock('w')
2135
2039
        # All-in-one needs to always unlock/lock.
2136
2040
        repo_control = getattr(self.repository, 'control_files', None)
2137
2041
        if self.control_files == repo_control or not self.is_locked():
2138
 
            self.repository._warn_if_deprecated(self)
2139
2042
            self.repository.lock_write()
2140
2043
            took_lock = True
2141
2044
        else:
2148
2051
            raise
2149
2052
 
2150
2053
    def lock_read(self):
2151
 
        if not self.is_locked():
2152
 
            self._note_lock('r')
2153
2054
        # All-in-one needs to always unlock/lock.
2154
2055
        repo_control = getattr(self.repository, 'control_files', None)
2155
2056
        if self.control_files == repo_control or not self.is_locked():
2156
 
            self.repository._warn_if_deprecated(self)
2157
2057
            self.repository.lock_read()
2158
2058
            took_lock = True
2159
2059
        else:
2165
2065
                self.repository.unlock()
2166
2066
            raise
2167
2067
 
2168
 
    @only_raises(errors.LockNotHeld, errors.LockBroken)
2169
2068
    def unlock(self):
2170
2069
        try:
2171
2070
            self.control_files.unlock()
2467
2366
                    raise AssertionError(
2468
2367
                        "'transform_fallback_location' hook %s returned "
2469
2368
                        "None, not a URL." % hook_name)
2470
 
            self._activate_fallback_location(url)
 
2369
            self._activate_fallback_location(url, None)
2471
2370
 
2472
2371
    def __init__(self, *args, **kwargs):
2473
2372
        self._ignore_fallbacks = kwargs.get('ignore_fallbacks', False)
2474
2373
        super(BzrBranch8, self).__init__(*args, **kwargs)
2475
2374
        self._last_revision_info_cache = None
 
2375
        self._partial_revision_history_cache = []
2476
2376
        self._reference_info = None
2477
2377
 
2478
2378
    def _clear_cached_state(self):
2479
2379
        super(BzrBranch8, self)._clear_cached_state()
2480
2380
        self._last_revision_info_cache = None
 
2381
        self._partial_revision_history_cache = []
2481
2382
        self._reference_info = None
2482
2383
 
2483
2384
    def _last_revision_info(self):
2539
2440
        self._extend_partial_history(stop_index=last_revno-1)
2540
2441
        return list(reversed(self._partial_revision_history_cache))
2541
2442
 
 
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
 
2542
2472
    def _write_revision_history(self, history):
2543
2473
        """Factored out of set_revision_history.
2544
2474
 
2687
2617
            raise errors.NotStacked(self)
2688
2618
        return stacked_url
2689
2619
 
 
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
 
2690
2628
    def _get_append_revisions_only(self):
2691
2629
        value = self.get_config().get_user_option('append_revisions_only')
2692
2630
        return value == 'True'
2842
2780
 
2843
2781
    def __init__(self, branch):
2844
2782
        self.branch = branch
2845
 
        self.errors = []
2846
2783
 
2847
2784
    def report_results(self, verbose):
2848
2785
        """Report the check results via trace.note.
2850
2787
        :param verbose: Requests more detailed display of what was checked,
2851
2788
            if any.
2852
2789
        """
2853
 
        note('checked branch %s format %s', self.branch.base,
2854
 
            self.branch._format)
2855
 
        for error in self.errors:
2856
 
            note('found error:%s', error)
 
2790
        note('checked branch %s format %s',
 
2791
             self.branch.base,
 
2792
             self.branch._format)
2857
2793
 
2858
2794
 
2859
2795
class Converter5to6(object):
2954
2890
    @staticmethod
2955
2891
    def _get_branch_formats_to_test():
2956
2892
        """Return a tuple with the Branch formats to use when testing."""
2957
 
        raise NotImplementedError(InterBranch._get_branch_formats_to_test)
 
2893
        raise NotImplementedError(self._get_branch_formats_to_test)
2958
2894
 
2959
2895
    def pull(self, overwrite=False, stop_revision=None,
2960
2896
             possible_transports=None, local=False):
3115
3051
                _override_hook_source_branch=_override_hook_source_branch)
3116
3052
        finally:
3117
3053
            self.source.unlock()
 
3054
        return result
3118
3055
 
3119
3056
    def _push_with_bound_branches(self, overwrite, stop_revision,
3120
3057
            _override_hook_source_branch=None):