b5cba83df4
Co-authored-by: Cursor <cursoragent@cursor.com>
61 lines
1.6 KiB
Python
61 lines
1.6 KiB
Python
"""读写 .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
|