version.py 4.3 KB

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