/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
1
# Copyright (C) 2009-2018 Jelmer Vernooij <jelmer@jelmer.uk>
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
17
"""InterRepository operations."""
18
19
from __future__ import absolute_import
20
21
from io import BytesIO
6989.2.5 by Jelmer Vernooij
More test fixes.
22
import itertools
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
23
24
from dulwich.errors import (
25
    NotCommitError,
26
    )
27
from dulwich.object_store import (
28
    ObjectStoreGraphWalker,
29
    )
30
from dulwich.protocol import (
31
    CAPABILITY_THIN_PACK,
32
    ZERO_SHA,
33
    )
7103.2.1 by Jelmer Vernooij
Don't attempt to retrieve peeled SHAs.
34
from dulwich.refs import (
35
    ANNOTATED_TAG_SUFFIX,
36
    SYMREF,
37
    )
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
38
from dulwich.walk import Walker
39
6986.2.1 by Jelmer Vernooij
Move breezy.plugins.git to breezy.git.
40
from ..errors import (
0.404.5 by Jelmer Vernooij
Check for diverged branches during push.
41
    DivergedBranches,
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
42
    FetchLimitUnsupported,
43
    InvalidRevisionId,
44
    LossyPushToSameVCS,
45
    NoRoundtrippingSupport,
46
    NoSuchRevision,
47
    )
6986.2.1 by Jelmer Vernooij
Move breezy.plugins.git to breezy.git.
48
from ..repository import (
7455.2.1 by Jelmer Vernooij
Return a FetchResult object from Repository.fetch / Branch.fetch.
49
    FetchResult,
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
50
    InterRepository,
51
    )
6986.2.1 by Jelmer Vernooij
Move breezy.plugins.git to breezy.git.
52
from ..revision import (
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
53
    NULL_REVISION,
54
    )
6986.2.3 by Jelmer Vernooij
Merge trunk
55
from ..sixish import (
7018.3.2 by Jelmer Vernooij
Fix some git tests.
56
    viewitems,
6986.2.3 by Jelmer Vernooij
Merge trunk
57
    viewvalues,
7018.3.2 by Jelmer Vernooij
Fix some git tests.
58
    )
6986.2.1 by Jelmer Vernooij
Move breezy.plugins.git to breezy.git.
59
from .. import (
0.418.1 by Jelmer Vernooij
Support suppressing slow intervcs warnings.
60
    config,
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
61
    trace,
62
    ui,
63
    )
64
65
from .errors import (
66
    NoPushSupport,
67
    )
68
from .fetch import (
69
    import_git_objects,
70
    DetermineWantsRecorder,
71
    )
72
from .mapping import (
73
    needs_roundtripping,
74
    )
75
from .object_store import (
76
    get_object_store,
77
    )
78
from .push import (
79
    MissingObjectsIterator,
0.404.5 by Jelmer Vernooij
Check for diverged branches during push.
80
    remote_divergence,
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
81
    )
82
from .refs import (
83
    is_tag,
7489.4.2 by Jelmer Vernooij
Plumb through tag_selector.
84
    ref_to_tag_name,
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
85
    )
86
from .repository import (
87
    GitRepository,
88
    LocalGitRepository,
89
    GitRepositoryFormat,
90
    )
91
from .remote import (
92
    RemoteGitRepository,
7490.60.1 by Jelmer Vernooij
Add support for new push interface in Dulwich >= 0.20.4.
93
    RemoteGitError,
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
94
    )
95
from .unpeel_map import (
96
    UnpeelMap,
97
    )
98
99
100
class InterToGitRepository(InterRepository):
101
    """InterRepository that copies into a Git repository."""
102
103
    _matching_repo_format = GitRepositoryFormat()
104
105
    def __init__(self, source, target):
106
        super(InterToGitRepository, self).__init__(source, target)
107
        self.mapping = self.target.get_mapping()
108
        self.source_store = get_object_store(self.source, self.mapping)
109
110
    @staticmethod
111
    def _get_repo_format_to_test():
112
        return None
113
114
    def copy_content(self, revision_id=None, pb=None):
115
        """See InterRepository.copy_content."""
116
        self.fetch(revision_id, pb, find_ghosts=False)
117
0.404.5 by Jelmer Vernooij
Check for diverged branches during push.
118
    def fetch_refs(self, update_refs, lossy, overwrite=False):
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
119
        """Fetch possibly roundtripped revisions into the target repository
120
        and update refs.
121
122
        :param update_refs: Generate refs to fetch. Receives dictionary
123
            with old refs (git shas), returns dictionary of new names to
124
            git shas.
125
        :param lossy: Whether to roundtrip
126
        :return: old refs, new refs
127
        """
128
        raise NotImplementedError(self.fetch_refs)
129
130
    def search_missing_revision_ids(self,
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
131
                                    find_ghosts=True, revision_ids=None,
132
                                    if_present_ids=None, limit=None):
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
133
        if limit is not None:
134
            raise FetchLimitUnsupported(self)
135
        git_shas = []
136
        todo = []
137
        if revision_ids:
138
            todo.extend(revision_ids)
139
        if if_present_ids:
140
            todo.extend(revision_ids)
141
        with self.source_store.lock_read():
142
            for revid in revision_ids:
143
                if revid == NULL_REVISION:
144
                    continue
6989.2.3 by Jelmer Vernooij
Allow testing interrepo formats that don't support roundtripping.
145
                try:
146
                    git_sha = self.source_store._lookup_revision_sha1(revid)
147
                except KeyError:
148
                    raise NoSuchRevision(revid, self.source)
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
149
                git_shas.append(git_sha)
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
150
            walker = Walker(
151
                self.source_store,
152
                include=git_shas,
153
                exclude=[
154
                    sha for sha in self.target.controldir.get_refs_container().as_dict().values()
155
                    if sha != ZERO_SHA])
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
156
            missing_revids = set()
157
            for entry in walker:
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
158
                for (kind, type_data) in self.source_store.lookup_git_sha(
159
                        entry.commit.id):
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
160
                    if kind == "commit":
161
                        missing_revids.add(type_data[0])
6989.2.3 by Jelmer Vernooij
Allow testing interrepo formats that don't support roundtripping.
162
            return self.source.revision_ids_to_search_result(missing_revids)
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
163
164
    def _warn_slow(self):
0.418.1 by Jelmer Vernooij
Support suppressing slow intervcs warnings.
165
        if not config.GlobalConfig().suppress_warning('slow_intervcs_push'):
166
            trace.warning(
167
                'Pushing from a Bazaar to a Git repository. '
168
                'For better performance, push into a Bazaar repository.')
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
169
170
171
class InterToLocalGitRepository(InterToGitRepository):
172
    """InterBranch implementation between a Bazaar and a Git repository."""
173
174
    def __init__(self, source, target):
175
        super(InterToLocalGitRepository, self).__init__(source, target)
176
        self.target_store = self.target.controldir._git.object_store
177
        self.target_refs = self.target.controldir._git.refs
178
179
    def _commit_needs_fetching(self, sha_id):
180
        try:
181
            return (sha_id not in self.target_store)
182
        except NoSuchRevision:
183
            # Ghost, can't push
184
            return False
185
186
    def _revision_needs_fetching(self, sha_id, revid):
187
        if revid == NULL_REVISION:
188
            return False
189
        if sha_id is None:
190
            try:
191
                sha_id = self.source_store._lookup_revision_sha1(revid)
192
            except KeyError:
193
                return False
194
        return self._commit_needs_fetching(sha_id)
195
196
    def missing_revisions(self, stop_revisions):
197
        """Find the revisions that are missing from the target repository.
198
199
        :param stop_revisions: Revisions to check for (tuples with
200
            Git SHA1, bzr revid)
201
        :return: sequence of missing revisions, in topological order
202
        :raise: NoSuchRevision if the stop_revisions are not present in
203
            the source
204
        """
205
        revid_sha_map = {}
206
        stop_revids = []
207
        for (sha1, revid) in stop_revisions:
208
            if sha1 is not None and revid is not None:
209
                revid_sha_map[revid] = sha1
210
                stop_revids.append(revid)
211
            elif sha1 is not None:
212
                if self._commit_needs_fetching(sha1):
213
                    for (kind, (revid, tree_sha, verifiers)) in self.source_store.lookup_git_sha(sha1):
214
                        revid_sha_map[revid] = sha1
215
                        stop_revids.append(revid)
216
            else:
217
                if revid is None:
218
                    raise AssertionError
219
                stop_revids.append(revid)
220
        missing = set()
221
        graph = self.source.get_graph()
7143.22.1 by Jelmer Vernooij
use context on progress bars.
222
        with ui.ui_factory.nested_progress_bar() as pb:
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
223
            while stop_revids:
224
                new_stop_revids = []
225
                for revid in stop_revids:
226
                    sha1 = revid_sha_map.get(revid)
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
227
                    if (revid not in missing and
7143.15.2 by Jelmer Vernooij
Run autopep8.
228
                            self._revision_needs_fetching(sha1, revid)):
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
229
                        missing.add(revid)
230
                        new_stop_revids.append(revid)
231
                stop_revids = set()
232
                parent_map = graph.get_parent_map(new_stop_revids)
7018.3.2 by Jelmer Vernooij
Fix some git tests.
233
                for parent_revids in viewvalues(parent_map):
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
234
                    stop_revids.update(parent_revids)
235
                pb.update("determining revisions to fetch", len(missing))
236
        return graph.iter_topo_order(missing)
237
238
    def _get_target_bzr_refs(self):
239
        """Return a dictionary with references.
240
241
        :return: Dictionary with reference names as keys and tuples
242
            with Git SHA, Bazaar revid as values.
243
        """
244
        bzr_refs = {}
245
        for k in self.target._git.refs.allkeys():
246
            try:
6987.1.2 by Jelmer Vernooij
Correctly deal with symbolic refs when pushing.
247
                v = self.target._git.refs.read_ref(k)
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
248
            except KeyError:
249
                # broken symref?
250
                continue
6987.1.2 by Jelmer Vernooij
Correctly deal with symbolic refs when pushing.
251
            revid = None
7490.93.2 by Jelmer Vernooij
Ignore missing revs.
252
            if v and not v.startswith(SYMREF):
6987.1.2 by Jelmer Vernooij
Correctly deal with symbolic refs when pushing.
253
                try:
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
254
                    for (kind, type_data) in self.source_store.lookup_git_sha(
255
                            v):
256
                        if kind == "commit" and self.source.has_revision(
257
                                type_data[0]):
6987.1.2 by Jelmer Vernooij
Correctly deal with symbolic refs when pushing.
258
                            revid = type_data[0]
259
                            break
260
                except KeyError:
261
                    pass
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
262
            bzr_refs[k] = (v, revid)
263
        return bzr_refs
264
0.404.5 by Jelmer Vernooij
Check for diverged branches during push.
265
    def fetch_refs(self, update_refs, lossy, overwrite=False):
0.403.1 by Jelmer Vernooij
Properly warn on slow push from bzr->git.
266
        self._warn_slow()
7131.14.2 by Jelmer Vernooij
Make sure resulting branch is correct too.
267
        result_refs = {}
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
268
        with self.source_store.lock_read():
269
            old_refs = self._get_target_bzr_refs()
270
            new_refs = update_refs(old_refs)
271
            revidmap = self.fetch_objects(
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
272
                [(git_sha, bzr_revid)
273
                 for (git_sha, bzr_revid) in new_refs.values()
274
                 if git_sha is None or not git_sha.startswith(SYMREF)],
275
                lossy=lossy)
7018.3.2 by Jelmer Vernooij
Fix some git tests.
276
            for name, (gitid, revid) in viewitems(new_refs):
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
277
                if gitid is None:
278
                    try:
279
                        gitid = revidmap[revid][0]
280
                    except KeyError:
281
                        gitid = self.source_store._lookup_revision_sha1(revid)
6987.1.2 by Jelmer Vernooij
Correctly deal with symbolic refs when pushing.
282
                if gitid.startswith(SYMREF):
7143.15.2 by Jelmer Vernooij
Run autopep8.
283
                    self.target_refs.set_symbolic_ref(
284
                        name, gitid[len(SYMREF):])
6987.1.1 by Jelmer Vernooij
Guard against race conditions.
285
                else:
6987.1.2 by Jelmer Vernooij
Correctly deal with symbolic refs when pushing.
286
                    try:
6988 by Jelmer Vernooij
Merge lp:~jelmer/brz/git-fixes.
287
                        old_git_id = old_refs[name][0]
6987.1.2 by Jelmer Vernooij
Correctly deal with symbolic refs when pushing.
288
                    except KeyError:
289
                        self.target_refs.add_if_new(name, gitid)
290
                    else:
291
                        self.target_refs.set_if_equals(name, old_git_id, gitid)
7131.14.2 by Jelmer Vernooij
Make sure resulting branch is correct too.
292
                    result_refs[name] = (gitid, revid if not lossy else self.mapping.revision_id_foreign_to_bzr(gitid))
293
        return revidmap, old_refs, result_refs
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
294
295
    def fetch_objects(self, revs, lossy, limit=None):
296
        if not lossy and not self.mapping.roundtripping:
297
            for git_sha, bzr_revid in revs:
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
298
                if (bzr_revid is not None and
299
                        needs_roundtripping(self.source, bzr_revid)):
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
300
                    raise NoPushSupport(self.source, self.target, self.mapping,
301
                                        bzr_revid)
302
        with self.source_store.lock_read():
303
            todo = list(self.missing_revisions(revs))[:limit]
304
            revidmap = {}
7143.22.1 by Jelmer Vernooij
use context on progress bars.
305
            with ui.ui_factory.nested_progress_bar() as pb:
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
306
                object_generator = MissingObjectsIterator(
307
                    self.source_store, self.source, pb)
308
                for (old_revid, git_sha) in object_generator.import_revisions(
7143.15.2 by Jelmer Vernooij
Run autopep8.
309
                        todo, lossy=lossy):
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
310
                    if lossy:
7143.15.2 by Jelmer Vernooij
Run autopep8.
311
                        new_revid = self.mapping.revision_id_foreign_to_bzr(
312
                            git_sha)
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
313
                    else:
314
                        new_revid = old_revid
315
                        try:
316
                            self.mapping.revision_id_bzr_to_foreign(old_revid)
317
                        except InvalidRevisionId:
7490.92.1 by Jelmer Vernooij
Don't spam refnames.
318
                            pass
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
319
                    revidmap[old_revid] = (git_sha, new_revid)
320
                self.target_store.add_objects(object_generator)
321
                return revidmap
322
323
    def fetch(self, revision_id=None, pb=None, find_ghosts=False,
7455.2.1 by Jelmer Vernooij
Return a FetchResult object from Repository.fetch / Branch.fetch.
324
              fetch_spec=None, mapped_refs=None, lossy=False):
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
325
        if mapped_refs is not None:
326
            stop_revisions = mapped_refs
327
        elif revision_id is not None:
328
            stop_revisions = [(None, revision_id)]
329
        elif fetch_spec is not None:
330
            recipe = fetch_spec.get_recipe()
331
            if recipe[0] in ("search", "proxy-search"):
332
                stop_revisions = [(None, revid) for revid in recipe[1]]
333
            else:
7143.15.2 by Jelmer Vernooij
Run autopep8.
334
                raise AssertionError(
335
                    "Unsupported search result type %s" % recipe[0])
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
336
        else:
7143.15.2 by Jelmer Vernooij
Run autopep8.
337
            stop_revisions = [(None, revid)
338
                              for revid in self.source.all_revision_ids()]
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
339
        self._warn_slow()
340
        try:
7455.2.1 by Jelmer Vernooij
Return a FetchResult object from Repository.fetch / Branch.fetch.
341
            revidmap = self.fetch_objects(stop_revisions, lossy=lossy)
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
342
        except NoPushSupport:
343
            raise NoRoundtrippingSupport(self.source, self.target)
7455.2.1 by Jelmer Vernooij
Return a FetchResult object from Repository.fetch / Branch.fetch.
344
        return FetchResult(revidmap)
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
345
346
    @staticmethod
347
    def is_compatible(source, target):
348
        """Be compatible with GitRepository."""
349
        return (not isinstance(source, GitRepository) and
350
                isinstance(target, LocalGitRepository))
351
352
353
class InterToRemoteGitRepository(InterToGitRepository):
354
0.404.5 by Jelmer Vernooij
Check for diverged branches during push.
355
    def fetch_refs(self, update_refs, lossy, overwrite=False):
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
356
        """Import the gist of the ancestry of a particular revision."""
357
        if not lossy and not self.mapping.roundtripping:
358
            raise NoPushSupport(self.source, self.target, self.mapping)
359
        unpeel_map = UnpeelMap.from_repository(self.source)
360
        revidmap = {}
7143.15.2 by Jelmer Vernooij
Run autopep8.
361
7103.2.1 by Jelmer Vernooij
Don't attempt to retrieve peeled SHAs.
362
        def git_update_refs(old_refs):
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
363
            ret = {}
7131.14.3 by Jelmer Vernooij
Merge trunk.
364
            self.old_refs = {
365
                k: (v, None) for (k, v) in viewitems(old_refs)}
7131.14.2 by Jelmer Vernooij
Make sure resulting branch is correct too.
366
            new_refs = update_refs(self.old_refs)
367
            for name, (gitid, revid) in viewitems(new_refs):
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
368
                if gitid is None:
369
                    git_sha = self.source_store._lookup_revision_sha1(revid)
7143.15.2 by Jelmer Vernooij
Run autopep8.
370
                    gitid = unpeel_map.re_unpeel_tag(
371
                        git_sha, old_refs.get(name))
0.404.5 by Jelmer Vernooij
Check for diverged branches during push.
372
                if not overwrite:
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
373
                    if remote_divergence(
374
                            old_refs.get(name), gitid, self.source_store):
0.404.5 by Jelmer Vernooij
Check for diverged branches during push.
375
                        raise DivergedBranches(self.source, self.target)
376
                ret[name] = gitid
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
377
            return ret
378
        self._warn_slow()
379
        with self.source_store.lock_read():
7490.60.1 by Jelmer Vernooij
Add support for new push interface in Dulwich >= 0.20.4.
380
            result = self.target.send_pack(
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
381
                git_update_refs, self.source_store.generate_lossy_pack_data)
7490.60.1 by Jelmer Vernooij
Add support for new push interface in Dulwich >= 0.20.4.
382
            if result is not None and not isinstance(result, dict):
383
                for ref, error in result.ref_status.items():
384
                    if error:
385
                        raise RemoteGitError(
386
                            'unable to update ref %r: %s' % (ref, error))
387
                new_refs = result.refs
388
            else:  # dulwich < 0.20.3
389
                new_refs = result
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
390
        # FIXME: revidmap?
7131.14.2 by Jelmer Vernooij
Make sure resulting branch is correct too.
391
        return revidmap, self.old_refs, new_refs
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
392
393
    @staticmethod
394
    def is_compatible(source, target):
395
        """Be compatible with GitRepository."""
396
        return (not isinstance(source, GitRepository) and
397
                isinstance(target, RemoteGitRepository))
398
399
6989.2.5 by Jelmer Vernooij
More test fixes.
400
class GitSearchResult(object):
401
402
    def __init__(self, start, exclude, keys):
403
        self._start = start
404
        self._exclude = exclude
405
        self._keys = keys
406
407
    def get_keys(self):
408
        return self._keys
409
410
    def get_recipe(self):
411
        return ('search', self._start, self._exclude, len(self._keys))
412
413
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
414
class InterFromGitRepository(InterRepository):
415
416
    _matching_repo_format = GitRepositoryFormat()
417
418
    def _target_has_shas(self, shas):
419
        raise NotImplementedError(self._target_has_shas)
420
7489.4.2 by Jelmer Vernooij
Plumb through tag_selector.
421
    def get_determine_wants_heads(self, wants, include_tags=False, tag_selector=None):
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
422
        wants = set(wants)
7143.15.2 by Jelmer Vernooij
Run autopep8.
423
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
424
        def determine_wants(refs):
7143.12.1 by Jelmer Vernooij
Support cloning revisions referenced only by an annotated tag.
425
            unpeel_lookup = {}
426
            for k, v in viewitems(refs):
427
                if k.endswith(ANNOTATED_TAG_SUFFIX):
428
                    unpeel_lookup[v] = refs[k[:-len(ANNOTATED_TAG_SUFFIX)]]
429
            potential = set([unpeel_lookup.get(w, w) for w in wants])
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
430
            if include_tags:
7143.12.1 by Jelmer Vernooij
Support cloning revisions referenced only by an annotated tag.
431
                for k, sha in viewitems(refs):
7103.2.1 by Jelmer Vernooij
Don't attempt to retrieve peeled SHAs.
432
                    if k.endswith(ANNOTATED_TAG_SUFFIX):
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
433
                        continue
7489.4.2 by Jelmer Vernooij
Plumb through tag_selector.
434
                    try:
435
                        tag_name = ref_to_tag_name(k)
436
                    except ValueError:
437
                        continue
438
                    if tag_selector and not tag_selector(tag_name):
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
439
                        continue
7143.12.1 by Jelmer Vernooij
Support cloning revisions referenced only by an annotated tag.
440
                    if sha == ZERO_SHA:
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
441
                        continue
7143.12.1 by Jelmer Vernooij
Support cloning revisions referenced only by an annotated tag.
442
                    potential.add(sha)
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
443
            return list(potential - self._target_has_shas(potential))
444
        return determine_wants
445
446
    def determine_wants_all(self, refs):
447
        raise NotImplementedError(self.determine_wants_all)
448
449
    @staticmethod
450
    def _get_repo_format_to_test():
451
        return None
452
453
    def copy_content(self, revision_id=None):
454
        """See InterRepository.copy_content."""
455
        self.fetch(revision_id, find_ghosts=False)
456
457
    def search_missing_revision_ids(self,
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
458
                                    find_ghosts=True, revision_ids=None,
459
                                    if_present_ids=None, limit=None):
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
460
        if limit is not None:
461
            raise FetchLimitUnsupported(self)
6989.2.7 by Jelmer Vernooij
hackishly fix search_missing_revision_ids.
462
        if revision_ids is None and if_present_ids is None:
6989.2.5 by Jelmer Vernooij
More test fixes.
463
            todo = set(self.source.all_revision_ids())
6989.2.7 by Jelmer Vernooij
hackishly fix search_missing_revision_ids.
464
        else:
465
            todo = set()
466
            if revision_ids is not None:
467
                for revid in revision_ids:
468
                    if not self.source.has_revision(revid):
469
                        raise NoSuchRevision(revid, self.source)
470
                todo.update(revision_ids)
471
            if if_present_ids is not None:
472
                todo.update(if_present_ids)
473
        result_set = todo.difference(self.target.all_revision_ids())
474
        result_parents = set(itertools.chain.from_iterable(viewvalues(
475
            self.source.get_graph().get_parent_map(result_set))))
476
        included_keys = result_set.intersection(result_parents)
477
        start_keys = result_set.difference(included_keys)
478
        exclude_keys = result_parents.difference(result_set)
479
        return GitSearchResult(start_keys, exclude_keys, result_set)
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
480
481
482
class InterGitNonGitRepository(InterFromGitRepository):
483
    """Base InterRepository that copies revisions from a Git into a non-Git
484
    repository."""
485
486
    def _target_has_shas(self, shas):
487
        revids = {}
488
        for sha in shas:
489
            try:
490
                revid = self.source.lookup_foreign_revision_id(sha)
491
            except NotCommitError:
492
                # Commit is definitely not present
493
                continue
494
            else:
495
                revids[revid] = sha
496
        return set([revids[r] for r in self.target.has_revisions(revids)])
497
498
    def determine_wants_all(self, refs):
499
        potential = set()
7018.3.2 by Jelmer Vernooij
Fix some git tests.
500
        for k, v in viewitems(refs):
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
501
            # For non-git target repositories, only worry about peeled
502
            if v == ZERO_SHA:
503
                continue
504
            potential.add(self.source.controldir.get_peeled(k) or v)
505
        return list(potential - self._target_has_shas(potential))
506
507
    def _warn_slow(self):
0.418.1 by Jelmer Vernooij
Support suppressing slow intervcs warnings.
508
        if not config.GlobalConfig().suppress_warning('slow_intervcs_push'):
509
            trace.warning(
510
                'Fetching from Git to Bazaar repository. '
511
                'For better performance, fetch into a Git repository.')
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
512
513
    def fetch_objects(self, determine_wants, mapping, limit=None, lossy=False):
514
        """Fetch objects from a remote server.
515
516
        :param determine_wants: determine_wants callback
517
        :param mapping: BzrGitMapping to use
518
        :param limit: Maximum number of commits to import.
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
519
        :return: Tuple with pack hint, last imported revision id and remote
520
            refs
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
521
        """
522
        raise NotImplementedError(self.fetch_objects)
523
7489.4.2 by Jelmer Vernooij
Plumb through tag_selector.
524
    def get_determine_wants_revids(self, revids, include_tags=False, tag_selector=None):
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
525
        wants = set()
526
        for revid in set(revids):
527
            if self.target.has_revision(revid):
528
                continue
529
            git_sha, mapping = self.source.lookup_bzr_revision_id(revid)
530
            wants.add(git_sha)
7489.4.2 by Jelmer Vernooij
Plumb through tag_selector.
531
        return self.get_determine_wants_heads(
532
            wants, include_tags=include_tags, tag_selector=tag_selector)
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
533
534
    def fetch(self, revision_id=None, find_ghosts=False,
7455.2.1 by Jelmer Vernooij
Return a FetchResult object from Repository.fetch / Branch.fetch.
535
              mapping=None, fetch_spec=None, include_tags=False, lossy=False):
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
536
        if mapping is None:
537
            mapping = self.source.get_mapping()
538
        if revision_id is not None:
539
            interesting_heads = [revision_id]
540
        elif fetch_spec is not None:
541
            recipe = fetch_spec.get_recipe()
542
            if recipe[0] in ("search", "proxy-search"):
543
                interesting_heads = recipe[1]
544
            else:
545
                raise AssertionError("Unsupported search result type %s" %
7143.15.2 by Jelmer Vernooij
Run autopep8.
546
                                     recipe[0])
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
547
        else:
548
            interesting_heads = None
549
550
        if interesting_heads is not None:
551
            determine_wants = self.get_determine_wants_revids(
552
                interesting_heads, include_tags=include_tags)
553
        else:
554
            determine_wants = self.determine_wants_all
555
7455.2.1 by Jelmer Vernooij
Return a FetchResult object from Repository.fetch / Branch.fetch.
556
        (pack_hint, _, remote_refs) = self.fetch_objects(
557
            determine_wants, mapping, lossy=lossy)
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
558
        if pack_hint is not None and self.target._format.pack_compresses:
559
            self.target.pack(hint=pack_hint)
7455.2.2 by Jelmer Vernooij
Fix git tests.
560
        result = FetchResult()
561
        result.refs = remote_refs
562
        return result
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
563
564
565
class InterRemoteGitNonGitRepository(InterGitNonGitRepository):
566
    """InterRepository that copies revisions from a remote Git into a non-Git
567
    repository."""
568
569
    def get_target_heads(self):
570
        # FIXME: This should be more efficient
571
        all_revs = self.target.all_revision_ids()
572
        parent_map = self.target.get_parent_map(all_revs)
573
        all_parents = set()
7045.4.5 by Jelmer Vernooij
Don't use map as a way to avoid loops.
574
        for values in viewvalues(parent_map):
575
            all_parents.update(values)
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
576
        return set(all_revs) - all_parents
577
578
    def fetch_objects(self, determine_wants, mapping, limit=None, lossy=False):
579
        """See `InterGitNonGitRepository`."""
580
        self._warn_slow()
581
        store = get_object_store(self.target, mapping)
582
        with store.lock_write():
583
            heads = self.get_target_heads()
584
            graph_walker = ObjectStoreGraphWalker(
585
                [store._lookup_revision_sha1(head) for head in heads],
586
                lambda sha: store[sha].parents)
587
            wants_recorder = DetermineWantsRecorder(determine_wants)
588
7143.22.1 by Jelmer Vernooij
use context on progress bars.
589
            with ui.ui_factory.nested_progress_bar() as pb:
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
590
                objects_iter = self.source.fetch_objects(
0.405.1 by Jelmer Vernooij
Use same logic for interpreting progress reports everywhere.
591
                    wants_recorder, graph_walker, store.get_raw)
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
592
                trace.mutter("Importing %d new revisions",
593
                             len(wants_recorder.wants))
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
594
                (pack_hint, last_rev) = import_git_objects(
595
                    self.target, mapping, objects_iter, store,
596
                    wants_recorder.wants, pb, limit)
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
597
                return (pack_hint, last_rev, wants_recorder.remote_refs)
598
599
    @staticmethod
600
    def is_compatible(source, target):
601
        """Be compatible with GitRepository."""
602
        if not isinstance(source, RemoteGitRepository):
603
            return False
604
        if not target.supports_rich_root():
605
            return False
606
        if isinstance(target, GitRepository):
607
            return False
608
        if not getattr(target._format, "supports_full_versioned_files", True):
609
            return False
610
        return True
611
612
613
class InterLocalGitNonGitRepository(InterGitNonGitRepository):
614
    """InterRepository that copies revisions from a local Git into a non-Git
615
    repository."""
616
617
    def fetch_objects(self, determine_wants, mapping, limit=None, lossy=False):
618
        """See `InterGitNonGitRepository`."""
619
        self._warn_slow()
620
        remote_refs = self.source.controldir.get_refs_container().as_dict()
621
        wants = determine_wants(remote_refs)
622
        target_git_object_retriever = get_object_store(self.target, mapping)
7143.22.1 by Jelmer Vernooij
use context on progress bars.
623
        with ui.ui_factory.nested_progress_bar() as pb:
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
624
            target_git_object_retriever.lock_write()
625
            try:
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
626
                (pack_hint, last_rev) = import_git_objects(
627
                    self.target, mapping, self.source._git.object_store,
628
                    target_git_object_retriever, wants, pb, limit)
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
629
                return (pack_hint, last_rev, remote_refs)
630
            finally:
631
                target_git_object_retriever.unlock()
632
633
    @staticmethod
634
    def is_compatible(source, target):
635
        """Be compatible with GitRepository."""
636
        if not isinstance(source, LocalGitRepository):
637
            return False
638
        if not target.supports_rich_root():
639
            return False
640
        if isinstance(target, GitRepository):
641
            return False
642
        if not getattr(target._format, "supports_full_versioned_files", True):
643
            return False
644
        return True
645
646
647
class InterGitGitRepository(InterFromGitRepository):
648
    """InterRepository that copies between Git repositories."""
649
0.404.5 by Jelmer Vernooij
Check for diverged branches during push.
650
    def fetch_refs(self, update_refs, lossy, overwrite=False):
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
651
        if lossy:
652
            raise LossyPushToSameVCS(self.source, self.target)
653
        old_refs = self.target.controldir.get_refs_container()
654
        ref_changes = {}
7143.15.2 by Jelmer Vernooij
Run autopep8.
655
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
656
        def determine_wants(heads):
7143.15.2 by Jelmer Vernooij
Run autopep8.
657
            old_refs = dict([(k, (v, None))
658
                             for (k, v) in viewitems(heads.as_dict())])
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
659
            new_refs = update_refs(old_refs)
660
            ref_changes.update(new_refs)
7018.3.2 by Jelmer Vernooij
Fix some git tests.
661
            return [sha1 for (sha1, bzr_revid) in viewvalues(new_refs)]
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
662
        self.fetch_objects(determine_wants, lossy=lossy)
7018.3.2 by Jelmer Vernooij
Fix some git tests.
663
        for k, (git_sha, bzr_revid) in viewitems(ref_changes):
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
664
            self.target._git.refs[k] = git_sha
665
        new_refs = self.target.controldir.get_refs_container()
666
        return None, old_refs, new_refs
667
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
668
    def fetch_objects(self, determine_wants, mapping=None, limit=None,
669
                      lossy=False):
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
670
        raise NotImplementedError(self.fetch_objects)
671
672
    def _target_has_shas(self, shas):
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
673
        return set(
674
            [sha for sha in shas if sha in self.target._git.object_store])
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
675
676
    def fetch(self, revision_id=None, find_ghosts=False,
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
677
              mapping=None, fetch_spec=None, branches=None, limit=None,
7455.2.1 by Jelmer Vernooij
Return a FetchResult object from Repository.fetch / Branch.fetch.
678
              include_tags=False, lossy=False):
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
679
        if mapping is None:
680
            mapping = self.source.get_mapping()
681
        if revision_id is not None:
682
            args = [revision_id]
683
        elif fetch_spec is not None:
684
            recipe = fetch_spec.get_recipe()
685
            if recipe[0] in ("search", "proxy-search"):
686
                heads = recipe[1]
687
            else:
688
                raise AssertionError(
689
                    "Unsupported search result type %s" % recipe[0])
690
            args = heads
691
        if branches is not None:
7413.4.2 by Jelmer Vernooij
Factor out determine wants for branches.
692
            determine_wants = self.get_determine_wants_branches(
693
                branches, include_tags=include_tags)
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
694
        elif fetch_spec is None and revision_id is None:
695
            determine_wants = self.determine_wants_all
696
        else:
7143.15.2 by Jelmer Vernooij
Run autopep8.
697
            determine_wants = self.get_determine_wants_revids(
698
                args, include_tags=include_tags)
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
699
        wants_recorder = DetermineWantsRecorder(determine_wants)
7455.2.1 by Jelmer Vernooij
Return a FetchResult object from Repository.fetch / Branch.fetch.
700
        self.fetch_objects(wants_recorder, mapping, limit=limit, lossy=lossy)
7455.2.2 by Jelmer Vernooij
Fix git tests.
701
        result = FetchResult()
702
        result.refs = wants_recorder.remote_refs
703
        return result
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
704
7489.4.2 by Jelmer Vernooij
Plumb through tag_selector.
705
    def get_determine_wants_revids(self, revids, include_tags=False, tag_selector=None):
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
706
        wants = set()
707
        for revid in set(revids):
708
            if revid == NULL_REVISION:
709
                continue
710
            git_sha, mapping = self.source.lookup_bzr_revision_id(revid)
711
            wants.add(git_sha)
7489.4.2 by Jelmer Vernooij
Plumb through tag_selector.
712
        return self.get_determine_wants_heads(wants, include_tags=include_tags, tag_selector=tag_selector)
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
713
7413.4.2 by Jelmer Vernooij
Factor out determine wants for branches.
714
    def get_determine_wants_branches(self, branches, include_tags=False):
715
        def determine_wants(refs):
716
            ret = []
717
            for name, value in viewitems(refs):
718
                if value == ZERO_SHA:
719
                    continue
720
721
                if name.endswith(ANNOTATED_TAG_SUFFIX):
722
                    continue
723
724
                if name in branches or (include_tags and is_tag(name)):
725
                    ret.append(value)
726
            return ret
727
        return determine_wants
728
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
729
    def determine_wants_all(self, refs):
7103.2.1 by Jelmer Vernooij
Don't attempt to retrieve peeled SHAs.
730
        potential = set([
731
            v for k, v in refs.items()
732
            if not v == ZERO_SHA and not k.endswith(ANNOTATED_TAG_SUFFIX)])
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
733
        return list(potential - self._target_has_shas(potential))
734
735
736
class InterLocalGitLocalGitRepository(InterGitGitRepository):
737
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
738
    def fetch_objects(self, determine_wants, mapping=None, limit=None,
739
                      lossy=False):
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
740
        if lossy:
741
            raise LossyPushToSameVCS(self.source, self.target)
742
        if limit is not None:
743
            raise FetchLimitUnsupported(self)
7131.6.1 by Jelmer Vernooij
Add progress bar for local git->git fetches.
744
        from .remote import DefaultProgressReporter
7143.22.1 by Jelmer Vernooij
use context on progress bars.
745
        with ui.ui_factory.nested_progress_bar() as pb:
746
            progress = DefaultProgressReporter(pb).progress
7131.6.1 by Jelmer Vernooij
Add progress bar for local git->git fetches.
747
            refs = self.source._git.fetch(
7143.15.2 by Jelmer Vernooij
Run autopep8.
748
                self.target._git, determine_wants,
749
                progress=progress)
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
750
        return (None, None, refs)
751
752
    @staticmethod
753
    def is_compatible(source, target):
754
        """Be compatible with GitRepository."""
755
        return (isinstance(source, LocalGitRepository) and
756
                isinstance(target, LocalGitRepository))
757
758
759
class InterRemoteGitLocalGitRepository(InterGitGitRepository):
760
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
761
    def fetch_objects(self, determine_wants, mapping=None, limit=None,
762
                      lossy=False):
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
763
        if lossy:
764
            raise LossyPushToSameVCS(self.source, self.target)
765
        if limit is not None:
766
            raise FetchLimitUnsupported(self)
767
        graphwalker = self.target._git.get_graph_walker()
7143.15.3 by Jelmer Vernooij
Fix pep8 issues in breezy.git.
768
        if (CAPABILITY_THIN_PACK in
769
                self.source.controldir._client._fetch_capabilities):
0.405.1 by Jelmer Vernooij
Use same logic for interpreting progress reports everywhere.
770
            # TODO(jelmer): Avoid reading entire file into memory and
771
            # only processing it after the whole file has been fetched.
772
            f = BytesIO()
773
774
            def commit():
775
                if f.tell():
776
                    f.seek(0)
777
                    self.target._git.object_store.move_in_thin_pack(f)
778
779
            def abort():
780
                pass
781
        else:
782
            f, commit, abort = self.target._git.object_store.add_pack()
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
783
        try:
0.405.1 by Jelmer Vernooij
Use same logic for interpreting progress reports everywhere.
784
            refs = self.source.controldir.fetch_pack(
785
                determine_wants, graphwalker, f.write)
786
            commit()
787
            return (None, None, refs)
788
        except BaseException:
789
            abort()
790
            raise
0.401.2 by Jelmer Vernooij
Move all InterRepository implementations into interrepo.
791
792
    @staticmethod
793
    def is_compatible(source, target):
794
        """Be compatible with GitRepository."""
795
        return (isinstance(source, RemoteGitRepository) and
796
                isinstance(target, LocalGitRepository))