version.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. #!/usb/bin/env python3
  2. from flipper.app import App
  3. import subprocess
  4. import os
  5. import json
  6. from datetime import date, datetime
  7. class GitVersion:
  8. def __init__(self, source_dir):
  9. self.source_dir = source_dir
  10. def get_version_info(self):
  11. commit = self._exec_git("rev-parse --short HEAD") or "unknown"
  12. dirty = False
  13. try:
  14. self._exec_git("diff --quiet")
  15. except subprocess.CalledProcessError as e:
  16. if e.returncode == 1:
  17. dirty = True
  18. # If WORKFLOW_BRANCH_OR_TAG is set in environment, is has precedence
  19. # (set by CI)
  20. branch = (
  21. os.environ.get("WORKFLOW_BRANCH_OR_TAG", None)
  22. or self._exec_git("rev-parse --abbrev-ref HEAD")
  23. or "unknown"
  24. )
  25. branch_num = self._exec_git("rev-list --count HEAD") or "n/a"
  26. try:
  27. version = self._exec_git("describe --tags --abbrev=0 --exact-match")
  28. except subprocess.CalledProcessError:
  29. version = "unknown"
  30. return {
  31. "GIT_COMMIT": commit,
  32. "GIT_BRANCH": branch,
  33. "GIT_BRANCH_NUM": branch_num,
  34. "VERSION": version,
  35. "BUILD_DIRTY": dirty and 1 or 0,
  36. }
  37. def _exec_git(self, args):
  38. cmd = ["git"]
  39. cmd.extend(args.split(" "))
  40. return (
  41. subprocess.check_output(cmd, cwd=self.source_dir, stderr=subprocess.STDOUT)
  42. .strip()
  43. .decode()
  44. )
  45. class Main(App):
  46. def init(self):
  47. self.subparsers = self.parser.add_subparsers(help="sub-command help")
  48. # generate
  49. self.parser_generate = self.subparsers.add_parser(
  50. "generate", help="Generate version header"
  51. )
  52. self.parser_generate.add_argument("-o", dest="outdir", required=True)
  53. self.parser_generate.add_argument(
  54. "-t",
  55. dest="target",
  56. type=int,
  57. help="hardware target",
  58. required=True,
  59. )
  60. self.parser_generate.add_argument("--dir", dest="sourcedir", required=True)
  61. self.parser_generate.set_defaults(func=self.generate)
  62. def generate(self):
  63. current_info = GitVersion(self.args.sourcedir).get_version_info()
  64. if "SOURCE_DATE_EPOCH" in os.environ:
  65. build_date = datetime.utcfromtimestamp(int(os.environ["SOURCE_DATE_EPOCH"]))
  66. else:
  67. build_date = date.today()
  68. current_info.update(
  69. {
  70. "BUILD_DATE": build_date.strftime("%d-%m-%Y"),
  71. "TARGET": self.args.target,
  72. }
  73. )
  74. version_values = []
  75. for key in current_info:
  76. val = current_info[key]
  77. if isinstance(val, str):
  78. val = f'"{val}"'
  79. version_values.append(f"#define {key} {val}")
  80. new_version_info_fmt = "\n".join(version_values) + "\n"
  81. current_version_info = None
  82. version_header_name = os.path.join(self.args.outdir, "version.inc.h")
  83. version_json_name = os.path.join(self.args.outdir, "version.json")
  84. try:
  85. with open(version_header_name, "r") as file:
  86. current_version_info = file.read()
  87. except EnvironmentError as e:
  88. if self.args.debug:
  89. print(e)
  90. if current_version_info != new_version_info_fmt:
  91. if self.args.debug:
  92. print("old: ", current_version_info)
  93. print("new: ", new_version_info_fmt)
  94. with open(version_header_name, "w", newline="\n") as file:
  95. file.write(new_version_info_fmt)
  96. # os.utime("../lib/toolbox/version.c", None)
  97. print("Version information updated")
  98. else:
  99. if self.args.debug:
  100. print("Version information hasn't changed")
  101. version_json = {
  102. "firmware_build_date": current_info["BUILD_DATE"],
  103. "firmware_commit": current_info["GIT_COMMIT"],
  104. "firmware_branch": current_info["GIT_BRANCH"],
  105. "firmware_target": current_info["TARGET"],
  106. }
  107. with open(version_json_name, "w", newline="\n") as file:
  108. json.dump(version_json, file, indent=4)
  109. return 0
  110. if __name__ == "__main__":
  111. Main()()