/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

Rename converter -> object_store, provide utility function for getting ObjectStore's.

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