mirror of
https://github.com/RGBCube/hjem
synced 2025-10-17 23:22:24 +00:00
Merge pull request #44 from feel-co/generator
feat: add config generator options
This commit is contained in:
commit
a1a2680af8
4 changed files with 100 additions and 16 deletions
|
@ -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
|
# This can be used to generate config files with various
|
||||||
# formats expected by different programs.
|
# formats expected by different programs.
|
||||||
".config/bar".source = pkgs.writeTextFile "file-foo" "file contents";
|
".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";
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
22
flake.nix
22
flake.nix
|
@ -28,7 +28,7 @@
|
||||||
packages = forAllSystems (system: {
|
packages = forAllSystems (system: {
|
||||||
# Expose the 'smfh' instance used by Hjem as a package in the Hjem flake
|
# 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.
|
# 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
|
checks = forAllSystems (system: let
|
||||||
|
@ -56,6 +56,8 @@
|
||||||
packages = attrValues {
|
packages = attrValues {
|
||||||
inherit
|
inherit
|
||||||
(pkgs)
|
(pkgs)
|
||||||
|
# formatter
|
||||||
|
alejandra
|
||||||
# cue validator
|
# cue validator
|
||||||
cue
|
cue
|
||||||
go
|
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 '{}'
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,11 +9,11 @@
|
||||||
...
|
...
|
||||||
}: let
|
}: let
|
||||||
inherit (lib.attrsets) mapAttrsToList;
|
inherit (lib.attrsets) mapAttrsToList;
|
||||||
inherit (lib.strings) concatMapStringsSep concatLines;
|
inherit (lib.strings) concatLines concatMapStringsSep;
|
||||||
inherit (lib.modules) mkIf mkDefault mkDerivedConfig;
|
inherit (lib.modules) mkDefault mkDerivedConfig mkIf mkMerge;
|
||||||
inherit (lib.options) mkOption literalExpression mkEnableOption;
|
inherit (lib.options) literalExpression mkEnableOption mkOption;
|
||||||
inherit (lib.strings) hasPrefix;
|
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;
|
inherit (builtins) isList;
|
||||||
|
|
||||||
cfg = config;
|
cfg = config;
|
||||||
|
@ -58,6 +58,32 @@
|
||||||
description = "Path of the source file or directory";
|
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 {
|
executable = mkOption {
|
||||||
type = bool;
|
type = bool;
|
||||||
default = false;
|
default = false;
|
||||||
|
@ -90,14 +116,30 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = {
|
config = let
|
||||||
target = mkDefault name;
|
generatedValue = config.generator config.value;
|
||||||
source = mkIf (config.text != null) (mkDerivedConfig options.text (text:
|
hasGenerator = config.generator != null;
|
||||||
pkgs.writeTextFile {
|
generatesDrv = options.source.type.check generatedValue;
|
||||||
inherit name text;
|
generatesStr = options.text.type.check generatedValue;
|
||||||
inherit (config) executable;
|
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 {
|
in {
|
||||||
imports = [
|
imports = [
|
||||||
|
|
|
@ -6,6 +6,7 @@ in
|
||||||
nodes = {
|
nodes = {
|
||||||
node1 = {
|
node1 = {
|
||||||
self,
|
self,
|
||||||
|
lib,
|
||||||
pkgs,
|
pkgs,
|
||||||
...
|
...
|
||||||
}: {
|
}: {
|
||||||
|
@ -22,8 +23,20 @@ in
|
||||||
alice = {
|
alice = {
|
||||||
enable = true;
|
enable = true;
|
||||||
packages = [pkgs.hello];
|
packages = [pkgs.hello];
|
||||||
files.".config/foo" = {
|
files = {
|
||||||
text = "Hello world!";
|
".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
|
# Test file created by Hjem
|
||||||
machine.succeed("[ -L ~alice/.config/foo ]")
|
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
|
# Test regular files, created by systemd-tmpfiles
|
||||||
machine.succeed("[ -d ~alice/user_tmpfiles_created ]")
|
machine.succeed("[ -d ~alice/user_tmpfiles_created ]")
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue