diff --git a/configuration.nix b/configuration.nix index 8ad95b0..f34f2e5 100644 --- a/configuration.nix +++ b/configuration.nix @@ -2,8 +2,8 @@ { imports = [ - ./dynamic.nix - ./dynamic-options.nix + ./modules/dynamic-overrides.nix + ./modules/dynamicism "${modulesPath}/profiles/qemu-guest.nix" ]; diff --git a/default.nix b/default.nix index ece52f0..023fac8 100644 --- a/default.nix +++ b/default.nix @@ -15,14 +15,41 @@ }); in dynix') qpkgs.validStdenvs; + evalNixos = import (pkgs.path + "/nixos"); + + doChange = { + option, + value, + }: + assert lib.isList option; + assert lib.all lib.isString option; + let + nixosBefore = evalNixos { + configuration = ./configuration.nix; + }; + dynamicBefore = nixosBefore.config.dynamicism.finalSettings; + + nixosAfter = evalNixos { + configuration = lib.mkMerge [ + nixosBefore + (lib.setAttrByPath option (lib.mkOverride (-999) value)) + ]; + }; + + dynamicAfter = nixosAfter.config.dynamicism.finalSettings; + in { + + }; + in dynix.overrideAttrs (final: prev: let self = final.finalPackage; in lib.recursiveUpdate prev { passthru = { inherit byStdenv; - nixos = import (pkgs.path + "/nixos") { + nixos = evalNixos { configuration = ./configuration.nix; }; nixos-vm = self.nixos.config.system.build.vm; + doChange = builtins.seq self.nixos.config.dynamicism doChange; }; }) diff --git a/dynamic-options.nix b/dynamic-options.nix deleted file mode 100644 index da3de76..0000000 --- a/dynamic-options.nix +++ /dev/null @@ -1,61 +0,0 @@ -{ pkgs, lib, config, ... }: -let - inherit (lib.modules) - mkIf - ; - inherit (lib.options) - mkOption - mkEnableOption - literalExpression - showOption - ; - t = lib.types; - cfg = config.dynamicism; - - settingsFormat = pkgs.formats.yaml { }; - - assertionFor = submodName: unitName: let - optName = [ "dynamicism" "for" submodName "systemd-services-updated" ]; - in { - assertion = config.systemd.units.${unitName}.enable or false; - message = "'${showOption optName}' specified non-existentant unit '${unitName}'"; - }; - - assertionsFor = - submodName: - submod: - lib.map (assertionFor submodName) submod.systemd-services-updated; -in -{ - options.dynamicism.for = mkOption { - type = t.attrsOf (t.submoduleWith { - modules = [ ./dynamic-submodule.nix ]; - shorthandOnlyDefinesConfig = false; - }); - default = { }; - }; - - options.dynamicism.finalSettings = mkOption { - type = t.attrsOf t.raw; - internal = true; - readOnly = true; - }; - - config.assertions = lib.foldlAttrs (acc: name: submod: let - next = lib.optionals submod.enable (assertionsFor name submod); - in acc ++ next) [ ] cfg.for; - - config.dynamicism.for = { - gotosocial = { - source-parameters = [ "services" "gotosocial" "settings" ]; - systemd-services-updated = [ "gotosocial.service" ]; - }; - }; - - # FIXME: this should be a fold. - config.dynamicism.finalSettings = lib.mapAttrs (name: submod: let - #optValue = lib.getAttrFromPath submod. - # FIXME: this should be a fold. - optValue = lib.getAttrFromPath submod.source-parameters config; - in optValue) cfg.for; -} diff --git a/dynamic.nix b/modules/dynamic-overrides.nix similarity index 54% rename from dynamic.nix rename to modules/dynamic-overrides.nix index b37d8da..1952e96 100644 --- a/dynamic.nix +++ b/modules/dynamic-overrides.nix @@ -12,4 +12,10 @@ lib.mkMerge [ }; }; } + { + services.gotosocial.settings.application-name = lib.mkOverride 99 "removed herobrine"; + } + { + services.gotosocial.settings.application-name = lib.mkOverride 98 "reädded herobrine"; + } ] diff --git a/modules/dynamicism/default.nix b/modules/dynamicism/default.nix new file mode 100644 index 0000000..0e769b5 --- /dev/null +++ b/modules/dynamicism/default.nix @@ -0,0 +1,73 @@ +{ pkgs, lib, config, options, ... }: +let + inherit (lib.modules) + mkIf + ; + inherit (lib.options) + mkOption + mkEnableOption + literalExpression + showOption + ; + t = lib.types; + cfg = config.dynamicism; + + settingsFormat = pkgs.formats.yaml { }; + + assertionFor = submodName: unitName: let + optName = [ "dynamicism" "for" submodName "systemd-services-updated" ]; + in { + assertion = config.systemd.units.${unitName}.enable or false; + message = "'${showOption optName}' specified non-existentant unit '${unitName}'"; + }; + + assertionsFor = + submodName: + submod: + lib.map (assertionFor submodName) submod.systemd-services-updated; + + 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; +in +{ + options.dynamicism = { + for = mkOption { + type = t.attrsOf (t.submoduleWith { + modules = [ ./submodule.nix ]; + shorthandOnlyDefinesConfig = false; + }); + default = { }; + }; + + finalSettings = mkOption { + type = t.attrsOf t.raw; + internal = true; + readOnly = true; + description = '' + Attrset of each `source-options` tree to their actual values. + ''; + }; + }; + + config.assertions = lib.foldlAttrs (acc: name: submod: let + next = lib.optionals submod.enable (assertionsFor name submod); + in acc ++ next) [ ] cfg.for; + + config.dynamicism.for = { + gotosocial = { + source-options = [ + "services.gotosocial.settings" + ]; + systemd-services-updated = [ + "gotosocial.service" + ]; + }; + }; + + config.dynamicism.finalSettings = lib.foldlAttrs (acc: name: { ... }@submod: let + next = finalSettingsFor submod; + in lib.recursiveUpdate acc next) { } config.dynamicism.for; +} diff --git a/dynamic-submodule.nix b/modules/dynamicism/submodule.nix similarity index 55% rename from dynamic-submodule.nix rename to modules/dynamicism/submodule.nix index d00b4d3..65039ae 100644 --- a/dynamic-submodule.nix +++ b/modules/dynamicism/submodule.nix @@ -1,6 +1,5 @@ { name, - pkgs, lib, config, ... @@ -15,16 +14,19 @@ let literalExpression ; t = lib.types; + + /** Either a list of strings, or a dotted string that will be split. */ + convenientAttrPath = t.coercedTo t.str (lib.splitString ".") (t.listOf t.str); in { options = { - enable = mkEnableOption "Dynamicism for ${name}"; + enable = mkEnableOption "Enable dynamicism for '${name}'"; - source-parameters = mkOption { - type = t.listOf t.str; - description = "An attrpath of the NixOS option this dynamicism uses"; + source-options = mkOption { + type = t.listOf convenientAttrPath; + description = "A list of attrpaths of the NixOS option the dynamicism for '${name}' uses"; example = literalExpression '' - [ "services" "gotosocial" "settings" ] + [ [ "services" "gotosocial" "settings" ] "services.nginx.settings" ] ''; }; diff --git a/src/args.rs b/src/args.rs index 3908454..cc2fa07 100644 --- a/src/args.rs +++ b/src/args.rs @@ -56,10 +56,15 @@ pub struct AppendCmd { pub value: Arc, } +#[derive(Debug, Clone, PartialEq, clap::Parser)] +pub struct DeltaCmd {} + #[derive(Debug, Clone, PartialEq, clap::Subcommand)] #[command(flatten_help = true)] pub enum Subcommand { Append(AppendCmd), + // TODO: rename + Delta(DeltaCmd), } #[derive(Debug, Clone, PartialEq, clap::Parser)] @@ -70,6 +75,7 @@ pub struct Args { #[arg(long, global(true), default_value = "auto")] pub color: ColorChoice, + // FIXME: default to /etc/configuration.nix, or something? #[arg(long, global(true), default_value = "./configuration.nix")] pub file: Arc, diff --git a/src/lib.rs b/src/lib.rs index 3743615..1956803 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,7 +34,7 @@ pub(crate) mod prelude { use prelude::*; pub mod args; -pub use args::{AppendCmd, Args}; +pub use args::{AppendCmd, Args, DeltaCmd}; mod color; pub use color::{_CLI_ENABLE_COLOR, SHOULD_COLOR}; pub mod line; @@ -49,6 +49,11 @@ use crate::source::SourceFile; pub const ASCII_WHITESPACE: &[char] = &['\t', '\n', '\x0C', '\r', ' ']; +#[tracing::instrument(level = "debug")] +pub fn do_delta(args: Arc, delta_args: DeltaCmd) -> Result<(), BoxDynError> { + todo!(); +} + #[tracing::instrument(level = "debug")] pub fn do_append(args: Arc, append_args: AppendCmd) -> Result<(), BoxDynError> { let filepath = Path::new(&args.file); diff --git a/src/main.rs b/src/main.rs index f77b9c0..ef00265 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,10 +26,13 @@ fn main_wrapped() -> Result<(), Box> { tracing::debug!("Parsed command-line arguments: {args:?}"); - use dynix::args::Subcommand::*; - match &args.subcommand { - Append(append_args) => dynix::do_append(args.clone(), append_args.clone())?, - }; + { + use dynix::args::Subcommand::*; + match &args.subcommand { + Append(append_args) => dynix::do_append(args.clone(), append_args.clone())?, + Delta(delta_args) => dynix::do_delta(args.clone(), delta_args.clone())?, + }; + } Ok(()) }