/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 breezy/git/cache.py

  • Committer: Jelmer Vernooij
  • Date: 2018-06-14 17:59:16 UTC
  • mto: This revision was merged to the branch mainline in revision 7065.
  • Revision ID: jelmer@jelmer.uk-20180614175916-a2e2xh5k533guq1x
Move breezy.plugins.git to breezy.git.

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
"""Map from Git sha's to Bazaar objects."""
18
18
 
 
19
from __future__ import absolute_import
 
20
 
19
21
from dulwich.objects import (
20
22
    sha_to_hex,
21
23
    hex_to_sha,
28
30
    )
29
31
 
30
32
from .. import (
31
 
    bedding,
32
33
    errors as bzr_errors,
33
34
    osutils,
34
35
    registry,
40
41
    versionedfile,
41
42
    )
42
43
from ..transport import (
43
 
    get_transport_from_path,
 
44
    get_transport,
44
45
    )
45
46
 
46
47
 
47
48
def get_cache_dir():
48
 
    path = os.path.join(bedding.cache_dir(), "git")
49
 
    if not os.path.isdir(path):
50
 
        os.mkdir(path)
51
 
    return path
 
49
    try:
 
50
        from xdg.BaseDirectory import xdg_cache_home
 
51
    except ImportError:
 
52
        from ..config import config_dir
 
53
        ret = os.path.join(config_dir(), "git")
 
54
    else:
 
55
        ret = os.path.join(xdg_cache_home, "breezy", "git")
 
56
    if not os.path.isdir(ret):
 
57
        os.makedirs(ret)
 
58
    return ret
52
59
 
53
60
 
54
61
def get_remote_cache_transport(repository):
55
 
    """Retrieve the transport to use when accessing (unwritable) remote
 
62
    """Retrieve the transport to use when accessing (unwritable) remote 
56
63
    repositories.
57
64
    """
58
65
    uuid = getattr(repository, "uuid", None)
62
69
        path = os.path.join(get_cache_dir(), uuid)
63
70
        if not os.path.isdir(path):
64
71
            os.mkdir(path)
65
 
    return get_transport_from_path(path)
 
72
    return get_transport(path)
66
73
 
67
74
 
68
75
def check_pysqlite_version(sqlite3):
69
76
    """Check that sqlite library is compatible.
70
77
 
71
78
    """
72
 
    if (sqlite3.sqlite_version_info[0] < 3
73
 
            or (sqlite3.sqlite_version_info[0] == 3 and
74
 
                sqlite3.sqlite_version_info[1] < 3)):
 
79
    if (sqlite3.sqlite_version_info[0] < 3 or
 
80
            (sqlite3.sqlite_version_info[0] == 3 and
 
81
             sqlite3.sqlite_version_info[1] < 3)):
75
82
        trace.warning('Needs at least sqlite 3.3.x')
76
83
        raise bzr_errors.BzrError("incompatible sqlite library")
77
84
 
78
 
 
79
85
try:
80
86
    try:
81
87
        import sqlite3
82
88
        check_pysqlite_version(sqlite3)
83
 
    except (ImportError, bzr_errors.BzrError):
 
89
    except (ImportError, bzr_errors.BzrError) as e:
84
90
        from pysqlite2 import dbapi2 as sqlite3
85
91
        check_pysqlite_version(sqlite3)
86
 
except BaseException:
 
92
except:
87
93
    trace.warning('Needs at least Python2.5 or Python2.4 with the pysqlite2 '
88
 
                  'module')
 
94
            'module')
89
95
    raise bzr_errors.BzrError("missing sqlite library")
90
96
 
91
97
 
92
98
_mapdbs = threading.local()
93
 
 
94
 
 
95
99
def mapdbs():
96
100
    """Get a cache for this thread's db connections."""
97
101
    try:
209
213
        """Open a cache file for a repository.
210
214
 
211
215
        This will use the repository's transport to store the cache file, or
212
 
        use the users global cache directory if the repository has no
 
216
        use the users global cache directory if the repository has no 
213
217
        transport associated with it.
214
218
 
215
219
        :param repository: Repository to open the cache for
217
221
        """
218
222
        from ..transport.local import LocalTransport
219
223
        repo_transport = getattr(repository, "_transport", None)
220
 
        if (repo_transport is not None
221
 
                and isinstance(repo_transport, LocalTransport)):
 
224
        if (repo_transport is not None and
 
225
            isinstance(repo_transport, LocalTransport)):
222
226
            # Even if we don't write to this repo, we should be able
223
227
            # to update its cache.
224
228
            try:
225
 
                repo_transport = remove_readonly_transport_decorator(
226
 
                    repo_transport)
 
229
                repo_transport = remove_readonly_transport_decorator(repo_transport)
227
230
            except bzr_errors.ReadOnlyError:
228
231
                transport = None
229
232
            else:
264
267
        self._cache_updater_klass = cache_updater_klass
265
268
 
266
269
    def get_updater(self, rev):
267
 
        """Update an object that implements the CacheUpdater interface for
 
270
        """Update an object that implements the CacheUpdater interface for 
268
271
        updating this cache.
269
272
        """
270
273
        return self._cache_updater_klass(self, rev)
271
274
 
272
275
 
273
 
def DictBzrGitCache():
274
 
    return BzrGitCache(DictGitShaMap(), DictCacheUpdater)
 
276
DictBzrGitCache = lambda: BzrGitCache(DictGitShaMap(), DictCacheUpdater)
275
277
 
276
278
 
277
279
class DictCacheUpdater(CacheUpdater):
288
290
        if isinstance(obj, tuple):
289
291
            (type_name, hexsha) = obj
290
292
        else:
291
 
            type_name = obj.type_name.decode('ascii')
 
293
            type_name = obj.type_name
292
294
            hexsha = obj.id
293
 
        if not isinstance(hexsha, bytes):
294
 
            raise TypeError(hexsha)
295
295
        if type_name == "commit":
296
296
            self._commit = obj
297
297
            if type(bzr_key_data) is not dict:
302
302
        elif type_name in ("blob", "tree"):
303
303
            if bzr_key_data is not None:
304
304
                key = type_data = bzr_key_data
305
 
                self.cache.idmap._by_fileid.setdefault(type_data[1], {})[
306
 
                    type_data[0]] = hexsha
 
305
                self.cache.idmap._by_fileid.setdefault(type_data[1], {})[type_data[0]] = hexsha
307
306
        else:
308
307
            raise AssertionError
309
308
        entry = (type_name, type_data)
327
326
        return self._by_fileid[revision][fileid]
328
327
 
329
328
    def lookup_git_sha(self, sha):
330
 
        if not isinstance(sha, bytes):
331
 
            raise TypeError(sha)
332
 
        for entry in self._by_sha[sha].values():
 
329
        for entry in self._by_sha[sha].itervalues():
333
330
            yield entry
334
331
 
335
332
    def lookup_tree_id(self, fileid, revision):
339
336
        return self._by_revid[revid]
340
337
 
341
338
    def revids(self):
342
 
        for key, entries in self._by_sha.items():
 
339
        for key, entries in self._by_sha.iteritems():
343
340
            for (type, type_data) in entries.values():
344
341
                if type == "commit":
345
342
                    yield type_data[0]
346
343
 
347
344
    def sha1s(self):
348
 
        return self._by_sha.keys()
 
345
        return self._by_sha.iterkeys()
349
346
 
350
347
 
351
348
class SqliteCacheUpdater(CacheUpdater):
362
359
        if isinstance(obj, tuple):
363
360
            (type_name, hexsha) = obj
364
361
        else:
365
 
            type_name = obj.type_name.decode('ascii')
 
362
            type_name = obj.type_name
366
363
            hexsha = obj.id
367
 
        if not isinstance(hexsha, bytes):
368
 
            raise TypeError(hexsha)
369
364
        if type_name == "commit":
370
365
            self._commit = obj
371
366
            if type(bzr_key_data) is not dict:
390
385
            "replace into blobs (sha1, fileid, revid) values (?, ?, ?)",
391
386
            self._blobs)
392
387
        self.db.execute(
393
 
            "replace into commits (sha1, revid, tree_sha, testament3_sha1) "
394
 
            "values (?, ?, ?, ?)",
395
 
            (self._commit.id, self.revid, self._commit.tree,
396
 
                self._testament3_sha1))
 
388
            "replace into commits (sha1, revid, tree_sha, testament3_sha1) values (?, ?, ?, ?)",
 
389
            (self._commit.id, self.revid, self._commit.tree, self._testament3_sha1))
397
390
        return self._commit
398
391
 
399
392
 
400
 
def SqliteBzrGitCache(p):
401
 
    return BzrGitCache(SqliteGitShaMap(p), SqliteCacheUpdater)
 
393
SqliteBzrGitCache = lambda p: BzrGitCache(SqliteGitShaMap(p), SqliteCacheUpdater)
402
394
 
403
395
 
404
396
class SqliteGitCacheFormat(BzrGitCacheFormat):
422
414
        if path is None:
423
415
            self.db = sqlite3.connect(":memory:")
424
416
        else:
425
 
            if path not in mapdbs():
 
417
            if not mapdbs().has_key(path):
426
418
                mapdbs()[path] = sqlite3.connect(path)
427
419
            self.db = mapdbs()[path]
428
420
        self.db.text_factory = str
440
432
            revid text not null
441
433
        );
442
434
        create index if not exists blobs_sha1 on blobs(sha1);
443
 
        create unique index if not exists blobs_fileid_revid on blobs(
444
 
            fileid, revid);
 
435
        create unique index if not exists blobs_fileid_revid on blobs(fileid, revid);
445
436
        create table if not exists trees(
446
437
            sha1 text unique not null check(length(sha1) == 40),
447
438
            fileid text not null,
448
439
            revid text not null
449
440
        );
450
441
        create unique index if not exists trees_sha1 on trees(sha1);
451
 
        create unique index if not exists trees_fileid_revid on trees(
452
 
            fileid, revid);
 
442
        create unique index if not exists trees_fileid_revid on trees(fileid, revid);
453
443
""")
454
444
        try:
455
445
            self.db.executescript(
456
446
                "ALTER TABLE commits ADD testament3_sha1 TEXT;")
457
447
        except sqlite3.OperationalError:
458
 
            pass  # Column already exists.
 
448
            pass # Column already exists.
459
449
 
460
450
    def __repr__(self):
461
451
        return "%s(%r)" % (self.__class__.__name__, self.path)
462
452
 
463
453
    def lookup_commit(self, revid):
464
 
        cursor = self.db.execute("select sha1 from commits where revid = ?",
465
 
                                 (revid,))
 
454
        cursor = self.db.execute("select sha1 from commits where revid = ?", 
 
455
            (revid,))
466
456
        row = cursor.fetchone()
467
457
        if row is not None:
468
458
            return row[0]
472
462
        self.db.commit()
473
463
 
474
464
    def lookup_blob_id(self, fileid, revision):
475
 
        row = self.db.execute(
476
 
            "select sha1 from blobs where fileid = ? and revid = ?",
477
 
            (fileid, revision)).fetchone()
 
465
        row = self.db.execute("select sha1 from blobs where fileid = ? and revid = ?", (fileid, revision)).fetchone()
478
466
        if row is not None:
479
467
            return row[0]
480
468
        raise KeyError(fileid)
481
469
 
482
470
    def lookup_tree_id(self, fileid, revision):
483
 
        row = self.db.execute(
484
 
            "select sha1 from trees where fileid = ? and revid = ?",
485
 
            (fileid, revision)).fetchone()
 
471
        row = self.db.execute("select sha1 from trees where fileid = ? and revid = ?", (fileid, revision)).fetchone()
486
472
        if row is not None:
487
473
            return row[0]
488
474
        raise KeyError(fileid)
497
483
            blob: fileid, revid
498
484
        """
499
485
        found = False
500
 
        cursor = self.db.execute(
501
 
            "select revid, tree_sha, testament3_sha1 from commits where "
502
 
            "sha1 = ?", (sha,))
 
486
        cursor = self.db.execute("select revid, tree_sha, testament3_sha1 from commits where sha1 = ?", (sha,))
503
487
        for row in cursor.fetchall():
504
488
            found = True
505
489
            if row[2] is not None:
507
491
            else:
508
492
                verifiers = {}
509
493
            yield ("commit", (row[0], row[1], verifiers))
510
 
        cursor = self.db.execute(
511
 
            "select fileid, revid from blobs where sha1 = ?", (sha,))
 
494
        cursor = self.db.execute("select fileid, revid from blobs where sha1 = ?", (sha,))
512
495
        for row in cursor.fetchall():
513
496
            found = True
514
497
            yield ("blob", row)
515
 
        cursor = self.db.execute(
516
 
            "select fileid, revid from trees where sha1 = ?", (sha,))
 
498
        cursor = self.db.execute("select fileid, revid from trees where sha1 = ?", (sha,))
517
499
        for row in cursor.fetchall():
518
500
            found = True
519
501
            yield ("tree", row)
528
510
        """List the SHA1s."""
529
511
        for table in ("blobs", "commits", "trees"):
530
512
            for (sha,) in self.db.execute("select sha1 from %s" % table):
531
 
                yield sha.encode('ascii')
 
513
                yield sha
532
514
 
533
515
 
534
516
class TdbCacheUpdater(CacheUpdater):
547
529
            (type_name, hexsha) = obj
548
530
            sha = hex_to_sha(hexsha)
549
531
        else:
550
 
            type_name = obj.type_name.decode('ascii')
 
532
            type_name = obj.type_name
551
533
            sha = obj.sha().digest()
552
534
        if type_name == "commit":
553
 
            self.db[b"commit\0" + self.revid] = b"\0".join((sha, obj.tree))
 
535
            self.db["commit\0" + self.revid] = "\0".join((sha, obj.tree))
554
536
            if type(bzr_key_data) is not dict:
555
537
                raise TypeError(bzr_key_data)
556
538
            type_data = (self.revid, obj.tree)
562
544
        elif type_name == "blob":
563
545
            if bzr_key_data is None:
564
546
                return
565
 
            self.db[b"\0".join(
566
 
                (b"blob", bzr_key_data[0], bzr_key_data[1]))] = sha
 
547
            self.db["\0".join(("blob", bzr_key_data[0], bzr_key_data[1]))] = sha
567
548
            type_data = bzr_key_data
568
549
        elif type_name == "tree":
569
550
            if bzr_key_data is None:
571
552
            type_data = bzr_key_data
572
553
        else:
573
554
            raise AssertionError
574
 
        entry = b"\0".join((type_name.encode('ascii'), ) + type_data) + b"\n"
575
 
        key = b"git\0" + sha
 
555
        entry = "\0".join((type_name, ) + type_data) + "\n"
 
556
        key = "git\0" + sha
576
557
        try:
577
558
            oldval = self.db[key]
578
559
        except KeyError:
579
560
            self.db[key] = entry
580
561
        else:
581
 
            if not oldval.endswith(b'\n'):
582
 
                self.db[key] = b"".join([oldval, b"\n", entry])
 
562
            if oldval[-1] != "\n":
 
563
                self.db[key] = "".join([oldval, "\n", entry])
583
564
            else:
584
 
                self.db[key] = b"".join([oldval, entry])
 
565
                self.db[key] = "".join([oldval, entry])
585
566
 
586
567
    def finish(self):
587
568
        if self._commit is None:
589
570
        return self._commit
590
571
 
591
572
 
592
 
def TdbBzrGitCache(p):
593
 
    return BzrGitCache(TdbGitShaMap(p), TdbCacheUpdater)
 
573
TdbBzrGitCache = lambda p: BzrGitCache(TdbGitShaMap(p), TdbCacheUpdater)
594
574
 
595
575
 
596
576
class TdbGitCacheFormat(BzrGitCacheFormat):
601
581
 
602
582
    def open(self, transport):
603
583
        try:
604
 
            basepath = transport.local_abspath(".")
 
584
            basepath = transport.local_abspath(".").encode(osutils._fs_enc)
605
585
        except bzr_errors.NotLocalUrl:
606
586
            basepath = get_cache_dir()
 
587
        if type(basepath) is not str:
 
588
            raise TypeError(basepath)
607
589
        try:
608
590
            return TdbBzrGitCache(os.path.join(basepath, "idmap.tdb"))
609
591
        except ImportError:
632
614
        if path is None:
633
615
            self.db = {}
634
616
        else:
635
 
            if path not in mapdbs():
 
617
            if type(path) is not str:
 
618
                raise TypeError(path)
 
619
            if not mapdbs().has_key(path):
636
620
                mapdbs()[path] = tdb.Tdb(path, self.TDB_HASH_SIZE, tdb.DEFAULT,
637
 
                                         os.O_RDWR | os.O_CREAT)
 
621
                                          os.O_RDWR|os.O_CREAT)
638
622
            self.db = mapdbs()[path]
639
623
        try:
640
 
            if int(self.db[b"version"]) not in (2, 3):
641
 
                trace.warning(
642
 
                    "SHA Map is incompatible (%s -> %d), rebuilding database.",
643
 
                    self.db[b"version"], self.TDB_MAP_VERSION)
 
624
            if int(self.db["version"]) not in (2, 3):
 
625
                trace.warning("SHA Map is incompatible (%s -> %d), rebuilding database.",
 
626
                              self.db["version"], self.TDB_MAP_VERSION)
644
627
                self.db.clear()
645
628
        except KeyError:
646
629
            pass
647
 
        self.db[b"version"] = b'%d' % self.TDB_MAP_VERSION
 
630
        self.db["version"] = str(self.TDB_MAP_VERSION)
648
631
 
649
632
    def start_write_group(self):
650
633
        """Start writing changes."""
663
646
 
664
647
    def lookup_commit(self, revid):
665
648
        try:
666
 
            return sha_to_hex(self.db[b"commit\0" + revid][:20])
 
649
            return sha_to_hex(self.db["commit\0" + revid][:20])
667
650
        except KeyError:
668
651
            raise KeyError("No cache entry for %r" % revid)
669
652
 
670
653
    def lookup_blob_id(self, fileid, revision):
671
 
        return sha_to_hex(self.db[b"\0".join((b"blob", fileid, revision))])
 
654
        return sha_to_hex(self.db["\0".join(("blob", fileid, revision))])
672
655
 
673
656
    def lookup_git_sha(self, sha):
674
657
        """Lookup a Git sha in the database.
681
664
        """
682
665
        if len(sha) == 40:
683
666
            sha = hex_to_sha(sha)
684
 
        value = self.db[b"git\0" + sha]
 
667
        value = self.db["git\0" + sha]
685
668
        for data in value.splitlines():
686
 
            data = data.split(b"\0")
687
 
            type_name = data[0].decode('ascii')
688
 
            if type_name == "commit":
 
669
            data = data.split("\0")
 
670
            if data[0] == "commit":
689
671
                if len(data) == 3:
690
 
                    yield (type_name, (data[1], data[2], {}))
 
672
                    yield (data[0], (data[1], data[2], {}))
691
673
                else:
692
 
                    yield (type_name, (data[1], data[2],
693
 
                                       {"testament3-sha1": data[3]}))
694
 
            elif type_name in ("tree", "blob"):
695
 
                yield (type_name, tuple(data[1:]))
 
674
                    yield (data[0], (data[1], data[2], {"testament3-sha1": data[3]}))
 
675
            elif data[0] in ("tree", "blob"):
 
676
                yield (data[0], tuple(data[1:]))
696
677
            else:
697
 
                raise AssertionError("unknown type %r" % type_name)
 
678
                raise AssertionError("unknown type %r" % data[0])
698
679
 
699
680
    def missing_revisions(self, revids):
700
681
        ret = set()
701
682
        for revid in revids:
702
 
            if self.db.get(b"commit\0" + revid) is None:
 
683
            if self.db.get("commit\0" + revid) is None:
703
684
                ret.add(revid)
704
685
        return ret
705
686
 
706
 
    def _keys(self):
707
 
        return self.db.keys()
708
 
 
709
687
    def revids(self):
710
688
        """List the revision ids known."""
711
 
        for key in self._keys():
712
 
            if key.startswith(b"commit\0"):
 
689
        for key in self.db.iterkeys():
 
690
            if key.startswith("commit\0"):
713
691
                yield key[7:]
714
692
 
715
693
    def sha1s(self):
716
694
        """List the SHA1s."""
717
 
        for key in self._keys():
718
 
            if key.startswith(b"git\0"):
 
695
        for key in self.db.iterkeys():
 
696
            if key.startswith("git\0"):
719
697
                yield sha_to_hex(key[4:])
720
698
 
721
699
 
726
704
 
727
705
    def add(self, obj):
728
706
        self._vf.insert_record_stream(
729
 
            [versionedfile.ChunkedContentFactory(
730
 
                (obj.id,), [], None, obj.as_legacy_object_chunks())])
 
707
            [versionedfile.ChunkedContentFactory((obj.id,), [], None,
 
708
                obj.as_legacy_object_chunks())])
731
709
 
732
710
    def __getitem__(self, sha):
733
711
        stream = self._vf.get_record_stream([(sha,)], 'unordered', True)
734
 
        entry = next(stream)
 
712
        entry = stream.next() 
735
713
        if entry.storage_kind == 'absent':
736
714
            raise KeyError(sha)
737
715
        return ShaFile._parse_legacy_object(entry.get_bytes_as('fulltext'))
750
728
        if isinstance(obj, tuple):
751
729
            (type_name, hexsha) = obj
752
730
        else:
753
 
            type_name = obj.type_name.decode('ascii')
 
731
            type_name = obj.type_name
754
732
            hexsha = obj.id
755
733
        if type_name == "commit":
756
734
            self._commit = obj
757
735
            if type(bzr_key_data) is not dict:
758
736
                raise TypeError(bzr_key_data)
759
 
            self.cache.idmap._add_git_sha(hexsha, b"commit",
760
 
                                          (self.revid, obj.tree, bzr_key_data))
761
 
            self.cache.idmap._add_node((b"commit", self.revid, b"X"),
762
 
                                       b" ".join((hexsha, obj.tree)))
 
737
            self.cache.idmap._add_git_sha(hexsha, "commit",
 
738
                (self.revid, obj.tree, bzr_key_data))
 
739
            self.cache.idmap._add_node(("commit", self.revid, "X"),
 
740
                " ".join((hexsha, obj.tree)))
763
741
        elif type_name == "blob":
764
 
            self.cache.idmap._add_git_sha(hexsha, b"blob", bzr_key_data)
765
 
            self.cache.idmap._add_node((b"blob", bzr_key_data[0],
766
 
                                        bzr_key_data[1]), hexsha)
 
742
            self.cache.idmap._add_git_sha(hexsha, "blob", bzr_key_data)
 
743
            self.cache.idmap._add_node(("blob", bzr_key_data[0],
 
744
                bzr_key_data[1]), hexsha)
767
745
        elif type_name == "tree":
768
 
            self.cache.idmap._add_git_sha(hexsha, b"tree", bzr_key_data)
 
746
            self.cache.idmap._add_git_sha(hexsha, "tree", bzr_key_data)
769
747
        else:
770
748
            raise AssertionError
771
749
 
776
754
class IndexBzrGitCache(BzrGitCache):
777
755
 
778
756
    def __init__(self, transport=None):
 
757
        mapper = versionedfile.ConstantMapper("trees")
779
758
        shamap = IndexGitShaMap(transport.clone('index'))
 
759
        from .transportgit import TransportObjectStore
780
760
        super(IndexBzrGitCache, self).__init__(shamap, IndexCacheUpdater)
781
761
 
782
762
 
820
800
            for name in self._transport.list_dir("."):
821
801
                if not name.endswith(".rix"):
822
802
                    continue
823
 
                x = _mod_btree_index.BTreeGraphIndex(
824
 
                    self._transport, name, self._transport.stat(name).st_size)
 
803
                x = _mod_btree_index.BTreeGraphIndex(self._transport, name,
 
804
                    self._transport.stat(name).st_size)
825
805
                self._index.insert_index(0, x)
826
806
 
827
807
    @classmethod
833
813
            except bzr_errors.FileExists:
834
814
                pass
835
815
            return cls(transport.clone('git'))
836
 
        return cls(get_transport_from_path(get_cache_dir()))
 
816
        from ..transport import get_transport
 
817
        return cls(get_transport(get_cache_dir()))
837
818
 
838
819
    def __repr__(self):
839
820
        if self._transport is not None:
843
824
 
844
825
    def repack(self):
845
826
        if self._builder is not None:
846
 
            raise bzr_errors.BzrError('builder already open')
 
827
            raise errors.BzrError('builder already open')
847
828
        self.start_write_group()
848
829
        self._builder.add_nodes(
849
830
            ((key, value) for (_, key, value) in
859
840
 
860
841
    def start_write_group(self):
861
842
        if self._builder is not None:
862
 
            raise bzr_errors.BzrError('builder already open')
 
843
            raise errors.BzrError('builder already open')
863
844
        self._builder = _mod_btree_index.BTreeBuilder(0, key_elements=3)
864
845
        self._name = osutils.sha()
865
846
 
866
847
    def commit_write_group(self):
867
848
        if self._builder is None:
868
 
            raise bzr_errors.BzrError('builder not open')
 
849
            raise errors.BzrError('builder not open')
869
850
        stream = self._builder.finish()
870
851
        name = self._name.hexdigest() + ".rix"
871
852
        size = self._transport.put_file(name, stream)
876
857
 
877
858
    def abort_write_group(self):
878
859
        if self._builder is None:
879
 
            raise bzr_errors.BzrError('builder not open')
 
860
            raise errors.BzrError('builder not open')
880
861
        self._builder = None
881
862
        self._name = None
882
863
 
892
873
    def _get_entry(self, key):
893
874
        entries = self._index.iter_entries([key])
894
875
        try:
895
 
            return next(entries)[2]
 
876
            return entries.next()[2]
896
877
        except StopIteration:
897
878
            if self._builder is None:
898
879
                raise KeyError
899
880
            entries = self._builder.iter_entries([key])
900
881
            try:
901
 
                return next(entries)[2]
 
882
                return entries.next()[2]
902
883
            except StopIteration:
903
884
                raise KeyError
904
885
 
910
891
                yield (entry[1], entry[2])
911
892
 
912
893
    def lookup_commit(self, revid):
913
 
        return self._get_entry((b"commit", revid, b"X"))[:40]
 
894
        return self._get_entry(("commit", revid, "X"))[:40]
914
895
 
915
896
    def _add_git_sha(self, hexsha, type, type_data):
916
897
        if hexsha is not None:
917
898
            self._name.update(hexsha)
918
 
            if type == b"commit":
 
899
            if type == "commit":
919
900
                td = (type_data[0], type_data[1])
920
901
                try:
921
902
                    td += (type_data[2]["testament3-sha1"],)
923
904
                    pass
924
905
            else:
925
906
                td = type_data
926
 
            self._add_node((b"git", hexsha, b"X"), b" ".join((type,) + td))
 
907
            self._add_node(("git", hexsha, "X"), " ".join((type,) + td))
927
908
        else:
928
909
            # This object is not represented in Git - perhaps an empty
929
910
            # directory?
930
 
            self._name.update(type + b" ".join(type_data))
 
911
            self._name.update(type + " ".join(type_data))
931
912
 
932
913
    def lookup_blob_id(self, fileid, revision):
933
 
        return self._get_entry((b"blob", fileid, revision))
 
914
        return self._get_entry(("blob", fileid, revision))
934
915
 
935
916
    def lookup_git_sha(self, sha):
936
917
        if len(sha) == 20:
937
918
            sha = sha_to_hex(sha)
938
 
        value = self._get_entry((b"git", sha, b"X"))
939
 
        data = value.split(b" ", 3)
940
 
        if data[0] == b"commit":
 
919
        value = self._get_entry(("git", sha, "X"))
 
920
        data = value.split(" ", 3)
 
921
        if data[0] == "commit":
941
922
            try:
942
923
                if data[3]:
943
924
                    verifiers = {"testament3-sha1": data[3]}
947
928
                verifiers = {}
948
929
            yield ("commit", (data[1], data[2], verifiers))
949
930
        else:
950
 
            yield (data[0].decode('ascii'), tuple(data[1:]))
 
931
            yield (data[0], tuple(data[1:]))
951
932
 
952
933
    def revids(self):
953
934
        """List the revision ids known."""
954
 
        for key, value in self._iter_entries_prefix((b"commit", None, None)):
 
935
        for key, value in self._iter_entries_prefix(("commit", None, None)):
955
936
            yield key[1]
956
937
 
957
938
    def missing_revisions(self, revids):
958
939
        """Return set of all the revisions that are not present."""
959
940
        missing_revids = set(revids)
960
941
        for _, key, value in self._index.iter_entries((
961
 
                (b"commit", revid, b"X") for revid in revids)):
 
942
            ("commit", revid, "X") for revid in revids)):
962
943
            missing_revids.remove(key[1])
963
944
        return missing_revids
964
945
 
965
946
    def sha1s(self):
966
947
        """List the SHA1s."""
967
 
        for key, value in self._iter_entries_prefix((b"git", None, None)):
 
948
        for key, value in self._iter_entries_prefix(("git", None, None)):
968
949
            yield key[1]
969
950
 
970
951
 
971
952
formats = registry.Registry()
972
953
formats.register(TdbGitCacheFormat().get_format_string(),
973
 
                 TdbGitCacheFormat())
 
954
    TdbGitCacheFormat())
974
955
formats.register(SqliteGitCacheFormat().get_format_string(),
975
 
                 SqliteGitCacheFormat())
 
956
    SqliteGitCacheFormat())
976
957
formats.register(IndexGitCacheFormat().get_format_string(),
977
 
                 IndexGitCacheFormat())
 
958
    IndexGitCacheFormat())
978
959
# In the future, this will become the default:
979
960
formats.register('default', IndexGitCacheFormat())
980
961
 
981
962
 
 
963
 
982
964
def migrate_ancient_formats(repo_transport):
983
965
    # Migrate older cache formats
984
966
    repo_transport = remove_readonly_transport_decorator(repo_transport)
990
972
        repo_transport.mkdir("git")
991
973
    except bzr_errors.FileExists:
992
974
        return
993
 
    # Prefer migrating git.db over git.tdb, since the latter may not
 
975
    # Prefer migrating git.db over git.tdb, since the latter may not 
994
976
    # be openable on some platforms.
995
977
    if has_sqlite:
996
978
        SqliteGitCacheFormat().initialize(repo_transport.clone("git"))
1023
1005
        try:
1024
1006
            migrate_ancient_formats(repo_transport)
1025
1007
        except bzr_errors.ReadOnlyError:
1026
 
            pass  # Not much we can do
 
1008
            pass # Not much we can do
1027
1009
    return BzrGitCacheFormat.from_repository(repository)