{ pkgs, lib, config, options, ... }: let inherit (lib.modules) mkIf ; inherit (lib.options) mkOption mkEnableOption literalExpression showOption ; t = lib.types; cfg = config.dynamicism; opts = options.dynamicism; subOpts = lib.mapAttrs (_: metaAttr: metaAttr.configuration.options) options.dynamicism.for.valueMeta.attrs; settingsFormat = pkgs.formats.yaml { }; concatFoldl = f: list: lib.foldl' (acc: value: acc ++ (f value)) [ ] list; recUpdateFoldlAttrs = f: attrs: lib.foldlAttrs (acc: name: value: lib.recursiveUpdate acc (f name value)) { } attrs; finalSettingsFor = { ... }@submod: lib.foldl (acc: optPath: let next = assert lib.isList optPath; lib.setAttrByPath optPath (lib.getAttrFromPath optPath config); in lib.recursiveUpdate acc next) { } submod.source-options; ourAssertions = lib.concatAttrValues { unitsExist = concatFoldl (submod: let next = lib.map (unit: assert lib.isString unit; { assertion = config.systemd.units.${unit}.enable or false; message = '' '${showOption submod.systemd-services-updated.loc}' specified non-existent unit '${unit}' ''; }) submod.systemd-services-updated.value; in lib.optionals submod.enable.value next) (lib.attrValues subOpts); 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. ''; }; }; # Assertions. config.assertions = ourAssertions; # # Generic implementation. # config.dynamicism.finalSettings = lib.asserts.checkAssertWarn ourAssertions [ ] ( recUpdateFoldlAttrs (name: { ... }@submod: finalSettingsFor submod) config.dynamicism.for ); # Implementations. config.dynamicism.for.gotosocial = let cfg = config.dynamicism.for.gotosocial; in { source-options = [ "services.gotosocial.settings" ]; configFile = settingsFormat.generate "gotosocial-override.yml" config.services.gotosocial.settings; unitDropins."gotosocial.service" = pkgs.writeText "gotosocial-override.conf" '' [Service] ExecStart= ExecStart=${lib.getExe' pkgs.gotosocial "gotosocial"} --config-path ${cfg.configFile} start ''; }; }