aboutsummaryrefslogtreecommitdiffstats
path: root/build/scripts/decimal_md5.py
blob: 598fbf8401207422173e51d37464e17aa6cc8e69 (plain) (blame)
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
#!/usr/bin/env python 
# -*- coding: utf-8 -*- 
 
import hashlib 
import struct 
import sys 
import os 
import argparse 
 
 
def print_code(checksum, func_name):
    if len(func_name) == 0: # safe fallback for old ya.make files
        func_name = "DecimalMD5"
    print 'const char* ' + func_name + '() {return "' + checksum + '";}'
 
 
def ensure_paths_exist(paths): 
    bad_paths = sorted( 
        path for path in paths 
        if not os.path.exists(path) 
    ) 
    if bad_paths: 
        print >> sys.stderr, "decimal_md5 inputs do not exist:" 
        for path in bad_paths: 
            print >> sys.stderr, path 
        sys.exit(1) 
 
 
def _update_digest_with_file_contents(digest, path, block_size=65535): 
    with open(path) as f: 
        while True: 
            block = f.read(block_size) 
            if not block: 
                break 
            digest.update(block) 
 
 
def main(): 
    parser = argparse.ArgumentParser() 
    parser.add_argument("--fixed-output", help="don not calculate md5, use this value instead") 
    parser.add_argument("--lower-bits", help="use specified count of lower bits", type=int, default=32) 
    parser.add_argument("--source-root", help="arcadia source root") 
    parser.add_argument("--func-name", help="custom function name to be defined", default="DecimalMD5")
    parser.add_argument("targets", nargs='*', default=['.']) 
 
    args = parser.parse_args() 
 
    abs_paths = [ 
        os.path.join(args.source_root, target)
        for target in args.targets 
    ] 
    ensure_paths_exist(abs_paths) 
 
    if args.fixed_output: 
        try: 
            bitmask = (1 << args.lower_bits) - 1
            fmt = '{:0%dd}' % len(str(bitmask))
            checksum = fmt.format(int(args.fixed_output) & bitmask)
        except ValueError: 
            raise ValueError("decimal_md5: bad value passed via --fixed-output: %s" % args.fixed_output) 
        print_code(str(checksum), func_name=args.func_name)
        return 
 
    md5 = hashlib.md5() 
    for path in abs_paths: 
        _update_digest_with_file_contents(md5, path) 
 
    md5_parts = struct.unpack('IIII', md5.digest()) 
    md5_int = sum(part << (32 * n) for n, part in enumerate(md5_parts)) 
    bitmask = (1 << args.lower_bits) - 1 
    fmt = '{:0%dd}' % len(str(bitmask)) 
 
    checksum_str = fmt.format(md5_int & bitmask) 
    print_code(checksum_str, func_name=args.func_name)
 
 
if __name__ == "__main__": 
    main()