mirror of
https://github.com/nix-community/home-manager
synced 2024-11-27 05:29:46 +01:00
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
2 changed files with 81 additions and 21 deletions
71
README.md
71
README.md
|
@ -9,32 +9,23 @@ read the warning below.
|
||||||
Words of warning
|
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.
|
several user configurations but it may fail catastrophically for you.
|
||||||
So beware!
|
So beware!
|
||||||
|
|
||||||
To configure programs and services the Home Manager must write various
|
In some cases Home Manager cannot detect whether it will overwrite a
|
||||||
things to your home directory and possibly overwrite files you have
|
previous manual configuration. For example, the Gnome Terminal module
|
||||||
previously created. For example, if you use Home Manager to install
|
will write to your dconf store and cannot tell whether a configuration
|
||||||
and configure Git then your `~/.gitconfig` will be replaced by a link
|
that it is about to be overwrite was from a previous Home Manager
|
||||||
to a configuration generated by Home Manager:
|
generation or from manual configuration.
|
||||||
|
|
||||||
```
|
Home Manager targets [NixOS][] version 17.03 (the current stable
|
||||||
$ ls -gG ~/.gitconfig
|
version), it may or may not work on other Linux distributions and
|
||||||
lrwxrwxrwx 1 73 Jan 8 21:59 /home/rycee/.gitconfig -> /nix/store/pk7g12816avnxyhnkbdhqhnlzrw7fsga-home-manager-files/.gitconfig
|
NixOS versions.
|
||||||
```
|
|
||||||
|
|
||||||
So, if you already have a wonderful, painstakingly created
|
Also, the `home-manager` tool does not explicitly support rollbacks at
|
||||||
`~/.gitconfig` it will be gone. Home Manager will _not_ attempt to
|
the moment so if your home directory gets messed up you'll have to fix
|
||||||
backup the previous `~/.gitconfig` file.
|
it yourself (you can attempt to run the activation script for the
|
||||||
|
|
||||||
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
|
|
||||||
desired generation).
|
desired generation).
|
||||||
|
|
||||||
Now when your expectations have been built up and you are eager to try
|
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
|
which will create a `result` link to a directory containing an
|
||||||
activation script and the generated home directory files.
|
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/
|
[Nix]: https://nixos.org/nix/
|
||||||
[NixOS]: https://nixos.org/
|
[NixOS]: https://nixos.org/
|
||||||
[Nixpkgs]: https://nixos.org/nixpkgs/
|
[Nixpkgs]: https://nixos.org/nixpkgs/
|
||||||
|
|
|
@ -246,6 +246,37 @@ in
|
||||||
# script's "check" and the "write" phases.
|
# script's "check" and the "write" phases.
|
||||||
home.activation.writeBoundary = dagEntryAnywhere "";
|
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"] (
|
home.activation.linkGeneration = dagEntryAfter ["writeBoundary"] (
|
||||||
let
|
let
|
||||||
link = pkgs.writeText "link" ''
|
link = pkgs.writeText "link" ''
|
||||||
|
|
Loading…
Reference in a new issue