/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-05-13 08:40:18 UTC
  • mto: (0.200.912 trunk)
  • mto: This revision was merged to the branch mainline in revision 6960.
  • Revision ID: jelmer@samba.org-20100513084018-xp9tbrasde6gih3o
Checks for roundtripping.

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()
147
 
 
148
109
 
149
110
class InterToLocalGitRepository(InterToGitRepository):
150
111
 
 
112
    def __init__(self, source, target):
 
113
        super(InterToLocalGitRepository, self).__init__(source, target)
 
114
        self.target_store = self.target._git.object_store
 
115
        self.target_refs = self.target._git.refs
 
116
 
151
117
    def missing_revisions(self, stop_revisions, check_revid):
152
118
        missing = []
153
119
        pb = ui.ui_factory.nested_progress_bar()
161
127
        finally:
162
128
            pb.finished()
163
129
 
 
130
    def fetch_refs(self, refs):
 
131
        fetch_spec = PendingAncestryResult(refs.values(), self.source)
 
132
        self.fetch(fetch_spec=fetch_spec)
 
133
 
164
134
    def dfetch_refs(self, refs):
165
 
        new_refs = {}
 
135
        old_refs = self.target._git.get_refs()
 
136
        new_refs = dict(old_refs)
166
137
        revidmap, gitidmap = self.dfetch(refs.values())
167
138
        for name, revid in refs.iteritems():
168
 
            if revid in gitidmap:
 
139
            try:
169
140
                gitid = gitidmap[revid]
170
 
            else:
 
141
            except KeyError:
171
142
                gitid = self.source_store._lookup_revision_sha1(revid)
172
143
            self.target._git.refs[name] = gitid
173
144
            new_refs[name] = gitid
174
 
        return revidmap, new_refs
 
145
        return revidmap, old_refs, new_refs
 
146
 
 
147
    def _find_missing_revs(self, stop_revisions):
 
148
        def check_revid(revid):
 
149
            if revid == NULL_REVISION:
 
150
                return True
 
151
            try:
 
152
                return (self.source_store._lookup_revision_sha1(revid) in self.target_store)
 
153
            except errors.NoSuchRevision:
 
154
                # Ghost, can't dpush
 
155
                return True
 
156
        return list(self.missing_revisions(stop_revisions, check_revid))
175
157
 
176
158
    def dfetch(self, stop_revisions):
177
159
        """Import the gist of the ancestry of a particular revision."""
179
161
        revidmap = {}
180
162
        self.source.lock_read()
181
163
        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))
 
164
            todo = self._find_missing_revs(stop_revisions)
188
165
            pb = ui.ui_factory.nested_progress_bar()
189
166
            try:
190
 
                object_generator = MissingObjectsIterator(self.source_store, self.source, pb)
 
167
                object_generator = MissingObjectsIterator(self.source_store,
 
168
                    self.source, pb)
191
169
                for old_bzr_revid, git_commit in object_generator.import_revisions(
192
 
                    todo):
 
170
                    todo, roundtrip=False):
193
171
                    new_bzr_revid = self.mapping.revision_id_foreign_to_bzr(git_commit)
194
172
                    revidmap[old_bzr_revid] = new_bzr_revid
195
173
                    gitidmap[old_bzr_revid] = git_commit
196
 
                target_store.add_objects(object_generator) 
 
174
                self.target_store.add_objects(object_generator)
197
175
            finally:
198
176
                pb.finished()
199
177
        finally:
200
178
            self.source.unlock()
201
179
        return revidmap, gitidmap
202
180
 
 
181
    def fetch(self, revision_id=None, pb=None, find_ghosts=False,
 
182
            fetch_spec=None):
 
183
        if revision_id is not None:
 
184
            stop_revisions = [revision_id]
 
185
        elif fetch_spec is not None:
 
186
            stop_revisions = fetch_spec.heads
 
187
        else:
 
188
            stop_revisions = self.source.all_revision_ids()
 
189
        self.source.lock_read()
 
190
        try:
 
191
            todo = self._find_missing_revs(stop_revisions)
 
192
            pb = ui.ui_factory.nested_progress_bar()
 
193
            try:
 
194
                object_generator = MissingObjectsIterator(self.source_store,
 
195
                    self.source, pb)
 
196
                for (revid, git_sha) in object_generator.import_revisions(
 
197
                    todo, roundtrip=True):
 
198
                    try:
 
199
                        self.mapping.revision_id_bzr_to_foreign(revid)
 
200
                    except errors.InvalidRevisionId:
 
201
                        self.target_refs[self.mapping.revid_as_refname(revid)] = git_sha
 
202
                self.target_store.add_objects(object_generator)
 
203
            finally:
 
204
                pb.finished()
 
205
        finally:
 
206
            self.source.unlock()
 
207
 
203
208
    @staticmethod
204
209
    def is_compatible(source, target):
205
210
        """Be compatible with GitRepository."""
206
 
        return (not isinstance(source, GitRepository) and 
 
211
        return (not isinstance(source, GitRepository) and
207
212
                isinstance(target, LocalGitRepository))
208
213
 
209
214
 
212
217
    def dfetch_refs(self, new_refs):
213
218
        """Import the gist of the ancestry of a particular revision."""
214
219
        revidmap = {}
 
220
        old_refs = {}
215
221
        def determine_wants(refs):
216
222
            ret = {}
 
223
            old_refs.update(new_refs)
217
224
            for name, revid in new_refs.iteritems():
218
225
                ret[name] = self.source_store._lookup_revision_sha1(revid)
219
226
            return ret
220
227
        self.source.lock_read()
221
228
        try:
222
229
            new_refs = self.target.send_pack(determine_wants,
223
 
                    self.source_store.generate_pack_contents)
 
230
                    self.source_store.generate_lossy_pack_contents)
224
231
        finally:
225
232
            self.source.unlock()
226
 
        return revidmap, new_refs
 
233
        return revidmap, old_refs, new_refs
 
234
 
 
235
    def fetch(self, revision_id=None, pb=None, find_ghosts=False,
 
236
            fetch_spec=None):
 
237
        raise NoPushSupport()
227
238
 
228
239
    @staticmethod
229
240
    def is_compatible(source, target):
230
241
        """Be compatible with GitRepository."""
231
 
        return (not isinstance(source, GitRepository) and 
 
242
        return (not isinstance(source, GitRepository) and
232
243
                isinstance(target, RemoteGitRepository))