File: git-evtag-compute-py

package info (click to toggle)
git-evtag 2022.1-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 380 kB
  • sloc: ansic: 841; sh: 389; python: 86; makefile: 48; xml: 48
file content (109 lines) | stat: -rwxr-xr-x 3,499 bytes parent folder | download | duplicates (3)
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
98
99
100
101
102
103
104
105
106
107
108
109
#!/usr/bin/env python3
#
# An implementation of Git-EVTag in a mixture of Python and
# git-as-subprocess.  Slower than C, but easier to understand
# and test.
# 
# For correct submodule handling, requires the working directory have
# submodule checkouts.

from __future__ import print_function

import os
import sys
import argparse
import subprocess
import hashlib

try:
    from subprocess import DEVNULL # pylint: disable=no-name-in-module
except ImportError:
    import os
    DEVNULL = open(os.devnull, 'wb')

parser = argparse.ArgumentParser(description="Compute Git-EVTag checksum")
parser.add_argument('rev', help='Revision to checksum')
opts = parser.parse_args()

csum = hashlib.sha512()

stats = {'commit': 0,
         'blob': 0,
         'tree': 0,
         'commitbytes': 0,
         'blobbytes': 0,
         'treebytes': 0}

def checksum_bytes(otype, buf):
    blen = len(buf)
    csum.update(buf)
    stats[otype + 'bytes'] += blen
    return blen

def checksum_object(repo, objid):
    assert objid is not None
    p = subprocess.Popen(['git', 'cat-file', '--batch'],
                         stdin=subprocess.PIPE,
                         stdout=subprocess.PIPE,
                         close_fds=True,
                         cwd=repo)
    p.stdin.write(objid.encode('ascii') + b'\n')
    p.stdin.close()
    (objid,objtype,lenstr) = p.stdout.readline().decode('ascii').split(None, 2)
    olen = int(lenstr)
    lenstr = lenstr.strip()
    buf = "{0} {1}\000".format(objtype, lenstr).encode('ascii')
    checksum_bytes(objtype, buf)

    stats[objtype] += 1

    if objtype == 'commit':
        buf = p.stdout.readline()
        olen -= checksum_bytes(objtype, buf)
        (treestr, treeobjid) = buf.decode('ascii').split(None, 1)
        treeobjid = treeobjid.strip()
        assert treestr == 'tree'
    else:
        treeobjid = None
        
    while olen > 0:
        b = p.stdout.read(min(8192, olen))
        bytes_read = checksum_bytes(objtype, b)
        olen -= bytes_read
    if olen > 0:
        raise ValueError("Failed to read {0} bytes from object".format(olen))
    p.wait()
    if p.returncode != 0:
        raise subprocess.CalledProcessError(p.returncode, 'git cat-file')
    return treeobjid

def checksum_tree(repo, path, objid):
    checksum_object(repo, objid)
    p = subprocess.Popen(['git', 'ls-tree', objid],
                         stdin=DEVNULL,
                         stdout=subprocess.PIPE,
                         close_fds=True,
                         cwd=repo)
    for line in p.stdout:
        (mode, otype, subid, fname) = line.decode('ascii').split(None, 3)
        fname = fname.strip()
        if otype == 'blob':
            checksum_object(repo, subid)
        elif otype == 'tree':
            checksum_tree(repo, os.path.join(path, fname), subid)
        elif otype == 'commit':
            checksum_repo(os.path.join(repo, path, fname), subid)
        else:
            assert False
    p.wait()
    if p.returncode != 0:
        raise subprocess.CalledProcessError(p.returncode, 'git ls-tree')

def checksum_repo(repo, objid):
    treeid = checksum_object(repo, objid)
    checksum_tree(repo, '.', treeid)

checksum_repo('.', opts.rev)

print("# git-evtag comment: submodules={0} commits={1} ({2}) trees={3} ({4}) blobs={5} ({6})".format(stats['commit']-1, stats['commit'], stats['commitbytes'], stats['tree'], stats['treebytes'], stats['blob'], stats['blobbytes']))
print("Git-EVTag-v0-SHA512: {0}".format(csum.hexdigest()))