/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.254.44 by Jelmer Vernooij
Add knit-based content cache for trees.
26
from dulwich.objects import (
27
    ShaFile,
28
    )
29
0.200.228 by Jelmer Vernooij
Split out map.
30
import bzrlib
0.200.528 by Jelmer Vernooij
Fix import.
31
from bzrlib import (
0.254.2 by jelmer
use btree indexes
32
    btree_index as _mod_btree_index,
0.254.1 by Jelmer Vernooij
Add trivial index-based sha map.
33
    index as _mod_index,
34
    osutils,
0.200.844 by Jelmer Vernooij
Add infrastructure for multiple cache formats.
35
    registry,
0.200.528 by Jelmer Vernooij
Fix import.
36
    trace,
0.254.31 by Jelmer Vernooij
Initial work on CHKMap support.
37
    versionedfile,
0.200.528 by Jelmer Vernooij
Fix import.
38
    )
0.200.844 by Jelmer Vernooij
Add infrastructure for multiple cache formats.
39
from bzrlib.transport import (
40
    get_transport,
41
    )
0.200.230 by Jelmer Vernooij
Implement sha cache.
42
0.200.226 by Jelmer Vernooij
Merge thin-pack work.
43
0.200.534 by Jelmer Vernooij
Use XDG cache directory if the python xdg module is available.
44
def get_cache_dir():
45
    try:
46
        from xdg.BaseDirectory import xdg_cache_home
47
    except ImportError:
0.200.558 by Jelmer Vernooij
Create cache dir if it doesn't exist yet.
48
        from bzrlib.config import config_dir
49
        ret = os.path.join(config_dir(), "git")
0.200.534 by Jelmer Vernooij
Use XDG cache directory if the python xdg module is available.
50
    else:
0.200.558 by Jelmer Vernooij
Create cache dir if it doesn't exist yet.
51
        ret = os.path.join(xdg_cache_home, "bazaar", "git")
52
    if not os.path.isdir(ret):
53
        os.makedirs(ret)
54
    return ret
0.200.534 by Jelmer Vernooij
Use XDG cache directory if the python xdg module is available.
55
56
0.200.844 by Jelmer Vernooij
Add infrastructure for multiple cache formats.
57
def get_remote_cache_transport():
58
    return get_transport(get_cache_dir())
59
60
0.200.228 by Jelmer Vernooij
Split out map.
61
def check_pysqlite_version(sqlite3):
62
    """Check that sqlite library is compatible.
63
64
    """
0.200.675 by Jelmer Vernooij
Fix formatting.
65
    if (sqlite3.sqlite_version_info[0] < 3 or
66
            (sqlite3.sqlite_version_info[0] == 3 and
0.200.228 by Jelmer Vernooij
Split out map.
67
             sqlite3.sqlite_version_info[1] < 3)):
0.200.586 by Jelmer Vernooij
Fix issues pointed out by pyflakes.
68
        trace.warning('Needs at least sqlite 3.3.x')
0.200.228 by Jelmer Vernooij
Split out map.
69
        raise bzrlib.errors.BzrError("incompatible sqlite library")
70
71
try:
72
    try:
73
        import sqlite3
74
        check_pysqlite_version(sqlite3)
0.200.675 by Jelmer Vernooij
Fix formatting.
75
    except (ImportError, bzrlib.errors.BzrError), e:
0.200.228 by Jelmer Vernooij
Split out map.
76
        from pysqlite2 import dbapi2 as sqlite3
77
        check_pysqlite_version(sqlite3)
78
except:
0.200.586 by Jelmer Vernooij
Fix issues pointed out by pyflakes.
79
    trace.warning('Needs at least Python2.5 or Python2.4 with the pysqlite2 '
0.200.228 by Jelmer Vernooij
Split out map.
80
            'module')
81
    raise bzrlib.errors.BzrError("missing sqlite library")
82
0.200.226 by Jelmer Vernooij
Merge thin-pack work.
83
0.200.365 by Jelmer Vernooij
Share sha map cache connections inside threads.
84
_mapdbs = threading.local()
85
def mapdbs():
86
    """Get a cache for this thread's db connections."""
87
    try:
88
        return _mapdbs.cache
89
    except AttributeError:
90
        _mapdbs.cache = {}
91
        return _mapdbs.cache
92
93
0.200.841 by Jelmer Vernooij
Eliminate InventorySHAMap.
94
class GitShaMap(object):
95
    """Git<->Bzr revision id mapping database."""
96
97
    def lookup_git_sha(self, sha):
98
        """Lookup a Git sha in the database.
99
        :param sha: Git object sha
100
        :return: (type, type_data) with type_data:
101
            revision: revid, tree sha
102
        """
103
        raise NotImplementedError(self.lookup_git_sha)
104
0.200.835 by Jelmer Vernooij
Rename lookup_{tree,blob} -> lookup_{tree,blob}_id.
105
    def lookup_blob_id(self, file_id, revision):
0.200.753 by Jelmer Vernooij
Move lookup_tree/lookup_blob to a separate object.
106
        """Retrieve a Git blob SHA by file id.
107
108
        :param file_id: File id of the file/symlink
0.200.806 by Jelmer Vernooij
Make revision_hint mandatory.
109
        :param revision: revision in which the file was last changed.
0.200.753 by Jelmer Vernooij
Move lookup_tree/lookup_blob to a separate object.
110
        """
0.200.835 by Jelmer Vernooij
Rename lookup_{tree,blob} -> lookup_{tree,blob}_id.
111
        raise NotImplementedError(self.lookup_blob_id)
0.200.753 by Jelmer Vernooij
Move lookup_tree/lookup_blob to a separate object.
112
0.200.841 by Jelmer Vernooij
Eliminate InventorySHAMap.
113
    def lookup_tree_id(self, file_id, revision):
0.200.753 by Jelmer Vernooij
Move lookup_tree/lookup_blob to a separate object.
114
        """Retrieve a Git tree SHA by file id.
115
        """
0.200.835 by Jelmer Vernooij
Rename lookup_{tree,blob} -> lookup_{tree,blob}_id.
116
        raise NotImplementedError(self.lookup_tree_id)
0.200.753 by Jelmer Vernooij
Move lookup_tree/lookup_blob to a separate object.
117
0.200.260 by Jelmer Vernooij
Add DictGitShaMap, useful for testing.
118
    def revids(self):
119
        """List the revision ids known."""
120
        raise NotImplementedError(self.revids)
121
0.200.677 by Jelmer Vernooij
Implement TdbCache.missing_revisions().
122
    def missing_revisions(self, revids):
123
        """Return set of all the revisions that are not present."""
124
        present_revids = set(self.revids())
125
        if not isinstance(revids, set):
126
            revids = set(revids)
127
        return revids - present_revids
128
0.200.586 by Jelmer Vernooij
Fix issues pointed out by pyflakes.
129
    def sha1s(self):
0.200.422 by Jelmer Vernooij
'bzr git-object' without arguments now prints the available git objects.
130
        """List the SHA1s."""
131
        raise NotImplementedError(self.sha1s)
132
0.200.687 by Jelmer Vernooij
Use start_write_group() / commit_write_group() mechanism when creating git SHA maps.
133
    def start_write_group(self):
134
        """Start writing changes."""
135
136
    def commit_write_group(self):
0.200.260 by Jelmer Vernooij
Add DictGitShaMap, useful for testing.
137
        """Commit any pending changes."""
138
0.200.687 by Jelmer Vernooij
Use start_write_group() / commit_write_group() mechanism when creating git SHA maps.
139
    def abort_write_group(self):
140
        """Abort any pending changes."""
141
0.200.260 by Jelmer Vernooij
Add DictGitShaMap, useful for testing.
142
0.254.44 by Jelmer Vernooij
Add knit-based content cache for trees.
143
class ContentCache(object):
144
    """Object that can cache Git objects."""
145
146
    def __getitem__(self, sha):
147
        """Retrieve an item, by SHA."""
148
        raise NotImplementedError(self.__getitem__)
149
150
0.200.844 by Jelmer Vernooij
Add infrastructure for multiple cache formats.
151
class BzrGitCacheFormat(object):
0.254.51 by Jelmer Vernooij
Add some docstrings.
152
    """Bazaar-Git Cache Format."""
0.200.844 by Jelmer Vernooij
Add infrastructure for multiple cache formats.
153
154
    def get_format_string(self):
0.200.866 by Jelmer Vernooij
More docstrings, prefer migrating git.db to migrating git.tdb.
155
        """Return a single-line unique format string for this cache format."""
0.200.844 by Jelmer Vernooij
Add infrastructure for multiple cache formats.
156
        raise NotImplementedError(self.get_format_string)
157
158
    def open(self, transport):
0.200.866 by Jelmer Vernooij
More docstrings, prefer migrating git.db to migrating git.tdb.
159
        """Open this format on a transport."""
0.200.844 by Jelmer Vernooij
Add infrastructure for multiple cache formats.
160
        raise NotImplementedError(self.open)
161
162
    def initialize(self, transport):
0.254.51 by Jelmer Vernooij
Add some docstrings.
163
        """Create a new instance of this cache format at transport."""
0.200.844 by Jelmer Vernooij
Add infrastructure for multiple cache formats.
164
        transport.put_bytes('format', self.get_format_string())
165
166
    @classmethod
0.200.866 by Jelmer Vernooij
More docstrings, prefer migrating git.db to migrating git.tdb.
167
    def from_transport(self, transport):
168
        """Open a cache file present on a transport, or initialize one.
169
170
        :param transport: Transport to use
171
        :return: A BzrGitCache instance
172
        """
173
        try:
174
            format_name = transport.get_bytes('format')
175
            format = formats.get(format_name)
176
        except bzrlib.errors.NoSuchFile:
177
            format = formats.get('default')
178
            format.initialize(transport)
179
        return format.open(transport)
180
181
    @classmethod
182
    def from_repository(cls, repository):
183
        """Open a cache file for a repository.
184
185
        This will use the repository's transport to store the cache file, or
186
        use the users global cache directory if the repository has no 
187
        transport associated with it.
188
189
        :param repository: Repository to open the cache for
190
        :return: A `BzrGitCache`
191
        """
0.200.844 by Jelmer Vernooij
Add infrastructure for multiple cache formats.
192
        repo_transport = getattr(repository, "_transport", None)
193
        if repo_transport is not None:
0.200.865 by Jelmer Vernooij
Support serving without --allow-writes.
194
            # Even if we don't write to this repo, we should be able 
195
            # to update its cache.
196
            repo_transport = remove_readonly_transport_decorator(repo_transport)
0.200.844 by Jelmer Vernooij
Add infrastructure for multiple cache formats.
197
            try:
198
                repo_transport.mkdir('git')
199
            except bzrlib.errors.FileExists:
200
                pass
201
            transport = repo_transport.clone('git')
202
        else:
203
            transport = get_remote_cache_transport()
0.200.866 by Jelmer Vernooij
More docstrings, prefer migrating git.db to migrating git.tdb.
204
        return cls.from_transport(transport)
0.200.844 by Jelmer Vernooij
Add infrastructure for multiple cache formats.
205
206
0.200.847 by Jelmer Vernooij
Add BzrGitCache object.
207
class CacheUpdater(object):
0.254.51 by Jelmer Vernooij
Add some docstrings.
208
    """Base class for objects that can update a bzr-git cache."""
0.200.847 by Jelmer Vernooij
Add BzrGitCache object.
209
0.200.849 by Jelmer Vernooij
Allow cache backends to decide when to add entries rather than adding once per commit.
210
    def add_object(self, obj, ie):
211
        raise NotImplementedError(self.add_object)
212
213
    def finish(self):
214
        raise NotImplementedError(self.finish)
215
216
217
class BzrGitCache(object):
218
    """Caching backend."""
219
220
    def __init__(self, idmap, content_cache, cache_updater_klass):
221
        self.idmap = idmap
222
        self.content_cache = content_cache
223
        self._cache_updater_klass = cache_updater_klass
224
225
    def get_updater(self, rev):
0.254.51 by Jelmer Vernooij
Add some docstrings.
226
        """Update an object that implements the CacheUpdater interface for 
227
        updating this cache.
228
        """
0.200.849 by Jelmer Vernooij
Allow cache backends to decide when to add entries rather than adding once per commit.
229
        return self._cache_updater_klass(self, rev)
230
231
232
DictBzrGitCache = lambda: BzrGitCache(DictGitShaMap(), None, DictCacheUpdater)
233
234
235
class DictCacheUpdater(CacheUpdater):
0.254.51 by Jelmer Vernooij
Add some docstrings.
236
    """Cache updater for dict-based caches."""
0.200.849 by Jelmer Vernooij
Allow cache backends to decide when to add entries rather than adding once per commit.
237
238
    def __init__(self, cache, rev):
0.200.847 by Jelmer Vernooij
Add BzrGitCache object.
239
        self.cache = cache
240
        self.revid = rev.revision_id
241
        self.parent_revids = rev.parent_ids
242
        self._commit = None
243
        self._entries = []
244
245
    def add_object(self, obj, ie):
246
        if obj.type_name == "commit":
247
            self._commit = obj
248
            assert ie is None
0.200.849 by Jelmer Vernooij
Allow cache backends to decide when to add entries rather than adding once per commit.
249
            type_data = (self.revid, self._commit.tree)
0.200.853 by Jelmer Vernooij
Fix lookup of commits in tdb.
250
            self.cache.idmap._by_revid[self.revid] = obj.id
0.200.847 by Jelmer Vernooij
Add BzrGitCache object.
251
        elif obj.type_name in ("blob", "tree"):
0.252.23 by Jelmer Vernooij
More work on roundtripping support.
252
            if ie is not None:
253
                if obj.type_name == "blob":
254
                    revision = ie.revision
255
                else:
256
                    revision = self.revid
257
                type_data = (ie.file_id, revision)
258
                self.cache.idmap._by_fileid.setdefault(type_data[1], {})[type_data[0]] =\
259
                    obj.id
0.200.847 by Jelmer Vernooij
Add BzrGitCache object.
260
        else:
261
            raise AssertionError
0.200.850 by Jelmer Vernooij
Fix tests.
262
        self.cache.idmap._by_sha[obj.id] = (obj.type_name, type_data)
0.200.847 by Jelmer Vernooij
Add BzrGitCache object.
263
264
    def finish(self):
265
        if self._commit is None:
266
            raise AssertionError("No commit object added")
267
        return self._commit
268
269
0.200.260 by Jelmer Vernooij
Add DictGitShaMap, useful for testing.
270
class DictGitShaMap(GitShaMap):
0.254.51 by Jelmer Vernooij
Add some docstrings.
271
    """Git SHA map that uses a dictionary."""
0.200.260 by Jelmer Vernooij
Add DictGitShaMap, useful for testing.
272
273
    def __init__(self):
0.200.753 by Jelmer Vernooij
Move lookup_tree/lookup_blob to a separate object.
274
        self._by_sha = {}
275
        self._by_fileid = {}
0.200.853 by Jelmer Vernooij
Fix lookup of commits in tdb.
276
        self._by_revid = {}
0.200.260 by Jelmer Vernooij
Add DictGitShaMap, useful for testing.
277
0.200.841 by Jelmer Vernooij
Eliminate InventorySHAMap.
278
    def lookup_blob_id(self, fileid, revision):
279
        return self._by_fileid[revision][fileid]
0.200.260 by Jelmer Vernooij
Add DictGitShaMap, useful for testing.
280
281
    def lookup_git_sha(self, sha):
0.200.753 by Jelmer Vernooij
Move lookup_tree/lookup_blob to a separate object.
282
        return self._by_sha[sha]
0.230.2 by Jelmer Vernooij
Fix versionedfiles.
283
0.200.841 by Jelmer Vernooij
Eliminate InventorySHAMap.
284
    def lookup_tree_id(self, fileid, revision):
0.200.860 by Jelmer Vernooij
Fix bugs in two lookup_tree_id implementations and add a test for it.
285
        return self._by_fileid[revision][fileid]
0.200.841 by Jelmer Vernooij
Eliminate InventorySHAMap.
286
0.200.853 by Jelmer Vernooij
Fix lookup of commits in tdb.
287
    def lookup_commit(self, revid):
288
        return self._by_revid[revid]
289
0.200.260 by Jelmer Vernooij
Add DictGitShaMap, useful for testing.
290
    def revids(self):
0.200.753 by Jelmer Vernooij
Move lookup_tree/lookup_blob to a separate object.
291
        for key, (type, type_data) in self._by_sha.iteritems():
0.200.260 by Jelmer Vernooij
Add DictGitShaMap, useful for testing.
292
            if type == "commit":
0.200.262 by Jelmer Vernooij
Add tests for GitShaMap.
293
                yield type_data[0]
0.200.260 by Jelmer Vernooij
Add DictGitShaMap, useful for testing.
294
0.200.422 by Jelmer Vernooij
'bzr git-object' without arguments now prints the available git objects.
295
    def sha1s(self):
0.200.753 by Jelmer Vernooij
Move lookup_tree/lookup_blob to a separate object.
296
        return self._by_sha.iterkeys()
0.200.422 by Jelmer Vernooij
'bzr git-object' without arguments now prints the available git objects.
297
0.200.260 by Jelmer Vernooij
Add DictGitShaMap, useful for testing.
298
0.200.849 by Jelmer Vernooij
Allow cache backends to decide when to add entries rather than adding once per commit.
299
class SqliteCacheUpdater(CacheUpdater):
300
301
    def __init__(self, cache, rev):
302
        self.cache = cache
0.200.850 by Jelmer Vernooij
Fix tests.
303
        self.db = self.cache.idmap.db
0.200.849 by Jelmer Vernooij
Allow cache backends to decide when to add entries rather than adding once per commit.
304
        self.revid = rev.revision_id
305
        self._commit = None
306
        self._trees = []
307
        self._blobs = []
308
309
    def add_object(self, obj, ie):
310
        if obj.type_name == "commit":
311
            self._commit = obj
312
            assert ie is None
313
        elif obj.type_name == "tree":
0.252.23 by Jelmer Vernooij
More work on roundtripping support.
314
            if ie is not None:
315
                self._trees.append((obj.id, ie.file_id, self.revid))
0.200.849 by Jelmer Vernooij
Allow cache backends to decide when to add entries rather than adding once per commit.
316
        elif obj.type_name == "blob":
0.252.23 by Jelmer Vernooij
More work on roundtripping support.
317
            if ie is not None:
318
                self._blobs.append((obj.id, ie.file_id, ie.revision))
0.200.849 by Jelmer Vernooij
Allow cache backends to decide when to add entries rather than adding once per commit.
319
        else:
320
            raise AssertionError
321
322
    def finish(self):
323
        if self._commit is None:
324
            raise AssertionError("No commit object added")
0.200.850 by Jelmer Vernooij
Fix tests.
325
        self.db.executemany(
326
            "replace into trees (sha1, fileid, revid) values (?, ?, ?)",
327
            self._trees)
328
        self.db.executemany(
329
            "replace into blobs (sha1, fileid, revid) values (?, ?, ?)",
330
            self._blobs)
331
        self.db.execute(
332
            "replace into commits (sha1, revid, tree_sha) values (?, ?, ?)",
333
            (self._commit.id, self.revid, self._commit.tree))
0.200.849 by Jelmer Vernooij
Allow cache backends to decide when to add entries rather than adding once per commit.
334
        return self._commit
335
336
337
SqliteBzrGitCache = lambda p: BzrGitCache(SqliteGitShaMap(p), None, SqliteCacheUpdater)
338
339
0.200.844 by Jelmer Vernooij
Add infrastructure for multiple cache formats.
340
class SqliteGitCacheFormat(BzrGitCacheFormat):
341
342
    def get_format_string(self):
343
        return 'bzr-git sha map version 1 using sqlite\n'
344
345
    def open(self, transport):
346
        try:
347
            basepath = transport.local_abspath(".")
348
        except bzrlib.errors.NotLocalUrl:
349
            basepath = get_cache_dir()
0.200.849 by Jelmer Vernooij
Allow cache backends to decide when to add entries rather than adding once per commit.
350
        return SqliteBzrGitCache(os.path.join(basepath, "idmap.db"))
0.200.844 by Jelmer Vernooij
Add infrastructure for multiple cache formats.
351
352
0.200.260 by Jelmer Vernooij
Add DictGitShaMap, useful for testing.
353
class SqliteGitShaMap(GitShaMap):
0.254.51 by Jelmer Vernooij
Add some docstrings.
354
    """Bazaar GIT Sha map that uses a sqlite database for storage."""
0.200.226 by Jelmer Vernooij
Merge thin-pack work.
355
0.200.365 by Jelmer Vernooij
Share sha map cache connections inside threads.
356
    def __init__(self, path=None):
357
        self.path = path
358
        if path is None:
0.200.262 by Jelmer Vernooij
Add tests for GitShaMap.
359
            self.db = sqlite3.connect(":memory:")
360
        else:
0.200.365 by Jelmer Vernooij
Share sha map cache connections inside threads.
361
            if not mapdbs().has_key(path):
362
                mapdbs()[path] = sqlite3.connect(path)
0.200.675 by Jelmer Vernooij
Fix formatting.
363
            self.db = mapdbs()[path]
0.200.688 by Jelmer Vernooij
Use str text factory rather than encoding/decoding each time.
364
        self.db.text_factory = str
0.200.230 by Jelmer Vernooij
Implement sha cache.
365
        self.db.executescript("""
0.200.691 by Jelmer Vernooij
Add extra constraints in sqlite tables.
366
        create table if not exists commits(
367
            sha1 text not null check(length(sha1) == 40),
368
            revid text not null,
369
            tree_sha text not null check(length(tree_sha) == 40)
370
        );
0.200.230 by Jelmer Vernooij
Implement sha cache.
371
        create index if not exists commit_sha1 on commits(sha1);
0.200.284 by Jelmer Vernooij
Add extra indexes.
372
        create unique index if not exists commit_revid on commits(revid);
0.200.691 by Jelmer Vernooij
Add extra constraints in sqlite tables.
373
        create table if not exists blobs(
374
            sha1 text not null check(length(sha1) == 40),
375
            fileid text not null,
376
            revid text not null
377
        );
0.200.230 by Jelmer Vernooij
Implement sha cache.
378
        create index if not exists blobs_sha1 on blobs(sha1);
0.200.284 by Jelmer Vernooij
Add extra indexes.
379
        create unique index if not exists blobs_fileid_revid on blobs(fileid, revid);
0.200.691 by Jelmer Vernooij
Add extra constraints in sqlite tables.
380
        create table if not exists trees(
0.255.1 by Jelmer Vernooij
Remove use of lookup_tree.
381
            sha1 text unique not null check(length(sha1) == 40),
0.200.691 by Jelmer Vernooij
Add extra constraints in sqlite tables.
382
            fileid text not null,
383
            revid text not null
384
        );
0.255.1 by Jelmer Vernooij
Remove use of lookup_tree.
385
        create unique index if not exists trees_sha1 on trees(sha1);
0.200.343 by Jelmer Vernooij
Use file ids consistently in map.
386
        create unique index if not exists trees_fileid_revid on trees(fileid, revid);
0.200.230 by Jelmer Vernooij
Implement sha cache.
387
""")
0.200.226 by Jelmer Vernooij
Merge thin-pack work.
388
0.254.19 by Jelmer Vernooij
Support upgrading sha maps.
389
    def __repr__(self):
390
        return "%s(%r)" % (self.__class__.__name__, self.path)
391
    
0.200.487 by Jelmer Vernooij
Prevent deep recursion if the shamap is out of date.
392
    def lookup_commit(self, revid):
0.254.51 by Jelmer Vernooij
Add some docstrings.
393
        cursor = self.db.execute("select sha1 from commits where revid = ?", 
394
            (revid,))
395
        row = cursor.fetchone()
0.200.364 by Jelmer Vernooij
Reimplement dpush, but more efficient and only writing a single pack file rather than one per revision.
396
        if row is not None:
0.200.688 by Jelmer Vernooij
Use str text factory rather than encoding/decoding each time.
397
            return row[0]
0.200.364 by Jelmer Vernooij
Reimplement dpush, but more efficient and only writing a single pack file rather than one per revision.
398
        raise KeyError
0.200.231 by Jelmer Vernooij
Partially fix pull.
399
0.200.687 by Jelmer Vernooij
Use start_write_group() / commit_write_group() mechanism when creating git SHA maps.
400
    def commit_write_group(self):
0.200.232 by Jelmer Vernooij
Fix pull from remote branches.
401
        self.db.commit()
402
0.200.841 by Jelmer Vernooij
Eliminate InventorySHAMap.
403
    def lookup_blob_id(self, fileid, revision):
404
        row = self.db.execute("select sha1 from blobs where fileid = ? and revid = ?", (fileid, revision)).fetchone()
405
        if row is not None:
406
            return row[0]
407
        raise KeyError(fileid)
408
409
    def lookup_tree_id(self, fileid, revision):
0.200.860 by Jelmer Vernooij
Fix bugs in two lookup_tree_id implementations and add a test for it.
410
        row = self.db.execute("select sha1 from trees where fileid = ? and revid = ?", (fileid, revision)).fetchone()
0.200.841 by Jelmer Vernooij
Eliminate InventorySHAMap.
411
        if row is not None:
412
            return row[0]
413
        raise KeyError(fileid)
0.230.2 by Jelmer Vernooij
Fix versionedfiles.
414
0.200.226 by Jelmer Vernooij
Merge thin-pack work.
415
    def lookup_git_sha(self, sha):
416
        """Lookup a Git sha in the database.
417
418
        :param sha: Git object sha
419
        :return: (type, type_data) with type_data:
420
            revision: revid, tree sha
421
        """
0.200.230 by Jelmer Vernooij
Implement sha cache.
422
        row = self.db.execute("select revid, tree_sha from commits where sha1 = ?", (sha,)).fetchone()
423
        if row is not None:
0.254.26 by Jelmer Vernooij
Fix typo, cope with invalid shamaps a bit better.
424
            return ("commit", row)
0.200.230 by Jelmer Vernooij
Implement sha cache.
425
        row = self.db.execute("select fileid, revid from blobs where sha1 = ?", (sha,)).fetchone()
426
        if row is not None:
0.254.26 by Jelmer Vernooij
Fix typo, cope with invalid shamaps a bit better.
427
            return ("blob", row)
0.200.343 by Jelmer Vernooij
Use file ids consistently in map.
428
        row = self.db.execute("select fileid, revid from trees where sha1 = ?", (sha,)).fetchone()
0.200.230 by Jelmer Vernooij
Implement sha cache.
429
        if row is not None:
0.254.26 by Jelmer Vernooij
Fix typo, cope with invalid shamaps a bit better.
430
            return ("tree", row)
0.200.230 by Jelmer Vernooij
Implement sha cache.
431
        raise KeyError(sha)
432
433
    def revids(self):
0.200.260 by Jelmer Vernooij
Add DictGitShaMap, useful for testing.
434
        """List the revision ids known."""
0.248.7 by Jelmer Vernooij
Avoid fetching all sha1s at once.
435
        return (row for (row,) in self.db.execute("select revid from commits"))
0.200.422 by Jelmer Vernooij
'bzr git-object' without arguments now prints the available git objects.
436
437
    def sha1s(self):
438
        """List the SHA1s."""
439
        for table in ("blobs", "commits", "trees"):
0.254.26 by Jelmer Vernooij
Fix typo, cope with invalid shamaps a bit better.
440
            for (sha,) in self.db.execute("select sha1 from %s" % table):
441
                yield sha
0.200.475 by Jelmer Vernooij
Add Tdb database backend.
442
443
0.200.849 by Jelmer Vernooij
Allow cache backends to decide when to add entries rather than adding once per commit.
444
class TdbCacheUpdater(CacheUpdater):
0.254.51 by Jelmer Vernooij
Add some docstrings.
445
    """Cache updater for tdb-based caches."""
0.200.849 by Jelmer Vernooij
Allow cache backends to decide when to add entries rather than adding once per commit.
446
447
    def __init__(self, cache, rev):
448
        self.cache = cache
449
        self.db = cache.idmap.db
450
        self.revid = rev.revision_id
451
        self.parent_revids = rev.parent_ids
452
        self._commit = None
453
        self._entries = []
454
455
    def add_object(self, obj, ie):
456
        sha = obj.sha().digest()
457
        if obj.type_name == "commit":
0.200.853 by Jelmer Vernooij
Fix lookup of commits in tdb.
458
            self.db["commit\0" + self.revid] = "\0".join((sha, obj.tree))
0.200.849 by Jelmer Vernooij
Allow cache backends to decide when to add entries rather than adding once per commit.
459
            type_data = (self.revid, obj.tree)
460
            self._commit = obj
461
            assert ie is None
462
        elif obj.type_name == "blob":
0.252.23 by Jelmer Vernooij
More work on roundtripping support.
463
            if ie is None:
464
                return
0.200.849 by Jelmer Vernooij
Allow cache backends to decide when to add entries rather than adding once per commit.
465
            self.db["\0".join(("blob", ie.file_id, ie.revision))] = sha
466
            type_data = (ie.file_id, ie.revision)
467
        elif obj.type_name == "tree":
0.252.23 by Jelmer Vernooij
More work on roundtripping support.
468
            if ie is None:
469
                return
0.200.849 by Jelmer Vernooij
Allow cache backends to decide when to add entries rather than adding once per commit.
470
            type_data = (ie.file_id, self.revid)
471
        else:
472
            raise AssertionError
0.200.853 by Jelmer Vernooij
Fix lookup of commits in tdb.
473
        self.db["git\0" + sha] = "\0".join((obj.type_name, ) + type_data)
0.200.849 by Jelmer Vernooij
Allow cache backends to decide when to add entries rather than adding once per commit.
474
475
    def finish(self):
476
        if self._commit is None:
477
            raise AssertionError("No commit object added")
478
        return self._commit
479
480
481
TdbBzrGitCache = lambda p: BzrGitCache(TdbGitShaMap(p), None, TdbCacheUpdater)
0.200.479 by Jelmer Vernooij
Version tdb sha map.
482
0.200.844 by Jelmer Vernooij
Add infrastructure for multiple cache formats.
483
class TdbGitCacheFormat(BzrGitCacheFormat):
0.254.51 by Jelmer Vernooij
Add some docstrings.
484
    """Cache format for tdb-based caches."""
0.200.844 by Jelmer Vernooij
Add infrastructure for multiple cache formats.
485
486
    def get_format_string(self):
487
        return 'bzr-git sha map version 3 using tdb\n'
488
489
    def open(self, transport):
490
        try:
491
            basepath = transport.local_abspath(".")
492
        except bzrlib.errors.NotLocalUrl:
493
            basepath = get_cache_dir()
494
        try:
0.200.850 by Jelmer Vernooij
Fix tests.
495
            return TdbBzrGitCache(os.path.join(basepath, "idmap.tdb"))
0.200.844 by Jelmer Vernooij
Add infrastructure for multiple cache formats.
496
        except ImportError:
497
            raise ImportError(
498
                "Unable to open existing bzr-git cache because 'tdb' is not "
499
                "installed.")
500
501
0.200.475 by Jelmer Vernooij
Add Tdb database backend.
502
class TdbGitShaMap(GitShaMap):
503
    """SHA Map that uses a TDB database.
504
505
    Entries:
506
0.200.476 by Jelmer Vernooij
Fix Tdb backend, use tdb if possible by default.
507
    "git <sha1>" -> "<type> <type-data1> <type-data2>"
508
    "commit revid" -> "<sha1> <tree-id>"
0.200.477 by Jelmer Vernooij
More tests for sha maps, fix cache misses in tdb.
509
    "tree fileid revid" -> "<sha1>"
510
    "blob fileid revid" -> "<sha1>"
0.200.475 by Jelmer Vernooij
Add Tdb database backend.
511
    """
512
0.200.849 by Jelmer Vernooij
Allow cache backends to decide when to add entries rather than adding once per commit.
513
    TDB_MAP_VERSION = 3
514
    TDB_HASH_SIZE = 50000
515
0.200.475 by Jelmer Vernooij
Add Tdb database backend.
516
    def __init__(self, path=None):
517
        import tdb
518
        self.path = path
519
        if path is None:
520
            self.db = {}
521
        else:
522
            if not mapdbs().has_key(path):
0.200.849 by Jelmer Vernooij
Allow cache backends to decide when to add entries rather than adding once per commit.
523
                mapdbs()[path] = tdb.Tdb(path, self.TDB_HASH_SIZE, tdb.DEFAULT,
0.200.475 by Jelmer Vernooij
Add Tdb database backend.
524
                                          os.O_RDWR|os.O_CREAT)
0.200.676 by Jelmer Vernooij
Avoid iterating over all keys in the tdb database.
525
            self.db = mapdbs()[path]
526
        try:
0.200.751 by Jelmer Vernooij
Unrelated small fixes - import, avoid storing tree info (no longer used).
527
            if int(self.db["version"]) not in (2, 3):
0.235.1 by Jelmer Vernooij
Store sha map more efficiently.
528
                trace.warning("SHA Map is incompatible (%s -> %d), rebuilding database.",
0.200.849 by Jelmer Vernooij
Allow cache backends to decide when to add entries rather than adding once per commit.
529
                              self.db["version"], self.TDB_MAP_VERSION)
0.235.1 by Jelmer Vernooij
Store sha map more efficiently.
530
                self.db.clear()
0.200.676 by Jelmer Vernooij
Avoid iterating over all keys in the tdb database.
531
        except KeyError:
0.200.751 by Jelmer Vernooij
Unrelated small fixes - import, avoid storing tree info (no longer used).
532
            pass
0.200.849 by Jelmer Vernooij
Allow cache backends to decide when to add entries rather than adding once per commit.
533
        self.db["version"] = str(self.TDB_MAP_VERSION)
0.200.475 by Jelmer Vernooij
Add Tdb database backend.
534
0.200.809 by Jelmer Vernooij
Use tdb transactions for write groups.
535
    def start_write_group(self):
536
        """Start writing changes."""
0.200.778 by Jelmer Vernooij
Use transactions in tdb.
537
        self.db.transaction_start()
0.200.809 by Jelmer Vernooij
Use tdb transactions for write groups.
538
539
    def commit_write_group(self):
540
        """Commit any pending changes."""
541
        self.db.transaction_commit()
542
543
    def abort_write_group(self):
544
        """Abort any pending changes."""
545
        self.db.transaction_cancel()
0.200.778 by Jelmer Vernooij
Use transactions in tdb.
546
0.200.750 by Jelmer Vernooij
Remove unused tree code, add mechanism for migrating between sha maps.
547
    def __repr__(self):
548
        return "%s(%r)" % (self.__class__.__name__, self.path)
549
0.200.487 by Jelmer Vernooij
Prevent deep recursion if the shamap is out of date.
550
    def lookup_commit(self, revid):
0.235.1 by Jelmer Vernooij
Store sha map more efficiently.
551
        return sha_to_hex(self.db["commit\0" + revid][:20])
0.200.475 by Jelmer Vernooij
Add Tdb database backend.
552
0.200.841 by Jelmer Vernooij
Eliminate InventorySHAMap.
553
    def lookup_blob_id(self, fileid, revision):
554
        return sha_to_hex(self.db["\0".join(("blob", fileid, revision))])
0.200.753 by Jelmer Vernooij
Move lookup_tree/lookup_blob to a separate object.
555
                
0.200.475 by Jelmer Vernooij
Add Tdb database backend.
556
    def lookup_git_sha(self, sha):
557
        """Lookup a Git sha in the database.
558
559
        :param sha: Git object sha
560
        :return: (type, type_data) with type_data:
561
            revision: revid, tree sha
562
        """
0.200.564 by Jelmer Vernooij
Accept 'binary' shas.
563
        if len(sha) == 40:
564
            sha = hex_to_sha(sha)
565
        data = self.db["git\0" + sha].split("\0")
0.200.476 by Jelmer Vernooij
Fix Tdb backend, use tdb if possible by default.
566
        return (data[0], (data[1], data[2]))
0.200.475 by Jelmer Vernooij
Add Tdb database backend.
567
0.200.677 by Jelmer Vernooij
Implement TdbCache.missing_revisions().
568
    def missing_revisions(self, revids):
569
        ret = set()
570
        for revid in revids:
571
            if self.db.get("commit\0" + revid) is None:
572
                ret.add(revid)
573
        return ret
574
0.200.475 by Jelmer Vernooij
Add Tdb database backend.
575
    def revids(self):
576
        """List the revision ids known."""
577
        for key in self.db.iterkeys():
0.235.1 by Jelmer Vernooij
Store sha map more efficiently.
578
            if key.startswith("commit\0"):
579
                yield key[7:]
0.200.475 by Jelmer Vernooij
Add Tdb database backend.
580
581
    def sha1s(self):
582
        """List the SHA1s."""
583
        for key in self.db.iterkeys():
0.235.1 by Jelmer Vernooij
Store sha map more efficiently.
584
            if key.startswith("git\0"):
585
                yield sha_to_hex(key[4:])
0.254.1 by Jelmer Vernooij
Add trivial index-based sha map.
586
0.200.750 by Jelmer Vernooij
Remove unused tree code, add mechanism for migrating between sha maps.
587
0.254.44 by Jelmer Vernooij
Add knit-based content cache for trees.
588
class VersionedFilesContentCache(ContentCache):
589
590
    def __init__(self, vf):
591
        self._vf = vf
592
593
    def add(self, obj):
594
        self._vf.insert_record_stream(
595
            [versionedfile.ChunkedContentFactory((obj.id,), [], None,
596
                obj.as_legacy_object_chunks())])
597
598
    def __getitem__(self, sha):
599
        stream = self._vf.get_record_stream([(sha,)], 'unordered', True)
600
        entry = stream.next() 
601
        if entry.storage_kind == 'absent':
602
            raise KeyError(sha)
603
        return ShaFile._parse_legacy_object(entry.get_bytes_as('fulltext'))
604
605
0.254.52 by Jelmer Vernooij
Merge trunk, use git objects to cache tree objects.
606
class GitObjectStoreContentCache(ContentCache):
607
608
    def __init__(self, store):
609
        self.store = store
610
611
    def add(self, obj):
612
        self.store.add_object(obj)
613
614
    def __getitem__(self, sha):
615
        return self.store[sha]
616
617
0.254.46 by Jelmer Vernooij
Merge trunk.
618
class IndexCacheUpdater(CacheUpdater):
619
620
    def __init__(self, cache, rev):
621
        self.cache = cache
622
        self.revid = rev.revision_id
623
        self.parent_revids = rev.parent_ids
624
        self._commit = None
625
        self._entries = []
626
627
    def add_object(self, obj, ie):
628
        if obj.type_name == "commit":
629
            self._commit = obj
630
            assert ie is None
0.254.47 by Jelmer Vernooij
Merge trunk.
631
            self.cache.idmap._add_git_sha(obj.id, "commit",
632
                (self.revid, obj.tree))
633
            self.cache.idmap._add_node(("commit", self.revid, "X"),
0.254.46 by Jelmer Vernooij
Merge trunk.
634
                " ".join((obj.id, obj.tree)))
0.254.53 by Jelmer Vernooij
Cache commits as well
635
            self.cache.content_cache.add(obj)
0.254.46 by Jelmer Vernooij
Merge trunk.
636
        elif obj.type_name == "blob":
0.254.47 by Jelmer Vernooij
Merge trunk.
637
            self.cache.idmap._add_git_sha(obj.id, "blob",
638
                (ie.file_id, ie.revision))
639
            self.cache.idmap._add_node(("blob", ie.file_id, ie.revision), obj.id)
0.254.49 by Jelmer Vernooij
Also cache full contents of symlinks.
640
            if ie.kind == "symlink":
641
                self.cache.content_cache.add(obj)
0.254.46 by Jelmer Vernooij
Merge trunk.
642
        elif obj.type_name == "tree":
0.254.47 by Jelmer Vernooij
Merge trunk.
643
            self.cache.idmap._add_git_sha(obj.id, "tree",
644
                (ie.file_id, self.revid))
0.254.46 by Jelmer Vernooij
Merge trunk.
645
            self.cache.content_cache.add(obj)
646
        else:
647
            raise AssertionError
648
649
    def finish(self):
650
        return self._commit
651
652
653
class IndexBzrGitCache(BzrGitCache):
654
655
    def __init__(self, transport=None):
656
        mapper = versionedfile.ConstantMapper("trees")
0.254.52 by Jelmer Vernooij
Merge trunk, use git objects to cache tree objects.
657
        shamap = IndexGitShaMap(transport.clone('index'))
658
        #trees_store = knit.make_file_factory(True, mapper)(transport)
659
        #content_cache = VersionedFilesContentCache(trees_store)
660
        from bzrlib.plugins.git.transportgit import TransportObjectStore
661
        store = TransportObjectStore(transport.clone('objects'))
662
        content_cache = GitObjectStoreContentCache(store)
663
        super(IndexBzrGitCache, self).__init__(shamap, content_cache,
0.254.47 by Jelmer Vernooij
Merge trunk.
664
                IndexCacheUpdater)
0.254.46 by Jelmer Vernooij
Merge trunk.
665
666
0.254.43 by Jelmer Vernooij
Merge trunk.
667
class IndexGitCacheFormat(BzrGitCacheFormat):
668
669
    def get_format_string(self):
0.254.52 by Jelmer Vernooij
Merge trunk, use git objects to cache tree objects.
670
        return 'bzr-git sha map with git object cache version 1\n'
0.254.43 by Jelmer Vernooij
Merge trunk.
671
672
    def initialize(self, transport):
673
        super(IndexGitCacheFormat, self).initialize(transport)
674
        transport.mkdir('index')
0.254.52 by Jelmer Vernooij
Merge trunk, use git objects to cache tree objects.
675
        transport.mkdir('objects')
676
        from bzrlib.plugins.git.transportgit import TransportObjectStore
677
        TransportObjectStore.init(transport.clone('objects'))
0.254.43 by Jelmer Vernooij
Merge trunk.
678
679
    def open(self, transport):
0.254.46 by Jelmer Vernooij
Merge trunk.
680
        return IndexBzrGitCache(transport)
0.254.1 by Jelmer Vernooij
Add trivial index-based sha map.
681
682
683
class IndexGitShaMap(GitShaMap):
0.254.31 by Jelmer Vernooij
Initial work on CHKMap support.
684
    """SHA Map that uses the Bazaar APIs to store a cache.
685
686
    BTree Index file with the following contents:
687
688
    ("git", <sha1>) -> "<type> <type-data1> <type-data2>"
689
    ("commit", <revid>) -> "<sha1> <tree-id>"
0.254.36 by Jelmer Vernooij
Merge trunk.
690
    ("blob", <fileid>, <revid>) -> <sha1>
691
0.254.1 by Jelmer Vernooij
Add trivial index-based sha map.
692
    """
693
694
    def __init__(self, transport=None):
695
        if transport is None:
0.254.43 by Jelmer Vernooij
Merge trunk.
696
            self._transport = None
0.254.36 by Jelmer Vernooij
Merge trunk.
697
            self._index = _mod_index.InMemoryGraphIndex(0, key_elements=3)
0.254.2 by jelmer
use btree indexes
698
            self._builder = self._index
0.254.1 by Jelmer Vernooij
Add trivial index-based sha map.
699
        else:
0.254.30 by Jelmer Vernooij
Move index to separate dir.
700
            self._builder = None
0.254.43 by Jelmer Vernooij
Merge trunk.
701
            self._transport = transport
0.254.2 by jelmer
use btree indexes
702
            self._index = _mod_index.CombinedGraphIndex([])
0.254.43 by Jelmer Vernooij
Merge trunk.
703
            for name in self._transport.list_dir("."):
0.254.2 by jelmer
use btree indexes
704
                if not name.endswith(".rix"):
705
                    continue
0.254.43 by Jelmer Vernooij
Merge trunk.
706
                x = _mod_btree_index.BTreeGraphIndex(self._transport, name,
707
                    self._transport.stat(name).st_size)
0.254.2 by jelmer
use btree indexes
708
                self._index.insert_index(0, x)
0.254.1 by Jelmer Vernooij
Add trivial index-based sha map.
709
710
    @classmethod
711
    def from_repository(cls, repository):
712
        transport = getattr(repository, "_transport", None)
713
        if transport is not None:
0.254.2 by jelmer
use btree indexes
714
            try:
715
                transport.mkdir('git')
716
            except bzrlib.errors.FileExists:
717
                pass
0.254.1 by Jelmer Vernooij
Add trivial index-based sha map.
718
            return cls(transport.clone('git'))
719
        from bzrlib.transport import get_transport
720
        return cls(get_transport(get_cache_dir()))
721
0.254.19 by Jelmer Vernooij
Support upgrading sha maps.
722
    def __repr__(self):
723
        if self._transport is not None:
724
            return "%s(%r)" % (self.__class__.__name__, self._transport.base)
725
        else:
726
            return "%s()" % (self.__class__.__name__)
727
0.254.3 by John Arbash Meinel
Add repack function.
728
    def repack(self):
729
        assert self._builder is None
730
        self.start_write_group()
731
        for _, key, value in self._index.iter_all_entries():
732
            self._builder.add_node(key, value)
733
        to_remove = []
0.254.43 by Jelmer Vernooij
Merge trunk.
734
        for name in self._transport.list_dir('.'):
0.254.3 by John Arbash Meinel
Add repack function.
735
            if name.endswith('.rix'):
736
                to_remove.append(name)
737
        self.commit_write_group()
738
        del self._index.indices[1:]
739
        for name in to_remove:
0.254.43 by Jelmer Vernooij
Merge trunk.
740
            self._transport.rename(name, name + '.old')
0.254.3 by John Arbash Meinel
Add repack function.
741
0.254.1 by Jelmer Vernooij
Add trivial index-based sha map.
742
    def start_write_group(self):
0.254.2 by jelmer
use btree indexes
743
        assert self._builder is None
0.254.36 by Jelmer Vernooij
Merge trunk.
744
        self._builder = _mod_btree_index.BTreeBuilder(0, key_elements=3)
0.254.1 by Jelmer Vernooij
Add trivial index-based sha map.
745
        self._name = osutils.sha()
746
747
    def commit_write_group(self):
0.254.2 by jelmer
use btree indexes
748
        assert self._builder is not None
0.254.1 by Jelmer Vernooij
Add trivial index-based sha map.
749
        stream = self._builder.finish()
0.254.2 by jelmer
use btree indexes
750
        name = self._name.hexdigest() + ".rix"
0.254.43 by Jelmer Vernooij
Merge trunk.
751
        size = self._transport.put_file(name, stream)
752
        index = _mod_btree_index.BTreeGraphIndex(self._transport, name, size)
0.254.1 by Jelmer Vernooij
Add trivial index-based sha map.
753
        self._index.insert_index(0, index)
754
        self._builder = None
755
        self._name = None
756
757
    def abort_write_group(self):
0.254.2 by jelmer
use btree indexes
758
        assert self._builder is not None
0.254.1 by Jelmer Vernooij
Add trivial index-based sha map.
759
        self._builder = None
760
        self._name = None
761
0.254.15 by Jelmer Vernooij
Convenience function for adding index nodes.
762
    def _add_node(self, key, value):
763
        try:
764
            self._builder.add_node(key, value)
765
        except bzrlib.errors.BadIndexDuplicateKey:
0.254.26 by Jelmer Vernooij
Fix typo, cope with invalid shamaps a bit better.
766
            # Multiple bzr objects can have the same contents
767
            return True
768
        else:
769
            return False
0.254.15 by Jelmer Vernooij
Convenience function for adding index nodes.
770
0.254.2 by jelmer
use btree indexes
771
    def _get_entry(self, key):
772
        entries = self._index.iter_entries([key])
0.254.1 by Jelmer Vernooij
Add trivial index-based sha map.
773
        try:
0.254.2 by jelmer
use btree indexes
774
            return entries.next()[2]
0.254.1 by Jelmer Vernooij
Add trivial index-based sha map.
775
        except StopIteration:
0.254.2 by jelmer
use btree indexes
776
            if self._builder is None:
777
                raise KeyError
778
            entries = self._builder.iter_entries([key])
779
            try:
780
                return entries.next()[2]
781
            except StopIteration:
782
                raise KeyError
783
784
    def _iter_keys_prefix(self, prefix):
785
        for entry in self._index.iter_entries_prefix([prefix]):
786
            yield entry[1]
787
        if self._builder is not None:
788
            for entry in self._builder.iter_entries_prefix([prefix]):
789
                yield entry[1]
790
791
    def lookup_commit(self, revid):
0.254.36 by Jelmer Vernooij
Merge trunk.
792
        return self._get_entry(("commit", revid, "X"))[:40]
0.254.1 by Jelmer Vernooij
Add trivial index-based sha map.
793
0.254.33 by Jelmer Vernooij
Merge trunk.
794
    def _add_git_sha(self, hexsha, type, type_data):
0.254.2 by jelmer
use btree indexes
795
        if hexsha is not None:
796
            self._name.update(hexsha)
0.254.36 by Jelmer Vernooij
Merge trunk.
797
            self._add_node(("git", hexsha, "X"),
0.254.15 by Jelmer Vernooij
Convenience function for adding index nodes.
798
                " ".join((type, type_data[0], type_data[1])))
0.254.2 by jelmer
use btree indexes
799
        else:
800
            # This object is not represented in Git - perhaps an empty
801
            # directory?
802
            self._name.update(type + " ".join(type_data))
0.254.33 by Jelmer Vernooij
Merge trunk.
803
0.254.42 by Jelmer Vernooij
Merge trunk.
804
    def lookup_blob_id(self, fileid, revision):
805
        return self._get_entry(("blob", fileid, revision))
0.254.1 by Jelmer Vernooij
Add trivial index-based sha map.
806
807
    def lookup_git_sha(self, sha):
808
        if len(sha) == 20:
809
            sha = sha_to_hex(sha)
0.254.36 by Jelmer Vernooij
Merge trunk.
810
        data = self._get_entry(("git", sha, "X")).split(" ", 2)
0.254.2 by jelmer
use btree indexes
811
        return (data[0], (data[1], data[2]))
0.254.1 by Jelmer Vernooij
Add trivial index-based sha map.
812
813
    def revids(self):
814
        """List the revision ids known."""
0.254.36 by Jelmer Vernooij
Merge trunk.
815
        for key in self._iter_keys_prefix(("commit", None, None)):
0.254.2 by jelmer
use btree indexes
816
            yield key[1]
0.254.1 by Jelmer Vernooij
Add trivial index-based sha map.
817
0.254.21 by Jelmer Vernooij
Implement faster missing_revisions.
818
    def missing_revisions(self, revids):
819
        """Return set of all the revisions that are not present."""
820
        missing_revids = set(revids)
821
        for _, key, value in self._index.iter_entries((
0.254.37 by Jelmer Vernooij
merge trunk
822
            ("commit", revid, "X") for revid in revids)):
0.254.21 by Jelmer Vernooij
Implement faster missing_revisions.
823
            missing_revids.remove(key[1])
824
        return missing_revids
825
0.254.1 by Jelmer Vernooij
Add trivial index-based sha map.
826
    def sha1s(self):
827
        """List the SHA1s."""
0.254.36 by Jelmer Vernooij
Merge trunk.
828
        for key in self._iter_keys_prefix(("git", None, None)):
0.254.2 by jelmer
use btree indexes
829
            yield key[1]
0.254.19 by Jelmer Vernooij
Support upgrading sha maps.
830
831
0.200.844 by Jelmer Vernooij
Add infrastructure for multiple cache formats.
832
formats = registry.Registry()
833
formats.register(TdbGitCacheFormat().get_format_string(),
834
    TdbGitCacheFormat())
835
formats.register(SqliteGitCacheFormat().get_format_string(),
836
    SqliteGitCacheFormat())
0.254.43 by Jelmer Vernooij
Merge trunk.
837
formats.register(IndexGitCacheFormat().get_format_string(),
838
    IndexGitCacheFormat())
0.200.951 by Jelmer Vernooij
merge support for git object store-based caching mechanism.
839
# In the future, this will become the default:
840
# formats.register('default', IndexGitCacheFormat())
841
try:
842
    import tdb
843
except ImportError:
844
    formats.register('default', SqliteGitCacheFormat())
845
else:
846
    formats.register('default', TdbGitCacheFormat())
847
0.200.844 by Jelmer Vernooij
Add infrastructure for multiple cache formats.
848
849
850
def migrate_ancient_formats(repo_transport):
0.200.866 by Jelmer Vernooij
More docstrings, prefer migrating git.db to migrating git.tdb.
851
    # Prefer migrating git.db over git.tdb, since the latter may not 
852
    # be openable on some platforms.
853
    if repo_transport.has("git.db"):
854
        SqliteGitCacheFormat().initialize(repo_transport.clone("git"))
855
        repo_transport.rename("git.db", "git/idmap.db")
856
    elif repo_transport.has("git.tdb"):
0.200.844 by Jelmer Vernooij
Add infrastructure for multiple cache formats.
857
        TdbGitCacheFormat().initialize(repo_transport.clone("git"))
858
        repo_transport.rename("git.tdb", "git/idmap.tdb")
859
860
0.200.865 by Jelmer Vernooij
Support serving without --allow-writes.
861
def remove_readonly_transport_decorator(transport):
862
    if transport.is_readonly():
863
        return transport._decorated
864
    return transport
865
866
0.254.19 by Jelmer Vernooij
Support upgrading sha maps.
867
def from_repository(repository):
0.200.866 by Jelmer Vernooij
More docstrings, prefer migrating git.db to migrating git.tdb.
868
    """Open a cache file for a repository.
869
870
    If the repository is remote and there is no transport available from it
871
    this will use a local file in the users cache directory
872
    (typically ~/.cache/bazaar/git/)
873
874
    :param repository: A repository object
875
    """
0.200.844 by Jelmer Vernooij
Add infrastructure for multiple cache formats.
876
    repo_transport = getattr(repository, "_transport", None)
877
    if repo_transport is not None:
878
        # Migrate older cache formats
0.200.865 by Jelmer Vernooij
Support serving without --allow-writes.
879
        repo_transport = remove_readonly_transport_decorator(repo_transport)
0.200.844 by Jelmer Vernooij
Add infrastructure for multiple cache formats.
880
        try:
881
            repo_transport.mkdir("git")
882
        except bzrlib.errors.FileExists:
883
            pass
884
        else:
885
            migrate_ancient_formats(repo_transport)
886
    return BzrGitCacheFormat.from_repository(repository)