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 18 import datetime 19 import os 20 import re 21 import sys 22 import subprocess 23 24 try: 25 import hashlib 26 sha1 = hashlib.sha1 27 except ImportError, e: 28 import sha 29 sha1 = sha.sha 30 31 def 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 60 def 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 73 def 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 80 def 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 100 def 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 133 using namespace bcc; 134 135 const char* BuildInfo::GetBuildTime() { 136 return %s; 137 } 138 139 const char *BuildInfo::GetBuildRev() { 140 return %s; 141 } 142 143 const 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 153 if __name__ == '__main__': 154 main() 155