Files
linuxcncWebWASM/doc-g/generate_inventory.py

119 lines
4.0 KiB
Python

#!/usr/bin/env python3
"""Build a deterministic inventory for the GMOCCAPY source and case assets."""
from __future__ import annotations
import hashlib
import json
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
OUT = Path(__file__).resolve().parent
def sha256(path: Path) -> str:
return hashlib.sha256(path.read_bytes()).hexdigest()
def classify(rel: str) -> str:
path = Path(rel)
if "/configs/sim/gmoccapy/" in rel:
if path.suffix == ".ini":
return "simulation_ini"
if path.suffix in {".hal", ".tbl", ".para", ".var", ".pref"}:
return "simulation_runtime_data"
if path.suffix in {".ngc", ".py", ".ui", ".glade", ".svg", ".txt", ".README"}:
return "simulation_resource"
return "simulation_asset"
if "/src/emc/usr_intf/gmoccapy/" in rel or "/lib/python/gmoccapy/" in rel:
return "implementation"
if "/share/gmoccapy/" in rel:
if "icons/" in rel:
return "icon_asset"
return "installed_ui_asset"
if "/src/po/gmoccapy/" in rel:
return "translation"
if "/docs/src/gui/images/gmoccapy_" in rel or "/docs/src/user/images/gmoccapy_" in rel:
return "documentation_asset"
if "/docs/src/gui/gmoccapy" in rel or "/docs/man/man1/gmoccapy" in rel:
return "documentation"
return "cross_reference"
def collect(paths: list[Path]) -> list[dict[str, object]]:
files: list[Path] = []
for base in paths:
if base.is_file():
files.append(base)
elif base.is_dir():
files.extend(p for p in base.rglob("*") if p.is_file())
rows = []
for path in sorted(set(files)):
rel = path.relative_to(ROOT).as_posix()
rows.append(
{
"path": rel,
"role": classify(rel),
"bytes": path.stat().st_size,
"sha256": sha256(path),
}
)
return rows
def main() -> None:
rows = collect(
[
ROOT / "linuxcnc/configs/sim/gmoccapy",
ROOT / "linuxcnc/src/emc/usr_intf/gmoccapy",
ROOT / "linuxcnc/lib/python/gmoccapy",
ROOT / "linuxcnc/share/gmoccapy",
ROOT / "linuxcnc/src/po/gmoccapy",
ROOT / "linuxcnc/docs/src/gui/gmoccapy.adoc",
ROOT / "linuxcnc/docs/man/man1/gmoccapy.1",
*sorted((ROOT / "linuxcnc/docs/src/gui/images").glob("gmoccapy_*")),
*sorted((ROOT / "linuxcnc/docs/src/user/images").glob("gmoccapy_*")),
]
)
summary: dict[str, int] = {}
for row in rows:
role = str(row["role"])
summary[role] = summary.get(role, 0) + 1
payload = {
"schema": "gmoccapy-file-inventory.v1",
"scope": [
"linuxcnc/configs/sim/gmoccapy/**",
"linuxcnc/src/emc/usr_intf/gmoccapy/**",
"linuxcnc/lib/python/gmoccapy/**",
"linuxcnc/share/gmoccapy/**",
"linuxcnc/src/po/gmoccapy/**",
"linuxcnc/docs/src/gui/gmoccapy.adoc",
"linuxcnc/docs/man/man1/gmoccapy.1",
"linuxcnc/docs/src/gui/images/gmoccapy_*",
"linuxcnc/docs/src/user/images/gmoccapy_*",
],
"file_count": len(rows),
"role_counts": dict(sorted(summary.items())),
"files": rows,
}
(OUT / "gmoccapy-file-inventory.json").write_text(
json.dumps(payload, ensure_ascii=False, sort_keys=True, indent=2) + "\n",
encoding="utf-8",
)
lines = [
"# GMOCCAPY 文件清单",
"",
f"清单范围内共 `{len(rows)}` 个文件;每项包含相对路径、角色、字节数和 SHA-256。",
"",
"| 角色 | 数量 |",
"|---|---:|",
]
lines.extend(f"| `{role}` | {count} |" for role, count in sorted(summary.items()))
lines.extend(["", "完整逐文件数据见 [`gmoccapy-file-inventory.json`](gmoccapy-file-inventory.json)。", ""])
(OUT / "gmoccapy-file-inventory.md").write_text("\n".join(lines), encoding="utf-8")
if __name__ == "__main__":
main()