/brz/remove-bazaar

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