/ tools / kconfig / update_build_info.py
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