aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Helgesson <robert@rycee.net>2017-05-06 00:44:00 +0200
committerRobert Helgesson <robert@rycee.net>2017-05-06 13:01:01 +0200
commit88ec7145ba065b331bfe85149d9cfcf40ac8e648 (patch)
tree317a44b9d90d32326550d98bed92a1e4ee8cbf28
parent7e58b6bb356165254f45f068649138c16d676c39 (diff)
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
-rw-r--r--README.md71
-rw-r--r--modules/home-environment.nix31
2 files changed, 81 insertions, 21 deletions
diff --git a/README.md b/README.md
index b5ed92b35f1..0b946a98d2e 100644
--- a/README.md
+++ b/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:
-
-```
-$ ls -gG ~/.gitconfig
-lrwxrwxrwx 1 73 Jan 8 21:59 /home/rycee/.gitconfig -> /nix/store/pk7g12816avnxyhnkbdhqhnlzrw7fsga-home-manager-files/.gitconfig
-```
-
-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.
+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.
-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.
+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/
diff --git a/modules/home-environment.nix b/modules/home-environment.nix
index b270b1cc317..3b62b77f4e5 100644
--- a/modules/home-environment.nix
+++ b/modules/home-environment.nix
@@ -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" ''