/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: Jelmer Vernooij
  • Date: 2020-02-18 01:57:45 UTC
  • mto: This revision was merged to the branch mainline in revision 7493.
  • Revision ID: jelmer@jelmer.uk-20200218015745-q2ss9tsk74h4nh61
drop use of future.

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,
44
45
    trace,
45
46
    transport,
46
47
    urlutils,
49
50
from ..revision import (
50
51
    NULL_REVISION,
51
52
    )
52
 
from ..tag import (
53
 
    Tags,
54
 
    InterTags,
55
 
    )
56
53
from ..trace import (
57
54
    is_quiet,
58
55
    mutter,
59
56
    warning,
60
57
    )
61
58
 
 
59
from .config import (
 
60
    GitBranchConfig,
 
61
    GitBranchStack,
 
62
    )
62
63
from .errors import (
63
64
    NoPushSupport,
64
65
    )
65
 
from .mapping import (
66
 
    encode_git_path,
67
 
    decode_git_path,
68
 
    )
69
66
from .push import (
70
67
    remote_divergence,
71
68
    )
114
111
        return self._lookup_revno(self.new_revid)
115
112
 
116
113
 
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 {}, []
 
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):
132
123
        updates = {}
133
124
        conflicts = []
134
 
        source_tag_refs = self.source.branch.get_tag_refs()
135
 
        ref_to_tag_map = {}
136
125
 
137
126
        def get_changed_refs(old_refs):
138
127
            ret = dict(old_refs)
139
128
            for ref_name, tag_name, peeled, unpeeled in (
140
129
                    source_tag_refs.iteritems()):
141
 
                if selector and not selector(tag_name):
142
 
                    continue
143
130
                if old_refs.get(ref_name) == unpeeled:
144
131
                    pass
145
132
                elif overwrite or ref_name not in old_refs:
146
133
                    ret[ref_name] = unpeeled
147
 
                    updates[tag_name] = self.target.branch.repository.lookup_foreign_revision_id(
 
134
                    updates[tag_name] = target_repo.lookup_foreign_revision_id(
148
135
                        peeled)
149
 
                    ref_to_tag_map[ref_name] = tag_name
150
 
                    self.target.branch._tag_refs = None
151
136
                else:
152
137
                    conflicts.append(
153
138
                        (tag_name,
154
139
                         self.repository.lookup_foreign_revision_id(peeled),
155
 
                         self.target.branch.repository.lookup_foreign_revision_id(
 
140
                         target_repo.lookup_foreign_revision_id(
156
141
                             old_refs[ref_name])))
157
142
            return ret
158
 
        result = self.target.branch.repository.controldir.send_pack(
 
143
        target_repo.controldir.send_pack(
159
144
            get_changed_refs, lambda have, want: [])
160
 
        if result is not None and not isinstance(result, dict):
161
 
            for ref, error in result.ref_status.items():
162
 
                if error:
163
 
                    warning('unable to update ref %s: %s',
164
 
                            ref, error)
165
 
                    del updates[ref_to_tag_map[ref]]
166
 
        return updates, set(conflicts)
167
 
 
168
 
 
169
 
class InterTagsFromGitToLocalGit(InterTags):
170
 
 
171
 
    @classmethod
172
 
    def is_compatible(klass, source, target):
173
 
        if not isinstance(source, GitTags):
174
 
            return False
175
 
        if not isinstance(target, GitTags):
176
 
            return False
177
 
        if getattr(target.branch.repository, "_git", None) is None:
178
 
            return False
179
 
        return True
180
 
 
181
 
    def merge(self, overwrite=False, ignore_master=False, selector=None):
182
 
        if self.source.branch.repository.has_same_location(self.target.branch.repository):
183
 
            return {}, []
184
 
 
 
145
        return updates, conflicts
 
146
 
 
147
    def _merge_to_local_git(self, target_repo, source_tag_refs,
 
148
                            overwrite=False):
185
149
        conflicts = []
186
150
        updates = {}
187
 
        source_tag_refs = self.source.branch.get_tag_refs()
188
 
 
189
 
        target_repo = self.target.branch.repository
190
 
 
191
151
        for ref_name, tag_name, peeled, unpeeled in source_tag_refs:
192
 
            if selector and not selector(tag_name):
193
 
                continue
194
152
            if target_repo._git.refs.get(ref_name) == unpeeled:
195
153
                pass
196
154
            elif overwrite or ref_name not in target_repo._git.refs:
206
164
                                  tag_name)
207
165
                    continue
208
166
                target_repo._git.refs[ref_name] = unpeeled or peeled
209
 
                self.target.branch._tag_refs = None
210
167
            else:
211
168
                try:
212
 
                    source_revid = self.source.branch.repository.lookup_foreign_revision_id(
 
169
                    source_revid = self.repository.lookup_foreign_revision_id(
213
170
                        peeled)
214
171
                    target_revid = target_repo.lookup_foreign_revision_id(
215
172
                        target_repo._git.refs[ref_name])
222
179
                                  tag_name)
223
180
                    continue
224
181
                conflicts.append((tag_name, source_revid, target_revid))
225
 
        return updates, set(conflicts)
226
 
 
227
 
 
228
 
class InterTagsFromGitToNonGit(InterTags):
229
 
 
230
 
    @classmethod
231
 
    def is_compatible(klass, source, target):
232
 
        if not isinstance(source, GitTags):
233
 
            return False
234
 
        if isinstance(target, GitTags):
235
 
            return False
236
 
        return True
237
 
 
238
 
    def merge(self, overwrite=False, ignore_master=False, selector=None):
239
 
        """See Tags.merge_to."""
240
 
        source_tag_refs = self.source.branch.get_tag_refs()
241
 
        if ignore_master:
242
 
            master = None
243
 
        else:
244
 
            master = self.target.branch.get_master_branch()
245
 
        with contextlib.ExitStack() as es:
246
 
            if master is not None:
247
 
                es.enter_context(master.lock_write())
248
 
            updates, conflicts = self._merge_to(
249
 
                self.target, source_tag_refs, overwrite=overwrite,
250
 
                selector=selector)
251
 
            if master is not None:
252
 
                extra_updates, extra_conflicts = self._merge_to(
253
 
                    master.tags, overwrite=overwrite,
254
 
                    source_tag_refs=source_tag_refs,
255
 
                    ignore_master=ignore_master, selector=selector)
256
 
                updates.update(extra_updates)
257
 
                conflicts.update(extra_conflicts)
258
 
            return updates, conflicts
259
 
 
260
 
    def _merge_to(self, to_tags, source_tag_refs, overwrite=False,
261
 
                  selector=None):
 
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):
262
199
        unpeeled_map = defaultdict(set)
263
200
        conflicts = []
264
201
        updates = {}
265
202
        result = dict(to_tags.get_tag_dict())
266
203
        for ref_name, tag_name, peeled, unpeeled in source_tag_refs:
267
 
            if selector and not selector(tag_name):
268
 
                continue
269
204
            if unpeeled is not None:
270
205
                unpeeled_map[peeled].add(unpeeled)
271
206
            try:
272
 
                bzr_revid = self.source.branch.lookup_foreign_revision_id(peeled)
 
207
                bzr_revid = self.branch.lookup_foreign_revision_id(peeled)
273
208
            except NotCommitError:
274
209
                continue
275
210
            if result.get(tag_name) == bzr_revid:
284
219
            map_file = UnpeelMap.from_repository(to_tags.branch.repository)
285
220
            map_file.update(unpeeled_map)
286
221
            map_file.save_in_repository(to_tags.branch.repository)
287
 
        return updates, set(conflicts)
288
 
 
289
 
 
290
 
InterTags.register_optimiser(InterTagsFromGitToRemoteGit)
291
 
InterTags.register_optimiser(InterTagsFromGitToLocalGit)
292
 
InterTags.register_optimiser(InterTagsFromGitToNonGit)
293
 
 
294
 
 
295
 
class GitTags(Tags):
296
 
    """Ref-based tag dictionary."""
297
 
 
298
 
    def __init__(self, branch):
299
 
        self.branch = branch
300
 
        self.repository = 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
301
252
 
302
253
    def get_tag_dict(self):
303
254
        ret = {}
311
262
                ret[tag_name] = bzr_revid
312
263
        return ret
313
264
 
314
 
    def lookup_tag(self, tag_name):
315
 
        """Return the referent string of a tag"""
316
 
        # TODO(jelmer): Replace with something more efficient for local tags.
317
 
        td = self.get_tag_dict()
318
 
        try:
319
 
            return td[tag_name]
320
 
        except KeyError:
321
 
            raise errors.NoSuchTag(tag_name)
322
 
 
323
265
 
324
266
class LocalGitTagDict(GitTags):
325
267
    """Dictionary with tags in a local repository."""
482
424
        return "git"
483
425
 
484
426
    def get_config(self):
485
 
        from .config import GitBranchConfig
486
427
        return GitBranchConfig(self)
487
428
 
488
429
    def get_config_stack(self):
489
 
        from .config import GitBranchStack
490
430
        return GitBranchStack(self)
491
431
 
492
432
    def _get_nick(self, local=False, possible_master_transports=None):
498
438
            cs = self.repository._git.get_config_stack()
499
439
            try:
500
440
                return cs.get((b"branch", self.name.encode('utf-8')),
501
 
                        b"nick").decode("utf-8")
 
441
                              b"nick").decode("utf-8")
502
442
            except KeyError:
503
443
                pass
504
444
        return self.name or u"HEAD"
672
612
                return revision.NULL_REVISION
673
613
            return self.lookup_foreign_revision_id(self.head)
674
614
 
675
 
    def _basic_push(self, target, overwrite=False, stop_revision=None,
676
 
                    tag_selector=None):
 
615
    def _basic_push(self, target, overwrite=False, stop_revision=None):
677
616
        return branch.InterBranch.get(self, target)._basic_push(
678
 
            overwrite, stop_revision, tag_selector=tag_selector)
 
617
            overwrite, stop_revision)
679
618
 
680
619
    def lookup_foreign_revision_id(self, foreign_revid):
681
620
        try:
995
934
            stop_revision, fetch_tags=fetch_tags, limit=limit, lossy=lossy)
996
935
        return _mod_repository.FetchResult()
997
936
 
998
 
    def fetch_objects(self, stop_revision, fetch_tags, limit=None, lossy=False, tag_selector=None):
 
937
    def fetch_objects(self, stop_revision, fetch_tags, limit=None, lossy=False):
999
938
        interrepo = self._get_interrepo(self.source, self.target)
1000
939
        if fetch_tags is None:
1001
940
            c = self.source.get_config_stack()
1013
952
            else:
1014
953
                self._last_revid = stop_revision
1015
954
            real = interrepo.get_determine_wants_revids(
1016
 
                [self._last_revid], include_tags=fetch_tags, tag_selector=tag_selector)
 
955
                [self._last_revid], include_tags=fetch_tags)
1017
956
            return real(heads)
1018
957
        pack_hint, head, refs = interrepo.fetch_objects(
1019
958
            determine_wants, self.source.mapping, limit=limit,
1023
962
            self.target.repository.pack(hint=pack_hint)
1024
963
        return head, refs
1025
964
 
1026
 
    def _update_revisions(self, stop_revision=None, overwrite=False, tag_selector=None):
1027
 
        head, refs = self.fetch_objects(stop_revision, fetch_tags=None, tag_selector=tag_selector)
 
965
    def _update_revisions(self, stop_revision=None, overwrite=False):
 
966
        head, refs = self.fetch_objects(stop_revision, fetch_tags=None)
1028
967
        if overwrite:
1029
968
            prev_last_revid = None
1030
969
        else:
1043
982
                for path, url, section in parse_submodules(
1044
983
                        GitConfigFile.from_file(f)):
1045
984
                    self.target.set_reference_info(
1046
 
                        tree.path2id(decode_git_path(path)), url.decode('utf-8'),
1047
 
                        decode_git_path(path))
 
985
                        tree.path2id(path.decode('utf-8')), url.decode('utf-8'),
 
986
                        path.decode('utf-8'))
1048
987
        except errors.NoSuchFile:
1049
988
            pass
1050
989
 
1051
990
    def _basic_pull(self, stop_revision, overwrite, run_hooks,
1052
 
                    _override_hook_target, _hook_master, tag_selector=None):
 
991
                    _override_hook_target, _hook_master):
1053
992
        if overwrite is True:
1054
993
            overwrite = set(["history", "tags"])
1055
994
        elif not overwrite:
1066
1005
            (result.old_revno, result.old_revid) = \
1067
1006
                self.target.last_revision_info()
1068
1007
            result.new_git_head, remote_refs = self._update_revisions(
1069
 
                stop_revision, overwrite=("history" in overwrite),
1070
 
                tag_selector=tag_selector)
 
1008
                stop_revision, overwrite=("history" in overwrite))
1071
1009
            tags_ret = self.source.tags.merge_to(
1072
1010
                self.target.tags, ("tags" in overwrite), ignore_master=True)
1073
1011
            if isinstance(tags_ret, tuple):
1090
1028
 
1091
1029
    def pull(self, overwrite=False, stop_revision=None,
1092
1030
             possible_transports=None, _hook_master=None, run_hooks=True,
1093
 
             _override_hook_target=None, local=False, tag_selector=None):
 
1031
             _override_hook_target=None, local=False):
1094
1032
        """See Branch.pull.
1095
1033
 
1096
1034
        :param _hook_master: Private parameter - set the branch to
1128
1066
                master_branch = None
1129
1067
            return self._basic_pull(stop_revision, overwrite, run_hooks,
1130
1068
                                    _override_hook_target,
1131
 
                                    _hook_master=master_branch,
1132
 
                                    tag_selector=tag_selector)
 
1069
                                    _hook_master=master_branch)
1133
1070
 
1134
 
    def _basic_push(self, overwrite, stop_revision, tag_selector=None):
 
1071
    def _basic_push(self, overwrite, stop_revision):
1135
1072
        if overwrite is True:
1136
1073
            overwrite = set(["history", "tags"])
1137
1074
        elif not overwrite:
1141
1078
        result.target_branch = self.target
1142
1079
        result.old_revno, result.old_revid = self.target.last_revision_info()
1143
1080
        result.new_git_head, remote_refs = self._update_revisions(
1144
 
            stop_revision, overwrite=("history" in overwrite),
1145
 
            tag_selector=tag_selector)
 
1081
            stop_revision, overwrite=("history" in overwrite))
1146
1082
        tags_ret = self.source.tags.merge_to(
1147
 
            self.target.tags, "tags" in overwrite, ignore_master=True,
1148
 
            selector=tag_selector)
 
1083
            self.target.tags, "tags" in overwrite, ignore_master=True)
1149
1084
        (result.tag_updates, result.tag_conflicts) = tags_ret
1150
1085
        result.new_revno, result.new_revid = self.target.last_revision_info()
1151
1086
        self.update_references(revid=result.new_revid)
1174
1109
        return (isinstance(source, LocalGitBranch) and
1175
1110
                isinstance(target, RemoteGitBranch))
1176
1111
 
1177
 
    def _basic_push(self, overwrite, stop_revision, tag_selector=None):
1178
 
        from .remote import parse_git_error
 
1112
    def _basic_push(self, overwrite, stop_revision):
1179
1113
        result = GitBranchPushResult()
1180
1114
        result.source_branch = self.source
1181
1115
        result.target_branch = self.target
1200
1134
            result.new_revid = stop_revision
1201
1135
            for name, sha in (
1202
1136
                    self.source.repository._git.refs.as_dict(b"refs/tags").items()):
1203
 
                if tag_selector and not tag_selector(name):
1204
 
                    continue
1205
1137
                if sha not in self.source.repository._git:
1206
1138
                    trace.mutter('Ignoring missing SHA: %s', sha)
1207
1139
                    continue
1208
1140
                refs[tag_name_to_ref(name)] = sha
1209
1141
            return refs
1210
 
        dw_result = self.target.repository.send_pack(
 
1142
        self.target.repository.send_pack(
1211
1143
            get_changed_refs,
1212
 
            self.source.repository._git.generate_pack_data)
1213
 
        if dw_result is not None and not isinstance(dw_result, dict):
1214
 
            error = dw_result.ref_status.get(self.target.ref)
1215
 
            if error:
1216
 
                raise parse_git_error(self.target.user_url, error)
1217
 
            for ref, error in dw_result.ref_status.items():
1218
 
                if error:
1219
 
                    trace.warning('unable to open ref %s: %s', ref, error)
 
1144
            self.source.repository._git.object_store.generate_pack_data)
1220
1145
        return result
1221
1146
 
1222
1147
 
1248
1173
        interrepo.fetch_objects(determine_wants, limit=limit, lossy=lossy)
1249
1174
        return _mod_repository.FetchResult()
1250
1175
 
1251
 
    def _basic_push(self, overwrite=False, stop_revision=None, tag_selector=None):
 
1176
    def _basic_push(self, overwrite=False, stop_revision=None):
1252
1177
        if overwrite is True:
1253
1178
            overwrite = set(["history", "tags"])
1254
1179
        elif not overwrite:
1264
1189
            other_branch=self.source)
1265
1190
        tags_ret = self.source.tags.merge_to(
1266
1191
            self.target.tags,
1267
 
            overwrite=("tags" in overwrite),
1268
 
            selector=tag_selector)
 
1192
            source_tag_refs=remote_refs_dict_to_tag_refs(refs),
 
1193
            overwrite=("tags" in overwrite))
1269
1194
        if isinstance(tags_ret, tuple):
1270
1195
            (result.tag_updates, result.tag_conflicts) = tags_ret
1271
1196
        else:
1293
1218
        return result.refs, stop_revision
1294
1219
 
1295
1220
    def pull(self, stop_revision=None, overwrite=False,
1296
 
             possible_transports=None, run_hooks=True, local=False,
1297
 
             tag_selector=None):
 
1221
             possible_transports=None, run_hooks=True, local=False):
1298
1222
        # This type of branch can't be bound.
1299
1223
        if local:
1300
1224
            raise errors.LocalRequiresBoundBranch()
1315
1239
                other_branch=self.source)
1316
1240
            tags_ret = self.source.tags.merge_to(
1317
1241
                self.target.tags, overwrite=("tags" in overwrite),
1318
 
                selector=tag_selector)
 
1242
                source_tag_refs=remote_refs_dict_to_tag_refs(refs))
1319
1243
            if isinstance(tags_ret, tuple):
1320
1244
                (result.tag_updates, result.tag_conflicts) = tags_ret
1321
1245
            else:
1383
1307
                    refs[ref] = (None, revid)
1384
1308
        return refs, main_ref, (stop_revno, stop_revision)
1385
1309
 
1386
 
    def _update_refs(self, result, old_refs, new_refs, overwrite, tag_selector):
 
1310
    def _update_refs(self, result, old_refs, new_refs, overwrite):
1387
1311
        mutter("updating refs. old refs: %r, new refs: %r",
1388
1312
               old_refs, new_refs)
1389
1313
        result.tag_updates = {}
1390
1314
        result.tag_conflicts = []
1391
 
        ret = {}
 
1315
        ret = dict(old_refs)
1392
1316
 
1393
1317
        def ref_equals(refs, ref, git_sha, revid):
1394
1318
            try:
1422
1346
                except ValueError:
1423
1347
                    pass
1424
1348
                else:
1425
 
                    if tag_selector and not tag_selector(tag_name):
1426
 
                        continue
1427
1349
                    result.tag_updates[tag_name] = revid
1428
1350
                ret[ref] = (git_sha, revid)
1429
1351
            else:
1459
1381
            for (old_revid, (new_sha, new_revid)) in revidmap.items()})
1460
1382
 
1461
1383
    def pull(self, overwrite=False, stop_revision=None, local=False,
1462
 
             possible_transports=None, run_hooks=True, _stop_revno=None,
1463
 
             tag_selector=None):
 
1384
             possible_transports=None, run_hooks=True, _stop_revno=None):
1464
1385
        result = GitBranchPullResult()
1465
1386
        result.source_branch = self.source
1466
1387
        result.target_branch = self.target
1469
1390
                stop_revision, stop_revno=_stop_revno)
1470
1391
 
1471
1392
            def update_refs(old_refs):
1472
 
                return self._update_refs(result, old_refs, new_refs, overwrite, tag_selector)
 
1393
                return self._update_refs(result, old_refs, new_refs, overwrite)
1473
1394
            try:
1474
1395
                result.revidmap, old_refs, new_refs = (
1475
1396
                    self.interrepo.fetch_refs(update_refs, lossy=False))
1489
1410
        return result
1490
1411
 
1491
1412
    def push(self, overwrite=False, stop_revision=None, lossy=False,
1492
 
             _override_hook_source_branch=None, _stop_revno=None,
1493
 
             tag_selector=None):
 
1413
             _override_hook_source_branch=None, _stop_revno=None):
1494
1414
        result = GitBranchPushResult()
1495
1415
        result.source_branch = self.source
1496
1416
        result.target_branch = self.target
1501
1421
                stop_revision, stop_revno=_stop_revno)
1502
1422
 
1503
1423
            def update_refs(old_refs):
1504
 
                return self._update_refs(result, old_refs, new_refs, overwrite, tag_selector)
 
1424
                return self._update_refs(result, old_refs, new_refs, overwrite)
1505
1425
            try:
1506
1426
                result.revidmap, old_refs, new_refs = (
1507
1427
                    self.interrepo.fetch_refs(