"""读写 .env(保留其它键;不记录密钥到日志)。""" from __future__ import annotations import os import re from pathlib import Path _KEY_RE = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*$") def read_env_value(path: Path, key: str) -> str | None: if not path.is_file(): return None for line in path.read_text(encoding="utf-8").splitlines(): s = line.strip() if not s or s.startswith("#") or "=" not in s: continue k, v = s.split("=", 1) if k.strip() == key: return v.strip() return None def update_env_file(path: Path, updates: dict[str, str]) -> None: """更新或追加键值;已有键覆盖。""" for key in updates: if not _KEY_RE.fullmatch(key): raise ValueError(f"invalid env key: {key!r}") lines: list[str] = [] if path.is_file(): lines = path.read_text(encoding="utf-8").splitlines() seen: set[str] = set() out: list[str] = [] for line in lines: raw = line s = line.strip() if s and not s.startswith("#") and "=" in s: k, _ = s.split("=", 1) key = k.strip() if key in updates: out.append(f"{key}={updates[key]}") seen.add(key) continue out.append(raw) for key, val in updates.items(): if key not in seen: out.append(f"{key}={val}") path.parent.mkdir(parents=True, exist_ok=True) text = "\n".join(out) if text and not text.endswith("\n"): text += "\n" path.write_text(text, encoding="utf-8") for key, val in updates.items(): os.environ[key] = val