home-environment: prevent overwriting existing files
This should reduce the risk of overwriting an existing file in the user's home directory. A file will only be replaced if it is a link pointing to a home-manager tree inside the Nix store. If an existing file is detected an error is written indicating the file's path and the activation will terminate before any mutation occurs. Fixes #6
This commit is contained in:
parent
7e58b6bb35
commit
88ec7145ba
71
README.md
71
README.md
|
@ -9,32 +9,23 @@ read the warning below.
|
|||
Words of warning
|
||||
----------------
|
||||
|
||||
This project is in early development! I personally use it to manage
|
||||
This project is under development. I personally use it to manage
|
||||
several user configurations but it may fail catastrophically for you.
|
||||
So beware!
|
||||
|
||||
To configure programs and services the Home Manager must write various
|
||||
things to your home directory and possibly overwrite files you have
|
||||
previously created. For example, if you use Home Manager to install
|
||||
and configure Git then your `~/.gitconfig` will be replaced by a link
|
||||
to a configuration generated by Home Manager:
|
||||
In some cases Home Manager cannot detect whether it will overwrite a
|
||||
previous manual configuration. For example, the Gnome Terminal module
|
||||
will write to your dconf store and cannot tell whether a configuration
|
||||
that it is about to be overwrite was from a previous Home Manager
|
||||
generation or from manual configuration.
|
||||
|
||||
```
|
||||
$ ls -gG ~/.gitconfig
|
||||
lrwxrwxrwx 1 73 Jan 8 21:59 /home/rycee/.gitconfig -> /nix/store/pk7g12816avnxyhnkbdhqhnlzrw7fsga-home-manager-files/.gitconfig
|
||||
```
|
||||
Home Manager targets [NixOS][] version 17.03 (the current stable
|
||||
version), it may or may not work on other Linux distributions and
|
||||
NixOS versions.
|
||||
|
||||
So, if you already have a wonderful, painstakingly created
|
||||
`~/.gitconfig` it will be gone. Home Manager will _not_ attempt to
|
||||
backup the previous `~/.gitconfig` file.
|
||||
|
||||
Further, Home Manager targets [NixOS][] version 17.03 (the current
|
||||
stable version), it may or may not work on other Linux distributions
|
||||
and NixOS versions.
|
||||
|
||||
Finally, the `home-manager` tool does not explicitly support rollbacks
|
||||
at the moment so if your home directory gets messed up you'll have to
|
||||
fix it yourself (you can attempt to run the activation script for the
|
||||
Also, the `home-manager` tool does not explicitly support rollbacks at
|
||||
the moment so if your home directory gets messed up you'll have to fix
|
||||
it yourself (you can attempt to run the activation script for the
|
||||
desired generation).
|
||||
|
||||
Now when your expectations have been built up and you are eager to try
|
||||
|
@ -132,6 +123,44 @@ $ home-manager build
|
|||
which will create a `result` link to a directory containing an
|
||||
activation script and the generated home directory files.
|
||||
|
||||
File safety
|
||||
-----------
|
||||
|
||||
To configure programs and services the Home Manager must write various
|
||||
things to your home directory. To prevent overwriting any existing
|
||||
files when switching to a new generation, Home Manager will attempt to
|
||||
detect collisions between existing files and generated files. If any
|
||||
such collision is detected the activation will terminate before
|
||||
changing anything on your computer.
|
||||
|
||||
For example, suppose you have a wonderful, painstakingly created
|
||||
`~/.gitconfig` and add
|
||||
|
||||
```nix
|
||||
{
|
||||
# …
|
||||
|
||||
programs.git = {
|
||||
enable = true;
|
||||
userName = "Jane Doe";
|
||||
userEmail = "jane.doe@example.org";
|
||||
};
|
||||
|
||||
# …
|
||||
}
|
||||
```
|
||||
|
||||
to your configuration. Attempting to switch to the generation will
|
||||
then result in
|
||||
|
||||
```
|
||||
$ home-manager switch
|
||||
…
|
||||
Activating checkLinkTargets
|
||||
Existing file '/home/jdoe/.gitconfig' is in the way
|
||||
Please move the above files and try again
|
||||
```
|
||||
|
||||
[Nix]: https://nixos.org/nix/
|
||||
[NixOS]: https://nixos.org/
|
||||
[Nixpkgs]: https://nixos.org/nixpkgs/
|
||||
|
|
|
@ -246,6 +246,37 @@ in
|
|||
# script's "check" and the "write" phases.
|
||||
home.activation.writeBoundary = dagEntryAnywhere "";
|
||||
|
||||
# This verifies that the links we are about to create will not
|
||||
# overwrite an existing file.
|
||||
home.activation.checkLinkTargets = dagEntryBefore ["writeBoundary"] (
|
||||
let
|
||||
pattern = "-home-manager-files/";
|
||||
check = pkgs.writeText "check" ''
|
||||
newGenFiles="$1"
|
||||
shift
|
||||
for sourcePath in "$@" ; do
|
||||
relativePath="''${sourcePath#$newGenFiles/}"
|
||||
targetPath="$HOME/$relativePath"
|
||||
if [[ -e "$targetPath" \
|
||||
&& ! "$(readlink -e "$targetPath")" =~ "${pattern}" ]] ; then
|
||||
echo -e "Existing file '$targetPath' is in the way"
|
||||
collision=1
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ -v collision ]] ; then
|
||||
echo -e "Please move the above files and try again"
|
||||
exit 1
|
||||
fi
|
||||
'';
|
||||
in
|
||||
''
|
||||
newGenFiles="$(readlink -e "$newGenPath/home-files")"
|
||||
find "$newGenFiles" -type f -print0 -or -type l -print0 \
|
||||
| xargs -0 bash ${check} "$newGenFiles"
|
||||
''
|
||||
);
|
||||
|
||||
home.activation.linkGeneration = dagEntryAfter ["writeBoundary"] (
|
||||
let
|
||||
link = pkgs.writeText "link" ''
|
||||
|
|
Loading…
Reference in a new issue