✨ feat(cli): parse toml config and dispatch actions
This commit is contained in:
parent
05903c33ae
commit
8cfcc25f98
|
|
@ -52,6 +52,12 @@ Playbook:TSL(`.tsl`/`.tsf`)+ C++ + Python + Markdown(代码格式化)
|
||||||
|
|
||||||
### 快速部署
|
### 快速部署
|
||||||
|
|
||||||
|
统一入口(配置驱动,示例见 `playbook.toml.example`):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python scripts/playbook.py -config playbook.toml
|
||||||
|
```
|
||||||
|
|
||||||
使用 `sync_templates` 脚本一键部署项目架构:
|
使用 `sync_templates` 脚本一键部署项目架构:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,26 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import sys
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import tomllib
|
||||||
|
|
||||||
|
ORDER = ["vendor", "sync_templates", "sync_standards", "install_skills", "format_md"]
|
||||||
|
|
||||||
|
|
||||||
def usage() -> str:
|
def usage() -> str:
|
||||||
return "Usage:\n python scripts/playbook.py -config <path>\n python scripts/playbook.py -h"
|
return "Usage:\n python scripts/playbook.py -config <path>\n python scripts/playbook.py -h"
|
||||||
|
|
||||||
|
|
||||||
|
def load_config(path: Path) -> dict:
|
||||||
|
return tomllib.loads(path.read_text(encoding="utf-8"))
|
||||||
|
|
||||||
|
|
||||||
|
def run_action(name: str, config: dict, context: dict) -> int:
|
||||||
|
_ = config, context
|
||||||
|
print(f"[action] {name}")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
def main(argv: list[str]) -> int:
|
def main(argv: list[str]) -> int:
|
||||||
if "-h" in argv or "-help" in argv:
|
if "-h" in argv or "-help" in argv:
|
||||||
print(usage())
|
print(usage())
|
||||||
|
|
@ -13,6 +28,31 @@ def main(argv: list[str]) -> int:
|
||||||
if "-config" not in argv:
|
if "-config" not in argv:
|
||||||
print("ERROR: -config is required.\n" + usage(), file=sys.stderr)
|
print("ERROR: -config is required.\n" + usage(), file=sys.stderr)
|
||||||
return 2
|
return 2
|
||||||
|
idx = argv.index("-config")
|
||||||
|
if idx + 1 >= len(argv) or not argv[idx + 1]:
|
||||||
|
print("ERROR: -config requires a path.\n" + usage(), file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
|
||||||
|
config_path = Path(argv[idx + 1]).expanduser()
|
||||||
|
if not config_path.is_file():
|
||||||
|
print(f"ERROR: config not found: {config_path}", file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
|
||||||
|
config = load_config(config_path)
|
||||||
|
playbook_config = config.get("playbook", {})
|
||||||
|
project_root = playbook_config.get("project_root")
|
||||||
|
if project_root:
|
||||||
|
root = Path(project_root).expanduser()
|
||||||
|
else:
|
||||||
|
root = config_path.parent
|
||||||
|
context = {"project_root": root.resolve(), "config_path": config_path.resolve()}
|
||||||
|
|
||||||
|
for name in ORDER:
|
||||||
|
if name in config:
|
||||||
|
result = run_action(name, config[name], context)
|
||||||
|
if result != 0:
|
||||||
|
return result
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
import tempfile
|
||||||
import unittest
|
import unittest
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
@ -26,6 +27,25 @@ class PlaybookCliTests(unittest.TestCase):
|
||||||
self.assertNotEqual(result.returncode, 0)
|
self.assertNotEqual(result.returncode, 0)
|
||||||
self.assertIn("-config", result.stdout + result.stderr)
|
self.assertIn("-config", result.stdout + result.stderr)
|
||||||
|
|
||||||
|
def test_action_order(self):
|
||||||
|
config_body = """
|
||||||
|
[playbook]
|
||||||
|
project_root = "."
|
||||||
|
|
||||||
|
[format_md]
|
||||||
|
|
||||||
|
[sync_standards]
|
||||||
|
langs = ["tsl"]
|
||||||
|
"""
|
||||||
|
with tempfile.TemporaryDirectory() as tmp_dir:
|
||||||
|
config_path = Path(tmp_dir) / "playbook.toml"
|
||||||
|
config_path.write_text(config_body, encoding="utf-8")
|
||||||
|
result = run_cli("-config", str(config_path))
|
||||||
|
|
||||||
|
self.assertEqual(result.returncode, 0)
|
||||||
|
output = result.stdout + result.stderr
|
||||||
|
self.assertIn("sync_standards", output)
|
||||||
|
self.assertIn("format_md", output)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue