update_build_info.py
1 # 2 # @file from https://github.com/Neutree/c_cpp_project_framework 3 # @author neucrack 4 # 5 6 import argparse 7 import os, sys, time, re 8 import subprocess 9 10 11 time_str_header = ''' 12 #define BUILD_TIME_YEAR {} 13 #define BUILD_TIME_MONTH {} 14 #define BUILD_TIME_DAY {} 15 #define BUILD_TIME_HOUR {} 16 #define BUILD_TIME_MINUTE {} 17 #define BUILD_TIME_SECOND {} 18 #define BUILD_TIME_WEEK_OF_DAY {} 19 #define BUILD_TIME_YEAR_OF_DAY {} 20 ''' 21 22 time_str_cmake = ''' 23 set(BUILD_TIME_YEAR "{}") 24 set(BUILD_TIME_MONTH "{}") 25 set(BUILD_TIME_DAY "{}") 26 set(BUILD_TIME_HOUR "{}") 27 set(BUILD_TIME_MINUTE "{}") 28 set(BUILD_TIME_SECOND "{}") 29 set(BUILD_TIME_WEEK_OF_DAY "{}") 30 set(BUILD_TIME_YEAR_OF_DAY "{}") 31 ''' 32 33 time_str_makefile = ''' 34 BUILD_TIME_YEAR ={} 35 BUILD_TIME_MONTH ={} 36 BUILD_TIME_DAY ={} 37 BUILD_TIME_HOUR ={} 38 BUILD_TIME_MINUTE ={} 39 BUILD_TIME_SECOND ={} 40 BUILD_TIME_WEEK_OF_DAY ={} 41 BUILD_TIME_YEAR_OF_DAY ={} 42 ''' 43 44 git_str_header = ''' 45 #define BUILD_VERSION_MAJOR {} 46 #define BUILD_VERSION_MINOR {} 47 #define BUILD_VERSION_DEV {} 48 #define BUILD_VERSION_DEV2 {} 49 #define BUILD_GIT_COMMIT_ID "{}" 50 #define BUILD_GIT_IS_DIRTY {} 51 ''' 52 53 git_str_cmake = ''' 54 set(BUILD_VERSION_MAJOR "{}") 55 set(BUILD_VERSION_MINOR "{}") 56 set(BUILD_VERSION_DEV "{}") 57 set(BUILD_VERSION_DEV2 "{}") 58 set(BUILD_GIT_COMMIT_ID "{}") 59 set(BUILD_GIT_IS_DIRTY "{}") 60 ''' 61 62 git_str_makefile = ''' 63 BUILD_VERSION_MAJOR ={} 64 BUILD_VERSION_MINOR ={} 65 BUILD_VERSION_DEV ={} 66 BUILD_VERSION_DEV2 ={} 67 BUILD_GIT_COMMIT_ID ={} 68 BUILD_GIT_IS_DIRTY ={} 69 ''' 70 71 str_define_start_makefile = "\n# compile append define start\n" 72 str_define_end_makefile = "\n# compile append define end\n" 73 str_define_start_cmake = "\n# compile append define start\n" 74 str_define_end_cmake = "\n# compile append define end\n" 75 str_define_start_header = "\n//compile append define start\n" 76 str_define_end_header = "\n//compile append define end\n" 77 78 INFO_FORMAT_STR = {"header": [str_define_start_header, str_define_end_header, time_str_header, git_str_header], 79 "cmake": [str_define_start_cmake, str_define_end_cmake, time_str_cmake, git_str_cmake], 80 "makefile": [str_define_start_makefile, str_define_end_makefile, time_str_makefile, git_str_makefile], 81 } 82 83 def remove_old_config_info(start_flag_str, end_flag_str, content): 84 match = re.findall(r"{}(.*){}".format(start_flag_str, end_flag_str), content, re.MULTILINE|re.DOTALL) 85 if len(match) == 0: 86 content += start_flag_str+end_flag_str 87 else: 88 content = content.replace(match[0], "") 89 return content 90 91 def append_time_info(time_info_filename, version_info_filename, file_type): 92 str_time_define_start = INFO_FORMAT_STR[file_type][0] 93 str_time_define_end = INFO_FORMAT_STR[file_type][1] 94 append_format_time_str= INFO_FORMAT_STR[file_type][2] 95 append_format_git_str = INFO_FORMAT_STR[file_type][3] 96 content = "" 97 content2 = "" 98 content2_old = content2 99 try: 100 f = open(time_info_filename) 101 content = f.read() 102 f.close() 103 except Exception: 104 pass 105 if version_info_filename: 106 try: 107 f = open(version_info_filename) 108 content2 = f.read() 109 content2_old = content2 110 f.close() 111 except Exception: 112 pass 113 time_now = time.localtime(time.time()) 114 # remove old config info 115 content = remove_old_config_info(str_time_define_start, str_time_define_end, content) 116 content2 = remove_old_config_info(str_time_define_start, str_time_define_end, content2) 117 118 # time info 119 time_define = append_format_time_str.format(time_now.tm_year, 120 time_now.tm_mon, 121 time_now.tm_mday, 122 time_now.tm_hour, 123 time_now.tm_min, 124 time_now.tm_sec, 125 time_now.tm_wday, 126 time_now.tm_yday) 127 # git info 128 # add tag by command; 129 # git tag -a v0.1.1 -m "release v0.1.1 describe....." 130 # git push origin --tags 131 git_tag_name = "" 132 version_major = 0 133 version_minor = 0 134 version_dev = 0 135 version_dev2 = 0 136 git_hash = "" 137 git_dirty = "" 138 try: 139 git_tag = subprocess.check_output(["git", "describe", "--long", "--tag", "--dirty", "--always"], stderr=subprocess.STDOUT, universal_newlines=True).strip() 140 except subprocess.CalledProcessError as er: 141 if er.returncode == 128: 142 # git exit code of 128 means no repository found 143 print("== WARNING: NOT a git repository !!!") 144 git_tag = "" 145 except OSError: 146 git_tag = "" 147 # git_tag = "v0.3.2-39-gbeae86483-dirty" 148 git_tag = git_tag.split("-") 149 if len(git_tag) == 0: 150 print("== WARNING: git get info fail") 151 if len(git_tag) == 1: # bdc1dcf 152 git_hash = git_tag[0] 153 elif len(git_tag) == 2: # bdc1dcf-dirty or v0.1.1-bdc1dcf 154 if git_tag[1] == "dirty": 155 git_hash = git_tag[0] 156 git_dirty = git_tag[1] 157 else: 158 git_tag_name = git_tag[0] 159 git_hash = git_tag[1] 160 elif len(git_tag) == 3: # v0.1.1-10-bdc1dcf or v0.1.1-bdc1dcf-dirty 161 if git_tag[2] == "dirty": 162 git_tag_name = git_tag[0] 163 git_hash = git_tag[1] 164 git_dirty = git_tag[2] 165 else: 166 git_tag_name = git_tag[0]+"."+git_tag[1] 167 git_hash = git_tag[2] 168 else: # v0.1.1-10-bdc1dcf-dirty 169 git_tag_name = git_tag[0]+"."+git_tag[1] 170 git_hash = git_tag[2] 171 git_dirty = git_tag[3] 172 173 if git_tag_name.lower().startswith("v"): 174 version = git_tag_name[1:].split(".") 175 # convert to int from str 176 for i,v in enumerate(version): 177 try: 178 version[i] = int(v) 179 except Exception: 180 version[i] = 0 181 if len(version) >= 1: 182 version_major = version[0] 183 if len(version) >= 2: 184 version_minor = version[1] 185 if len(version) >= 3: 186 version_dev = version[2] 187 if len(version) >= 4: 188 version_dev2 = version[3] 189 if file_type == "header": 190 dirty_value = 1 if git_dirty=="dirty" else 0 191 elif file_type == "cmake": 192 dirty_value = "y" if git_dirty=="dirty" else "" 193 else: 194 if git_dirty=="dirty": 195 dirty_value = "y" 196 else: 197 append_format_git_str = append_format_git_str.replace("BUILD_GIT_IS_DIRTY", "# BUILD_GIT_IS_DIRTY") 198 dirty_value = " is not set" 199 git_define = append_format_git_str.format(version_major, 200 version_minor, 201 version_dev, 202 version_dev2, 203 git_hash, 204 dirty_value) 205 # append time and git info to content 206 content = content.split(str_time_define_end) 207 if not version_info_filename: 208 content = (time_define+git_define+str_time_define_end).join(content) 209 else: 210 content2 = content2.split(str_time_define_end) 211 content = (time_define+str_time_define_end).join(content) 212 content2 = (git_define+str_time_define_end).join(content2) 213 # update config file 214 with open(time_info_filename, "w") as f: 215 f.write(content) 216 if version_info_filename and content2 != content2_old: 217 with open(version_info_filename, "w") as f: 218 f.write(content2) 219 220 def write_config(filename): 221 print("-- Update build time and version info to makefile config at: " + str(filename)) 222 time_info_filename = None 223 version_info_filename = None 224 if filename[0] != None and filename[0].lower() != "none" and os.path.exists(filename[0]): 225 time_info_filename = filename[0] 226 if filename[1] != None and filename[1].lower() != "none" and os.path.exists(filename[1]): 227 version_info_filename = filename[1] 228 if time_info_filename == None: 229 raise Exception("param error") 230 append_time_info(time_info_filename, version_info_filename, "makefile") 231 232 def write_cmake(filename): 233 print("-- Update build time and version info to cmake config at: " + str(filename)) 234 time_info_filename = None 235 version_info_filename = None 236 if filename[0] != None and filename[0].lower() != "none" and os.path.exists(filename[0]): 237 time_info_filename = filename[0] 238 if filename[1] != None and filename[1].lower() != "none" and os.path.exists(filename[1]): 239 version_info_filename = filename[1] 240 if time_info_filename == None: 241 raise Exception("param error") 242 append_time_info(time_info_filename, version_info_filename, "cmake") 243 244 def write_header(filename): 245 print("-- Update build time and version info to header config at: " + str(filename)) 246 time_info_filename = None 247 version_info_filename = None 248 if filename[0] != None and filename[0].lower() != "none": 249 time_info_filename = filename[0] 250 if filename[1] != None and filename[1].lower() != "none": 251 version_info_filename = filename[1] 252 if time_info_filename == None: 253 raise Exception("param error") 254 append_time_info(time_info_filename, version_info_filename, "header") 255 256 parser = argparse.ArgumentParser(description='generate time info for', prog=os.path.basename(sys.argv[0])) 257 258 OUTPUT_FORMATS = {"makefile": write_config, 259 "header": write_header, 260 "cmake": write_cmake 261 } 262 263 264 parser.add_argument('--configfile', nargs=3, action='append', 265 help='Write config file (format and output filename), version_filename can be None so all version info will append to time_filename', 266 metavar=('FORMAT', 'TIME_FILENAME', "VERSION_FILENAME"), 267 default=[]) 268 269 args = parser.parse_args() 270 271 out_format = {} 272 for fmt, filename, version_filename in args.configfile: 273 if fmt not in OUTPUT_FORMATS.keys(): 274 print("Format %s not supported! Known formats:%s" %(fmt, OUTPUT_FORMATS.keys())) 275 sys.exit(1) 276 out_format[fmt] = (filename, version_filename) 277 278 for fmt, filename in out_format.items(): 279 # if not os.path.exists(filename): 280 # print("File not found:%s" %(filename)) 281 # not check always create 282 func = OUTPUT_FORMATS[fmt] 283 func(filename) 284 285