/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.200.252 by Jelmer Vernooij
Clarify history, copyright.
1
# Copyright (C) 2009 Jelmer Vernooij <jelmer@samba.org>
0.200.226 by Jelmer Vernooij
Merge thin-pack work.
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
"""Map from Git sha's to Bazaar objects."""
18
0.235.1 by Jelmer Vernooij
Store sha map more efficiently.
19
from dulwich.objects import (
20
    sha_to_hex,
21
    hex_to_sha,
22
    )
0.200.292 by Jelmer Vernooij
Fix formatting.
23
import os
0.200.365 by Jelmer Vernooij
Share sha map cache connections inside threads.
24
import threading
0.200.292 by Jelmer Vernooij
Fix formatting.
25
0.200.228 by Jelmer Vernooij
Split out map.
26
import bzrlib
0.200.528 by Jelmer Vernooij
Fix import.
27
from bzrlib import (
28
    trace,
29
    )
0.200.292 by Jelmer Vernooij
Fix formatting.
30
from bzrlib.errors import (
31
    NoSuchRevision,
32
    )
0.200.230 by Jelmer Vernooij
Implement sha cache.
33
0.200.226 by Jelmer Vernooij
Merge thin-pack work.
34
0.200.534 by Jelmer Vernooij
Use XDG cache directory if the python xdg module is available.
35
def get_cache_dir():
36
    try:
37
        from xdg.BaseDirectory import xdg_cache_home
38
    except ImportError:
39
        pass
40
    else:
41
        return os.path.join(xdg_cache_home, "bazaar", "git")
42
    from bzrlib.config import config_dir
43
    return os.path.join(config_dir(), "git")
44
45
0.200.228 by Jelmer Vernooij
Split out map.
46
def check_pysqlite_version(sqlite3):
47
    """Check that sqlite library is compatible.
48
49
    """
50
    if (sqlite3.sqlite_version_info[0] < 3 or 
51
            (sqlite3.sqlite_version_info[0] == 3 and 
52
             sqlite3.sqlite_version_info[1] < 3)):
53
        warning('Needs at least sqlite 3.3.x')
54
        raise bzrlib.errors.BzrError("incompatible sqlite library")
55
56
try:
57
    try:
58
        import sqlite3
59
        check_pysqlite_version(sqlite3)
60
    except (ImportError, bzrlib.errors.BzrError), e: 
61
        from pysqlite2 import dbapi2 as sqlite3
62
        check_pysqlite_version(sqlite3)
63
except:
64
    warning('Needs at least Python2.5 or Python2.4 with the pysqlite2 '
65
            'module')
66
    raise bzrlib.errors.BzrError("missing sqlite library")
67
0.200.226 by Jelmer Vernooij
Merge thin-pack work.
68
0.200.365 by Jelmer Vernooij
Share sha map cache connections inside threads.
69
_mapdbs = threading.local()
70
def mapdbs():
71
    """Get a cache for this thread's db connections."""
72
    try:
73
        return _mapdbs.cache
74
    except AttributeError:
75
        _mapdbs.cache = {}
76
        return _mapdbs.cache
77
78
0.200.226 by Jelmer Vernooij
Merge thin-pack work.
79
class GitShaMap(object):
0.200.260 by Jelmer Vernooij
Add DictGitShaMap, useful for testing.
80
    """Git<->Bzr revision id mapping database."""
81
82
    def add_entry(self, sha, type, type_data):
83
        """Add a new entry to the database.
84
        """
85
        raise NotImplementedError(self.add_entry)
86
0.200.361 by Jelmer Vernooij
Fix existing object lookup issues when pulling from remote branches.
87
    def add_entries(self, entries):
88
        """Add multiple new entries to the database.
89
        """
90
        for e in entries:
91
            self.add_entry(*e)
92
0.200.343 by Jelmer Vernooij
Use file ids consistently in map.
93
    def lookup_tree(self, fileid, revid):
0.200.287 by Jelmer Vernooij
Skip tree sha's already in the git sha map.
94
        """Lookup the SHA of a git tree."""
95
        raise NotImplementedError(self.lookup_tree)
96
0.230.2 by Jelmer Vernooij
Fix versionedfiles.
97
    def lookup_blob(self, fileid, revid):
0.200.477 by Jelmer Vernooij
More tests for sha maps, fix cache misses in tdb.
98
        """Lookup a blob by the fileid it has in a bzr revision."""
0.230.2 by Jelmer Vernooij
Fix versionedfiles.
99
        raise NotImplementedError(self.lookup_blob)
100
0.200.260 by Jelmer Vernooij
Add DictGitShaMap, useful for testing.
101
    def lookup_git_sha(self, sha):
102
        """Lookup a Git sha in the database.
103
104
        :param sha: Git object sha
105
        :return: (type, type_data) with type_data:
106
            revision: revid, tree sha
107
        """
108
        raise NotImplementedError(self.lookup_git_sha)
109
110
    def revids(self):
111
        """List the revision ids known."""
112
        raise NotImplementedError(self.revids)
113
0.200.422 by Jelmer Vernooij
'bzr git-object' without arguments now prints the available git objects.
114
    def sha1s(Self):
115
        """List the SHA1s."""
116
        raise NotImplementedError(self.sha1s)
117
0.200.260 by Jelmer Vernooij
Add DictGitShaMap, useful for testing.
118
    def commit(self):
119
        """Commit any pending changes."""
120
121
122
class DictGitShaMap(GitShaMap):
123
124
    def __init__(self):
125
        self.dict = {}
126
127
    def add_entry(self, sha, type, type_data):
128
        self.dict[sha] = (type, type_data)
129
130
    def lookup_git_sha(self, sha):
131
        return self.dict[sha]
132
0.200.343 by Jelmer Vernooij
Use file ids consistently in map.
133
    def lookup_tree(self, fileid, revid):
0.200.287 by Jelmer Vernooij
Skip tree sha's already in the git sha map.
134
        for k, v in self.dict.iteritems():
0.200.343 by Jelmer Vernooij
Use file ids consistently in map.
135
            if v == ("tree", (fileid, revid)):
0.200.287 by Jelmer Vernooij
Skip tree sha's already in the git sha map.
136
                return k
0.200.343 by Jelmer Vernooij
Use file ids consistently in map.
137
        raise KeyError((fileid, revid))
0.200.287 by Jelmer Vernooij
Skip tree sha's already in the git sha map.
138
0.230.2 by Jelmer Vernooij
Fix versionedfiles.
139
    def lookup_blob(self, fileid, revid):
140
        for k, v in self.dict.iteritems():
141
            if v == ("blob", (fileid, revid)):
142
                return k
143
        raise KeyError((fileid, revid))
144
0.200.260 by Jelmer Vernooij
Add DictGitShaMap, useful for testing.
145
    def revids(self):
146
        for key, (type, type_data) in self.dict.iteritems():
147
            if type == "commit":
0.200.262 by Jelmer Vernooij
Add tests for GitShaMap.
148
                yield type_data[0]
0.200.260 by Jelmer Vernooij
Add DictGitShaMap, useful for testing.
149
0.200.422 by Jelmer Vernooij
'bzr git-object' without arguments now prints the available git objects.
150
    def sha1s(self):
151
        return self.dict.iterkeys()
152
0.200.260 by Jelmer Vernooij
Add DictGitShaMap, useful for testing.
153
154
class SqliteGitShaMap(GitShaMap):
0.200.226 by Jelmer Vernooij
Merge thin-pack work.
155
0.200.365 by Jelmer Vernooij
Share sha map cache connections inside threads.
156
    def __init__(self, path=None):
157
        self.path = path
158
        if path is None:
0.200.262 by Jelmer Vernooij
Add tests for GitShaMap.
159
            self.db = sqlite3.connect(":memory:")
160
        else:
0.200.365 by Jelmer Vernooij
Share sha map cache connections inside threads.
161
            if not mapdbs().has_key(path):
162
                mapdbs()[path] = sqlite3.connect(path)
163
            self.db = mapdbs()[path]    
0.200.230 by Jelmer Vernooij
Implement sha cache.
164
        self.db.executescript("""
165
        create table if not exists commits(sha1 text, revid text, tree_sha text);
166
        create index if not exists commit_sha1 on commits(sha1);
0.200.284 by Jelmer Vernooij
Add extra indexes.
167
        create unique index if not exists commit_revid on commits(revid);
0.200.230 by Jelmer Vernooij
Implement sha cache.
168
        create table if not exists blobs(sha1 text, fileid text, revid text);
169
        create index if not exists blobs_sha1 on blobs(sha1);
0.200.284 by Jelmer Vernooij
Add extra indexes.
170
        create unique index if not exists blobs_fileid_revid on blobs(fileid, revid);
0.200.343 by Jelmer Vernooij
Use file ids consistently in map.
171
        create table if not exists trees(sha1 text, fileid text, revid text);
0.200.230 by Jelmer Vernooij
Implement sha cache.
172
        create index if not exists trees_sha1 on trees(sha1);
0.200.343 by Jelmer Vernooij
Use file ids consistently in map.
173
        create unique index if not exists trees_fileid_revid on trees(fileid, revid);
0.200.230 by Jelmer Vernooij
Implement sha cache.
174
""")
0.200.226 by Jelmer Vernooij
Merge thin-pack work.
175
0.200.365 by Jelmer Vernooij
Share sha map cache connections inside threads.
176
    @classmethod
177
    def from_repository(cls, repository):
0.200.533 by Jelmer Vernooij
Use user home dir cache when transport for sqlite cache is readonly.
178
        try:
179
            transport = getattr(repository, "_transport", None)
180
            if transport is not None:
181
                return cls(os.path.join(transport.local_abspath("."), "git.db"))
182
        except bzrlib.errors.NotLocalUrl:
183
            pass
0.200.534 by Jelmer Vernooij
Use XDG cache directory if the python xdg module is available.
184
        return cls(os.path.join(get_cache_dir(), "remote.db"))
0.200.365 by Jelmer Vernooij
Share sha map cache connections inside threads.
185
0.200.487 by Jelmer Vernooij
Prevent deep recursion if the shamap is out of date.
186
    def lookup_commit(self, revid):
0.200.364 by Jelmer Vernooij
Reimplement dpush, but more efficient and only writing a single pack file rather than one per revision.
187
        row = self.db.execute("select sha1 from commits where revid = ?", (revid,)).fetchone()
188
        if row is not None:
189
            return row[0].encode("utf-8")
190
        raise KeyError
0.200.231 by Jelmer Vernooij
Partially fix pull.
191
0.200.232 by Jelmer Vernooij
Fix pull from remote branches.
192
    def commit(self):
193
        self.db.commit()
194
0.200.377 by Jelmer Vernooij
use executemany when inserting sha map entries.
195
    def add_entries(self, entries):
196
        trees = []
197
        blobs = []
198
        for sha, type, type_data in entries:
0.200.410 by Jelmer Vernooij
Fix compatibility with python 2.4.
199
            assert isinstance(type_data[0], str)
200
            assert isinstance(type_data[1], str)
201
            entry = (sha.decode("utf-8"), type_data[0].decode("utf-8"), 
202
                     type_data[1].decode("utf-8"))
0.200.377 by Jelmer Vernooij
use executemany when inserting sha map entries.
203
            if type == "tree":
0.200.410 by Jelmer Vernooij
Fix compatibility with python 2.4.
204
                trees.append(entry)
0.200.377 by Jelmer Vernooij
use executemany when inserting sha map entries.
205
            elif type == "blob":
0.200.410 by Jelmer Vernooij
Fix compatibility with python 2.4.
206
                blobs.append(entry)
0.200.377 by Jelmer Vernooij
use executemany when inserting sha map entries.
207
            else:
208
                raise AssertionError
209
        if trees:
210
            self.db.executemany("replace into trees (sha1, fileid, revid) values (?, ?, ?)", trees)
211
        if blobs:
212
            self.db.executemany("replace into blobs (sha1, fileid, revid) values (?, ?, ?)", blobs)
213
214
0.200.226 by Jelmer Vernooij
Merge thin-pack work.
215
    def add_entry(self, sha, type, type_data):
216
        """Add a new entry to the database.
217
        """
0.200.231 by Jelmer Vernooij
Partially fix pull.
218
        assert isinstance(type_data, tuple)
219
        assert isinstance(sha, str), "type was %r" % sha
0.200.230 by Jelmer Vernooij
Implement sha cache.
220
        if type == "commit":
221
            self.db.execute("replace into commits (sha1, revid, tree_sha) values (?, ?, ?)", (sha, type_data[0], type_data[1]))
0.200.343 by Jelmer Vernooij
Use file ids consistently in map.
222
        elif type in ("blob", "tree"):
223
            self.db.execute("replace into %ss (sha1, fileid, revid) values (?, ?, ?)" % type, (sha, type_data[0], type_data[1]))
0.200.230 by Jelmer Vernooij
Implement sha cache.
224
        else:
225
            raise AssertionError("Unknown type %s" % type)
0.200.226 by Jelmer Vernooij
Merge thin-pack work.
226
0.200.343 by Jelmer Vernooij
Use file ids consistently in map.
227
    def lookup_tree(self, fileid, revid):
228
        row = self.db.execute("select sha1 from trees where fileid = ? and revid = ?", (fileid,revid)).fetchone()
0.200.287 by Jelmer Vernooij
Skip tree sha's already in the git sha map.
229
        if row is None:
0.200.343 by Jelmer Vernooij
Use file ids consistently in map.
230
            raise KeyError((fileid, revid))
0.200.358 by Jelmer Vernooij
Use plain strings for sha1 strings, not unicode.
231
        return row[0].encode("utf-8")
0.200.287 by Jelmer Vernooij
Skip tree sha's already in the git sha map.
232
0.230.2 by Jelmer Vernooij
Fix versionedfiles.
233
    def lookup_blob(self, fileid, revid):
0.230.3 by Jelmer Vernooij
Fix blob lookup.
234
        row = self.db.execute("select sha1 from blobs where fileid = ? and revid = ?", (fileid, revid)).fetchone()
0.230.2 by Jelmer Vernooij
Fix versionedfiles.
235
        if row is None:
236
            raise KeyError((fileid, revid))
0.200.358 by Jelmer Vernooij
Use plain strings for sha1 strings, not unicode.
237
        return row[0].encode("utf-8")
0.230.2 by Jelmer Vernooij
Fix versionedfiles.
238
0.200.226 by Jelmer Vernooij
Merge thin-pack work.
239
    def lookup_git_sha(self, sha):
240
        """Lookup a Git sha in the database.
241
242
        :param sha: Git object sha
243
        :return: (type, type_data) with type_data:
244
            revision: revid, tree sha
245
        """
0.200.353 by Jelmer Vernooij
fileids/revids are plain strings, not unicode
246
        def format(type, row):
247
            return (type, (row[0].encode("utf-8"), row[1].encode("utf-8")))
0.200.230 by Jelmer Vernooij
Implement sha cache.
248
        row = self.db.execute("select revid, tree_sha from commits where sha1 = ?", (sha,)).fetchone()
249
        if row is not None:
0.200.353 by Jelmer Vernooij
fileids/revids are plain strings, not unicode
250
            return format("commit", row)
0.200.230 by Jelmer Vernooij
Implement sha cache.
251
        row = self.db.execute("select fileid, revid from blobs where sha1 = ?", (sha,)).fetchone()
252
        if row is not None:
0.200.353 by Jelmer Vernooij
fileids/revids are plain strings, not unicode
253
            return format("blob", row)
0.200.343 by Jelmer Vernooij
Use file ids consistently in map.
254
        row = self.db.execute("select fileid, revid from trees where sha1 = ?", (sha,)).fetchone()
0.200.230 by Jelmer Vernooij
Implement sha cache.
255
        if row is not None:
0.200.353 by Jelmer Vernooij
fileids/revids are plain strings, not unicode
256
            return format("tree", row)
0.200.230 by Jelmer Vernooij
Implement sha cache.
257
        raise KeyError(sha)
258
259
    def revids(self):
0.200.260 by Jelmer Vernooij
Add DictGitShaMap, useful for testing.
260
        """List the revision ids known."""
0.200.230 by Jelmer Vernooij
Implement sha cache.
261
        for row in self.db.execute("select revid from commits").fetchall():
0.200.347 by Jelmer Vernooij
Simplify converter a bit.
262
            yield row[0].encode("utf-8")
0.200.422 by Jelmer Vernooij
'bzr git-object' without arguments now prints the available git objects.
263
264
    def sha1s(self):
265
        """List the SHA1s."""
266
        for table in ("blobs", "commits", "trees"):
267
            for row in self.db.execute("select sha1 from %s" % table).fetchall():
268
                yield row[0].encode("utf-8")
0.200.475 by Jelmer Vernooij
Add Tdb database backend.
269
270
0.235.1 by Jelmer Vernooij
Store sha map more efficiently.
271
TDB_MAP_VERSION = 2
0.200.539 by Jelmer Vernooij
Default to larger hash size.
272
TDB_HASH_SIZE = 10000
0.200.479 by Jelmer Vernooij
Version tdb sha map.
273
274
0.200.475 by Jelmer Vernooij
Add Tdb database backend.
275
class TdbGitShaMap(GitShaMap):
276
    """SHA Map that uses a TDB database.
277
278
    Entries:
279
0.200.476 by Jelmer Vernooij
Fix Tdb backend, use tdb if possible by default.
280
    "git <sha1>" -> "<type> <type-data1> <type-data2>"
281
    "commit revid" -> "<sha1> <tree-id>"
0.200.477 by Jelmer Vernooij
More tests for sha maps, fix cache misses in tdb.
282
    "tree fileid revid" -> "<sha1>"
283
    "blob fileid revid" -> "<sha1>"
0.200.475 by Jelmer Vernooij
Add Tdb database backend.
284
    """
285
286
    def __init__(self, path=None):
287
        import tdb
288
        self.path = path
289
        if path is None:
290
            self.db = {}
291
        else:
292
            if not mapdbs().has_key(path):
0.200.539 by Jelmer Vernooij
Default to larger hash size.
293
                mapdbs()[path] = tdb.Tdb(path, TDB_HASH_SIZE, tdb.DEFAULT, 
0.200.475 by Jelmer Vernooij
Add Tdb database backend.
294
                                          os.O_RDWR|os.O_CREAT)
295
            self.db = mapdbs()[path]    
0.200.479 by Jelmer Vernooij
Version tdb sha map.
296
        if not "version" in self.db:
297
            self.db["version"] = str(TDB_MAP_VERSION)
298
        else:
0.235.1 by Jelmer Vernooij
Store sha map more efficiently.
299
            if int(self.db["version"]) != TDB_MAP_VERSION:
300
                trace.warning("SHA Map is incompatible (%s -> %d), rebuilding database.",
301
                              self.db["version"], TDB_MAP_VERSION)
302
                self.db.clear()
303
            self.db["version"] = str(TDB_MAP_VERSION)
0.200.475 by Jelmer Vernooij
Add Tdb database backend.
304
305
    @classmethod
306
    def from_repository(cls, repository):
0.200.482 by Jelmer Vernooij
Use tdb file in the config dir if it's remote.
307
        try:
0.200.500 by Jelmer Vernooij
Cope with repositories that don't have a _transport attribute.
308
            transport = getattr(repository, "_transport", None)
309
            if transport is not None:
310
                return cls(os.path.join(transport.local_abspath("."), "git.tdb"))
0.200.482 by Jelmer Vernooij
Use tdb file in the config dir if it's remote.
311
        except bzrlib.errors.NotLocalUrl:
0.200.500 by Jelmer Vernooij
Cope with repositories that don't have a _transport attribute.
312
            pass
0.200.534 by Jelmer Vernooij
Use XDG cache directory if the python xdg module is available.
313
        return cls(os.path.join(get_cache_dir(), "remote.tdb"))
0.200.475 by Jelmer Vernooij
Add Tdb database backend.
314
0.200.487 by Jelmer Vernooij
Prevent deep recursion if the shamap is out of date.
315
    def lookup_commit(self, revid):
0.235.1 by Jelmer Vernooij
Store sha map more efficiently.
316
        return sha_to_hex(self.db["commit\0" + revid][:20])
0.200.475 by Jelmer Vernooij
Add Tdb database backend.
317
318
    def commit(self):
319
        pass
320
321
    def add_entry(self, sha, type, type_data):
322
        """Add a new entry to the database.
323
        """
0.235.1 by Jelmer Vernooij
Store sha map more efficiently.
324
        self.db["git\0" + hex_to_sha(sha)] = "\0".join((type, type_data[0], type_data[1]))
0.200.476 by Jelmer Vernooij
Fix Tdb backend, use tdb if possible by default.
325
        if type == "commit":
0.235.1 by Jelmer Vernooij
Store sha map more efficiently.
326
            self.db["commit\0" + type_data[0]] = "\0".join((hex_to_sha(sha), type_data[1]))
0.200.476 by Jelmer Vernooij
Fix Tdb backend, use tdb if possible by default.
327
        else:
0.235.1 by Jelmer Vernooij
Store sha map more efficiently.
328
            self.db["\0".join((type, type_data[0], type_data[1]))] = hex_to_sha(sha)
0.200.475 by Jelmer Vernooij
Add Tdb database backend.
329
330
    def lookup_tree(self, fileid, revid):
0.235.1 by Jelmer Vernooij
Store sha map more efficiently.
331
        return sha_to_hex(self.db["\0".join(("tree", fileid, revid))])
0.200.475 by Jelmer Vernooij
Add Tdb database backend.
332
333
    def lookup_blob(self, fileid, revid):
0.235.1 by Jelmer Vernooij
Store sha map more efficiently.
334
        return sha_to_hex(self.db["\0".join(("blob", fileid, revid))])
0.200.475 by Jelmer Vernooij
Add Tdb database backend.
335
336
    def lookup_git_sha(self, sha):
337
        """Lookup a Git sha in the database.
338
339
        :param sha: Git object sha
340
        :return: (type, type_data) with type_data:
341
            revision: revid, tree sha
342
        """
0.235.1 by Jelmer Vernooij
Store sha map more efficiently.
343
        data = self.db["git\0" + hex_to_sha(sha)].split("\0")
0.200.476 by Jelmer Vernooij
Fix Tdb backend, use tdb if possible by default.
344
        return (data[0], (data[1], data[2]))
0.200.475 by Jelmer Vernooij
Add Tdb database backend.
345
346
    def revids(self):
347
        """List the revision ids known."""
348
        for key in self.db.iterkeys():
0.235.1 by Jelmer Vernooij
Store sha map more efficiently.
349
            if key.startswith("commit\0"):
350
                yield key[7:]
0.200.475 by Jelmer Vernooij
Add Tdb database backend.
351
352
    def sha1s(self):
353
        """List the SHA1s."""
354
        for key in self.db.iterkeys():
0.235.1 by Jelmer Vernooij
Store sha map more efficiently.
355
            if key.startswith("git\0"):
356
                yield sha_to_hex(key[4:])