version.py 4.2 KB

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