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