Use a generation directory

Before we put only user files in the generation directory but that was
quite limiting. In particular, we lost track of the activation script.
This commit is contained in:
Robert Helgesson 2017-01-08 22:06:53 +01:00
parent 671805009c
commit 43fd747ba7
No known key found for this signature in database
GPG key ID: C3DB11069E65DC86
3 changed files with 89 additions and 44 deletions

View file

@ -17,16 +17,18 @@ function doRebuild() {
--argstr modulesPath "$HOME/.nixpkgs/home-manager/modules" \ --argstr modulesPath "$HOME/.nixpkgs/home-manager/modules" \
--argstr confPath "$confFile" \ --argstr confPath "$confFile" \
-A activation-script \ -A activation-script \
-o "$wrkdir/activate" -o "$wrkdir/generation"
"$wrkdir/activate/libexec/home-activate" "$wrkdir/generation/activate"
rm -rv "$wrkdir" rm -r "$wrkdir"
} }
function doListGens() { function doListGens() {
ls --color=yes -gG --sort time "/nix/var/nix/gcroots/per-user/$(whoami)" \ pushd "/nix/var/nix/profiles/per-user/$USER" > /dev/null
ls --color=yes -gG --sort time home-manager-*-link \
| cut -d' ' -f 4- | cut -d' ' -f 4-
popd > /dev/null
} }
function doListPackages() { function doListPackages() {

View file

@ -193,34 +193,26 @@ in
home.activation.linkages = home.activation.linkages =
let let
pak = pkgs.stdenv.mkDerivation {
name = "home-environment";
phases = [ "installPhase" ];
installPhase =
concatStringsSep "\n" (
mapAttrsToList (name: value:
"install -v -D -m${value.mode} ${value.source} $out/${value.target}"
) cfg.file
);
};
link = pkgs.writeText "link" '' link = pkgs.writeText "link" ''
newGenFiles="$1"
shift
for sourcePath in "$@" ; do for sourcePath in "$@" ; do
basePath="''${sourcePath#/nix/store/*-home-environment/}" relativePath="$(realpath --relative-to "$newGenFiles" "$sourcePath")"
targetPath="$HOME/$basePath" targetPath="$HOME/$relativePath"
mkdir -vp "$(dirname "$targetPath")" mkdir -vp "$(dirname "$targetPath")"
ln -vsf "$sourcePath" "$targetPath" ln -vsf "$sourcePath" "$targetPath"
done done
''; '';
cleanup = pkgs.writeText "cleanup" '' cleanup = pkgs.writeText "cleanup" ''
newGenFiles="$1"
oldGenFiles="$2"
shift 2
for sourcePath in "$@" ; do for sourcePath in "$@" ; do
basePath="''${sourcePath#/nix/store/*-home-environment/}" relativePath="$(realpath --relative-to "$oldGenFiles" "$sourcePath")"
targetPath="$HOME/$basePath" targetPath="$HOME/$relativePath"
echo -n "Checking $targetPath" echo -n "Checking $targetPath"
if [[ -f "${pak}/$basePath" ]] ; then if [[ -f "$newGenFiles/$relativePath" ]] ; then
echo " exists" echo " exists"
else else
echo " gone (deleting)" echo " gone (deleting)"
@ -232,34 +224,67 @@ in
in in
'' ''
function setupVars() { function setupVars() {
local profilesPath="/nix/var/nix/profiles/per-user/$(whoami)"
local gcPath="/nix/var/nix/gcroots/per-user/$(whoami)" local gcPath="/nix/var/nix/gcroots/per-user/$(whoami)"
local greatestGenNum=( \ local greatestGenNum=( \
$(find "$gcPath" -name 'home-*' \ $(find "$profilesPath" -name 'home-manager-*-link' \
| sed 's/^.*-\([0-9]*\)$/\1/' \ | sed 's/^.*-\([0-9]*\)-link$/\1/' \
| sort -rn \ | sort -rn \
| head -1) \ | head -1) \
) )
if [[ -n "$greatestGenNum" ]] ; then if [[ -n "$greatestGenNum" ]] ; then
oldGenNum=$greatestGenNum oldGenNum=$greatestGenNum
newGenNum=$(($oldGenNum + 1)) newGenNum=$(($oldGenNum + 1))
oldGenPath="$(readlink -e "$gcPath/home-$oldGenNum")"
else else
newGenNum=1 newGenNum=1
fi fi
newGenPath="${pak}";
newGenGcPath="$gcPath/home-$newGenNum" if [[ -e "$gcPath/current-home" ]] ; then
oldGenPath="$(readlink -e "$gcPath/current-home")"
fi
newGenPath="@GENERATION_DIR@";
newGenProfilePath="$profilesPath/home-manager-$newGenNum-link"
newGenGcPath="$gcPath/current-home"
} }
# Set some vars, these can be used later on as well. # Set some vars, these can be used later on as well.
setupVars setupVars
if [[ "$oldGenPath" != "$newGenPath" ]] ; then echo oldGenNum=$oldGenNum
ln -sfv "$newGenPath" "$newGenGcPath" echo newGenNum=$newGenNum
find "$newGenPath" -type f -print0 | xargs -0 bash ${link} echo oldGenPath=$oldGenPath
if [[ -n "$oldGenPath" ]] ; then echo newGenPath=$newGenPath
echo "Cleaning up orphan links from $HOME" echo newGenProfilePath=$newGenProfilePath
find "$oldGenPath" -type f -print0 | xargs -0 bash ${cleanup} echo newGenGcPath=$newGenGcPath
function linkNewGen() {
local newGenFiles
newGenFiles="$(readlink -e "$newGenPath/home-files")"
find "$newGenFiles" -type f -print0 \
| xargs -0 bash ${link} "$newGenFiles"
}
function cleanOldGen() {
if [[ -z "$oldGenPath" ]] ; then
return
fi fi
echo "Cleaning up orphan links from $HOME"
local newGenFiles oldGenFiles
newGenFiles="$(readlink -e "$newGenPath/home-files")"
oldGenFiles="$(readlink -e "$oldGenPath/home-files")"
find "$oldGenFiles" -type f -print0 \
| xargs -0 bash ${cleanup} "$newGenFiles" "$oldGenFiles"
}
if [[ "$oldGenPath" != "$newGenPath" ]] ; then
ln -Tsfv "$newGenPath" "$newGenProfilePath"
ln -Tsfv "$newGenPath" "$newGenGcPath"
linkNewGen
cleanOldGen
else else
echo "Same home files as previous generation ... doing nothing" echo "Same home files as previous generation ... doing nothing"
fi fi
@ -290,14 +315,32 @@ in
${activationCmds} ${activationCmds}
''; '';
home-files = pkgs.stdenv.mkDerivation {
name = "home-manager-files";
phases = [ "installPhase" ];
installPhase =
concatStringsSep "\n" (
mapAttrsToList (name: value:
"install -v -D -m${value.mode} ${value.source} $out/${value.target}"
) cfg.file
);
};
in in
pkgs.stdenv.mkDerivation { pkgs.stdenv.mkDerivation {
name = "activate-home"; name = "home-manager-generation";
phases = [ "installPhase" ]; phases = [ "installPhase" ];
installPhase = '' installPhase = ''
install -v -D -m755 ${sf} $out/libexec/home-activate install -v -D -m755 ${sf} $out/activate
substituteInPlace $out/activate \
--subst-var-by GENERATION_DIR $out
ln -vs ${home-files} $out/home-files
''; '';
}; };

View file

@ -64,13 +64,15 @@ in
home.activation.reloadSystemD = stringAfter ["linkages"] '' home.activation.reloadSystemD = stringAfter ["linkages"] ''
function systemdPostReload() { function systemdPostReload() {
local servicesDiffFile="$(mktemp)" local servicesDiffFile="$(mktemp)"
local oldUserServicePath="$oldGenPath/home-files/.config/systemd/user"
local newUserServicePath="$newGenPath/home-files/.config/systemd/user"
diff \ diff \
--new-line-format='+%L' \ --new-line-format='+%L' \
--old-line-format='-%L' \ --old-line-format='-%L' \
--unchanged-line-format=' %L' \ --unchanged-line-format=' %L' \
<(basename -a $(echo "$oldGenPath/.config/systemd/user/*.service") | sort) \ <(basename -a $(echo "$oldUserServicePath/*.service") | sort) \
<(basename -a $(echo "$newGenPath/.config/systemd/user/*.service") | sort) \ <(basename -a $(echo "$newUserServicePath/*.service") | sort) \
> $servicesDiffFile > $servicesDiffFile
local -a maybeRestart=( $(grep '^ ' $servicesDiffFile | cut -c2-) ) local -a maybeRestart=( $(grep '^ ' $servicesDiffFile | cut -c2-) )
@ -81,8 +83,8 @@ in
for f in ''${maybeRestart[@]} ; do for f in ''${maybeRestart[@]} ; do
if systemctl --quiet --user is-active "$f" \ if systemctl --quiet --user is-active "$f" \
&& ! cmp --quiet \ && ! cmp --quiet \
"$oldGenPath/.config/systemd/user/$f" \ "$oldUserServicePath/$f" \
"$newGenPath/.config/systemd/user/$f" ; then "$newUserServicePath/$f" ; then
echo "Adding '$f' to restart list"; echo "Adding '$f' to restart list";
toRestart+=("$f") toRestart+=("$f")
fi fi
@ -90,7 +92,7 @@ in
rm $servicesDiffFile rm $servicesDiffFile
sugg="" local sugg=""
if [[ -n "''${toRestart[@]}" ]] ; then if [[ -n "''${toRestart[@]}" ]] ; then
sugg="$sugg\nsystemctl --user restart ''${toRestart[@]}" sugg="$sugg\nsystemctl --user restart ''${toRestart[@]}"
@ -110,10 +112,8 @@ in
fi fi
} }
if [[ "$oldGenPath" != "$newGenPath" ]] ; then systemctl --user daemon-reload
systemctl --user daemon-reload systemdPostReload
systemdPostReload
fi
''; '';
}; };
} }