- 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
96 lines
2.8 KiB
Python
96 lines
2.8 KiB
Python
from __future__ import annotations
|
||
|
||
import configparser
|
||
import os
|
||
from dataclasses import dataclass
|
||
|
||
from sapcli.exceptions import ConfigError
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class SAPConfig:
|
||
host: str
|
||
client: str
|
||
user: str
|
||
password: str
|
||
|
||
def __post_init__(self):
|
||
missing = []
|
||
if not self.host:
|
||
missing.append("host")
|
||
if not self.user:
|
||
missing.append("user")
|
||
if not self.password:
|
||
missing.append("password")
|
||
if missing:
|
||
raise ConfigError(
|
||
f"配置缺失: {', '.join(missing)}. "
|
||
f"请设置环境变量或配置文件 (config.ini)"
|
||
)
|
||
|
||
|
||
def list_profiles(config_path: str | None = None) -> list[str]:
|
||
"""列出配置文件中所有可用的 profile(section 名称)。"""
|
||
cfg = configparser.ConfigParser()
|
||
path = config_path or _find_config_file()
|
||
if path:
|
||
cfg.read(path, encoding="utf-8")
|
||
return cfg.sections()
|
||
|
||
|
||
def _find_config_file() -> str | None:
|
||
"""按搜索路径查找 config.ini。"""
|
||
search_paths: list[str] = []
|
||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||
project_root = os.path.dirname(script_dir)
|
||
search_paths.append(os.path.join(os.getcwd(), "config.ini"))
|
||
search_paths.append(os.path.join(project_root, "config.ini"))
|
||
for p in search_paths:
|
||
if os.path.isfile(p):
|
||
return p
|
||
return None
|
||
|
||
|
||
def load_config(
|
||
config_path: str | None = None,
|
||
profile: str | None = None,
|
||
) -> tuple[SAPConfig, str | None]:
|
||
cfg = configparser.ConfigParser()
|
||
search_paths: list[str] = []
|
||
|
||
if config_path:
|
||
search_paths.append(config_path)
|
||
|
||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||
project_root = os.path.dirname(script_dir)
|
||
search_paths.append(os.path.join(os.getcwd(), "config.ini"))
|
||
search_paths.append(os.path.join(project_root, "config.ini"))
|
||
|
||
loaded_from = None
|
||
for p in search_paths:
|
||
if os.path.isfile(p):
|
||
cfg.read(p, encoding="utf-8")
|
||
loaded_from = p
|
||
break
|
||
|
||
# profile 参数决定读哪个 section,默认 SAP
|
||
section = profile or "SAP"
|
||
sap = cfg[section] if cfg.has_section(section) else {}
|
||
|
||
host = os.environ.get("SAP_HOST", sap.get("host", ""))
|
||
client = os.environ.get("SAP_CLIENT", sap.get("client", "100"))
|
||
user = os.environ.get("SAP_USER", sap.get("user", ""))
|
||
config_password = sap.get("password", "")
|
||
env_password = os.environ.get("SAP_PASSWORD", "")
|
||
|
||
# 密码优先级: 环境变量 > keyring > config.ini
|
||
from sapcli.password import resolve_password
|
||
password = resolve_password(host, client, user, config_password, env_password)
|
||
|
||
return SAPConfig(
|
||
host=host,
|
||
client=client,
|
||
user=user,
|
||
password=password,
|
||
), loaded_from
|