{ pkgs, lib, config, options, ... }: let inherit (lib.options) mkOption showOption ; t = lib.types; inherit (import ./lib.nix { inherit lib; }) typeCheck convenientAttrPath concatFoldl recUpdateFoldl recUpdateFoldlAttrs ; evalNixos = import (pkgs.path + "/nixos"); opts = options.dynamicism; subOpts = lib.mapAttrs (_: metaAttr: metaAttr.configuration.options) options.dynamicism.for.valueMeta.attrs; settingsFormat = pkgs.formats.yaml { }; 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 = { inherit pkgs; }; }); default = { }; }; finalSettings = mkOption { type = t.attrsOf t.raw; internal = true; readOnly = true; description = '' Attrset of each `source-options` tree to their actual values. ''; }; doChange = mkOption { type = t.functionTo t.pathInStore; readOnly = true; description = '' The function to call to Do The Thing. ''; }; }; # Assertions. config.assertions = ourAssertions; # # Generic implementation. # config.dynamicism.doChange = { option, value, configuration ? builtins.getEnv "NIXOS_CONFIG", }: let loc = opts.doChange.loc ++ [ "(function argument)" "value" ]; option' = typeCheck loc convenientAttrPath option; nixosAfter = evalNixos { configuration = { config, ... }: { imports = [ configuration (lib.setAttrByPath option' (lib.mkOverride (-999) value)) ]; environment.systemPackages = [ config.dynamicism.for.gotosocial.activate ]; }; }; allActivations = lib.mapAttrsToList (name: submod: submod.activate) config.dynamicism.for; allActivationScripts = pkgs.writeShellApplication { name = "dynamicism-activate"; runtimeInputs = allActivations; text = nixosAfter.config.dynamicism.for |> lib.mapAttrsToList (name: submod: '' echo "Activating dynamicism for ${name}" ${lib.getExe submod.activate} '') |> lib.concatStringsSep "\n"; }; in allActivationScripts; config.dynamicism.finalSettings = lib.asserts.checkAssertWarn ourAssertions [ ] ( recUpdateFoldlAttrs (name: { ... }@submod: finalSettingsFor submod) config.dynamicism.for ); # Implementations. imports = [ ./gotosocial.nix ]; }