summaryrefslogtreecommitdiff
path: root/git_crecord/gitrepo.py
blob: 7b65988777aa305cffd520ba3c21c6d1ba32ddfb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# Git wrapper for repo/tree/index manipulation
#
# Copyright 2016, 2018—2022 Andrej Shadura <andrew@shadura.me>
#
# This software may be used and distributed according to the terms of
# the GNU General Public License, incorporated herein by reference.
#
# SPDX-License-Identifier: GPL-2.0-or-later
from __future__ import annotations

import os
import sys
from pathlib import Path

from . import util

INDEX_FILENAME = "index"

ObjectHash = str


class GitTree:
    def __init__(self, tree):
        self._tree = tree

    def __repr__(self):
        return "%s(%r)" % (self.__class__.__name__, self._tree)

    def read(self):
        util.system(['git', 'read-tree', '--reset',
                     self._tree], onerr=RuntimeError)


class GitIndex:
    def __init__(self, filename):
        self._filename = filename
        self.indextree = None

    def __repr__(self):
        return "%s(%r, %r)" % (self.__class__.__name__, self._filename, self.indextree)

    def commit(self) -> ObjectHash:
        return util.systemcall(
            ['git', 'write-tree'],
            onerr=RuntimeError,
            encoding="ascii",
        ).rstrip('\n')

    def write(self):
        GitTree(self.indextree).read()

    def backup_tree(self) -> ObjectHash:
        try:
            self.indextree = self.commit()
        except RuntimeError as inst:
            raise util.Abort('failed to read the index: %s' % inst)
        return self.indextree


class GitRepo:
    def __init__(self, path: os.PathLike | str | None):
        try:
            self.path = Path(util.systemcall(
                ['git', 'rev-parse', '--show-toplevel'],
                dir=path,
                encoding="fs",
                onerr=util.Abort
            ).rstrip('\n'))
            self._controldir = Path(util.systemcall(
                ['git', 'rev-parse', '--git-dir'],
                dir=path,
                encoding="fs",
            ).rstrip('\n'))
            if not self._controldir.is_dir():
                raise util.Abort
        except util.Abort:
            sys.exit(1)

    def __repr__(self):
        return "%s(%s)" % (self.__class__.__name__, self.path)

    @property
    def controldir(self) -> Path:
        return self._controldir.resolve()

    @property
    def index_path(self) -> Path:
        return self.controldir / INDEX_FILENAME

    def open_index(self) -> GitIndex:
        return GitIndex(self.index_path)

    def head(self) -> ObjectHash:
        return util.systemcall(
            ['git', 'rev-parse', '--verify', '-q', 'HEAD'],
            encoding="ascii",
        ).rstrip('\n')