#!/usr/bin/env python3 """ 项目配置读取工具。 读取顺序: 1. 当前进程环境变量 2. 项目根目录下的 .env / .env.local 3. 用户常见 shell 配置文件中的 export 语句 """ from pathlib import Path import os PROJECT_DIR = Path(__file__).resolve().parent ENV_FILE_NAMES = (".env", ".env.local") SHELL_RC_FILES = ( Path("~/.zshrc").expanduser(), Path("~/.zprofile").expanduser(), Path("~/.zlogin").expanduser(), Path("~/.bash_profile").expanduser(), Path("~/.bashrc").expanduser(), Path("~/.profile").expanduser(), ) def _parse_assignment(line): """解析 KEY=VALUE 或 export KEY=VALUE 形式的配置行。""" stripped = line.strip() if not stripped or stripped.startswith("#"): return None if stripped.startswith("export "): stripped = stripped[7:].strip() if "=" not in stripped: return None key, value = stripped.split("=", 1) key = key.strip() value = value.strip() if not key or any(ch.isspace() for ch in key): return None if value[:1] in {"'", '"'} and value[-1:] == value[:1]: value = value[1:-1] else: value = value.split(" #", 1)[0].strip() return key, value def _read_var_from_file(file_path, var_name): """从文本配置文件里读取指定变量,后出现的值优先。""" try: lines = file_path.read_text(encoding="utf-8").splitlines() except OSError: return "" result = "" for line in lines: parsed = _parse_assignment(line) if not parsed: continue key, value = parsed if key == var_name and value: result = value return result def _project_env_files(project_dir=None): base_dir = Path(project_dir) if project_dir else PROJECT_DIR return [base_dir / name for name in ENV_FILE_NAMES] def load_project_env(project_dir=None): """把项目 .env 文件里的变量加载到当前进程环境中。""" for file_path in _project_env_files(project_dir): if not file_path.exists(): continue try: lines = file_path.read_text(encoding="utf-8").splitlines() except OSError: continue for line in lines: parsed = _parse_assignment(line) if not parsed: continue key, value = parsed if key and value and key not in os.environ: os.environ[key] = value def get_env_value(var_name, default="", project_dir=None): """按项目约定顺序读取配置值,并回填到当前进程环境。""" value = os.environ.get(var_name, "") if value: return value load_project_env(project_dir) value = os.environ.get(var_name, "") if value: return value for file_path in _project_env_files(project_dir): value = _read_var_from_file(file_path, var_name) if value: os.environ[var_name] = value return value for file_path in SHELL_RC_FILES: value = _read_var_from_file(file_path, var_name) if value: os.environ[var_name] = value return value return default