/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to cache.py

Merge a bunch of fixes from store-roundtrip-info.

Show diffs side-by-side

added added

removed removed

Lines of Context:
54
54
    return ret
55
55
 
56
56
 
57
 
def get_remote_cache_transport():
 
57
def get_remote_cache_transport(repository):
58
58
    """Retrieve the transport to use when accessing (unwritable) remote 
59
59
    repositories.
60
60
    """
61
 
    return get_transport(get_cache_dir())
 
61
    uuid = getattr(repository, "uuid", None)
 
62
    if uuid is None:
 
63
        path = get_cache_dir()
 
64
    else:
 
65
        path = os.path.join(get_cache_dir(), uuid)
 
66
        if not os.path.isdir(path):
 
67
            os.mkdir(path)
 
68
    return get_transport(path)
62
69
 
63
70
 
64
71
def check_pysqlite_version(sqlite3):
100
107
    def lookup_git_sha(self, sha):
101
108
        """Lookup a Git sha in the database.
102
109
        :param sha: Git object sha
103
 
        :return: (type, type_data) with type_data:
 
110
        :return: list with (type, type_data) tuples with type_data:
104
111
            commit: revid, tree_sha, verifiers
105
112
            blob: fileid, revid
106
113
            tree: fileid, revid
120
127
        """
121
128
        raise NotImplementedError(self.lookup_tree_id)
122
129
 
 
130
    def lookup_commit(self, revid):
 
131
        """Retrieve a Git commit SHA by Bazaar revision id.
 
132
        """
 
133
        raise NotImplementedError(self.lookup_commit)
 
134
 
123
135
    def revids(self):
124
136
        """List the revision ids known."""
125
137
        raise NotImplementedError(self.revids)
203
215
        :param repository: Repository to open the cache for
204
216
        :return: A `BzrGitCache`
205
217
        """
 
218
        from bzrlib.transport.local import LocalTransport
206
219
        repo_transport = getattr(repository, "_transport", None)
207
 
        if repo_transport is not None:
208
 
            # Even if we don't write to this repo, we should be able 
 
220
        if (repo_transport is not None and
 
221
            isinstance(repo_transport, LocalTransport)):
 
222
            # Even if we don't write to this repo, we should be able
209
223
            # to update its cache.
210
 
            repo_transport = remove_readonly_transport_decorator(repo_transport)
211
224
            try:
212
 
                repo_transport.mkdir('git')
213
 
            except bzrlib.errors.FileExists:
214
 
                pass
215
 
            transport = repo_transport.clone('git')
 
225
                repo_transport = remove_readonly_transport_decorator(repo_transport)
 
226
            except bzrlib.errors.ReadOnlyError:
 
227
                transport = None
 
228
            else:
 
229
                try:
 
230
                    repo_transport.mkdir('git')
 
231
                except bzrlib.errors.FileExists:
 
232
                    pass
 
233
                transport = repo_transport.clone('git')
216
234
        else:
217
 
            transport = get_remote_cache_transport()
 
235
            transport = None
 
236
        if transport is None:
 
237
            transport = get_remote_cache_transport(repository)
218
238
        return cls.from_transport(transport)
219
239
 
220
240
 
221
241
class CacheUpdater(object):
222
242
    """Base class for objects that can update a bzr-git cache."""
223
243
 
224
 
    def add_object(self, obj, ie, path):
 
244
    def add_object(self, obj, bzr_key_data, path):
225
245
        """Add an object.
226
246
 
227
247
        :param obj: Object type ("commit", "blob" or "tree")
228
 
        :param ie: Inventory entry (for blob/tree) or testament_sha in case
 
248
        :param bzr_key_data: bzr key store data or testament_sha in case
229
249
            of commit
230
250
        :param path: Path of the object (optional)
231
251
        """
263
283
        self._commit = None
264
284
        self._entries = []
265
285
 
266
 
    def add_object(self, obj, ie, path):
 
286
    def add_object(self, obj, bzr_key_data, path):
267
287
        if obj.type_name == "commit":
268
288
            self._commit = obj
269
 
            assert type(ie) is dict
270
 
            type_data = (self.revid, self._commit.tree, ie)
 
289
            assert type(bzr_key_data) is dict
 
290
            key = self.revid
 
291
            type_data = (self.revid, self._commit.tree, bzr_key_data)
271
292
            self.cache.idmap._by_revid[self.revid] = obj.id
272
293
        elif obj.type_name in ("blob", "tree"):
273
 
            if ie is not None:
 
294
            if bzr_key_data is not None:
274
295
                if obj.type_name == "blob":
275
 
                    revision = ie.revision
 
296
                    revision = bzr_key_data[1]
276
297
                else:
277
298
                    revision = self.revid
278
 
                type_data = (ie.file_id, revision)
 
299
                key = type_data = (bzr_key_data[0], revision)
279
300
                self.cache.idmap._by_fileid.setdefault(type_data[1], {})[type_data[0]] = obj.id
280
301
        else:
281
302
            raise AssertionError
282
 
        self.cache.idmap._by_sha[obj.id] = (obj.type_name, type_data)
 
303
        entry = (obj.type_name, type_data)
 
304
        self.cache.idmap._by_sha.setdefault(obj.id, {})[key] = entry
283
305
 
284
306
    def finish(self):
285
307
        if self._commit is None:
299
321
        return self._by_fileid[revision][fileid]
300
322
 
301
323
    def lookup_git_sha(self, sha):
302
 
        return self._by_sha[sha]
 
324
        for entry in self._by_sha[sha].itervalues():
 
325
            yield entry
303
326
 
304
327
    def lookup_tree_id(self, fileid, revision):
305
328
        return self._by_fileid[revision][fileid]
308
331
        return self._by_revid[revid]
309
332
 
310
333
    def revids(self):
311
 
        for key, (type, type_data) in self._by_sha.iteritems():
312
 
            if type == "commit":
313
 
                yield type_data[0]
 
334
        for key, entries in self._by_sha.iteritems():
 
335
            for (type, type_data) in entries.values():
 
336
                if type == "commit":
 
337
                    yield type_data[0]
314
338
 
315
339
    def sha1s(self):
316
340
        return self._by_sha.iterkeys()
326
350
        self._trees = []
327
351
        self._blobs = []
328
352
 
329
 
    def add_object(self, obj, ie, path):
 
353
    def add_object(self, obj, bzr_key_data, path):
330
354
        if obj.type_name == "commit":
331
355
            self._commit = obj
332
 
            self._testament3_sha1 = ie["testament3-sha1"]
333
 
            assert type(ie) is dict
 
356
            assert type(bzr_key_data) is dict
 
357
            self._testament3_sha1 = bzr_key_data.get("testament3-sha1")
334
358
        elif obj.type_name == "tree":
335
 
            if ie is not None:
336
 
                self._trees.append((obj.id, ie.file_id, self.revid))
 
359
            if bzr_key_data is not None:
 
360
                self._trees.append((obj.id, bzr_key_data[0], self.revid))
337
361
        elif obj.type_name == "blob":
338
 
            if ie is not None:
339
 
                self._blobs.append((obj.id, ie.file_id, ie.revision))
 
362
            if bzr_key_data is not None:
 
363
                self._blobs.append((obj.id, bzr_key_data[0], bzr_key_data[1]))
340
364
        else:
341
365
            raise AssertionError
342
366
 
447
471
            tree: fileid, revid
448
472
            blob: fileid, revid
449
473
        """
450
 
        row = self.db.execute("select revid, tree_sha, testament3_sha1 from commits where sha1 = ?", (sha,)).fetchone()
451
 
        if row is not None:
452
 
            return ("commit", (row[0], row[1], {"testament3-sha1": row[2]}))
453
 
        row = self.db.execute("select fileid, revid from blobs where sha1 = ?", (sha,)).fetchone()
454
 
        if row is not None:
455
 
            return ("blob", row)
456
 
        row = self.db.execute("select fileid, revid from trees where sha1 = ?", (sha,)).fetchone()
457
 
        if row is not None:
458
 
            return ("tree", row)
459
 
        raise KeyError(sha)
 
474
        found = False
 
475
        cursor = self.db.execute("select revid, tree_sha, testament3_sha1 from commits where sha1 = ?", (sha,))
 
476
        for row in cursor.fetchall():
 
477
            found = True
 
478
            if row[2] is not None:
 
479
                verifiers = {"testament3-sha1": row[2]}
 
480
            else:
 
481
                verifiers = {}
 
482
            yield ("commit", (row[0], row[1], verifiers))
 
483
        cursor = self.db.execute("select fileid, revid from blobs where sha1 = ?", (sha,))
 
484
        for row in cursor.fetchall():
 
485
            found = True
 
486
            yield ("blob", row)
 
487
        cursor = self.db.execute("select fileid, revid from trees where sha1 = ?", (sha,))
 
488
        for row in cursor.fetchall():
 
489
            found = True
 
490
            yield ("tree", row)
 
491
        if not found:
 
492
            raise KeyError(sha)
460
493
 
461
494
    def revids(self):
462
495
        """List the revision ids known."""
480
513
        self._commit = None
481
514
        self._entries = []
482
515
 
483
 
    def add_object(self, obj, ie, path):
 
516
    def add_object(self, obj, bzr_key_data, path):
484
517
        sha = obj.sha().digest()
485
518
        if obj.type_name == "commit":
486
519
            self.db["commit\0" + self.revid] = "\0".join((sha, obj.tree))
487
 
            assert type(ie) is dict, "was %r" % ie
488
 
            type_data = (self.revid, obj.tree, ie["testament3-sha1"])
 
520
            assert type(bzr_key_data) is dict, "was %r" % bzr_key_data
 
521
            type_data = (self.revid, obj.tree)
 
522
            try:
 
523
                type_data += (bzr_key_data["testament3-sha1"],)
 
524
            except KeyError:
 
525
                pass
489
526
            self._commit = obj
490
527
        elif obj.type_name == "blob":
491
 
            if ie is None:
 
528
            if bzr_key_data is None:
492
529
                return
493
 
            self.db["\0".join(("blob", ie.file_id, ie.revision))] = sha
494
 
            type_data = (ie.file_id, ie.revision)
 
530
            self.db["\0".join(("blob", bzr_key_data[0], bzr_key_data[1]))] = sha
 
531
            type_data = bzr_key_data
495
532
        elif obj.type_name == "tree":
496
 
            if ie is None:
 
533
            if bzr_key_data is None:
497
534
                return
498
 
            type_data = (ie.file_id, self.revid)
 
535
            (file_id, ) = bzr_key_data
 
536
            type_data = (file_id, self.revid)
499
537
        else:
500
538
            raise AssertionError
501
 
        self.db["git\0" + sha] = "\0".join((obj.type_name, ) + type_data)
 
539
        entry = "\0".join((obj.type_name, ) + type_data) + "\n"
 
540
        key = "git\0" + sha
 
541
        try:
 
542
            oldval = self.db[key]
 
543
        except KeyError:
 
544
            self.db[key] = entry
 
545
        else:
 
546
            if oldval[-1] != "\n":
 
547
                self.db[key] = "".join([oldval, "\n", entry])
 
548
            else:
 
549
                self.db[key] = "".join([oldval, entry])
502
550
 
503
551
    def finish(self):
504
552
        if self._commit is None:
508
556
 
509
557
TdbBzrGitCache = lambda p: BzrGitCache(TdbGitShaMap(p), None, TdbCacheUpdater)
510
558
 
 
559
 
511
560
class TdbGitCacheFormat(BzrGitCacheFormat):
512
561
    """Cache format for tdb-based caches."""
513
562
 
516
565
 
517
566
    def open(self, transport):
518
567
        try:
519
 
            basepath = transport.local_abspath(".")
 
568
            basepath = transport.local_abspath(".").encode(osutils._fs_enc)
520
569
        except bzrlib.errors.NotLocalUrl:
521
570
            basepath = get_cache_dir()
 
571
        assert isinstance(basepath, str)
522
572
        try:
523
573
            return TdbBzrGitCache(os.path.join(basepath, "idmap.tdb"))
524
574
        except ImportError:
547
597
        if path is None:
548
598
            self.db = {}
549
599
        else:
 
600
            assert isinstance(path, str)
550
601
            if not mapdbs().has_key(path):
551
602
                mapdbs()[path] = tdb.Tdb(path, self.TDB_HASH_SIZE, tdb.DEFAULT,
552
603
                                          os.O_RDWR|os.O_CREAT)
576
627
        return "%s(%r)" % (self.__class__.__name__, self.path)
577
628
 
578
629
    def lookup_commit(self, revid):
579
 
        return sha_to_hex(self.db["commit\0" + revid][:20])
 
630
        try:
 
631
            return sha_to_hex(self.db["commit\0" + revid][:20])
 
632
        except KeyError:
 
633
            raise KeyError("No cache entry for %r" % revid)
580
634
 
581
635
    def lookup_blob_id(self, fileid, revision):
582
636
        return sha_to_hex(self.db["\0".join(("blob", fileid, revision))])
592
646
        """
593
647
        if len(sha) == 40:
594
648
            sha = hex_to_sha(sha)
595
 
        data = self.db["git\0" + sha].split("\0")
596
 
        if data[0] == "commit":
597
 
            if len(data) == 3:
598
 
                return (data[0], (data[1], data[2], {}))
 
649
        value = self.db["git\0" + sha]
 
650
        for data in value.splitlines():
 
651
            data = data.split("\0")
 
652
            if data[0] == "commit":
 
653
                if len(data) == 3:
 
654
                    yield (data[0], (data[1], data[2], {}))
 
655
                else:
 
656
                    yield (data[0], (data[1], data[2], {"testament3-sha1": data[3]}))
 
657
            elif data[0] in ("tree", "blob"):
 
658
                yield (data[0], tuple(data[1:]))
599
659
            else:
600
 
                return (data[0], (data[1], data[2], {"testament3-sha1": data[3]}))
601
 
        else:
602
 
            return (data[0], tuple(data[1:]))
 
660
                raise AssertionError("unknown type %r" % data[0])
603
661
 
604
662
    def missing_revisions(self, revids):
605
663
        ret = set()
664
722
        self._entries = []
665
723
        self._cache_objs = set()
666
724
 
667
 
    def add_object(self, obj, ie, path):
 
725
    def add_object(self, obj, bzr_key_data, path):
668
726
        if obj.type_name == "commit":
669
727
            self._commit = obj
670
 
            assert type(ie) is dict
 
728
            assert type(bzr_key_data) is dict
671
729
            self.cache.idmap._add_git_sha(obj.id, "commit",
672
 
                (self.revid, obj.tree, ie))
 
730
                (self.revid, obj.tree, bzr_key_data))
673
731
            self.cache.idmap._add_node(("commit", self.revid, "X"),
674
732
                " ".join((obj.id, obj.tree)))
675
733
            self._cache_objs.add((obj, path))
676
734
        elif obj.type_name == "blob":
677
 
            self.cache.idmap._add_git_sha(obj.id, "blob",
678
 
                (ie.file_id, ie.revision))
679
 
            self.cache.idmap._add_node(("blob", ie.file_id, ie.revision), obj.id)
680
 
            if ie.kind == "symlink":
681
 
                self._cache_objs.add((obj, path))
 
735
            self.cache.idmap._add_git_sha(obj.id, "blob", bzr_key_data)
 
736
            self.cache.idmap._add_node(("blob", bzr_key_data[0],
 
737
                bzr_key_data[1]), obj.id)
682
738
        elif obj.type_name == "tree":
683
739
            self.cache.idmap._add_git_sha(obj.id, "tree",
684
 
                (ie.file_id, self.revid))
 
740
                (bzr_key_data[0], self.revid))
685
741
            self._cache_objs.add((obj, path))
686
742
        else:
687
743
            raise AssertionError
822
878
            except StopIteration:
823
879
                raise KeyError
824
880
 
825
 
    def _iter_keys_prefix(self, prefix):
 
881
    def _iter_entries_prefix(self, prefix):
826
882
        for entry in self._index.iter_entries_prefix([prefix]):
827
 
            yield entry[1]
 
883
            yield (entry[1], entry[2])
828
884
        if self._builder is not None:
829
885
            for entry in self._builder.iter_entries_prefix([prefix]):
830
 
                yield entry[1]
 
886
                yield (entry[1], entry[2])
831
887
 
832
888
    def lookup_commit(self, revid):
833
889
        return self._get_entry(("commit", revid, "X"))[:40]
836
892
        if hexsha is not None:
837
893
            self._name.update(hexsha)
838
894
            if type == "commit":
839
 
                td = (type_data[0], type_data[1], type_data[2]["testament3-sha1"])
 
895
                td = (type_data[0], type_data[1])
 
896
                try:
 
897
                    td += (type_data[2]["testament3-sha1"],)
 
898
                except KeyError:
 
899
                    pass
840
900
            else:
841
901
                td = type_data
842
902
            self._add_node(("git", hexsha, "X"), " ".join((type,) + td))
851
911
    def lookup_git_sha(self, sha):
852
912
        if len(sha) == 20:
853
913
            sha = sha_to_hex(sha)
854
 
        data = self._get_entry(("git", sha, "X")).split(" ", 3)
855
 
        if data[0] == "commit":
856
 
            return ("commit", (data[1], data[2], {"testament3-sha1": data[3]}))
857
 
        else:
858
 
            return (data[0], tuple(data[1:]))
 
914
        found = False
 
915
        for key, value in self._iter_entries_prefix(("git", sha, None)):
 
916
            found = True
 
917
            data = value.split(" ", 3)
 
918
            if data[0] == "commit":
 
919
                if data[3]:
 
920
                    verifiers = {"testament3-sha1": data[3]}
 
921
                else:
 
922
                    verifiers = {}
 
923
                yield ("commit", (data[1], data[2], verifiers))
 
924
            else:
 
925
                yield (data[0], tuple(data[1:]))
 
926
        if not found:
 
927
            raise KeyError(sha)
859
928
 
860
929
    def revids(self):
861
930
        """List the revision ids known."""
862
 
        for key in self._iter_keys_prefix(("commit", None, None)):
 
931
        for key, value in self._iter_entries_prefix(("commit", None, None)):
863
932
            yield key[1]
864
933
 
865
934
    def missing_revisions(self, revids):
872
941
 
873
942
    def sha1s(self):
874
943
        """List the SHA1s."""
875
 
        for key in self._iter_keys_prefix(("git", None, None)):
 
944
        for key, value in self._iter_entries_prefix(("git", None, None)):
876
945
            yield key[1]
877
946
 
878
947
 
895
964
 
896
965
 
897
966
def migrate_ancient_formats(repo_transport):
 
967
    # Migrate older cache formats
 
968
    repo_transport = remove_readonly_transport_decorator(repo_transport)
 
969
    has_sqlite = repo_transport.has("git.db")
 
970
    has_tdb = repo_transport.has("git.tdb")
 
971
    if not has_sqlite or has_tdb:
 
972
        return
 
973
    try:
 
974
        repo_transport.mkdir("git")
 
975
    except bzrlib.errors.FileExists:
 
976
        return
898
977
    # Prefer migrating git.db over git.tdb, since the latter may not 
899
978
    # be openable on some platforms.
900
 
    if repo_transport.has("git.db"):
 
979
    if has_sqlite:
901
980
        SqliteGitCacheFormat().initialize(repo_transport.clone("git"))
902
981
        repo_transport.rename("git.db", "git/idmap.db")
903
 
    elif repo_transport.has("git.tdb"):
 
982
    elif has_tdb:
904
983
        TdbGitCacheFormat().initialize(repo_transport.clone("git"))
905
984
        repo_transport.rename("git.tdb", "git/idmap.tdb")
906
985
 
907
986
 
908
987
def remove_readonly_transport_decorator(transport):
909
988
    if transport.is_readonly():
910
 
        return transport._decorated
 
989
        try:
 
990
            return transport._decorated
 
991
        except AttributeError:
 
992
            raise bzrlib.errors.ReadOnlyError(transport)
911
993
    return transport
912
994
 
913
995
 
922
1004
    """
923
1005
    repo_transport = getattr(repository, "_transport", None)
924
1006
    if repo_transport is not None:
925
 
        # Migrate older cache formats
926
 
        repo_transport = remove_readonly_transport_decorator(repo_transport)
927
1007
        try:
928
 
            repo_transport.mkdir("git")
929
 
        except bzrlib.errors.FileExists:
930
 
            pass
931
 
        else:
932
1008
            migrate_ancient_formats(repo_transport)
 
1009
        except bzrlib.errors.ReadOnlyError:
 
1010
            pass # Not much we can do
933
1011
    return BzrGitCacheFormat.from_repository(repository)