/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

  • Committer: Jelmer Vernooij
  • Date: 2010-06-28 22:30:34 UTC
  • mto: (0.200.953 trunk)
  • mto: This revision was merged to the branch mainline in revision 6960.
  • Revision ID: jelmer@samba.org-20100628223034-vylrgdyakmqoupl6
use transport repo objects even for local access.

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):
 
64
        """Import a set of revisions into this git repository.
 
65
 
 
66
        :param revids: Revision ids of revisions to import
 
67
        :param roundtrip: Whether to roundtrip bzr metadata
 
68
        """
66
69
        for i, revid in enumerate(revids):
67
70
            if self.pb:
68
71
                self.pb.update("pushing revisions", i, len(revids))
69
 
            git_commit = self.import_revision(revid)
 
72
            git_commit = self.import_revision(revid, roundtrip)
70
73
            yield (revid, git_commit)
71
74
 
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):
91
 
        """Import the gist of a revision into this Git repository.
92
 
 
 
75
    def import_revision(self, revid, roundtrip):
 
76
        """Import a revision into this Git repository.
 
77
 
 
78
        :param revid: Revision id of the revision
 
79
        :param roundtrip: Whether to roundtrip bzr metadata
93
80
        """
94
 
        inv = self.source.get_inventory(revid)
 
81
        tree = self._object_store.tree_cache.revision_tree(revid)
95
82
        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)
 
83
        commit = None
 
84
        for path, obj, ie in self._object_store._revision_to_objects(rev, tree,
 
85
            roundtrip):
 
86
            if obj.type_name == "commit":
 
87
                commit = obj
 
88
            self._pending.append((obj, path))
112
89
        return commit.id
113
90
 
114
91
    def __len__(self):
115
92
        return len(self._pending)
116
93
 
117
94
    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)   
 
95
        return iter(self._pending)
124
96
 
125
97
 
126
98
class InterToGitRepository(InterRepository):
141
113
        """See InterRepository.copy_content."""
142
114
        self.fetch(revision_id, pb, find_ghosts=False)
143
115
 
144
 
    def fetch(self, revision_id=None, pb=None, find_ghosts=False, 
145
 
            fetch_spec=None):
146
 
        raise NoPushSupport()
 
116
    def dfetch_refs(self, update_refs):
 
117
        """Fetch non-roundtripped revisions into the target repository.
 
118
 
 
119
        :param update_refs: Generate refs to fetch. Receives dictionary 
 
120
            with old names to old git shas. Should return a dictionary
 
121
            of new names to Bazaar revision ids.
 
122
        :return: revision id map, old refs dictionary and new refs dictionary
 
123
        """
 
124
        raise NotImplementedError(self.dfetch_refs)
 
125
 
 
126
    def fetch_refs(self, update_refs):
 
127
        """Fetch possibly roundtripped revisions into the target repository.
 
128
 
 
129
        :param update_refs: Generate refs to fetch. Receives dictionary 
 
130
            with old refs (git shas), returns dictionary of new names to 
 
131
            git shas.
 
132
        :return: old refs, new refs
 
133
        """
 
134
        raise NotImplementedError(self.fetch_refs)
147
135
 
148
136
 
149
137
class InterToLocalGitRepository(InterToGitRepository):
150
138
 
 
139
    def __init__(self, source, target):
 
140
        super(InterToLocalGitRepository, self).__init__(source, target)
 
141
        self.target_store = self.target._git.object_store
 
142
        self.target_refs = self.target._git.refs
 
143
 
151
144
    def missing_revisions(self, stop_revisions, check_revid):
152
145
        missing = []
 
146
        graph = self.source.get_graph()
153
147
        pb = ui.ui_factory.nested_progress_bar()
154
148
        try:
155
 
            graph = self.source.get_graph()
156
149
            for revid, _ in graph.iter_ancestry(stop_revisions):
157
150
                pb.update("determining revisions to fetch", len(missing))
158
151
                if not check_revid(revid):
159
152
                    missing.append(revid)
160
 
            return graph.iter_topo_order(missing)
161
153
        finally:
162
154
            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:
 
155
        return graph.iter_topo_order(missing)
 
156
 
 
157
    def fetch_refs(self, update_refs):
 
158
        old_refs = self.target._git.get_refs()
 
159
        new_refs = update_refs(old_refs)
 
160
        fetch_spec = PendingAncestryResult(new_refs.values(), self.source)
 
161
        self.fetch(fetch_spec=fetch_spec)
 
162
        return old_refs, new_refs
 
163
 
 
164
    def dfetch_refs(self, update_refs):
 
165
        old_refs = self.target._git.get_refs()
 
166
        new_refs = update_refs(old_refs)
 
167
        revidmap, gitidmap = self.dfetch(new_refs.values())
 
168
        for name, revid in new_refs.iteritems():
 
169
            try:
169
170
                gitid = gitidmap[revid]
170
 
            else:
 
171
            except KeyError:
171
172
                gitid = self.source_store._lookup_revision_sha1(revid)
172
173
            self.target._git.refs[name] = gitid
173
 
            new_refs[name] = gitid
174
 
        return revidmap, new_refs
 
174
            new_refs[name] = revid
 
175
        return revidmap, old_refs, new_refs
 
176
 
 
177
    def _find_missing_revs(self, stop_revisions):
 
178
        def check_revid(revid):
 
179
            if revid == NULL_REVISION:
 
180
                return True
 
181
            sha_id = self.source_store._lookup_revision_sha1(revid)
 
182
            try:
 
183
                return (sha_id in self.target_store)
 
184
            except errors.NoSuchRevision:
 
185
                # Ghost, can't push
 
186
                return True
 
187
        return list(self.missing_revisions(stop_revisions, check_revid))
 
188
 
 
189
    def _get_missing_objects_iterator(self, pb):
 
190
        return MissingObjectsIterator(self.source_store, self.source, pb)
175
191
 
176
192
    def dfetch(self, stop_revisions):
177
193
        """Import the gist of the ancestry of a particular revision."""
179
195
        revidmap = {}
180
196
        self.source.lock_read()
181
197
        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))
 
198
            todo = self._find_missing_revs(stop_revisions)
188
199
            pb = ui.ui_factory.nested_progress_bar()
189
200
            try:
190
 
                object_generator = MissingObjectsIterator(self.source_store, self.source, pb)
 
201
                object_generator = self._get_missing_objects_iterator()
191
202
                for old_bzr_revid, git_commit in object_generator.import_revisions(
192
 
                    todo):
 
203
                    todo, roundtrip=False):
193
204
                    new_bzr_revid = self.mapping.revision_id_foreign_to_bzr(git_commit)
194
205
                    revidmap[old_bzr_revid] = new_bzr_revid
195
206
                    gitidmap[old_bzr_revid] = git_commit
196
 
                target_store.add_objects(object_generator) 
 
207
                self.target_store.add_objects(object_generator)
197
208
            finally:
198
209
                pb.finished()
199
210
        finally:
200
211
            self.source.unlock()
201
212
        return revidmap, gitidmap
202
213
 
 
214
    def fetch(self, revision_id=None, pb=None, find_ghosts=False,
 
215
            fetch_spec=None):
 
216
        if revision_id is not None:
 
217
            stop_revisions = [revision_id]
 
218
        elif fetch_spec is not None:
 
219
            stop_revisions = fetch_spec.heads
 
220
        else:
 
221
            stop_revisions = self.source.all_revision_ids()
 
222
        self.source.lock_read()
 
223
        try:
 
224
            todo = self._find_missing_revs(stop_revisions)
 
225
            pb = ui.ui_factory.nested_progress_bar()
 
226
            try:
 
227
                object_generator = self._get_missing_objects_iterator(pb)
 
228
                for (revid, git_sha) in object_generator.import_revisions(
 
229
                    todo, roundtrip=True):
 
230
                    try:
 
231
                        self.mapping.revision_id_bzr_to_foreign(revid)
 
232
                    except errors.InvalidRevisionId:
 
233
                        self.target_refs[self.mapping.revid_as_refname(revid)] = git_sha
 
234
                self.target_store.add_objects(object_generator)
 
235
            finally:
 
236
                pb.finished()
 
237
        finally:
 
238
            self.source.unlock()
 
239
 
203
240
    @staticmethod
204
241
    def is_compatible(source, target):
205
242
        """Be compatible with GitRepository."""
206
 
        return (not isinstance(source, GitRepository) and 
 
243
        return (not isinstance(source, GitRepository) and
207
244
                isinstance(target, LocalGitRepository))
208
245
 
209
246
 
210
247
class InterToRemoteGitRepository(InterToGitRepository):
211
248
 
212
 
    def dfetch_refs(self, new_refs):
 
249
    def dfetch_refs(self, update_refs):
213
250
        """Import the gist of the ancestry of a particular revision."""
214
251
        revidmap = {}
215
 
        def determine_wants(refs):
 
252
        def determine_wants(old_refs):
216
253
            ret = {}
217
 
            for name, revid in new_refs.iteritems():
 
254
            self.old_refs = old_refs
 
255
            self.new_refs = update_refs(self.old_refs)
 
256
            for name, revid in self.new_refs.iteritems():
218
257
                ret[name] = self.source_store._lookup_revision_sha1(revid)
219
258
            return ret
220
259
        self.source.lock_read()
221
260
        try:
222
261
            new_refs = self.target.send_pack(determine_wants,
223
 
                    self.source_store.generate_pack_contents)
 
262
                    self.source_store.generate_lossy_pack_contents)
224
263
        finally:
225
264
            self.source.unlock()
226
 
        return revidmap, new_refs
 
265
        return revidmap, self.old_refs, self.new_refs
 
266
 
 
267
    def fetch_refs(self, update_refs):
 
268
        raise NoPushSupport()
227
269
 
228
270
    @staticmethod
229
271
    def is_compatible(source, target):
230
272
        """Be compatible with GitRepository."""
231
 
        return (not isinstance(source, GitRepository) and 
 
273
        return (not isinstance(source, GitRepository) and
232
274
                isinstance(target, RemoteGitRepository))