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()))
|