/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 breezy/git/branch.py

  • Committer: Breezy landing bot
  • Author(s): Jelmer Vernooij
  • Date: 2020-02-21 04:40:09 UTC
  • mfrom: (7494.1.1 trunk-3.1)
  • Revision ID: breezy.the.bot@gmail.com-20200221044009-cijpllwtz5ql9tar
Merge lp:brz/3.1.

Merged from https://code.launchpad.net/~jelmer/brz/trunk-3.1/+merge/379600

Show diffs side-by-side

added added

removed removed

Lines of Context:
41
41
    lock,
42
42
    repository as _mod_repository,
43
43
    revision,
44
 
    tag,
45
44
    trace,
46
45
    transport,
47
46
    urlutils,
50
49
from ..revision import (
51
50
    NULL_REVISION,
52
51
    )
 
52
from ..tag import (
 
53
    Tags,
 
54
    InterTags,
 
55
    )
53
56
from ..trace import (
54
57
    is_quiet,
55
58
    mutter,
111
114
        return self._lookup_revno(self.new_revid)
112
115
 
113
116
 
114
 
class GitTags(tag.BasicTags):
115
 
    """Ref-based tag dictionary."""
116
 
 
117
 
    def __init__(self, branch):
118
 
        self.branch = branch
119
 
        self.repository = branch.repository
120
 
 
121
 
    def _merge_to_remote_git(self, target_repo, source_tag_refs,
122
 
                             overwrite=False):
 
117
class InterTagsFromGitToRemoteGit(InterTags):
 
118
 
 
119
    @classmethod
 
120
    def is_compatible(klass, source, target):
 
121
        if not isinstance(source, GitTags):
 
122
            return False
 
123
        if not isinstance(target, GitTags):
 
124
            return False
 
125
        if getattr(target.branch.repository, "_git", None) is not None:
 
126
            return False
 
127
        return True
 
128
 
 
129
    def merge(self, overwrite=False, ignore_master=False, selector=None):
 
130
        if self.source.branch.repository.has_same_location(self.target.branch.repository):
 
131
            return {}, []
123
132
        updates = {}
124
133
        conflicts = []
 
134
        source_tag_refs = self.source.branch.get_tag_refs()
125
135
 
126
136
        def get_changed_refs(old_refs):
127
137
            ret = dict(old_refs)
128
138
            for ref_name, tag_name, peeled, unpeeled in (
129
139
                    source_tag_refs.iteritems()):
 
140
                if selector and not selector(tag_name):
 
141
                    continue
130
142
                if old_refs.get(ref_name) == unpeeled:
131
143
                    pass
132
144
                elif overwrite or ref_name not in old_refs:
133
145
                    ret[ref_name] = unpeeled
134
 
                    updates[tag_name] = target_repo.lookup_foreign_revision_id(
 
146
                    updates[tag_name] = self.target.branch.repository.lookup_foreign_revision_id(
135
147
                        peeled)
 
148
                    self.target.branch._tag_refs = None
136
149
                else:
137
150
                    conflicts.append(
138
151
                        (tag_name,
139
152
                         self.repository.lookup_foreign_revision_id(peeled),
140
 
                         target_repo.lookup_foreign_revision_id(
 
153
                         self.target.branch.repository.lookup_foreign_revision_id(
141
154
                             old_refs[ref_name])))
142
155
            return ret
143
 
        target_repo.controldir.send_pack(
 
156
        self.target.branch.repository.controldir.send_pack(
144
157
            get_changed_refs, lambda have, want: [])
145
 
        return updates, conflicts
146
 
 
147
 
    def _merge_to_local_git(self, target_repo, source_tag_refs,
148
 
                            overwrite=False):
 
158
        return updates, set(conflicts)
 
159
 
 
160
 
 
161
class InterTagsFromGitToLocalGit(InterTags):
 
162
 
 
163
    @classmethod
 
164
    def is_compatible(klass, source, target):
 
165
        if not isinstance(source, GitTags):
 
166
            return False
 
167
        if not isinstance(target, GitTags):
 
168
            return False
 
169
        if getattr(target.branch.repository, "_git", None) is None:
 
170
            return False
 
171
        return True
 
172
 
 
173
    def merge(self, overwrite=False, ignore_master=False, selector=None):
 
174
        if self.source.branch.repository.has_same_location(self.target.branch.repository):
 
175
            return {}, []
 
176
 
149
177
        conflicts = []
150
178
        updates = {}
 
179
        source_tag_refs = self.source.branch.get_tag_refs()
 
180
 
 
181
        target_repo = self.target.branch.repository
 
182
 
151
183
        for ref_name, tag_name, peeled, unpeeled in source_tag_refs:
 
184
            if selector and not selector(tag_name):
 
185
                continue
152
186
            if target_repo._git.refs.get(ref_name) == unpeeled:
153
187
                pass
154
188
            elif overwrite or ref_name not in target_repo._git.refs:
164
198
                                  tag_name)
165
199
                    continue
166
200
                target_repo._git.refs[ref_name] = unpeeled or peeled
 
201
                self.target.branch._tag_refs = None
167
202
            else:
168
203
                try:
169
 
                    source_revid = self.repository.lookup_foreign_revision_id(
 
204
                    source_revid = self.source.branch.repository.lookup_foreign_revision_id(
170
205
                        peeled)
171
206
                    target_revid = target_repo.lookup_foreign_revision_id(
172
207
                        target_repo._git.refs[ref_name])
179
214
                                  tag_name)
180
215
                    continue
181
216
                conflicts.append((tag_name, source_revid, target_revid))
182
 
        return updates, conflicts
183
 
 
184
 
    def _merge_to_git(self, to_tags, source_tag_refs, overwrite=False):
185
 
        target_repo = to_tags.repository
186
 
        if self.repository.has_same_location(target_repo):
187
 
            return {}, []
188
 
        try:
189
 
            if getattr(target_repo, "_git", None):
190
 
                return self._merge_to_local_git(
191
 
                    target_repo, source_tag_refs, overwrite)
192
 
            else:
193
 
                return self._merge_to_remote_git(
194
 
                    target_repo, source_tag_refs, overwrite)
195
 
        finally:
196
 
            to_tags.branch._tag_refs = None
197
 
 
198
 
    def _merge_to_non_git(self, to_tags, source_tag_refs, overwrite=False):
 
217
        return updates, set(conflicts)
 
218
 
 
219
 
 
220
class InterTagsFromGitToNonGit(InterTags):
 
221
 
 
222
    @classmethod
 
223
    def is_compatible(klass, source, target):
 
224
        if not isinstance(source, GitTags):
 
225
            return False
 
226
        if isinstance(target, GitTags):
 
227
            return False
 
228
        return True
 
229
 
 
230
    def merge(self, overwrite=False, ignore_master=False, selector=None):
 
231
        """See Tags.merge_to."""
 
232
        source_tag_refs = self.source.branch.get_tag_refs()
 
233
        if ignore_master:
 
234
            master = None
 
235
        else:
 
236
            master = self.target.branch.get_master_branch()
 
237
        with contextlib.ExitStack() as es:
 
238
            if master is not None:
 
239
                es.enter_context(master.lock_write())
 
240
            updates, conflicts = self._merge_to(
 
241
                self.target, source_tag_refs, overwrite=overwrite,
 
242
                selector=selector)
 
243
            if master is not None:
 
244
                extra_updates, extra_conflicts = self._merge_to(
 
245
                    master.tags, overwrite=overwrite,
 
246
                    source_tag_refs=source_tag_refs,
 
247
                    ignore_master=ignore_master, selector=selector)
 
248
                updates.update(extra_updates)
 
249
                conflicts.update(extra_conflicts)
 
250
            return updates, conflicts
 
251
 
 
252
    def _merge_to(self, to_tags, source_tag_refs, overwrite=False,
 
253
                  selector=None):
199
254
        unpeeled_map = defaultdict(set)
200
255
        conflicts = []
201
256
        updates = {}
202
257
        result = dict(to_tags.get_tag_dict())
203
258
        for ref_name, tag_name, peeled, unpeeled in source_tag_refs:
 
259
            if selector and not selector(tag_name):
 
260
                continue
204
261
            if unpeeled is not None:
205
262
                unpeeled_map[peeled].add(unpeeled)
206
263
            try:
207
 
                bzr_revid = self.branch.lookup_foreign_revision_id(peeled)
 
264
                bzr_revid = self.source.branch.lookup_foreign_revision_id(peeled)
208
265
            except NotCommitError:
209
266
                continue
210
267
            if result.get(tag_name) == bzr_revid:
219
276
            map_file = UnpeelMap.from_repository(to_tags.branch.repository)
220
277
            map_file.update(unpeeled_map)
221
278
            map_file.save_in_repository(to_tags.branch.repository)
222
 
        return updates, conflicts
223
 
 
224
 
    def merge_to(self, to_tags, overwrite=False, ignore_master=False,
225
 
                 source_tag_refs=None):
226
 
        """See Tags.merge_to."""
227
 
        if source_tag_refs is None:
228
 
            source_tag_refs = self.branch.get_tag_refs()
229
 
        if self == to_tags:
230
 
            return {}, []
231
 
        if isinstance(to_tags, GitTags):
232
 
            return self._merge_to_git(to_tags, source_tag_refs,
233
 
                                      overwrite=overwrite)
234
 
        else:
235
 
            if ignore_master:
236
 
                master = None
237
 
            else:
238
 
                master = to_tags.branch.get_master_branch()
239
 
            with contextlib.ExitStack() as es:
240
 
                if master is not None:
241
 
                    es.enter_context(master.lock_write())
242
 
                updates, conflicts = self._merge_to_non_git(
243
 
                    to_tags, source_tag_refs, overwrite=overwrite)
244
 
                if master is not None:
245
 
                    extra_updates, extra_conflicts = self.merge_to(
246
 
                        master.tags, overwrite=overwrite,
247
 
                        source_tag_refs=source_tag_refs,
248
 
                        ignore_master=ignore_master)
249
 
                    updates.update(extra_updates)
250
 
                    conflicts += extra_conflicts
251
 
                return updates, conflicts
 
279
        return updates, set(conflicts)
 
280
 
 
281
 
 
282
InterTags.register_optimiser(InterTagsFromGitToRemoteGit)
 
283
InterTags.register_optimiser(InterTagsFromGitToLocalGit)
 
284
InterTags.register_optimiser(InterTagsFromGitToNonGit)
 
285
 
 
286
 
 
287
class GitTags(Tags):
 
288
    """Ref-based tag dictionary."""
 
289
 
 
290
    def __init__(self, branch):
 
291
        self.branch = branch
 
292
        self.repository = branch.repository
252
293
 
253
294
    def get_tag_dict(self):
254
295
        ret = {}
262
303
                ret[tag_name] = bzr_revid
263
304
        return ret
264
305
 
 
306
    def lookup_tag(self, tag_name):
 
307
        """Return the referent string of a tag"""
 
308
        # TODO(jelmer): Replace with something more efficient for local tags.
 
309
        td = self.get_tag_dict()
 
310
        try:
 
311
            return td[tag_name]
 
312
        except KeyError:
 
313
            raise errors.NoSuchTag(tag_name)
 
314
 
265
315
 
266
316
class LocalGitTagDict(GitTags):
267
317
    """Dictionary with tags in a local repository."""
612
662
                return revision.NULL_REVISION
613
663
            return self.lookup_foreign_revision_id(self.head)
614
664
 
615
 
    def _basic_push(self, target, overwrite=False, stop_revision=None):
 
665
    def _basic_push(self, target, overwrite=False, stop_revision=None,
 
666
                    tag_selector=None):
616
667
        return branch.InterBranch.get(self, target)._basic_push(
617
 
            overwrite, stop_revision)
 
668
            overwrite, stop_revision, tag_selector=tag_selector)
618
669
 
619
670
    def lookup_foreign_revision_id(self, foreign_revid):
620
671
        try:
934
985
            stop_revision, fetch_tags=fetch_tags, limit=limit, lossy=lossy)
935
986
        return _mod_repository.FetchResult()
936
987
 
937
 
    def fetch_objects(self, stop_revision, fetch_tags, limit=None, lossy=False):
 
988
    def fetch_objects(self, stop_revision, fetch_tags, limit=None, lossy=False, tag_selector=None):
938
989
        interrepo = self._get_interrepo(self.source, self.target)
939
990
        if fetch_tags is None:
940
991
            c = self.source.get_config_stack()
952
1003
            else:
953
1004
                self._last_revid = stop_revision
954
1005
            real = interrepo.get_determine_wants_revids(
955
 
                [self._last_revid], include_tags=fetch_tags)
 
1006
                [self._last_revid], include_tags=fetch_tags, tag_selector=tag_selector)
956
1007
            return real(heads)
957
1008
        pack_hint, head, refs = interrepo.fetch_objects(
958
1009
            determine_wants, self.source.mapping, limit=limit,
962
1013
            self.target.repository.pack(hint=pack_hint)
963
1014
        return head, refs
964
1015
 
965
 
    def _update_revisions(self, stop_revision=None, overwrite=False):
966
 
        head, refs = self.fetch_objects(stop_revision, fetch_tags=None)
 
1016
    def _update_revisions(self, stop_revision=None, overwrite=False, tag_selector=None):
 
1017
        head, refs = self.fetch_objects(stop_revision, fetch_tags=None, tag_selector=tag_selector)
967
1018
        if overwrite:
968
1019
            prev_last_revid = None
969
1020
        else:
988
1039
            pass
989
1040
 
990
1041
    def _basic_pull(self, stop_revision, overwrite, run_hooks,
991
 
                    _override_hook_target, _hook_master):
 
1042
                    _override_hook_target, _hook_master, tag_selector=None):
992
1043
        if overwrite is True:
993
1044
            overwrite = set(["history", "tags"])
994
1045
        elif not overwrite:
1005
1056
            (result.old_revno, result.old_revid) = \
1006
1057
                self.target.last_revision_info()
1007
1058
            result.new_git_head, remote_refs = self._update_revisions(
1008
 
                stop_revision, overwrite=("history" in overwrite))
 
1059
                stop_revision, overwrite=("history" in overwrite),
 
1060
                tag_selector=tag_selector)
1009
1061
            tags_ret = self.source.tags.merge_to(
1010
1062
                self.target.tags, ("tags" in overwrite), ignore_master=True)
1011
1063
            if isinstance(tags_ret, tuple):
1028
1080
 
1029
1081
    def pull(self, overwrite=False, stop_revision=None,
1030
1082
             possible_transports=None, _hook_master=None, run_hooks=True,
1031
 
             _override_hook_target=None, local=False):
 
1083
             _override_hook_target=None, local=False, tag_selector=None):
1032
1084
        """See Branch.pull.
1033
1085
 
1034
1086
        :param _hook_master: Private parameter - set the branch to
1066
1118
                master_branch = None
1067
1119
            return self._basic_pull(stop_revision, overwrite, run_hooks,
1068
1120
                                    _override_hook_target,
1069
 
                                    _hook_master=master_branch)
 
1121
                                    _hook_master=master_branch,
 
1122
                                    tag_selector=tag_selector)
1070
1123
 
1071
 
    def _basic_push(self, overwrite, stop_revision):
 
1124
    def _basic_push(self, overwrite, stop_revision, tag_selector=None):
1072
1125
        if overwrite is True:
1073
1126
            overwrite = set(["history", "tags"])
1074
1127
        elif not overwrite:
1078
1131
        result.target_branch = self.target
1079
1132
        result.old_revno, result.old_revid = self.target.last_revision_info()
1080
1133
        result.new_git_head, remote_refs = self._update_revisions(
1081
 
            stop_revision, overwrite=("history" in overwrite))
 
1134
            stop_revision, overwrite=("history" in overwrite),
 
1135
            tag_selector=tag_selector)
1082
1136
        tags_ret = self.source.tags.merge_to(
1083
 
            self.target.tags, "tags" in overwrite, ignore_master=True)
 
1137
            self.target.tags, "tags" in overwrite, ignore_master=True,
 
1138
            selector=tag_selector)
1084
1139
        (result.tag_updates, result.tag_conflicts) = tags_ret
1085
1140
        result.new_revno, result.new_revid = self.target.last_revision_info()
1086
1141
        self.update_references(revid=result.new_revid)
1109
1164
        return (isinstance(source, LocalGitBranch) and
1110
1165
                isinstance(target, RemoteGitBranch))
1111
1166
 
1112
 
    def _basic_push(self, overwrite, stop_revision):
 
1167
    def _basic_push(self, overwrite, stop_revision, tag_selector=None):
1113
1168
        result = GitBranchPushResult()
1114
1169
        result.source_branch = self.source
1115
1170
        result.target_branch = self.target
1134
1189
            result.new_revid = stop_revision
1135
1190
            for name, sha in (
1136
1191
                    self.source.repository._git.refs.as_dict(b"refs/tags").items()):
 
1192
                if tag_selector and not tag_selector(name):
 
1193
                    continue
1137
1194
                if sha not in self.source.repository._git:
1138
1195
                    trace.mutter('Ignoring missing SHA: %s', sha)
1139
1196
                    continue
1173
1230
        interrepo.fetch_objects(determine_wants, limit=limit, lossy=lossy)
1174
1231
        return _mod_repository.FetchResult()
1175
1232
 
1176
 
    def _basic_push(self, overwrite=False, stop_revision=None):
 
1233
    def _basic_push(self, overwrite=False, stop_revision=None, tag_selector=None):
1177
1234
        if overwrite is True:
1178
1235
            overwrite = set(["history", "tags"])
1179
1236
        elif not overwrite:
1189
1246
            other_branch=self.source)
1190
1247
        tags_ret = self.source.tags.merge_to(
1191
1248
            self.target.tags,
1192
 
            source_tag_refs=remote_refs_dict_to_tag_refs(refs),
1193
 
            overwrite=("tags" in overwrite))
 
1249
            overwrite=("tags" in overwrite),
 
1250
            selector=tag_selector)
1194
1251
        if isinstance(tags_ret, tuple):
1195
1252
            (result.tag_updates, result.tag_conflicts) = tags_ret
1196
1253
        else:
1218
1275
        return result.refs, stop_revision
1219
1276
 
1220
1277
    def pull(self, stop_revision=None, overwrite=False,
1221
 
             possible_transports=None, run_hooks=True, local=False):
 
1278
             possible_transports=None, run_hooks=True, local=False,
 
1279
             tag_selector=None):
1222
1280
        # This type of branch can't be bound.
1223
1281
        if local:
1224
1282
            raise errors.LocalRequiresBoundBranch()
1239
1297
                other_branch=self.source)
1240
1298
            tags_ret = self.source.tags.merge_to(
1241
1299
                self.target.tags, overwrite=("tags" in overwrite),
1242
 
                source_tag_refs=remote_refs_dict_to_tag_refs(refs))
 
1300
                selector=tag_selector)
1243
1301
            if isinstance(tags_ret, tuple):
1244
1302
                (result.tag_updates, result.tag_conflicts) = tags_ret
1245
1303
            else:
1307
1365
                    refs[ref] = (None, revid)
1308
1366
        return refs, main_ref, (stop_revno, stop_revision)
1309
1367
 
1310
 
    def _update_refs(self, result, old_refs, new_refs, overwrite):
 
1368
    def _update_refs(self, result, old_refs, new_refs, overwrite, tag_selector):
1311
1369
        mutter("updating refs. old refs: %r, new refs: %r",
1312
1370
               old_refs, new_refs)
1313
1371
        result.tag_updates = {}
1346
1404
                except ValueError:
1347
1405
                    pass
1348
1406
                else:
 
1407
                    if tag_selector and not tag_selector(tag_name):
 
1408
                        continue
1349
1409
                    result.tag_updates[tag_name] = revid
1350
1410
                ret[ref] = (git_sha, revid)
1351
1411
            else:
1381
1441
            for (old_revid, (new_sha, new_revid)) in revidmap.items()})
1382
1442
 
1383
1443
    def pull(self, overwrite=False, stop_revision=None, local=False,
1384
 
             possible_transports=None, run_hooks=True, _stop_revno=None):
 
1444
             possible_transports=None, run_hooks=True, _stop_revno=None,
 
1445
             tag_selector=None):
1385
1446
        result = GitBranchPullResult()
1386
1447
        result.source_branch = self.source
1387
1448
        result.target_branch = self.target
1390
1451
                stop_revision, stop_revno=_stop_revno)
1391
1452
 
1392
1453
            def update_refs(old_refs):
1393
 
                return self._update_refs(result, old_refs, new_refs, overwrite)
 
1454
                return self._update_refs(result, old_refs, new_refs, overwrite, tag_selector)
1394
1455
            try:
1395
1456
                result.revidmap, old_refs, new_refs = (
1396
1457
                    self.interrepo.fetch_refs(update_refs, lossy=False))
1410
1471
        return result
1411
1472
 
1412
1473
    def push(self, overwrite=False, stop_revision=None, lossy=False,
1413
 
             _override_hook_source_branch=None, _stop_revno=None):
 
1474
             _override_hook_source_branch=None, _stop_revno=None,
 
1475
             tag_selector=None):
1414
1476
        result = GitBranchPushResult()
1415
1477
        result.source_branch = self.source
1416
1478
        result.target_branch = self.target
1421
1483
                stop_revision, stop_revno=_stop_revno)
1422
1484
 
1423
1485
            def update_refs(old_refs):
1424
 
                return self._update_refs(result, old_refs, new_refs, overwrite)
 
1486
                return self._update_refs(result, old_refs, new_refs, overwrite, tag_selector)
1425
1487
            try:
1426
1488
                result.revidmap, old_refs, new_refs = (
1427
1489
                    self.interrepo.fetch_refs(