{ config, lib, pkgs, home-manager, ... }: let cfg = config.me.install; inherit (lib) filter attrNames ; install_user_file = let constructors = { "overwrite" = install_user_file_overwrite; "symlink" = install_user_file_symlink; }; in stage: target: (constructors."${target.method}"."${stage}" target); old_install_user_file = let constructors = { "overwrite" = install_user_file_overwrite; "symlink" = install_user_file_symlink; }; in (target: (constructors."${target.method}" target)); install_user_file_overwrite = { "check" = (target: ""); "install" = ( target: let source = lib.strings.escapeShellArg "${target.source}"; destination = lib.strings.escapeShellArg "${target.target}"; mode = lib.strings.escapeShellArg "${target.mode}"; in '' $DRY_RUN_CMD install $VERBOSE_ARG -D --compare -m ${mode} ${source} ${destination} '' ); "uninstall" = (target: ""); }; install_user_file_symlink = { "check" = (target: ""); "install" = ( target: let source = lib.strings.escapeShellArg "${target.source}"; destination = lib.strings.escapeShellArg "${target.target}"; in '' $DRY_RUN_CMD ln $VERBOSE_ARG -s ${source} ${destination} '' ); "uninstall" = (target: ""); }; in { imports = [ ]; options.me.install = { user = lib.mkOption { type = lib.types.attrsOf ( lib.types.submodule ( { name, config, ... }: let username = name; in { options = { enable = lib.mkOption { type = lib.types.bool; default = true; defaultText = "enable"; example = lib.literalExpression false; description = "Whether we want to install files in this user's home directory."; }; file = lib.mkOption { type = lib.types.attrsOf ( lib.types.submodule ( { name, config, ... }: let path = name; in { options = { enable = lib.mkOption { type = lib.types.bool; default = true; defaultText = "enable"; example = lib.literalExpression false; description = "Whether we want to install this file in this user's home directory."; }; username = lib.mkOption { type = lib.types.str; defaultText = "username"; example = "root"; description = "The username for the user whose home directory will contain the file."; }; target = lib.mkOption { type = lib.types.str; defaultText = "target"; example = ".local/share/foo/bar.txt"; description = "The path where the file should be written."; }; method = lib.mkOption { type = lib.types.enum [ "symlink" "overwrite" # "bind_mount" TODO: for directories? ]; default = "symlink"; defaultText = "me.install.file.‹path›.method"; example = "overwrite"; description = "The way in which the file should be installed."; }; mode = lib.mkOption { type = lib.types.str; default = "0444"; defaultText = "me.install.file.‹path›.mode"; example = "0750"; description = "The read, write, execute permission flags."; }; source = lib.mkOption { type = lib.types.path; defaultText = "me.install.file.‹path›.source"; example = ./files/foo.txt; description = "The source file to install into the destination."; }; }; config = { username = lib.mkDefault username; target = lib.mkDefault path; }; } ) ); }; }; } ) ); }; }; config = let all_users = builtins.map (username: cfg.user."${username}") (attrNames cfg.user); enabled_users = filter (user: user.enable) all_users; all_file_targets = lib.flatten ( builtins.map (user: (builtins.map (path: user.file."${path}") (attrNames user.file))) enabled_users ); enabled_file_targets = filter (target: target.enable) all_file_targets; check_commands = builtins.map (install_user_file "check") enabled_file_targets; install_commands = builtins.map (install_user_file "install") enabled_file_targets; uninstall_commands = builtins.map (install_user_file "uninstall") enabled_file_targets; in { systemd.services.me-install-file = { enable = true; description = "me-install-file"; wantedBy = [ "multi-user.target" ]; wants = [ "multi-user.target" ]; after = [ "multi-user.target" ]; # path = with pkgs; [ # zfs # ]; unitConfig.DefaultDependencies = "no"; serviceConfig = { Type = "oneshot"; RemainAfterExit = "yes"; }; script = (lib.strings.concatStringsSep "\n" (check_commands ++ install_commands)); preStop = (lib.strings.concatStringsSep "\n" uninstall_commands); }; environment.etc."install_out".text = config.systemd.services.me-install-file.script; }; }