1#!/usr/bin/env python
2#
3# Copyright (C) 2011-2012 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17
18import datetime
19import os
20import re
21import sys
22import subprocess
23
24try:
25    import hashlib
26    sha1 = hashlib.sha1
27except ImportError, e:
28    import sha
29    sha1 = sha.sha
30
31def get_repo_revision(repo_dir):
32    if not os.path.exists(os.path.join(repo_dir, '.git')):
33        return 'Unknown (not git)'
34
35    # Get the HEAD revision
36    proc = subprocess.Popen(['git', 'log', '-1', '--format=%H'],
37                            stdout=subprocess.PIPE,
38                            stderr=subprocess.PIPE,
39                            cwd=repo_dir)
40    out, err = proc.communicate()
41    proc.wait()
42
43    rev_sha1 = out.strip()
44
45    # Working Directory Modified
46    proc = subprocess.Popen(['git', 'status'],
47                            stdout=subprocess.PIPE,
48                            stderr=subprocess.PIPE,
49                            cwd=repo_dir)
50    out, err = proc.communicate()
51    proc.wait()
52
53    if out.find('(working directory clean)') == -1:
54      mod = ' modified'
55    else:
56      mod = ''
57
58    return rev_sha1 + mod + ' (git)'
59
60def compute_sha1(path, global_hasher = None):
61    f = open(path, 'rb')
62    hasher = sha1()
63    while True:
64        buf = f.read(512)
65        hasher.update(buf)
66        if global_hasher:
67            global_hasher.update(buf)
68        if len(buf) < 512:
69            break
70    f.close()
71    return hasher.hexdigest()
72
73def compute_sha1_list(paths):
74    hasher = sha1()
75    sha1sums = []
76    for path in paths:
77        sha1sums.append(compute_sha1(path, hasher))
78    return (hasher.hexdigest(), sha1sums)
79
80def quote_str(s):
81    result = '"'
82    for c in s:
83        if c == '\\':
84            result += '\\\\'
85        elif c == '\r':
86            result += '\\r'
87        elif c == '\n':
88            result += '\\n'
89        elif c == '\t':
90            result += '\\t'
91        elif c == '\"':
92            result += '\\"'
93        elif c == '\'':
94            result += '\\\''
95        else:
96            result += c
97    result += '"'
98    return result
99
100def main():
101    # Check Argument
102    if len(sys.argv) < 2:
103        print >> sys.stderr, 'USAGE:', sys.argv[0], '[REPO] [LIBs]'
104        sys.exit(1)
105
106    # Record Build Time
107    build_time = datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S')
108
109    # Repository Directory (For build revision)
110    repo_dir = sys.argv[1]
111    build_rev = get_repo_revision(repo_dir)
112
113    # Compute SHA1
114    lib_list = list(set(sys.argv[2:]))
115    lib_list.sort()
116    build_sha1, sha1sum_list = compute_sha1_list(lib_list)
117
118    # Build file list string
119    lib_list_str = ''
120    for i, path in enumerate(lib_list):
121        lib_list_str += '   %s %s\n' % (sha1sum_list[i], path)
122
123    # Print the automatically generated code
124    print """/* Automatically generated file (DON'T MODIFY) */
125
126/* Repository directory: %s */
127
128/* File list:
129%s*/
130
131#include "bcc/Config/BuildInfo.h"
132
133using namespace bcc;
134
135const char* BuildInfo::GetBuildTime() {
136  return %s;
137}
138
139const char *BuildInfo::GetBuildRev() {
140  return %s;
141}
142
143const char *BuildInfo::GetBuildSourceBlob() {
144  return %s;
145}
146
147""" % (os.path.abspath(repo_dir),
148       lib_list_str,
149       quote_str(build_time),
150       quote_str(build_rev),
151       quote_str(build_sha1))
152
153if __name__ == '__main__':
154    main()
155