{ config, lib, pkgs, home-manager, ... }: let inherit (lib) attrNames filter flatten ; makeFileOption = prefix: lib.mkOption { type = lib.types.attrsOf ( lib.types.submodule ( { name, config, ... }: { options = { enable = lib.mkOption { type = lib.types.bool; default = true; defaultText = "${prefix}.‹path›.enable"; example = false; description = "Whether we want to install this file."; }; method = lib.mkOption { type = lib.types.enum [ "symlink" "overwrite" "initialize" # "bind_mount" TODO: for directories? ]; default = "symlink"; defaultText = "${prefix}.‹path›.method"; example = "overwrite"; description = "The way in which the file should be installed."; }; mode = lib.mkOption { type = lib.types.str; default = "0444"; defaultText = "${prefix}.‹path›.mode"; example = "0750"; description = "The read, write, execute permission flags."; }; source = lib.mkOption { type = lib.types.path; defaultText = "${prefix}.‹path›.source"; example = ./files/foo.txt; description = "The source file to install into the destination."; }; target = lib.mkOption { type = lib.types.str; defaultText = "${prefix}.‹path›.target"; example = ".local/share/foo/bar.txt"; description = "The path where the file should be written."; }; }; config = { target = lib.mkDefault name; }; } ) ); defaultText = "${prefix}.‹path›"; default = { }; example = lib.literalExpression '' { ".config/foo/bar.txt" = { source = ./files/bar.txt }; } ''; }; in { imports = [ ]; options.me.install = { user = lib.mkOption { type = lib.types.attrsOf ( lib.types.submodule ( { name, config, ... }: { options = { enable = lib.mkOption { type = lib.types.bool; default = true; defaultText = "me.install.user.‹username›.enable"; example = false; description = "Whether we want to install files in this user's home directory."; }; target_username = lib.mkOption { type = lib.types.str; defaultText = "me.install.file.‹username›.target_username"; example = "root"; description = "The username for the user whose home directory will contain the file."; }; file = makeFileOption "me.install.user.‹username›.file"; }; config = { target_username = lib.mkDefault name; }; } ) ); defaultText = "me.install.user.‹username›"; default = { }; # TODO: example }; # TODO: Global option owned by root? # file = makeFileOption "me.install.file"; }; config = let cfg = config.me.install; active_install_users = filter (username: cfg.user."${username}".enable) (attrNames cfg.user); install_commands = flatten ( builtins.map ( username: let active_install_file_targets = filter (target: cfg.user."${username}".file."${target}".enable) ( attrNames cfg.user."${username}".file ); in builtins.map ( target: let target_config = cfg.user."${username}".file."${target}"; source = lib.strings.escapeShellArg "${target_config.source}"; destination = lib.strings.escapeShellArg "${target_config.target}"; mode = lib.strings.escapeShellArg "${target_config.mode}"; escaped_username = lib.strings.escapeShellArg "${username}"; in '' $DRY_RUN_CMD install $VERBOSE_ARG -D --compare -o ${escaped_username} -m ${mode} ${source} ${destination} '' ) active_install_file_targets ) active_install_users ); in lib.mkMerge [ (lib.mkIf (install_commands != [ ]) ({ systemd.services.me-install-file = { enable = true; description = "me-install-file"; wantedBy = [ "multi-user.target" ]; wants = [ "multi-user.target" ]; after = [ "multi-user.target" ]; unitConfig.DefaultDependencies = "no"; serviceConfig = { Type = "oneshot"; RemainAfterExit = "yes"; }; script = (lib.strings.concatStringsSep "\n" install_commands); }; })) ]; }