mirror of
https://github.com/nix-community/home-manager
synced 2024-11-26 21:19:45 +01:00
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
3 changed files with 67 additions and 19 deletions
|
@ -163,11 +163,12 @@ in
|
||||||
home.activation.linkGeneration = hm.dag.entryAfter ["writeBoundary"] (
|
home.activation.linkGeneration = hm.dag.entryAfter ["writeBoundary"] (
|
||||||
let
|
let
|
||||||
link = pkgs.writeShellScript "link" ''
|
link = pkgs.writeShellScript "link" ''
|
||||||
newGenFiles="$1"
|
rootPath="$1"
|
||||||
shift
|
newGenFiles="$2"
|
||||||
|
shift 2
|
||||||
for sourcePath in "$@" ; do
|
for sourcePath in "$@" ; do
|
||||||
relativePath="''${sourcePath#$newGenFiles/}"
|
relativePath="''${sourcePath#$newGenFiles/}"
|
||||||
targetPath="$HOME/$relativePath"
|
targetPath="$rootPath/$relativePath"
|
||||||
if [[ -e "$targetPath" && ! -L "$targetPath" && -n "$HOME_MANAGER_BACKUP_EXT" ]] ; then
|
if [[ -e "$targetPath" && ! -L "$targetPath" && -n "$HOME_MANAGER_BACKUP_EXT" ]] ; then
|
||||||
backup="$targetPath.$HOME_MANAGER_BACKUP_EXT"
|
backup="$targetPath.$HOME_MANAGER_BACKUP_EXT"
|
||||||
$DRY_RUN_CMD mv $VERBOSE_ARG "$targetPath" "$backup" || errorEcho "Moving '$targetPath' failed!"
|
$DRY_RUN_CMD mv $VERBOSE_ARG "$targetPath" "$backup" || errorEcho "Moving '$targetPath' failed!"
|
||||||
|
@ -184,10 +185,11 @@ in
|
||||||
# considered part of a Home Manager generation.
|
# considered part of a Home Manager generation.
|
||||||
homeFilePattern="$(readlink -e ${escapeShellArg builtins.storeDir})/*-home-manager-files/*"
|
homeFilePattern="$(readlink -e ${escapeShellArg builtins.storeDir})/*-home-manager-files/*"
|
||||||
|
|
||||||
newGenFiles="$1"
|
rootPath="$1"
|
||||||
shift 1
|
newGenFiles="$2"
|
||||||
|
shift 2
|
||||||
for relativePath in "$@" ; do
|
for relativePath in "$@" ; do
|
||||||
targetPath="$HOME/$relativePath"
|
targetPath="$rootPath/$relativePath"
|
||||||
if [[ -e "$newGenFiles/$relativePath" ]] ; then
|
if [[ -e "$newGenFiles/$relativePath" ]] ; then
|
||||||
$VERBOSE_ECHO "Checking $targetPath: exists"
|
$VERBOSE_ECHO "Checking $targetPath: exists"
|
||||||
elif [[ ! "$(readlink "$targetPath")" == $homeFilePattern ]] ; then
|
elif [[ ! "$(readlink "$targetPath")" == $homeFilePattern ]] ; then
|
||||||
|
@ -199,7 +201,8 @@ in
|
||||||
# Recursively delete empty parent directories.
|
# Recursively delete empty parent directories.
|
||||||
targetDir="$(dirname "$relativePath")"
|
targetDir="$(dirname "$relativePath")"
|
||||||
if [[ "$targetDir" != "." ]] ; then
|
if [[ "$targetDir" != "." ]] ; then
|
||||||
pushd "$HOME" > /dev/null
|
# TODO
|
||||||
|
# pushd "$HOME" > /dev/null
|
||||||
|
|
||||||
# Call rmdir with a relative path excluding $HOME.
|
# Call rmdir with a relative path excluding $HOME.
|
||||||
# Otherwise, it might try to delete $HOME and exit
|
# Otherwise, it might try to delete $HOME and exit
|
||||||
|
@ -208,7 +211,7 @@ in
|
||||||
-p --ignore-fail-on-non-empty \
|
-p --ignore-fail-on-non-empty \
|
||||||
"$targetDir"
|
"$targetDir"
|
||||||
|
|
||||||
popd > /dev/null
|
# popd > /dev/null
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
@ -216,12 +219,17 @@ in
|
||||||
in
|
in
|
||||||
''
|
''
|
||||||
function linkNewGen() {
|
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
|
local newGenFiles
|
||||||
newGenFiles="$(readlink -e "$newGenPath/home-files")"
|
newGenFiles="$(readlink -e "$newGenPath/home-files")"
|
||||||
find "$newGenFiles" \( -type f -or -type l \) \
|
find "$newGenFiles" \( -type f -or -type l \) \
|
||||||
-exec bash ${link} "$newGenFiles" {} +
|
-exec bash ${link} "$rootPath" "$newGenFiles" {} +
|
||||||
}
|
}
|
||||||
|
|
||||||
function cleanOldGen() {
|
function cleanOldGen() {
|
||||||
|
@ -229,17 +237,35 @@ in
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Cleaning up orphan links from $HOME"
|
echo "Cleaning up orphan links"
|
||||||
|
|
||||||
local newGenFiles oldGenFiles
|
local newGenFiles oldGenFiles
|
||||||
newGenFiles="$(readlink -e "$newGenPath/home-files")"
|
newGenFiles="$(readlink -e "$newGenPath/home-files")"
|
||||||
oldGenFiles="$(readlink -e "$oldGenPath/home-files")"
|
oldGenFiles="$(readlink -e "$oldGenPath/home-files")"
|
||||||
|
|
||||||
# Apply the cleanup script on each leaf in the old
|
# When transitioning from layout 0 to 1 we need to prefix all old
|
||||||
# generation. The find command below will print the
|
# paths with the home directory. Conversely, if we ever go from
|
||||||
# relative path of the entry.
|
# layout 1 to 0 we need to "subtract" the home directory from the
|
||||||
find "$oldGenFiles" '(' -type f -or -type l ')' -printf '%P\0' \
|
# old generation path, this is done by appending an "antiprefix" to
|
||||||
| xargs -0 bash ${cleanup} "$newGenFiles"
|
# 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
|
cleanOldGen
|
||||||
|
|
|
@ -622,6 +622,13 @@ in
|
||||||
mkdir $out/bin
|
mkdir $out/bin
|
||||||
ln -s $out/activate $out/bin/home-manager-generation
|
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 \
|
substituteInPlace $out/activate \
|
||||||
--subst-var-by GENERATION_DIR $out
|
--subst-var-by GENERATION_DIR $out
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,17 @@ function setupVars() {
|
||||||
local profilesPath="$nixStateDir/profiles/per-user/$USER"
|
local profilesPath="$nixStateDir/profiles/per-user/$USER"
|
||||||
local gcPath="$nixStateDir/gcroots/per-user/$USER"
|
local gcPath="$nixStateDir/gcroots/per-user/$USER"
|
||||||
|
|
||||||
genProfilePath="$profilesPath/home-manager"
|
declare -gr genProfilePath="$profilesPath/home-manager"
|
||||||
newGenPath="@GENERATION_DIR@";
|
declare -gr newGenPath="@GENERATION_DIR@";
|
||||||
newGenGcPath="$gcPath/current-home"
|
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
|
local greatestGenNum
|
||||||
greatestGenNum=$( \
|
greatestGenNum=$( \
|
||||||
|
@ -23,7 +31,14 @@ function setupVars() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -e $profilesPath/home-manager ]] ; then
|
if [[ -e $profilesPath/home-manager ]] ; then
|
||||||
|
declare -g oldGenPath oldGenLayoutVersion
|
||||||
oldGenPath="$(readlink -e "$profilesPath/home-manager")"
|
oldGenPath="$(readlink -e "$profilesPath/home-manager")"
|
||||||
|
if [[ -f $oldGenPath/version ]]; then
|
||||||
|
oldGenLayoutVersion=$(< "$oldGenPath/version")
|
||||||
|
else
|
||||||
|
oldGenLayoutVersion=0
|
||||||
|
fi
|
||||||
|
readonly oldGenPath oldGenLayoutVersion
|
||||||
fi
|
fi
|
||||||
|
|
||||||
$VERBOSE_ECHO "Sanity checking oldGenNum and oldGenPath"
|
$VERBOSE_ECHO "Sanity checking oldGenNum and oldGenPath"
|
||||||
|
|
Loading…
Reference in a new issue