1

Modules/Impermanence: Convert newhome/newroot to shell scripts

This commit is contained in:
2025-07-20 19:33:40 +02:00
parent 786c8120c5
commit 866a43b360
2 changed files with 63 additions and 45 deletions

View File

@ -133,33 +133,6 @@ in {
ns = "nix shell nixpkgs#"; ns = "nix shell nixpkgs#";
} }
# Impermanence
# TODO: Those should be a single script to be called with the search path (/ or /home/christoph or just .)
(let
fdIgnoreHome = "fdignore-home";
fdIgnoreRoot = "fdignore-root";
cmdHome = "sudo fd --one-file-system --base-directory /home/${username} --type f --hidden --ignore-file /home/${username}/.config/impermanence/${fdIgnoreHome}";
cmdRoot = "sudo fd --one-file-system --base-directory / --type f --hidden --ignore-file /home/${username}/.config/impermanence/${fdIgnoreRoot}";
fzfHome = "sudo fzf --preview 'bat --color=always --theme=ansi --style=numbers --line-range=:100 {}'";
fzfRoot = "sudo fzf --preview 'bat --color=always --theme=ansi --style=numbers --line-range=:100 /{}'";
mvHome = "mkdir -p /persist/home/${username}/$(dirname {}) && mv {} /persist/home/${username}/$(dirname {})";
mvRoot = "sudo mkdir -p /persist/$(dirname {}) && sudo mv {} /persist/$(dirname {})";
header = "--header 'Press CTRL-R to reload, CTRL-M to move, CTRL-F to ignore file'";
ignoreFileHome = "echo '{}' >> /home/${username}/.config/impermanence/${fdIgnoreHome}";
ignoreFileRoot = "echo '{}' >> /home/${username}/.config/impermanence/${fdIgnoreRoot}";
bindHome = "--bind 'ctrl-r:reload(${cmdHome}),ctrl-m:execute(${mvHome}),ctrl-f:execute(${ignoreFileHome})'";
bindRoot = "--bind 'ctrl-r:reload(${cmdRoot}),ctrl-m:execute(${mvRoot}),ctrl-f:execute(${ignoreFileRoot})'";
in {
newhome = ''${cmdHome} | ${fzfHome} ${header} ${bindHome}'';
newroot = ''${cmdRoot} | ${fzfRoot} ${header} ${bindRoot}'';
})
# Abbrs only available if package is installed # Abbrs only available if package is installed
(abbrify pkgs.duf { (abbrify pkgs.duf {
@ -211,6 +184,8 @@ in {
# grep = rg; # grep = rg;
}) })
(lib.optionalAttrs config.modules.rmpc.enable {r = "rcmp";})
(abbrify pkgs.rsync rec { (abbrify pkgs.rsync rec {
rsync = "rsync -ahv --inplace --partial --info=progress2"; rsync = "rsync -ahv --inplace --partial --info=progress2";
copy = rsync; copy = rsync;

View File

@ -38,15 +38,17 @@ in {
# group = config.users.users.${user}.group; # group = config.users.users.${user}.group;
# }; # };
}; };
mkRDir = mkDir "root";
mkRFile = mkFile "root";
mkUDir = mkDir "${username}";
mkUFile = mkFile "${username}";
in in
lib.mkIf impermanence.enable { lib.mkIf impermanence.enable {
environment.persistence."/persist" = let # TODO: Create options to allow host-specific impermanence setup
mkRDir = mkDir "root"; # inside the respective modules
mkRFile = mkFile "root"; environment.persistence."/persist" = {
mkUDir = mkDir "${username}"; hideMounts = false; # Sets x-gvfs-hide option
mkUFile = mkFile "${username}";
in {
hideMounts = true; # Sets x-gvfs-hide option
files = [ files = [
(mkRFile "/etc/adjtime" m644) (mkRFile "/etc/adjtime" m644)
@ -155,14 +157,57 @@ in {
}; };
}; };
# NOTE: This is REQUIRED for HM activation! Otherwise the home directory won't be writable! # Add some helper scripts to identify files that might need persisting
environment.systemPackages = let
base = {
"root" = "/";
"home" = "/home/${username}";
};
ignore = {
"root" = "/home/${username}/.config/impermanence/fdignore-root";
"home" = "/home/${username}/.config/impermanence/fdignore-home";
};
move = {
"root" = "/persist/$(dirname {})";
"home" = "/persist/home/${username}/$(dirname {})";
};
mkHeader = "Press CTRL-R to reload, CTRL-M to move, CTRL-I to ignore file";
mkPreview = mode: "bat --color=always --theme=ansi --style=numbers --line-range=:100 ${base.${mode}}/{}";
mkReload = mode: "sudo fd --one-file-system --type f --hidden --base-directory ${base.${mode}} --ignore-file ${ignore.${mode}}";
mkIgnore = mode: "echo '{}' >> ${ignore.${mode}}";
mkMove = mode: "sudo mkdir -p ${move.${mode}} && sudo mv {} ${move.${mode}}";
mkScript = mode: ''
sudo ${mkReload mode} | \
sudo fzf \
--header "${mkHeader}" \
--preview "${mkPreview mode}" \
--bind "ctrl-r:reload:(${mkReload mode})" \
--bind "ctrl-i:execute:(${mkIgnore mode})" \
--bind "ctrl-m:execute:(${mkMove mode})"
'';
newroot = pkgs.writeShellScriptBin "newroot" (mkScript "root");
newhome = pkgs.writeShellScriptBin "newhome" (mkScript "home");
in [
newroot
newhome
];
# NOTE: This is REQUIRED for HM activation!
# Otherwise the home directory won't be writable!
systemd.services."impermanence-fix-home-ownership" = let systemd.services."impermanence-fix-home-ownership" = let
homeDir = "/home/${username}"; homeDir = "/home/${username}";
homeUser = builtins.toString config.users.users.${username}.uid; homeUser =
homeGroup = builtins.toString config.users.groups.${config.users.users.${username}.group}.gid; builtins.toString
config.users.users.${username}.uid;
homeGroup =
builtins.toString
config.users.groups.${config.users.users.${username}.group}.gid;
in { in {
description = "Fix impermanent home ownership"; description = "Fix impermanent home ownership";
wantedBy = ["home-manager-${username}.service"]; # Required for HM activation wantedBy = ["home-manager-${username}.service"];
before = ["home-manager-${username}.service"]; before = ["home-manager-${username}.service"];
after = ["home.mount"]; after = ["home.mount"];
partOf = ["home.mount"]; partOf = ["home.mount"];
@ -201,21 +246,18 @@ in {
backupDuration = "7"; # Days backupDuration = "7"; # Days
mountDir = "/btrfs_tmp"; mountDir = "/btrfs_tmp";
persistDir = "${mountDir}/persist"; persistDir = "${mountDir}/persist";
homeUser = builtins.toString config.users.users.${username}.uid;
homeGroup = builtins.toString config.users.groups.${config.users.users.${username}.group}.gid;
in { in {
description = "Clean impermanent btrfs subvolumes"; description = "Clean impermanent btrfs subvolumes";
wantedBy = ["initrd.target"]; wantedBy = ["initrd.target"];
# after = ["dev-mapper-crypted.device"];
after = ["systemd-cryptsetup@crypted.service"]; after = ["systemd-cryptsetup@crypted.service"];
before = ["sysroot.mount"]; before = ["sysroot.mount"];
unitConfig.DefaultDependencies = "no"; unitConfig.DefaultDependencies = "no";
serviceConfig.Type = "oneshot"; serviceConfig.Type = "oneshot";
# path = ["/bin" config.system.build.extraUtils pkgs.coreutils-full];
# NOTE: If any single line of this script fails, the entire system might be bricked # NOTE: If any single line of this script fails
# NixOS automatically sets "-e", so if unlucky, the subvolumes won'e exist for mounting # the entire system might be bricked.
# NixOS automatically sets "-e", so if unlucky,
# the subvolumes won'e exist for mounting...
script = let script = let
mvSubvolToPersist = subvol: '' mvSubvolToPersist = subvol: ''
if [[ -e ${mountDir}/${subvol} ]]; then if [[ -e ${mountDir}/${subvol} ]]; then
@ -239,6 +281,7 @@ in {
fi fi
''; '';
# TODO: This fails and bricks the system
deleteOldBackups = subvol: '' deleteOldBackups = subvol: ''
for old_${subvol} in $(find ${persistDir}/old_${subvol}s/ -maxdepth 1 -mtime +${backupDuration}); do for old_${subvol} in $(find ${persistDir}/old_${subvol}s/ -maxdepth 1 -mtime +${backupDuration}); do
delete_subvolume_recursively "$old_${subvol}" delete_subvolume_recursively "$old_${subvol}"