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 p = subprocess.Popen(['git', 'cat-file', '--batch'],
45 stdin=subprocess.PIPE,
46 stdout=subprocess.PIPE,
49 p.stdin.write(objid + '\n')
51 (objid,objtype,lenstr) = p.stdout.readline().split(None, 2)
53 lenstr = lenstr.strip()
54 buf = "{0} {1}\000".format(objtype, lenstr)
55 checksum_bytes(objtype, buf)
59 if objtype == 'commit':
60 buf = p.stdout.readline()
61 olen -= checksum_bytes(objtype, buf)
62 (treestr, treeobjid) = buf.split(None, 1)
63 treeobjid = treeobjid.strip()
64 assert treestr == 'tree'
69 b = p.stdout.read(min(8192, olen))
70 bytes_read = checksum_bytes(objtype, b)
73 raise ValueError("Failed to read {0} bytes from object".format(olen))
76 raise subprocess.CalledProcessError(p.returncode, 'git cat-file')
79 def checksum_tree(repo, objid):
80 checksum_object(repo, objid)
81 p = subprocess.Popen(['git', 'ls-tree', objid],
83 stdout=subprocess.PIPE,
87 (mode, otype, subid, fname) = line.split(None, 3)
90 checksum_object(repo, subid)
92 checksum_tree(repo, subid)
93 elif otype == 'commit':
94 checksum_repo(os.path.join(repo, fname), subid)
99 raise subprocess.CalledProcessError(p.returncode, 'git ls-tree')
101 def checksum_repo(repo, objid):
102 treeid = checksum_object(repo, objid)
103 checksum_tree(repo, treeid)
105 checksum_repo('.', opts.rev)
107 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']))
108 print("Git-EVTag-v0-SHA512: {0}".format(csum.hexdigest()))