af5b9835ba
Co-authored-by: Cursor <cursoragent@cursor.com>
73 lines
2.2 KiB
Python
73 lines
2.2 KiB
Python
"""Hub .env 读写(仅中控账号等少量键)."""
|
|
from __future__ import annotations
|
|
|
|
import re
|
|
from pathlib import Path
|
|
from typing import Dict, List
|
|
|
|
_KEY_RE = re.compile(r"^([A-Za-z_][A-Za-z0-9_]*)=(.*)$")
|
|
|
|
|
|
def _parse_line(line: str) -> tuple[str | None, str]:
|
|
raw = line.rstrip("\n\r")
|
|
if not raw.strip() or raw.lstrip().startswith("#"):
|
|
return None, raw
|
|
m = _KEY_RE.match(raw)
|
|
if not m:
|
|
return None, raw
|
|
return m.group(1), raw
|
|
|
|
|
|
def apply_env_updates(path: Path | str, updates: Dict[str, str]) -> List[str]:
|
|
"""更新或追加 .env 键;返回实际写入的 key 列表.不删其它行."""
|
|
env_path = Path(path)
|
|
wanted = {str(k).strip(): str(v) for k, v in updates.items() if str(k).strip()}
|
|
if not wanted:
|
|
return []
|
|
|
|
lines: list[str] = []
|
|
if env_path.is_file():
|
|
lines = env_path.read_text(encoding="utf-8").splitlines(keepends=True)
|
|
|
|
seen: set[str] = set()
|
|
out: list[str] = []
|
|
changed: list[str] = []
|
|
|
|
for line in lines:
|
|
key, _ = _parse_line(line)
|
|
if key and key in wanted:
|
|
out.append(f"{key}={wanted[key]}\n")
|
|
seen.add(key)
|
|
changed.append(key)
|
|
else:
|
|
if line.endswith("\n") or line.endswith("\r"):
|
|
out.append(line if line.endswith("\n") else line + "\n")
|
|
else:
|
|
out.append(line + "\n")
|
|
|
|
for key, val in wanted.items():
|
|
if key not in seen:
|
|
out.append(f"{key}={val}\n")
|
|
changed.append(key)
|
|
|
|
env_path.parent.mkdir(parents=True, exist_ok=True)
|
|
env_path.write_text("".join(out), encoding="utf-8")
|
|
return changed
|
|
|
|
|
|
def env_get(path: Path | str, key: str, default: str = "") -> str:
|
|
env_path = Path(path)
|
|
if not env_path.is_file():
|
|
return default
|
|
want = (key or "").strip()
|
|
if not want:
|
|
return default
|
|
for line in env_path.read_text(encoding="utf-8").splitlines():
|
|
k, _ = _parse_line(line)
|
|
if k == want:
|
|
m = _KEY_RE.match(line.rstrip("\n\r"))
|
|
if m:
|
|
return m.group(2)
|
|
return default
|
|
return default
|