Files
nixos-config/home/xdg-compat.nix
T
2026-03-31 16:53:11 +02:00

175 lines
4.6 KiB
Nix

{
config,
lib,
pkgs,
...
}: let
cfg = config.xdg;
username = "someone";
fileType = lib.types.submodule {
options = {
text = lib.mkOption {
type = lib.types.nullOr lib.types.lines;
default = null;
};
source = lib.mkOption {
type = lib.types.nullOr lib.types.path;
default = null;
};
mutable = lib.mkOption {
type = lib.types.bool;
default = false;
description = "If true, copy the file instead of symlinking, allowing the application to modify it";
};
};
};
userOpts = _: {
options = {
configFiles = lib.mkOption {
type = lib.types.attrsOf fileType;
default = {};
};
cacheFiles = lib.mkOption {
type = lib.types.attrsOf fileType;
default = {};
};
dataFiles = lib.mkOption {
type = lib.types.attrsOf fileType;
default = {};
};
stateFiles = lib.mkOption {
type = lib.types.attrsOf fileType;
default = {};
};
homeFiles = lib.mkOption {
type = lib.types.attrsOf fileType;
default = {};
};
};
};
mkLinkScript = baseDir: name: file: let
target =
if file.text != null
then pkgs.writeText name file.text
else file.source;
fullPath = "${baseDir}/${name}";
parentDir = builtins.dirOf fullPath;
in
if file.mutable
then ''
mkdir -p "${parentDir}"
if [ -L "${fullPath}" ]; then
# Replace symlink with a copy
rm -f "${fullPath}"
cp "${target}" "${fullPath}"
chmod +w "${fullPath}"
elif [ -e "${fullPath}" ]; then
:
else
cp "${target}" "${fullPath}"
chmod +w "${fullPath}"
fi
''
else ''
mkdir -p "${parentDir}"
if [ -L "${fullPath}" ]; then
current_target=$(readlink "${fullPath}")
if [ "$current_target" != "${target}" ]; then
rm -f "${fullPath}"
ln -s "${target}" "${fullPath}"
fi
elif [ -e "${fullPath}" ]; then
rm -f "${fullPath}"
ln -s "${target}" "${fullPath}"
else
ln -s "${target}" "${fullPath}"
fi
'';
in {
options = {
users.users = lib.mkOption {type = lib.types.attrsOf (lib.types.submodule userOpts);};
home = {
homeDirectory = lib.mkOption {
type = lib.types.path;
default = "/home/${username}";
};
file = lib.mkOption {
type = lib.types.attrsOf fileType;
default = {};
};
};
xdg = {
configHome = lib.mkOption {
type = lib.types.path;
default = "/home/${username}/.config";
};
cacheHome = lib.mkOption {
type = lib.types.path;
default = "/home/${username}/.cache";
};
dataHome = lib.mkOption {
type = lib.types.path;
default = "/home/${username}/.local/share";
};
stateHome = lib.mkOption {
type = lib.types.path;
default = "/home/${username}/.local/state";
};
runtimeDir = lib.mkOption {
type = lib.types.str;
default = "/run/user/1000";
};
configFile = lib.mkOption {
type = lib.types.attrsOf fileType;
default = {};
};
cacheFile = lib.mkOption {
type = lib.types.attrsOf fileType;
default = {};
};
dataFile = lib.mkOption {
type = lib.types.attrsOf fileType;
default = {};
};
stateFile = lib.mkOption {
type = lib.types.attrsOf fileType;
default = {};
};
};
};
config = {
users.users.${username} = {
configFiles = cfg.configFile;
cacheFiles = cfg.cacheFile;
dataFiles = cfg.dataFile;
stateFiles = cfg.stateFile;
homeFiles = config.home.file;
};
environment.sessionVariables = {
XDG_CONFIG_HOME = cfg.configHome;
XDG_CACHE_HOME = cfg.cacheHome;
XDG_DATA_HOME = cfg.dataHome;
XDG_STATE_HOME = cfg.stateHome;
};
system.activationScripts.xdgUserFiles = lib.stringAfter ["users"] ''
${lib.concatStringsSep "\n" (
lib.flatten (
lib.mapAttrsToList (
user: userCfg:
(lib.mapAttrsToList (mkLinkScript cfg.configHome) userCfg.configFiles)
++ (lib.mapAttrsToList (mkLinkScript cfg.cacheHome) userCfg.cacheFiles)
++ (lib.mapAttrsToList (mkLinkScript cfg.dataHome) userCfg.dataFiles)
++ (lib.mapAttrsToList (mkLinkScript cfg.stateHome) userCfg.stateFiles)
++ (lib.mapAttrsToList (mkLinkScript config.home.homeDirectory) userCfg.homeFiles)
)
config.users.users
)
)}
'';
};
}