/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
    )
47
51
 
48
52
    """
49
53
 
50
 
    def __init__(self, source, mapping, pb=None):
 
54
    def __init__(self, store, source, pb=None):
51
55
        """Create a new missing objects iterator.
52
56
 
53
57
        """
54
58
        self.source = source
55
 
        self._object_store = BazaarObjectStore(self.source, mapping)
56
 
        self._revids = set()
57
 
        self._sent_shas = set()
 
59
        self._object_store = store
58
60
        self._pending = []
59
61
        self.pb = pb
60
62
 
61
 
    def import_revisions(self, revids):
62
 
        self._revids.update(revids)
 
63
    def import_revisions(self, revids, roundtrip):
63
64
        for i, revid in enumerate(revids):
64
65
            if self.pb:
65
66
                self.pb.update("pushing revisions", i, len(revids))
66
 
            git_commit = self.import_revision(revid)
 
67
            git_commit = self.import_revision(revid, roundtrip)
67
68
            yield (revid, git_commit)
68
69
 
69
 
    def need_sha(self, sha):
70
 
        if sha in self._sent_shas:
71
 
            return False
72
 
        (type, (fileid, revid)) = self._object_store._idmap.lookup_git_sha(sha)
73
 
        assert type in ("blob", "tree")
74
 
        if revid in self._revids:
75
 
            # Not sent yet, and part of the set of revisions to send
76
 
            return True
77
 
        # Not changed in the revisions to send, so either not necessary
78
 
        # or already present remotely (as git doesn't do ghosts)
79
 
        return False
80
 
 
81
 
    def queue(self, sha, obj, path, ie=None, inv=None):
82
 
        if obj is None:
83
 
            obj = (ie, inv)
84
 
        self._pending.append((obj, path))
85
 
        self._sent_shas.add(sha)
86
 
 
87
 
    def import_revision(self, revid):
 
70
    def import_revision(self, revid, roundtrip):
88
71
        """Import the gist of a revision into this Git repository.
89
72
 
90
73
        """
91
 
        inv = self.source.get_inventory(revid)
92
 
        todo = [inv.root]
93
 
        tree_sha = None
94
 
        while todo:
95
 
            ie = todo.pop()
96
 
            (sha, object) = self._object_store._get_ie_object_or_sha1(ie, inv)
97
 
            if ie.parent_id is None:
98
 
                tree_sha = sha
99
 
            if not self.need_sha(sha):
100
 
                continue
101
 
            self.queue(sha, object, inv.id2path(ie.file_id), ie, inv)
102
 
            if ie.kind == "directory":
103
 
                todo.extend(ie.children.values())
104
 
        assert tree_sha is not None
105
 
        commit = self._object_store._get_commit(revid, tree_sha)
106
 
        self.queue(commit.id, commit, None)
 
74
        tree = self._object_store.tree_cache.revision_tree(revid)
 
75
        rev = self.source.get_revision(revid)
 
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))
107
82
        return commit.id
108
83
 
109
84
    def __len__(self):
110
85
        return len(self._pending)
111
86
 
112
87
    def __iter__(self):
113
 
        for i, (object, path) in enumerate(self._pending):
114
 
            if self.pb:
115
 
                self.pb.update("writing pack objects", i, len(self))
116
 
            if isinstance(object, tuple):
117
 
                object = self._object_store._get_ie_object(*object)
118
 
            yield (object, path)   
 
88
        return iter(self._pending)
119
89
 
120
90
 
121
91
class InterToGitRepository(InterRepository):
126
96
    def __init__(self, source, target):
127
97
        super(InterToGitRepository, self).__init__(source, target)
128
98
        self.mapping = self.target.get_mapping()
 
99
        self.source_store = BazaarObjectStore(self.source, self.mapping)
129
100
 
130
101
    @staticmethod
131
102
    def _get_repo_format_to_test():
135
106
        """See InterRepository.copy_content."""
136
107
        self.fetch(revision_id, pb, find_ghosts=False)
137
108
 
138
 
    def fetch(self, revision_id=None, pb=None, find_ghosts=False, 
139
 
            fetch_spec=None):
140
 
        raise NoPushSupport()
141
 
 
142
109
 
143
110
class InterToLocalGitRepository(InterToGitRepository):
144
111
 
145
 
    def missing_revisions(self, stop_revision):
146
 
        if stop_revision is None:
147
 
            raise NotImplementedError
 
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
 
 
117
    def missing_revisions(self, stop_revisions, check_revid):
148
118
        missing = []
149
119
        pb = ui.ui_factory.nested_progress_bar()
150
120
        try:
151
121
            graph = self.source.get_graph()
152
 
            for revid, _ in graph.iter_ancestry([stop_revision]):
 
122
            for revid, _ in graph.iter_ancestry(stop_revisions):
153
123
                pb.update("determining revisions to fetch", len(missing))
154
 
                if not self.target.has_revision(revid):
 
124
                if not check_revid(revid):
155
125
                    missing.append(revid)
156
126
            return graph.iter_topo_order(missing)
157
127
        finally:
158
128
            pb.finished()
159
129
 
 
130
    def fetch_refs(self, refs):
 
131
        fetch_spec = PendingAncestryResult(refs.values(), self.source)
 
132
        self.fetch(fetch_spec=fetch_spec)
 
133
 
160
134
    def dfetch_refs(self, refs):
161
 
        revidmap = {}
162
 
        new_refs = {}
 
135
        old_refs = self.target._git.get_refs()
 
136
        new_refs = dict(old_refs)
 
137
        revidmap, gitidmap = self.dfetch(refs.values())
163
138
        for name, revid in refs.iteritems():
164
 
            newrevidmap, newgitidmap = self.dfetch(revid)
165
 
            revidmap.update(newrevidmap)
166
 
            if revid in newgitidmap:
167
 
                gitid = newgitidmap[revid]
168
 
            else:
169
 
                gitid, _ = self.mapping.revision_id_bzr_to_foreign(revid)
 
139
            try:
 
140
                gitid = gitidmap[revid]
 
141
            except KeyError:
 
142
                gitid = self.source_store._lookup_revision_sha1(revid)
170
143
            self.target._git.refs[name] = gitid
171
144
            new_refs[name] = gitid
172
 
        return revidmap, new_refs
173
 
 
174
 
    def dfetch(self, stop_revision=None):
 
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))
 
157
 
 
158
    def dfetch(self, stop_revisions):
175
159
        """Import the gist of the ancestry of a particular revision."""
176
160
        gitidmap = {}
177
161
        revidmap = {}
178
162
        self.source.lock_read()
179
163
        try:
180
 
            todo = [revid for revid in self.missing_revisions(stop_revision) if revid != NULL_REVISION]
 
164
            todo = self._find_missing_revs(stop_revisions)
181
165
            pb = ui.ui_factory.nested_progress_bar()
182
166
            try:
183
 
                object_generator = MissingObjectsIterator(self.source, self.mapping, pb)
 
167
                object_generator = MissingObjectsIterator(self.source_store,
 
168
                    self.source, pb)
184
169
                for old_bzr_revid, git_commit in object_generator.import_revisions(
185
 
                    todo):
 
170
                    todo, roundtrip=False):
186
171
                    new_bzr_revid = self.mapping.revision_id_foreign_to_bzr(git_commit)
187
172
                    revidmap[old_bzr_revid] = new_bzr_revid
188
173
                    gitidmap[old_bzr_revid] = git_commit
189
 
                self.target._git.object_store.add_objects(object_generator) 
 
174
                self.target_store.add_objects(object_generator)
190
175
            finally:
191
176
                pb.finished()
192
177
        finally:
193
178
            self.source.unlock()
194
179
        return revidmap, gitidmap
195
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
 
196
208
    @staticmethod
197
209
    def is_compatible(source, target):
198
210
        """Be compatible with GitRepository."""
199
 
        return (not isinstance(source, GitRepository) and 
 
211
        return (not isinstance(source, GitRepository) and
200
212
                isinstance(target, LocalGitRepository))
201
213
 
202
214
 
205
217
    def dfetch_refs(self, new_refs):
206
218
        """Import the gist of the ancestry of a particular revision."""
207
219
        revidmap = {}
 
220
        old_refs = {}
208
221
        def determine_wants(refs):
209
222
            ret = {}
 
223
            old_refs.update(new_refs)
210
224
            for name, revid in new_refs.iteritems():
211
 
                ret[name] = store._lookup_revision_sha1(revid)
 
225
                ret[name] = self.source_store._lookup_revision_sha1(revid)
212
226
            return ret
213
227
        self.source.lock_read()
214
228
        try:
215
 
            store = BazaarObjectStore(self.source, self.mapping)
216
 
            def generate_blob_contents(have, want):
217
 
                return store.iter_shas(store.find_missing_objects(have, want))
218
229
            new_refs = self.target.send_pack(determine_wants,
219
 
                    generate_blob_contents)
 
230
                    self.source_store.generate_lossy_pack_contents)
220
231
        finally:
221
232
            self.source.unlock()
222
 
        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()
223
238
 
224
239
    @staticmethod
225
240
    def is_compatible(source, target):
226
241
        """Be compatible with GitRepository."""
227
 
        return (not isinstance(source, GitRepository) and 
 
242
        return (not isinstance(source, GitRepository) and
228
243
                isinstance(target, RemoteGitRepository))