diff --git a/home-manager/home-manager b/home-manager/home-manager index bb52ec72f..e72151d28 100644 --- a/home-manager/home-manager +++ b/home-manager/home-manager @@ -1132,6 +1132,11 @@ while [[ $# -gt 0 ]]; do EXTRA_NIX_PATH+=("$1") shift ;; + -B) + [[ -v 1 && $1 != -* ]] || errMissingOptArg "$opt" + export HOME_MANAGER_BACKUP_COMMAND="$1" + shift + ;; -b) [[ -v 1 && $1 != -* ]] || errMissingOptArg "$opt" export HOME_MANAGER_BACKUP_EXT="$1" diff --git a/modules/files.nix b/modules/files.nix index ba45665b9..db63fced8 100644 --- a/modules/files.nix +++ b/modules/files.nix @@ -146,13 +146,18 @@ in for sourcePath in "$@" ; do relativePath="''${sourcePath#$newGenFiles/}" targetPath="$HOME/$relativePath" - if [[ -e "$targetPath" && ! -L "$targetPath" && -n "$HOME_MANAGER_BACKUP_EXT" ]] ; then - # The target exists, back it up - backup="$targetPath.$HOME_MANAGER_BACKUP_EXT" - if [[ -e "$backup" && -n "$HOME_MANAGER_BACKUP_OVERWRITE" ]]; then - run rm $VERBOSE_ARG "$backup" + if [[ -e "$targetPath" && ! -L "$targetPath" ]] ; then + if [[ -n "$HOME_MANAGER_BACKUP_COMMAND" ]] ; then + verboseEcho "Running $HOME_MANAGER_BACKUP_COMMAND $targetPath." + run $HOME_MANAGER_BACKUP_COMMAND "$targetPath" || errorEcho "Running `$HOME_MANAGER_BACKUP_COMMAND` on '$targetPath' failed." + elif [[ -n "$HOME_MANAGER_BACKUP_EXT" ]] ; then + # The target exists, back it up + backup="$targetPath.$HOME_MANAGER_BACKUP_EXT" + if [[ -e "$backup" && -n "$HOME_MANAGER_BACKUP_OVERWRITE" ]]; then + run rm $VERBOSE_ARG "$backup" + fi + run mv $VERBOSE_ARG "$targetPath" "$backup" || errorEcho "Moving '$targetPath' failed!" fi - run mv $VERBOSE_ARG "$targetPath" "$backup" || errorEcho "Moving '$targetPath' failed!" fi if [[ -e "$targetPath" && ! -L "$targetPath" ]] && cmp -s "$sourcePath" "$targetPath" ; then diff --git a/modules/files/check-link-targets.sh b/modules/files/check-link-targets.sh index 21ffba0f3..c16c8b0de 100644 --- a/modules/files/check-link-targets.sh +++ b/modules/files/check-link-targets.sh @@ -30,6 +30,9 @@ for sourcePath in "$@" ; do if cmp -s "$sourcePath" "$targetPath"; then # First compare the files' content. If they're equal, we're fine. warnEcho "Existing file '$targetPath' is in the way of '$sourcePath', will be skipped since they are the same" + elif [[ ! -L "$targetPath" && -n "$HOME_MANAGER_BACKUP_COMMAND" ]] ; then + # Next, try to run the custom backup command. Assume this always succeeds. + verboseEcho "Existing file '$targetPath' exists and differs from '$sourcePath'. `$HOME_MANAGER_BACKUP_COMMAND` will be used to backup the file." elif [[ ! -L "$targetPath" && -n "$HOME_MANAGER_BACKUP_EXT" ]] ; then # Next, try to move the file to a backup location if configured and possible backup="$targetPath.$HOME_MANAGER_BACKUP_EXT" @@ -49,12 +52,13 @@ done if [[ ${#collisionErrors[@]} -gt 0 ]] ; then errorEcho "Please do one of the following: -- Move or remove the files below and try again. - In standalone mode, use 'home-manager switch -b backup' to back up"\ " files automatically. -- When used as a NixOS or nix-darwin module, set"\ -" 'home-manager.backupFileExtension'"\ -" to, for example, 'backup' and rebuild. +- When used as a NixOS or nix-darwin module, set either + - 'home-manager.backupFileExtension', or + - 'home-manager.backupCommand', + to move the file to a new location in the same directory, or run a"\ +" custom command. - Set 'force = true' on the related file options to forcefully overwrite"\ " the files below. eg. 'xdg.configFile.\"mimeapps.list\".force = true'" diff --git a/nix-darwin/default.nix b/nix-darwin/default.nix index 971c2769a..49415ef7a 100644 --- a/nix-darwin/default.nix +++ b/nix-darwin/default.nix @@ -28,6 +28,9 @@ in ${lib.optionalString ( cfg.backupFileExtension != null ) "export HOME_MANAGER_BACKUP_EXT=${lib.escapeShellArg cfg.backupFileExtension}"} + ${lib.optionalString ( + cfg.backupCommand != null + ) "export HOME_MANAGER_BACKUP_COMMAND=${lib.escapeShellArg cfg.backupCommand}"} ${lib.optionalString cfg.overwriteBackup "export HOME_MANAGER_BACKUP_OVERWRITE=1"} ${lib.optionalString cfg.verbose "export VERBOSE=1"} exec ${usercfg.home.activationPackage}/activate --driver-version ${driverVersion} >&2 diff --git a/nixos/common.nix b/nixos/common.nix index f2dec70b5..dd2b3f10a 100644 --- a/nixos/common.nix +++ b/nixos/common.nix @@ -81,6 +81,16 @@ in argument in Home Manager. This disables the Home Manager options {option}`nixpkgs.*`''; + backupCommand = mkOption { + type = types.nullOr (types.either types.str types.path); + default = null; + example = lib.literalExpression "''${pkgs.trash-cli}/bin/trash"; + description = '' + On activation run this command on each existing file + rather than exiting with an error. + ''; + }; + backupFileExtension = mkOption { type = types.nullOr types.str; default = null; diff --git a/nixos/default.nix b/nixos/default.nix index 91378683b..f14813e38 100644 --- a/nixos/default.nix +++ b/nixos/default.nix @@ -12,7 +12,9 @@ let serviceEnvironment = lib.mkMerge [ (mkIf cfg.verbose { VERBOSE = "1"; }) - + (mkIf (cfg.backupCommand != null) { + HOME_MANAGER_BACKUP_COMMAND = cfg.backupCommand; + }) (mkIf (cfg.backupFileExtension != null) { HOME_MANAGER_BACKUP_EXT = cfg.backupFileExtension; })