diff --git a/hosts/common/configs/zsh/default.nix b/hosts/common/configs/zsh/default.nix index 1c7d3a5..81d894c 100644 --- a/hosts/common/configs/zsh/default.nix +++ b/hosts/common/configs/zsh/default.nix @@ -4,5 +4,8 @@ histFile = "/var/lib/zsh/history"; }; - environment.persistence."/persist".directories = [ "/var/lib/zsh" ]; + environment = { + persistence."/persist".directories = [ "/var/lib/zsh" ]; + pathsToLink = [ "/share/zsh" ]; + }; } diff --git a/hosts/common/default.nix b/hosts/common/default.nix index 159d958..0c8b317 100644 --- a/hosts/common/default.nix +++ b/hosts/common/default.nix @@ -12,6 +12,7 @@ ./configs/nix-ld ./configs/git ./configs/gpg-agent + ./scripts/cleanup ]; boot = { @@ -63,8 +64,13 @@ }; nix = { - settings.experimental-features = [ "nix-command" "flakes" ]; + settings = { + use-xdg-base-directories = true; + experimental-features = [ "nix-command" "flakes" ]; + }; + gc.automatic = true; + optimise.automatic = true; }; nixpkgs.config.allowUnfree = true; diff --git a/hosts/common/scripts/cleanup/cleanup.sh b/hosts/common/scripts/cleanup/cleanup.sh new file mode 100644 index 0000000..0aac6da --- /dev/null +++ b/hosts/common/scripts/cleanup/cleanup.sh @@ -0,0 +1,34 @@ +set -e + +if [ "$(id -u)" -ne 0 ]; then + echo "This script must be run as root or with sudo privileges." + exit 1 +fi + +delete_subvolume_recursively() { + IFS=$'\n' + for i in $(btrfs subvolume list -o "$1" | cut -f 9- -d ' '); do + delete_subvolume_recursively "/mnt/btrfs/$i" + done + btrfs subvolume delete "$1" +} + +if [[ -e /mnt/btrfs && $(mountpoint -q /mnt/btrfs) ]]; then + echo "/mnt/btrfs is already mounted. Exiting." + exit 1 +fi + +mkdir -p /mnt/btrfs +mount /dev/mapper/luks /mnt/btrfs + +if [[ -e /mnt/btrfs/root.bak ]]; then + for i in /mnt/btrfs/root.bak/*; do + delete_subvolume_recursively "$i" + done +fi + +umount /mnt/btrfs +rmdir /mnt/btrfs + +nix-collect-garbage -d +nix-store --gc -v diff --git a/hosts/common/scripts/cleanup/default.nix b/hosts/common/scripts/cleanup/default.nix new file mode 100644 index 0000000..bad1e58 --- /dev/null +++ b/hosts/common/scripts/cleanup/default.nix @@ -0,0 +1,5 @@ +{ pkgs, ... }: + +{ + environment.systemPackages = [ (pkgs.writeShellScriptBin "nix-cleanup" (builtins.readFile ./cleanup.sh)) ]; +} diff --git a/hosts/eirene/base/default.nix b/hosts/eirene/base/default.nix index a9d6c85..4c6f7c0 100644 --- a/hosts/eirene/base/default.nix +++ b/hosts/eirene/base/default.nix @@ -11,7 +11,6 @@ networking.hostName = "eirene"; # https://github.com/NixOS/nixos-hardware/tree/master/lenovo/legion/16achg6 - hardware = { cpu.amd.updateMicrocode = true; diff --git a/hosts/eirene/format.nix b/hosts/eirene/format.nix index 9c9c7af..4a95d8f 100644 --- a/hosts/eirene/format.nix +++ b/hosts/eirene/format.nix @@ -58,6 +58,10 @@ mountpoint = "/nix"; mountOptions = ["subvol=nix" "compress=zstd" "noatime"]; }; + "/cache" = { + mountpoint = "/cache"; + mountOptions = ["subvol=cache" "compress=zstd" "noatime"]; + }; }; }; }; diff --git a/users/common/configs/persist/default.nix b/users/common/configs/persist/default.nix index daf8a8f..ea7d9c7 100644 --- a/users/common/configs/persist/default.nix +++ b/users/common/configs/persist/default.nix @@ -6,25 +6,20 @@ in { programs.fuse.userAllowOther = lib.mkIf (users != [ ]) true; systemd.tmpfiles.rules = lib.mkIf (users != [ ]) ( - [ "d /persist/home 0755 root root -" ] ++ - lib.attrsets.mapAttrsToList (user: config: "d /persist${config.home} 0700 ${user} users -") users + [ + "d /persist/home 0755 root root -" + "d /cache/home 0755 root root -" + ] ++ + lib.attrsets.mapAttrsToList (user: config: "d /persist${config.home} 0700 ${user} users -") users ++ + lib.attrsets.mapAttrsToList (user: config: "d /cache${config.home} 0700 ${user} users -") users ); home-manager.users = lib.attrsets.mapAttrs (user: config: ({ imports = [ inputs.impermanence.nixosModules.home-manager.impermanence ]; - home.persistence."/persist${config.home}" = { - allowOther = true; - directories = [ - "Documents" - "Downloads" - "Music" - "Pictures" - "Videos" - "Templates" - "VMs" - "git" - ]; + home.persistence = { + "/persist${config.home}".allowOther = true; + "/cache${config.home}".allowOther = true; }; })) users; } diff --git a/users/common/configs/xdg/default.nix b/users/common/configs/xdg/default.nix new file mode 100644 index 0000000..af42c92 --- /dev/null +++ b/users/common/configs/xdg/default.nix @@ -0,0 +1,44 @@ +{ config, lib, ... }: + +let + users = lib.attrsets.filterAttrs (name: config: config.isNormalUser) config.users.users; +in { + home-manager.users = lib.attrsets.mapAttrs (user: cfg: (let + cacheHome = "${cfg.home}/.cache"; + configHome = "${cfg.home}/.config"; + dataHome = "${cfg.home}/.local/share"; + stateHome = "${cfg.home}/.local/state"; + xdgVmDir = "${cfg.home}/VMs"; + xdgGitDir = "${cfg.home}/git"; + in { + xdg = { + enable = true; + mimeApps.enable = true; + + inherit cacheHome; + inherit configHome; + inherit dataHome; + inherit stateHome; + + userDirs = { + enable = true; + extraConfig = { + XDG_VM_DIR = xdgVmDir; + XDG_GIT_DIR = xdgGitDir; + }; + }; + }; + + home.persistence."/persist${cfg.home}".directories = [ + "Desktop" # userDirs.desktop + "Documents" # userDirs.documents + "Downloads" # userDirs.download + "Music" # userDirs.music + "Pictures" # userDirs.pictures + "Templates" # userDirs.templates + "Videos" # userDirs.videos + "VMs" # xdgVmDir + "git" # xdgGitDir + ]; + })) users; +} diff --git a/users/common/default.nix b/users/common/default.nix index cff82d2..0e35e72 100644 --- a/users/common/default.nix +++ b/users/common/default.nix @@ -1,4 +1,4 @@ -{ inputs, ... }: +{ config, inputs, ... }: { imports = [ @@ -6,6 +6,7 @@ ./options.nix ./configs/persist ./configs/sops + ./configs/xdg ]; home-manager = { @@ -15,6 +16,7 @@ sharedModules = [{ home.stateVersion = "24.05"; systemd.user.startServices = "sd-switch"; + nix.settings = config.nix.settings; }]; }; diff --git a/users/configs/firefox/default.nix b/users/configs/firefox/default.nix index 7a4f449..e3302e2 100644 --- a/users/configs/firefox/default.nix +++ b/users/configs/firefox/default.nix @@ -88,6 +88,9 @@ }; }; - home.persistence."/persist${user.home}".directories = [ ".mozilla" ]; + home.persistence = { + "/persist${user.home}".directories = [ ".mozilla" ]; + "/cache${user.home}".directories = [ ".cache/mozilla" ]; + }; }; } diff --git a/users/configs/git/default.nix b/users/configs/git/default.nix index 1054f83..14802bd 100644 --- a/users/configs/git/default.nix +++ b/users/configs/git/default.nix @@ -1,6 +1,8 @@ -{ user ? throw "user argument is required" }: { pkgs, ... }: +{ user ? throw "user argument is required" }: { config, pkgs, ... }: -{ +let + hmConfig = config.home-manager.users."${user.name}"; +in { home-manager.users."${user.name}" = { programs.git = { enable = true; @@ -14,7 +16,7 @@ extraConfig.credential.helper = "store"; hooks = let commit-msg-hook = pkgs.writeShellScriptBin "git-commit-msg" '' - git interpret-trailers --if-exists doNothing --trailer \ + ${pkgs.git}/bin/git interpret-trailers --if-exists doNothing --trailer \ "Signed-off-by: $(git config user.name) <$(git config user.email)>" \ --in-place "$1" ''; @@ -22,5 +24,7 @@ commit-msg = "${commit-msg-hook}/bin/git-commit-msg"; }; }; + + sops.secrets."git".path = "${hmConfig.xdg.configHome}/git/credentials"; }; } diff --git a/users/configs/gpg-agent/default.nix b/users/configs/gpg-agent/default.nix index 0ea0a89..4a63256 100644 --- a/users/configs/gpg-agent/default.nix +++ b/users/configs/gpg-agent/default.nix @@ -1,7 +1,16 @@ -{ user ? throw "user argument is required" }: { pkgs, ... }: +{ user ? throw "user argument is required" }: { config, lib, pkgs, ... }: +let + hmConfig = config.home-manager.users."${user.name}"; + gpgPath = "${hmConfig.xdg.dataHome}/gnupg"; +in { home-manager.users."${user.name}" = { + programs.gpg = { + enable = true; + homedir = gpgPath; + }; + services.gpg-agent = { enable = true; defaultCacheTtl = 31536000; @@ -11,22 +20,24 @@ systemd.user = { services.gpg-agent-import = let init = pkgs.writeShellScriptBin "import-gpg-keys" '' + export GNUPGHOME=${gpgPath} + for keyfile in "${user.home}"/.config/sops-nix/secrets/gpg-agent/*.key; do passfile="''${keyfile%.key}.pass" if [ -f "$passfile" ]; then - gpg --batch --yes --pinentry-mode loopback --passphrase-file "$passfile" --import "$keyfile" + ${pkgs.gnupg}/bin/gpg2 --batch --yes --pinentry-mode loopback --passphrase-file "$passfile" --import "$keyfile" else - gpg --batch --yes --import "$keyfile" + ${pkgs.gnupg}/bin/gpg2 --batch --yes --import "$keyfile" fi - gpg --with-colons --import-options show-only --import "$keyfile" | grep '^fpr' | cut -d: -f10 | while read -r KEY_ID; do - echo "$KEY_ID:6:" >> "${user.home}"/.gnupg/otrust.txt + ${pkgs.gnupg}/bin/gpg2 --with-colons --import-options show-only --import "$keyfile" | grep '^fpr' | cut -d: -f10 | while read -r KEY_ID; do + echo "$KEY_ID:6:" >> "${gpgPath}"/otrust.txt done done - gpg --import-ownertrust "${user.home}"/.gnupg/otrust.txt - rm "${user.home}"/.gnupg/otrust.txt + ${pkgs.gnupg}/bin/gpg2 --import-ownertrust "${gpgPath}"/otrust.txt + rm "${gpgPath}"/otrust.txt ''; in { Unit = { @@ -43,7 +54,12 @@ Install = { WantedBy = [ "default.target" ]; }; }; - tmpfiles.rules = [ "d ${user.home}/.gnupg 0700 ${user.name} users -" ]; + tmpfiles.rules = [ "d ${hmConfig.xdg.dataHome}/gnupg 0700 ${user.name} users -" ]; + }; + + sops.secrets = { + "gpg-agent/pgp.key" = { }; + "gpg-agent/pgp.pass" = { }; }; }; } diff --git a/users/configs/gtk/default.nix b/users/configs/gtk/default.nix new file mode 100644 index 0000000..793c685 --- /dev/null +++ b/users/configs/gtk/default.nix @@ -0,0 +1,10 @@ +{ user ? throw "user argument is required" }: { config, ... }: + +let + hmConfig = config.home-manager.users."${user.name}"; +in +{ + home-manager.users."${user.name}" = { + gtk.gtk2.configLocation = "${hmConfig.xdg.configHome}/gtk-2.0/gtkrc"; + }; +} diff --git a/users/configs/hyprland/default.nix b/users/configs/hyprland/default.nix index b30e957..351382f 100644 --- a/users/configs/hyprland/default.nix +++ b/users/configs/hyprland/default.nix @@ -1,5 +1,8 @@ -{ user ? throw "user argument is required" }: { lib, pkgs, ... }: +{ user ? throw "user argument is required" }: { config, lib, pkgs, ... }: +let + hmConfig = config.home-manager.users."${user.name}"; +in { programs.hyprland.enable = true; @@ -8,12 +11,12 @@ enable = true; settings = { "$mod" = "SUPER"; - "$term" = "kitty"; + "$term" = "${pkgs.kitty}/bin/kitty"; bind = [ "$mod, Return, exec, $term" - "$mod, r, exec, rofi -show drun" - "$mod, b, exec, firefox" + "$mod, r, exec, ${pkgs.rofi-wayland}/bin/rofi -cache-dir ${hmConfig.xdg.cacheHome}/rofi -show drun" + "$mod, b, exec, ${pkgs.firefox}/bin/firefox" "$mod, 1, workspace, 1" "$mod, 2, workspace, 2" @@ -116,9 +119,8 @@ home = { sessionVariables.NIXOS_OZONE_WL = "1"; + packages = with pkgs; [ - swww - rofi-wayland pavucontrol ]; }; diff --git a/users/configs/kitty/default.nix b/users/configs/kitty/default.nix index c497f72..6eb5cfd 100644 --- a/users/configs/kitty/default.nix +++ b/users/configs/kitty/default.nix @@ -8,5 +8,7 @@ confirm_os_window_close 0 ''; }; + + home.persistence."/cache${user.home}".directories = [ ".cache/kitty" ]; }; } diff --git a/users/configs/rofi/default.nix b/users/configs/rofi/default.nix new file mode 100644 index 0000000..1f854c6 --- /dev/null +++ b/users/configs/rofi/default.nix @@ -0,0 +1,10 @@ +{ user ? throw "user argument is required" }: { pkgs, ... }: + +{ + home-manager.users."${user.name}" = { + home = { + packages = with pkgs; [ rofi-wayland ]; + persistence."/cache${user.home}".directories = [ ".cache/rofi" ]; + }; + }; +} diff --git a/users/configs/swww/default.nix b/users/configs/swww/default.nix new file mode 100644 index 0000000..819facb --- /dev/null +++ b/users/configs/swww/default.nix @@ -0,0 +1,10 @@ +{ user ? throw "user argument is required" }: { pkgs, ... }: + +{ + home-manager.users."${user.name}" = { + home = { + packages = with pkgs; [ swww ]; + persistence."/cache${user.home}".directories = [ ".cache/swww" ]; + }; + }; +} diff --git a/users/configs/vscode/default.nix b/users/configs/vscode/default.nix index 2509cce..18c7061 100644 --- a/users/configs/vscode/default.nix +++ b/users/configs/vscode/default.nix @@ -1,6 +1,22 @@ -{ user ? throw "user argument is required" }: { pkgs, ... }: +{ user ? throw "user argument is required" }: { inputs, lib, pkgs, ... }: -{ +let + configDir = ".config/Code"; + cacheDirs = [ + ".config/Code/Cache" + ".config/Code/CachedConfigurations" + ".config/Code/CachedData" + ".config/Code/CachedExtensionVSIXs" + ".config/Code/CachedExtensions" + ".config/Code/CachedProfilesData" + ".config/Code/Code Cache" + ".config/Code/DawnCache" + ".config/Code/GPUCache" + ".config/Code/Service Worker/CacheStorage" + ".config/Code/Service Worker/ScriptCache" + ]; + inherit (pkgs.callPackage "${inputs.impermanence}/lib.nix" { }) sanitizeName concatPaths; +in { home-manager.users."${user.name}" = { programs.vscode = { enable = true; @@ -59,6 +75,28 @@ ./langs/nix.nix ]; - home.persistence."/persist${user.home}".directories = [ ".config/Code" ]; + home.persistence = { + "/persist${user.home}".directories = [ configDir ]; + # Bastard: https://github.com/microsoft/vscode/issues/3884 + "/cache${user.home}".directories = cacheDirs; + }; + + # Some filthy fucking shit below, be warned. + # Microsoft stores cache under .config/Code instead of .cache/Code like normal people. + # Sometimes a race condition is caused if the cache bind mounts are created before the config one. + # So we do this. Sorry. + # https://github.com/nix-community/impermanence/blob/27979f1c3a0d3b9617a3563e2839114ba7d48d3f/home-manager.nix#L238 + systemd.user.services = let + configDirService = "bindMount-${sanitizeName (lib.strings.escapeShellArg (concatPaths [ "/persist${user.home}" configDir ]))}.service"; + in + builtins.listToAttrs (builtins.map (dir: { + name = "bindMount-${sanitizeName (lib.strings.escapeShellArg (concatPaths [ "/cache${user.home}" dir ]))}"; + value = { + Unit = { + Requires = [ configDirService ]; + After = [ configDirService ]; + }; + }; + }) cacheDirs); }; } diff --git a/users/configs/x/default.nix b/users/configs/x/default.nix new file mode 100644 index 0000000..cb3997f --- /dev/null +++ b/users/configs/x/default.nix @@ -0,0 +1,10 @@ +{ user ? throw "user argument is required" }: { config, ... }: + +let + hmConfig = config.home-manager.users."${user.name}"; +in +{ + home-manager.users."${user.name}" = { + xresources.path = "${hmConfig.xdg.configHome}/X11/xresources"; + }; +} diff --git a/users/configs/zsh/default.nix b/users/configs/zsh/default.nix index 671bdee..a7bc9af 100644 --- a/users/configs/zsh/default.nix +++ b/users/configs/zsh/default.nix @@ -4,6 +4,7 @@ home-manager.users."${user.name}" = { programs.zsh = { enable = true; + dotDir = ".config/zsh"; autocd = true; history = { path = "${user.home}/.local/share/zsh/history"; diff --git a/users/nick/default.nix b/users/nick/default.nix index aa0d1ef..683d9cd 100644 --- a/users/nick/default.nix +++ b/users/nick/default.nix @@ -8,8 +8,12 @@ in ./nogui.nix (import ../configs/firefox { inherit user; }) (import ../configs/hyprland { inherit user; }) + (import ../configs/rofi { inherit user; }) + (import ../configs/swww { inherit user; }) (import ../configs/kitty { inherit user; }) (import ../configs/vscode { inherit user; }) + (import ../configs/gtk { inherit user; }) + (import ../configs/x { inherit user; }) (import ../configs/stylix { inherit user; }) ]; diff --git a/users/nick/nogui.nix b/users/nick/nogui.nix index e57ec03..5a795cf 100644 --- a/users/nick/nogui.nix +++ b/users/nick/nogui.nix @@ -2,8 +2,7 @@ let user = config.users.users.nick; -in -{ +in { imports = [ ../common (import ../configs/zsh { inherit user; }) @@ -23,7 +22,7 @@ in home = "/home/nick"; email = "nick@karaolidis.com"; fullName = "Nikolaos Karaolidis"; - description = config.users.users.nick.fullName; + description = user.fullName; hashedPasswordFile = config.sops.secrets.nick-password.path; extraGroups = [ "wheel" ]; linger = true; @@ -31,14 +30,7 @@ in }; home-manager.users.nick = { - home.homeDirectory = config.users.users.nick.home; - sops = { - defaultSopsFile = ./secrets/secrets.yaml; - secrets = { - "git" = { path = "/home/nick/.git-credentials"; }; - "gpg-agent/pgp.key" = { }; - "gpg-agent/pgp.pass" = { }; - }; - }; + home.homeDirectory = user.home; + sops.defaultSopsFile = ./secrets/secrets.yaml; }; }