Merge pull request #11 from naturallaw777/copilot/eliminate-hub-overrides

Eliminate hub-overrides.nix: write feature toggles directly into custom.nix
This commit is contained in:
Sovran_Systems
2026-04-03 09:30:43 -05:00
committed by GitHub
3 changed files with 53 additions and 43 deletions

View File

@@ -36,8 +36,10 @@ REBUILD_LOG = "/var/log/sovran-hub-rebuild.log"
REBUILD_STATUS = "/var/log/sovran-hub-rebuild.status" REBUILD_STATUS = "/var/log/sovran-hub-rebuild.status"
REBUILD_UNIT = "sovran-hub-rebuild.service" REBUILD_UNIT = "sovran-hub-rebuild.service"
HUB_OVERRIDES_NIX = "/etc/nixos/hub-overrides.nix" CUSTOM_NIX = "/etc/nixos/custom.nix"
DOMAINS_DIR = "/var/lib/domains" 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" NOSTR_NPUB_FILE = "/var/lib/secrets/nostr_npub"
NJALLA_SCRIPT = "/var/lib/njalla/njalla.sh" NJALLA_SCRIPT = "/var/lib/njalla/njalla.sh"
@@ -434,21 +436,30 @@ def _read_rebuild_log(offset: int = 0) -> tuple[str, int]:
return "", 0 return "", 0
# ── hub-overrides.nix helpers ───────────────────────────────────── # ── custom.nix Hub Managed section helpers ────────────────────────
def _read_hub_overrides() -> tuple[dict, str | None]: 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] = {} features: dict[str, bool] = {}
nostr_npub = None nostr_npub = None
try: try:
with open(HUB_OVERRIDES_NIX, "r") as f: with open(CUSTOM_NIX, "r") as f:
content = f.read() 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( for m in re.finditer(
r'sovran_systemsOS\.features\.([a-zA-Z0-9_-]+)\s*=\s*(?:lib\.mkForce\s+)?(true|false)\s*;', 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" 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: if m2:
nostr_npub = m2.group(1) nostr_npub = m2.group(1)
except FileNotFoundError: 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: 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 = [] lines = []
for feat_id, enabled in features.items(): for feat_id, enabled in features.items():
val = "true" if enabled else "false" val = "true" if enabled else "false"
lines.append(f" sovran_systemsOS.features.{feat_id} = lib.mkForce {val};") lines.append(f" sovran_systemsOS.features.{feat_id} = lib.mkForce {val};")
if nostr_npub: if nostr_npub:
lines.append(f' sovran_systemsOS.nostr_npub = lib.mkForce "{nostr_npub}";') lines.append(f' sovran_systemsOS.nostr_npub = lib.mkForce "{nostr_npub}";')
body = "\n".join(lines) + "\n" if lines else "" hub_block = (
content = ( HUB_BEGIN + "\n"
"# Auto-generated by Sovran Hub — do not edit manually\n" + "\n".join(lines) + ("\n" if lines else "")
"{ lib, ... }:\n" + HUB_END + "\n"
"{\n"
+ body
+ "}\n"
) )
nix_dir = os.path.dirname(HUB_OVERRIDES_NIX)
if nix_dir: try:
os.makedirs(nix_dir, exist_ok=True) with open(CUSTOM_NIX, "r") as f:
with open(HUB_OVERRIDES_NIX, "w") 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) f.write(content)
@@ -631,7 +661,7 @@ async def api_services():
loop = asyncio.get_event_loop() 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) overrides, _ = await loop.run_in_executor(None, _read_hub_overrides)
async def get_status(entry): async def get_status(entry):
@@ -640,7 +670,7 @@ async def api_services():
icon = entry.get("icon", "") icon = entry.get("icon", "")
enabled = entry.get("enabled", True) 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) feat_id = unit_to_feature.get(unit)
if feat_id is None: if feat_id is None:
feat_id = FEATURE_ICON_MAP.get(icon) feat_id = FEATURE_ICON_MAP.get(icon)
@@ -838,7 +868,7 @@ async def api_features():
feat_id = feat["id"] feat_id = feat["id"]
# Determine enabled state: # 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) # 2. Fall back to config.json services (features enabled in custom.nix)
if feat_id in overrides: if feat_id in overrides:
enabled = overrides[feat_id] enabled = overrides[feat_id]

View File

@@ -4,9 +4,7 @@
imports = [ imports = [
./modules/modules.nix ./modules/modules.nix
./iso/branding.nix ./iso/branding.nix
] ++ (if builtins.pathExists /etc/nixos/hub-overrides.nix ];
then [ /etc/nixos/hub-overrides.nix ]
else []);
# ── Boot ──────────────────────────────────────────────────── # ── Boot ────────────────────────────────────────────────────
boot.loader.systemd-boot.enable = true; boot.loader.systemd-boot.enable = true;

View File

@@ -283,24 +283,6 @@ in
}; };
}; };
systemd.services.hub-overrides-init = {
description = "Initialize hub-overrides.nix if missing";
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
unitConfig.ConditionPathExists = "!/etc/nixos/hub-overrides.nix";
script = ''
cat > /etc/nixos/hub-overrides.nix <<'EOF'
# Auto-generated by Sovran Hub do not edit manually
{ lib, ... }:
{
}
EOF
'';
};
networking.firewall.allowedTCPPorts = [ 8937 ]; networking.firewall.allowedTCPPorts = [ 8937 ];
}; };
} }