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

Partially fix pull.

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 Canonical Ltd
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
16
16
 
17
17
"""Map from Git sha's to Bazaar objects."""
18
18
 
 
19
import bzrlib
 
20
 
 
21
from bzrlib import ui
 
22
 
 
23
from bzrlib.errors import NoSuchRevision
 
24
 
 
25
from bzrlib.plugins.git.mapping import (
 
26
    inventory_to_tree_and_blobs,
 
27
    revision_to_commit,
 
28
    )
 
29
from bzrlib.plugins.git.shamap import GitShaMap
 
30
 
19
31
from dulwich.objects import (
20
32
    Blob,
21
 
    Tree,
22
 
    )
23
 
from dulwich.object_store import (
24
 
    BaseObjectStore,
25
 
    ObjectStoreIterator,
26
 
    )
27
 
import stat
28
 
 
29
 
from bzrlib import (
30
 
    debug,
31
 
    errors,
32
 
    trace,
33
 
    ui,
34
 
    )
35
 
from bzrlib.revision import (
36
 
    NULL_REVISION,
37
 
    )
38
 
 
39
 
from bzrlib.plugins.git.errors import (
40
 
    GhostRevision,
41
 
    )
42
 
 
43
 
from bzrlib.plugins.git.mapping import (
44
 
    default_mapping,
45
 
    directory_to_tree,
46
 
    extract_unusual_modes,
47
 
    mapping_registry,
48
 
    revision_to_commit,
49
 
    )
50
 
from bzrlib.plugins.git.shamap import (
51
 
    SqliteGitShaMap,
52
 
    TdbGitShaMap,
53
 
    )
54
 
 
55
 
 
56
 
def get_object_store(repo, mapping=None):
57
 
    git = getattr(repo, "_git", None)
58
 
    if git is not None:
59
 
        return git.object_store
60
 
    return BazaarObjectStore(repo, mapping)
61
 
 
62
 
 
63
 
class BazaarObjectStore(BaseObjectStore):
64
 
    """A Git-style object store backed onto a Bazaar repository."""
 
33
    )
 
34
 
 
35
 
 
36
class GitObjectConverter(object):
65
37
 
66
38
    def __init__(self, repository, mapping=None):
67
39
        self.repository = repository
68
40
        if mapping is None:
69
 
            self.mapping = default_mapping
 
41
            self.mapping = self.repository.get_mapping()
70
42
        else:
71
43
            self.mapping = mapping
72
 
        try:
73
 
            self._idmap = TdbGitShaMap.from_repository(repository)
74
 
        except ImportError:
75
 
            self._idmap = SqliteGitShaMap.from_repository(repository)
 
44
        self._idmap = GitShaMap(self.repository._transport)
76
45
 
77
 
    def _update_sha_map(self, stop_revision=None):
78
 
        if stop_revision is None:
79
 
            all_revids = self.repository.all_revision_ids()
80
 
        else:
81
 
            all_revids = self.repository.get_ancestry(stop_revision)
82
 
            first = all_revids.pop(0) # Pop leading None
83
 
            assert first is None
 
46
    def _update_sha_map(self):
 
47
        all_revids = self.repository.all_revision_ids()
84
48
        graph = self.repository.get_graph()
85
49
        present_revids = set(self._idmap.revids())
86
 
        missing_revids = [revid for revid in graph.iter_topo_order(all_revids) if revid not in present_revids]
87
50
        pb = ui.ui_factory.nested_progress_bar()
88
51
        try:
89
 
            for i, revid in enumerate(missing_revids):
90
 
                pb.update("updating git map", i, len(missing_revids))
 
52
            for i, revid in enumerate(graph.iter_topo_order(all_revids)):
 
53
                if revid in present_revids:
 
54
                    continue
 
55
                pb.update("updating git map", i, len(all_revids))
91
56
                self._update_sha_map_revision(revid)
92
57
        finally:
93
 
            self._idmap.commit()
94
58
            pb.finished()
95
59
 
96
 
    def __iter__(self):
97
 
        self._update_sha_map()
98
 
        return iter(self._idmap.sha1s())
99
 
 
100
60
    def _update_sha_map_revision(self, revid):
101
61
        inv = self.repository.get_inventory(revid)
 
62
        objects = inventory_to_tree_and_blobs(self.repository, self.mapping, revid)
 
63
        for sha, o, path in objects:
 
64
            if path == "":
 
65
                tree_sha = sha
 
66
            ie = inv[inv.path2id(path)]
 
67
            if ie.kind in ("file", "symlink"):
 
68
                self._idmap.add_entry(sha, "blob", (ie.file_id, ie.revision))
 
69
            else:
 
70
                self._idmap.add_entry(sha, "tree", (ie.file_id, ie.revision))
102
71
        rev = self.repository.get_revision(revid)
103
 
        unusual_modes = extract_unusual_modes(rev)
104
 
        tree_sha = self._get_ie_sha1(inv.root, inv, unusual_modes)
105
 
        commit_obj = revision_to_commit(rev, tree_sha,
106
 
                                        self._idmap.lookup_commit)
107
 
        try:
108
 
            foreign_revid, mapping = mapping_registry.parse_revision_id(revid)
109
 
        except errors.InvalidRevisionId:
110
 
            pass
111
 
        else:
112
 
            if foreign_revid != commit_obj.id:
113
 
                if not "fix-shamap" in debug.debug_flags:
114
 
                    raise AssertionError("recreated git commit had different sha1: expected %s, got %s" % (foreign_revid, commit_obj.id))
115
 
        self._idmap.add_entry(commit_obj.id, "commit", (revid, tree_sha))
116
 
 
117
 
    def _check_expected_sha(self, expected_sha, object):
118
 
        if expected_sha is None:
119
 
            return
120
 
        if expected_sha != object.id:
121
 
            raise AssertionError("Invalid sha for %r: %s" % (object, expected_sha))
122
 
 
123
 
    def _get_ie_object(self, entry, inv, unusual_modes):  
124
 
        if entry.kind == "directory":
125
 
            return self._get_tree(entry.file_id, inv.revision_id, inv, unusual_modes)
126
 
        else:
127
 
            return self._get_blob(entry.file_id, entry.revision)
128
 
 
129
 
    def _get_ie_object_or_sha1(self, entry, inv, unusual_modes):
130
 
        if entry.kind == "directory":
131
 
            try:
132
 
                return self._idmap.lookup_tree(entry.file_id, inv.revision_id), None
133
 
            except KeyError:
134
 
                ret = self._get_ie_object(entry, inv, unusual_modes)
135
 
                self._idmap.add_entry(ret.id, "tree", (entry.file_id, inv.revision_id))
136
 
                return ret.id, ret
137
 
        else:
138
 
            try:
139
 
                return self._idmap.lookup_blob(entry.file_id, entry.revision), None
140
 
            except KeyError:
141
 
                ret = self._get_ie_object(entry, inv, unusual_modes)
142
 
                self._idmap.add_entry(ret.id, "blob", (entry.file_id, entry.revision))
143
 
                return ret.id, ret
144
 
 
145
 
    def _get_ie_sha1(self, entry, inv, unusual_modes):
146
 
        return self._get_ie_object_or_sha1(entry, inv, unusual_modes)[0]
147
 
 
148
 
    def _get_blob(self, fileid, revision, expected_sha=None):
149
 
        """Return a Git Blob object from a fileid and revision stored in bzr.
150
 
        
151
 
        :param fileid: File id of the text
152
 
        :param revision: Revision of the text
153
 
        """
154
 
        text = self.repository.texts.get_record_stream([(fileid, revision)],
155
 
            "unordered", True).next().get_bytes_as("fulltext")
 
72
        commit_obj = revision_to_commit(rev, tree_sha, self._idmap._parent_lookup)
 
73
        self._idmap.add_entry(commit_obj.sha().hexdigest(), "commit", (revid, tree_sha))
 
74
 
 
75
    def _get_blob(self, fileid, revision):
 
76
        text = self.repository.texts.get_record_stream([(fileid, revision)], "unordered", True).next().get_bytes_as("fulltext")
156
77
        blob = Blob()
157
78
        blob._text = text
158
 
        self._check_expected_sha(expected_sha, blob)
159
79
        return blob
160
80
 
161
 
    def _get_tree(self, fileid, revid, inv, unusual_modes, expected_sha=None):
162
 
        """Return a Git Tree object from a file id and a revision stored in bzr.
163
 
 
164
 
        :param fileid: fileid in the tree.
165
 
        :param revision: Revision of the tree.
166
 
        """
167
 
        tree = directory_to_tree(inv[fileid], 
168
 
            lambda ie: self._get_ie_sha1(ie, inv, unusual_modes),
169
 
            unusual_modes)
170
 
        self._check_expected_sha(expected_sha, tree)
171
 
        return tree
172
 
 
173
 
    def _get_commit(self, rev, tree_sha, expected_sha=None):
174
 
        try:
175
 
            commit = revision_to_commit(rev, tree_sha, self._lookup_revision_sha1)
176
 
        except errors.NoSuchRevision, e:
177
 
            raise GhostRevision(e.branch, e.revision)
178
 
        self._check_expected_sha(expected_sha, commit)
179
 
        return commit
180
 
 
181
 
    def get_parents(self, sha):
182
 
        """Retrieve the parents of a Git commit by SHA1.
183
 
 
184
 
        :param sha: SHA1 of the commit
185
 
        :raises: KeyError, NotCommitError
186
 
        """
187
 
        return self[sha].parents
188
 
 
189
 
    def _lookup_revision_sha1(self, revid):
190
 
        """Return the SHA1 matching a Bazaar revision."""
191
 
        if revid == NULL_REVISION:
192
 
            return "0" * 40
193
 
        try:
194
 
            return self._idmap.lookup_commit(revid)
195
 
        except KeyError:
196
 
            self._update_sha_map(revid)
197
 
            return self._idmap.lookup_commit(revid)
198
 
 
199
 
    def get_raw(self, sha):
200
 
        """Get the raw representation of a Git object by SHA1.
201
 
 
202
 
        :param sha: SHA1 of the git object
203
 
        """
204
 
        return self[sha].as_raw_string()
205
 
 
206
 
    def __contains__(self, sha):
207
 
        # See if sha is in map
208
 
        try:
209
 
            self._lookup_git_sha(sha)
210
 
        except KeyError:
211
 
            return False
212
 
        else:
213
 
            return True
214
 
 
215
 
    def _lookup_git_sha(self, sha):
216
 
        # See if sha is in map
217
 
        try:
218
 
            return self._idmap.lookup_git_sha(sha)
 
81
    def _get_tree(self, fileid, revid):
 
82
        raise NotImplementedError(self._get_tree)
 
83
 
 
84
    def _get_commit(self, revid, tree_sha):
 
85
        rev = self.repository.get_revision(revid)
 
86
        return revision_to_commit(rev, tree_sha, self._idmap._parent_lookup)
 
87
 
 
88
    def __getitem__(self, sha):
 
89
        # See if sha is in map
 
90
        try:
 
91
            (type, type_data) = self._idmap.lookup_git_sha(sha)
219
92
        except KeyError:
220
93
            # if not, see if there are any unconverted revisions and add them 
221
94
            # to the map, search for sha in map again
222
95
            self._update_sha_map()
223
 
            return self._idmap.lookup_git_sha(sha)
224
 
 
225
 
    def __getitem__(self, sha):
226
 
        (type, type_data) = self._lookup_git_sha(sha)
 
96
            (type, type_data) = self._idmap.lookup_git_sha(sha)
227
97
        # convert object to git object
228
98
        if type == "commit":
229
 
            try:
230
 
                rev = self.repository.get_revision(type_data[0])
231
 
            except errors.NoSuchRevision:
232
 
                trace.mutter('entry for %s %s in shamap: %r, but not found in repository', type, sha, type_data)
233
 
                raise KeyError(sha)
234
 
            return self._get_commit(rev, type_data[1], expected_sha=sha)
 
99
            return self._get_commit(*type_data)
235
100
        elif type == "blob":
236
 
            return self._get_blob(type_data[0], type_data[1], expected_sha=sha)
 
101
            return self._get_blob(*type_data)
237
102
        elif type == "tree":
238
 
            inv = self.repository.get_inventory(type_data[1])
239
 
            rev = self.repository.get_revision(type_data[1])
240
 
            unusual_modes = extract_unusual_modes(rev)
241
 
            try:
242
 
                return self._get_tree(type_data[0], type_data[1], inv, unusual_modes,
243
 
                                      expected_sha=sha)
244
 
            except errors.NoSuchRevision:
245
 
                raise KeyError(sha)
 
103
            return self._get_tree(*type_data)
246
104
        else:
247
105
            raise AssertionError("Unknown object type '%s'" % type)