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