feat: Add generate_readme.py script
This commit is contained in:
125
generate_readme.py
Normal file
125
generate_readme.py
Normal file
@@ -0,0 +1,125 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
自动生成 README.md:扫描当前目录下的 Python 脚本和可执行包,
|
||||
提取其 docstring 并更新到 README 中。
|
||||
"""
|
||||
|
||||
import os
|
||||
import ast
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# 当前脚本所在目录
|
||||
SCRIPT_DIR = Path(__file__).parent.resolve()
|
||||
|
||||
# 输出 README 路径
|
||||
README_PATH = SCRIPT_DIR / "README.md"
|
||||
|
||||
# 模板路径(可选)
|
||||
TEMPLATE_PATH = SCRIPT_DIR / "README.template.md"
|
||||
|
||||
|
||||
def extract_docstring_from_file(file_path: Path) -> str:
|
||||
"""从 Python 文件中提取模块级 docstring。"""
|
||||
try:
|
||||
with open(file_path, "r", encoding="utf-8") as f:
|
||||
node = ast.parse(f.read())
|
||||
return ast.get_docstring(node) or "(无文档说明)"
|
||||
except Exception as e:
|
||||
return f"(解析失败: {e})"
|
||||
|
||||
|
||||
def collect_items():
|
||||
"""收集当前目录下所有 .py 文件和含 __main__.py 的子目录。"""
|
||||
items = []
|
||||
|
||||
for item in SCRIPT_DIR.iterdir():
|
||||
if item.name == Path(__file__).name:
|
||||
continue # 跳过本脚本
|
||||
if item.name.startswith("."):
|
||||
continue # 跳过隐藏文件/目录
|
||||
|
||||
if item.is_file() and item.suffix == ".py":
|
||||
name = item.stem
|
||||
doc = extract_docstring_from_file(item)
|
||||
items.append({"type": "script", "name": name, "doc": doc, "path": item.name})
|
||||
|
||||
elif item.is_dir():
|
||||
main_py = item / "__main__.py"
|
||||
if main_py.exists():
|
||||
name = item.name
|
||||
doc = extract_docstring_from_file(main_py)
|
||||
items.append({"type": "package", "name": name, "doc": doc, "path": str(item.name) + "/__main__.py"})
|
||||
|
||||
# 按名称排序
|
||||
items.sort(key=lambda x: x["name"].lower())
|
||||
return items
|
||||
|
||||
|
||||
def load_template() -> str:
|
||||
"""加载模板:优先用 README.template.md,否则用内置模板。"""
|
||||
if TEMPLATE_PATH.exists():
|
||||
with open(TEMPLATE_PATH, "r", encoding="utf-8") as f:
|
||||
return f.read()
|
||||
else:
|
||||
# 内置默认模板
|
||||
return """# 工具集
|
||||
|
||||
本目录包含以下可执行脚本与工具包:
|
||||
|
||||
{content}
|
||||
|
||||
---
|
||||
> 自动由 `{script_name}` 生成
|
||||
"""
|
||||
|
||||
|
||||
def generate_content(items):
|
||||
"""根据 items 生成 Markdown 内容。"""
|
||||
if not items:
|
||||
return "> 暂无 Python 脚本或可执行包。\n"
|
||||
|
||||
lines = []
|
||||
for item in items:
|
||||
title = f"`{item['name']}`"
|
||||
if item["type"] == "package":
|
||||
title += " (包)"
|
||||
lines.append(f"## {title}")
|
||||
lines.append("")
|
||||
# 渲染 docstring(保留原始换行,但缩进处理)
|
||||
doc = item["doc"].strip()
|
||||
if doc:
|
||||
# 如果 docstring 是多行,用引用块或直接段落
|
||||
if "\n" in doc:
|
||||
lines.append("```text")
|
||||
lines.append(doc)
|
||||
lines.append("```")
|
||||
else:
|
||||
lines.append(doc)
|
||||
else:
|
||||
lines.append("(无文档说明)")
|
||||
lines.append("")
|
||||
lines.append(f"> 文件路径: `{item['path']}`")
|
||||
lines.append("")
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def main():
|
||||
items = collect_items()
|
||||
template = load_template()
|
||||
content = generate_content(items)
|
||||
readme_text = template.format(
|
||||
content=content,
|
||||
script_name=Path(__file__).name
|
||||
)
|
||||
|
||||
with open(README_PATH, "w", encoding="utf-8") as f:
|
||||
f.write(readme_text)
|
||||
|
||||
print(f"✅ README.md 已更新,共收录 {len(items)} 个项目。")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user