/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

Licensing information is in all of the individual files.

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