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