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