43 lines
1.3 KiB
Python
43 lines
1.3 KiB
Python
import json
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
|
|
def load_runtime_config(path: str) -> tuple[dict[str, Any], str | None]:
|
|
p = Path(path).expanduser()
|
|
if not p.exists():
|
|
return {}, None
|
|
try:
|
|
data = json.loads(p.read_text(encoding="utf-8"))
|
|
except Exception as e:
|
|
return {}, f"Failed to parse config '{p}': {e}"
|
|
if not isinstance(data, dict):
|
|
return {}, f"Config '{p}' must be a JSON object"
|
|
return data, None
|
|
|
|
|
|
def save_runtime_config(path: str, config: dict[str, Any]) -> str | None:
|
|
p = Path(path).expanduser()
|
|
try:
|
|
p.parent.mkdir(parents=True, exist_ok=True)
|
|
p.write_text(json.dumps(config, indent=2, sort_keys=True), encoding="utf-8")
|
|
return None
|
|
except Exception as e:
|
|
return f"Failed to save config '{p}': {e}"
|
|
|
|
|
|
def collect_cli_overrides(argv: list[str]) -> set[str]:
|
|
"""
|
|
Collect option names explicitly passed on CLI, normalized to argparse dest form.
|
|
Example: --focus-epics-enabled -> focus_epics_enabled
|
|
"""
|
|
out: set[str] = set()
|
|
for token in argv[1:]:
|
|
if not token.startswith("--"):
|
|
continue
|
|
key = token[2:]
|
|
if "=" in key:
|
|
key = key.split("=", 1)[0]
|
|
out.add(key.replace("-", "_"))
|
|
return out
|