From c173ea87cfe56cb2e3f091bfda7c230816cf633a Mon Sep 17 00:00:00 2001
From: Tom Alexander <tom@fizz.buzz>
Date: Sun, 30 Mar 2025 17:26:05 -0400
Subject: [PATCH] Auto-create persist directories.

---
 nix/steam_deck/configuration/home.nix         |  1 +
 .../roles/2ship2harkinian/default.nix         | 10 +--
 .../configuration/roles/ares/default.nix      | 17 +---
 .../configuration/roles/dolphin/default.nix   | 70 +++-------------
 .../configuration/roles/pcsx2/default.nix     | 41 ++--------
 .../configuration/roles/rpcs3/default.nix     | 42 ++--------
 .../roles/shipwright/default.nix              | 10 +--
 .../roles/steam_rom_manager/default.nix       |  3 +-
 .../util/persist_symlink/default.nix          | 79 +++++++++++++++++++
 9 files changed, 116 insertions(+), 157 deletions(-)
 create mode 100644 nix/steam_deck/configuration/util/persist_symlink/default.nix

diff --git a/nix/steam_deck/configuration/home.nix b/nix/steam_deck/configuration/home.nix
index 1800c16..254b357 100644
--- a/nix/steam_deck/configuration/home.nix
+++ b/nix/steam_deck/configuration/home.nix
@@ -18,6 +18,7 @@
     ./roles/sm64ex
     ./roles/steam_rom_manager
     ./util/unfree_polyfill
+    ./util/persist_symlink
   ];
 
   home.username = "deck";
diff --git a/nix/steam_deck/configuration/roles/2ship2harkinian/default.nix b/nix/steam_deck/configuration/roles/2ship2harkinian/default.nix
index ea85fbe..e91fa0e 100644
--- a/nix/steam_deck/configuration/roles/2ship2harkinian/default.nix
+++ b/nix/steam_deck/configuration/roles/2ship2harkinian/default.nix
@@ -1,4 +1,3 @@
-# MANUAL: mkdir -p ~/.persist/.local/share/2ship/saves
 {
   config,
   lib,
@@ -39,14 +38,7 @@ in
           source = ./files/2ship2harkinian.json;
         };
 
-        home.persistence."/home/deck/.persist" = {
-          directories = [
-            {
-              directory = ".local/share/2ship/saves";
-              method = "symlink";
-            }
-          ];
-        };
+        me.persist.directories = [ ".local/share/2ship/saves" ];
         home.persistence."/home/deck/.state" = {
           files = [
             ".local/share/2ship/mm.o2r"
diff --git a/nix/steam_deck/configuration/roles/ares/default.nix b/nix/steam_deck/configuration/roles/ares/default.nix
index 1a45aa8..4486c31 100644
--- a/nix/steam_deck/configuration/roles/ares/default.nix
+++ b/nix/steam_deck/configuration/roles/ares/default.nix
@@ -1,4 +1,3 @@
-# MANUAL: mkdir -p ~/.persist/.local/share/ares/saves ~/.persist/.local/share/ares/screenshots
 {
   config,
   lib,
@@ -34,18 +33,10 @@ in
           steam_ares
         ];
 
-        home.persistence."/home/deck/.persist" = {
-          directories = [
-            {
-              directory = ".local/share/ares/saves";
-              method = "symlink";
-            }
-            {
-              directory = ".local/share/ares/screenshots";
-              method = "symlink";
-            }
-          ];
-        };
+        me.persist.directories = [
+          ".local/share/ares/saves"
+          ".local/share/ares/screenshots"
+        ];
 
         home.file.".local/share/ares/settings.bml" = {
           source = ./files/settings.bml;
diff --git a/nix/steam_deck/configuration/roles/dolphin/default.nix b/nix/steam_deck/configuration/roles/dolphin/default.nix
index 7b9fc20..083b051 100644
--- a/nix/steam_deck/configuration/roles/dolphin/default.nix
+++ b/nix/steam_deck/configuration/roles/dolphin/default.nix
@@ -2,7 +2,6 @@
   config,
   lib,
   pkgs,
-  home-manager,
   ...
 }:
 
@@ -48,63 +47,18 @@ in
           source = ./files/GCPadNew.ini;
         };
 
-        home.persistence."/home/deck/.persist" = {
-          directories = [
-            {
-              # The system memory
-              directory = ".local/share/dolphin-emu/Wii";
-              method = "symlink";
-            }
-            {
-              # Memory card(s)
-              directory = ".local/share/dolphin-emu/Load";
-              method = "symlink";
-            }
-            {
-              # Gamecube
-              directory = ".local/share/dolphin-emu/GC";
-              method = "symlink";
-            }
-            {
-              # Screenshots
-              directory = ".local/share/dolphin-emu/ScreenShots";
-              method = "symlink";
-            }
-            {
-              # GameBoy Advanced
-              directory = ".local/share/dolphin-emu/GBA/Saves";
-              method = "symlink";
-            }
-          ];
-        };
-
-        home.persistence."/home/deck/.state" = {
-          directories = [
-            {
-              directory = ".cache/dolphin-emu";
-              method = "symlink";
-            }
-            {
-              directory = ".local/share/dolphin-emu/Shaders";
-              method = "symlink";
-            }
-            {
-              directory = ".local/share/dolphin-emu/StateSaves";
-              method = "symlink";
-            }
-          ];
-        };
-
-        home.activation = {
-          createDolphinDirectories = home-manager.lib.hm.dag.entryAfter [ "writeBoundary" ] ''
-            for dir in '.local/share/dolphin-emu/Wii' '.cache/dolphin-emu' '.local/share/dolphin-emu/Load' '.local/share/dolphin-emu/GC' '.local/share/dolphin-emu/ScreenShots' '.local/share/dolphin-emu/GBA/Saves' '.local/share/dolphin-emu/Shaders' '.local/share/dolphin-emu/StateSaves' ; do
-              echo "checking $dir"
-              if [[ ! -d "$HOME/.persist/$dir" ]]; then
-                $DRY_RUN_CMD mkdir $VERBOSE_ARG -p "$HOME/.persist/$dir"
-              fi
-            done
-          '';
-        };
+        me.persist.directories = [
+          ".local/share/dolphin-emu/Wii" # The system memory
+          ".local/share/dolphin-emu/Load" # Memory card(s)
+          ".local/share/dolphin-emu/GC" # Gamecube
+          ".local/share/dolphin-emu/ScreenShots" # Screenshots
+          ".local/share/dolphin-emu/GBA/Saves" # GameBoy Advanced
+        ];
+        me.state.directories = [
+          ".cache/dolphin-emu"
+          ".local/share/dolphin-emu/Shaders"
+          ".local/share/dolphin-emu/StateSaves"
+        ];
 
         nixpkgs.overlays = [
           (
diff --git a/nix/steam_deck/configuration/roles/pcsx2/default.nix b/nix/steam_deck/configuration/roles/pcsx2/default.nix
index d3f71b4..c95f70b 100644
--- a/nix/steam_deck/configuration/roles/pcsx2/default.nix
+++ b/nix/steam_deck/configuration/roles/pcsx2/default.nix
@@ -1,4 +1,3 @@
-# MANUAL: mkdir -p ~/.persist/.config/PCSX2/memcards ~/.state/.config/PCSX2/cache ~/.state/.config/PCSX2/sstates ~/.state/.config/PCSX2/snaps ~/.state/.config/PCSX2/covers ~/.state/.config/PCSX2/videos
 {
   config,
   lib,
@@ -36,38 +35,14 @@ in
           source = ./files/PCSX2.ini;
         };
 
-        home.persistence."/home/deck/.persist" = {
-          directories = [
-            {
-              directory = ".config/PCSX2/memcards";
-              method = "symlink";
-            }
-          ];
-        };
-        home.persistence."/home/deck/.state" = {
-          directories = [
-            {
-              directory = ".config/PCSX2/cache";
-              method = "symlink";
-            }
-            {
-              directory = ".config/PCSX2/sstates";
-              method = "symlink";
-            }
-            {
-              directory = ".config/PCSX2/snaps";
-              method = "symlink";
-            }
-            {
-              directory = ".config/PCSX2/covers";
-              method = "symlink";
-            }
-            {
-              directory = ".config/PCSX2/videos";
-              method = "symlink";
-            }
-          ];
-        };
+        me.persist.directories = [ ".config/PCSX2/memcards" ];
+        me.state.directories = [
+          ".config/PCSX2/cache"
+          ".config/PCSX2/sstates"
+          ".config/PCSX2/snaps"
+          ".config/PCSX2/covers"
+          ".config/PCSX2/videos"
+        ];
 
         nixpkgs.overlays = [
           (
diff --git a/nix/steam_deck/configuration/roles/rpcs3/default.nix b/nix/steam_deck/configuration/roles/rpcs3/default.nix
index 4f2d56c..dc944ab 100644
--- a/nix/steam_deck/configuration/roles/rpcs3/default.nix
+++ b/nix/steam_deck/configuration/roles/rpcs3/default.nix
@@ -1,4 +1,3 @@
-# MANUAL: mkdir -p ~/.state/.cache/rpcs3 ~/.persist/.config/rpcs3/dev_hdd0 ~/.persist/.config/rpcs3/dev_hdd1 ~/.persist/.config/rpcs3/savestates ~/.persist/.config/rpcs3/dev_usb000 ~/.persist/.config/rpcs3/dev_flash
 {
   config,
   lib,
@@ -35,39 +34,14 @@ in
         # .config/rpcs3/config.yml
         # .config/rpcs3/GuiConfigs/CurrentSettings.ini
 
-        home.persistence."/home/deck/.persist" = {
-          directories = [
-            {
-              directory = ".config/rpcs3/dev_hdd0";
-              method = "symlink";
-            }
-            {
-              directory = ".config/rpcs3/dev_hdd1";
-              method = "symlink";
-            }
-            {
-              directory = ".config/rpcs3/savestates";
-              method = "symlink";
-            }
-            {
-              directory = ".config/rpcs3/dev_usb000";
-              method = "symlink";
-            }
-            {
-              # Seems to be where the firmware is installed.
-              directory = ".config/rpcs3/dev_flash";
-              method = "symlink";
-            }
-          ];
-        };
-        home.persistence."/home/deck/.state" = {
-          directories = [
-            {
-              directory = ".cache/rpcs3";
-              method = "symlink";
-            }
-          ];
-        };
+        me.persist.directories = [
+          ".config/rpcs3/dev_hdd0"
+          ".config/rpcs3/dev_hdd1"
+          ".config/rpcs3/savestates"
+          ".config/rpcs3/dev_usb000"
+          ".config/rpcs3/dev_flash" # Seems to be where the firmware is installed.
+        ];
+        me.state.directories = [ ".cache/rpcs3" ];
 
         nixpkgs.overlays = [
           (
diff --git a/nix/steam_deck/configuration/roles/shipwright/default.nix b/nix/steam_deck/configuration/roles/shipwright/default.nix
index 4cfe884..3779a35 100644
--- a/nix/steam_deck/configuration/roles/shipwright/default.nix
+++ b/nix/steam_deck/configuration/roles/shipwright/default.nix
@@ -1,4 +1,3 @@
-# MANUAL: mkdir -p ~/.persist/.local/share/soh/Save
 {
   config,
   lib,
@@ -39,14 +38,7 @@ in
           source = ./files/shipofharkinian.json;
         };
 
-        home.persistence."/home/deck/.persist" = {
-          directories = [
-            {
-              directory = ".local/share/soh/Save";
-              method = "symlink";
-            }
-          ];
-        };
+        me.persist.directories = [ ".local/share/soh/Save" ];
         home.persistence."/home/deck/.state" = {
           files = [
             ".local/share/soh/oot.otr"
diff --git a/nix/steam_deck/configuration/roles/steam_rom_manager/default.nix b/nix/steam_deck/configuration/roles/steam_rom_manager/default.nix
index 6e0c655..082781f 100644
--- a/nix/steam_deck/configuration/roles/steam_rom_manager/default.nix
+++ b/nix/steam_deck/configuration/roles/steam_rom_manager/default.nix
@@ -1,4 +1,3 @@
-# MANUAL: mkdir -p ~/.persist/.config/steam-rom-manager/userData
 {
   stdenv,
   config,
@@ -29,6 +28,8 @@ in
           package
         ];
 
+        me.persist.directories = [ ".config/steam-rom-manager/userData" ];
+
         home.persistence."/home/deck/.persist" = {
           directories = [
             {
diff --git a/nix/steam_deck/configuration/util/persist_symlink/default.nix b/nix/steam_deck/configuration/util/persist_symlink/default.nix
new file mode 100644
index 0000000..0860d66
--- /dev/null
+++ b/nix/steam_deck/configuration/util/persist_symlink/default.nix
@@ -0,0 +1,79 @@
+{
+  config,
+  lib,
+  pkgs,
+  home-manager,
+  ...
+}:
+
+{
+  imports = [ ];
+
+  options.me = {
+    persist.directories = lib.mkOption {
+      type = lib.types.listOf lib.types.str;
+      default = [ ];
+      example = [ ".local/share/dolphin-emu/Wii" ];
+      description = "List of folders relative to the home directory to persist.";
+    };
+    state.directories = lib.mkOption {
+      type = lib.types.listOf lib.types.str;
+      default = [ ];
+      example = [ ".local/share/dolphin-emu/Shaders" ];
+      description = "List of folders relative to the home directory to keep as state.";
+    };
+  };
+
+  config = lib.mkMerge [
+    (lib.mkIf (config.me.persist.directories != [ ]) {
+      home.persistence."/home/deck/.persist" = {
+        directories = (
+          builtins.map (entry: {
+            directory = entry;
+            method = "symlink";
+          }) config.me.persist.directories
+        );
+      };
+
+      home.activation = {
+        createPersistDirectories = home-manager.lib.hm.dag.entryAfter [ "writeBoundary" ] (
+          let
+            dirlist = lib.strings.escapeShellArgs config.me.persist.directories;
+          in
+          ''
+            for dir in ${dirlist} ; do
+              if [[ ! -d "$HOME/.persist/$dir" ]]; then
+                $DRY_RUN_CMD mkdir $VERBOSE_ARG -p "$HOME/.persist/$dir"
+              fi
+            done
+          ''
+        );
+      };
+    })
+    (lib.mkIf (config.me.state.directories != [ ]) {
+      home.persistence."/home/deck/.state" = {
+        directories = (
+          builtins.map (entry: {
+            directory = entry;
+            method = "symlink";
+          }) config.me.state.directories
+        );
+      };
+
+      home.activation = {
+        createStateDirectories = home-manager.lib.hm.dag.entryAfter [ "writeBoundary" ] (
+          let
+            dirlist = lib.strings.escapeShellArgs config.me.state.directories;
+          in
+          ''
+            for dir in ${dirlist} ; do
+              if [[ ! -d "$HOME/.state/$dir" ]]; then
+                $DRY_RUN_CMD mkdir $VERBOSE_ARG -p "$HOME/.state/$dir"
+              fi
+            done
+          ''
+        );
+      };
+    })
+  ];
+}