From 2b485f7f1d725af01c93fe03e355f6ea4d5dcf31 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sat, 9 Aug 2025 22:28:24 -0400 Subject: [PATCH] Support recursive. --- nix/configuration/configuration.nix | 5 +- .../util/install_files/default.nix | 132 +++++++++++++++--- 2 files changed, 115 insertions(+), 22 deletions(-) diff --git a/nix/configuration/configuration.nix b/nix/configuration/configuration.nix index 3b36f76..09a85e0 100644 --- a/nix/configuration/configuration.nix +++ b/nix/configuration/configuration.nix @@ -80,8 +80,9 @@ # me.install.user.file.talexander.".local/nixcfg" = ./README.org; me.install.user.talexander.file.".local/nixcfg" = { - source = ./flake.lock; - # method = "overwrite"; + source = ./roles; + recursive = true; + method = "overwrite"; }; nix.settings.experimental-features = [ diff --git a/nix/configuration/util/install_files/default.nix b/nix/configuration/util/install_files/default.nix index 341250a..0f9391c 100644 --- a/nix/configuration/util/install_files/default.nix +++ b/nix/configuration/util/install_files/default.nix @@ -51,20 +51,51 @@ let (if group != "" then "-g ${group}" else "") ]; in - '' - $DRY_RUN_CMD install $VERBOSE_ARG -D --compare ${flags} ${source} ${destination} - '' + if target.recursive then + [ + '' + find ${source} -type f -print0 | while read -r -d "" file; do + relative_path=$(realpath -s --relative-to ${source} "$file") + full_dest=${destination}/"$relative_path" + containing_directory=$(dirname "$full_dest") + if [ ! -e "$containing_directory" ]; then + $DRY_RUN_CMD install $VERBOSE_ARG -d "$containing_directory" + fi + $DRY_RUN_CMD install $VERBOSE_ARG -D --compare ${flags} "$file" "$full_dest" + done + '' + ] + else + [ + '' + $DRY_RUN_CMD install $VERBOSE_ARG -D --compare ${flags} ${source} ${destination} + '' + ] ); "uninstall" = ( target: let inherit (get_shell_values target) + source destination ; in - '' - $DRY_RUN_CMD echo rm -f ${destination} - '' + if target.recursive then + [ + '' + find ${source} -type f -print0 | while read -r -d "" file; do + relative_path=$(realpath -s --relative-to ${source} "$file") + full_dest=${destination}/"$relative_path" + $DRY_RUN_CMD echo rm -f "$full_dest" + done + '' + ] + else + [ + '' + $DRY_RUN_CMD echo rm -f ${destination} + '' + ] ); }; install_user_file_symlink = { @@ -75,6 +106,7 @@ let inherit (get_shell_values target) source destination + mode username group ; @@ -84,22 +116,59 @@ let group ] ); + flags = lib.strings.concatStringsSep " " [ + (if mode != "" then "-m ${mode}" else "") + (if username != "" then "-o ${username}" else "") + (if group != "" then "-g ${group}" else "") + ]; in - '' - $DRY_RUN_CMD ln $VERBOSE_ARG -s ${source} ${destination} - $DRY_RUN_CMD chown $VERBOSE_ARG -h ${owner} ${destination} - '' + if target.recursive then + [ + '' + find ${source} -type f -print0 | while read -r -d "" file; do + relative_path=$(realpath -s --relative-to ${source} "$file") + full_dest=${destination}/"$relative_path" + containing_directory=$(dirname "$full_dest") + if [ ! -e "$containing_directory" ]; then + $DRY_RUN_CMD install $VERBOSE_ARG -d ${flags} "$containing_directory" + fi + $DRY_RUN_CMD ln $VERBOSE_ARG -s "$file" "$full_dest" + $DRY_RUN_CMD chown $VERBOSE_ARG -h ${owner} "$full_dest" + done + '' + ] + else + [ + '' + $DRY_RUN_CMD ln $VERBOSE_ARG -s ${source} ${destination} + $DRY_RUN_CMD chown $VERBOSE_ARG -h ${owner} ${destination} + '' + ] ); "uninstall" = ( target: let inherit (get_shell_values target) + source destination ; in - '' - $DRY_RUN_CMD echo rm -f ${destination} - '' + if target.recursive then + [ + '' + find ${source} -type f -print0 | while read -r -d "" file; do + relative_path=$(realpath -s --relative-to ${source} "$file") + full_dest=${destination}/"$relative_path" + $DRY_RUN_CMD echo rm -f "$full_dest" + done + '' + ] + else + [ + '' + $DRY_RUN_CMD echo rm -f ${destination} + '' + ] ); }; in @@ -176,6 +245,13 @@ in example = ./files/foo.txt; description = "The source file to install into the destination."; }; + recursive = lib.mkOption { + type = lib.types.bool; + default = false; + defaultText = "recursive"; + example = lib.literalExpression false; + description = "Whether we want to recurse through the directory doing individual installs for each file."; + }; }; config = { @@ -201,9 +277,11 @@ in 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; + check_commands = lib.flatten (builtins.map (install_user_file "check") enabled_file_targets); + install_commands = lib.flatten (builtins.map (install_user_file "install") enabled_file_targets); + uninstall_commands = lib.flatten ( + builtins.map (install_user_file "uninstall") enabled_file_targets + ); in { systemd.services.me-install-file = { @@ -220,12 +298,26 @@ in Type = "oneshot"; RemainAfterExit = "yes"; }; - script = ( - lib.strings.concatStringsSep "\n" (filter (cmd: cmd != "") (check_commands ++ install_commands)) - ); - preStop = (lib.strings.concatStringsSep "\n" (filter (cmd: cmd != "") uninstall_commands)); + script = + '' + set -o pipefail + IFS=$'\n\t' + '' + + (lib.strings.concatStringsSep "\n" ( + [ + ] + ++ check_commands + ++ install_commands + )); + preStop = + '' + set -o pipefail + IFS=$'\n\t' + '' + + (lib.strings.concatStringsSep "\n" uninstall_commands); }; environment.etc."install_out".text = config.systemd.services.me-install-file.script; + environment.etc."uninstall_out".text = config.systemd.services.me-install-file.preStop; }; }