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

Remove bzr-foreign.

Show diffs side-by-side

added added

removed removed

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