# SPDX-FileCopyrightText: 2026 Qyriad # # SPDX-License-Identifier: EUPL-1.1 { pkgs, lib, config, options, ... }: let inherit (lib.options) mkOption showOption ; inherit (lib.asserts) checkAssertWarn ; t = lib.types; inherit (import ./lib.nix { inherit lib; }) typeCheck executablePathInStore concatFoldl recUpdateFoldl recUpdateFoldlAttrs ; evalNixos = import (pkgs.path + "/nixos"); opts = options.dynamicism; subOpts = lib.mapAttrs (_: metaAttr: metaAttr.configuration.options) options.dynamicism.for.valueMeta.attrs; seqTrue = v: lib.seq v true; finalSettingsFor = { ... }@submod: recUpdateFoldl (optPath: lib.setAttrByPath optPath (lib.getAttrFromPath optPath config) ) submod.source-options; ourAssertions = lib.concatAttrValues { unitsExist = subOpts |> lib.attrValues |> concatFoldl (submod: submod.systemd-services-updated.value |> lib.map (unit: { assertion = config.systemd.units.${unit}.enable or false; message = '' ${showOption submod.systemd-services-updated.loc}' specified non-existent unit '${unit}' ''; }) |> lib.optionals submod.enable.value ); optsExist = concatFoldl (submod: lib.optionals submod.enable.value (lib.map (optPath: { assertion = lib.hasAttrByPath optPath options; message = "'${showOption submod.source-options.loc}' specified non-existent option '${showOption optPath}'"; }) submod.source-options.value)) (lib.attrValues subOpts); }; in { # # Interface. # options.dynamicism = { for = mkOption { type = t.attrsOf (t.submoduleWith { modules = [ ./submodule.nix ]; shorthandOnlyDefinesConfig = false; specialArgs = { host = { inherit pkgs options config; }; }; }); default = { }; }; finalEnabledSubmodules = mkOption { type = options.dynamicism.for.type; internal = true; readOnly = true; default = lib.filterAttrs (lib.const (lib.getAttr "enable")) config.dynamicism.for; }; finalSettings = mkOption { type = t.attrsOf t.raw; internal = true; readOnly = true; description = '' Attrset of each `source-options` tree to their actual values. ''; }; finalActivationScript = mkOption { type = executablePathInStore; internal = true; }; applyDynamicConfiguration = mkOption { #type = t.functionTo t.pathInStore; type = t.functionTo t.raw; readOnly = true; }; }; # Assertions. config.assertions = ourAssertions; # # Generic implementation. # config.system.activationScripts = config.dynamicism.for |> lib.filterAttrs (lib.const (lib.getAttr "enable")) |> lib.mapAttrs' (name: submod: let forUnit = unitName: assert lib.isString unitName; let dropinDir = "/run/systemd/system/${unitName}.d"; systemctl = lib.getExe' pkgs.systemd "systemctl"; in '' if [[ -d "${dropinDir}" ]]; then echo "Removing files in "${dropinDir}" echo "Removing files in "${dropinDir}" >&2 rm -rvf "${dropinDir}/"* rmdir "${dropinDir}" ${systemctl} daemon-reload ${systemctl} try-reload-or-restart "${unitName}" fi ''; in { name = "dynix-reset-dynamicism-for-${name}"; value.deps = [ "etc" "stdio" "specialfs" "binsh" "usrbinenv" "var" "udevd" ]; value.text = '' set -x echo "Removing existing dynamic overrides for ${name}" echo "Removing existing dynamic overrides for ${name}" >&2 ${submod.systemd-services-updated |> lib.map forUnit |> lib.concatStringsSep "\n"} set +x ''; }); config.dynamicism = { applyDynamicConfiguration = { baseConfiguration ? builtins.getEnv "NIXOS_CONFIG", newConfiguration ? (lib.filesystem.dirOf baseConfiguration) + "/dynamic.nix", }: let locFor = appendage: lib.concatLists [ opts.applyDynamicConfiguration.loc [ "(function argument)" ] (lib.toList appendage) ]; in assert seqTrue (typeCheck (locFor "baseConfiguration") t.deferredModule baseConfiguration); assert seqTrue (typeCheck (locFor "newConfiguration") t.deferredModule newConfiguration); let _file = "«inline module in ${showOption opts.applyDynamicConfiguration.loc}»"; nixosBefore = evalNixos { configuration = { ... }: { inherit _file; imports = [ baseConfiguration ]; }; }; nixosAfter = evalNixos { configuration = { ... }: { inherit _file; imports = [ baseConfiguration newConfiguration ]; }; }; submodulesChanged = nixosAfter.config.dynamicism.for |> lib.filterAttrs (lib.const (lib.getAttr "enable")) |> lib.filterAttrs (submodName: _: nixosBefore.config.dynamicism.for.${submodName}.finalSettings != nixosAfter.config.dynamicism.for.${submodName}.finalSettings ); runForSubmodCalled = name: '' echo "Activating dynamic configuration for ${name}" ${lib.getExe nixosAfter.config.dynamicism.for.${name}.activate} ''; runForChanged = submodulesChanged |> lib.mapAttrsToList (name: _: runForSubmodCalled name) |> lib.concatStringsSep "\n"; in pkgs.writeShellApplication { name = "dynamicism-activate"; text = runForChanged; passthru.configuration = nixosAfter; }; finalActivationScript = pkgs.writeShellApplication { name = "dynamicism-activate-all"; text = config.dynamicism.for |> lib.filterAttrs (lib.const (lib.getAttr "enable")) |> lib.mapAttrsToList (name: submod: '' echo "Activating dynamic configuration for ${name}" ${lib.getExe submod.activate} '') |> lib.concatStringsSep "\n"; }; finalSettings = config.dynamicism.for |> recUpdateFoldlAttrs (name: { ... }@submod: finalSettingsFor submod) |> checkAssertWarn ourAssertions [ ]; }; # Implementations. imports = [ ./gotosocial.nix ./harmonia.nix ./distccd.nix ]; }