/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to branch.py

Don't peel tags automatically when pushing back.

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
 
18
18
"""An adapter between a Git Branch and a Bazaar Branch"""
19
19
 
 
20
from collections import defaultdict
 
21
 
20
22
from dulwich.objects import (
21
23
    Commit,
22
24
    Tag,
51
53
    NoSuchRef,
52
54
    )
53
55
from bzrlib.plugins.git.refs import (
 
56
    extract_tags,
 
57
    is_tag,
54
58
    ref_to_branch_name,
55
 
    extract_tags,
 
59
    ref_to_tag_name,
56
60
    tag_name_to_ref,
 
61
    UnpeelMap,
57
62
    )
58
63
 
59
64
from bzrlib.foreign import ForeignBranch
76
81
        return self._lookup_revno(self.new_revid)
77
82
 
78
83
 
79
 
class LocalGitTagDict(tag.BasicTags):
80
 
    """Dictionary with tags in a local repository."""
 
84
class GitTags(tag.BasicTags):
 
85
    """Ref-based tag dictionary."""
81
86
 
82
87
    def __init__(self, branch):
83
88
        self.branch = branch
84
89
        self.repository = branch.repository
85
90
 
 
91
    def _iter_tag_refs(self, refs):
 
92
        raise NotImplementedError(self._iter_tag_refs)
 
93
 
 
94
    def _merge_to_git(self, to_tags, refs, overwrite=False):
 
95
        target_repo = to_tags.repository
 
96
        conflicts = []
 
97
        for k, v in refs.iteritems():
 
98
            if not is_tag(k):
 
99
                continue
 
100
            if overwrite or not k in self.target.repository.refs:
 
101
                target_repo.refs[k] = v
 
102
            elif target_repo.repository.refs[k] == v:
 
103
                pass
 
104
            else:
 
105
                conflicts.append((ref_to_tag_name(k), v, target_repo.refs[k]))
 
106
        return conflicts
 
107
 
 
108
    def _merge_to_non_git(self, to_tags, refs, overwrite=False):
 
109
        unpeeled_map = defaultdict(set)
 
110
        conflicts = []
 
111
        result = dict(to_tags.get_tag_dict())
 
112
        for n, peeled, unpeeled, bzr_revid in self._iter_tag_refs(refs):
 
113
            if unpeeled is not None:
 
114
                unpeeled_map[peeled].add(unpeeled)
 
115
            if n not in result or overwrite:
 
116
                result[n] = bzr_revid
 
117
            elif result[n] == bzr_revid:
 
118
                pass
 
119
            else:
 
120
                conflicts.append((n, result[n], bzr_revid))
 
121
        to_tags._set_tag_dict(result)
 
122
        if len(unpeeled_map) > 0:
 
123
            map_file = UnpeelMap.from_repository(to_tags.branch.repository)
 
124
            map_file.update(unpeeled_map)
 
125
            map_file.save_in_repository(to_tags.branch.repository)
 
126
        return conflicts
 
127
 
 
128
    def merge_to(self, to_tags, overwrite=False, ignore_master=False,
 
129
                 source_refs=None):
 
130
        if source_refs is None:
 
131
            source_refs = self.repository.get_refs()
 
132
        if self == to_tags:
 
133
            return
 
134
        if isinstance(to_tags, GitTags):
 
135
            return self._merge_to_git(to_tags, source_refs,
 
136
                                      overwrite=overwrite)
 
137
        else:
 
138
            if ignore_master:
 
139
                master = None
 
140
            else:
 
141
                master = to_tags.branch.get_master_branch()
 
142
            conflicts = self._merge_to_non_git(to_tags, source_refs,
 
143
                                              overwrite=overwrite)
 
144
            if master is not None:
 
145
                conflicts += self.merge_to(to_tags, overwrite=overwrite,
 
146
                                           source_refs=source_refs,
 
147
                                           ignore_master=ignore_master)
 
148
            return conflicts
 
149
 
86
150
    def get_tag_dict(self):
87
151
        ret = {}
88
 
        for k,v in extract_tags(self.repository._git.get_refs()).iteritems():
 
152
        refs = self.repository.get_refs()
 
153
        for (name, peeled, unpeeled, bzr_revid) in self._iter_tag_refs(refs):
 
154
            ret[name] = bzr_revid
 
155
        return ret
 
156
 
 
157
 
 
158
class LocalGitTagDict(GitTags):
 
159
    """Dictionary with tags in a local repository."""
 
160
 
 
161
    def __init__(self, branch):
 
162
        super(LocalGitTagDict, self).__init__(branch)
 
163
        self.refs = self.repository._git.refs
 
164
 
 
165
    def _iter_tag_refs(self, refs):
 
166
        """Iterate over the tag refs.
 
167
 
 
168
        :param refs: Refs dictionary (name -> git sha1)
 
169
        :return: iterator over (name, peeled_sha1, unpeeled_sha1, bzr_revid)
 
170
        """
 
171
        for k, (peeled, unpeeled) in extract_tags(refs).iteritems():
89
172
            try:
90
 
                obj = self.repository._git[v]
 
173
                obj = self.repository._git[peeled]
91
174
            except KeyError:
92
 
                mutter("Tag %s points at unknown object %s, ignoring", v, obj)
 
175
                mutter("Tag %s points at unknown object %s, ignoring", peeled,
 
176
                       obj)
93
177
                continue
 
178
            # FIXME: this shouldn't really be necessary, the repository
 
179
            # already should have these unpeeled.
94
180
            while isinstance(obj, Tag):
95
 
                v = obj.object[1]
96
 
                obj = self.repository._git[v]
 
181
                peeled = obj.object[1]
 
182
                obj = self.repository._git[peeled]
97
183
            if not isinstance(obj, Commit):
98
184
                mutter("Tag %s points at object %r that is not a commit, "
99
185
                       "ignoring", k, obj)
100
186
                continue
101
 
            ret[k] = self.branch.lookup_foreign_revision_id(v)
102
 
        return ret
 
187
            yield (k, peeled, unpeeled,
 
188
                   self.branch.lookup_foreign_revision_id(peeled))
 
189
 
103
190
 
104
191
    def _set_tag_dict(self, to_dict):
105
192
        extra = set(self.repository._git.get_refs().keys())
109
196
                extra.remove(name)
110
197
            self.set_tag(k, revid)
111
198
        for name in extra:
112
 
            if name.startswith("refs/tags/"):
 
199
            if is_tag(name):
113
200
                del self.repository._git[name]
114
201
 
115
202
    def set_tag(self, name, revid):
116
 
        self.repository._git.refs[tag_name_to_ref(name)], _ = \
 
203
        self.refs[tag_name_to_ref(name)], _ = \
117
204
            self.branch.lookup_bzr_revision_id(revid)
118
205
 
119
206
 
351
438
        return True
352
439
 
353
440
 
 
441
def _quick_lookup_revno(local_branch, remote_branch, revid):
 
442
    assert isinstance(revid, str), "was %r" % revid
 
443
    # Try in source branch first, it'll be faster
 
444
    try:
 
445
        return local_branch.revision_id_to_revno(revid)
 
446
    except errors.NoSuchRevision:
 
447
        graph = local_branch.repository.get_graph()
 
448
        try:
 
449
            return graph.find_distance_to_null(revid)
 
450
        except errors.GhostRevisionsHaveNoRevno:
 
451
            # FIXME: Check using graph.find_distance_to_null() ?
 
452
            return remote_branch.revision_id_to_revno(revid)
 
453
 
 
454
 
354
455
class GitBranchPullResult(branch.PullResult):
355
456
 
356
457
    def __init__(self):
371
472
        self._show_tag_conficts(to_file)
372
473
 
373
474
    def _lookup_revno(self, revid):
374
 
        assert isinstance(revid, str), "was %r" % revid
375
 
        # Try in source branch first, it'll be faster
376
 
        try:
377
 
            return self.source_branch.revision_id_to_revno(revid)
378
 
        except errors.NoSuchRevision:
379
 
            # FIXME: Check using graph.find_distance_to_null() ?
380
 
            return self.target_branch.revision_id_to_revno(revid)
 
475
        return _quick_lookup_revno(self.target_branch, self.source_branch, revid)
381
476
 
382
477
    def _get_old_revno(self):
383
478
        if self._old_revno is not None:
403
498
class GitBranchPushResult(branch.BranchPushResult):
404
499
 
405
500
    def _lookup_revno(self, revid):
406
 
        assert isinstance(revid, str), "was %r" % revid
407
 
        # Try in source branch first, it'll be faster
408
 
        try:
409
 
            return self.source_branch.revision_id_to_revno(revid)
410
 
        except errors.NoSuchRevision:
411
 
            # FIXME: Check using graph.find_distance_to_null() ?
412
 
            return self.target_branch.revision_id_to_revno(revid)
 
501
        return _quick_lookup_revno(self.source_branch, self.target_branch, revid)
413
502
 
414
503
    @property
415
504
    def old_revno(self):
417
506
 
418
507
    @property
419
508
    def new_revno(self):
 
509
        new_original_revno = getattr(self, "new_original_revno", None)
 
510
        if new_original_revno:
 
511
            return new_original_revno
 
512
        if getattr(self, "new_original_revid", None) is not None:
 
513
            return self._lookup_revno(self.new_original_revid)
420
514
        return self._lookup_revno(self.new_revid)
421
515
 
422
516
 
444
538
 
445
539
        Compared to the `update_revisions()` below, this function takes a
446
540
        `limit` argument that limits how many git commits will be converted
447
 
        and returns the new git head.
 
541
        and returns the new git head and remote refs.
448
542
        """
449
543
        interrepo = self._get_interrepo(self.source, self.target)
450
544
        def determine_wants(heads):
476
570
            prev_last_revid = self.target.last_revision()
477
571
        self.target.generate_revision_history(self._last_revid,
478
572
            prev_last_revid)
479
 
        return head
 
573
        return head, refs
480
574
 
481
575
    def update_revisions(self, stop_revision=None, overwrite=False,
482
576
                         graph=None):
514
608
            graph = self.target.repository.get_graph(self.source.repository)
515
609
            (result.old_revno, result.old_revid) = \
516
610
                self.target.last_revision_info()
517
 
            result.new_git_head = self._update_revisions(
 
611
            result.new_git_head, remote_refs = self._update_revisions(
518
612
                stop_revision, overwrite=overwrite, graph=graph, limit=limit)
519
613
            result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
520
614
                overwrite)
539
633
        result.target_branch = self.target
540
634
        graph = self.target.repository.get_graph(self.source.repository)
541
635
        result.old_revno, result.old_revid = self.target.last_revision_info()
542
 
        result.new_git_head = self._update_revisions(
 
636
        result.new_git_head, remote_refs = self._update_revisions(
543
637
            stop_revision, overwrite=overwrite, graph=graph)
544
638
        result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
545
639
            overwrite)
604
698
        result.old_revid = self.target.last_revision()
605
699
        refs, stop_revision = self.update_refs(stop_revision)
606
700
        self.target.generate_revision_history(stop_revision, result.old_revid)
607
 
        self.update_tags(refs)
 
701
        result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
 
702
            source_refs=refs, overwrite=overwrite)
608
703
        result.new_revid = self.target.last_revision()
609
704
        return result
610
705
 
611
 
    def update_tags(self, refs):
612
 
        for name, v in extract_tags(refs).iteritems():
613
 
            revid = self.target.lookup_foreign_revision_id(v)
614
 
            self.target.tags.set_tag(name, revid)
615
 
 
616
706
    def update_refs(self, stop_revision=None):
617
707
        interrepo = repository.InterRepository.get(self.source.repository,
618
708
            self.target.repository)
634
724
        result.old_revid = self.target.last_revision()
635
725
        refs, stop_revision = self.update_refs(stop_revision)
636
726
        self.target.generate_revision_history(stop_revision, result.old_revid)
637
 
        self.update_tags(refs)
 
727
        result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
 
728
            overwrite=overwrite, source_refs=refs)
638
729
        result.new_revid = self.target.last_revision()
639
730
        return result
640
731
 
661
752
 
662
753
    def _get_new_refs(self, stop_revision=None):
663
754
        if stop_revision is None:
664
 
            stop_revision = self.source.last_revision()
 
755
            (stop_revno, stop_revision) = self.source.last_revision_info()
665
756
        assert type(stop_revision) is str
666
757
        main_ref = self.target.ref or "refs/heads/master"
667
758
        refs = { main_ref: (None, stop_revision) }
668
759
        for name, revid in self.source.tags.get_tag_dict().iteritems():
669
760
            if self.source.repository.has_revision(revid):
670
761
                refs[tag_name_to_ref(name)] = (None, revid)
671
 
        return refs, main_ref
 
762
        return refs, main_ref, (stop_revno, stop_revision)
672
763
 
673
764
    def pull(self, overwrite=False, stop_revision=None, local=False,
674
765
             possible_transports=None):
676
767
        result = GitBranchPullResult()
677
768
        result.source_branch = self.source
678
769
        result.target_branch = self.target
679
 
        new_refs, main_ref = self._get_new_refs(stop_revision)
 
770
        new_refs, main_ref, stop_revinfo = self._get_new_refs(stop_revision)
680
771
        def update_refs(old_refs):
681
772
            refs = dict(old_refs)
682
773
            # FIXME: Check for diverged branches
683
774
            refs.update(new_refs)
684
775
            return refs
685
776
        old_refs, new_refs = self.interrepo.fetch_refs(update_refs)
686
 
        result.old_revid = self.target.lookup_foreign_revision_id(
687
 
            old_refs.get(main_ref, ZERO_SHA))
688
 
        result.new_revid = new_refs[main_ref]
 
777
        (result.old_revid, old_sha1) = old_refs.get(main_ref, (ZERO_SHA, NULL_REVISION))
 
778
        if result.old_revid is None:
 
779
            result.old_revid = self.target.lookup_foreign_revision_id(old_sha1)
 
780
        result.new_revid = new_refs[main_ref][1]
689
781
        return result
690
782
 
691
783
    def push(self, overwrite=False, stop_revision=None,
694
786
        result = GitBranchPushResult()
695
787
        result.source_branch = self.source
696
788
        result.target_branch = self.target
697
 
        new_refs, main_ref = self._get_new_refs(stop_revision)
 
789
        new_refs, main_ref, stop_revinfo = self._get_new_refs(stop_revision)
698
790
        def update_refs(old_refs):
699
791
            refs = dict(old_refs)
700
792
            # FIXME: Check for diverged branches
704
796
        (result.old_revid, old_sha1) = old_refs.get(main_ref, (ZERO_SHA, NULL_REVISION))
705
797
        if result.old_revid is None:
706
798
            result.old_revid = self.target.lookup_foreign_revision_id(old_sha1)
707
 
        result.new_revid = new_refs[main_ref]
 
799
        result.new_revid = new_refs[main_ref][1]
708
800
        return result
709
801
 
710
802
    def lossy_push(self, stop_revision=None):
711
803
        result = GitBranchPushResult()
712
804
        result.source_branch = self.source
713
805
        result.target_branch = self.target
714
 
        new_refs, main_ref = self._get_new_refs(stop_revision)
 
806
        new_refs, main_ref, stop_revinfo = self._get_new_refs(stop_revision)
715
807
        def update_refs(old_refs):
716
808
            refs = dict(old_refs)
717
809
            # FIXME: Check for diverged branches
721
813
            update_refs)
722
814
        result.old_revid = old_refs.get(self.target.ref, (None, NULL_REVISION))[1]
723
815
        result.new_revid = new_refs[main_ref][1]
 
816
        (result.new_original_revno, result.new_original_revid) = stop_revinfo
724
817
        return result
725
818
 
726
819