98 lines
3.5 KiB
Python
98 lines
3.5 KiB
Python
from __future__ import annotations
|
|
|
|
import argparse
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
from common import MATERIAL_CATALOG, ensure_output_layout, iter_material_entries, list_files, safe_filename, write_json, write_text
|
|
|
|
|
|
def match_catalog(file_name: str) -> dict[str, Any] | None:
|
|
lowered = file_name.lower()
|
|
for item in MATERIAL_CATALOG:
|
|
if any(keyword.lower() in lowered for keyword in item["keywords"]):
|
|
return item
|
|
return None
|
|
|
|
|
|
def serialize_files(project_dir: Path, paths: list[Path], source_root: Path) -> list[dict[str, Any]]:
|
|
results: list[dict[str, Any]] = []
|
|
for path in paths:
|
|
catalog = match_catalog(path.name)
|
|
results.append(
|
|
{
|
|
"name": path.name,
|
|
"path": str(path),
|
|
"relative_path": str(path.relative_to(project_dir)),
|
|
"source_root": source_root.name,
|
|
"source_root_path": str(source_root),
|
|
"matched_catalog_key": catalog["key"] if catalog else "",
|
|
"matched_catalog_label": catalog["label"] if catalog else "",
|
|
"safe_name": safe_filename(path.stem),
|
|
}
|
|
)
|
|
return results
|
|
|
|
|
|
def build_inventory(project_dir: Path) -> dict[str, Any]:
|
|
scan_roots: list[dict[str, str]] = []
|
|
material_files: list[dict[str, Any]] = []
|
|
for entry in iter_material_entries(project_dir):
|
|
scan_roots.append(
|
|
{
|
|
"name": entry.name,
|
|
"path": str(entry),
|
|
"type": "file" if entry.is_file() else "directory",
|
|
}
|
|
)
|
|
files = [entry] if entry.is_file() else list_files(entry)
|
|
material_files.extend(serialize_files(project_dir, files, entry))
|
|
material_files.sort(key=lambda item: item["relative_path"])
|
|
return {
|
|
"project_name": project_dir.name,
|
|
"project_dir": str(project_dir),
|
|
"scan_roots": scan_roots,
|
|
"material_files": material_files,
|
|
"summary": {
|
|
"scan_root_count": len(scan_roots),
|
|
"file_count": len(material_files),
|
|
"hinted_count": len([item for item in material_files if item["matched_catalog_key"]]),
|
|
},
|
|
}
|
|
|
|
|
|
def main() -> None:
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--project", required=True)
|
|
parser.add_argument("--out")
|
|
args = parser.parse_args()
|
|
|
|
project_dir = Path(args.project).resolve()
|
|
output_path = Path(args.out).resolve() if args.out else ensure_output_layout(project_dir)["work"] / "material_inventory.json"
|
|
inventory = build_inventory(project_dir)
|
|
write_json(output_path, inventory)
|
|
|
|
report_lines = [f"# {inventory['project_name']} 材料盘点", ""]
|
|
report_lines.append(f"- 扫描根:{inventory['summary']['scan_root_count']} 个")
|
|
report_lines.append(f"- 发现材料:{inventory['summary']['file_count']} 份")
|
|
report_lines.append(f"- 命中弱提示:{inventory['summary']['hinted_count']} 份")
|
|
report_lines.extend(["", "## 扫描根"])
|
|
report_lines.extend(
|
|
[f"- {item['name']} ({item['type']})" for item in inventory["scan_roots"]]
|
|
or ["- 暂无"]
|
|
)
|
|
report_lines.extend(["", "## 发现的材料"])
|
|
report_lines.extend(
|
|
[
|
|
f"- {item['relative_path']}"
|
|
+ (f" [提示:{item['matched_catalog_label']}]" if item["matched_catalog_label"] else "")
|
|
for item in inventory["material_files"]
|
|
]
|
|
or ["- 暂无"]
|
|
)
|
|
write_text(output_path.with_suffix(".md"), "\n".join(report_lines))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|