3 # An implementation of Git-EVTag in a mixture of Python and
4 # git-as-subprocess. Slower than C, but easier to understand
7 # For correct submodule handling, requires the working directory have
10 from __future__ import print_function
19 from subprocess import DEVNULL # pylint: disable=no-name-in-module
22 DEVNULL = open(os.devnull, 'wb')
24 parser = argparse.ArgumentParser(description="Compute Git-EVTag checksum")
25 parser.add_argument('rev', help='Revision to checksum')
26 opts = parser.parse_args()
28 csum = hashlib.sha512()
37 def checksum_bytes(otype, buf):
40 stats[otype + 'bytes'] += blen
43 def checksum_object(repo, objid):
44 assert objid is not None
45 p = subprocess.Popen(['git', 'cat-file', '--batch'],
46 stdin=subprocess.PIPE,
47 stdout=subprocess.PIPE,
50 p.stdin.write(objid.encode('ascii') + b'\n')
52 (objid,objtype,lenstr) = p.stdout.readline().decode('ascii').split(None, 2)
54 lenstr = lenstr.strip()
55 buf = "{0} {1}\000".format(objtype, lenstr).encode('ascii')
56 checksum_bytes(objtype, buf)
60 if objtype == 'commit':
61 buf = p.stdout.readline()
62 olen -= checksum_bytes(objtype, buf)
63 (treestr, treeobjid) = buf.decode('ascii').split(None, 1)
64 treeobjid = treeobjid.strip()
65 assert treestr == 'tree'
70 b = p.stdout.read(min(8192, olen))
71 bytes_read = checksum_bytes(objtype, b)
74 raise ValueError("Failed to read {0} bytes from object".format(olen))
77 raise subprocess.CalledProcessError(p.returncode, 'git cat-file')
80 def checksum_tree(repo, path, objid):
81 checksum_object(repo, objid)
82 p = subprocess.Popen(['git', 'ls-tree', objid],
84 stdout=subprocess.PIPE,
88 (mode, otype, subid, fname) = line.decode('ascii').split(None, 3)
91 checksum_object(repo, subid)
93 checksum_tree(repo, os.path.join(path, fname), subid)
94 elif otype == 'commit':
95 checksum_repo(os.path.join(repo, path, fname), subid)
100 raise subprocess.CalledProcessError(p.returncode, 'git ls-tree')
102 def checksum_repo(repo, objid):
103 treeid = checksum_object(repo, objid)
104 checksum_tree(repo, '.', treeid)
106 checksum_repo('.', opts.rev)
108 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']))
109 print("Git-EVTag-v0-SHA512: {0}".format(csum.hexdigest()))