/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

  • Committer: Invité
  • Date: 2009-05-05 20:43:26 UTC
  • mto: (0.200.441 trunk)
  • mto: This revision was merged to the branch mainline in revision 6960.
  • Revision ID: guest@mirexpress-20090505204326-n0vcprylu2hyzq4v
Ensure git plugin is loaded in bzr-*-pack

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