# -*- coding: utf-8 -*- """Generate protocol/git_user_fw_ver.h from current git HEAD + branch. 用户固件版本 (01 0C) 线格式: {branch}_{short6}[optional '*'] 例: develop_0aedb4 / feature-ui_57448b* - short6 = git rev-parse --short=6 HEAD(小写 hex) - branch 清洗为 [A-Za-z0-9.-],整串(不含 dirty '*') ≤ 24 - dirty working tree 时末尾追加 '*' 用法(IAR Pre-build): python \"$PROJ_DIR$\\..\\..\\tools\\gen_git_user_fw_ver.py\" """ from __future__ import annotations import os import re import subprocess ROOT = os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..")) OUT = os.path.join(ROOT, "protocol", "git_user_fw_ver.h") BUILD_ID_MAX = 24 # without trailing dirty '*' def _git(*args: str) -> str | None: try: return subprocess.check_output( ["git", *args], cwd=ROOT, stderr=subprocess.DEVNULL, text=True, ).strip() except (subprocess.CalledProcessError, FileNotFoundError, OSError): return None def sanitize_branch(name: str) -> str: if not name or name == "HEAD": return "DETACHED" # feature/foo → feature-foo;去掉其它非法字符 s = name.replace("/", "-") s = re.sub(r"[^A-Za-z0-9.-]+", "-", s) s = re.sub(r"-{2,}", "-", s).strip("-.") return s or "DETACHED" def make_build_id(branch: str, short6: str) -> str: """Ensure '{branch}_{short6}' length ≤ BUILD_ID_MAX; keep commit suffix intact.""" short6 = short6.lower()[:6].ljust(6, "0") suffix = "_" + short6 max_br = BUILD_ID_MAX - len(suffix) if max_br < 1: return short6[:BUILD_ID_MAX] br = branch[:max_br] return br + suffix def main() -> int: full = _git("rev-parse", "HEAD") or ("0" * 40) if len(full) < 6 or not all(c in "0123456789abcdefABCDEF" for c in full): full = "0" * 40 full = full.lower() short6 = full[:6] br_raw = _git("rev-parse", "--abbrev-ref", "HEAD") or "DETACHED" branch = sanitize_branch(br_raw) dirty = False st = _git("status", "--porcelain") if st: dirty = True build_id = make_build_id(branch, short6) wire = build_id + ("*" if dirty else "") # C string escape wire_c = wire.replace("\\", "\\\\").replace('"', '\\"') text = f"""/* Auto-generated by tools/gen_git_user_fw_ver.py — do not edit. * git HEAD{' (dirty)' if dirty else ''}: {full} * branch: {br_raw} → {branch} * 01 0C wire: {wire} */ #ifndef GIT_USER_FW_VER_H #define GIT_USER_FW_VER_H #define GIT_COMMIT_ID_FULL "{full}" #define GIT_BRANCH_NAME "{branch}" #define GIT_COMMIT_SHORT6 "{short6}" #define GIT_DIRTY ({1 if dirty else 0}) #define GIT_BUILD_ID "{wire_c}" #define GIT_BUILD_ID_LEN {len(wire)}u #endif /* GIT_USER_FW_VER_H */ """ os.makedirs(os.path.dirname(OUT), exist_ok=True) old = "" if os.path.isfile(OUT): with open(OUT, "r", encoding="utf-8") as f: old = f.read() if old != text: with open(OUT, "w", encoding="utf-8", newline="\n") as f: f.write(text) print(f"gen_git_user_fw_ver: wrote {OUT} ({wire})") else: print(f"gen_git_user_fw_ver: up-to-date ({wire})") return 0 if __name__ == "__main__": raise SystemExit(main())