/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 push.py

Move fixmes

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2009 Jelmer Vernooij <jelmer@samba.org>
 
1
# Copyright (C) 2009-2010 Jelmer Vernooij <jelmer@samba.org>
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
17
17
"""Push implementation that simply prints message saying push is not supported."""
18
18
 
19
19
from bzrlib import (
 
20
    errors,
20
21
    ui,
21
22
    )
 
23
from bzrlib.graph import (
 
24
    PendingAncestryResult,
 
25
    )
22
26
from bzrlib.repository import (
23
27
    InterRepository,
24
28
    )
29
33
from bzrlib.plugins.git.errors import (
30
34
    NoPushSupport,
31
35
    )
32
 
from bzrlib.plugins.git.mapping import (
33
 
    extract_unusual_modes,
34
 
    )
35
36
from bzrlib.plugins.git.object_store import (
36
37
    BazaarObjectStore,
37
38
    )
56
57
        """
57
58
        self.source = source
58
59
        self._object_store = store
59
 
        self._revids = set()
60
 
        self._sent_shas = set()
61
60
        self._pending = []
62
61
        self.pb = pb
63
62
 
64
 
    def import_revisions(self, revids):
65
 
        self._revids.update(revids)
 
63
    def import_revisions(self, revids, roundtrip):
66
64
        for i, revid in enumerate(revids):
67
65
            if self.pb:
68
66
                self.pb.update("pushing revisions", i, len(revids))
69
 
            git_commit = self.import_revision(revid)
 
67
            git_commit = self.import_revision(revid, roundtrip)
70
68
            yield (revid, git_commit)
71
69
 
72
 
    def need_sha(self, sha):
73
 
        if sha in self._sent_shas:
74
 
            return False
75
 
        (type, (fileid, revid)) = self._object_store._idmap.lookup_git_sha(sha)
76
 
        assert type in ("blob", "tree")
77
 
        if revid in self._revids:
78
 
            # Not sent yet, and part of the set of revisions to send
79
 
            return True
80
 
        # Not changed in the revisions to send, so either not necessary
81
 
        # or already present remotely (as git doesn't do ghosts)
82
 
        return False
83
 
 
84
 
    def queue(self, sha, obj, path, ie=None, inv=None):
85
 
        if obj is None:
86
 
            obj = (ie, inv)
87
 
        self._pending.append((obj, path))
88
 
        self._sent_shas.add(sha)
89
 
 
90
 
    def import_revision(self, revid):
 
70
    def import_revision(self, revid, roundtrip):
91
71
        """Import the gist of a revision into this Git repository.
92
72
 
93
73
        """
94
 
        inv = self.source.get_inventory(revid)
 
74
        tree = self._object_store.tree_cache.revision_tree(revid)
95
75
        rev = self.source.get_revision(revid)
96
 
        unusual_modes = extract_unusual_modes(rev)
97
 
        todo = [inv.root]
98
 
        tree_sha = None
99
 
        while todo:
100
 
            ie = todo.pop()
101
 
            (sha, object) = self._object_store._get_ie_object_or_sha1(ie, inv, unusual_modes)
102
 
            if ie.parent_id is None:
103
 
                tree_sha = sha
104
 
            if not self.need_sha(sha):
105
 
                continue
106
 
            self.queue(sha, object, inv.id2path(ie.file_id), ie, inv)
107
 
            if ie.kind == "directory":
108
 
                todo.extend(ie.children.values())
109
 
        assert tree_sha is not None
110
 
        commit = self._object_store._get_commit(rev, tree_sha)
111
 
        self.queue(commit.id, commit, None)
 
76
        commit = None
 
77
        for path, obj, ie in self._object_store._revision_to_objects(rev, tree,
 
78
            roundtrip):
 
79
            if obj.type_name == "commit":
 
80
                commit = obj
 
81
            self._pending.append((obj, path))
112
82
        return commit.id
113
83
 
114
84
    def __len__(self):
115
85
        return len(self._pending)
116
86
 
117
87
    def __iter__(self):
118
 
        for i, (object, path) in enumerate(self._pending):
119
 
            if self.pb:
120
 
                self.pb.update("writing pack objects", i, len(self))
121
 
            if isinstance(object, tuple):
122
 
                object = self._object_store._get_ie_object(*object)
123
 
            yield (object, path)   
 
88
        return iter(self._pending)
124
89
 
125
90
 
126
91
class InterToGitRepository(InterRepository):
141
106
        """See InterRepository.copy_content."""
142
107
        self.fetch(revision_id, pb, find_ghosts=False)
143
108
 
144
 
    def fetch(self, revision_id=None, pb=None, find_ghosts=False, 
145
 
            fetch_spec=None):
146
 
        raise NoPushSupport()
 
109
    def dfetch_refs(self, update_refs):
 
110
        """Fetch non-roundtripped revisions into the target repository.
 
111
 
 
112
        :param update_refs: Generate refs to fetch. Receives dictionary 
 
113
            with old names to old git shas. Should return a dictionary
 
114
            of new names to Bazaar revision ids.
 
115
        :return: revision id map, old refs dictionary and new refs dictionary
 
116
        """
 
117
        raise NotImplementedError(self.dfetch_refs)
 
118
 
 
119
    def fetch_refs(self, update_refs):
 
120
        """Fetch possibly roundtripped revisions into the target repository.
 
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
        :return: old refs, new refs
 
126
        """
 
127
        raise NotImplementedError(self.fetch_refs)
147
128
 
148
129
 
149
130
class InterToLocalGitRepository(InterToGitRepository):
150
131
 
 
132
    def __init__(self, source, target):
 
133
        super(InterToLocalGitRepository, self).__init__(source, target)
 
134
        self.target_store = self.target._git.object_store
 
135
        self.target_refs = self.target._git.refs
 
136
 
151
137
    def missing_revisions(self, stop_revisions, check_revid):
152
138
        missing = []
 
139
        graph = self.source.get_graph()
153
140
        pb = ui.ui_factory.nested_progress_bar()
154
141
        try:
155
 
            graph = self.source.get_graph()
156
142
            for revid, _ in graph.iter_ancestry(stop_revisions):
157
143
                pb.update("determining revisions to fetch", len(missing))
158
144
                if not check_revid(revid):
159
145
                    missing.append(revid)
160
 
            return graph.iter_topo_order(missing)
161
146
        finally:
162
147
            pb.finished()
163
 
 
164
 
    def dfetch_refs(self, refs):
165
 
        new_refs = {}
166
 
        revidmap, gitidmap = self.dfetch(refs.values())
167
 
        for name, revid in refs.iteritems():
168
 
            if revid in gitidmap:
 
148
        return graph.iter_topo_order(missing)
 
149
 
 
150
    def fetch_refs(self, update_refs):
 
151
        old_refs = self.target._git.get_refs()
 
152
        new_refs = update_refs(old_refs)
 
153
        fetch_spec = PendingAncestryResult(new_refs.values(), self.source)
 
154
        self.fetch(fetch_spec=fetch_spec)
 
155
        return old_refs, new_refs
 
156
 
 
157
    def dfetch_refs(self, update_refs):
 
158
        old_refs = self.target._git.get_refs()
 
159
        new_refs = update_refs(old_refs)
 
160
        revidmap, gitidmap = self.dfetch(new_refs.values())
 
161
        for name, revid in new_refs.iteritems():
 
162
            try:
169
163
                gitid = gitidmap[revid]
170
 
            else:
 
164
            except KeyError:
171
165
                gitid = self.source_store._lookup_revision_sha1(revid)
172
166
            self.target._git.refs[name] = gitid
173
 
            new_refs[name] = gitid
174
 
        return revidmap, new_refs
 
167
            new_refs[name] = revid
 
168
        return revidmap, old_refs, new_refs
 
169
 
 
170
    def _find_missing_revs(self, stop_revisions):
 
171
        def check_revid(revid):
 
172
            if revid == NULL_REVISION:
 
173
                return True
 
174
            sha_id = self.source_store._lookup_revision_sha1(revid)
 
175
            try:
 
176
                return (sha_id in self.target_store)
 
177
            except errors.NoSuchRevision:
 
178
                # Ghost, can't push
 
179
                return True
 
180
        return list(self.missing_revisions(stop_revisions, check_revid))
175
181
 
176
182
    def dfetch(self, stop_revisions):
177
183
        """Import the gist of the ancestry of a particular revision."""
179
185
        revidmap = {}
180
186
        self.source.lock_read()
181
187
        try:
182
 
            target_store = self.target._git.object_store
183
 
            def check_revid(revid):
184
 
                if revid == NULL_REVISION:
185
 
                    return True
186
 
                return (self.source_store._lookup_revision_sha1(revid) in target_store)
187
 
            todo = list(self.missing_revisions(stop_revisions, check_revid))
 
188
            todo = self._find_missing_revs(stop_revisions)
188
189
            pb = ui.ui_factory.nested_progress_bar()
189
190
            try:
190
 
                object_generator = MissingObjectsIterator(self.source_store, self.source, pb)
 
191
                object_generator = MissingObjectsIterator(self.source_store,
 
192
                    self.source, pb)
191
193
                for old_bzr_revid, git_commit in object_generator.import_revisions(
192
 
                    todo):
 
194
                    todo, roundtrip=False):
193
195
                    new_bzr_revid = self.mapping.revision_id_foreign_to_bzr(git_commit)
194
196
                    revidmap[old_bzr_revid] = new_bzr_revid
195
197
                    gitidmap[old_bzr_revid] = git_commit
196
 
                target_store.add_objects(object_generator) 
 
198
                self.target_store.add_objects(object_generator)
197
199
            finally:
198
200
                pb.finished()
199
201
        finally:
200
202
            self.source.unlock()
201
203
        return revidmap, gitidmap
202
204
 
 
205
    def fetch(self, revision_id=None, pb=None, find_ghosts=False,
 
206
            fetch_spec=None):
 
207
        if revision_id is not None:
 
208
            stop_revisions = [revision_id]
 
209
        elif fetch_spec is not None:
 
210
            stop_revisions = fetch_spec.heads
 
211
        else:
 
212
            stop_revisions = self.source.all_revision_ids()
 
213
        self.source.lock_read()
 
214
        try:
 
215
            todo = self._find_missing_revs(stop_revisions)
 
216
            pb = ui.ui_factory.nested_progress_bar()
 
217
            try:
 
218
                object_generator = MissingObjectsIterator(self.source_store,
 
219
                    self.source, pb)
 
220
                for (revid, git_sha) in object_generator.import_revisions(
 
221
                    todo, roundtrip=True):
 
222
                    try:
 
223
                        self.mapping.revision_id_bzr_to_foreign(revid)
 
224
                    except errors.InvalidRevisionId:
 
225
                        self.target_refs[self.mapping.revid_as_refname(revid)] = git_sha
 
226
                self.target_store.add_objects(object_generator)
 
227
            finally:
 
228
                pb.finished()
 
229
        finally:
 
230
            self.source.unlock()
 
231
 
203
232
    @staticmethod
204
233
    def is_compatible(source, target):
205
234
        """Be compatible with GitRepository."""
206
 
        return (not isinstance(source, GitRepository) and 
 
235
        return (not isinstance(source, GitRepository) and
207
236
                isinstance(target, LocalGitRepository))
208
237
 
209
238
 
210
239
class InterToRemoteGitRepository(InterToGitRepository):
211
240
 
212
 
    def dfetch_refs(self, new_refs):
 
241
    def dfetch_refs(self, update_refs):
213
242
        """Import the gist of the ancestry of a particular revision."""
214
243
        revidmap = {}
215
 
        def determine_wants(refs):
 
244
        def determine_wants(old_refs):
216
245
            ret = {}
217
 
            for name, revid in new_refs.iteritems():
 
246
            self.old_refs = old_refs
 
247
            self.new_refs = update_refs(self.old_refs)
 
248
            for name, revid in self.new_refs.iteritems():
218
249
                ret[name] = self.source_store._lookup_revision_sha1(revid)
219
250
            return ret
220
251
        self.source.lock_read()
221
252
        try:
222
253
            new_refs = self.target.send_pack(determine_wants,
223
 
                    self.source_store.generate_pack_contents)
 
254
                    self.source_store.generate_lossy_pack_contents)
224
255
        finally:
225
256
            self.source.unlock()
226
 
        return revidmap, new_refs
 
257
        return revidmap, self.old_refs, self.new_refs
 
258
 
 
259
    def fetch_refs(self, update_refs):
 
260
        raise NoPushSupport()
227
261
 
228
262
    @staticmethod
229
263
    def is_compatible(source, target):
230
264
        """Be compatible with GitRepository."""
231
 
        return (not isinstance(source, GitRepository) and 
 
265
        return (not isinstance(source, GitRepository) and
232
266
                isinstance(target, RemoteGitRepository))