6505cef9df
规则:在**掩码后**的文本上匹配 malloc/calloc/realloc/strdup/strndup/ free/aligned_alloc 调用。三条判据都是踩过坑之后定的—— - 大小写敏感:pvPortMalloc / vPortFree(唯一允许的配对)不会误报; - 词边界 \b:dhara_nand_is_free(、buf_alloc( 这类同形后缀不误报; - 用掩码:注释与字符串字面量里写 malloc 不报(规范示例就踩过这种)。 覆盖名比 AGENTS 列的五枚多带上 strndup / aligned_alloc——同族同类, 漏一个就等于留后门。 出处不在规范 V1.0,在平台约束:MicroLIB 的 C 堆由 startup_stm32f407xx.s 的 Heap_Size EQU 0x200 只有 512 B,KB 级分配必返 NULL,而模拟器(宿主 CRT 堆)完全正常、**照不出来**——配置引擎 2026-09-18 那次堆分配纠偏与 lftpd 的 malloc 隐患都是**先上线才发现**的那类,靠评审等于没管。 落地前按 门禁说明/coding-standard.md §8 的纪律先全库普查:钩子范围内 C/H 共 151 个文件,命中**只有** simulator/sim/cfg_file_store_sim.c 两行, 即 cfg_store_alloc/cfg_store_free = **平台分配后端的宿主侧实现**(设计依据 写在 docs/子系统设计/配置文件设计说明.md 的"MCU 端 = pvPortMalloc、 模拟器端 = 宿主 CRT")。所以零基线、直接硬拦截;豁免用脚本里的 HEAP_ALLOC_ALLOWLIST(**文件路径 + 函数名**双条件),刻意不做目录级豁免: 下次谁要碰 C 堆就得往这张表加一行,评审看得见。 自证:临时样例文件里 malloc/calloc/free 各报一处,pvPortMalloc/vPortFree/ buf_alloc(、注释、字符串五种陷阱形态全部不误报; pre-commit run coding-standard --all-files → **Passed**(= 全库零存量)。 顺带修三处口径不一致: - 规范 V1.0 §6.1 的示例自己写着 malloc/free(通用 C 模板遗留)→ 已在示例 下加"本仓例外,别照抄"批注,事实源指向 AGENTS.md 平台约束; - docs/门禁说明/mem-budget.md 里"这条纪律只靠 AGENTS 铁律与评审"已过期 → 更正为由 CODE-RULE-20 机器拦截; - AGENTS.md 平台约束条加"已机器拦截 + 唯一豁免"一句;scripts/README.md 补登 check_test_coverage.py(上一个提交漏登记)。 另:本次一并修好上一处编辑事故——报告 §4.8 曾被我的脚本调用截成半句 (只落第一行、丢掉 malloc 那半句),已重写为"两处空白均已闭合"。 自查:pre-commit run --files(9 个改动文件)适用项全 Passed; check_doc_links.py --all = 35 处,与主干同数(本分支贡献 0); check_ids.py --strict 通过(裸编号 P0-1 改平实说法,避免记成新账); 9 个文件 BOM/CR/U+FFFD/行尾与 HEAD 逐项一致。本轮零 .c/.h 改动,未跑 @build、未占 build/bench 锁;分支已 rebase 到 v2-on-ui,覆盖率脚本全量 回归仍 16/16、line=2552/2893 不变。
90 lines
7.7 KiB
Markdown
90 lines
7.7 KiB
Markdown
# scripts/ — 开发脚本(提交门禁 + 报告生成)
|
||
|
||
> 本目录是 **pre-commit 门禁脚本**与**报告生成脚本**的存放处。
|
||
> 与 `tools/`(面向开发者的功能工具)区别:本目录服务于**质量门禁与工程度量**。
|
||
|
||
## 文件一览
|
||
|
||
### 提交门禁(接入 `.pre-commit-config.yaml`)
|
||
|
||
| 脚本 | 钩子名 | 作用 |
|
||
|---|---|---|
|
||
| `check_coding_standard.py` | `C coding standard` | C 代码规范机械检查(命名前缀/常量右置/头文件保护宏等) |
|
||
| `check_mojibake.py` | `Forbid U+FFFD mojibake` | 扫描 `U+FFFD` 乱码(`EF BF BD` 字节) |
|
||
| `check_doc_links.py` | `doc-links` | **文档链接存在性** + 命名规范(D-3/D-7)+ **`§N.M` 章节引用**(口径见 `docs/文档规范.md` §3.5)。钩子已带 `--sections-strict`(自引用失效也拦);`--section-todo` 列出机器判不了目标的 `§`(带改写建议)。每次跑打印「可判定比例」行,防覆盖率回落 |
|
||
| `section_aliases.json` | (被 `check_doc_links.py` 读) | 文档**昵称别名表**:「内存方案」→ `docs/内存管理/RAM使用分析与优化方案.md`。只登记无歧义昵称;登记一次即把该昵称的引用纳入硬门禁 |
|
||
| `check_ids.py` | `id-check` | **编号门禁**:`docs/编号规范.md` §8 的八项校验(未登记前缀 / 形态 / 悬空 / 重复定义 / 越游标 / 未紧邻文档名 / 孤儿 / 可判定比例)。**已关闸为增量拦截**:钩子带 `--strict`,只拦 `scripts/id_known_backlog.json` 台账之外的新错误级问题(存量按指纹豁免、台账只减不增);可判定比例跌破基线任何模式都失败。详表(含限制与盲区)→ `docs/门禁说明/id-check.md` |
|
||
| `id_registry.json` | (被 `check_ids.py` 读) | 前缀族**注册表**:属主登记处 / 形态正则 / 冻结 / 游标,逐项来自 `docs/编号规范.md` §4;`decidable_ratio_baseline` = 校验 8 的基线(只许涨)。与 `section_aliases.json` 同一套"别名表 + 可判定比例"范式 |
|
||
| `id_aliases.json` | (被 `check_ids.py` 读) | 编号**别名/作废表**:旧字面量 → 现行字面量或 `status: void`(如 `N-32` 销项后仍被引用、`T-4` 随销项永久作废、模块码 `PHY→NET`) |
|
||
| `check_test_traceability.py` | (被 `id-check` 顺带调用) | **TC 用例双向追溯**:文档 ↔ 代码两侧的 TC 编号集合比对;2026-10-20 起范围扩到 `test/host/` 与 7 篇「单元测试说明.md」(`--board-only` 回退旧板级口径)。此前该脚本**未挂任何钩子** |
|
||
| `gen_task_table.py` | `task-table` | FreeRTOS 任务表以 `Src/freertos.c` 为**唯一事实源**生成/校验(D-2/D-7) |
|
||
| `check_mem_numbers.py` | `mem-numbers` | 内存/Flash 数字以 `.map` 为唯一事实源校验(D-7 体积档) |
|
||
| `check_test_suite.py` | `test-suite-switch` | 测试套件开关=产品构建(防测试固件静默提交) |
|
||
|
||
### 报告生成(非门禁)
|
||
|
||
| 脚本 | 作用 |
|
||
|---|---|
|
||
| `ram_report.py` | 从 `.map` 生成**静态 RAM/Flash 占用**报告(→ `docs/内存管理/data/`) |
|
||
| `stack_report.py` | 从 Keil 静态调用图 + 串口 `[STACK]` 水位生成**每任务最坏链**报告 |
|
||
|
||
### 引用同步(改名 / 挪目录)
|
||
|
||
| 脚本 | 作用 |
|
||
|---|---|
|
||
| `rename_ids.py` | **编号(字面量)批量改名**:映射表 JSON 驱动,`files` 显式 scope(同一裸形字面量可能属多族,实测 `S3` 三义 → 全局替换必造新撞号);默认干跑,`--apply` 落盘并自动写 `id_aliases.json` 的 scoped 旧号→新号条目;`[示例]`/`[计划]` 行与变更记录表不改写;按原字节读写(保 BOM 与行尾)。用法与批次记录 → `docs/编号规范.md` §8.3 |
|
||
| `rename_ref.py` | **改名/挪目录 + 全库引用自动改写**:默认 dry-run 预览,`--apply` 才落盘(`git mv` → 改写引用 → 自动跑 `check_doc_links --all` 复核)。覆盖反引号引用、Markdown 链接、图片 `../` 层级换算、`#include`、`uvprojx`/`CMakeLists.txt` 源列表。固定动作与边界 → `docs/文档规范.md` §3.6 |
|
||
|
||
> `check_doc_links.py` 除链接存在性外,还校验 **`§N.M` 章节引用**是否指向目标文档真实存在的编号标题(口径见 `docs/文档规范.md` §3.5)。
|
||
|
||
### CI 与本地等价(2026-10-01 T-6)
|
||
|
||
| 脚本 / 文件 | 作用 |
|
||
|---|---|
|
||
| `ci_local.py` | **本地跑与 CI 等价的门禁**(L0 pre-commit + L0b 提交信息 + L0.5 主机侧单测):自动选用装了 pre-commit 的解释器;无 `.map` 时自适应跳过 `mem-numbers`;退出码 0/1/2 与 CI 对齐。CI 定义见 `../.gitea/workflows/ci.yml`,覆盖边界见 `docs/测试说明/测试开发标准流程.md` §9 |
|
||
| `check_test_coverage.py` | 主机单测**覆盖率**(2026-10-23):mscoverage 动态插桩跑 `test/host/**` 全部 16 套,统计自研生产源码行/函数覆盖(并集)+ 与 `test_coverage_baseline.json` 比回退;`--module/--update-baseline/--md/--json/--list`;**不在 pre-commit 里**,入口是 `ci_local.py --coverage`(口径见 `docs/测试说明/主机单测覆盖率口径.md`) |
|
||
| `ci_gitlint_range.ps1` | CI 侧**提交信息门禁**:逐条校验本次 push/PR 引入的提交(`--all-files` 跑不到 `commit-msg` stage,故必须单独守) |
|
||
| `ci_find_python.ps1` | CI 侧 Python 探测(候选顺序须与 `ci_local.py` 同序同步,否则 CI 与本地判定会分叉) |
|
||
| `ci_runner_bootstrap.ps1` | **本机 runner 运维脚本**(体检 `-Status` / 干跑 `-DryRun` / 部署 `-SetEnv -StartNow`):装"等 Gitea 就绪 + 崩溃自拉起"的看门狗 + 开机计划任务 + 机器级 `DTU_*` |
|
||
|
||
> ⚠️ 后三个脚本是**本机 runner 专属运维**(远程 CI 只跑在本机一台机器上),用法、原理与
|
||
> 踩坑全部集中在 `docs/CI/README.md`,本表只登记不展开。
|
||
|
||
## 使用方式
|
||
|
||
```bash
|
||
# 全库跑门禁(用仓库 .venv 的 python,其 pre-commit 随 requirements.txt 安装;
|
||
# 其他装有 pre-commit 的解释器可用 DTU_PRECOMMIT_PYTHON 指定)
|
||
& '.venv\Scripts\python.exe' -m pre_commit run --all-files
|
||
|
||
# 本地跑与 CI 等价的门禁(L0 + L0.5)
|
||
& '.venv\Scripts\python.exe' scripts/ci_local.py
|
||
& '.venv\Scripts\python.exe' scripts/ci_local.py --l0-only # 只跑 L0
|
||
& '.venv\Scripts\python.exe' scripts/ci_local.py --l05-only # 只跑 L0.5
|
||
|
||
# 单个脚本
|
||
& '.venv\Scripts\python.exe' scripts/check_doc_links.py --all
|
||
& '.venv\Scripts\python.exe' scripts/rename_ref.py docs/旧/名.md docs/新/名.md # 预览
|
||
& '.venv\Scripts\python.exe' scripts/rename_ref.py docs/旧/名.md docs/新/名.md --apply # 落盘
|
||
& '.venv\Scripts\python.exe' scripts/gen_task_table.py --check # 或 --write / --diff
|
||
& '.venv\Scripts\python.exe' scripts/check_mem_numbers.py --check
|
||
& '.venv\Scripts\python.exe' scripts/check_test_suite.py # 门禁判定
|
||
& '.venv\Scripts\python.exe' scripts/check_test_suite.py --allow-test-build # 放行测试构建
|
||
& '.venv\Scripts\python.exe' scripts/ram_report.py
|
||
& '.venv\Scripts\python.exe' scripts/stack_report.py -s .dsh\skills\serial-assistant\scripts\state\serial.log
|
||
```
|
||
|
||
## ⚠️ 脚本编写约定
|
||
|
||
- **保真回写**:改文件前先探测原换行符(LF/CRLF)与 BOM,按原样回写(本仓库各文件换行混杂)
|
||
- **受管区锚点**:改文档中的数值/表格时用 `<!-- XXX:BEGIN/END -->` 锚点,只替换锚点内内容
|
||
- 脚本**输出文件绝不能落在自身扫描范围内**(否则会"自我污染",见 `docs-tree-reorg` skill)
|
||
- 生成器与校验器**共用同一套正则/口径**,避免两处数字打架
|
||
|
||
## 相关文档
|
||
|
||
- `docs/代码规范/pre-commit使用说明.md` — 门禁完整说明与排除项
|
||
- `docs/代码规范/cppcheck使用说明.md`
|
||
- `docs/文档规范.md` — 文档门禁三档
|
||
- `docs/内存管理/RAM使用分析与优化方案.md` — RAM/栈报告口径
|