From d952a910e3d6214ddb497ceb73fee008c3b32010 Mon Sep 17 00:00:00 2001 From: Ali Rizvi Date: Thu, 5 Dec 2024 22:15:35 -0500 Subject: [PATCH] treewide: revamp the persistence module Massive changes have been accomplished here. Gone is the large unwieldy bash script and in is a smaller and significantly simpler script that executes within systemd. This has one major benefit of parallelizing the mounting, which can have some pretty decent speedups. Another major benefit is that we have more fine-tuned control over the execution of our logic. This allowed us to insert it earlier in the initrd than even when NixOS activation occurs. Alongside it comes a persist copy script, which will attempt to perform a copy of any file contents that exist during shutdown for the first time in order to create a trivial directory tree of the persisted entries. The main reason for this was simply to have a set of permissions to reference during mounting, but performing a mostly safe copy was good too. Regrettably there is no way to assure our copied content is complete, but that's simply not something we can handle at this stage anyways. Permissions have been completely thrown out from the module. Instead, it is encouraged that permissions are managed on the filesystem itself. Is this bad for reproducibility? You could say, but I argue that permissions are stateful and shouldn't have been mingled here anyways. Software should be responsible for setting the permissions it needs and those permissions will be copied and respected through this setup. This is more than enough. Since a lot of stuff within this module only works in a sane manner thanks to our persist being on "/nix", we're throwing out the ability to change it entirely. Most of our stuff works because "/sysroot/nix" is mounted in the sysroot early on alongside "/sysroot". Other mounts are not so lucky. Thinking of an implementation to force this to happen as early as possible whilst also thinking about the abstractions needed was simply too annoying, so I will not be considering it at all. --- lib/default.nix | 28 +--- modules/common/persist/config.nix | 134 ++++++++++++++++++ modules/common/persist/module-impl.nix | 130 ----------------- modules/common/persist/module.nix | 71 +--------- modules/common/persist/options.nix | 116 +++++++++++++++ modules/common/persist/package/default.nix | 39 +++++ .../common/persist/package/persist-helper.sh | 118 +++++++++++++++ .../home-manager/programs/element/module.nix | 7 +- .../home-manager/programs/gnupg/module.nix | 10 +- .../home-manager/programs/legcord/module.nix | 7 +- .../programs/libreoffice/module.nix | 7 +- .../programs/microsoft-edge/module.nix | 10 +- .../home-manager/programs/neovim/module.nix | 7 +- modules/home-manager/programs/zsh/module.nix | 8 +- modules/nixos/desktops/sway/module.nix | 9 +- modules/nixos/system/mounts/tmp/module.nix | 2 +- 16 files changed, 437 insertions(+), 266 deletions(-) create mode 100644 modules/common/persist/config.nix delete mode 100644 modules/common/persist/module-impl.nix create mode 100644 modules/common/persist/options.nix create mode 100644 modules/common/persist/package/default.nix create mode 100755 modules/common/persist/package/persist-helper.sh diff --git a/lib/default.nix b/lib/default.nix index 06f0abd..ed53c5c 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -60,28 +60,8 @@ outputsToRemove = [ "inputs" "outputs" "sourceInfo" ]; in (removeSystemAttr (removeAttrs flake outputsToRemove))); - types = ( - let - mkPathOption = { name, prefix }: prev.mkOptionType { - inherit name; - description = "An absolute path, prefixed with ${prefix}."; - descriptionClass = "nonRestrictiveClause"; - - check = (x: - prev.isStringLike x && - prev.substring 0 1 x == prefix - ); - merge = prev.mergeEqualOption; - }; - in { - systemPath = mkPathOption { - name = "systemPath"; - prefix = "/"; - }; - - userPath = mkPathOption { - name = "userPath"; - prefix = "~"; - }; - } // prev.types); + types = rec { + systemPath = prev.types.path; + userPath = prev.types.either systemPath (prev.types.strMatching "~/.+"); + } // prev.types; } diff --git a/modules/common/persist/config.nix b/modules/common/persist/config.nix new file mode 100644 index 0000000..e5d4fcf --- /dev/null +++ b/modules/common/persist/config.nix @@ -0,0 +1,134 @@ +{ + config, + lib, + pkgs, + utils, + ... +}: +let + cfg = config.my.persist; + + persist-helper = lib.getExe (pkgs.callPackage ./package {}); +in { + config = lib.mkIf cfg.enable { + # Automatically add a default sane set of directories + # to persist on a standard system. + my.persist = { + directories = [ + "/var/lib" # contains persistent information about system state for services + "/var/log" # logging.. fairly straightforward, you'd always want this. + ] ++ lib.optionals config.security.sudo.enable [ + "/var/db/sudo/lectured" # preferential. + ]; + + files = [ + "/etc/machine-id" # systemd uses this to match up system-specific data. + ]; + }; + + # Kill the `systemd-machine-id-commit` service, introduced in systemd 256.7. + # + # This service detects when `/etc/machine-id` seems to be in danger of being + # lost, and attempts to persist it to a writable medium. I don't know the + # details of what it considers "a writable medium", however we do know that + # our setup causes this unit to fire. + # + # In our case, choosing to persist `/etc/machine-id` (default behaviour) + # causes this service to think our file is at risk of disappearing, and as + # a result, tries to persist it. However, it cannot determine a place to + # save it, which causes the service to fail. + # + # This doesn't matter at all for our setup because we have the confidence + # in knowing the file is safe. If for some reason it's not, then that was + # a concious decision by the user and they can handle the problems with it. + boot.initrd.systemd.suppressedUnits = [ "systemd-machine-id-commit.service" ]; + systemd.suppressedSystemUnits = [ "systemd-machine-id-commit.service" ]; + + # Create services that will attempt to mount our units in parallel + # from within the initrd. + # + # The motivation behind performing this in the initrd is to avoid + # conflicts with files that needed to exist earlier. For example, + # if we want to persist `/var/log` but do so too late, the journal + # will already have created this directory and written to it. Any + # attempts at a bind here will result in a loss of data, or race + # conditions between attempting to copy and bind on top. This is + # just too messy. + # + # Furthermore, at a conceptual level, one could think of these bind + # mounts like real files that were brought up thanks to the sysroot + # mount. After all, on a non-ephemeral root system, these files would + # be brought with the root, so why not make it almost seem like that? + # + # Note that there isn't a hard dependency on when these must finish. + # This is because there's no immediate importance to force them to finish + # fast since nothing in the initrd (to my knowledge) should cause problems + # for these mounts. + boot.initrd.systemd.storePaths = [ persist-helper ]; + boot.initrd.systemd.services = lib.listToAttrs (map (path: { + name = "persist-mount-${utils.escapeSystemdPath path}"; + value = { + unitConfig = { + DefaultDependencies = "no"; + + After = "sysroot.mount"; + Before = "initrd-root-fs.target"; + + ConditionPathExists = [ + "/sysroot/${cfg.volume}/${path}" + "!/sysroot/${path}" + ]; + + RequiresMountsFor = [ "/sysroot/${cfg.volume}" ]; + }; + + serviceConfig = { + ExecStart = "${persist-helper} 'mount'" + + " '/sysroot/${cfg.volume}' '/sysroot' '${path}'"; + }; + + requiredBy = [ "initrd-root-fs.target" ]; + }; + }) cfg.toplevel); + + # Perform a possibly mostly safe copy of file contents as they are + # found during the shutdown phase of the system. + # + # There is no truly safe way to perform this without losing some minimal + # amount of data during the copy, especially for services that refuse to + # let their fd's go. We cannot reasonably do anything at this stage, so + # we instead opt to perform a one-off copy to obtain the initial set of + # files from whatever we wanted to persist. + # + # The expectation here is that this directory won't be too big given the + # root is mostly expected to be a tmpfs, and even if the files are big + # and the copy takes a long time, we can justify it by remembering that + # this copy won't happen again. It's a one-off service to obtain the bare + # minimum level of directories (mostly for the permissions) so that a + # reasonable directory tree is produced in the persistent location. + systemd.services = lib.listToAttrs (map (path: { + name = "persist-copy-${utils.escapeSystemdPath path}"; + value = { + unitConfig = { + DefaultDependencies = "no"; + + Before = "final.target"; + + ConditionPathExists = [ + "${path}" + "!${cfg.volume}/${path}" + ]; + + RequiresMountsFor = [ "${cfg.volume}" ]; + }; + + serviceConfig = { + ExecStart = "${persist-helper} 'copy' '/' '${cfg.volume}'" + + " '${path}'"; + }; + + requiredBy = [ "final.target" ]; + }; + }) cfg.toplevel); + }; +} diff --git a/modules/common/persist/module-impl.nix b/modules/common/persist/module-impl.nix deleted file mode 100644 index e7cc448..0000000 --- a/modules/common/persist/module-impl.nix +++ /dev/null @@ -1,130 +0,0 @@ -{ - config, - lib, - pkgs, - ... -}: -let - cfg = config.my.persist; - - mkPersistActivation = (root: cfg: - let - dirs = map (e: e.path) cfg.directories; - - parentExists = (path: - let - parent = dirOf path; - in - parent != root - && (lib.elem parent dirs - || parentExists parent) - ); - - uniqueDirs = lib.filter (p: !parentExists p) dirs; - in lib.concatStringsSep "\n" ((map (e: - if lib.elem e.path uniqueDirs then - ''persist "${config.my.persist.volume + e.path}" "${e.path}" "${e.user}" "${e.group}" "${e.mode}" "dir"'' - else - ''mkown "${config.my.persist.volume + e.path}" "${e.path}" "${e.user}" "${e.group}" "${e.mode}" "dir" '' - ) cfg.directories) ++ map (e: - ''persist "${config.my.persist.volume + e.path}" "${e.path}" "${e.user}" "${e.group}" "${e.mode}" "file"'' - ) cfg.files)); -in { - config = lib.mkIf cfg.enable { - # These directories should logically exist to ensure - # a consistent and expected system state. - my.persist.directories = [ - "/var/lib" - "/var/log" - ] ++ lib.optionals config.security.sudo.enable [{ - path = "/var/db/sudo/lectured"; - mode = "700"; - }]; - - # machine-id is widely used by systemd to track system-specific - # things, very important to persist it for general expectations. - my.persist.files = [ - "/etc/machine-id" - ]; - - # Kill the systemd-machine-id-commit.service from systemd 256.7, - # it does what we already handle via the activation script. - systemd.services."systemd-machine-id-commit".enable = false; - - system.activationScripts.persist = lib.stringAfter [ "users" "groups" ] '' - log() { - echo "[persist] $1" - } - - # $1 - Path to entry in the persisted volume - # $2 - Absolute path to entry as it will be on the rootfs - # $3 - User value for permissions - # $4 - Group value for permissions - # $5 - Mode value for permissions - # $6 - Enum of either "dir" or "file" - mkown() { - # Create all the parent paths with sane default permissions. - # This is usually only necessary in cases where the persist - # entry was made new, and has not existed in previous contexts - mkdir -pv "$(dirname "$1")" "$(dirname "$2")" | ${lib.getExe pkgs.gnused} "s|'||g;s|.* ||g" | while read -r dir; do - log "mkown: mkdir $dir '$3:$4' 755" - chown "$3:$4" "$dir" - chmod "755" "$dir" - done - - # Create the entry if it does not exist within the persist volume. - # We use either mkdir or touch depending on the type of entry. - if [ ! -e "$1" ]; then - log "mkown: mkent $1" - (test "$6" = "dir" && mkdir -p "$1") || (test "$6" = "file" && touch "$1") - fi - - # Create the entry if it does not exist on the rootfs. - # This is necessary for the bind mount to succeed in persist. - if [ ! -e "$2" ]; then - log "mkown: mkent $2" - (test "$6" = "dir" && mkdir -p "$2") || (test "$6" = "file" && touch "$2") - fi - - # Correctly enforce desired permissions on the entry in the persist. - log "mkown: ch{mod,own} $1" - chown "$3:$4" "$1" - chmod "$5" "$1" - } - - # $1 - Path to entry in the persisted volume - # $2 - Absolute path to entry as it will be on the rootfs - # $3 - User value for permissions - # $4 - Group value for permissions - # $5 - Mode value for permissions - # $6 - Enum of either "dir" or "file" - persist() { - # Ensure the existence of the directory tree with sufficient - # permissions beforehand. This will not replace anything that - # already exists, it is non-destructive. - mkown "$1" "$2" "$3" "$4" "$5" "$6" - - # Fast fail in situations where the entry is already linked. - # This usually happens when we perform a switch-to-configuration - # on a running system. - if [ "$1" -ef "$2" ]; then - log "persist: skip $1 ==> $2" - return 0 - fi - - # Create the bind mount onto the rootfs. We make the assumption - # that this entry does not exist, as we performed a 'test -ef' - # check earlier on. - log "persist: bind $1 ==> $2" - mount -o bind "$1" "$2" - } - - ${mkPersistActivation "/" cfg} - ${lib.pipe config.home-manager.users [ - lib.attrValues - (map (cfg: mkPersistActivation cfg.home.homeDirectory cfg.my.persist)) - (lib.concatStringsSep "\n") - ]} - ''; - }; -} diff --git a/modules/common/persist/module.nix b/modules/common/persist/module.nix index 25d79a3..7706f10 100644 --- a/modules/common/persist/module.nix +++ b/modules/common/persist/module.nix @@ -1,74 +1,9 @@ { - lib, ... }: -let - mkPathOption = user: group: mode: type: apply: { - options = { - path = lib.mkOption { - default = null; - - inherit apply type; - }; - - user = lib.mkOption { - default = user; - - type = with lib.types; passwdEntry str; - }; - - group = lib.mkOption { - default = group; - - type = with lib.types; str; - }; - - mode = lib.mkOption { - default = mode; - - type = with lib.types; str; - }; - }; - }; - - mkPersistOption = user: group: type: apply: { - enable = lib.mkEnableOption "impermanence"; - - volume = lib.mkOption { - default = "/nix/persist"; - - type = with lib.types; path; - }; - - directories = lib.mkOption { - default = []; - - type = with lib.types; listOf (coercedTo str (path: { inherit path; }) (submodule (mkPathOption user group "755" type apply))); - }; - - files = lib.mkOption { - default = []; - - type = with lib.types; listOf (coercedTo str (path: { inherit path; }) (submodule (mkPathOption user group "644" type apply))); - }; - }; -in { +{ imports = [ - ./module-impl.nix + ./options.nix + ./config.nix ]; - - options.my.persist = mkPersistOption "root" "root" (with lib.types; systemPath) (x: x); - - config = { - # Add the module into the home-manager context. - home-manager.sharedModules = lib.singleton ( - { - osConfig, - config, - ... - }: - { - options.my.persist = lib.removeAttrs (mkPersistOption config.home.username osConfig.users.extraUsers.${config.home.username}.group (with lib.types; userPath) (lib.replaceStrings [ "~" ] [ config.home.homeDirectory ])) [ "enable" "volume" ]; # strip enable and volume options, they are irrelevant for home-manager. - }); - }; } diff --git a/modules/common/persist/options.nix b/modules/common/persist/options.nix new file mode 100644 index 0000000..1d8a838 --- /dev/null +++ b/modules/common/persist/options.nix @@ -0,0 +1,116 @@ +{ + config, + lib, + ... +}: +let + cfg = config.my.persist; + + # Common module options shared between NixOS and Home-Manager. + # `attrs` allows for minimal extensability in the necessary context. + commonOpts = attrs: lib.genAttrs [ "directories" "files" ] (_: lib.mkOption { + default = []; + + type = with lib.types; listOf systemPath; + } // attrs); + + # Optimizes a list of filesystem directories by intelligently + # deciding which are redundant based on whether their parents + # exist as part of the list. + # + # The simple description of this algorithm is as follows: + # 1. Break down each path into an attribute set + # 2. Sort these attribute sets to ensure the shortest + # paths are at the bottom of the list + # 3. Recursively merge them into one another, which + # will destructively merge the shorter parents into + # any existing children, thereby "optimizing" them + # 4. Join them back into a valid path string + optimizePaths = (paths: ( + let + splitList = (paths: lib.forEach paths (path: + lib.splitString "/" path + |> lib.filter (x: x != "") + )); + + joinAttrs = (delim: attrs: (map (n: + if attrs.${n} == null then + "${delim}${n}" + else + joinAttrs "${delim}${n}/" attrs.${n} + ) (lib.attrNames attrs))); + in splitList paths + |> lib.sort (e1: e2: lib.length e1 > lib.length e2) + |> map (path: lib.setAttrByPath path null) + |> lib.foldl lib.recursiveUpdate {} + |> joinAttrs "/" + |> lib.flatten + )); + + # We prefer to use '~' as a prefix for our home-manager paths, + # since it feels natural to type and use. This is obviously + # not something that works when resolving paths, so we normalize + # these paths to strip off the '~' and replace it with the user's + # home directory. + # + # We intentionally perform the check to prevent breaking any paths + # which are absolute. In the 99% case, these absolute paths are + # to directories within the users control, so it won't pose a + # permissions problem. In the 1% mishap, the activation will fail, + # and I think that's sufficient. + normalizeUserPaths = (config: + let + cfg = config.my.persist; + in cfg.directories ++ cfg.files + |> map (path: + if lib.hasPrefix "~" path then + config.home.homeDirectory + (lib.removePrefix "~" path) + else + path + ) + ); +in { + options = { + my.persist = { + enable = lib.mkEnableOption "persist"; + + volume = lib.mkOption { + default = "/nix/persist"; + + type = with lib.types; path; + + readOnly = true; + internal = true; + }; + + toplevel = lib.mkOption { + type = with lib.types; listOf path; + + readOnly = true; + internal = true; + }; + } // commonOpts {}; + }; + + config = { + # Optimize all the important paths from all users and the system. + my.persist.toplevel = optimizePaths ( + cfg.directories ++ + cfg.files ++ ( + lib.attrValues config.home-manager.users + |> map normalizeUserPaths + |> lib.flatten + ) + ); + + home-manager.sharedModules = [{ + options = { + # Ensure our custom paths are valid. We will resolve them later on so + # this won't pose a problem. + my.persist = commonOpts { + type = with lib.types; listOf userPath; + }; + }; + }]; + }; +} diff --git a/modules/common/persist/package/default.nix b/modules/common/persist/package/default.nix new file mode 100644 index 0000000..8cd48a3 --- /dev/null +++ b/modules/common/persist/package/default.nix @@ -0,0 +1,39 @@ +{ + lib, + stdenvNoCC, + + coreutils, + util-linux, +}: +stdenvNoCC.mkDerivation { + pname = "persist-helper"; + version = "0.1.1"; + + src = with lib.fileset; toSource { + root = ./.; + fileset = unions [ + ./persist-helper.sh + ]; + }; + + installPhase = '' + runHook preInstall + + install -Dm755 persist-helper.sh $out/bin/persist-helper + + runHook postInstall + ''; + + postInstall = '' + substituteInPlace $out/bin/persist-helper \ + --subst-var-by path ${lib.makeBinPath [ coreutils util-linux ]} + ''; + + meta = with lib; { + license = licenses.agpl3Plus; + maintainers = with maintainers; [ frontear ]; + platforms = platforms.linux; + + mainProgram = "persist-helper"; + }; +} diff --git a/modules/common/persist/package/persist-helper.sh b/modules/common/persist/package/persist-helper.sh new file mode 100755 index 0000000..3caf56b --- /dev/null +++ b/modules/common/persist/package/persist-helper.sh @@ -0,0 +1,118 @@ +#!/usr/bin/env bash + +set -o errexit +set -o nounset +set -o pipefail + +export PATH="@path@:$PATH" + +logVerbose() { + echo -n "[persist-helper] " >&2 + echo $@ >&2 # passes arguments raw to `echo` to allow echo to process them as direct arguments (like -n or -e) +} + +runVerbose() { + echo "\$ $@" >&2 + echo " $($@ 2>&1)" >&2 + echo "" >&2 +} + +if [ "$#" -ne 4 ]; then + logVerbose "invalid arguments provided (expected: 4, got: $#)" + logVerbose "arguments: $@" + exit 1 +fi + +operation="$1" +sourceRoot=$(echo "$2" | tr -s '/') +targetRoot=$(echo "$3" | tr -s '/') +sourcePath=$(echo "$sourceRoot/$4" | tr -s '/') +targetPath=$(echo "$targetRoot/${sourcePath#"$sourceRoot"}" | tr -s '/') +parentArray=($(dirname "$4" | tr '/' ' ')) + +cat <<- EOF >&2 +================================================================================ +origArgs: $@ + +operation: $operation +sourceRoot: $sourceRoot +targetRoot: $targetRoot +sourcePath: $sourcePath +targetPath: $targetPath +parentArray: [ ${parentArray[@]} ] +================================================================================ + +EOF + +if [ "$operation" != "mount" ] && [ "$operation" != "copy" ]; then + logVerbose "invalid operation (expected one of: [mount, copy], got $operation)" + exit 1 +fi + +if [ ! -e "$sourceRoot" ] || [ ! -e "$sourcePath" ]; then + logVerbose "sources do not exist" + exit 1 +fi + +# Accumulate the parents that we know we need to create +# on both the source and target roots. This slowly builds +# up a path string that grows in tandem and points to a +# location which is semantically related. +# +# During the accumulation, we create the contents at the +# target, and perform permission synchronisation from +# the source path accumulated at that point. +# +# As a trivial example, for some input into the CLI: +# sourceRoot="/" +# targetRoot="/nix/persist/" +# parentArray=("var" "lib") # assuming /var/lib/foo is the targetPath +# +# A step by step accumulation would accumulate "var" onto the two roots, +# producing "/var" and "/nix/persist/var", then continues to accumulate +# the "lib", producing "/var/lib" and "/nix/persist/var/lib". +createDirectories() { + local sourceAcc="$sourceRoot" + local targetAcc="$targetRoot" + + for parent in ${parentArray[@]}; do + sourceAcc=$(echo "$sourceAcc/$parent" | tr -s '/') + targetAcc=$(echo "$targetAcc/$parent" | tr -s '/') + + logVerbose "creating directory '$targetAcc'" + runVerbose mkdir --verbose --parents "$targetAcc" + + logVerbose "cloning permissions from '$sourceAcc' to '$targetAcc'" + runVerbose chown --verbose --reference="$sourceAcc" "$targetAcc" + runVerbose chmod --verbose --reference="$sourceAcc" "$targetAcc" + done +} + +if [ ! -d "$targetRoot" ]; then + logVerbose "creating target root at '$targetRoot'" + runVerbose mkdir --parents "$targetRoot" +fi + +createDirectories + +case "$operation" in + "mount") + logEntry="creating entry at '$targetPath' (" + if [ -f "$sourcePath" ]; then + logEntry+="file)" + logVerbose "$logEntry" + runVerbose touch "$targetPath" + elif [ -d "$sourcePath" ]; then + logEntry+="directory)" + logVerbose "$logEntry" + runVerbose mkdir "$targetPath" + fi + + logVerbose "mounting from '$sourcePath' to '$targetPath'" + runVerbose mount --bind "$sourcePath" "$targetPath" + ;; + "copy") + logVerbose "copying from '$sourcePath' to '$targetPath'" + runVerbose cp --archive "$sourcePath" "$targetPath" + ;; +esac diff --git a/modules/home-manager/programs/element/module.nix b/modules/home-manager/programs/element/module.nix index 543d443..895f958 100644 --- a/modules/home-manager/programs/element/module.nix +++ b/modules/home-manager/programs/element/module.nix @@ -18,10 +18,9 @@ in { }; config = lib.mkIf cfg.enable { - my.persist.directories = [{ - path = "~/.config/Element"; - mode = "700"; - }]; + my.persist.directories = [ + "~/.config/Element" + ]; home.packages = [ cfg.package ]; }; diff --git a/modules/home-manager/programs/gnupg/module.nix b/modules/home-manager/programs/gnupg/module.nix index 9a57e6d..2927d27 100644 --- a/modules/home-manager/programs/gnupg/module.nix +++ b/modules/home-manager/programs/gnupg/module.nix @@ -52,14 +52,8 @@ in { config = lib.mkIf cfg.enable { my.persist.directories = [ - { - path = lib.replaceStrings [ config.home.homeDirectory ] [ "~" ] cfg.dotDir; - mode = "700"; - } - { - path = "~/.ssh"; - mode = "700"; - } + cfg.dotDir + "~/.ssh" ]; # https://wiki.archlinux.org/title/GnuPG#Configure_pinentry_to_use_the_correct_TTY diff --git a/modules/home-manager/programs/legcord/module.nix b/modules/home-manager/programs/legcord/module.nix index 2ea7d2c..c1dc302 100644 --- a/modules/home-manager/programs/legcord/module.nix +++ b/modules/home-manager/programs/legcord/module.nix @@ -21,10 +21,9 @@ in { }; config = lib.mkIf cfg.enable { - my.persist.directories = [{ - path = "~/.config/legcord"; - mode = "700"; - }]; + my.persist.directories = [ + "~/.config/legcord" + ]; home.packages = [ cfg.package ]; }; diff --git a/modules/home-manager/programs/libreoffice/module.nix b/modules/home-manager/programs/libreoffice/module.nix index 1c7aa74..5408997 100644 --- a/modules/home-manager/programs/libreoffice/module.nix +++ b/modules/home-manager/programs/libreoffice/module.nix @@ -45,10 +45,9 @@ in { }; config = lib.mkIf cfg.enable { - my.persist.directories = [{ - path = "~/.config/libreoffice"; - mode = "700"; - }]; + my.persist.directories = [ + "~/.config/libreoffice" + ]; fonts.fontconfig.enable = lib.mkDefault true; diff --git a/modules/home-manager/programs/microsoft-edge/module.nix b/modules/home-manager/programs/microsoft-edge/module.nix index d6a7cbe..1dd7f3b 100644 --- a/modules/home-manager/programs/microsoft-edge/module.nix +++ b/modules/home-manager/programs/microsoft-edge/module.nix @@ -34,14 +34,8 @@ in { config = lib.mkIf cfg.enable (lib.mkMerge [ { my.persist.directories = [ - { - path = "${cfg.userDataDir}"; - mode = "700"; - } - { - path = "~/.cache/microsoft-edge"; - mode = "700"; - } + "${cfg.userDataDir}" + "~/.cache/microsoft-edge" ]; home.packages = [ cfg.package ]; diff --git a/modules/home-manager/programs/neovim/module.nix b/modules/home-manager/programs/neovim/module.nix index 3544ee2..8f42895 100644 --- a/modules/home-manager/programs/neovim/module.nix +++ b/modules/home-manager/programs/neovim/module.nix @@ -64,10 +64,9 @@ in { }; config = lib.mkIf cfg.enable { - my.persist.directories = [{ - path = "~/.local/state/nvim"; - mode = "700"; - }]; + my.persist.directories = [ + "~/.local/state/nvim" + ]; xdg.configFile."nvim/init.lua".text = '' ${cfg.init} diff --git a/modules/home-manager/programs/zsh/module.nix b/modules/home-manager/programs/zsh/module.nix index aaad3a3..a4f06e2 100644 --- a/modules/home-manager/programs/zsh/module.nix +++ b/modules/home-manager/programs/zsh/module.nix @@ -103,11 +103,9 @@ in { ]; # Persist the history file - my.persist.files = [{ - path = (lib.replaceStrings [ config.home.homeDirectory ] [ "~" ] - cfg.history.file); - mode= "600"; - }]; + my.persist.files = [ + cfg.history.file + ]; programs.zsh = lib.mkMerge [ ({ diff --git a/modules/nixos/desktops/sway/module.nix b/modules/nixos/desktops/sway/module.nix index 3d974db..9c4de7a 100644 --- a/modules/nixos/desktops/sway/module.nix +++ b/modules/nixos/desktops/sway/module.nix @@ -14,12 +14,9 @@ in { config = lib.mkIf cfg.enable { my.audio.pipewire.enable = lib.mkDefault true; - my.persist.directories = [{ - path = "/var/cache/tuigreet"; - user = "greeter"; - group = "greeter"; - mode = "700"; - }]; + my.persist.directories = [ + "/var/cache/tuigreet" + ]; services.greetd = { enable = true; diff --git a/modules/nixos/system/mounts/tmp/module.nix b/modules/nixos/system/mounts/tmp/module.nix index fc4d41d..faeb73e 100644 --- a/modules/nixos/system/mounts/tmp/module.nix +++ b/modules/nixos/system/mounts/tmp/module.nix @@ -13,7 +13,7 @@ in { config = lib.mkMerge [ (lib.mkIf cfg.enableTmpfs { # Force the Nix builder into a sane TMPDIR - my.persist.directories = [{ path = "/var/tmp"; mode = "1777"; }]; + my.persist.directories = [ "/var/tmp" ]; systemd.services.nix-daemon.environment.TMPDIR = "/var/tmp"; # Use tmpfs for /tmp as it's just easier to use.