2023-08-08 10:19:01 +00:00
# Moves the existing profile from /nix or $XDG_STATE_HOME/home-manager to
# $XDG_STATE_HOME/nix to match changed behavior in Nix 2.14. See
# https://github.com/NixOS/nix/pull/5226.
function migrateProfile( ) {
declare -r stateHome = " ${ XDG_STATE_HOME :- $HOME /.local/state } "
declare -r userNixStateDir = " $stateHome /nix "
declare -r hmStateDir = " $stateHome /home-manager "
declare -r globalNixStateDir = " ${ NIX_STATE_DIR :- /nix/var/nix } "
declare -r globalProfilesDir = " $globalNixStateDir /profiles/per-user/ $USER "
if [ [ -e $globalProfilesDir /home-manager ] ] ; then
declare -r oldProfilesDir = " $globalProfilesDir "
elif [ [ -e $hmStateDir /profiles/home-manager ] ] ; then
declare -r oldProfilesDir = " $hmStateDir /profiles "
fi
declare -r newProfilesDir = " $userNixStateDir /profiles "
if [ [ -v oldProfilesDir && -e $newProfilesDir ] ] ; then
if [ [ ! -e $newProfilesDir /home-manager ] ] ; then
_i 'Migrating profile from %s to %s' " $oldProfilesDir " " $newProfilesDir "
for p in " $oldProfilesDir " /home-manager-*; do
declare name = " ${ p ##*/ } "
nix-store --realise " $p " --add-root " $newProfilesDir / $name " > /dev/null
done
cp -P " $oldProfilesDir /home-manager " " $newProfilesDir "
fi
rm " $oldProfilesDir /home-manager " " $oldProfilesDir " /home-manager-*
fi
}
2020-10-12 00:22:58 +00:00
function setupVars( ) {
2023-08-08 10:19:01 +00:00
declare -r stateHome = " ${ XDG_STATE_HOME :- $HOME /.local/state } "
declare -r userNixStateDir = " $stateHome /nix "
2024-06-04 18:23:39 +00:00
declare -gr hmStatePath = " $stateHome /home-manager "
declare -r hmGcrootsDir = " $hmStatePath /gcroots "
2023-08-08 10:19:01 +00:00
declare -r globalNixStateDir = " ${ NIX_STATE_DIR :- /nix/var/nix } "
declare -r globalProfilesDir = " $globalNixStateDir /profiles/per-user/ $USER "
declare -r globalGcrootsDir = " $globalNixStateDir /gcroots/per-user/ $USER "
# If the user Nix profiles path exists, then place the HM profile there.
# Otherwise, if the global Nix per-user state directory exists then use
# that. If neither exists, then we give up.
#
# shellcheck disable=2174
if [ [ -d $userNixStateDir /profiles ] ] ; then
declare -r profilesDir = " $userNixStateDir /profiles "
elif [ [ -d $globalProfilesDir ] ] ; then
declare -r profilesDir = " $globalProfilesDir "
else
_iError 'Could not find suitable profile directory, tried %s and %s' \
" $userNixStateDir /profiles " " $globalProfilesDir " >& 2
exit 1
fi
2020-10-12 00:22:58 +00:00
2024-06-04 18:23:39 +00:00
declare -gr hmDataPath = " ${ XDG_DATA_HOME :- $HOME /.local/share } /home-manager "
2023-08-08 10:19:01 +00:00
declare -gr genProfilePath = " $profilesDir /home-manager "
2021-11-04 16:42:44 +00:00
declare -gr newGenPath = "@GENERATION_DIR@" ;
2023-08-08 10:19:01 +00:00
declare -gr newGenGcPath = " $hmGcrootsDir /current-home "
declare -gr legacyGenGcPath = " $globalGcrootsDir /current-home "
2020-10-12 00:22:58 +00:00
2023-08-08 10:19:01 +00:00
declare greatestGenNum
2020-10-12 00:22:58 +00:00
greatestGenNum = $( \
nix-env --list-generations --profile " $genProfilePath " \
| tail -1 \
| sed -E 's/ *([[:digit:]]+) .*/\1/' )
if [ [ -n $greatestGenNum ] ] ; then
2021-11-04 16:42:44 +00:00
declare -gr oldGenNum = $greatestGenNum
declare -gr newGenNum = $(( oldGenNum + 1 ))
2020-10-12 00:22:58 +00:00
else
2021-11-04 16:42:44 +00:00
declare -gr newGenNum = 1
2020-10-12 00:22:58 +00:00
fi
2023-08-08 10:19:01 +00:00
if [ [ -e $genProfilePath ] ] ; then
declare -g oldGenPath
oldGenPath = " $( readlink -e " $genProfilePath " ) "
2020-10-12 00:22:58 +00:00
fi
2024-06-04 18:23:39 +00:00
_iVerbose "Sanity checking oldGenNum and oldGenPath"
2020-10-12 00:22:58 +00:00
if [ [ -v oldGenNum && ! -v oldGenPath
|| ! -v oldGenNum && -v oldGenPath ] ] ; then
2023-01-10 09:35:00 +00:00
_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 :- } " \
2023-08-08 10:19:01 +00:00
" $profilesDir " " $hmGcrootsDir "
2020-10-12 00:22:58 +00:00
exit 1
fi
}
2024-06-04 18:23:39 +00:00
# Helper used to list content of a `nix profile` profile.
function nixProfileList( ) {
# We attempt to use `--json` first (added in Nix 2.17). Otherwise attempt to
# parse the legacy output format.
{
nix profile list --json 2>/dev/null \
| jq -r --arg name " $1 " '.elements[].storePaths[] | select(endswith($name))'
} || {
nix profile list \
| { grep " $1 \$ " || test $? = 1; } \
| cut -d ' ' -f 4
}
}
# Helper used to remove a package from a Nix profile. Supports both `nix-env`
# and `nix profile`.
function nixProfileRemove( ) {
# We don't use `cfg.profileDirectory` here because it defaults to
# `/etc/profiles/per-user/<user>` which is constructed by NixOS or
# nix-darwin and won't require uninstalling `home-manager-path`.
if [ [ -e $HOME /.nix-profile/manifest.json \
|| -e ${ XDG_STATE_HOME :- $HOME /.local/state } /nix/profile/manifest.json ] ] ; then
nixProfileList " $1 " | xargs -rt $DRY_RUN_CMD nix profile remove $VERBOSE_ARG
else
if nix-env -q | grep -q " ^ $1 $" ; then
run --quiet nix-env -e " $1 "
fi
fi
}
2023-08-08 10:19:01 +00:00
function checkUsername( ) {
local expectedUser = " $1 "
if [ [ " $USER " != " $expectedUser " ] ] ; then
_iError 'Error: USER is set to "%s" but we expect "%s"' " $USER " " $expectedUser "
exit 1
fi
}
function checkHomeDirectory( ) {
local expectedHome = " $1 "
if ! [ [ $HOME -ef $expectedHome ] ] ; then
_iError 'Error: HOME is set to "%s" but we expect "%s"' " $HOME " " $expectedHome "
exit 1
fi
}
2024-06-04 18:23:39 +00:00
# Note, the VERBOSE_ECHO variable is deprecated and should not be used inside
# the Home Manager project. It is provided here for backwards compatibility.
2020-10-12 00:22:58 +00:00
if [ [ -v VERBOSE ] ] ; then
export VERBOSE_ECHO = echo
export VERBOSE_ARG = "--verbose"
2023-01-10 09:35:00 +00:00
export VERBOSE_RUN = ""
2020-10-12 00:22:58 +00:00
else
export VERBOSE_ECHO = true
export VERBOSE_ARG = ""
2023-01-10 09:35:00 +00:00
export VERBOSE_RUN = true
2020-10-12 00:22:58 +00:00
fi
2023-01-10 09:35:00 +00:00
_i "Starting Home Manager activation"
2020-10-12 00:22:58 +00:00
# Verify that we can connect to the Nix store and/or daemon. This will
# also create the necessary directories in profiles and gcroots.
2024-06-04 18:23:39 +00:00
_iVerbose "Sanity checking Nix"
nix-build --quiet --expr '{}' --no-out-link
2020-10-12 00:22:58 +00:00
2023-08-08 10:19:01 +00:00
# Also make sure that the Nix profiles path is created.
nix-env -q > /dev/null 2>& 1 || true
migrateProfile
2020-10-12 00:22:58 +00:00
setupVars
2024-06-04 18:23:39 +00:00
# Note, the DRY_RUN_CMD and DRY_RUN_NULL variables are deprecated and should not
# be used inside the Home Manager project. They are provided here for backwards
# compatibility.
2020-10-12 00:22:58 +00:00
if [ [ -v DRY_RUN ] ] ; then
2023-01-10 09:35:00 +00:00
_i "This is a dry run"
2020-10-12 00:22:58 +00:00
export DRY_RUN_CMD = echo
2023-08-08 10:19:01 +00:00
export DRY_RUN_NULL = /dev/stdout
2020-10-12 00:22:58 +00:00
else
2024-06-04 18:23:39 +00:00
_iVerbose "This is a live run"
2020-10-12 00:22:58 +00:00
export DRY_RUN_CMD = ""
2023-08-08 10:19:01 +00:00
export DRY_RUN_NULL = /dev/null
2020-10-12 00:22:58 +00:00
fi
if [ [ -v VERBOSE ] ] ; then
2023-01-10 09:35:00 +00:00
_i 'Using Nix version: %s' " $( nix-env --version) "
2020-10-12 00:22:58 +00:00
fi
2024-06-04 18:23:39 +00:00
_iVerbose "Activation variables:"
2020-10-12 00:22:58 +00:00
if [ [ -v oldGenNum ] ] ; then
2024-06-04 18:23:39 +00:00
verboseEcho " oldGenNum= $oldGenNum "
verboseEcho " oldGenPath= $oldGenPath "
2020-10-12 00:22:58 +00:00
else
2024-06-04 18:23:39 +00:00
verboseEcho " oldGenNum undefined (first run?)"
verboseEcho " oldGenPath undefined (first run?)"
2020-10-12 00:22:58 +00:00
fi
2024-06-04 18:23:39 +00:00
verboseEcho " newGenPath= $newGenPath "
verboseEcho " newGenNum= $newGenNum "
verboseEcho " genProfilePath= $genProfilePath "
verboseEcho " newGenGcPath= $newGenGcPath "
verboseEcho " legacyGenGcPath= $legacyGenGcPath "