gen-build-info.py revision 76bb588a309ba11c1b6a3c2af3b97f784f29a833
148dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien#!/usr/bin/env python
248dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien
348dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chienimport datetime
448dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chienimport os
548dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chienimport re
648dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chienimport sys
748dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chienimport subprocess
848dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien
91c13147fd7d2294a0f34a569fe36660b6b056a91Daniel Sandlertry:
101c13147fd7d2294a0f34a569fe36660b6b056a91Daniel Sandler    import hashlib
111c13147fd7d2294a0f34a569fe36660b6b056a91Daniel Sandler    sha1 = hashlib.sha1
121c13147fd7d2294a0f34a569fe36660b6b056a91Daniel Sandlerexcept ImportError, e:
131c13147fd7d2294a0f34a569fe36660b6b056a91Daniel Sandler    import sha
141c13147fd7d2294a0f34a569fe36660b6b056a91Daniel Sandler    sha1 = sha.sha
151c13147fd7d2294a0f34a569fe36660b6b056a91Daniel Sandler
1648dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chiendef get_repo_revision(repo_dir):
1748dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien    if not os.path.exists(os.path.join(repo_dir, '.git')):
1848dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien        return 'Unknown (not git)'
1948dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien
203bfcd866e752a77e42b93dea1754417e5c466472Logan Chien    # Get the HEAD revision
2148dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien    proc = subprocess.Popen(['git', 'log', '-1', '--format=%H'],
2248dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien                            stdout=subprocess.PIPE,
2348dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien                            stderr=subprocess.PIPE,
2448dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien                            cwd=repo_dir)
2548dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien    out, err = proc.communicate()
2648dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien    proc.wait()
2748dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien
283bfcd866e752a77e42b93dea1754417e5c466472Logan Chien    rev_sha1 = out.strip()
293bfcd866e752a77e42b93dea1754417e5c466472Logan Chien
303bfcd866e752a77e42b93dea1754417e5c466472Logan Chien    # Working Directory Modified
313bfcd866e752a77e42b93dea1754417e5c466472Logan Chien    proc = subprocess.Popen(['git', 'status'],
323bfcd866e752a77e42b93dea1754417e5c466472Logan Chien                            stdout=subprocess.PIPE,
333bfcd866e752a77e42b93dea1754417e5c466472Logan Chien                            stderr=subprocess.PIPE,
343bfcd866e752a77e42b93dea1754417e5c466472Logan Chien                            cwd=repo_dir)
353bfcd866e752a77e42b93dea1754417e5c466472Logan Chien    out, err = proc.communicate()
363bfcd866e752a77e42b93dea1754417e5c466472Logan Chien    proc.wait()
373bfcd866e752a77e42b93dea1754417e5c466472Logan Chien
3876bb588a309ba11c1b6a3c2af3b97f784f29a833Logan Chien    if out.find('(working directory clean)') == -1:
391c13147fd7d2294a0f34a569fe36660b6b056a91Daniel Sandler      mod = ' modified'
401c13147fd7d2294a0f34a569fe36660b6b056a91Daniel Sandler    else:
411c13147fd7d2294a0f34a569fe36660b6b056a91Daniel Sandler      mod = ''
423bfcd866e752a77e42b93dea1754417e5c466472Logan Chien
433bfcd866e752a77e42b93dea1754417e5c466472Logan Chien    return rev_sha1 + mod + ' (git)'
4448dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien
4548dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chiendef compute_sha1(path, global_hasher = None):
4648dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien    f = open(path, 'rb')
471c13147fd7d2294a0f34a569fe36660b6b056a91Daniel Sandler    hasher = sha1()
4848dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien    while True:
4948dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien        buf = f.read(512)
5048dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien        hasher.update(buf)
5148dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien        if global_hasher:
5248dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien            global_hasher.update(buf)
5348dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien        if len(buf) < 512:
5448dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien            break
5548dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien    f.close()
5648dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien    return hasher.hexdigest()
5748dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien
5848dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chiendef compute_sha1_list(paths):
591c13147fd7d2294a0f34a569fe36660b6b056a91Daniel Sandler    hasher = sha1()
6048dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien    sha1sums = []
6148dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien    for path in paths:
6248dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien        sha1sums.append(compute_sha1(path, hasher))
6348dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien    return (hasher.hexdigest(), sha1sums)
6448dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien
6548dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chiendef quote_str(s):
6648dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien    result = '"'
6748dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien    for c in s:
6848dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien        if c == '\\':
6948dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien            result += '\\\\'
7048dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien        elif c == '\r':
7148dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien            result += '\\r'
7248dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien        elif c == '\n':
7348dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien            result += '\\n'
7448dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien        elif c == '\t':
7548dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien            result += '\\t'
7648dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien        elif c == '\"':
7748dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien            result += '\\"'
7848dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien        elif c == '\'':
7948dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien            result += '\\\''
8048dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien        else:
8148dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien            result += c
8248dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien    result += '"'
8348dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien    return result
8448dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien
8548dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chiendef main():
8648dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien    # Check Argument
8748dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien    if len(sys.argv) < 2:
8848dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien        print >> sys.stderr, 'USAGE:', sys.argv[0], '[REPO] [LIBs]'
8948dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien        sys.exit(1)
9048dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien
9148dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien    # Record Build Time
9248dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien    build_time = datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S')
9348dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien
9448dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien    # Repository Directory (For build revision)
9548dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien    repo_dir = sys.argv[1]
9648dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien    build_rev = get_repo_revision(repo_dir)
9748dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien
9848dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien    # Compute SHA1
9948dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien    lib_list = list(set(sys.argv[2:]))
10048dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien    lib_list.sort()
10148dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien    build_sha1, sha1sum_list = compute_sha1_list(lib_list)
10248dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien
10348dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien    # Build file list string
10448dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien    lib_list_str = ''
10548dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien    for i, path in enumerate(lib_list):
10648dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien        lib_list_str += '   %s %s\n' % (sha1sum_list[i], path)
10748dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien
10848dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien    # Print the automatically generated code
10948dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien    print """/* Automatically generated file (DON'T MODIFY) */
11048dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien
11148dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien/* Repository directory: %s */
11248dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien
11348dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien/* File list:
11448dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien%s*/
11548dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien
11648dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien#ifdef __cplusplus
11748dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chienextern "C" {
11848dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien#endif
11948dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien
12048dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chienchar const *bccGetBuildTime() {
12148dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien  return %s;
12248dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien}
12348dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien
12448dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chienchar const *bccGetBuildRev() {
12548dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien  return %s;
12648dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien}
12748dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien
12848dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chienchar const *bccGetBuildSHA1() {
12948dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien  return %s;
13048dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien}
13148dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien
13248dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien#ifdef __cplusplus
13348dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien}
13448dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien#endif
13548dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien
13648dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien""" % (os.path.abspath(repo_dir),
13748dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien       lib_list_str,
13848dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien       quote_str(build_time),
13948dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien       quote_str(build_rev),
14048dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien       quote_str(build_sha1))
14148dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien
14248dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chienif __name__ == '__main__':
14348dc01db0b865b73f41cef53bcb72f65fd027af4Logan Chien    main()
144