diff --git a/home-manager/home-manager b/home-manager/home-manager index 390ab47d6..d758653d5 100644 --- a/home-manager/home-manager +++ b/home-manager/home-manager @@ -19,7 +19,7 @@ function removeByName() { } function setNixProfileCommands() { - if [[ -e ~/.nix-profile/manifest.json ]] ; then + if [[ -e $HOME/.nix-profile/manifest.json ]] ; then LIST_OUTPATH_CMD="nix profile list" REMOVE_CMD="removeByName" else @@ -93,6 +93,23 @@ function setHomeManagerNixPath() { done } +# Sets some useful Home Manager related paths as global read-only variables. +function setHomeManagerPathVariables() { + declare -r nixStateDir="${NIX_STATE_DIR:-/nix/var/nix}" + declare -r globalProfilesDir="$nixStateDir/profiles/per-user/$USER" + declare -r globalGcrootsDir="$nixStateDir/gcroots/per-user/$USER" + + declare -gr HM_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}/home-manager" + declare -gr HM_STATE_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/home-manager" + declare -gr HM_GCROOT_LEGACY_PATH="$globalGcrootsDir/current-home" + + if [[ -d "$globalProfilesDir" ]]; then + declare -gr HM_PROFILE_DIR="$globalProfilesDir" + else + declare -gr HM_PROFILE_DIR="$HM_STATE_DIR/profiles" + fi +} + function setFlakeAttribute() { local configFlake="${XDG_CONFIG_HOME:-$HOME/.config}/nixpkgs/flake.nix" if [[ -z $FLAKE_ARG && ! -v HOME_MANAGER_CONFIG && -e "$configFlake" ]]; then @@ -339,7 +356,7 @@ function doListGens() { color="always" fi - pushd "$NIX_STATE_DIR/profiles/per-user/$USER" > /dev/null + pushd "$HM_PROFILE_DIR" > /dev/null # shellcheck disable=2012 ls --color=$color -gG --time-style=long-iso --sort time home-manager-*-link \ | cut -d' ' -f 4- \ @@ -352,7 +369,7 @@ function doListGens() { function doRmGenerations() { setVerboseAndDryRun - pushd "$NIX_STATE_DIR/profiles/per-user/$USER" > /dev/null + pushd "$HM_PROFILE_DIR" > /dev/null for generationId in "$@"; do local linkName="home-manager-$generationId-link" @@ -370,17 +387,10 @@ function doRmGenerations() { popd > /dev/null } -function doRmAllGenerations() { - $DRY_RUN_CMD rm $VERBOSE_ARG \ - "$NIX_STATE_DIR/profiles/per-user/$USER/home-manager"* -} - function doExpireGenerations() { - local profileDir="$NIX_STATE_DIR/profiles/per-user/$USER" - local generations generations="$( \ - find "$profileDir" -name 'home-manager-*-link' -not -newermt "$1" \ + find "$HM_PROFILE_DIR" -name 'home-manager-*-link' -not -newermt "$1" \ | sed 's/^.*-\([0-9]*\)-link$/\1/' \ )" @@ -482,6 +492,7 @@ function doUninstall() { read -r -n 1 -p "$(_i 'Really uninstall Home Manager?') [y/n] " confirmation echo + # shellcheck disable=2086 case $confirmation in y|Y) _i "Switching to empty Home Manager configuration..." @@ -493,10 +504,22 @@ function doUninstall() { doSwitch $DRY_RUN_CMD $REMOVE_CMD home-manager-path || true rm "$HOME_MANAGER_CONFIG" - $DRY_RUN_CMD rm $VERBOSE_ARG -r \ - "${XDG_DATA_HOME:-$HOME/.local/share}/home-manager" - $DRY_RUN_CMD rm $VERBOSE_ARG \ - "$NIX_STATE_DIR/gcroots/per-user/$USER/current-home" + + if [[ -e $HM_DATA_HOME ]]; then + $DRY_RUN_CMD rm $VERBOSE_ARG -r "$HM_DATA_HOME" + fi + + if [[ -e $HM_PROFILE_DIR ]]; then + $DRY_RUN_CMD rm $VERBOSE_ARG "$HM_PROFILE_DIR/home-manager"* + fi + + if [[ -e $HM_GCROOT_LEGACY_PATH ]]; then + $DRY_RUN_CMD rm $VERBOSE_ARG "$HM_GCROOT_LEGACY_PATH" + fi + + if [[ -e $HM_STATE_DIR ]]; then + $DRY_RUN_CMD rm $VERBOSE_ARG -r "$HM_STATE_DIR" + fi ;; *) _i "Yay!" @@ -504,22 +527,6 @@ function doUninstall() { ;; esac - local deleteProfiles - read -r -n 1 \ - -p "$(_i 'Remove all Home Manager generations?') [y/n] " \ - deleteProfiles - echo - - case $deleteProfiles in - y|Y) - doRmAllGenerations - _i 'All generations are now eligible for garbage collection.' - ;; - *) - _i 'Leaving generations but they may still be garbage collected.' - ;; - esac - _i "Home Manager is uninstalled but your home.nix is left untouched." } @@ -591,8 +598,6 @@ function doHelp() { echo " uninstall Remove Home Manager" } -readonly NIX_STATE_DIR="${NIX_STATE_DIR:-/nix/var/nix}" - EXTRA_NIX_PATH=() HOME_MANAGER_CONFIG_ATTRIBUTE="" PASSTHROUGH_OPTS=() @@ -601,6 +606,7 @@ COMMAND_ARGS=() FLAKE_ARG="" setHomeManagerNixPath +setHomeManagerPathVariables while [[ $# -gt 0 ]]; do opt="$1" diff --git a/home-manager/po/home-manager.pot b/home-manager/po/home-manager.pot index 003a344b0..a6a77c7f3 100644 --- a/home-manager/po/home-manager.pot +++ b/home-manager/po/home-manager.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Home Manager\n" "Report-Msgid-Bugs-To: https://github.com/nix-community/home-manager/issues\n" -"POT-Creation-Date: 2022-03-26 15:08+0100\n" +"POT-Creation-Date: 2023-03-07 23:36+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -26,15 +26,15 @@ msgstr "" msgid "No configuration file found. Please create one at %s" msgstr "" -#: home-manager/home-manager:122 +#: home-manager/home-manager:146 msgid "Can't inspect options of a flake configuration" msgstr "" -#: home-manager/home-manager:162 +#: home-manager/home-manager:185 msgid "Can't instantiate a flake configuration" msgstr "" -#: home-manager/home-manager:237 +#: home-manager/home-manager:258 msgid "" "There is %d unread and relevant news item.\n" "Read it by running the command \"%s news\"." @@ -44,92 +44,80 @@ msgid_plural "" msgstr[0] "" msgstr[1] "" -#: home-manager/home-manager:251 +#: home-manager/home-manager:272 msgid "Unknown \"news.display\" setting \"%s\"." msgstr "" -#: home-manager/home-manager:258 +#: home-manager/home-manager:279 #, sh-format msgid "Please set the $EDITOR environment variable" msgstr "" -#: home-manager/home-manager:273 +#: home-manager/home-manager:294 msgid "Cannot run build in read-only directory" msgstr "" -#: home-manager/home-manager:355 +#: home-manager/home-manager:378 msgid "No generation with ID %s" msgstr "" -#: home-manager/home-manager:357 +#: home-manager/home-manager:380 msgid "Cannot remove the current generation %s" msgstr "" -#: home-manager/home-manager:359 +#: home-manager/home-manager:382 msgid "Removing generation %s" msgstr "" -#: home-manager/home-manager:385 +#: home-manager/home-manager:401 msgid "No generations to expire" msgstr "" -#: home-manager/home-manager:396 +#: home-manager/home-manager:412 msgid "No home-manager packages seem to be installed." msgstr "" -#: home-manager/home-manager:453 +#: home-manager/home-manager:469 msgid "Unknown argument %s" msgstr "" -#: home-manager/home-manager:469 +#: home-manager/home-manager:485 msgid "This will remove Home Manager from your system." msgstr "" -#: home-manager/home-manager:472 +#: home-manager/home-manager:488 msgid "This is a dry run, nothing will actually be uninstalled." msgstr "" -#: home-manager/home-manager:476 +#: home-manager/home-manager:492 msgid "Really uninstall Home Manager?" msgstr "" -#: home-manager/home-manager:481 +#: home-manager/home-manager:498 msgid "Switching to empty Home Manager configuration..." msgstr "" -#: home-manager/home-manager:493 +#: home-manager/home-manager:525 msgid "Yay!" msgstr "" -#: home-manager/home-manager:500 -msgid "Remove all Home Manager generations?" -msgstr "" - -#: home-manager/home-manager:507 -msgid "All generations are now eligible for garbage collection." -msgstr "" - -#: home-manager/home-manager:510 -msgid "Leaving generations but they may still be garbage collected." -msgstr "" - -#: home-manager/home-manager:514 +#: home-manager/home-manager:530 msgid "Home Manager is uninstalled but your home.nix is left untouched." msgstr "" -#: home-manager/home-manager:673 +#: home-manager/home-manager:695 msgid "%s: unknown option '%s'" msgstr "" -#: home-manager/home-manager:674 +#: home-manager/home-manager:696 msgid "Run '%s --help' for usage help" msgstr "" -#: home-manager/home-manager:708 +#: home-manager/home-manager:730 msgid "expire-generations expects one argument, got %d." msgstr "" -#: home-manager/home-manager:730 +#: home-manager/home-manager:752 msgid "Unknown command: %s" msgstr "" diff --git a/modules/files.nix b/modules/files.nix index 0f4207fe8..4f64a9f86 100644 --- a/modules/files.nix +++ b/modules/files.nix @@ -272,7 +272,10 @@ in $DRY_RUN_CMD nix-env $VERBOSE_ARG --profile "$genProfilePath" --set "$newGenPath" fi - $DRY_RUN_CMD ln -Tsf $VERBOSE_ARG "$newGenPath" "$newGenGcPath" + $DRY_RUN_CMD nix-store --realise "$newGenPath" --add-root "$newGenGcPath" > "$DRY_RUN_NULL" + if [[ -e "$legacyGenGcPath" ]]; then + $DRY_RUN_CMD rm $VERBOSE_ARG "$legacyGenGcPath" + fi else _i "No change so reusing latest profile generation %s" "$oldGenNum" fi diff --git a/modules/home-environment.nix b/modules/home-environment.nix index 098e10b21..aca3723ef 100644 --- a/modules/home-environment.nix +++ b/modules/home-environment.nix @@ -584,7 +584,7 @@ in if config.submoduleSupport.externalPackageInstall then '' - if [[ -e "$nixProfilePath"/manifest.json ]] ; then + if [[ -e $HOME/.nix-profile/manifest.json ]] ; then nix profile list \ | { grep 'home-manager-path$' || test $? = 1; } \ | cut -d ' ' -f 4 \ @@ -608,7 +608,7 @@ in $DRY_RUN_CMD $oldNix profile install $1 } - if [[ -e "$nixProfilePath"/manifest.json ]] ; then + if [[ -e $HOME/.nix-profile/manifest.json ]] ; then INSTALL_CMD="nix profile install" INSTALL_CMD_ACTUAL="nixReplaceProfile" LIST_CMD="nix profile list" diff --git a/modules/lib-bash/activation-init.sh b/modules/lib-bash/activation-init.sh index 3b0f5320a..e719352dc 100644 --- a/modules/lib-bash/activation-init.sh +++ b/modules/lib-bash/activation-init.sh @@ -1,14 +1,60 @@ +# Moves the existing profile from /nix to ~ to match changed behavior in Nix +# 2.14. See https://github.com/NixOS/nix/pull/5226. +# +# Note, this function is intentionally unused for now. There remains a few open +# questions about backwards compatibility and support from +# `nix-collect-garbage`. +function migrateProfile() { + declare -r stateHome="${XDG_STATE_HOME:-$HOME/.local/state}" + declare -r hmStateDir="$stateHome/home-manager" + declare -r nixStateDir="${NIX_STATE_DIR:-/nix/var/nix}" + + declare -r newProfilesDir="$hmStateDir/profiles" + declare -r oldProfilesDir="$nixStateDir/profiles/per-user/$USER" + + if [[ ! -d $newProfilesDir ]]; then + _i 'Migrating profiles from %s to %s' "$oldProfilesDir" "$newProfilesDir" + mkdir -p "$newProfilesDir" + for p in "$oldProfilesDir"/home-manager-*; do + declare -r name="${p##*/}" + nix-store --realise "$p" --add-root "$newProfilesDir/$name" > /dev/null + done + cp -P "$oldProfilesDir/home-manager" "$newProfilesDir" + fi + + rm "$oldProfilesDir"/home-manager-* +} + function setupVars() { - local nixStateDir="${NIX_STATE_DIR:-/nix/var/nix}" - local profilesPath="$nixStateDir/profiles/per-user/$USER" - local gcPath="$nixStateDir/gcroots/per-user/$USER" + declare -r nixStateDir="${NIX_STATE_DIR:-/nix/var/nix}" + declare -r globalProfilesDir="$nixStateDir/profiles/per-user/$USER" + declare -r globalGcrootsDir="$nixStateDir/gcroots/per-user/$USER" - declare -gr nixProfilePath="$profilesPath/profile" - declare -gr genProfilePath="$profilesPath/home-manager" + declare -r stateHome="${XDG_STATE_HOME:-$HOME/.local/state}" + declare -r hmStateDir="$stateHome/home-manager" + declare -r hmGcrootsDir="$hmStateDir/gcroots" + + # If the global profiles path exists or we can create it, then place the HM + # profile there. Otherwise place it in the HM data directory. We prefer to + # use the global location since it makes it visible to + # `nix-collect-garbage`. + # + # In the future we may perform a one-shot migration to the new location. + # + # shellcheck disable=2174 + if [[ -d "$globalProfilesDir" ]] || mkdir -m 0755 -p "$globalProfilesDir"; then + declare -r hmProfilesDir="$globalProfilesDir" + else + declare -r hmProfilesDir="$hmStateDir/profiles" + mkdir -m 0755 -p "$hmProfilesDir" + fi + + declare -gr genProfilePath="$hmProfilesDir/home-manager" declare -gr newGenPath="@GENERATION_DIR@"; - declare -gr newGenGcPath="$gcPath/current-home" + declare -gr newGenGcPath="$hmGcrootsDir/current-home" + declare -gr legacyGenGcPath="$globalGcrootsDir/current-home" - local greatestGenNum + declare greatestGenNum greatestGenNum=$( \ nix-env --list-generations --profile "$genProfilePath" \ | tail -1 \ @@ -21,9 +67,9 @@ function setupVars() { declare -gr newGenNum=1 fi - if [[ -e $profilesPath/home-manager ]] ; then - oldGenPath="$(readlink -e "$profilesPath/home-manager")" - declare -gr oldGenPath + if [[ -e $genProfilePath ]] ; then + declare -g oldGenPath + oldGenPath="$(readlink -e "$genProfilePath")" fi $VERBOSE_RUN _i "Sanity checking oldGenNum and oldGenPath" @@ -31,7 +77,7 @@ function setupVars() { || ! -v oldGenNum && -v oldGenPath ]]; then _i $'The previous generation number and path are in conflict! These\nmust be either both empty or both set but are now set to\n\n \'%s\' and \'%s\'\n\nIf you don\'t mind losing previous profile generations then\nthe easiest solution is probably to run\n\n rm %s/home-manager*\n rm %s/current-home\n\nand trying home-manager switch again. Good luck!' \ "${oldGenNum:-}" "${oldGenPath:-}" \ - "$profilesPath" "$gcPath" + "$hmProfilesDir" "$hmGcrootsDir" exit 1 fi } @@ -58,9 +104,12 @@ setupVars if [[ -v DRY_RUN ]] ; then _i "This is a dry run" export DRY_RUN_CMD=echo + export DRY_RUN_NULL=/dev/stdout else $VERBOSE_RUN _i "This is a live run" export DRY_RUN_CMD="" + export DRY_RUN_NULL=/dev/null + fi if [[ -v VERBOSE ]]; then @@ -77,5 +126,6 @@ else fi $VERBOSE_ECHO " newGenPath=$newGenPath" $VERBOSE_ECHO " newGenNum=$newGenNum" -$VERBOSE_ECHO " newGenGcPath=$newGenGcPath" $VERBOSE_ECHO " genProfilePath=$genProfilePath" +$VERBOSE_ECHO " newGenGcPath=$newGenGcPath" +$VERBOSE_ECHO " legacyGenGcPath=$legacyGenGcPath" diff --git a/modules/po/hm-modules.pot b/modules/po/hm-modules.pot index 7bff64af4..8bbcc221b 100644 --- a/modules/po/hm-modules.pot +++ b/modules/po/hm-modules.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Home Manager Modules\n" "Report-Msgid-Bugs-To: https://github.com/nix-community/home-manager/issues\n" -"POT-Creation-Date: 2022-03-26 15:08+0100\n" +"POT-Creation-Date: 2023-03-07 23:36+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,23 +17,23 @@ msgstr "" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" -#: modules/files.nix:233 +#: modules/files.nix:234 msgid "Creating home file links in %s" msgstr "" -#: modules/files.nix:246 +#: modules/files.nix:247 msgid "Cleaning up orphan links from %s" msgstr "" -#: modules/files.nix:262 +#: modules/files.nix:263 msgid "Creating profile generation %s" msgstr "" -#: modules/files.nix:276 +#: modules/files.nix:280 msgid "No change so reusing latest profile generation %s" msgstr "" -#: modules/home-environment.nix:607 +#: modules/home-environment.nix:625 msgid "" "Oops, Nix failed to install your new Home Manager profile!\n" "\n" @@ -49,15 +49,19 @@ msgid "" "Then try activating your Home Manager configuration again." msgstr "" -#: modules/home-environment.nix:639 +#: modules/home-environment.nix:658 msgid "Activating %s" msgstr "" -#: modules/lib-bash/activation-init.sh:31 +#: modules/lib-bash/activation-init.sh:18 +msgid "Migrating profiles from %s to %s" +msgstr "" + +#: modules/lib-bash/activation-init.sh:77 msgid "Sanity checking oldGenNum and oldGenPath" msgstr "" -#: modules/lib-bash/activation-init.sh:34 +#: modules/lib-bash/activation-init.sh:80 msgid "" "The previous generation number and path are in conflict! These\n" "must be either both empty or both set but are now set to\n" @@ -73,26 +77,26 @@ msgid "" "and trying home-manager switch again. Good luck!" msgstr "" -#: modules/lib-bash/activation-init.sh:51 +#: modules/lib-bash/activation-init.sh:97 msgid "Starting Home Manager activation" msgstr "" -#: modules/lib-bash/activation-init.sh:55 +#: modules/lib-bash/activation-init.sh:101 msgid "Sanity checking Nix" msgstr "" -#: modules/lib-bash/activation-init.sh:61 +#: modules/lib-bash/activation-init.sh:107 msgid "This is a dry run" msgstr "" -#: modules/lib-bash/activation-init.sh:64 +#: modules/lib-bash/activation-init.sh:111 msgid "This is a live run" msgstr "" -#: modules/lib-bash/activation-init.sh:69 +#: modules/lib-bash/activation-init.sh:118 msgid "Using Nix version: %s" msgstr "" -#: modules/lib-bash/activation-init.sh:72 +#: modules/lib-bash/activation-init.sh:121 msgid "Activation variables:" msgstr ""