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