Skip to content

Commit

Permalink
home-manager: handle missing per-user profiles directory
Browse files Browse the repository at this point in the history
Specifically, if the global per-user profiles path do not exist and we
cannot create it during the activation, then place our profile in the
Home Manager data directory. We prefer to use the global location,
though, since it makes it visible to `nix-collect-garbage`.

This is intended to improve compatibility with Nix version 2.14 and
later, which no longer creates the per-user directories.

Also, use the Home Manager data directory to manage the gcroot for the
current generation. It does not have to sit in the global per-user
gcroots directory since it should never be eligible for GC.
  • Loading branch information
rycee committed Mar 7, 2023
1 parent d6ce6d0 commit f7faeab
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 98 deletions.
72 changes: 39 additions & 33 deletions home-manager/home-manager
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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- \
Expand All @@ -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"
Expand All @@ -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/' \
)"

Expand Down Expand Up @@ -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..."
Expand All @@ -493,30 +504,26 @@ 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"
;;
*)
_i "Yay!"
exit 0
;;
esac

local deleteProfiles
read -r -n 1 \
-p "$(_i 'Remove all Home Manager generations?') [y/n] " \
deleteProfiles
echo
if [[ -e $HM_DATA_HOME ]]; then
$DRY_RUN_CMD rm $VERBOSE_ARG -r "$HM_DATA_HOME"
fi

case $deleteProfiles in
y|Y)
doRmAllGenerations
_i 'All generations are now eligible for garbage collection.'
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 'Leaving generations but they may still be garbage collected.'
_i "Yay!"
exit 0
;;
esac

Expand Down Expand Up @@ -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=()
Expand All @@ -601,6 +606,7 @@ COMMAND_ARGS=()
FLAKE_ARG=""

setHomeManagerNixPath
setHomeManagerPathVariables

while [[ $# -gt 0 ]]; do
opt="$1"
Expand Down
58 changes: 23 additions & 35 deletions home-manager/po/home-manager.pot
Original file line number Diff line number Diff line change
Expand Up @@ -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:23+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
Expand All @@ -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\"."
Expand All @@ -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:521
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:526
msgid "Home Manager is uninstalled but your home.nix is left untouched."
msgstr ""

#: home-manager/home-manager:673
#: home-manager/home-manager:691
msgid "%s: unknown option '%s'"
msgstr ""

#: home-manager/home-manager:674
#: home-manager/home-manager:692
msgid "Run '%s --help' for usage help"
msgstr ""

#: home-manager/home-manager:708
#: home-manager/home-manager:726
msgid "expire-generations expects one argument, got %d."
msgstr ""

#: home-manager/home-manager:730
#: home-manager/home-manager:748
msgid "Unknown command: %s"
msgstr ""

Expand Down
5 changes: 4 additions & 1 deletion modules/files.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions modules/home-environment.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand All @@ -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"
Expand Down
Loading

0 comments on commit f7faeab

Please sign in to comment.