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