files: add preliminary support for full paths
This represents the first step in migrating `home.file` to support arbitrary absolute paths. This is to allow Home Manager to manage files anywhere, provided the user has sufficient privileges. For example, with this change the configuration home.file."test/one".text = "foo"; home.file."/test/two".text = "foo"; will result in the files "$HOME/test/one" and "/test/two", respectively. Note, a relative file name will still be relative `$HOME`. To allow a reasonable transition between the old and new path handling we introduce the notion of "generation directory layout version". The version is simply a file `version` within the generation directory containing a number indicating the version number. The version 0 (also implied if the version file is missing) indicates the legacy layout where managed file paths always are relative `$HOME`. Version 1 indicates the new layout where managed file paths are relative `/`.
This commit is contained in:
parent
47ad3655ec
commit
de0070c4cf
|
@ -163,11 +163,12 @@ in
|
|||
home.activation.linkGeneration = hm.dag.entryAfter ["writeBoundary"] (
|
||||
let
|
||||
link = pkgs.writeShellScript "link" ''
|
||||
newGenFiles="$1"
|
||||
shift
|
||||
rootPath="$1"
|
||||
newGenFiles="$2"
|
||||
shift 2
|
||||
for sourcePath in "$@" ; do
|
||||
relativePath="''${sourcePath#$newGenFiles/}"
|
||||
targetPath="$HOME/$relativePath"
|
||||
targetPath="$rootPath/$relativePath"
|
||||
if [[ -e "$targetPath" && ! -L "$targetPath" && -n "$HOME_MANAGER_BACKUP_EXT" ]] ; then
|
||||
backup="$targetPath.$HOME_MANAGER_BACKUP_EXT"
|
||||
$DRY_RUN_CMD mv $VERBOSE_ARG "$targetPath" "$backup" || errorEcho "Moving '$targetPath' failed!"
|
||||
|
@ -184,10 +185,11 @@ in
|
|||
# considered part of a Home Manager generation.
|
||||
homeFilePattern="$(readlink -e ${escapeShellArg builtins.storeDir})/*-home-manager-files/*"
|
||||
|
||||
newGenFiles="$1"
|
||||
shift 1
|
||||
rootPath="$1"
|
||||
newGenFiles="$2"
|
||||
shift 2
|
||||
for relativePath in "$@" ; do
|
||||
targetPath="$HOME/$relativePath"
|
||||
targetPath="$rootPath/$relativePath"
|
||||
if [[ -e "$newGenFiles/$relativePath" ]] ; then
|
||||
$VERBOSE_ECHO "Checking $targetPath: exists"
|
||||
elif [[ ! "$(readlink "$targetPath")" == $homeFilePattern ]] ; then
|
||||
|
@ -199,7 +201,8 @@ in
|
|||
# Recursively delete empty parent directories.
|
||||
targetDir="$(dirname "$relativePath")"
|
||||
if [[ "$targetDir" != "." ]] ; then
|
||||
pushd "$HOME" > /dev/null
|
||||
# TODO
|
||||
# pushd "$HOME" > /dev/null
|
||||
|
||||
# Call rmdir with a relative path excluding $HOME.
|
||||
# Otherwise, it might try to delete $HOME and exit
|
||||
|
@ -208,7 +211,7 @@ in
|
|||
-p --ignore-fail-on-non-empty \
|
||||
"$targetDir"
|
||||
|
||||
popd > /dev/null
|
||||
# popd > /dev/null
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
@ -216,12 +219,17 @@ in
|
|||
in
|
||||
''
|
||||
function linkNewGen() {
|
||||
echo "Creating home file links in $HOME"
|
||||
echo "Creating home file links"
|
||||
|
||||
local rootPath=
|
||||
if [[ $newGenLayoutVersion -eq 0 ]] ; then
|
||||
rootPath="$HOME"
|
||||
fi
|
||||
|
||||
local newGenFiles
|
||||
newGenFiles="$(readlink -e "$newGenPath/home-files")"
|
||||
find "$newGenFiles" \( -type f -or -type l \) \
|
||||
-exec bash ${link} "$newGenFiles" {} +
|
||||
-exec bash ${link} "$rootPath" "$newGenFiles" {} +
|
||||
}
|
||||
|
||||
function cleanOldGen() {
|
||||
|
@ -229,17 +237,35 @@ in
|
|||
return
|
||||
fi
|
||||
|
||||
echo "Cleaning up orphan links from $HOME"
|
||||
echo "Cleaning up orphan links"
|
||||
|
||||
local newGenFiles oldGenFiles
|
||||
newGenFiles="$(readlink -e "$newGenPath/home-files")"
|
||||
oldGenFiles="$(readlink -e "$oldGenPath/home-files")"
|
||||
|
||||
# Apply the cleanup script on each leaf in the old
|
||||
# generation. The find command below will print the
|
||||
# relative path of the entry.
|
||||
find "$oldGenFiles" '(' -type f -or -type l ')' -printf '%P\0' \
|
||||
| xargs -0 bash ${cleanup} "$newGenFiles"
|
||||
# When transitioning from layout 0 to 1 we need to prefix all old
|
||||
# paths with the home directory. Conversely, if we ever go from
|
||||
# layout 1 to 0 we need to "subtract" the home directory from the
|
||||
# old generation path, this is done by appending an "antiprefix" to
|
||||
# the layout 1 paths.
|
||||
local prefix= antiprefix=
|
||||
if [[ $oldGenLayoutVersion -eq 0 && $newGenLayoutVersion -ge 1 ]] ; then
|
||||
prefix="''${HOME#/}/"
|
||||
elif [[ $oldGenLayoutVersion -ge 1 && $newGenLayoutVersion -eq 0 ]] ; then
|
||||
antiprefix="/$HOME"
|
||||
fi
|
||||
|
||||
local rootPath=
|
||||
if [[ $newGenLayoutVersion -eq 0 ]] ; then
|
||||
rootPath="$HOME"
|
||||
fi
|
||||
|
||||
$VERBOSE_ECHO "Orphan link cleanup uses prefix=$prefix antiprefix=$antiprefix rootPath=$rootPath"
|
||||
|
||||
# Apply the cleanup script on each leaf in the old generation. The
|
||||
# find command below will print the relative path of the entry.
|
||||
find "$oldGenFiles$antiprefix" '(' -type f -or -type l ')' -printf "$prefix%P\0" \
|
||||
| xargs -0 bash ${cleanup} "$rootPath" "$newGenFiles"
|
||||
}
|
||||
|
||||
cleanOldGen
|
||||
|
|
|
@ -622,6 +622,13 @@ in
|
|||
mkdir $out/bin
|
||||
ln -s $out/activate $out/bin/home-manager-generation
|
||||
|
||||
# The generation directory layout version.
|
||||
#
|
||||
# - Version 0 (also implied when file is missing) means
|
||||
# "legacy layout".
|
||||
# - Version 1 adds full home file paths.
|
||||
echo 0 > $out/version
|
||||
|
||||
substituteInPlace $out/activate \
|
||||
--subst-var-by GENERATION_DIR $out
|
||||
|
||||
|
|
|
@ -5,9 +5,17 @@ function setupVars() {
|
|||
local profilesPath="$nixStateDir/profiles/per-user/$USER"
|
||||
local gcPath="$nixStateDir/gcroots/per-user/$USER"
|
||||
|
||||
genProfilePath="$profilesPath/home-manager"
|
||||
newGenPath="@GENERATION_DIR@";
|
||||
newGenGcPath="$gcPath/current-home"
|
||||
declare -gr genProfilePath="$profilesPath/home-manager"
|
||||
declare -gr newGenPath="@GENERATION_DIR@";
|
||||
declare -gr newGenGcPath="$gcPath/current-home"
|
||||
|
||||
declare -g newGenLayoutVersion
|
||||
if [[ -f $newGenPath/version ]]; then
|
||||
newGenLayoutVersion=$(< "$newGenPath/version")
|
||||
else
|
||||
newGenLayoutVersion=0
|
||||
fi
|
||||
readonly newGenLayoutVersion
|
||||
|
||||
local greatestGenNum
|
||||
greatestGenNum=$( \
|
||||
|
@ -23,7 +31,14 @@ function setupVars() {
|
|||
fi
|
||||
|
||||
if [[ -e $profilesPath/home-manager ]] ; then
|
||||
declare -g oldGenPath oldGenLayoutVersion
|
||||
oldGenPath="$(readlink -e "$profilesPath/home-manager")"
|
||||
if [[ -f $oldGenPath/version ]]; then
|
||||
oldGenLayoutVersion=$(< "$oldGenPath/version")
|
||||
else
|
||||
oldGenLayoutVersion=0
|
||||
fi
|
||||
readonly oldGenPath oldGenLayoutVersion
|
||||
fi
|
||||
|
||||
$VERBOSE_ECHO "Sanity checking oldGenNum and oldGenPath"
|
||||
|
|
Loading…
Reference in a new issue