Files
chongming-template/init.py
T

96 lines
3.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""chongming 项目模板初始化。
用法:
python init.py <目标目录> [--name 项目名] [--app-name 应用名] [--no-sync]
行为:
1. 拒绝覆盖非空目录
2. 复制模板内容(不含 init.py 与模板自身 README;README.project.md 重命名为 README.md)
3. 替换占位符 {{project_name}}(发行名)/ {{app_name}}(应用显示名)
4. 默认在目标目录执行 uv sync(--no-sync 跳过)
示例:
python init.py ~/proj/my-gateway
python init.py ../demo --name demo --app-name "演示网关"
"""
from __future__ import annotations
import argparse
import shutil
import subprocess
import sys
from pathlib import Path
TEMPLATE_DIR = Path(__file__).resolve().parent
# 模板自身文件 / 生成物:不复制
SKIP_NAMES = {"init.py", "README.md", ".git", "__pycache__", ".venv", "dist", "build"}
# 做占位符替换的文本文件
TEXT_SUFFIXES = {".py", ".toml", ".md", ".json5", ".json", ".yaml", ".yml", ".sh", ".txt"}
TEXT_NAMES = {".gitignore", ".env.example"}
# 生成项目里该文件重命名为 README.md
PROJECT_README = "README.project.md"
def main() -> int:
parser = argparse.ArgumentParser(description="chongming 项目模板初始化")
parser.add_argument("target", help="目标项目目录(不存在则创建;必须为空)")
parser.add_argument("--name", help="项目名(pyproject 的 name,默认取目标目录名)")
parser.add_argument("--app-name", help="应用显示名(config.toml 的 app.name,默认同项目名)")
parser.add_argument("--no-sync", action="store_true", help="跳过 uv sync")
args = parser.parse_args()
target = Path(args.target).expanduser().resolve()
project_name = args.name or target.name
app_name = args.app_name or project_name
if target.exists() and any(target.iterdir()):
print(f"❌ 目标目录非空,拒绝覆盖: {target}")
return 1
replacements = {"{{project_name}}": project_name, "{{app_name}}": app_name}
copied = 0
for src in sorted(TEMPLATE_DIR.rglob("*")):
rel = src.relative_to(TEMPLATE_DIR)
if any(part in SKIP_NAMES for part in rel.parts):
continue
dst = target / ("README.md" if rel.as_posix() == PROJECT_README else rel)
if src.is_dir():
dst.mkdir(parents=True, exist_ok=True)
continue
dst.parent.mkdir(parents=True, exist_ok=True)
if src.suffix in TEXT_SUFFIXES or src.name in TEXT_NAMES:
text = src.read_text(encoding="utf-8")
for key, value in replacements.items():
text = text.replace(key, value)
dst.write_text(text, encoding="utf-8")
else:
shutil.copy2(src, dst)
copied += 1
print(f"✅ 已初始化: {target}")
print(f" 项目名={project_name} 应用名={app_name} 文件数={copied}")
if args.no_sync:
print("(--no-sync:跳过 uv sync)")
elif shutil.which("uv") is None:
print("⚠️ 未找到 uv,跳过依赖安装;请在目标目录自行执行 uv sync")
else:
print("→ uv sync(首次安装依赖,可能需要几分钟)")
if subprocess.call(["uv", "sync"], cwd=target) != 0:
print("⚠️ uv sync 未成功,请在目标目录手动重试")
print("\n下一步:")
print(f" cd {target}")
print(" uv run serve # 启动(http://localhost:8000/docs)")
print(" curl 'http://localhost:8000/api/v1/example/hello?name=world'")
print(" uv run gen_plugin <name> # 生成新插件骨架")
return 0
if __name__ == "__main__":
sys.exit(main())