1
Fork 0
mirror of https://github.com/RGBCube/hjem synced 2025-10-13 13:12:16 +00:00

Merge pull request #44 from feel-co/generator

feat: add config generator options
This commit is contained in:
éclairevoyant 2025-07-05 15:20:47 +00:00 committed by GitHub
commit a1a2680af8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 100 additions and 16 deletions

View file

@ -49,6 +49,15 @@ may use to manage individual users' homes by leveraging the module system.
# This can be used to generate config files with various
# formats expected by different programs.
".config/bar".source = pkgs.writeTextFile "file-foo" "file contents";
# You can also use generators to transform Nix values
".config/baz" = {
# Works with `pkgs.formats` too!
generator = lib.generators.toJSON { };
value = {
some = "contents";
};
};
};
};
}

View file

@ -28,7 +28,7 @@
packages = forAllSystems (system: {
# Expose the 'smfh' instance used by Hjem as a package in the Hjem flake
# outputs. This allows consuming the exact copy of smfh used by Hjem.
smfh = inputs.smfh.packages.${system}.smfh;
inherit (inputs.smfh.packages.${system}) smfh;
});
checks = forAllSystems (system: let
@ -56,6 +56,8 @@
packages = attrValues {
inherit
(pkgs)
# formatter
alejandra
# cue validator
cue
go
@ -64,6 +66,22 @@
};
});
formatter = forAllSystems (system: nixpkgs.legacyPackages.${system}.alejandra);
formatter = forAllSystems (
system: let
pkgs = nixpkgs.legacyPackages.${system};
in
pkgs.writeShellApplication {
name = "nix3-fmt-wrapper";
runtimeInputs = [
pkgs.alejandra
pkgs.fd
];
text = ''
fd "$@" -t f -e nix -x alejandra -q '{}'
'';
}
);
};
}

View file

@ -9,11 +9,11 @@
...
}: let
inherit (lib.attrsets) mapAttrsToList;
inherit (lib.strings) concatMapStringsSep concatLines;
inherit (lib.modules) mkIf mkDefault mkDerivedConfig;
inherit (lib.options) mkOption literalExpression mkEnableOption;
inherit (lib.strings) concatLines concatMapStringsSep;
inherit (lib.modules) mkDefault mkDerivedConfig mkIf mkMerge;
inherit (lib.options) literalExpression mkEnableOption mkOption;
inherit (lib.strings) hasPrefix;
inherit (lib.types) attrsOf bool lines listOf nullOr package path str submodule oneOf int;
inherit (lib.types) addCheck anything attrsOf bool either functionTo int lines listOf nullOr package path str submodule oneOf;
inherit (builtins) isList;
cfg = config;
@ -58,6 +58,32 @@
description = "Path of the source file or directory";
};
generator = lib.mkOption {
# functionTo doesn't actually check the return type, so do that ourselves
type = addCheck (nullOr (functionTo (either options.source.type options.text.type))) (x: let
generatedValue = x config.value;
generatesDrv = options.source.type.check generatedValue;
generatesStr = options.text.type.check generatedValue;
in
x != null -> (generatesDrv || generatesStr));
default = null;
description = ''
Function that when applied to `value` will create the `source` or `text` of the file.
Detection is automatic, as we check if the `generator` generates a derivation or a string after applying to `value`.
'';
example = literalExpression "lib.generators.toGitINI";
};
value = lib.mkOption {
type = nullOr (attrsOf anything);
default = null;
description = "Value passed to the `generator`.";
example = {
user.email = "me@example.com";
};
};
executable = mkOption {
type = bool;
default = false;
@ -90,14 +116,30 @@
};
};
config = {
target = mkDefault name;
source = mkIf (config.text != null) (mkDerivedConfig options.text (text:
pkgs.writeTextFile {
inherit name text;
inherit (config) executable;
}));
};
config = let
generatedValue = config.generator config.value;
hasGenerator = config.generator != null;
generatesDrv = options.source.type.check generatedValue;
generatesStr = options.text.type.check generatedValue;
in
mkMerge [
{
target = mkDefault name;
source = mkIf (config.text != null) (mkDerivedConfig options.text (text:
pkgs.writeTextFile {
inherit name text;
inherit (config) executable;
}));
}
(lib.mkIf (hasGenerator && generatesDrv) {
source = mkDefault generatedValue;
})
(lib.mkIf (hasGenerator && generatesStr) {
text = mkDefault generatedValue;
})
];
});
in {
imports = [

View file

@ -6,6 +6,7 @@ in
nodes = {
node1 = {
self,
lib,
pkgs,
...
}: {
@ -22,8 +23,20 @@ in
alice = {
enable = true;
packages = [pkgs.hello];
files.".config/foo" = {
text = "Hello world!";
files = {
".config/foo" = {
text = "Hello world!";
};
".config/bar.json" = {
generator = lib.generators.toJSON {};
value = {bar = true;};
};
".config/baz.toml" = {
generator = (pkgs.formats.toml {}).generate "baz.toml";
value = {baz = true;};
};
};
};
};
@ -47,6 +60,8 @@ in
# Test file created by Hjem
machine.succeed("[ -L ~alice/.config/foo ]")
machine.succeed("[ -L ~alice/.config/bar.json ]")
machine.succeed("[ -L ~alice/.config/baz.toml ]")
# Test regular files, created by systemd-tmpfiles
machine.succeed("[ -d ~alice/user_tmpfiles_created ]")