~cjwatson/brz-svn/fix-http-probe

« back to all changes in this revision

Viewing changes to branch.py

  • Committer: Jelmer Vernooij
  • Date: 2020-02-03 09:16:45 UTC
  • Revision ID: jelmer@jelmer.uk-20200203091645-q0f1yq77zkr1s3cz
More Python3 / formatting / breezy fixes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
    )
28
28
 
29
29
from breezy import (
 
30
    cleanup,
30
31
    tag,
31
32
    trace,
32
33
    urlutils,
124
125
                to_file.write('No revisions to pull.\n')
125
126
            else:
126
127
                if self.new_revmeta is None:
127
 
                    self.new_revmeta, _ = self.source_branch.repository._get_revmeta(self.new_revid)
128
 
                to_file.write('Now on revision %d (svn revno: %d).\n' %
129
 
                        (self.new_revno, self.new_revmeta.metarev.revnum))
 
128
                    self.new_revmeta, _ = (
 
129
                        self.source_branch.repository._get_revmeta(
 
130
                            self.new_revid))
 
131
                to_file.write(
 
132
                    'Now on revision %d (svn revno: %d).\n' %
 
133
                    (self.new_revno, self.new_revmeta.metarev.revnum))
130
134
        self._show_tag_conficts(to_file)
131
135
 
132
136
 
186
190
    """Maps to a Branch in a Subversion repository """
187
191
 
188
192
    def __init__(self, repository, controldir, branch_path, mapping,
189
 
            revnum=None, project=None, _skip_check=False):
 
193
                 revnum=None, project=None, _skip_check=False):
190
194
        """Instantiate a new SvnBranch.
191
195
 
192
196
        :param repository: SvnRepository this branch is part of.
204
208
        if not isinstance(branch_path, text_type):
205
209
            raise TypeError(branch_path)
206
210
        self._branch_path = branch_path.strip(u"/")
207
 
        self.base = urlutils.join(self.repository.base, urlutils.escape(self._branch_path)).rstrip("/")
 
211
        self.base = urlutils.join(
 
212
            self.repository.base, urlutils.escape(self._branch_path)
 
213
            ).rstrip("/")
208
214
        super(SvnBranch, self).__init__(mapping)
209
215
        self._lock_mode = None
210
216
        self._lock_count = 0
244
250
        return self.supports_tags()
245
251
 
246
252
    def check_path(self):
247
 
        return self.repository.svn_transport.check_path(self._branch_path,
248
 
            self.repository.get_latest_revnum())
 
253
        return self.repository.svn_transport.check_path(
 
254
            self._branch_path, self.repository.get_latest_revnum())
249
255
 
250
256
    def supports_tags(self):
251
257
        """See Branch.supports_tags()."""
346
352
        :return: Tuple with foreign revision id and mapping
347
353
        :raises NoSuchRevision: If the revision id was not found.
348
354
        """
349
 
        return self.repository.lookup_bzr_revision_id(revid,
350
 
            ancestry=(self.get_branch_path(), self.get_revnum()),
 
355
        return self.repository.lookup_bzr_revision_id(
 
356
            revid, ancestry=(self.get_branch_path(), self.get_revnum()),
351
357
            project=self.project)
352
358
 
353
359
    def _create_lightweight_checkout(self, to_location, revision_id=None):
373
379
        transport = get_transport(to_location)
374
380
        transport.ensure_base()
375
381
        to_path = transport.local_abspath(".")
376
 
        svn_url, readonly = bzr_to_svn_url(urlutils.join(self.repository.base, bp))
 
382
        svn_url, readonly = bzr_to_svn_url(
 
383
            urlutils.join(self.repository.base, bp))
377
384
        wc.ensure_adm(to_path.encode("utf-8"), uuid,
378
385
                      svn_url, bzr_to_svn_url(self.repository.base)[0], revnum)
379
386
        with wc.Adm(None, to_path.encode("utf-8"), write_lock=True) as adm:
481
488
            try:
482
489
                rev = self.repository.get_revision(revid)
483
490
            except NoSuchRevision:
484
 
                raise NotImplementedError("set_last_revision_info can't add ghosts")
 
491
                raise NotImplementedError(
 
492
                    "set_last_revision_info can't add ghosts")
485
493
            interrepo = InterToSvnRepository(self.repository, self.repository)
486
494
            try:
487
495
                base_revid = rev.parent_ids[0]
488
496
            except IndexError:
489
497
                base_foreign_info = None, None
490
498
            else:
491
 
                base_foreign_info = self.lookup_bzr_revision_id(rev.parent_ids[0])
 
499
                base_foreign_info = self.lookup_bzr_revision_id(
 
500
                    rev.parent_ids[0])
492
501
            interrepo.push_single_revision(
493
502
                self.get_branch_path(), self.get_config_stack(), rev,
494
503
                push_metadata=True, root_action=("replace", self.get_revnum()),
555
564
            if hidden:
556
565
                continue
557
566
            if count == 0:
558
 
                assert revmeta.get_revno(mapping) == revno, "Expected %d, was (%r,%r) %d" % (revno, revmeta, mapping, revmeta.get_revno(mapping))
 
567
                if revmeta.get_revno(mapping) != revno:
 
568
                    raise AssertionError(
 
569
                        "Expected %d, was (%r,%r) %d" % (
 
570
                            revno, revmeta, mapping,
 
571
                            revmeta.get_revno(mapping)))
559
572
                return revmeta.get_revision_id(mapping)
560
573
            count -= 1
561
574
        raise AssertionError
562
575
 
563
576
    def _gen_revision_history(self):
564
577
        """Generate the revision history from last revision."""
565
 
        history = [revmeta.get_revision_id(mapping) for revmeta, hidden, mapping in self._revision_meta_history() if not hidden]
 
578
        history = [
 
579
            revmeta.get_revision_id(mapping)
 
580
            for revmeta, hidden, mapping in self._revision_meta_history()
 
581
            if not hidden]
566
582
        history.reverse()
567
583
        return history
568
584
 
569
585
    def last_revision(self):
570
586
        """See Branch.last_revision()."""
571
587
        with self.lock_read():
572
 
            # Shortcut for finding the tip. This avoids expensive generation time
573
 
            # on large branches.
 
588
            # Shortcut for finding the tip. This avoids expensive generation
 
589
            # time on large branches.
574
590
            if self._cached_last_revid is not None:
575
591
                return self._cached_last_revid
576
592
            last_revmeta, mapping = self.last_revmeta(skip_hidden=True)
587
603
        return (self.layout.push_merged_revisions(self.project) and
588
604
                self.get_config_stack().get('push_merged_revisions'))
589
605
 
590
 
    def import_last_revision_info(self, source_repo, revno, revid, lossy=False):
 
606
    def import_last_revision_info(
 
607
            self, source_repo, revno, revid, lossy=False):
591
608
        interrepo = InterToSvnRepository(source_repo, self.repository)
592
609
        base_revmeta, base_mapping = self.last_revmeta(skip_hidden=False)
593
 
        revidmap = interrepo.push_todo(self.last_revision(),
594
 
            base_revmeta.metarev.get_foreign_revid(),
595
 
            base_mapping, revid, self.layout,
596
 
            self.project, self.get_branch_path(), self.get_config_stack(),
597
 
            push_merged=self.get_push_merged_revisions(),
598
 
            overwrite=False, push_metadata=not lossy,
599
 
            append_revisions_only=True)
 
610
        revidmap = interrepo.push_todo(
 
611
            self.last_revision(), base_revmeta.metarev.get_foreign_revid(),
 
612
            base_mapping, revid, self.layout, self.project,
 
613
            self.get_branch_path(), self.get_config_stack(),
 
614
            push_merged=self.get_push_merged_revisions(), overwrite=False,
 
615
            push_metadata=not lossy, append_revisions_only=True)
600
616
        return (revno, revidmap[revid][0])
601
617
 
602
 
    def import_last_revision_info_and_tags(self, source, revno, revid,
603
 
            lossy=False):
604
 
        (revno, revid) = self.import_last_revision_info(source.repository,
605
 
            revno, revid, lossy=lossy)
 
618
    def import_last_revision_info_and_tags(
 
619
            self, source, revno, revid, lossy=False):
 
620
        (revno, revid) = self.import_last_revision_info(
 
621
            source.repository, revno, revid, lossy=lossy)
606
622
        self.tags.merge_to(source.tags, overwrite=False)
607
623
        return (revno, revid)
608
624
 
609
 
    def generate_revision_history(self, revision_id, last_rev=None,
610
 
        other_branch=None):
 
625
    def generate_revision_history(
 
626
            self, revision_id, last_rev=None, other_branch=None):
611
627
        """Create a new revision history that will finish with revision_id.
612
628
 
613
629
        :param revision_id: the new tip to use.
711
727
        return InterBranch.get(self, target)._basic_push(
712
728
            overwrite, stop_revision)
713
729
 
 
730
    def reconcile(self, thorough=True):
 
731
        """Make sure the data stored in this branch is consistent.
 
732
 
 
733
        :return: A `ReconcileResult` object.
 
734
        """
 
735
        from ...reconcile import ReconcileResult
 
736
        return ReconcileResult()
 
737
 
714
738
 
715
739
class SvnBranchFormat(BranchFormat):
716
740
    """Branch format for Subversion Branches."""
720
744
 
721
745
    def __get_matchingcontroldir(self):
722
746
        """See BranchFormat.__get_matchingcontroldir()."""
723
 
        from breezy.plugins.svn.remote import SvnRemoteFormat
 
747
        from .remote import SvnRemoteFormat
724
748
        return SvnRemoteFormat()
725
749
 
726
750
    _matchingcontroldir = property(__get_matchingcontroldir)
781
805
        return [(SvnBranchFormat(), branch_format_registry.get_default())]
782
806
 
783
807
    def fetch(self, stop_revision=None, fetch_tags=None, find_ghosts=False,
784
 
              limit=None, exclude_non_mainline=None):
 
808
              limit=None, exclude_non_mainline=None, lossy=False):
785
809
        """See InterBranch.fetch."""
786
810
        # we fetch here so that we don't process data twice in the
787
811
        # common case of having something to pull, and so that the
806
830
            d = resolve_tags_svn_ancestry(self.source, tag_revmetas)
807
831
            for name, (revmeta, mapping, revid) in d.items():
808
832
                todo.append((revmeta, mapping))
809
 
        self._fetch_revmetas(todo, find_ghosts=find_ghosts, limit=limit,
810
 
                exclude_non_mainline=exclude_non_mainline)
 
833
        self._fetch_revmetas(
 
834
            todo, find_ghosts=find_ghosts, limit=limit,
 
835
            exclude_non_mainline=exclude_non_mainline)
811
836
 
812
 
    def _fetch_revmetas(self, revmetas, find_ghosts=False, limit=None,
 
837
    def _fetch_revmetas(
 
838
            self, revmetas, find_ghosts=False, limit=None,
813
839
            exclude_non_mainline=None):
814
 
        interrepo = InterFromSvnToInventoryRepository(self.source.repository,
815
 
            self.target.repository)
 
840
        interrepo = InterFromSvnToInventoryRepository(
 
841
            self.source.repository, self.target.repository)
816
842
        revisionfinder = interrepo.get_revision_finder()
817
843
        for revmeta, mapping in revmetas:
818
 
            revisionfinder.find_until(revmeta.metarev.get_foreign_revid(),
819
 
                mapping, find_ghosts=find_ghosts,
 
844
            revisionfinder.find_until(
 
845
                revmeta.metarev.get_foreign_revid(), mapping,
 
846
                find_ghosts=find_ghosts,
820
847
                exclude_non_mainline=exclude_non_mainline)
821
 
        interrepo.fetch(needed=revisionfinder.get_missing(limit=limit),
 
848
        interrepo.fetch(
 
849
            needed=revisionfinder.get_missing(limit=limit),
822
850
            project=self.source.project, mapping=self.source.mapping)
823
851
 
824
852
    def _update_revisions(self, stop_revision=None, overwrite=False,
825
 
                         graph=None, fetch_tags=None,
826
 
                         fetch_non_mainline=None):
 
853
                          graph=None, fetch_tags=None,
 
854
                          fetch_non_mainline=None):
827
855
        "See InterBranch.update_revisions."""
828
856
        with self.source.lock_read():
829
857
            if stop_revision is None:
853
881
            self.target.generate_revision_history(stop_revision)
854
882
            return self.target.last_revision_info()
855
883
 
856
 
    def _basic_push(self, overwrite=False, stop_revision=None,
 
884
    def _basic_push(
 
885
            self, overwrite=False, stop_revision=None,
857
886
            fetch_non_mainline=False):
858
887
        result = BranchPushResult()
859
888
        result.source_branch = self.source
878
907
        else:
879
908
            result.tag_conflicts = tag_ret
880
909
 
881
 
    def _basic_pull(self, stop_revision, overwrite, run_hooks,
882
 
              _override_hook_target, _hook_master,
883
 
              fetch_non_mainline=None):
884
 
        self.target.lock_write()
885
 
        try:
 
910
    def _basic_pull(
 
911
            self, stop_revision, overwrite, run_hooks,
 
912
            _override_hook_target, _hook_master,
 
913
            fetch_non_mainline=None):
 
914
        with self.target.lock_write():
886
915
            result = SubversionSourcePullResult()
887
916
            result.source_branch = self.source
888
917
            if _override_hook_target is None:
924
953
            if run_hooks:
925
954
                for hook in Branch.hooks['post_pull']:
926
955
                    hook(result)
927
 
        finally:
928
 
            self.target.unlock()
929
956
        return result
930
957
 
931
958
    def pull(self, overwrite=False, stop_revision=None,
938
965
            raise LocalRequiresBoundBranch()
939
966
        master_branch = None
940
967
        source_is_master = False
941
 
        self.source.lock_read()
942
 
        if bound_location:
943
 
            # bound_location comes from a config file, some care has to be
944
 
            # taken to relate it to source.user_url
945
 
            normalized = urlutils.normalize_url(bound_location)
946
 
            try:
947
 
                relpath = self.source.user_transport.relpath(normalized)
948
 
                source_is_master = (relpath == '')
949
 
            except (PathNotChild, urlutils.InvalidURL):
950
 
                source_is_master = False
951
 
        if not local and bound_location and not source_is_master:
952
 
            # not pulling from master, so we need to update master.
953
 
            master_branch = self.target.get_master_branch(possible_transports)
954
 
            master_branch.lock_write()
955
 
        try:
956
 
            try:
957
 
                if master_branch:
958
 
                    # pull from source into master.
959
 
                    master_branch.pull(self.source, overwrite, stop_revision,
960
 
                        run_hooks=False, fetch_non_mainline=fetch_non_mainline)
961
 
                result = self._basic_pull(stop_revision, overwrite, run_hooks,
962
 
                    _override_hook_target, _hook_master=master_branch,
963
 
                    fetch_non_mainline=fetch_non_mainline)
964
 
            finally:
965
 
                self.source.unlock()
966
 
        finally:
967
 
            if master_branch:
968
 
                master_branch.unlock()
969
 
        return result
 
968
        with cleanup.ExitStack() as es:
 
969
            es.enter_context(self.source.lock_read())
 
970
            if bound_location:
 
971
                # bound_location comes from a config file, some care has to be
 
972
                # taken to relate it to source.user_url
 
973
                normalized = urlutils.normalize_url(bound_location)
 
974
                try:
 
975
                    relpath = self.source.user_transport.relpath(normalized)
 
976
                    source_is_master = (relpath == '')
 
977
                except (PathNotChild, urlutils.InvalidURL):
 
978
                    source_is_master = False
 
979
            if not local and bound_location and not source_is_master:
 
980
                # not pulling from master, so we need to update master.
 
981
                master_branch = self.target.get_master_branch(
 
982
                    possible_transports)
 
983
                es.enter_context(master_branch.lock_write())
 
984
                # pull from source into master.
 
985
                master_branch.pull(
 
986
                    self.source, overwrite, stop_revision,
 
987
                    run_hooks=False, fetch_non_mainline=fetch_non_mainline)
 
988
            return self._basic_pull(
 
989
                stop_revision, overwrite, run_hooks,
 
990
                _override_hook_target, _hook_master=master_branch,
 
991
                fetch_non_mainline=fetch_non_mainline)
970
992
 
971
993
    @classmethod
972
994
    def is_compatible(self, source, target):
976
998
            return False
977
999
        return True
978
1000
 
 
1001
 
979
1002
InterBranch.register_optimiser(InterFromSvnBranch)
980
1003
 
981
1004
 
1017
1040
    def _push(self, stop_revision, overwrite, push_metadata):
1018
1041
        old_last_revid = self.target.last_revision()
1019
1042
        if old_last_revid == stop_revision:
1020
 
            return (old_last_revid, { old_last_revid: (old_last_revid, None) })
 
1043
            return (old_last_revid, {old_last_revid: (old_last_revid, None)})
1021
1044
        push_merged = self.target.get_push_merged_revisions()
1022
1045
        interrepo = InterToSvnRepository(
1023
1046
            self.source.repository, self.target.repository)
1024
 
        base_revmeta, base_mapping = self.target.last_revmeta(skip_hidden=False)
 
1047
        base_revmeta, base_mapping = self.target.last_revmeta(
 
1048
            skip_hidden=False)
1025
1049
        try:
1026
 
            revidmap = interrepo.push_branch(self.target.get_branch_path(),
1027
 
                    self.target.get_config_stack(), old_last_revid,
1028
 
                    base_revmeta.metarev.get_foreign_revid(),
1029
 
                    base_mapping,
1030
 
                    stop_revision=stop_revision, overwrite=overwrite,
1031
 
                    push_metadata=push_metadata, push_merged=push_merged,
1032
 
                    layout=self.target.layout, project=self.target.project)
 
1050
            revidmap = interrepo.push_branch(
 
1051
                self.target.get_branch_path(),
 
1052
                self.target.get_config_stack(), old_last_revid,
 
1053
                base_revmeta.metarev.get_foreign_revid(),
 
1054
                base_mapping, stop_revision=stop_revision, overwrite=overwrite,
 
1055
                push_metadata=push_metadata, push_merged=push_merged,
 
1056
                layout=self.target.layout, project=self.target.project)
1033
1057
        except SubversionBranchDiverged as e:
1034
1058
            if self._target_is_empty(interrepo.get_graph(), e.target_revid):
1035
1059
                raise PushToEmptyBranch(self.target, self.source)
1036
1060
            raise DivergedBranches(self.target, self.source)
1037
1061
        return (old_last_revid, revidmap)
1038
1062
 
1039
 
    def _update_revisions(self, stop_revision=None, overwrite=False,
1040
 
            lossy=False, fetch_non_mainline=False):
 
1063
    def _update_revisions(
 
1064
            self, stop_revision=None, overwrite=False, lossy=False,
 
1065
            fetch_non_mainline=False):
1041
1066
        """Push derivatives of the revisions missing from target from source
1042
1067
        into target.
1043
1068
 
1057
1082
                dict([(k, v[0]) for (k, v) in revid_map.items()]))
1058
1083
 
1059
1084
    def fetch(self, stop_revision=None, fetch_tags=None, find_ghosts=False,
1060
 
            limit=None, exclude_non_mainline=None):
 
1085
              limit=None, exclude_non_mainline=None, lossy=False):
1061
1086
        """Fetch into a subversion repository."""
1062
1087
        # FIXME: Handle fetch_tags
1063
1088
        # FIXME: Handle find_ghosts
1065
1090
            self.source.repository, self.target.repository)
1066
1091
        if stop_revision is None:
1067
1092
            stop_revision = self.source.last_revision()
1068
 
        interrepo.fetch(revision_id=stop_revision, limit=limit,
 
1093
        interrepo.fetch(
 
1094
            revision_id=stop_revision, limit=limit,
1069
1095
            exclude_non_mainline=exclude_non_mainline)
1070
1096
 
1071
1097
    def update_tags(self, result, overwrite=False):
1076
1102
            result.tag_conflicts = ret
1077
1103
 
1078
1104
    def _basic_push(self, overwrite=False, stop_revision=None, lossy=False,
1079
 
            fetch_non_mainline=False):
 
1105
                    fetch_non_mainline=False):
1080
1106
        """Basic implementation of push without bound branches or hooks.
1081
1107
 
1082
1108
        Must be called with source read locked and target write locked.
1083
1109
        """
1084
1110
        if lossy and isinstance(self.source, SvnBranch):
1085
1111
            raise LossyPushToSameVCS(self.source, self.target)
1086
 
        return self._update_revisions(stop_revision, overwrite=overwrite,
1087
 
            lossy=lossy, fetch_non_mainline=fetch_non_mainline)
 
1112
        return self._update_revisions(
 
1113
            stop_revision, overwrite=overwrite, lossy=lossy,
 
1114
            fetch_non_mainline=fetch_non_mainline)
1088
1115
 
1089
1116
    def push(self, overwrite=False, stop_revision=None,
1090
 
            lossy=False, _override_hook_source_branch=None,
1091
 
            fetch_non_mainline=None):
 
1117
             lossy=False, _override_hook_source_branch=None,
 
1118
             fetch_non_mainline=None):
1092
1119
        """See InterBranch.push()."""
1093
1120
        result = SubversionTargetBranchPushResult()
1094
1121
        result.target_branch = self.target
1118
1145
        result.master_branch = self.target
1119
1146
        with self.source.lock_read(), self.target.lock_write():
1120
1147
            (result.old_revid, result.new_revid, result.revidmap) = \
1121
 
                self._update_revisions(stop_revision, overwrite,
1122
 
                        fetch_non_mainline=fetch_non_mainline)
 
1148
                self._update_revisions(
 
1149
                    stop_revision, overwrite,
 
1150
                    fetch_non_mainline=fetch_non_mainline)
1123
1151
            self.update_tags(result, overwrite)
1124
1152
            if run_hooks:
1125
1153
                for hook in Branch.hooks['post_pull']: