/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

Reduce number of round trips when fetching from Git.

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
"""Push implementation that simply prints message saying push is not supported."""
18
18
 
 
19
from dulwich.client import (
 
20
    SimpleFetchGraphWalker,
 
21
    )
 
22
from dulwich.object_store import (
 
23
    MissingObjectFinder,
 
24
    )
 
25
 
19
26
from bzrlib import (
20
 
    errors,
21
27
    ui,
22
28
    )
23
29
from bzrlib.repository import (
30
36
from bzrlib.plugins.git.errors import (
31
37
    NoPushSupport,
32
38
    )
33
 
from bzrlib.plugins.git.mapping import (
34
 
    extract_unusual_modes,
35
 
    )
36
39
from bzrlib.plugins.git.object_store import (
37
40
    BazaarObjectStore,
38
41
    )
51
54
 
52
55
    """
53
56
 
54
 
    def __init__(self, store, source, pb=None):
 
57
    def __init__(self, source, mapping, pb=None):
55
58
        """Create a new missing objects iterator.
56
59
 
57
60
        """
58
61
        self.source = source
59
 
        self._object_store = store
 
62
        self._object_store = BazaarObjectStore(self.source, mapping)
60
63
        self._revids = set()
61
64
        self._sent_shas = set()
62
65
        self._pending = []
71
74
            yield (revid, git_commit)
72
75
 
73
76
    def need_sha(self, sha):
74
 
        if sha is None or sha in self._sent_shas:
 
77
        if sha in self._sent_shas:
75
78
            return False
76
79
        (type, (fileid, revid)) = self._object_store._idmap.lookup_git_sha(sha)
77
80
        assert type in ("blob", "tree")
82
85
        # or already present remotely (as git doesn't do ghosts)
83
86
        return False
84
87
 
85
 
    def queue(self, sha, obj, path, ie=None, inv=None, unusual_modes=None):
 
88
    def queue(self, sha, obj, path, ie=None, inv=None):
86
89
        if obj is None:
87
 
            # Can't lazy-evaluate directories, since they might be eliminated
88
 
            if ie.kind == "directory":
89
 
                obj = self._object_store._get_ie_object(ie, inv, unusual_modes)
90
 
                if obj is None:
91
 
                    return
92
 
            else:
93
 
                obj = (ie, inv, unusual_modes)
 
90
            obj = (ie, inv)
94
91
        self._pending.append((obj, path))
95
92
        self._sent_shas.add(sha)
96
93
 
99
96
 
100
97
        """
101
98
        inv = self.source.get_inventory(revid)
102
 
        rev = self.source.get_revision(revid)
103
 
        unusual_modes = extract_unusual_modes(rev)
104
99
        todo = [inv.root]
105
100
        tree_sha = None
106
101
        while todo:
107
102
            ie = todo.pop()
108
 
            (sha, object) = self._object_store._get_ie_object_or_sha1(ie, inv, unusual_modes)
 
103
            (sha, object) = self._object_store._get_ie_object_or_sha1(ie, inv)
109
104
            if ie.parent_id is None:
110
105
                tree_sha = sha
111
106
            if not self.need_sha(sha):
112
107
                continue
113
 
            self.queue(sha, object, inv.id2path(ie.file_id), ie, inv, unusual_modes)
 
108
            self.queue(sha, object, inv.id2path(ie.file_id), ie, inv)
114
109
            if ie.kind == "directory":
115
110
                todo.extend(ie.children.values())
116
111
        assert tree_sha is not None
117
 
        commit = self._object_store._get_commit(rev, tree_sha)
118
 
        self.queue(commit.id, commit, None, None)
 
112
        commit = self._object_store._get_commit(revid, tree_sha)
 
113
        self.queue(commit.id, commit, None)
119
114
        return commit.id
120
115
 
121
116
    def __len__(self):
127
122
                self.pb.update("writing pack objects", i, len(self))
128
123
            if isinstance(object, tuple):
129
124
                object = self._object_store._get_ie_object(*object)
130
 
            yield (object, path)
 
125
            yield (object, path)   
131
126
 
132
127
 
133
128
class InterToGitRepository(InterRepository):
138
133
    def __init__(self, source, target):
139
134
        super(InterToGitRepository, self).__init__(source, target)
140
135
        self.mapping = self.target.get_mapping()
141
 
        self.source_store = BazaarObjectStore(self.source, self.mapping)
142
136
 
143
137
    @staticmethod
144
138
    def _get_repo_format_to_test():
148
142
        """See InterRepository.copy_content."""
149
143
        self.fetch(revision_id, pb, find_ghosts=False)
150
144
 
151
 
    def fetch(self, revision_id=None, pb=None, find_ghosts=False,
 
145
    def fetch(self, revision_id=None, pb=None, find_ghosts=False, 
152
146
            fetch_spec=None):
153
147
        raise NoPushSupport()
154
148
 
155
149
 
156
150
class InterToLocalGitRepository(InterToGitRepository):
157
151
 
158
 
    def missing_revisions(self, stop_revisions, check_revid):
 
152
    def missing_revisions(self, stop_revision):
 
153
        if stop_revision is None:
 
154
            raise NotImplementedError
159
155
        missing = []
160
156
        pb = ui.ui_factory.nested_progress_bar()
161
157
        try:
162
158
            graph = self.source.get_graph()
163
 
            for revid, _ in graph.iter_ancestry(stop_revisions):
 
159
            for revid, _ in graph.iter_ancestry([stop_revision]):
164
160
                pb.update("determining revisions to fetch", len(missing))
165
 
                if not check_revid(revid):
 
161
                if not self.target.has_revision(revid):
166
162
                    missing.append(revid)
167
163
            return graph.iter_topo_order(missing)
168
164
        finally:
169
165
            pb.finished()
170
166
 
171
167
    def dfetch_refs(self, refs):
 
168
        revidmap = {}
172
169
        new_refs = {}
173
 
        revidmap, gitidmap = self.dfetch(refs.values())
174
170
        for name, revid in refs.iteritems():
175
 
            if revid in gitidmap:
176
 
                gitid = gitidmap[revid]
 
171
            newrevidmap, newgitidmap = self.dfetch(revid)
 
172
            revidmap.update(newrevidmap)
 
173
            if revid in newgitidmap:
 
174
                gitid = newgitidmap[revid]
177
175
            else:
178
 
                gitid = self.source_store._lookup_revision_sha1(revid)
179
 
            self.target._git.refs[name] = gitid
 
176
                gitid, _ = self.mapping.revision_id_bzr_to_foreign(revid)
 
177
            self.target._git.set_ref(name, gitid)
180
178
            new_refs[name] = gitid
181
179
        return revidmap, new_refs
182
180
 
183
 
    def dfetch(self, stop_revisions):
 
181
    def dfetch(self, stop_revision=None):
184
182
        """Import the gist of the ancestry of a particular revision."""
185
183
        gitidmap = {}
186
184
        revidmap = {}
187
185
        self.source.lock_read()
188
186
        try:
189
 
            target_store = self.target._git.object_store
190
 
            def check_revid(revid):
191
 
                if revid == NULL_REVISION:
192
 
                    return True
193
 
                try:
194
 
                    return (self.source_store._lookup_revision_sha1(revid) in target_store)
195
 
                except errors.NoSuchRevision:
196
 
                    # Ghost, can't dpush
197
 
                    return True
198
 
            todo = list(self.missing_revisions(stop_revisions, check_revid))
 
187
            todo = [revid for revid in self.missing_revisions(stop_revision) if revid != NULL_REVISION]
199
188
            pb = ui.ui_factory.nested_progress_bar()
200
189
            try:
201
 
                object_generator = MissingObjectsIterator(self.source_store, self.source, pb)
 
190
                object_generator = MissingObjectsIterator(self.source, self.mapping, pb)
202
191
                for old_bzr_revid, git_commit in object_generator.import_revisions(
203
192
                    todo):
204
193
                    new_bzr_revid = self.mapping.revision_id_foreign_to_bzr(git_commit)
205
194
                    revidmap[old_bzr_revid] = new_bzr_revid
206
195
                    gitidmap[old_bzr_revid] = git_commit
207
 
                target_store.add_objects(object_generator)
 
196
                self.target._git.object_store.add_objects(object_generator) 
208
197
            finally:
209
198
                pb.finished()
210
199
        finally:
214
203
    @staticmethod
215
204
    def is_compatible(source, target):
216
205
        """Be compatible with GitRepository."""
217
 
        return (not isinstance(source, GitRepository) and
 
206
        return (not isinstance(source, GitRepository) and 
218
207
                isinstance(target, LocalGitRepository))
219
208
 
220
209
 
226
215
        def determine_wants(refs):
227
216
            ret = {}
228
217
            for name, revid in new_refs.iteritems():
229
 
                ret[name] = self.source_store._lookup_revision_sha1(revid)
 
218
                ret[name] = store._lookup_revision_sha1(revid)
230
219
            return ret
231
220
        self.source.lock_read()
232
221
        try:
 
222
            store = BazaarObjectStore(self.source, self.mapping)
 
223
            def generate_blob_contents(have, want):
 
224
                graphwalker = SimpleFetchGraphWalker(want, store.get_parents)
 
225
                for h in have:
 
226
                    graphwalker.ack(h)
 
227
                return store.iter_shas(store.find_missing_objects(want, graphwalker))
233
228
            new_refs = self.target.send_pack(determine_wants,
234
 
                    self.source_store.generate_pack_contents)
 
229
                    generate_blob_contents)
235
230
        finally:
236
231
            self.source.unlock()
237
232
        return revidmap, new_refs
239
234
    @staticmethod
240
235
    def is_compatible(source, target):
241
236
        """Be compatible with GitRepository."""
242
 
        return (not isinstance(source, GitRepository) and
 
237
        return (not isinstance(source, GitRepository) and 
243
238
                isinstance(target, RemoteGitRepository))