Eliminate hub-overrides.nix: write feature toggles into custom.nix instead
Agent-Logs-Url: https://github.com/naturallaw777/staging_alpha/sessions/db82f216-af3e-4d7f-a972-86c03f23e069 Co-authored-by: naturallaw777 <99053422+naturallaw777@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
8d05f43594
commit
3c6106d06a
@@ -36,8 +36,10 @@ REBUILD_LOG = "/var/log/sovran-hub-rebuild.log"
|
||||
REBUILD_STATUS = "/var/log/sovran-hub-rebuild.status"
|
||||
REBUILD_UNIT = "sovran-hub-rebuild.service"
|
||||
|
||||
HUB_OVERRIDES_NIX = "/etc/nixos/hub-overrides.nix"
|
||||
DOMAINS_DIR = "/var/lib/domains"
|
||||
CUSTOM_NIX = "/etc/nixos/custom.nix"
|
||||
HUB_BEGIN = " # ── Hub Managed (do not edit) ──────────────"
|
||||
HUB_END = " # ── End Hub Managed ────────────────────────"
|
||||
DOMAINS_DIR = "/var/lib/domains"
|
||||
NOSTR_NPUB_FILE = "/var/lib/secrets/nostr_npub"
|
||||
NJALLA_SCRIPT = "/var/lib/njalla/njalla.sh"
|
||||
|
||||
@@ -434,21 +436,30 @@ def _read_rebuild_log(offset: int = 0) -> tuple[str, int]:
|
||||
return "", 0
|
||||
|
||||
|
||||
# ── hub-overrides.nix helpers ─────────────────────────────────────
|
||||
# ── custom.nix Hub Managed section helpers ────────────────────────
|
||||
|
||||
def _read_hub_overrides() -> tuple[dict, str | None]:
|
||||
"""Parse hub-overrides.nix. Returns (features_dict, nostr_npub_or_none)."""
|
||||
"""Parse the Hub Managed section inside custom.nix.
|
||||
Returns (features_dict, nostr_npub_or_none)."""
|
||||
features: dict[str, bool] = {}
|
||||
nostr_npub = None
|
||||
try:
|
||||
with open(HUB_OVERRIDES_NIX, "r") as f:
|
||||
with open(CUSTOM_NIX, "r") as f:
|
||||
content = f.read()
|
||||
begin = content.find(HUB_BEGIN)
|
||||
end = content.find(HUB_END)
|
||||
if begin == -1 or end == -1:
|
||||
return features, nostr_npub
|
||||
section = content[begin:end]
|
||||
for m in re.finditer(
|
||||
r'sovran_systemsOS\.features\.([a-zA-Z0-9_-]+)\s*=\s*(?:lib\.mkForce\s+)?(true|false)\s*;',
|
||||
content,
|
||||
section,
|
||||
):
|
||||
features[m.group(1)] = m.group(2) == "true"
|
||||
m2 = re.search(r'sovran_systemsOS\.nostr_npub\s*=\s*(?:lib\.mkForce\s+)?"([^"]*)"', content)
|
||||
m2 = re.search(
|
||||
r'sovran_systemsOS\.nostr_npub\s*=\s*(?:lib\.mkForce\s+)?"([^"]*)"',
|
||||
section,
|
||||
)
|
||||
if m2:
|
||||
nostr_npub = m2.group(1)
|
||||
except FileNotFoundError:
|
||||
@@ -457,25 +468,44 @@ def _read_hub_overrides() -> tuple[dict, str | None]:
|
||||
|
||||
|
||||
def _write_hub_overrides(features: dict, nostr_npub: str | None) -> None:
|
||||
"""Write a complete hub-overrides.nix from the given state."""
|
||||
"""Write the Hub Managed section inside custom.nix."""
|
||||
lines = []
|
||||
for feat_id, enabled in features.items():
|
||||
val = "true" if enabled else "false"
|
||||
lines.append(f" sovran_systemsOS.features.{feat_id} = lib.mkForce {val};")
|
||||
if nostr_npub:
|
||||
lines.append(f' sovran_systemsOS.nostr_npub = lib.mkForce "{nostr_npub}";')
|
||||
body = "\n".join(lines) + "\n" if lines else ""
|
||||
content = (
|
||||
"# Auto-generated by Sovran Hub — do not edit manually\n"
|
||||
"{ lib, ... }:\n"
|
||||
"{\n"
|
||||
+ body
|
||||
+ "}\n"
|
||||
hub_block = (
|
||||
HUB_BEGIN + "\n"
|
||||
+ "\n".join(lines) + ("\n" if lines else "")
|
||||
+ HUB_END + "\n"
|
||||
)
|
||||
nix_dir = os.path.dirname(HUB_OVERRIDES_NIX)
|
||||
if nix_dir:
|
||||
os.makedirs(nix_dir, exist_ok=True)
|
||||
with open(HUB_OVERRIDES_NIX, "w") as f:
|
||||
|
||||
try:
|
||||
with open(CUSTOM_NIX, "r") as f:
|
||||
content = f.read()
|
||||
except FileNotFoundError:
|
||||
return
|
||||
|
||||
begin = content.find(HUB_BEGIN)
|
||||
end = content.find(HUB_END)
|
||||
|
||||
if begin != -1 and end != -1:
|
||||
# Replace existing hub section (include the HUB_END line itself)
|
||||
newline_after_end = content.find("\n", end)
|
||||
if newline_after_end == -1:
|
||||
end_of_marker = len(content)
|
||||
else:
|
||||
end_of_marker = newline_after_end + 1
|
||||
content = content[:begin] + hub_block + content[end_of_marker:]
|
||||
else:
|
||||
# Insert hub section just before the final closing }
|
||||
last_brace = content.rfind("}")
|
||||
if last_brace == -1:
|
||||
return
|
||||
content = content[:last_brace] + "\n" + hub_block + content[last_brace:]
|
||||
|
||||
with open(CUSTOM_NIX, "w") as f:
|
||||
f.write(content)
|
||||
|
||||
|
||||
@@ -631,7 +661,7 @@ async def api_services():
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
|
||||
# Read runtime feature overrides from hub-overrides.nix
|
||||
# Read runtime feature overrides from custom.nix Hub Managed section
|
||||
overrides, _ = await loop.run_in_executor(None, _read_hub_overrides)
|
||||
|
||||
async def get_status(entry):
|
||||
@@ -640,7 +670,7 @@ async def api_services():
|
||||
icon = entry.get("icon", "")
|
||||
enabled = entry.get("enabled", True)
|
||||
|
||||
# Overlay runtime feature state from hub-overrides.nix
|
||||
# Overlay runtime feature state from custom.nix Hub Managed section
|
||||
feat_id = unit_to_feature.get(unit)
|
||||
if feat_id is None:
|
||||
feat_id = FEATURE_ICON_MAP.get(icon)
|
||||
@@ -838,7 +868,7 @@ async def api_features():
|
||||
feat_id = feat["id"]
|
||||
|
||||
# Determine enabled state:
|
||||
# 1. Check hub-overrides.nix first (explicit hub toggle)
|
||||
# 1. Check custom.nix Hub Managed section first (explicit hub toggle)
|
||||
# 2. Fall back to config.json services (features enabled in custom.nix)
|
||||
if feat_id in overrides:
|
||||
enabled = overrides[feat_id]
|
||||
|
||||
Reference in New Issue
Block a user