Files
wurangyu 1e39b6da88 feat: sap-cli skill v2.1.0 — self-contained distributable package
- assets/: sap-cli source (v2.1.0, 26 commands, 16 object types)
- references/: tool constraints + error handling (self-contained)
- scripts/setup.py: one-click install/config/verify
- SKILL.md: full command reference + dual-platform install guide
- VERSION: 2.1.0

Built from D:/Codespace/sap-cli via scripts/pack_skill.py
2026-06-13 20:52:24 +08:00

213 lines
7.4 KiB
Python

#!/usr/bin/env python3
"""sap-cli 安装与配置脚本。
用法:
python setup.py install # 安装 sap-cli 及依赖
python setup.py config # 交互式配置 SAP 连接
python setup.py verify # 验证安装和连接
python setup.py all # 一键完成:安装 + 配置 + 验证
"""
from __future__ import annotations
import os
import sys
import subprocess
from pathlib import Path
# ── 路径常量 ──────────────────────────────────────────────
SKILL_DIR = Path(__file__).resolve().parent.parent
ASSETS_DIR = SKILL_DIR / "assets"
CONFIG_EXAMPLE = ASSETS_DIR / "config.ini.example"
CONFIG_FILE = ASSETS_DIR / "config.ini"
def _run(cmd: list[str], **kw) -> int:
"""运行命令并实时输出。"""
print(f" $ {' '.join(cmd)}")
return subprocess.call(cmd, **kw)
def _pip_available() -> bool:
try:
subprocess.run([sys.executable, "-m", "pip", "--version"],
capture_output=True, check=True)
return True
except Exception:
return False
# ── 安装 ─────────────────────────────────────────────────
def do_install():
"""安装 sap-cli 及其依赖。"""
print("\n📦 安装 sap-cli ...")
# 1. 检查 Python 版本
py_ver = sys.version_info
if py_ver < (3, 10):
print(f" ❌ Python 3.10+ required, got {py_ver.major}.{py_ver.minor}")
sys.exit(1)
print(f" ✅ Python {py_ver.major}.{py_ver.minor}.{py_ver.micro}")
# 2. 安装依赖
if _pip_available():
print("\n Installing dependencies ...")
ret = _run([sys.executable, "-m", "pip", "install", "requests>=2.28.0"])
if ret != 0:
print(" ⚠️ pip install failed, trying manual install ...")
else:
print(" ⚠️ pip not available, skipping dependency install.")
print(" 请手动安装: pip install requests")
# 3. 验证 sapcli 包可导入
print("\n Verifying sapcli package ...")
ret = _run([sys.executable, "-c", "from sapcli import __version__; print(f' ✅ sap-cli v{__version__}')"],
cwd=str(ASSETS_DIR))
if ret != 0:
print(" ❌ sapcli package import failed.")
sys.exit(1)
# 4. 验证 CLI 入口
ret = _run([sys.executable, "main.py", "--help"], cwd=str(ASSETS_DIR))
if ret != 0:
print(" ❌ CLI entry point failed.")
sys.exit(1)
print("\n ✅ sap-cli 安装成功!")
print(f" 安装位置: {ASSETS_DIR}")
print(f" 运行方式: cd {ASSETS_DIR} && python main.py <command>")
# ── 配置 ─────────────────────────────────────────────────
def do_config():
"""交互式配置 SAP 连接。"""
print("\n⚙️ 配置 SAP 连接 ...")
if CONFIG_FILE.exists():
print(f" 配置文件已存在: {CONFIG_FILE}")
answer = input(" 是否覆盖?(y/N): ").strip().lower()
if answer != "y":
print(" 保留现有配置。")
return
# 从模板创建
if CONFIG_EXAMPLE.exists():
import shutil
shutil.copy2(CONFIG_EXAMPLE, CONFIG_FILE)
print(f" ✅ 已从模板创建: {CONFIG_FILE}")
else:
# 手动创建
CONFIG_FILE.write_text(
"[SAP]\nhost = \nclient = \nuser = \npassword = \n",
encoding="utf-8",
)
print(f" ✅ 已创建空白配置: {CONFIG_FILE}")
# 交互式填写
print("\n 请输入 SAP 连接信息(留空跳过):")
host = input(" SAP 服务器地址 (如 http://sap.example.com:8000): ").strip()
client = input(" SAP Client (如 100): ").strip()
user = input(" 用户名: ").strip()
password = input(" 密码: ").strip()
if host or client or user or password:
# 简单替换
content = CONFIG_FILE.read_text(encoding="utf-8")
if host:
content = _replace_config_value(content, "host", host)
if client:
content = _replace_config_value(content, "client", client)
if user:
content = _replace_config_value(content, "user", user)
if password:
content = _replace_config_value(content, "password", password)
CONFIG_FILE.write_text(content, encoding="utf-8")
print(" ✅ 配置已更新。")
else:
print(" ⚠️ 未填写任何信息,请手动编辑: " + str(CONFIG_FILE))
print("\n 💡 也可以通过环境变量配置(优先级更高):")
print(" SAP_HOST / SAP_CLIENT / SAP_USER / SAP_PASSWORD")
def _replace_config_value(content: str, key: str, value: str) -> str:
"""替换 config.ini 中的值。"""
import re
pattern = rf"^({key}\s*=\s*).*?$"
return re.sub(pattern, rf"\g<1>{value}", content, flags=re.MULTILINE)
# ── 验证 ─────────────────────────────────────────────────
def do_verify():
"""验证安装和连接。"""
print("\n🔍 验证安装 ...")
# 1. 包导入
ret = _run([sys.executable, "-c", "from sapcli import __version__; print(' ✅ 包导入正常')"],
cwd=str(ASSETS_DIR))
if ret != 0:
print(" ❌ 包导入失败")
return False
# 2. CLI 帮助
ret = _run([sys.executable, "main.py", "--help"], cwd=str(ASSETS_DIR))
if ret != 0:
print(" ❌ CLI 入口失败")
return False
# 3. 配置文件
if CONFIG_FILE.exists():
print(f" ✅ 配置文件: {CONFIG_FILE}")
else:
print(f" ⚠️ 未找到配置文件,请运行: python setup.py config")
return False
# 4. SAP 连接测试
print("\n 测试 SAP 连接 ...")
ret = _run([sys.executable, "main.py", "config", "show"], cwd=str(ASSETS_DIR))
if ret == 0:
print(" ✅ SAP 连接正常!")
return True
else:
print(" ⚠️ 连接测试失败,请检查配置。")
return False
# ── 一键全部 ─────────────────────────────────────────────
def do_all():
"""安装 + 配置 + 验证。"""
do_install()
do_config()
do_verify()
print("\n" + "=" * 50)
print(" 🎉 sap-cli 已就绪!")
print(" 使用示例:")
print(f" cd {ASSETS_DIR}")
print(" python main.py info --name ZMY_CLASS --type class")
print("=" * 50)
# ── 入口 ─────────────────────────────────────────────────
def main():
commands = {
"install": do_install,
"config": do_config,
"verify": do_verify,
"all": do_all,
}
if len(sys.argv) < 2 or sys.argv[1] not in commands:
print("Usage: python setup.py <install|config|verify|all>")
print()
print("Commands:")
print(" install - Install sap-cli and dependencies")
print(" config - Configure SAP connection (interactive)")
print(" verify - Verify installation and connection")
print(" all - Install + config + verify (recommended)")
sys.exit(1)
commands[sys.argv[1]]()
if __name__ == "__main__":
main()