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

Update NEWS.

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 os
 
20
import threading
 
21
 
19
22
import bzrlib
20
 
 
21
 
from bzrlib.errors import NoSuchRevision
22
 
 
23
 
import os
 
23
from bzrlib.errors import (
 
24
    NoSuchRevision,
 
25
    )
24
26
 
25
27
 
26
28
def check_pysqlite_version(sqlite3):
46
48
    raise bzrlib.errors.BzrError("missing sqlite library")
47
49
 
48
50
 
 
51
_mapdbs = threading.local()
 
52
def mapdbs():
 
53
    """Get a cache for this thread's db connections."""
 
54
    try:
 
55
        return _mapdbs.cache
 
56
    except AttributeError:
 
57
        _mapdbs.cache = {}
 
58
        return _mapdbs.cache
 
59
 
 
60
 
49
61
class GitShaMap(object):
50
 
 
51
 
    def __init__(self, transport):
52
 
        self.transport = transport
53
 
        self.db = sqlite3.connect(
54
 
            os.path.join(self.transport.local_abspath("."), "git.db"))
 
62
    """Git<->Bzr revision id mapping database."""
 
63
 
 
64
    def add_entry(self, sha, type, type_data):
 
65
        """Add a new entry to the database.
 
66
        """
 
67
        raise NotImplementedError(self.add_entry)
 
68
 
 
69
    def add_entries(self, entries):
 
70
        """Add multiple new entries to the database.
 
71
        """
 
72
        for e in entries:
 
73
            self.add_entry(*e)
 
74
 
 
75
    def lookup_tree(self, fileid, revid):
 
76
        """Lookup the SHA of a git tree."""
 
77
        raise NotImplementedError(self.lookup_tree)
 
78
 
 
79
    def lookup_blob(self, fileid, revid):
 
80
        """Lookup a blob by the fileid it has in a bzr revision."""
 
81
        raise NotImplementedError(self.lookup_blob)
 
82
 
 
83
    def lookup_git_sha(self, sha):
 
84
        """Lookup a Git sha in the database.
 
85
 
 
86
        :param sha: Git object sha
 
87
        :return: (type, type_data) with type_data:
 
88
            revision: revid, tree sha
 
89
        """
 
90
        raise NotImplementedError(self.lookup_git_sha)
 
91
 
 
92
    def revids(self):
 
93
        """List the revision ids known."""
 
94
        raise NotImplementedError(self.revids)
 
95
 
 
96
    def sha1s(Self):
 
97
        """List the SHA1s."""
 
98
        raise NotImplementedError(self.sha1s)
 
99
 
 
100
    def commit(self):
 
101
        """Commit any pending changes."""
 
102
 
 
103
 
 
104
class DictGitShaMap(GitShaMap):
 
105
 
 
106
    def __init__(self):
 
107
        self.dict = {}
 
108
 
 
109
    def add_entry(self, sha, type, type_data):
 
110
        self.dict[sha] = (type, type_data)
 
111
 
 
112
    def lookup_git_sha(self, sha):
 
113
        return self.dict[sha]
 
114
 
 
115
    def lookup_tree(self, fileid, revid):
 
116
        for k, v in self.dict.iteritems():
 
117
            if v == ("tree", (fileid, revid)):
 
118
                return k
 
119
        raise KeyError((fileid, revid))
 
120
 
 
121
    def lookup_blob(self, fileid, revid):
 
122
        for k, v in self.dict.iteritems():
 
123
            if v == ("blob", (fileid, revid)):
 
124
                return k
 
125
        raise KeyError((fileid, revid))
 
126
 
 
127
    def revids(self):
 
128
        for key, (type, type_data) in self.dict.iteritems():
 
129
            if type == "commit":
 
130
                yield type_data[0]
 
131
 
 
132
    def sha1s(self):
 
133
        return self.dict.iterkeys()
 
134
 
 
135
 
 
136
class SqliteGitShaMap(GitShaMap):
 
137
 
 
138
    def __init__(self, path=None):
 
139
        self.path = path
 
140
        if path is None:
 
141
            self.db = sqlite3.connect(":memory:")
 
142
        else:
 
143
            if not mapdbs().has_key(path):
 
144
                mapdbs()[path] = sqlite3.connect(path)
 
145
            self.db = mapdbs()[path]    
55
146
        self.db.executescript("""
56
147
        create table if not exists commits(sha1 text, revid text, tree_sha text);
57
148
        create index if not exists commit_sha1 on commits(sha1);
 
149
        create unique index if not exists commit_revid on commits(revid);
58
150
        create table if not exists blobs(sha1 text, fileid text, revid text);
59
151
        create index if not exists blobs_sha1 on blobs(sha1);
 
152
        create unique index if not exists blobs_fileid_revid on blobs(fileid, revid);
60
153
        create table if not exists trees(sha1 text, fileid text, revid text);
61
154
        create index if not exists trees_sha1 on trees(sha1);
 
155
        create unique index if not exists trees_fileid_revid on trees(fileid, revid);
62
156
""")
63
157
 
64
 
    def _parent_lookup(self, revid):
65
 
        return self.db.execute("select sha1 from commits where revid = ?", (revid,)).fetchone()[0].encode("utf-8")
 
158
    @classmethod
 
159
    def from_repository(cls, repository):
 
160
        return cls(os.path.join(repository._transport.local_abspath("."), "git.db"))
 
161
 
 
162
    def lookup_commit(self, revid):
 
163
        row = self.db.execute("select sha1 from commits where revid = ?", (revid,)).fetchone()
 
164
        if row is not None:
 
165
            return row[0].encode("utf-8")
 
166
        raise KeyError
 
167
 
 
168
    def commit(self):
 
169
        self.db.commit()
 
170
 
 
171
    def add_entries(self, entries):
 
172
        trees = []
 
173
        blobs = []
 
174
        for sha, type, type_data in entries:
 
175
            assert isinstance(type_data[0], str)
 
176
            assert isinstance(type_data[1], str)
 
177
            entry = (sha.decode("utf-8"), type_data[0].decode("utf-8"), 
 
178
                     type_data[1].decode("utf-8"))
 
179
            if type == "tree":
 
180
                trees.append(entry)
 
181
            elif type == "blob":
 
182
                blobs.append(entry)
 
183
            else:
 
184
                raise AssertionError
 
185
        if trees:
 
186
            self.db.executemany("replace into trees (sha1, fileid, revid) values (?, ?, ?)", trees)
 
187
        if blobs:
 
188
            self.db.executemany("replace into blobs (sha1, fileid, revid) values (?, ?, ?)", blobs)
 
189
 
66
190
 
67
191
    def add_entry(self, sha, type, type_data):
68
192
        """Add a new entry to the database.
71
195
        assert isinstance(sha, str), "type was %r" % sha
72
196
        if type == "commit":
73
197
            self.db.execute("replace into commits (sha1, revid, tree_sha) values (?, ?, ?)", (sha, type_data[0], type_data[1]))
74
 
        elif type == "blob":
75
 
            self.db.execute("replace into blobs (sha1, fileid, revid) values (?, ?, ?)", (sha, type_data[0], type_data[1]))
76
 
        elif type == "tree":
77
 
            self.db.execute("replace into trees (sha1, fileid, revid) values (?, ?, ?)", (sha, type_data[0], type_data[1]))
 
198
        elif type in ("blob", "tree"):
 
199
            self.db.execute("replace into %ss (sha1, fileid, revid) values (?, ?, ?)" % type, (sha, type_data[0], type_data[1]))
78
200
        else:
79
201
            raise AssertionError("Unknown type %s" % type)
80
202
 
 
203
    def lookup_tree(self, fileid, revid):
 
204
        row = self.db.execute("select sha1 from trees where fileid = ? and revid = ?", (fileid,revid)).fetchone()
 
205
        if row is None:
 
206
            raise KeyError((fileid, revid))
 
207
        return row[0].encode("utf-8")
 
208
 
 
209
    def lookup_blob(self, fileid, revid):
 
210
        row = self.db.execute("select sha1 from blobs where fileid = ? and revid = ?", (fileid, revid)).fetchone()
 
211
        if row is None:
 
212
            raise KeyError((fileid, revid))
 
213
        return row[0].encode("utf-8")
 
214
 
81
215
    def lookup_git_sha(self, sha):
82
216
        """Lookup a Git sha in the database.
83
217
 
85
219
        :return: (type, type_data) with type_data:
86
220
            revision: revid, tree sha
87
221
        """
 
222
        def format(type, row):
 
223
            return (type, (row[0].encode("utf-8"), row[1].encode("utf-8")))
88
224
        row = self.db.execute("select revid, tree_sha from commits where sha1 = ?", (sha,)).fetchone()
89
225
        if row is not None:
90
 
            return ("commit", row)
 
226
            return format("commit", row)
91
227
        row = self.db.execute("select fileid, revid from blobs where sha1 = ?", (sha,)).fetchone()
92
228
        if row is not None:
93
 
            return ("blob", row)
 
229
            return format("blob", row)
94
230
        row = self.db.execute("select fileid, revid from trees where sha1 = ?", (sha,)).fetchone()
95
231
        if row is not None:
96
 
            return ("tree", row)
 
232
            return format("tree", row)
97
233
        raise KeyError(sha)
98
234
 
99
235
    def revids(self):
 
236
        """List the revision ids known."""
100
237
        for row in self.db.execute("select revid from commits").fetchall():
101
 
            yield row[0]
 
238
            yield row[0].encode("utf-8")
 
239
 
 
240
    def sha1s(self):
 
241
        """List the SHA1s."""
 
242
        for table in ("blobs", "commits", "trees"):
 
243
            for row in self.db.execute("select sha1 from %s" % table).fetchall():
 
244
                yield row[0].encode("utf-8")
 
245
 
 
246
 
 
247
TDB_MAP_VERSION = 1
 
248
 
 
249
 
 
250
class TdbGitShaMap(GitShaMap):
 
251
    """SHA Map that uses a TDB database.
 
252
 
 
253
    Entries:
 
254
 
 
255
    "git <sha1>" -> "<type> <type-data1> <type-data2>"
 
256
    "commit revid" -> "<sha1> <tree-id>"
 
257
    "tree fileid revid" -> "<sha1>"
 
258
    "blob fileid revid" -> "<sha1>"
 
259
    """
 
260
 
 
261
    def __init__(self, path=None):
 
262
        import tdb
 
263
        self.path = path
 
264
        if path is None:
 
265
            self.db = {}
 
266
        else:
 
267
            if not mapdbs().has_key(path):
 
268
                mapdbs()[path] = tdb.open(path, 0, tdb.DEFAULT, 
 
269
                                          os.O_RDWR|os.O_CREAT)
 
270
            self.db = mapdbs()[path]    
 
271
        if not "version" in self.db:
 
272
            self.db["version"] = str(TDB_MAP_VERSION)
 
273
        else:
 
274
            assert int(self.db["version"]) == TDB_MAP_VERSION
 
275
 
 
276
    @classmethod
 
277
    def from_repository(cls, repository):
 
278
        try:
 
279
            return cls(os.path.join(repository._transport.local_abspath("."), "git.tdb"))
 
280
        except bzrlib.errors.NotLocalUrl:
 
281
            from bzrlib.config import config_dir
 
282
            return cls(os.path.join(config_dir(), "remote-git.tdb"))
 
283
 
 
284
    def lookup_commit(self, revid):
 
285
        return self.db["commit %s" % revid].split(" ")[0]
 
286
 
 
287
    def commit(self):
 
288
        pass
 
289
 
 
290
    def add_entry(self, sha, type, type_data):
 
291
        """Add a new entry to the database.
 
292
        """
 
293
        self.db["git %s" % sha] = "%s %s %s" % (type, type_data[0], type_data[1])
 
294
        if type == "commit":
 
295
            self.db["commit %s" % type_data[0]] = "%s %s" % (sha, type_data[1])
 
296
        else:
 
297
            self.db["%s %s %s" % (type, type_data[0], type_data[1])] = sha
 
298
 
 
299
    def lookup_tree(self, fileid, revid):
 
300
        return self.db["tree %s %s" % (fileid, revid)]
 
301
 
 
302
    def lookup_blob(self, fileid, revid):
 
303
        return self.db["blob %s %s" % (fileid, revid)]
 
304
 
 
305
    def lookup_git_sha(self, sha):
 
306
        """Lookup a Git sha in the database.
 
307
 
 
308
        :param sha: Git object sha
 
309
        :return: (type, type_data) with type_data:
 
310
            revision: revid, tree sha
 
311
        """
 
312
        data = self.db["git %s" % sha].split(" ")
 
313
        return (data[0], (data[1], data[2]))
 
314
 
 
315
    def revids(self):
 
316
        """List the revision ids known."""
 
317
        for key in self.db.iterkeys():
 
318
            if key.startswith("commit "):
 
319
                yield key.split(" ")[1]
 
320
 
 
321
    def sha1s(self):
 
322
        """List the SHA1s."""
 
323
        for key in self.db.iterkeys():
 
324
            if key.startswith("git "):
 
325
                yield key.split(" ")[1]